lte-ue.c 54.1 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 24
    see <http://www.gnu.org/licenses/>.

   Contact Information
   OpenAirInterface Admin: openair_admin@eurecom.fr
   OpenAirInterface Tech : openair_tech@eurecom.fr
   OpenAirInterface Dev  : openair4g-devel@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 56 57 58 59 60 61
   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>

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

#include "PHY/defs.h"
62
#ifdef OPENAIR2
63 64
#include "LAYER2/MAC/defs.h"
#include "RRC/LITE/extern.h"
65
#endif
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
#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

#ifdef EXMIMO
#include "openair0_lib.h"
#else
#include "../../ARCH/COMMON/common_lib.h"
#endif

#include "PHY/extern.h"
#include "MAC_INTERFACE/extern.h"
//#include "SCHED/defs.h"
#include "SCHED/extern.h"
81
#ifdef OPENAIR2
82 83
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/proto.h"
84
#endif
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

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

int init_dlsch_threads(void);
void cleanup_dlsch_threads(void);
int32_t init_rx_pdsch_thread(void);
void cleanup_rx_pdsch_thread(void);

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];
113
extern int32_t           uplink_frequency_offset[MAX_NUM_CCs][4];
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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
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;

extern unsigned int samples_per_frame;
extern unsigned int tx_forward_nsamps;
extern int tx_delay;

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

#ifdef EXMIMO

extern unsigned int             rxg_max[4];
extern unsigned int             rxg_med[4];
extern unsigned int             rxg_byp[4];
extern unsigned int             nf_max[4];
extern unsigned int             nf_med[4];
extern unsigned int             nf_byp[4];
extern rx_gain_t                rx_gain_mode[MAX_NUM_CCs][4];

extern double tx_gain[MAX_NUM_CCs][4];
extern double rx_gain[MAX_NUM_CCs][4];
#endif
#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;

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
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},
  {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},
};

static void *UE_thread_synch(void *arg)
{
198 199 200 201 202 203 204

  int i,hw_slot_offset;
  PHY_VARS_UE *UE = arg;
  int current_band = 0;
  int current_offset = 0;
  sync_mode_t sync_mode = pss;
  int card;
205
  int ind;
206 207
  //  int CC_id;
  //  int k;
208
  int found;
209 210 211 212 213 214 215 216

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


  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_sync_thread)\n");
217

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

221 222 223 224
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex (UE_sync_thread)\n");

  printf("starting UE synch thread\n");
225 226
  ind = 0;
  found = 0;
227 228 229
  current_band = eutra_bands[ind].band;


230 231 232
  if (UE->UE_scan == 0) {
    do  {
      printf("Scanning band %d, dl_min %u\n",current_band,eutra_bands[ind].dl_min);
233

234 235 236 237 238 239 240 241
      if ((eutra_bands[ind].dl_min <= downlink_frequency[0][0]) && (eutra_bands[ind].dl_max>= downlink_frequency[0][0])) {
        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;
      }
242

243 244 245
      ind++;
      current_band = eutra_bands[ind].band;
    } while (current_band < 44);
246

247 248 249 250
    if (found == 0) {
      exit_fun("Can't find EUTRA band for frequency");
      oai_exit=1;
    }
251
  }
252

253 254
  else if  (UE->UE_scan == 1) {
    current_band=0;
255
    for (card=0; card<MAX_CARDS; card++) {
256
      for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
257 258 259 260 261
        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];
262
#ifdef OAI_USRP
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
        openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB-USRP_GAIN_OFFSET;

        switch(UE->lte_frame_parms.N_RB_DL) {
        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;

        default:
          printf("Unknown number of RBs %d\n",UE->lte_frame_parms.N_RB_DL);
          break;
        }

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

287
#ifdef EXMIMO
288
      //openair0_config(&openair0_cfg[card],1);
289
#endif
290 291
    }

292
#ifdef OAI_USRP
293
#ifndef USRP_DEBUG
294 295
    openair0_set_rx_frequencies(&openair0,&openair0_cfg[0]);
    openair0_set_gains(&openair0,&openair0_cfg[0]);
296 297
#endif
#endif
298

299
  } else {
300 301 302
    LOG_D(PHY,"[SCHED][UE] Check absolute frequency %u (oai_exit %d)\n",downlink_frequency[0][0],oai_exit);

    sync_mode=pbch;
303
  }
304 305

  while (oai_exit==0) {
306

307 308 309
    if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
      LOG_E(PHY,"[SCHED][UE] error locking mutex for UE initial synch thread\n");
      exit_fun("noting to add");
310
    } else {
311
      while (UE->instance_cnt_synch < 0) {
312
        pthread_cond_wait(&UE->cond_synch,&UE->mutex_synch);
313
      }
314 315 316 317

      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");
318 319
      }

320 321
    }  // mutex_lock

gauthier's avatar
gauthier committed
322
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH,1);
323

jiangx's avatar
jiangx committed
324
    //printf("Sync_mode %d\n",sync_mode);
325
    switch (sync_mode) {
326 327
    case pss:

328 329
      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);
330 331 332 333 334 335 336 337 338


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

339
      if (current_band==bands_to_scan.nbands) {
340 341
        current_band=0;
        oai_exit=1;
342
      }
343 344 345 346 347 348 349 350 351

      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;


          openair0_cfg[card].rx_freq[i] = downlink_frequency[card][i]+openair_daq_vars.freq_offset;
          openair0_cfg[card].tx_freq[i] = downlink_frequency[card][i]+uplink_frequency_offset[card][i]+openair_daq_vars.freq_offset;
352
#ifdef OAI_USRP
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
          openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB-USRP_GAIN_OFFSET;  // 65 calibrated for USRP B210 @ 2.6 GHz

          switch(UE->lte_frame_parms.N_RB_DL) {
          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;

          default:
            printf("Unknown number of RBs %d\n",UE->lte_frame_parms.N_RB_DL);
            break;
          }

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

376
  }
377

378
#ifdef EXMIMO
379
        //openair0_config(&openair0_cfg[card],1);
380
#endif
381 382
      }

383
#ifdef OAI_USRP
384
#ifndef USRP_DEBUG
385
      openair0_set_rx_frequencies(&openair0,&openair0_cfg[0]);
386
      //  openair0_set_gains(&openair0,&openair0_cfg[0]);
387 388
#endif
#endif
389

390
      break;
391

392
    case pbch:
393
      //      printf("synch: Running initial sync\n");
394 395
      // This is a hack to fix a bug when using USRP
      memset(PHY_vars_UE_g[0][0]->lte_ue_common_vars.rxdata[0],0,1024);
396

397
      if (initial_sync(UE,UE->mode)==0) {
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
        /*
          lte_adjust_synch(&PHY_vars_UE_g[0]->lte_frame_parms,
          PHY_vars_UE_g[0],
          0,
          1,
          16384);
        */
        //for better visualization afterwards
        /*
          for (aa=0; aa<PHY_vars_UE_g[0]->lte_frame_parms.nb_antennas_rx; aa++)
          memset(PHY_vars_UE_g[0]->lte_ue_common_vars.rxdata[aa],0,
          PHY_vars_UE_g[0]->lte_frame_parms.samples_per_tti*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*sizeof(int));
        */


        UE->is_synchronized = 1;
414
#ifndef EXMIMO
415 416
        UE->slot_rx = 0;
        UE->slot_tx = 4;
417
#else
418 419
        UE->slot_rx = 18;
        UE->slot_tx = 2;
420
#endif
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
        hw_slot_offset = (UE->rx_offset<<1) / UE->lte_frame_parms.samples_per_tti;
        LOG_I(HW,"Got synch: hw_slot_offset %d\n",hw_slot_offset);

      } else { // intial_synch

        if (openair_daq_vars.freq_offset >= 0) {
          openair_daq_vars.freq_offset += 100;
          openair_daq_vars.freq_offset *= -1;
        } else {
          openair_daq_vars.freq_offset *= -1;
        }

        if (abs(openair_daq_vars.freq_offset) > 7500) {
          LOG_I(PHY,"[initial_sync] No cell synchronization found, abandoning\n");
          mac_xface->macphy_exit("No cell synchronization found, abandoning");
436
          return 0; // not reached
437 438 439 440 441 442 443 444 445 446 447
        }

        LOG_I(PHY,"[initial_sync] trying carrier off %d Hz, rxgain %d (DL %u, UL %u)\n",openair_daq_vars.freq_offset,
              UE->rx_total_gain_dB,
              downlink_frequency[0][0]+openair_daq_vars.freq_offset,
              downlink_frequency[0][0]+uplink_frequency_offset[0][0]+openair_daq_vars.freq_offset);

        for (card=0; card<MAX_CARDS; card++) {
          for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
            openair0_cfg[card].rx_freq[i] = downlink_frequency[card][i]+openair_daq_vars.freq_offset;
            openair0_cfg[card].tx_freq[i] = downlink_frequency[card][i]+uplink_frequency_offset[card][i]+openair_daq_vars.freq_offset;
448
#ifdef OAI_USRP
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
            openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB-USRP_GAIN_OFFSET;  // 65 calibrated for USRP B210 @ 2.6 GHz

            switch(UE->lte_frame_parms.N_RB_DL) {
            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;

            default:
              printf("Unknown number of RBs %d\n",UE->lte_frame_parms.N_RB_DL);
              break;
            }

            //        printf("UE synch: setting RX gain (%d,%d) to %d\n",card,i,openair0_cfg[card].rx_gain[i]);
470
#endif
471 472
          }

473
#ifdef EXMIMO
474 475
          //openair0_config(&openair0_cfg[card],1);
          //rt_sleep_ns(FRAME_PERIOD);
476
#endif
477 478
        }

479
#ifdef OAI_USRP
480
#ifndef USRP_DEBUG
481 482
        openair0_set_frequencies(&openair0,&openair0_cfg[0]);
        //      openair0_set_gains(&openair0,&openair0_cfg[0]);
483
#endif
484

485
#endif
486

487 488 489 490 491


        //        openair0_dump_config(&openair0_cfg[0],UE_flag);

        //        rt_sleep_ns(FRAME_PERIOD);
492 493

      } // initial_sync=0
494

495
      break;
496

497 498 499 500
    case si:
    default:
      break;
    }
gauthier's avatar
gauthier committed
501
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH,0);
502

503 504
    if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
      printf("[openair][SCHED][eNB] error locking mutex for UE synch\n");
505
    } else {
506
      UE->instance_cnt_synch--;
507 508 509

      if (pthread_mutex_unlock(&UE->mutex_synch) != 0) {
        printf("[openair][SCHED][eNB] error unlocking mutex for UE synch\n");
510 511
      }
    }
512

gauthier's avatar
gauthier committed
513
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH,0);
514
  }  // while !oai_exit
515

516 517 518
  return(0);
}

519 520
static void *UE_thread_tx(void *arg)
{
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536

#ifdef LOWLATENCY
  struct sched_attr attr;
  unsigned int flags = 0;
#endif
#ifdef RTAI
  RT_TASK *task;
#endif
  int ret;

  PHY_VARS_UE *UE = (PHY_VARS_UE*)arg;

  UE->instance_cnt_tx=-1;

#ifdef RTAI
  task = rt_task_init_schmod(nam2num("UE TX Thread"), 0, 0, 0, SCHED_FIFO, 0xF);
537

538 539 540 541
  if (task==NULL) {
    LOG_E(PHY,"[SCHED][UE] Problem starting UE TX thread!!!!\n");
    return 0;
  }
542

543 544 545 546 547 548 549 550
  LOG_D(HW,"Started UE TX thread (id %p)\n",task);
#else

#ifdef LOWLATENCY
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;
551

552 553 554 555 556 557
  /* This creates a 1ms reservation every 10ms period*/
  attr.sched_policy = SCHED_DEADLINE;
  attr.sched_runtime = 1 * 500000;  // each tx thread requires .5ms to finish its job
  attr.sched_deadline =1 * 1000000; // each tx thread will finish within 1ms
  attr.sched_period = 1 * 1000000; // each tx thread has a period of 1ms from the starting point

558 559

  if (sched_setattr(0, &attr, flags) < 0 ) {
560 561 562
    perror("[SCHED] eNB tx thread: sched_setattr failed\n");
    exit(-1);
  }
563

564 565 566 567 568 569
#endif
#endif
  printf("waiting for sync (UE_thread_tx)\n");

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

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

574 575 576 577 578 579 580 581 582 583 584 585
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread_tx)\n");

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

  mlockall(MCL_CURRENT | MCL_FUTURE);

  while (!oai_exit) {

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

588
      while (UE->instance_cnt_tx < 0) {
589
        pthread_cond_wait(&UE->cond_tx,&UE->mutex_tx);
590
      }
591 592 593 594

      if (pthread_mutex_unlock(&UE->mutex_tx) != 0) {
        LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for UE TX\n");
        exit_fun("nothing to add");
595 596
      }
    }
597

598 599

    if ((subframe_select(&UE->lte_frame_parms,UE->slot_tx>>1)==SF_UL)||
600
        (UE->lte_frame_parms.frame_type == FDD)) {
601 602
      phy_procedures_UE_TX(UE,0,0,UE->mode,no_relay);
    }
603

604
    if ((subframe_select(&UE->lte_frame_parms,UE->slot_tx>>1)==SF_S) &&
605
        ((UE->slot_tx&1)==1)) {
606 607
      phy_procedures_UE_S_TX(UE,0,0,no_relay);
    }
608 609 610

#ifdef OPENAIR2

611
    if (UE->lte_frame_parms.frame_type == TDD) {
612 613 614 615 616 617 618 619

      ret = mac_xface->ue_scheduler(UE->Mod_id,
                                    UE->frame_tx,
                                    UE->slot_rx>>1,
                                    subframe_select(&UE->lte_frame_parms,UE->slot_tx>>1),
                                    0,
                                    0/*FIXME CC_id*/);

620
      if (ret == CONNECTION_LOST) {
621 622 623 624 625 626 627 628 629 630 631
        LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, returning to PRACH\n",UE->Mod_id,
              UE->frame_rx,UE->slot_tx>>1);
        UE->UE_mode[0] = PRACH;
        //      mac_xface->macphy_exit("Connection lost");
      } else if (ret == PHY_RESYNCH) {
        LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, trying to resynch\n",
              UE->Mod_id,
              UE->frame_rx,UE->slot_tx>>1);
        UE->UE_mode[0] = RESYNCH;
        //     mac_xface->macphy_exit("Connection lost");
        //exit(-1);
632
      } else if (ret == PHY_HO_PRACH) {
633 634 635
        LOG_I(PHY,"[UE %d] Frame %d, subframe %d, return to PRACH and perform a contention-free access\n",
              UE->Mod_id,UE->frame_rx,UE->slot_tx>>1);
        UE->UE_mode[0] = PRACH;
636 637
      }
    }
638 639

#endif
640 641


642 643
    if (pthread_mutex_lock(&UE->mutex_tx) != 0) {
      printf("[openair][SCHED][eNB] error locking mutex for UE TX thread\n");
644
    } else {
645
      UE->instance_cnt_tx--;
646 647 648

      if (pthread_mutex_unlock(&UE->mutex_tx) != 0) {
        printf("[openair][SCHED][eNB] error unlocking mutex for UE\n");
649 650
      }
    }
651

652
    UE->slot_tx+=2;
653

654 655 656
    if (UE->slot_tx>=20) {
      UE->slot_tx-=20;
      UE->frame_tx++;
gauthier's avatar
gauthier committed
657
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX_UE, UE->frame_tx);
658
    }
659

gauthier's avatar
gauthier committed
660
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX_UE, UE->slot_tx>>1);
661
  }
662

663 664 665
  return(0);
}

gauthier's avatar
gauthier committed
666 667 668
//! \brief .
//! This is a pthread.
//! \param arg expects a pointer to \ref PHY_VARS_UE.
669 670 671
static void *UE_thread_rx(void *arg)
{

672 673 674
  PHY_VARS_UE *UE = (PHY_VARS_UE*)arg;
  int i;
  int ret;
675

676 677 678 679 680 681 682
#ifdef LOWLATENCY
  struct sched_attr attr;
  unsigned int flags = 0;
#endif
#ifdef RTAI
  RT_TASK *task;
#endif
683

684 685 686
  UE->instance_cnt_rx=-1;

#ifdef RTAI
jiangx's avatar
jiangx committed
687
  task = rt_task_init_schmod(nam2num("UE RX Thread"), 0, 0, 0, SCHED_FIFO, 0xF);
688

689 690 691 692
  if (task==NULL) {
    LOG_E(PHY,"[SCHED][UE] Problem starting UE RX thread!!!!\n");
    return 0;
  }
693

694 695
  LOG_D(HW,"Started UE RX thread (id %p)\n",task);
#else
696

697 698 699 700 701
#ifdef LOWLATENCY
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;
702

703 704
  // This creates a 1ms reservation every 10ms period
  attr.sched_policy = SCHED_DEADLINE;
705
  attr.sched_runtime = 1 * 500000;  // each rx thread requires 1ms to finish its job
706 707
  attr.sched_deadline =1 * 1000000; // each rx thread will finish within 1ms
  attr.sched_period = 1 * 1000000; // each rx thread has a period of 1ms from the starting point
708 709

  if (sched_setattr(0, &attr, flags) < 0 ) {
710 711
    perror("[SCHED] eNB tx thread: sched_setattr failed\n");
    exit(-1);
712 713
  }

714 715
#endif
#endif
716

717
  mlockall(MCL_CURRENT | MCL_FUTURE);
718

719
  printf("waiting for sync (UE_thread_rx)\n");
720

721 722
  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_thread_rx)\n");
723

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

727 728
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread_rx)\n");
729

730
  printf("Starting UE RX thread\n");
731 732

  while (!oai_exit) {
733 734 735 736
    //   printf("UE_thread_rx: locking UE RX mutex\n");
    if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
      LOG_E(PHY,"[SCHED][eNB] error locking mutex for UE RX\n");
      exit_fun("nothing to add");
gauthier's avatar
gauthier committed
737
      break;
738
    }
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753

    while (UE->instance_cnt_rx < 0) {
      pthread_cond_wait(&UE->cond_rx,&UE->mutex_rx);
    }

    if (pthread_mutex_unlock(&UE->mutex_rx) != 0) {
      LOG_E(PHY,"[SCHED][eNB] error unlocking mutex for UE RX\n");
      exit_fun("nothing to add");
      break;
    }

    for (i=0; i<2; i++) {
      if ((subframe_select(&UE->lte_frame_parms,UE->slot_rx>>1)==SF_DL) |
          (UE->lte_frame_parms.frame_type == FDD)) {
        phy_procedures_UE_RX(UE,0,0,UE->mode,no_relay,NULL);
754
      }
gauthier's avatar
gauthier committed
755

756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
      if ((subframe_select(&UE->lte_frame_parms,UE->slot_rx>>1)==SF_S) &&
          ((UE->slot_rx&1)==0)) {
        phy_procedures_UE_RX(UE,0,0,UE->mode,no_relay,NULL);
      }

#ifdef OPENAIR2

      if (i==0) {
        ret = mac_xface->ue_scheduler(UE->Mod_id,
                                      UE->frame_tx,
                                      UE->slot_rx>>1,
                                      subframe_select(&UE->lte_frame_parms,UE->slot_tx>>1),
                                      0,
                                      0/*FIXME CC_id*/);

        if (ret == CONNECTION_LOST) {
          LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, returning to PRACH\n",UE->Mod_id,
                UE->frame_rx,UE->slot_tx>>1);
          UE->UE_mode[0] = PRACH;
          //      mac_xface->macphy_exit("Connection lost");
        } else if (ret == PHY_RESYNCH) {
          LOG_E(PHY,"[UE %d] Frame %d, subframe %d RRC Connection lost, trying to resynch\n",
                UE->Mod_id,
                UE->frame_rx,UE->slot_tx>>1);
          UE->UE_mode[0] = RESYNCH;
          //     mac_xface->macphy_exit("Connection lost");
        } else if (ret == PHY_HO_PRACH) {
          LOG_I(PHY,"[UE %d] Frame %d, subframe %d, return to PRACH and perform a contention-free access\n",
                UE->Mod_id,UE->frame_rx,UE->slot_tx>>1);
          UE->UE_mode[0] = PRACH;
        }
787
      }
788 789 790 791 792 793 794

#endif
      UE->slot_rx++;

      if (UE->slot_rx==20) {
        UE->slot_rx=0;
        UE->frame_rx++;
gauthier's avatar
gauthier committed
795
        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_UE, UE->frame_rx);
796 797
      }

gauthier's avatar
gauthier committed
798
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX_UE, UE->slot_rx>>1);
799 800 801 802 803 804 805 806 807 808

    }

    if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
      printf("[openair][SCHED][eNB] error locking mutex for UE RX\n");
    } else {
      UE->instance_cnt_rx--;

      if (pthread_mutex_unlock(&UE->mutex_rx) != 0) {
        printf("[openair][SCHED][eNB] error unlocking mutex for UE RX\n");
809
      }
810 811 812
    }

    //    printf("UE_thread_rx done\n");
gauthier's avatar
gauthier committed
813 814 815 816
  }

  // thread finished
  return 0;
817
}
818

819 820 821 822 823 824 825 826



#ifndef EXMIMO
#define RX_OFF_MAX 10
#define RX_OFF_MIN 5
#define RX_OFF_MID ((RX_OFF_MAX+RX_OFF_MIN)/2)

827 828
void *UE_thread(void *arg)
{
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852

  PHY_VARS_UE *UE=PHY_vars_UE_g[0][0];
  LTE_DL_FRAME_PARMS *frame_parms=&UE->lte_frame_parms;
  int spp = openair0_cfg[0].samples_per_packet;

  int slot=1,frame=0,hw_subframe=0,rxpos=0,txpos=0;
  // unsigned int aa;
  int dummy[2][spp];
  int dummy_dump = 0;
  int tx_enabled=0;
  int start_rx_stream=0;
  int rx_off_diff = 0;
  int rx_correction_timer = 0;
  int i;
  int first_rx=0;
  RTIME T0;
#ifdef RTAI
  RT_TASK *task;
#endif

  unsigned int rxs;
  void *rxp[2],*txp[2];
  openair0_timestamp timestamp;

853

854 855 856 857
#ifdef LOWLATENCY
  struct sched_attr attr;
  unsigned int flags = 0;
#endif
858

859 860 861 862


#ifdef RTAI
  task = rt_task_init_schmod(nam2num("UE thread"), 0, 0, 0, SCHED_FIFO, 0xF);
863

864 865 866 867
  if (task==NULL) {
    LOG_E(PHY,"[SCHED][UE] Problem starting UE thread!!!!\n");
    return 0;
  }
868

869
#else
870

871 872 873 874 875
#ifdef LOWLATENCY
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;
876

877 878 879 880 881
  // This creates a .5 ms  reservation
  attr.sched_policy = SCHED_DEADLINE;
  attr.sched_runtime  = 0.25 * 1000000;
  attr.sched_deadline = 0.25 * 1000000;
  attr.sched_period   = 0.5 * 1000000;
882

883 884 885 886
  // pin the UE main thread to CPU0
  // if (pthread_setaffinity_np(pthread_self(), sizeof(mask),&mask) <0) {
  //   perror("[MAIN_ENB_THREAD] pthread_setaffinity_np failed\n");
  //   }
887 888

  if (sched_setattr(0, &attr, flags) < 0 ) {
889 890 891 892
    perror("[SCHED] main eNB thread: sched_setattr failed\n");
    exit_fun("Nothing to add");
  } else {
    LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %ld started on CPU %d\n",
893
          gettid(),sched_getcpu());
894
  }
895

896 897 898 899 900 901 902 903
#endif
#endif

  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");
904

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

908 909 910 911 912
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread)\n");

  printf("starting UE thread\n");

913

914 915 916 917


  T0 = rt_get_time_ns();
  first_rx = 1;
918
  rxpos=0;
919

920
  while (!oai_exit) {
gauthier's avatar
gauthier committed
921 922
    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);
923

924

925
    while (rxpos < (1+hw_subframe)*UE->lte_frame_parms.samples_per_tti) {
gauthier's avatar
gauthier committed
926
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ,1);
927

928 929
#ifndef USRP_DEBUG

930 931 932
      for (i=0; i<UE->lte_frame_parms.nb_antennas_rx; i++)
        rxp[i] = (dummy_dump==0) ? (void*)&rxdata[i][rxpos] : (void*)dummy[i];

933
      rxs = openair0.trx_read_func(&openair0,
934 935 936 937 938
                                   &timestamp,
                                   rxp,
                                   spp - ((first_rx==1) ? rx_off_diff : 0),
                                   UE->lte_frame_parms.nb_antennas_rx);

939
      if (rxs != (spp- ((first_rx==1) ? rx_off_diff : 0)))
940
        exit_fun("problem in rx");
941 942

      rx_off_diff = 0;
gauthier's avatar
gauthier committed
943
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ,0);
944

945 946
      // Transmit TX buffer based on timestamp from RX
      if (tx_enabled) {
gauthier's avatar
gauthier committed
947
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE,1);
948 949 950 951 952 953 954 955 956 957 958

        for (i=0; i<UE->lte_frame_parms.nb_antennas_tx; i++)
          txp[i] = (void*)&txdata[i][txpos];

        openair0.trx_write_func(&openair0,
                                (timestamp+spp*tx_delay-tx_forward_nsamps),
                                txp,
                                spp,
                                UE->lte_frame_parms.nb_antennas_tx,
                                1);

gauthier's avatar
gauthier committed
959
        VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE,0);
960
      }
961

962 963 964 965 966
#else
      rt_sleep_ns(1000000);
#endif
      rxpos+=spp;
      txpos+=spp;
967

968
      if(txpos >= 10*PHY_vars_UE_g[0][0]->lte_frame_parms.samples_per_tti)
969
        txpos -= 10*PHY_vars_UE_g[0][0]->lte_frame_parms.samples_per_tti;
970
    }
971

972 973 974 975 976 977 978
    if(rxpos >= 10*PHY_vars_UE_g[0][0]->lte_frame_parms.samples_per_tti)
      rxpos -= 10*PHY_vars_UE_g[0][0]->lte_frame_parms.samples_per_tti;

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

      if (start_rx_stream==1) {
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
        //  printf("UE_thread: locking UE mutex_rx\n");
        if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
          LOG_E(PHY,"[SCHED][UE] error locking mutex for UE RX thread\n");
          exit_fun("nothing to add");
        } else {

          UE->instance_cnt_rx++;
          //    printf("UE_thread: Unlocking UE mutex_rx\n");
          pthread_mutex_unlock(&UE->mutex_rx);

          if (UE->instance_cnt_rx == 0) {
            // LOG_D(HW,"Scheduling UE RX for frame %d (hw frame %d), subframe %d (%d), mode %d\n",UE->frame_rx,frame,hw_subframe,UE->slot_rx>>1,mode);
            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");
            } else {
              //        printf("UE_thread: cond_signal for RX ok (%p) @ %llu\n",(void*)&UE->cond_rx,rt_get_time_ns()-T0);
            }

            if (UE->mode == rx_calib_ue) {
              if (frame == 10) {
                LOG_D(PHY,
                      "[SCHED][UE] Found cell with N_RB_DL %d, PHICH CONFIG (%d,%d), Nid_cell %d, NB_ANTENNAS_TX %d, initial frequency offset %d Hz, frequency offset %d Hz, RSSI (digital) %d dB, measured Gain %d dB, total_rx_gain %d dB, USRP rx gain %f dB\n",
                      UE->lte_frame_parms.N_RB_DL,
                      UE->lte_frame_parms.phich_config_common.phich_duration,
                      UE->lte_frame_parms.phich_config_common.phich_resource,
                      UE->lte_frame_parms.Nid_cell,
                      UE->lte_frame_parms.nb_antennas_tx_eNB,
                      openair_daq_vars.freq_offset,
                      UE->lte_ue_common_vars.freq_offset,
                      UE->PHY_measurements.rx_power_avg_dB[0],
                      UE->PHY_measurements.rx_power_avg_dB[0] - rx_input_level_dBm,
                      UE->rx_total_gain_dB,
                      openair0_cfg[0].rx_gain[0]
1013
		      );
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
                exit_fun("[HW][UE] UE in RX calibration mode, exiting");
              }
            }
          } else {
            LOG_E(PHY,"[SCHED][UE] UE RX thread busy!!\n");
            exit_fun("nothing to add");
          }
        }

        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");
        } else {

          if (tx_enabled == 1) {
            UE->instance_cnt_tx++;
            //printf("UE_thread: Unlocking UE mutex_rx\n");
            pthread_mutex_unlock(&UE->mutex_tx);

            if (UE->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");
                exit_fun("nothing to add");
              } else {
                //        printf("UE_thread: cond_signal for RX ok (%p) @ %llu\n",(void*)&UE->cond_rx,rt_get_time_ns()-T0);
              }
            } else {
              LOG_E(PHY,"[SCHED][UE] UE TX thread busy!!\n");
              exit_fun("nothing to add");
            }
          }
        }
1046
      }
1047
    } else { // we are not yet synchronized
1048
      if ((hw_subframe == 9)&&(dummy_dump == 0)) {
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
        // Wake up initial synch thread
        if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
          LOG_E(PHY,"[SCHED][UE] error locking mutex for UE initial synch thread\n");
          exit_fun("nothing to add");
        } else {

          UE->instance_cnt_synch++;
          pthread_mutex_unlock(&UE->mutex_synch);
          dummy_dump = 1;

          if (UE->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");
              exit_fun("nothing to add");
            }
          } else {
            LOG_E(PHY,"[SCHED][UE] UE sync thread busy!!\n");
            exit_fun("nothing to add");
          }
        }
1069 1070
      }
    }
1071

1072 1073
    hw_subframe++;
    slot+=2;
1074

1075 1076 1077 1078 1079
    if(hw_subframe==10) {
      hw_subframe = 0;
      first_rx = 1;
      frame++;
      slot = 1;
1080

1081
      if (UE->instance_cnt_synch < 0) {
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
        if (UE->is_synchronized == 1) {
          //    openair0_set_gains(&openair0,&openair0_cfg[0]);
          rx_off_diff = 0;

          //    LOG_D(PHY,"HW RESYNC: hw_frame %d: rx_offset = %d\n",frame,UE->rx_offset);
          if ((UE->rx_offset > RX_OFF_MAX)&&(start_rx_stream==0)) {
            start_rx_stream=1;
            //LOG_D(PHY,"HW RESYNC: hw_frame %d: Resynchronizing sample stream\n");
            frame=0;
            // dump ahead in time to start of frame
1092 1093

#ifndef USRP_DEBUG
1094 1095 1096 1097 1098
            rxs = openair0.trx_read_func(&openair0,
                                         &timestamp,
                                         (void**)rxdata,
                                         UE->rx_offset,
                                         UE->lte_frame_parms.nb_antennas_rx);
1099
#else
1100
            rt_sleep_ns(10000000);
1101
#endif
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
            UE->rx_offset=0;
            tx_enabled=1;
          } else if ((UE->rx_offset < RX_OFF_MIN)&&(start_rx_stream==1) && (rx_correction_timer == 0)) {
            rx_off_diff = -UE->rx_offset + RX_OFF_MIN;
            rx_correction_timer = 5;
          } else if ((UE->rx_offset > (FRAME_LENGTH_COMPLEX_SAMPLES-RX_OFF_MAX)) &&(start_rx_stream==1) && (rx_correction_timer == 0)) {
            rx_off_diff = FRAME_LENGTH_COMPLEX_SAMPLES-UE->rx_offset;
            rx_correction_timer = 5;
          }

          if (rx_correction_timer>0)
            rx_correction_timer--;

          //    LOG_D(PHY,"HW RESYNC: hw_frame %d: (rx_offset %d) Correction: rx_off_diff %d (timer %d)\n",frame,UE->rx_offset,rx_off_diff,rx_correction_timer);
        }

        dummy_dump=0;
1119 1120
      }
    }
1121

1122 1123 1124 1125
#if defined(ENABLE_ITTI)
    itti_update_lte_time(frame, slot);
#endif
  }
1126

1127 1128 1129 1130 1131 1132 1133 1134
  return(0);
}
#endif



#ifdef EXMIMO
/* This is the main UE thread. Initially it is doing a periodic get_frame. One synchronized it gets woken up by the kernel driver using the RTAI message mechanism (rt_send and rt_receive). */
1135 1136
void *UE_thread(void *arg)
{
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
  PHY_VARS_UE *UE=PHY_vars_UE_g[0][0];
#ifdef RTAI
  RT_TASK *task;
#endif
  // RTIME in, out, diff;
  int slot=0,frame=0,hw_slot,last_slot,next_slot;
  // unsigned int aa;
  int delay_cnt;
  RTIME time_in;
  int hw_slot_offset=0,rx_offset_mbox=0,mbox_target=0,mbox_current=0;
  int diff2;
  int i, ret;
  int CC_id,card;
  volatile unsigned int *DAQ_MBOX = openair0_daq_cnt();

  int wait_sync_cnt = 0;
  int first_synch = 1;
#ifdef LOWLATENCY
  struct sched_attr attr;
  unsigned int flags = 0;
1157
  unsigned long mask = 1; // processor 0
1158 1159 1160 1161 1162 1163
#endif



#ifdef RTAI
  task = rt_task_init_schmod(nam2num("UE thread"), 0, 0, 0, SCHED_FIFO, 0xF);
1164

1165 1166 1167 1168
  if (task==NULL) {
    LOG_E(PHY,"[SCHED][UE] Problem starting UE thread!!!!\n");
    return 0;
  }
1169

1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
#endif


#ifdef HARD_RT
  rt_make_hard_real_time();
#endif


#ifdef LOWLATENCY
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;
1183

1184 1185
  // This creates a .25 ms  reservation
  attr.sched_policy = SCHED_DEADLINE;
1186
  attr.sched_runtime  = 0.1 * 1000000;
1187 1188
  attr.sched_deadline = 0.25 * 1000000;
  attr.sched_period   = 0.5 * 1000000;
1189

1190 1191 1192 1193
  // pin the UE main thread to CPU0
  // if (pthread_setaffinity_np(pthread_self(), sizeof(mask),&mask) <0) {
  //   perror("[MAIN_ENB_THREAD] pthread_setaffinity_np failed\n");
  //   }
1194 1195

  if (sched_setattr(0, &attr, flags) < 0 ) {
1196 1197 1198 1199
    perror("[SCHED] main UE thread: sched_setattr failed\n");
    exit_fun("Nothing to add");
  } else {
    LOG_I(HW,"[SCHED][eNB] eNB main deadline thread %ld started on CPU %d\n",
1200
          gettid(),sched_getcpu());
1201
  }
1202

1203
#endif
1204

1205 1206 1207 1208 1209 1210 1211

  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");
1212

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

1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread)\n");

  printf("starting UE thread\n");

  openair_daq_vars.freq_offset = 0; //-7500;

  first_synch = 1;

  while (!oai_exit)  {

    hw_slot = (((((volatile unsigned int *)DAQ_MBOX)[0]+1)%150)<<1)/15; //the slot the hw is about to store

1229

1230 1231 1232
    if (UE->is_synchronized) {

      if (first_synch == 1) {
1233 1234 1235
        first_synch = 0;

        for (card=0; card<openair0_num_detected_cards; card++)
1236
          openair0_start_rt_acquisition(card);
1237 1238

        rt_sleep_ns(FRAME_PERIOD/10);
1239 1240 1241 1242
      }

      //this is the mbox counter that indicates the start of the frame
      rx_offset_mbox = (UE->rx_offset * 150) / (10*UE->lte_frame_parms.samples_per_tti);
gauthier's avatar
gauthier committed
1243 1244
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_RX_OFFSET, UE->rx_offset);
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_OFFSET_MBOX, rx_offset_mbox);
1245 1246 1247 1248 1249 1250
      //this is the mbox counter where we should be
      mbox_target = (((((slot+1)%20)*15+1)>>1) + rx_offset_mbox + 1)%150;
      // round up to the next multiple of two (mbox counter from express MIMO gives only even numbers)
      mbox_target = ((mbox_target+1)-((mbox_target-1)%2))%150;
      //this is the mbox counter where we are
      mbox_current = ((volatile unsigned int *)DAQ_MBOX)[0];
1251

1252 1253
      //this is the time we need to sleep in order to synchronize with the hw (in multiples of DAQ_PERIOD)
      if ((mbox_current>=120) && (mbox_target<30)) //handle the frame wrap-arround
1254
        diff2 = 150-mbox_current+mbox_target;
1255
      else if ((mbox_current<30) && (mbox_target>=120))
1256
        diff2 = -150+mbox_target-mbox_current;
1257
      else
1258 1259
        diff2 = mbox_target - mbox_current;

1260
      if (diff2 <(-7)) {
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
        LOG_D(HW,"UE Frame %d: missed slot, proceeding with next one (slot %d, hw_slot %d, diff %d)\n",frame, slot, hw_slot, diff2);

        if (frame>0) {
          if (exit_missed_slots==1)
            exit_fun("[HW][UE] missed slot");
          else {
            num_missed_slots++;
            LOG_W(HW,"[UE] just missed slot (total missed slots %ld)\n", num_missed_slots);
          }
        }

1272
        slot++;
1273

1274 1275 1276 1277
        if (slot==20) {
          slot=0;
          frame++;
        }
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293

        // update thread slot/frame counters because of skipped slot
        UE->slot_rx++;
        UE->slot_tx++;

        if (UE->slot_rx == 20) {
          UE->slot_rx = 0;
          UE->frame_rx++;
        }

        if (UE->slot_tx == 20) {
          UE->slot_tx = 0;
          UE->frame_tx++;
        }

        continue;
1294
      }
1295

1296
      if (diff2>8)
1297 1298 1299
        LOG_D(HW,"UE Frame %d: skipped slot, waiting for hw to catch up (slot %d, hw_slot %d, mbox_current %d, mbox_target %d, diff %d)\n",frame, slot, hw_slot, mbox_current, mbox_target, diff2);


gauthier's avatar
gauthier committed
1300 1301
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DAQ_MBOX, *DAQ_MBOX);
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(