lte-ue.c 62.3 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"
knopp's avatar
   
knopp committed
62
#ifdef OPENAIR2
63
64
#include "LAYER2/MAC/defs.h"
#include "RRC/LITE/extern.h"
knopp's avatar
   
knopp committed
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"
knopp's avatar
   
knopp committed
81
#ifdef OPENAIR2
82
83
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/proto.h"
knopp's avatar
   
knopp committed
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
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;

122
123
//extern unsigned int tx_forward_nsamps;
//extern int tx_delay;
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

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;

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

195
196
/*!
 * \brief This is the UE synchronize thread.
197
 * It performs band scanning and synchonization.
198
199
200
 * \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.
 */
201
202
static void *UE_thread_synch(void *arg)
{
203
204
205
  static int UE_thread_synch_retval;
  int i, hw_slot_offset;
  PHY_VARS_UE *UE = (PHY_VARS_UE*) arg;
206
207
  int current_band = 0;
  int current_offset = 0;
208
  sync_mode_t sync_mode = pbch;
209
  int card;
210
211
  int ind;
  int found;
212
  int freq_offset=0;
213
214
215
216
217
218
219

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

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

224
225
226
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex (UE_sync_thread)\n");

227
  printf("starting UE synch thread (IC %d)\n",UE->instance_cnt_synch);
228
229
  ind = 0;
  found = 0;
230
231


232
233
  if (UE->UE_scan == 0) {
    do  {
234
      current_band = eutra_bands[ind].band;
knopp's avatar
   
knopp committed
235
      printf( "Scanning band %d, dl_min %"PRIu32", ul_min %"PRIu32"\n", current_band, eutra_bands[ind].dl_min,eutra_bands[ind].ul_min);
236

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

246
      ind++;
247
248
    } while (ind < sizeof(eutra_bands) / sizeof(eutra_bands[0]));
  
249
250
    if (found == 0) {
      exit_fun("Can't find EUTRA band for frequency");
251
      return &UE_thread_synch_retval;
252
    }
253

254
255


256

257
258


knopp's avatar
   
knopp committed
259
    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 );
260
261
262
263
264
265
266

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

267
    sync_mode = pbch;
268

269
  } else if  (UE->UE_scan == 1) {
270
    current_band=0;
271

272
    for (card=0; card<MAX_CARDS; card++) {
273
      for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
274
275
276
277
278
        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];
279
#ifdef OAI_USRP
280
        openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
281

282
	
283
284
285
286
287
288
289
290
291
292
293
294
295
        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;

296
297
298
299
        case 100:
          openair0_cfg[card].rx_gain[i] -= 0;
          break;

300
        default:
301
          printf( "Unknown number of RBs %d\n", UE->lte_frame_parms.N_RB_DL );
302
303
          break;
        }
304
	
305
        printf( "UE synch: setting RX gain (%d,%d) to %f\n", card, i, openair0_cfg[card].rx_gain[i] );
306
307
#endif
      }
308
309
310
    }

  }
311
312

  while (oai_exit==0) {
313

314
    if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
315
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE initial synch thread\n" );
316
      exit_fun("noting to add");
317
318
      return &UE_thread_synch_retval;
    }
319
    
320

321
    while (UE->instance_cnt_synch < 0) {
322
      // the thread waits here most of the time
323
324
      pthread_cond_wait( &UE->cond_synch, &UE->mutex_synch );
    }
325

326
327
328
329
330
    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;
    }
331

332
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH, 1 );
333
334

    switch (sync_mode) {
335
    case pss:
336
337
      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);
338
339
340
341
342
343
344
      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;
      }

345
      if (current_band==bands_to_scan.nbands) {
346
347
        current_band=0;
        oai_exit=1;
348
      }
349
350
351
352
353
354
355

      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;


356
357
          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];
358
#ifdef OAI_USRP
359
360
          openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;  // 65 calibrated for USRP B210 @ 2.6 GHz
	  
361
362
363
364
365
366
367
368
369
370
371
372
373
          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;

374
375
376
377
          case 100:
            openair0_cfg[card].rx_gain[i] -= 0;
            break;

378
379
380
381
          default:
            printf("Unknown number of RBs %d\n",UE->lte_frame_parms.N_RB_DL);
            break;
          }
382
	  
383
384

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

387
        }
388
389
390

      }

391
      if (UE->UE_scan_carrier) {
392

393
394
395
396
	for (i=0;i<openair0_cfg[0].rx_num_channels;i++)
	  openair0_cfg[0].autocal[i] = 1;

      }
397

398
399
400

      break;
 
401
    case pbch:
402

403
      
404
      if (initial_sync( UE, UE->mode ) == 0) {
405
406
407
408
409
410
411
412
413
414
415
416
417
418

        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 );
	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++) {
	    openair0_cfg[0].rx_freq[i] -= UE->lte_ue_common_vars.freq_offset;
	    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;	    
	  }

419
	  // reconfigure for potentially different bandwidth
420
421
422
	  switch(UE->lte_frame_parms.N_RB_DL) {
	  case 6:
	    openair0_cfg[0].sample_rate =1.92e6;
423
424
	    openair0_cfg[0].rx_bw          =.96e6;
	    openair0_cfg[0].tx_bw          =.96e6;
425
            openair0_cfg[0].rx_gain[0] -= 12;
426
427
	    break;
	  case 25:
428
429
430
	    openair0_cfg[0].sample_rate =7.68e6;
	    openair0_cfg[0].rx_bw          =2.5e6;
	    openair0_cfg[0].tx_bw          =2.5e6;
431
            openair0_cfg[0].rx_gain[0] -= 6;
432
433
	    break;
	  case 50:
434
435
436
	    openair0_cfg[0].sample_rate =15.36e6;
	    openair0_cfg[0].rx_bw          =5.0e6;
	    openair0_cfg[0].tx_bw          =5.0e6;
437
            openair0_cfg[0].rx_gain[0] -= 3;
438
439
440
	    break;
	  case 100:
	    openair0_cfg[0].sample_rate=30.72e6;
441
442
	    openair0_cfg[0].rx_bw=10.0e6;
	    openair0_cfg[0].tx_bw=10.0e6;
443
            openair0_cfg[0].rx_gain[0] -= 0;
444
445
	    break;
	  }
446
447
448
449
	  openair0_set_frequencies(&openair0,&openair0_cfg[0],0);
	  openair0_set_gains(&openair0,&openair0_cfg[0]);
	  openair0_stop(0);
	  sleep(1);
450
451
452
453
454

	  init_frame_parms(&UE->lte_frame_parms,1);
	}
	else {
	  UE->is_synchronized = 1;
455
456

	 if( UE->mode == rx_dump_frame ){
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
	   FILE *fd;
	   if ((UE->frame_rx&1) == 0) {  // this guarantees SIB1 is present 
	     if (fd = fopen("rxsig_frame0.dat","w")) {
	       fwrite((void*)&UE->lte_ue_common_vars.rxdata[0][0],
		      sizeof(int32_t),
		      10*UE->lte_frame_parms.samples_per_tti,
		      fd);
	       LOG_I(PHY,"Dummping Frame ... bye bye \n");
	       fclose(fd);
	       exit(0);
	     }
	     else {
	       LOG_E(PHY,"Cannot open file for writing\n");
	       exit(0);
	     }
	   }
	   else {
	     UE->is_synchronized = 0;
	   }
476
	 }
477
	 
478

479
#ifndef EXMIMO
480
481
	  UE->slot_rx = 0;
	  UE->slot_tx = 4;
482
#else
483
484
	  UE->slot_rx = 18;
	  UE->slot_tx = 2;
485
#endif
486
	}
487
488
489
      } else {
        // initial sync failed
        // calculate new offset and try again
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
	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" );
	    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,
509
               UE->rx_total_gain_dB,
510
511
               downlink_frequency[0][0]+freq_offset,
               downlink_frequency[0][0]+uplink_frequency_offset[0][0]+freq_offset );
512
513
514

        for (card=0; card<MAX_CARDS; card++) {
          for (i=0; i<openair0_cfg[card].rx_num_channels; i++) {
515
516
            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;
517
#ifdef OAI_USRP
518
            openair0_cfg[card].rx_gain[i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
519

520
521
	    openair0_set_frequencies(&openair0,&openair0_cfg[0],0);

522
	    
523
524
525
526
527
528
529
530
531
532
            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:
533
534
535
536
537
              openair0_cfg[card].rx_gain[i] -= 0;//3;
              break;

            case 100:
              openair0_cfg[card].rx_gain[i] -= 0;
538
539
540
541
542
543
              break;

            default:
              printf("Unknown number of RBs %d\n",UE->lte_frame_parms.N_RB_DL);
              break;
            }
544
	    
545
#endif
546
547
          }
        }
548
549
550
551
552
553
	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
554

555
      break;
556

557
558
559
560
    case si:
    default:
      break;
    }
561

562
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH, 0 );
knopp's avatar
   
knopp committed
563

564
565


566
    if (pthread_mutex_lock(&UE->mutex_synch) != 0) {
567
568
569
570
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE synch\n" );
      exit_fun("noting to add");
      return &UE_thread_synch_retval;
    }
571

572
    // indicate readiness
573
574
575
576
577
578
    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;
579
    }
580

581
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SYNCH, 0 );
582
  }  // while !oai_exit
583

584
  return &UE_thread_synch_retval;
585
586
}

587
588
589
590
591
592
/*!
 * \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.
 */
593
594
static void *UE_thread_tx(void *arg)
{
595
  static int UE_thread_tx_retval;
596
597
598
599
600
601
602
  int ret;

  PHY_VARS_UE *UE = (PHY_VARS_UE*)arg;

  UE->instance_cnt_tx=-1;

#ifdef RTAI
603
  RT_TASK *task = rt_task_init_schmod(nam2num("UE TX Thread"), 0, 0, 0, SCHED_FIFO, 0xF);
604

605
606
607
608
  if (task==NULL) {
    LOG_E(PHY,"[SCHED][UE] Problem starting UE TX thread!!!!\n");
    return 0;
  }
609

610
611
612
613
  LOG_D(HW,"Started UE TX thread (id %p)\n",task);
#else

#ifdef LOWLATENCY
614
615
616
  struct sched_attr attr;
  unsigned int flags = 0;

617
618
619
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
620
  attr.sched_priority = 0;
621

622
  /* This creates a 1ms reservation every 10ms period*/
623
624
625
626
  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
627

628
629

  if (sched_setattr(0, &attr, flags) < 0 ) {
knopp's avatar
knopp committed
630
    perror("[SCHED] UE_thread_tx thread: sched_setattr failed\n");
631
    return &UE_thread_tx_retval;
632
  }
633

634
635
636
637
638
#else
  struct sched_param sp;
  sp.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
  pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);

639
640
#endif
#endif
641

642
643
644
645
  printf("waiting for sync (UE_thread_tx)\n");

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

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

650
651
652
653
654
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread_tx)\n");

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

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

  while (!oai_exit) {

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

666
667
668
    while (UE->instance_cnt_tx < 0) {
      // most of the time, the thread is waiting here
      pthread_cond_wait( &UE->cond_tx, &UE->mutex_tx );
669
    }
670

671
672
673
674
675
    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;
    }
676
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_TX, 1 );
677

678
    if ((subframe_select( &UE->lte_frame_parms, UE->slot_tx>>1 ) == SF_UL) ||
679
        (UE->lte_frame_parms.frame_type == FDD)) {
680
      phy_procedures_UE_TX( UE, 0, 0, UE->mode, no_relay );
681
    }
682

683
684
685
    if ((subframe_select( &UE->lte_frame_parms, UE->slot_tx>>1 ) == SF_S) &&
        ((UE->slot_tx&1) == 1)) {
      phy_procedures_UE_S_TX( UE, 0, 0, no_relay );
686
    }
687

688
689
690
691
692
693
694
695
696
697
698
    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 );
699

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

706
    UE->instance_cnt_tx--;
707
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_TX, UE->instance_cnt_tx);
708
709
710
711
712

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

715
  }
716

717
  return &UE_thread_tx_retval;
718
719
}

720
721
722
723
724
725
/*!
 * \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.
 */
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746

#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

747
748
static void *UE_thread_rx(void *arg)
{
749
  static int UE_thread_rx_retval;
750
751
752
  PHY_VARS_UE *UE = (PHY_VARS_UE*)arg;
  int i;
  int ret;
753

754
755
756
  UE->instance_cnt_rx=-1;

#ifdef RTAI
757
  RT_TASK *task = rt_task_init_schmod(nam2num("UE RX Thread"), 0, 0, 0, SCHED_FIFO, 0xF);
758

759
760
  if (task==NULL) {
    LOG_E(PHY,"[SCHED][UE] Problem starting UE RX thread!!!!\n");
761
    return &UE_thread_rx_retval;
762
  }
763

764
765
  LOG_D(HW,"Started UE RX thread (id %p)\n",task);
#else
766

767
#ifdef LOWLATENCY
768
769
770
  struct sched_attr attr;
  unsigned int flags = 0;

771
772
773
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
774
  attr.sched_priority = 0;
775

776
  // This creates a .5ms reservation every 1ms period
777
778
779
780
  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
781
782

  if (sched_setattr(0, &attr, flags) < 0 ) {
knopp's avatar
knopp committed
783
    perror("[SCHED] UE_thread_rx : sched_setattr failed\n");
784
    return &UE_thread_rx_retval;
785
786
  }

787
788
789
790
791
#else
  struct sched_param sp;
  sp.sched_priority = sched_get_priority_max(SCHED_FIFO)-1;
  pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);

792
793
#endif
#endif
794

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

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

800
801
  pthread_mutex_lock(&sync_mutex);
  printf("Locked sync_mutex, waiting (UE_thread_rx)\n");
802

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

806
807
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread_rx)\n");
808

809
  printf("Starting UE RX thread\n");
810
811

  while (!oai_exit) {
812
    if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
813
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX\n" );
814
      exit_fun("nothing to add");
815
      return &UE_thread_rx_retval;
816
    }
817
818

    while (UE->instance_cnt_rx < 0) {
819
820
      // most of the time, the thread is waiting here
      pthread_cond_wait( &UE->cond_rx, &UE->mutex_rx );
821
822
823
    }

    if (pthread_mutex_unlock(&UE->mutex_rx) != 0) {
824
      LOG_E( PHY, "[SCHED][UE] error unlocking mutex for UE RX\n" );
825
      exit_fun("nothing to add");
826
      return &UE_thread_rx_retval;
827
828
    }

829
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RX, 1 );
830
    for (i=0; i<2; i++) {
831
      if ((subframe_select( &UE->lte_frame_parms, UE->slot_rx>>1 ) == SF_DL) ||
832
          (UE->lte_frame_parms.frame_type == FDD)) {
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
#ifdef OAI_USRP
	// this does the adjustments of RX signal amplitude to bring into least 12 significant bits
	int slot_length = UE->lte_frame_parms.samples_per_tti>>1;
	int rx_offset = (UE->slot_rx)*slot_length + UE->rx_offset;
	int frame_length = UE->lte_frame_parms.samples_per_tti*10;
	int aa;
	if (rx_offset > frame_length)
	  rx_offset-=frame_length;


	if (rx_offset >= 0) {
	  if (rx_offset + slot_length < frame_length)
	    for (aa=0;aa<UE->lte_frame_parms.nb_antennas_rx;aa++)
	      rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][rx_offset&(~0x3)],
		      slot_length);
	  else {
	    int diff = rx_offset + slot_length - frame_length;
	    for (aa=0;aa<UE->lte_frame_parms.nb_antennas_rx;aa++){
	      rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][rx_offset&(~0x3)],
		      slot_length-diff);
	      rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][0],
		      diff);
	    }
	  }
	}
	else {
	    for (aa=0;aa<UE->lte_frame_parms.nb_antennas_rx;aa++){
	      rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][(frame_length+rx_offset)&(~0x3)],
		      -rx_offset);
	      rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][0],
		      slot_length+rx_offset);
	    }
	}
#endif
867
        phy_procedures_UE_RX( UE, 0, 0, UE->mode, no_relay, NULL );
868
      }
gauthier's avatar
gauthier committed
869

870
871
      if ((subframe_select( &UE->lte_frame_parms, UE->slot_rx>>1 ) == SF_S) &&
          ((UE->slot_rx&1) == 0)) {
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
#ifdef OAI_USRP
	// this does the adjustments of RX signal amplitude to bring into least 12 significant bits
	int slot_length = UE->lte_frame_parms.samples_per_tti>>1;
	int rx_offset = (UE->slot_rx)*slot_length + UE->rx_offset;
	int frame_length = UE->lte_frame_parms.samples_per_tti*10;
	if (rx_offset > frame_length)
	  rx_offset-=frame_length;
	int aa;

	if (rx_offset >= 0) {
	  if (rx_offset + slot_length < frame_length)
	    for (aa=0;aa<UE->lte_frame_parms.nb_antennas_rx;aa++)
	      rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][rx_offset&(~0x3)],
		      slot_length);
	  else {
	    int diff = rx_offset + slot_length - frame_length;
	    for (aa=0;aa<UE->lte_frame_parms.nb_antennas_rx;aa++){
	      rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][rx_offset&(~0x3)],
		      slot_length-diff);
	      rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][0],
		      diff);
	    }
	  }
	}
	else {
	  for (aa=0;aa<UE->lte_frame_parms.nb_antennas_rx;aa++){
	    rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][(frame_length+rx_offset)&(~0x3)],
		    -rx_offset);
	    rescale((int16_t*)&UE->lte_ue_common_vars.rxdata[aa][0],
		    slot_length+rx_offset);
	  }
	}
#endif
905
        phy_procedures_UE_RX( UE, 0, 0, UE->mode, no_relay, NULL );
906
907
908
909
910
911
912
913
914
915
916
917
918
      }

#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) {
919
          LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, returning to PRACH\n",
920
                 UE->Mod_id, UE->frame_rx, UE->slot_tx>>1 );
921
922
          UE->UE_mode[0] = PRACH;
        } else if (ret == PHY_RESYNCH) {
923
          LOG_E( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u RRC Connection lost, trying to resynch\n",
924
                 UE->Mod_id, UE->frame_rx, UE->slot_tx>>1 );
925
926
          UE->UE_mode[0] = RESYNCH;
        } else if (ret == PHY_HO_PRACH) {
927
          LOG_I( PHY, "[UE %"PRIu8"] Frame %"PRIu32", subframe %u, return to PRACH and perform a contention-free access\n",
928
                 UE->Mod_id, UE->frame_rx, UE->slot_tx>>1 );
929
930
          UE->UE_mode[0] = PRACH;
        }
931
      }
932
933
934
935

#endif
      UE->slot_rx++;

936
937
      if (UE->slot_rx == 20) {
        UE->slot_rx = 0;
938
        UE->frame_rx++;
939
        VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX_UE, UE->frame_rx );
940
941
      }

942
      VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX_UE, UE->slot_rx>>1 );
943
    }
944
945
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_THREAD_RX, 0 );

946
    if (pthread_mutex_lock(&UE->mutex_rx) != 0) {
947
948
949
      LOG_E( PHY, "[SCHED][UE] error locking mutex for UE RX\n" );
      exit_fun("noting to add");
      return &UE_thread_rx_retval;
950
951
    }

952
    UE->instance_cnt_rx--;
953
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_UE_INST_CNT_RX, UE->instance_cnt_rx);
954
955
956
957
958
959

    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;
    }
gauthier's avatar
gauthier committed
960
961
962
  }

  // thread finished
963
  return &UE_thread_rx_retval;
Florian Kaltenberger's avatar
   
Florian Kaltenberger committed
964
}
965

966
967
968
969
970
971
972
973



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

974
975
976
977
978
979
980
981
982
/*!
 * \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.
 */
983
984
void *UE_thread(void *arg)
{
985
986
987
  UNUSED(arg)
  static int UE_thread_retval;
  PHY_VARS_UE *UE = PHY_vars_UE_g[0][0];
988
  int spp = openair0_cfg[0].samples_per_packet;
989
  int slot=1, frame=0, hw_subframe=0, rxpos=0, txpos=spp*openair0_cfg[0].tx_delay;
990
991
  int dummy[2][spp];
  int dummy_dump = 0;
992
993
  int tx_enabled = 0;
  int start_rx_stream = 0;
994
995
  int rx_off_diff = 0;
  int rx_correction_timer = 0;
996
  int first_rx = 0;
997
  RTIME T0;
998
  unsigned int rxs;
999
1000
1001
1002

  openair0_timestamp timestamp;

#ifdef RTAI
1003
  RT_TASK *task = rt_task_init_schmod(nam2num("UE thread"), 0, 0, 0, SCHED_FIFO, 0xF);
1004

1005
1006
1007
1008
  if (task==NULL) {
    LOG_E(PHY,"[SCHED][UE] Problem starting UE thread!!!!\n");
    return 0;
  }
1009

1010
#else
1011

1012
#ifdef LOWLATENCY
1013
1014
1015
  struct sched_attr attr;
  unsigned int flags = 0;

1016
1017
1018
  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
1019
  attr.sched_priority = 0;//sched_get_priority_max(SCHED_DEADLINE);
1020

1021
1022
  // This creates a .5 ms  reservation
  attr.sched_policy = SCHED_DEADLINE;
1023
1024
1025
  attr.sched_runtime  = 100000;
  attr.sched_deadline = 500000;
  attr.sched_period   = 500000;
1026
1027

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

1035
1036
1037
1038
#else
  struct sched_param sp;
  sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
  pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);
1039
1040
1041
#endif
#endif

1042
  // Lock memory from swapping. This is a process wide call (not constraint to this thread).
1043
1044
1045
1046
1047
  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");
1048

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

1052
1053
1054
1055
1056
1057
1058
  pthread_mutex_unlock(&sync_mutex);
  printf("unlocked sync_mutex, waiting (UE_thread)\n");

  printf("starting UE thread\n");

  T0 = rt_get_time_ns();
  first_rx = 1;
1059
  rxpos=0;
1060

1061
  while (!oai_exit) {
1062
1063
    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 );
1064
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_DUMMY_DUMP, dummy_dump );
1065

1066

1067
    while (rxpos < (1+hw_subframe)*UE->lte_frame_parms.samples_per_tti) {
1068
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
1069

1070
1071
#ifndef USRP_DEBUG

1072
1073
      DevAssert( UE->lte_frame_parms.nb_antennas_rx <= 2 );
      void* rxp[2];
1074

1075
      for (int i=0; i<UE->lte_frame_parms.nb_antennas_rx; i++)
1076
        rxp[i] = (dummy_dump==0) ? (void*)&rxdata[i][rxpos] : (void*)dummy[i];
1077
      
1078
1079
1080
      /*      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);
      */
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
      if (UE->mode != loop_through_memory) {
	rxs = openair0.trx_read_func(&openair0,
				     &timestamp,
				     rxp,
				     spp - ((first_rx==1) ? rx_off_diff : 0),
				     UE->lte_frame_parms.nb_antennas_rx);

	if (rxs != (spp- ((first_rx==1) ? rx_off_diff : 0))) {
	  exit_fun("problem in rx");
	  return &UE_thread_retval;
	}
1092
      }
1093

1094
      if (rx_off_diff !=0)
1095
	LOG_D(PHY,"frame %d, rx_offset %d, rx_off_diff %d\n",UE->frame_rx,UE->rx_offset,rx_off_diff);
1096

1097
      VCD_SIGNAL_