openair0_lib.c 29.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
    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

ghaddab's avatar
ghaddab committed
26
   Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
27
28

 *******************************************************************************/
29
30
31
32
33
34
35
36
37
38

/** openair0_lib : API to interface with ExpressMIMO-1&2 kernel driver
*
*  Authors: Matthias Ihmig <matthias.ihmig@mytum.de>, 2013
*           Raymond Knopp <raymond.knopp@eurecom.fr>
*
*  Changelog:
*  28.01.2013: Initial version
*/

39
#define _GNU_SOURCE
40
#include <stdio.h>
knopp's avatar
   
knopp committed
41
#include <stdlib.h>
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h> 
#include <sys/types.h>
#include <sys/mman.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <sys/sysinfo.h>
#include <sys/ioctl.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <syscall.h>
60
61
62

#include "openair0_lib.h"
#include "openair_device.h"
knopp's avatar
   
knopp committed
63
#include "common_lib.h"
64
65
66

#include <pthread.h>

Raymond Knopp's avatar
Raymond Knopp committed
67

knopp's avatar
   
knopp committed
68
#define max(a,b) ((a)>(b) ? (a) : (b))
Raymond Knopp's avatar
Raymond Knopp committed
69
70


71
exmimo_pci_interface_bot_virtual_t openair0_exmimo_pci[MAX_CARDS]; // contains userspace pointers for each card
72
73
74
75
76
77
78
79
80

char *bigshm_top[MAX_CARDS] = INIT_ZEROS;

int openair0_fd;
int openair0_num_antennas[MAX_CARDS];
int openair0_num_detected_cards = 0;

unsigned int PAGE_SHIFT;

knopp's avatar
   
knopp committed
81
static uint32_t                      rf_local[4] =       {8255000,8255000,8255000,8255000}; // UE zepto
82
83
//{8254617, 8254617, 8254617, 8254617}; //eNB khalifa
//{8255067,8254810,8257340,8257340}; // eNB PETRONAS
knopp's avatar
   
knopp committed
84
85
86
87

static uint32_t                      rf_vcocal[4] =      {910,910,910,910};
static uint32_t                      rf_vcocal_850[4] =  {2015, 2015, 2015, 2015};
static uint32_t                      rf_rxdc[4] =        {32896,32896,32896,32896};
88

89
90
91
92
93
94
95


extern volatile int                    oai_exit;


void kill_watchdog(openair0_device *);
void create_watchdog(openair0_device *);
Raymond Knopp's avatar
Raymond Knopp committed
96
void rt_sleep(struct timespec *,long );
97

98
99
100
unsigned int log2_int( unsigned int x )
{
  unsigned int ans = 0 ;
101

102
  while( x>>=1 ) ans++;
103

104
105
106
107
108
  return ans ;
}

int openair0_open(void)
{
109
110
  exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS];
  void *bigshm_top_kvirtptr[MAX_CARDS];
knopp's avatar
   
knopp committed
111

112
113
  int card;
  int ant;
knopp's avatar
   
knopp committed
114

115
  PAGE_SHIFT = log2_int( sysconf( _SC_PAGESIZE ) );
knopp's avatar
   
knopp committed
116

117

118
119
120
  if ((openair0_fd = open("/dev/openair0", O_RDWR,0)) <0) {
    return -1;
  }
knopp's avatar
   
knopp committed
121

122
  ioctl(openair0_fd, openair_GET_NUM_DETECTED_CARDS, &openair0_num_detected_cards);
knopp's avatar
   
knopp committed
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
  if ( openair0_num_detected_cards == 0 ) {
    fprintf(stderr, "No cards detected!\n");
    return -4;
  }

  ioctl(openair0_fd, openair_GET_BIGSHMTOPS_KVIRT, &bigshm_top_kvirtptr[0]);
  ioctl(openair0_fd, openair_GET_PCI_INTERFACE_BOTS_KVIRT, &exmimo_pci_kvirt[0]);

  //printf("bigshm_top_kvirtptr (MAX_CARDS %d): %p  %p  %p  %p\n", MAX_CARDS,bigshm_top_kvirtptr[0], bigshm_top_kvirtptr[1], bigshm_top_kvirtptr[2], bigshm_top_kvirtptr[3]);



  for( card=0; card < openair0_num_detected_cards; card++) {
    bigshm_top[card] = (char *)mmap( NULL,
                                     BIGSHM_SIZE_PAGES<<PAGE_SHIFT,
                                     PROT_READ|PROT_WRITE,
                                     MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
                                     openair0_fd,
                                     ( openair_mmap_BIGSHM | openair_mmap_Card(card) )<<PAGE_SHIFT);

    if (bigshm_top[card] == MAP_FAILED) {
      openair0_close();
      return -2;
    }

    // calculate userspace addresses
knopp's avatar
   
knopp committed
152
#if __x86_64
153
154
155
156
    openair0_exmimo_pci[card].firmware_block_ptr = (bigshm_top[card] +  (int64_t)exmimo_pci_kvirt[0].firmware_block_ptr - (int64_t)bigshm_top_kvirtptr[0]);
    openair0_exmimo_pci[card].printk_buffer_ptr  = (bigshm_top[card] +  (int64_t)exmimo_pci_kvirt[0].printk_buffer_ptr  - (int64_t)bigshm_top_kvirtptr[0]);
    openair0_exmimo_pci[card].exmimo_config_ptr  = (exmimo_config_t*) (bigshm_top[card] +  (int64_t)exmimo_pci_kvirt[0].exmimo_config_ptr  - (int64_t)bigshm_top_kvirtptr[0]);
    openair0_exmimo_pci[card].exmimo_id_ptr      = (exmimo_id_t*)     (bigshm_top[card] +  (int64_t)exmimo_pci_kvirt[0].exmimo_id_ptr      - (int64_t)bigshm_top_kvirtptr[0]);
knopp's avatar
   
knopp committed
157
#else
158
159
160
161
    openair0_exmimo_pci[card].firmware_block_ptr = (bigshm_top[card] +  (int32_t)exmimo_pci_kvirt[0].firmware_block_ptr - (int32_t)bigshm_top_kvirtptr[0]);
    openair0_exmimo_pci[card].printk_buffer_ptr  = (bigshm_top[card] +  (int32_t)exmimo_pci_kvirt[0].printk_buffer_ptr  - (int32_t)bigshm_top_kvirtptr[0]);
    openair0_exmimo_pci[card].exmimo_config_ptr  = (exmimo_config_t*) (bigshm_top[card] +  (int32_t)exmimo_pci_kvirt[0].exmimo_config_ptr  - (int32_t)bigshm_top_kvirtptr[0]);
    openair0_exmimo_pci[card].exmimo_id_ptr      = (exmimo_id_t*)     (bigshm_top[card] +  (int32_t)exmimo_pci_kvirt[0].exmimo_id_ptr      - (int32_t)bigshm_top_kvirtptr[0]);
knopp's avatar
   
knopp committed
162
163
#endif

164
165
166
167
168
169
170
171
172
173
174
175
176
177
    /*
          printf("openair0_exmimo_pci.firmware_block_ptr (%p) =  bigshm_top(%p) + exmimo_pci_kvirt.firmware_block_ptr(%p) - bigshm_top_kvirtptr(%p)\n",
              openair0_exmimo_pci[card].firmware_block_ptr, bigshm_top, exmimo_pci_kvirt[card].firmware_block_ptr, bigshm_top_kvirtptr[card]);
          printf("card%d, openair0_exmimo_pci.exmimo_id_ptr      (%p) =  bigshm_top(%p) + exmimo_pci_kvirt.exmimo_id_ptr     (%p) - bigshm_top_kvirtptr(%p)\n",
              card, openair0_exmimo_pci[card].exmimo_id_ptr, bigshm_top[card], exmimo_pci_kvirt[card].exmimo_id_ptr, bigshm_top_kvirtptr[card]);
    */

    /*
    if (openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev != BOARD_SWREV_CNTL2)
      {
        error("Software revision %d and firmware revision %d do not match, Please update either Software or Firmware",BOARD_SWREV_CNTL2,openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev);
        return -5;
      }
    */
knopp's avatar
   
knopp committed
178

179
180
    if ( openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion == 1)
      openair0_num_antennas[card] = 2;
181

182
183
    if ( openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion == 2)
      openair0_num_antennas[card] = 4;
184

ghaddab's avatar
   
ghaddab committed
185

186
    for (ant=0; ant<openair0_num_antennas[card]; ant++) {
knopp's avatar
   
knopp committed
187
#if __x86_64__
188
189
      openair0_exmimo_pci[card].rxcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] +  (int64_t)exmimo_pci_kvirt[card].rxcnt_ptr[ant] - (int64_t)bigshm_top_kvirtptr[card]);
      openair0_exmimo_pci[card].txcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] +  (int64_t)exmimo_pci_kvirt[card].txcnt_ptr[ant] - (int64_t)bigshm_top_kvirtptr[card]);
knopp's avatar
   
knopp committed
190
#else
191
192
      openair0_exmimo_pci[card].rxcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] +  (int32_t)exmimo_pci_kvirt[card].rxcnt_ptr[ant] - (int32_t)bigshm_top_kvirtptr[card]);
      openair0_exmimo_pci[card].txcnt_ptr[ant] = (unsigned int *) (bigshm_top[card] +  (int32_t)exmimo_pci_kvirt[card].txcnt_ptr[ant] - (int32_t)bigshm_top_kvirtptr[card]);
knopp's avatar
   
knopp committed
193
#endif
194
    }
195

196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
    for (ant=0; ant<openair0_num_antennas[card]; ant++) {
      openair0_exmimo_pci[card].adc_head[ant] = mmap( NULL,
          ADAC_BUFFERSZ_PERCHAN_B,
          PROT_READ|PROT_WRITE,
          MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
          openair0_fd,
          ( openair_mmap_RX(ant) | openair_mmap_Card(card) )<<PAGE_SHIFT );

      openair0_exmimo_pci[card].dac_head[ant] = mmap( NULL,
          ADAC_BUFFERSZ_PERCHAN_B,
          PROT_READ|PROT_WRITE,
          MAP_SHARED, //|MAP_FIXED,//MAP_SHARED,
          openair0_fd,
          ( openair_mmap_TX(ant) | openair_mmap_Card(card) )<<PAGE_SHIFT );

      if (openair0_exmimo_pci[card].adc_head[ant] == MAP_FAILED || openair0_exmimo_pci[card].dac_head[ant] == MAP_FAILED) {
        openair0_close();
        return -3;
      }
    }

    //printf("p_exmimo_config = %p, p_exmimo_id = %p\n", openair0_exmimo_pci.exmimo_config_ptr, openair0_exmimo_pci.exmimo_id_ptr);

    printf("card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d, %d antennas\n", card, openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion,
           openair0_exmimo_pci[card].exmimo_id_ptr->board_hwrev, openair0_exmimo_pci[card].exmimo_id_ptr->board_swrev, openair0_num_antennas[card]);
ghaddab's avatar
   
ghaddab committed
221

222
223
224
  } // end for(card)

  return 0;
225
}
226
227


228
229
int openair0_close(void)
{
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  int ant;
  int card;

  close(openair0_fd);

  for (card=0; card<openair0_num_detected_cards; card++) {
    if (bigshm_top[card] != NULL && bigshm_top[card] != MAP_FAILED)
      munmap(bigshm_top[card], BIGSHM_SIZE_PAGES<<PAGE_SHIFT);

    for (ant=0; ant<openair0_num_antennas[card]; ant++) {
      if (openair0_exmimo_pci[card].adc_head[ant] != NULL && openair0_exmimo_pci[card].adc_head[ant] != MAP_FAILED)
        munmap(openair0_exmimo_pci[card].adc_head[ant], ADAC_BUFFERSZ_PERCHAN_B);

      if (openair0_exmimo_pci[card].dac_head[ant] != NULL && openair0_exmimo_pci[card].dac_head[ant] != MAP_FAILED)
        munmap(openair0_exmimo_pci[card].dac_head[ant], ADAC_BUFFERSZ_PERCHAN_B);
245
    }
246
247
248
  }

  return 0;
249
250
251
252
}

int openair0_dump_config(int card)
{
253
  return ioctl(openair0_fd, openair_DUMP_CONFIG, card);
254
255
256
257
}

int openair0_get_frame(int card)
{
258
  return ioctl(openair0_fd, openair_GET_FRAME, card);
259
260
261
262
}

int openair0_start_rt_acquisition(int card)
{
263
  return ioctl(openair0_fd, openair_START_RT_ACQUISITION, card);
264
265
266
267
}

int openair0_stop(int card)
{
268
  return ioctl(openair0_fd, openair_STOP, card);
269
270
}

ghaddab's avatar
   
ghaddab committed
271
272
int openair0_stop_without_reset(int card)
{
273
  return ioctl(openair0_fd, openair_STOP_WITHOUT_RESET, card);
ghaddab's avatar
   
ghaddab committed
274
}
knopp's avatar
   
knopp committed
275
276

#define MY_RF_MODE      (RXEN + TXEN + TXLPFNORM + TXLPFEN + TXLPF25 + RXLPFNORM + RXLPFEN + RXLPF25 + LNA1ON +LNAMax + RFBBNORM + DMAMODE_RX + DMAMODE_TX)
ghaddab's avatar
   
ghaddab committed
277
#define RF_MODE_BASE    (LNA1ON + RFBBNORM)
knopp's avatar
   
knopp committed
278

Raymond Knopp's avatar
Raymond Knopp committed
279
280
281
282
283
284
285
286
287
288
289
290
291
292
void rt_sleep(struct timespec *ts,long tv_nsec) {

  clock_gettime(CLOCK_MONOTONIC, ts);

  ts->tv_nsec += tv_nsec;

  if (ts->tv_nsec>=1000000000L) {
    ts->tv_nsec -= 1000000000L;
    ts->tv_sec++;
  }

  clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL);

}
293
294
295
296
297
298
299
300
301
302
303
static void *watchdog_thread(void *arg) {

  int policy, s, j;
  struct sched_param sparam;
  char cpu_affinity[1024];
  cpu_set_t cpuset;
  exmimo_state_t *exm=((openair0_device *)arg)->priv;
  openair0_config_t *cfg=&((openair0_device *)arg)->openair0_cfg[0];

  volatile unsigned int *daq_mbox = openair0_daq_cnt();
  unsigned int mbox,diff;
Raymond Knopp's avatar
Raymond Knopp committed
304
  int first_acquisition;
Raymond Knopp's avatar
Raymond Knopp committed
305
306
307
308
309
310
  struct timespec sleep_time,wait;


  wait.tv_sec=0;
  wait.tv_nsec=5000000L;

311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  /* Set affinity mask to include CPUs 1 to MAX_CPUS */
  /* CPU 0 is reserved for UHD threads */
  /* CPU 1 is reserved for all TX threads */
  /* Enable CPU Affinity only if number of CPUs >2 */
  CPU_ZERO(&cpuset);

#ifdef CPU_AFFINITY
  if (get_nprocs() > 2)
  {
    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");
      printf("Error setting processor affinity");
    }
  }
#endif //CPU_AFFINITY

  /* 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");
    printf("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);
  policy = SCHED_FIFO ; 
  
  s = pthread_setschedparam(pthread_self(), policy, &sparam);
  if (s != 0)
     {
     perror("pthread_setschedparam : ");
     printf("Error setting thread priority");
     }
  s = pthread_getschedparam(pthread_self(), &policy, &sparam);
  if (s != 0)
   {
     perror("pthread_getschedparam : ");
     printf("Error getting thread priority");

   }

 printf("EXMIMO2 Watchdog TX thread started on CPU %d TID %ld, sched_policy = %s , priority = %d, CPU Affinity=%s \n",
	sched_getcpu(),
	syscall(__NR_gettid),
	(policy == SCHED_FIFO)  ? "SCHED_FIFO" :
	(policy == SCHED_RR)    ? "SCHED_RR" :
	(policy == SCHED_OTHER) ? "SCHED_OTHER" :
	"???",
	sparam.sched_priority, 
	cpu_affinity );


  mlockall(MCL_CURRENT | MCL_FUTURE);

  exm->watchdog_exit = 0;
  exm->ts = 0;
  exm->last_mbox = 0;
  
  if (cfg->sample_rate==30.72e6) {
    exm->samples_per_tick  = 15360;
    exm->samples_per_frame = 307200; 
  }
  else if (cfg->sample_rate==23.04e6) {
    exm->samples_per_tick = 11520;
    exm->samples_per_frame = 230400; 
  }
  else if (cfg->sample_rate==15.36e6) {
    exm->samples_per_tick = 7680;
    exm->samples_per_frame = 153600; 
  }
  else if (cfg->sample_rate==7.68e6) {
    exm->samples_per_tick = 3840;
    exm->samples_per_frame = 76800; 
  }
  else if (cfg->sample_rate==3.84e6) {
    exm->samples_per_tick = 1920;
    exm->samples_per_frame = 38400; 
  }
  else if (cfg->sample_rate==1.92e6) {
    exm->samples_per_tick = 960;
    exm->samples_per_frame = 19200; 
  }
  else {
    printf("Unknown sampling rate %f, exiting \n",cfg->sample_rate);
    exm->watchdog_exit=1;
  }
Raymond Knopp's avatar
Raymond Knopp committed
411
412

  first_acquisition=1;
413
  // main loop to keep up with DMA transfers from exmimo2
Raymond Knopp's avatar
Raymond Knopp committed
414
415

  int cnt_diff0=0;
416
417
418
419
420
421
  while ((!oai_exit) && (!exm->watchdog_exit)) {

    if (exm->daq_state == running) {

      // grab time from MBOX
      mbox = daq_mbox[0];
Raymond Knopp's avatar
Raymond Knopp committed
422

423
424
425
426
427
428
429
430
      if (mbox<exm->last_mbox) { // wrap-around
	diff = 150 + mbox - exm->last_mbox;
      }
      else {
	diff = mbox - exm->last_mbox;
      }
      exm->last_mbox = mbox;

Raymond Knopp's avatar
Raymond Knopp committed
431
      pthread_mutex_timedlock(&exm->watchdog_mutex,&wait);
432
433
      exm->ts += (diff*exm->samples_per_frame/150) ; 

Raymond Knopp's avatar
Raymond Knopp committed
434
435
436
437
      if (first_acquisition==1) //set last read to a closest subframe boundary
         exm->last_ts_rx = (exm->ts/(exm->samples_per_frame/10))*(exm->samples_per_frame/10);

      if ((diff > 16)&&(first_acquisition==0))  {// we're too late so exit
438
	exm->watchdog_exit = 1;
Raymond Knopp's avatar
Raymond Knopp committed
439
440
441
442
443
        printf("exiting, too late to keep up\n");
      }
      first_acquisition=0;

      if (diff == 0) {
Raymond Knopp's avatar
Raymond Knopp committed
444
445
446
447
448
	cnt_diff0++;
	if (cnt_diff0 == 10) {
	  exm->watchdog_exit = 1;
	  printf("exiting, HW stopped\n");
	}
Raymond Knopp's avatar
Raymond Knopp committed
449
      }
Raymond Knopp's avatar
Raymond Knopp committed
450
451
      else
	cnt_diff0=0;
452
453
454
455
456

      if (exm->ts - exm->last_ts_rx > exm->samples_per_frame) {
	exm->watchdog_exit = 1;
	printf("RX Overflow, exiting\n");
      }
Raymond Knopp's avatar
Raymond Knopp committed
457
      //      printf("ts %lu, last_ts_rx %lu, mbox %d, diff %d\n",exm->ts, exm->last_ts_rx,mbox,diff);
458
459
      pthread_mutex_unlock(&exm->watchdog_mutex);
    }
Raymond Knopp's avatar
Raymond Knopp committed
460
    rt_sleep(&sleep_time,250000L);
461
462
463
  }
  
  oai_exit=1;
Raymond Knopp's avatar
Raymond Knopp committed
464
  printf("Exiting watchdog\n");
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
  return NULL;
}

void create_watchdog(openair0_device *dev) {
  
  exmimo_state_t *priv = dev->priv;
  priv->watchdog_exit=0;
#ifndef DEADLINE_SCHEDULER
  priv->watchdog_sched_param.sched_priority = sched_get_priority_max(SCHED_FIFO);  
  pthread_attr_setschedparam(&priv->watchdog_attr,&priv->watchdog_sched_param);
  pthread_attr_setschedpolicy(&priv->watchdog_attr,SCHED_FIFO);
  pthread_create(&priv->watchdog,&priv->watchdog_attr,watchdog_thread,dev);
#else
  pthread_create(&priv->watchdog,NULL,watchdog_thread,devv);
#endif
  pthread_mutex_init(&priv->watchdog_mutex,NULL);


}

int trx_exmimo_start(openair0_device *device) {

  exmimo_state_t *exm=device->priv;

Raymond Knopp's avatar
Raymond Knopp committed
489
  printf("Starting ...\n");
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
  openair0_start_rt_acquisition(0);
  exm->daq_state = running;  

  return(0);
}

int trx_exmimo_write(openair0_device *device,openair0_timestamp ptimestamp, void **buff, int nsamps, int cc, int flags) {

  return(0);
}

int trx_exmimo_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int cc) {

  exmimo_state_t *exm=device->priv;
  openair0_config_t *cfg=&device->openair0_cfg[0];
Raymond Knopp's avatar
Raymond Knopp committed
505
506
507
  openair0_timestamp old_ts=0,ts,diff;
  struct timespec sleep_time;
  unsigned long tv_nsec;
Raymond Knopp's avatar
Raymond Knopp committed
508
  //  int i;
Raymond Knopp's avatar
Raymond Knopp committed
509
  struct timespec wait;
510

Raymond Knopp's avatar
Raymond Knopp committed
511
512
513
514
515
516
517
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;

  if (exm->watchdog_exit == 1)
    return(0);

  pthread_mutex_timedlock(&exm->watchdog_mutex,&wait);
518
519
  ts = exm->ts;
  pthread_mutex_unlock(&exm->watchdog_mutex);
Raymond Knopp's avatar
Raymond Knopp committed
520
521
  while ((ts < exm->last_ts_rx + nsamps) && 
	 (exm->watchdog_exit==0)) {
522
523
524

    diff = exm->last_ts_rx+nsamps - ts; // difference in samples between current timestamp and last RX received sample
    // go to sleep until we should have enough samples (1024 for a bit more)
Raymond Knopp's avatar
Raymond Knopp committed
525
526
527
528
#ifdef DEBUG_EXMIMO
    printf("Reading %d samples, ts %lu, last_ts_rx %lu (%lu) => sleeping %u us\n",nsamps,ts,exm->last_ts_rx,exm->last_ts_rx+nsamps,
	   (unsigned int)((double)(diff+1024)*1e6/cfg->sample_rate));
#endif
Raymond Knopp's avatar
Raymond Knopp committed
529
530
531
532
    tv_nsec=(unsigned long)((double)(diff+3840)*1e9/cfg->sample_rate);
    //    tv_nsec = 500000L;
    old_ts = ts;
    rt_sleep(&sleep_time,tv_nsec);
Raymond Knopp's avatar
Raymond Knopp committed
533
534
535
#ifdef DEBUG_EXMIMO
    printf("back\n");
#endif
536
    // get new timestamp, in case we have to sleep again
Raymond Knopp's avatar
Raymond Knopp committed
537
    pthread_mutex_timedlock(&exm->watchdog_mutex,&wait);
538
539
    ts = exm->ts;
    pthread_mutex_unlock(&exm->watchdog_mutex);
Raymond Knopp's avatar
Raymond Knopp committed
540
541
542
543
    if (old_ts == ts) {
      printf("ts stopped, returning\n");
      return(0);
    }
544
545
  }

Raymond Knopp's avatar
Raymond Knopp committed
546
  /*
547
548
  if (cfg->mmapped_dma == 0) {  // if buff is not the dma buffer, do a memcpy, otherwise do nothing
    for (i=0;i<cc;i++) {
Raymond Knopp's avatar
Raymond Knopp committed
549

550
551
552
      memcpy(buff[i],
	     openair0_exmimo_pci[0].adc_head[i]+(exm->last_ts_rx % exm->samples_per_frame),
	     nsamps*sizeof(int));
Raymond Knopp's avatar
Raymond Knopp committed
553

554
    }
Raymond Knopp's avatar
Raymond Knopp committed
555
    }*/
556
557
558
559
  
  *ptimestamp=exm->last_ts_rx;
  exm->last_ts_rx += nsamps;

Raymond Knopp's avatar
Raymond Knopp committed
560

Raymond Knopp's avatar
Raymond Knopp committed
561
  return(nsamps);
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
}

void trx_exmimo_end(openair0_device *device) {

  exmimo_state_t *exm=device->priv;

  exm->daq_state = idle;
  openair0_stop(0);
 
}

int trx_exmimo_get_stats(openair0_device* device) {

  return(0);

}

int trx_exmimo_reset_stats(openair0_device* device) {

  return(0);

}

int trx_exmimo_stop(int card) {

  return(0);

}

int trx_exmimo_set_freq(openair0_device* device, openair0_config_t *openair0_cfg1,int exmimo_dump_config) {

  return(0);
}

int trx_exmimo_set_gains(openair0_device* device, openair0_config_t *openair0_cfg) {

  return(0);

}

void kill_watchdog(openair0_device *device) {

  exmimo_state_t *exm=(exmimo_state_t *)device->priv;
  exm->watchdog_exit=1;

}

609
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
knopp's avatar
   
knopp committed
610
611

  // Initialize card
612
  //  exmimo_config_t         *p_exmimo_config;
613
  exmimo_id_t             *p_exmimo_id;
knopp's avatar
   
knopp committed
614
  int ret;
615
  exmimo_state_t *exm = (exmimo_state_t *)malloc(sizeof(exmimo_state_t));
knopp's avatar
   
knopp committed
616

knopp's avatar
   
knopp committed
617
  ret = openair0_open();
618
 
knopp's avatar
   
knopp committed
619
620
621
  if ( ret != 0 ) {
    if (ret == -1)
      printf("Error opening /dev/openair0");
622

knopp's avatar
   
knopp committed
623
624
    if (ret == -2)
      printf("Error mapping bigshm");
625

knopp's avatar
   
knopp committed
626
627
    if (ret == -3)
      printf("Error mapping RX or TX buffer");
628

knopp's avatar
   
knopp committed
629
630
631
    return(ret);
  }

632
633
  if (openair0_num_detected_cards>MAX_CARDS) {
    printf ("Detected %d number of cards, but MAX_CARDS=%d\n", openair0_num_detected_cards, MAX_CARDS);
634
  } else {
635
636
637
    printf ("Detected %d number of cards, %d number of antennas.\n", openair0_num_detected_cards, openair0_num_antennas[0]);
  }

638
  //  p_exmimo_config = openair0_exmimo_pci[0].exmimo_config_ptr;
knopp's avatar
   
knopp committed
639
  p_exmimo_id     = openair0_exmimo_pci[0].exmimo_id_ptr;
640

knopp's avatar
   
knopp committed
641
642
643
644
645
  printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", 0, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev);

  // check if the software matches firmware
  if (p_exmimo_id->board_swrev!=BOARD_SWREV_CNTL2) {
    printf("Software revision %d and firmware revision %d do not match. Please update either the firmware or the software!\n",BOARD_SWREV_CNTL2,p_exmimo_id->board_swrev);
646
647
    return(-1);
  }
knopp's avatar
   
knopp committed
648

649
650
  device->type             = EXMIMO_DEV; 

651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
  // Add stuff that was in lte-softmodem here

  //
  device->trx_start_func = trx_exmimo_start;
  device->trx_end_func   = trx_exmimo_end;
  device->trx_read_func  = trx_exmimo_read;
  device->trx_write_func = trx_exmimo_write;
  device->trx_get_stats_func   = trx_exmimo_get_stats;
  device->trx_reset_stats_func = trx_exmimo_reset_stats;
  device->trx_stop_func        = trx_exmimo_stop;
  device->trx_set_freq_func    = trx_exmimo_set_freq;
  device->trx_set_gains_func   = trx_exmimo_set_gains;
  device->openair0_cfg = openair0_cfg;
  device->priv = (void *)exm;

Raymond Knopp's avatar
Raymond Knopp committed
666
667
  openair0_config(openair0_cfg,0);

668
669
  create_watchdog(device);

670
671
  return(0);
}
knopp's avatar
   
knopp committed
672

knopp's avatar
knopp committed
673
674
675
676
677
678
679
unsigned int             rxg_max[4] =    {128,128,128,126};
unsigned int             rxg_med[4] =    {122,123,123,120};
unsigned int             rxg_byp[4] =    {116,117,116,116};
unsigned int             nf_max[4] =    {7,9,16,12};
unsigned int             nf_med[4] =    {12,13,22,17};
unsigned int             nf_byp[4] =    {15,20,29,23};

680
int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
681
682
683
684
685
{
  int ret;
  int ant, card;
  int resampling_factor=2;
  int rx_filter=RXLPF25, tx_filter=TXLPF25;
686
  int ACTIVE_RF=0;
687

688
689
  exmimo_config_t         *p_exmimo_config;
  exmimo_id_t             *p_exmimo_id;
690

691
692
693
  if (!openair0_cfg) {
    printf("Error, openair0_cfg is null!!\n");
    return(-1);
694
695
  }

696
  for (card=0; card<openair0_num_detected_cards; card++) {
knopp's avatar
   
knopp committed
697

698
699
    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
700

701
    if (p_exmimo_id->board_swrev>=9)
702
703
      p_exmimo_config->framing.eNB_flag   = 0;
    else
704
      p_exmimo_config->framing.eNB_flag   = !UE_flag;
705

706
707
708
709
710
711
    if (openair0_num_detected_cards==1)
      p_exmimo_config->framing.multicard_syncmode=SYNCMODE_FREE;
    else if (card==0)
      p_exmimo_config->framing.multicard_syncmode=SYNCMODE_MASTER;
    else
      p_exmimo_config->framing.multicard_syncmode=SYNCMODE_SLAVE;
712

713
714
715
    /* device specific */
    openair0_cfg[card].iq_txshift = 4;//shift
    openair0_cfg[card].iq_rxrescale = 15;//rescale iqs
Raymond Knopp's avatar
Raymond Knopp committed
716
    openair0_cfg[card].mmapped_dma = 1;
717

718
719
720
721
    if (openair0_cfg[card].sample_rate==30.72e6) {
      resampling_factor = 0;
      rx_filter = RXLPF10;
      tx_filter = TXLPF10;
722
    } else if (openair0_cfg[card].sample_rate==15.36e6) {
723
724
725
      resampling_factor = 1;
      rx_filter = RXLPF5;
      tx_filter = TXLPF5;
726
    } else if (openair0_cfg[card].sample_rate==7.68e6) {
727
728
729
      resampling_factor = 2;
      rx_filter = RXLPF25;
      tx_filter = TXLPF25;
730
    } else {
731
732
733
734
      printf("Sampling rate not supported, using default 7.68MHz");
      resampling_factor = 2;
      rx_filter = RXLPF25;
      tx_filter = TXLPF25;
735

knopp's avatar
   
knopp committed
736
    }
737

738
#if (BOARD_SWREV_CNTL2>=0x0A)
739

740
741
    for (ant=0; ant<4; ant++)
      p_exmimo_config->framing.resampling_factor[ant] = resampling_factor;
742

743
744
745
#else
    p_exmimo_config->framing.resampling_factor = resampling_factor;
#endif
746
747

    for (ant=0; ant<4; ant++) {
Raymond Knopp's avatar
Raymond Knopp committed
748
749
750
751

      openair0_cfg[card].rxbase[ant] = (int32_t*)openair0_exmimo_pci[card].adc_head[ant];
      openair0_cfg[card].txbase[ant] = (int32_t*)openair0_exmimo_pci[card].dac_head[ant];

752
      if (openair0_cfg[card].rx_freq[ant] || openair0_cfg[card].tx_freq[ant]) {
753
	ACTIVE_RF += (1<<ant)<<5;
754
        p_exmimo_config->rf.rf_mode[ant] = RF_MODE_BASE;
755
756
        p_exmimo_config->rf.do_autocal[ant] = 1;//openair0_cfg[card].autocal[ant];
	printf("card %d, antenna %d, autocal %d\n",card,ant,openair0_cfg[card].autocal[ant]);
757
      }
758

Raymond Knopp's avatar
Raymond Knopp committed
759
      if (openair0_cfg[card].tx_freq[ant]>0) {
760
761
762
        p_exmimo_config->rf.rf_mode[ant] += (TXEN + DMAMODE_TX + TXLPFNORM + TXLPFEN + tx_filter);
        p_exmimo_config->rf.rf_freq_tx[ant] = (unsigned int)openair0_cfg[card].tx_freq[ant];
        p_exmimo_config->rf.tx_gain[ant][0] = (unsigned int)openair0_cfg[card].tx_gain[ant];
Raymond Knopp's avatar
Raymond Knopp committed
763
        printf("openair0 : programming card %d TX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_tx[ant],p_exmimo_config->rf.tx_gain[ant][0]);
764
      }
765

Raymond Knopp's avatar
Raymond Knopp committed
766
      if (openair0_cfg[card].rx_freq[ant]>0) {
767
768
769
        p_exmimo_config->rf.rf_mode[ant] += (RXEN + DMAMODE_RX + RXLPFNORM + RXLPFEN + rx_filter);

        p_exmimo_config->rf.rf_freq_rx[ant] = (unsigned int)openair0_cfg[card].rx_freq[ant];
knopp's avatar
knopp committed
770

771
772
773
774
775
776
        printf("openair0 : programming card %d RX antenna %d (freq %u, gain %d)\n",card,ant,p_exmimo_config->rf.rf_freq_rx[ant],p_exmimo_config->rf.rx_gain[ant][0]);

        switch (openair0_cfg[card].rxg_mode[ant]) {
        default:
        case max_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAMax;
knopp's avatar
knopp committed
777
778
779
780
781
782
783
	  if (rxg_max[ant] >= (int)openair0_cfg[card].rx_gain[ant]) {
	    p_exmimo_config->rf.rx_gain[ant][0] = 30 - (rxg_max[ant] - (int)openair0_cfg[card].rx_gain[ant]); //was measured at rxgain=30;
	  }
	  else {
	    printf("openair0: RX RF gain too high, reduce by %d dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_max[ant]);
	    exit(-1);
	  }
784
785
786
787
          break;

        case med_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAMed;
knopp's avatar
knopp committed
788
789
790
791
792
793
794
	  if (rxg_med[ant] >= (int)openair0_cfg[card].rx_gain[ant]) {
	    p_exmimo_config->rf.rx_gain[ant][0] = 30 - (rxg_med[ant] - (int)openair0_cfg[card].rx_gain[ant]); //was measured at rxgain=30;
	  }
	  else {
	    printf("openair0: RX RF gain too high, reduce by %d dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_med[ant]);
	    exit(-1);
	  }
795
796
797
798
          break;

        case byp_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAByp;
knopp's avatar
knopp committed
799
800
801
802
803
804
805
	  if (rxg_byp[ant] >= (int)openair0_cfg[card].rx_gain[ant]) {
	    p_exmimo_config->rf.rx_gain[ant][0] = 30 - (rxg_byp[ant] - (int)openair0_cfg[card].rx_gain[ant]); //was measured at rxgain=30;
	  }
	  else {
	    printf("openair0: RX RF gain too high, reduce by %d dB\n", (int)openair0_cfg[card].rx_gain[ant]-rxg_byp[ant]);
	    exit(-1);
	  }
806
807
808
809
810
          break;
        }
      } else {
        p_exmimo_config->rf.rf_mode[ant] = 0;
        p_exmimo_config->rf.do_autocal[ant] = 0;
811
      }
812

813
814
      p_exmimo_config->rf.rf_local[ant]   = rf_local[ant];
      p_exmimo_config->rf.rf_rxdc[ant]    = rf_rxdc[ant];
815

816
      if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 850000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 865000000)) {
817
818
819
820
821
822
823
824
        p_exmimo_config->rf.rf_vcocal[ant]  = rf_vcocal_850[ant];
        p_exmimo_config->rf.rffe_band_mode[ant] = DD_TDD;
      } else if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 1900000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 2000000000)) {
        p_exmimo_config->rf.rf_vcocal[ant]  = rf_vcocal[ant];
        p_exmimo_config->rf.rffe_band_mode[ant] = B19G_TDD;
      } else {
        p_exmimo_config->rf.rf_vcocal[ant]  = rf_vcocal[ant];
        p_exmimo_config->rf.rffe_band_mode[ant] = 0;
825
826
      }
    }
827

828
829
830
831
832
833
834
835
836
    if (openair0_cfg[card].duplex_mode==duplex_mode_FDD) {
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD;
      printf("!!!!!setting FDD (tdd_config=%d)\n",p_exmimo_config->framing.tdd_config);
    } 
    else {
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_TDD + TXRXSWITCH_LSB + ACTIVE_RF;
      printf("!!!!!setting TDD (tdd_config=%d)\n",p_exmimo_config->framing.tdd_config);
    }

837
    ret = ioctl(openair0_fd, openair_DUMP_CONFIG, card);
838

839
840
    if (ret!=0)
      return(-1);
841

knopp's avatar
   
knopp committed
842
  }
843

knopp's avatar
   
knopp committed
844
  return(0);
knopp's avatar
   
knopp committed
845
846
}

847
848
int openair0_reconfig(openair0_config_t *openair0_cfg)
{
849

850
851
852
  int ant, card;

  exmimo_config_t         *p_exmimo_config;
853
  //  exmimo_id_t             *p_exmimo_id;
854
855
856
857
858
859
860
861
862

  if (!openair0_cfg) {
    printf("Error, openair0_cfg is null!!\n");
    return(-1);
  }

  for (card=0; card<openair0_num_detected_cards; card++) {

    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
863
    //    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
864
865

    for (ant=0; ant<4; ant++) {
866
      if (openair0_cfg[card].tx_freq[ant]) {
867
868
        p_exmimo_config->rf.rf_freq_tx[ant] = (unsigned int)openair0_cfg[card].tx_freq[ant];
        p_exmimo_config->rf.tx_gain[ant][0] = (unsigned int)openair0_cfg[card].tx_gain[ant];
Raymond Knopp's avatar
Raymond Knopp committed
869
        printf("openair0 : programming TX antenna %d (freq %u, gain %d)\n",ant,p_exmimo_config->rf.rf_freq_tx[ant],p_exmimo_config->rf.tx_gain[ant][0]);
870
      }
871

Raymond Knopp's avatar
Raymond Knopp committed
872

873
      if (openair0_cfg[card].rx_freq[ant]) {
874
875
        p_exmimo_config->rf.rf_freq_rx[ant] = (unsigned int)openair0_cfg[card].rx_freq[ant];
        p_exmimo_config->rf.rx_gain[ant][0] = (unsigned int)openair0_cfg[card].rx_gain[ant];
Raymond Knopp's avatar
Raymond Knopp committed
876
        printf("openair0 : programming RX antenna %d (freq %u, gain %d)\n",ant,p_exmimo_config->rf.rf_freq_rx[ant],p_exmimo_config->rf.rx_gain[ant][0]);
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891

        switch (openair0_cfg[card].rxg_mode[ant]) {
        default:
        case max_gain:
          p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAMax;
          break;

        case med_gain:
          p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAMed;
          break;

        case byp_gain:
          p_exmimo_config->rf.rf_mode[ant] = (p_exmimo_config->rf.rf_mode[ant]&(~LNAGAINMASK))|LNAByp;
          break;
        }
892
893
894
      }
    }
  }
895

896
897
898
  return(0);
}

899
900
901
902
903
904
905
906
907
908
909
910
int openair0_set_frequencies(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config) {

  if (exmimo_dump_config > 0) {
    // do a full configuration
    openair0_config(openair0_cfg,0);
  }
  else {  // just change the frequencies in pci descriptor
    openair0_reconfig(openair0_cfg);
  }
  return(0);
  
}
911

912
913
914
915
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg){
  return(0);
}

916
unsigned int *openair0_daq_cnt(void) {
knopp's avatar
   
knopp committed
917
918
919
920

  return((unsigned int *)openair0_exmimo_pci[0].rxcnt_ptr[0]);

}