openair0_lib.c 32.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.0  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */
21
22
23
24
25
26
27
28
29
30

/** 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
*/

31
#define _GNU_SOURCE
32
#include <stdio.h>
knopp's avatar
   
knopp committed
33
#include <stdlib.h>
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#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>
52
53
54

#include "openair0_lib.h"
#include "openair_device.h"
knopp's avatar
   
knopp committed
55
#include "common_lib.h"
56
57
58

#include <pthread.h>

Raymond Knopp's avatar
Raymond Knopp committed
59

knopp's avatar
   
knopp committed
60
#define max(a,b) ((a)>(b) ? (a) : (b))
Raymond Knopp's avatar
Raymond Knopp committed
61

62
//#define DEBUG_EXMIMO
Raymond Knopp's avatar
Raymond Knopp committed
63

64
exmimo_pci_interface_bot_virtual_t openair0_exmimo_pci[MAX_CARDS]; // contains userspace pointers for each card
65

66
char *bigshm_top[MAX_CARDS];
67
68
69
70
71
72
73

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

unsigned int PAGE_SHIFT;

knopp's avatar
   
knopp committed
74
static uint32_t                      rf_local[4] =       {8255000,8255000,8255000,8255000}; // UE zepto
75
76
//{8254617, 8254617, 8254617, 8254617}; //eNB khalifa
//{8255067,8254810,8257340,8257340}; // eNB PETRONAS
knopp's avatar
   
knopp committed
77
78
79
80

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

82
83
84
85
86
87
88


extern volatile int                    oai_exit;


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

91
92
93
unsigned int log2_int( unsigned int x )
{
  unsigned int ans = 0 ;
94

95
  while( x>>=1 ) ans++;
96

97
98
99
100
101
  return ans ;
}

int openair0_open(void)
{
102
103
  exmimo_pci_interface_bot_virtual_t exmimo_pci_kvirt[MAX_CARDS];
  void *bigshm_top_kvirtptr[MAX_CARDS];
knopp's avatar
   
knopp committed
104

105
106
  int card;
  int ant;
knopp's avatar
   
knopp committed
107

108
  PAGE_SHIFT = log2_int( sysconf( _SC_PAGESIZE ) );
knopp's avatar
   
knopp committed
109

110

111
112
113
  if ((openair0_fd = open("/dev/openair0", O_RDWR,0)) <0) {
    return -1;
  }
knopp's avatar
   
knopp committed
114

115
  ioctl(openair0_fd, openair_GET_NUM_DETECTED_CARDS, &openair0_num_detected_cards);
knopp's avatar
   
knopp committed
116

117
118


119
120
121
122
123
124
125
126
127
128
  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]);

129
130
  for( card=0; card < MAX_CARDS; card++)
    bigshm_top[card] = NULL;
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

  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
146
#if __x86_64
147
148
149
150
    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
151
#else
152
153
154
155
    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
156
157
#endif

158
159
160
161
162
163
164
165
166
167
168
169
170
171
    /*
          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
172

173
174
    if ( openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion == 1)
      openair0_num_antennas[card] = 2;
175

176
177
    if ( openair0_exmimo_pci[card].exmimo_id_ptr->board_exmimoversion == 2)
      openair0_num_antennas[card] = 4;
178

ghaddab's avatar
   
ghaddab committed
179

180
    for (ant=0; ant<openair0_num_antennas[card]; ant++) {
knopp's avatar
   
knopp committed
181
#if __x86_64__
182
183
      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
184
#else
185
186
      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
187
#endif
188
    }
189

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    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
215

216
217
218
  } // end for(card)

  return 0;
219
}
220
221


222
223
int openair0_close(void)
{
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
  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);
239
    }
240
241
242
  }

  return 0;
243
244
245
246
}

int openair0_dump_config(int card)
{
247
  return ioctl(openair0_fd, openair_DUMP_CONFIG, card);
248
249
250
251
}

int openair0_get_frame(int card)
{
252
  return ioctl(openair0_fd, openair_GET_FRAME, card);
253
254
255
256
}

int openair0_start_rt_acquisition(int card)
{
257
  return ioctl(openair0_fd, openair_START_RT_ACQUISITION, card);
258
259
260
261
}

int openair0_stop(int card)
{
262
  return ioctl(openair0_fd, openair_STOP, card);
263
264
}

ghaddab's avatar
   
ghaddab committed
265
266
int openair0_stop_without_reset(int card)
{
267
  return ioctl(openair0_fd, openair_STOP_WITHOUT_RESET, card);
ghaddab's avatar
   
ghaddab committed
268
}
knopp's avatar
   
knopp committed
269
270

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

Raymond Knopp's avatar
Raymond Knopp committed
273
274
275
276
277
278
279
280
281
282
283
284
285
286
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);

}
287
288
289
290
291
292
293
294
295
296
297
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
298
  int first_acquisition;
Raymond Knopp's avatar
Raymond Knopp committed
299
300
301
302
  struct timespec sleep_time,wait;


  wait.tv_sec=0;
303
  wait.tv_nsec=50000000L;
Raymond Knopp's avatar
Raymond Knopp committed
304

305
306
307
308
309
310
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
  /* 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
405
406

  first_acquisition=1;
407
408
  printf("Locking watchdog for first acquisition\n");
  pthread_mutex_timedlock(&exm->watchdog_mutex,&wait);
409
  // main loop to keep up with DMA transfers from exmimo2
Raymond Knopp's avatar
Raymond Knopp committed
410
411

  int cnt_diff0=0;
412
413
414
415
416
417
  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
418

419
420
421
422
423
424
425
426
      if (mbox<exm->last_mbox) { // wrap-around
	diff = 150 + mbox - exm->last_mbox;
      }
      else {
	diff = mbox - exm->last_mbox;
      }
      exm->last_mbox = mbox;

427
428
429
      if (first_acquisition==0)
	pthread_mutex_timedlock(&exm->watchdog_mutex,&wait);

430
431
      exm->ts += (diff*exm->samples_per_frame/150) ; 

Raymond Knopp's avatar
Raymond Knopp committed
432

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

441
442
      if ((exm->daq_state == running) && 
	  (diff == 0)) {
Raymond Knopp's avatar
Raymond Knopp committed
443
444
445
446
447
	cnt_diff0++;
	if (cnt_diff0 == 10) {
	  exm->watchdog_exit = 1;
	  printf("exiting, HW stopped\n");
	}
Raymond Knopp's avatar
Raymond Knopp committed
448
      }
Raymond Knopp's avatar
Raymond Knopp committed
449
450
      else
	cnt_diff0=0;
451

452
453
454
      if ((exm->daq_state == running) &&
	  (exm->wait_first_read==0) &&
	  (exm->ts - exm->last_ts_rx > exm->samples_per_frame)) {
455
	exm->watchdog_exit = 1;
456
457
	printf("RX Overflow, exiting (TS %llu, TS last read %llu)\n",
	       exm->ts,exm->last_ts_rx);
458
      }
Raymond Knopp's avatar
Raymond Knopp committed
459
      //      printf("ts %lu, last_ts_rx %lu, mbox %d, diff %d\n",exm->ts, exm->last_ts_rx,mbox,diff);
460
461
      pthread_mutex_unlock(&exm->watchdog_mutex);
    }
462
463
464
    else {
      first_acquisition=1;
    }
Raymond Knopp's avatar
Raymond Knopp committed
465
    rt_sleep(&sleep_time,250000L);
466
467
468
  }
  
  oai_exit=1;
Raymond Knopp's avatar
Raymond Knopp committed
469
  printf("Exiting watchdog\n");
470
471
472
473
474
475
476
477
478
479
480
481
482
  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
Rohit Gupta's avatar
Rohit Gupta committed
483
  pthread_create(&priv->watchdog,NULL,watchdog_thread,dev);
484
485
486
487
488
489
490
491
492
493
#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
494
  printf("Starting ...\n");
495
  openair0_config(device->openair0_cfg,0);
496
  openair0_start_rt_acquisition(0);
knopp's avatar
knopp committed
497
  printf("Setting state to running\n");
498
  exm->daq_state = running;  
499
  exm->wait_first_read = 1;
500
501
502
503
504
  return(0);
}

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

knopp's avatar
knopp committed
505
506
  
  return(nsamps);
507
508
}

509
510


511
512
513
514
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
515
516
517
  openair0_timestamp old_ts=0,ts,diff;
  struct timespec sleep_time;
  unsigned long tv_nsec;
518
519
520
  int i;
  int n,n1,n2,ntot,first_len;
  int ret;
521

knopp's avatar
knopp committed
522
523
524
  //  struct timespec wait;
  //  wait.tv_sec=0;
  //  wait.tv_nsec=50000000L;
Raymond Knopp's avatar
Raymond Knopp committed
525
526
527
528

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

529
530
531
532
533
  if (exm->daq_state == idle) {
    tv_nsec=(unsigned long)((double)(nsamps)*1e9/cfg->sample_rate);
    return(0);
  }

534
  ret = pthread_mutex_lock(&exm->watchdog_mutex);
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561

  switch (ret) {
  case EINVAL:
#ifdef DEBUG_EXMIMO 
    printf("trx_exmimo_read: mutex_timedlock returned EINVAL\n");
#endif
    return(0);
    break;
  case ETIMEDOUT: 
#ifdef DEBUG_EXMIMO 
    printf("trx_exmimo_read: mutex_timedlock returned ETIMEDOUT\n");
#endif
    return(0);
    break;
  case EAGAIN: 
#ifdef DEBUG_EXMIMO 
    printf("trx_exmimo_read: mutex_timedlock returned EAGAIN\n");
#endif
    return(0);
    break;
  case EDEADLK: 
#ifdef DEBUG_EXMIMO 
    printf("trx_exmimo_read: mutex_timedlock returned EDEADLK\n");
#endif
    return(0);
    break;
  }
knopp's avatar
knopp committed
562

563
  ts = exm->ts;
564
565
566
567
568
  if (exm->wait_first_read==1) {
    exm->wait_first_read=0;
    exm->last_ts_rx = ts;
  }

569
  pthread_mutex_unlock(&exm->watchdog_mutex);
570
571
572
573
574
575
576
577
578
579
  //  dump_frame_parms(frame_parms[0]);
  
  if (nsamps > (exm->samples_per_frame>>1)) {
    n1 = nsamps>>1;
    n2 = nsamps-n1;
  }
  else {
    n1=nsamps;
    n2=0;
  }
580

Raymond Knopp's avatar
Raymond Knopp committed
581
#ifdef DEBUG_EXMIMO
582
  printf("Reading %d samples, ts %lu (%d), last_ts_rx %lu (%lu)\n",nsamps,ts,ts%exm->samples_per_frame,exm->last_ts_rx,exm->last_ts_rx+nsamps);
Raymond Knopp's avatar
Raymond Knopp committed
583
#endif
584
585
586
587
588
589
  for (n=n1,ntot=0;ntot<nsamps;n=n2) {
    while ((ts < exm->last_ts_rx + n) && 
	   (exm->watchdog_exit==0)) {
      
      diff = exm->last_ts_rx+n - 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
590
#ifdef DEBUG_EXMIMO
591
592
      printf("portion %d samples, ts %lu, last_ts_rx %lu (%lu) => sleeping %u us\n",n,ts,exm->last_ts_rx,exm->last_ts_rx+n,
	     (unsigned int)((double)(diff+1024)*1e6/cfg->sample_rate));
Raymond Knopp's avatar
Raymond Knopp committed
593
#endif
594
595
596
597
598
599
600
601
      tv_nsec=(unsigned long)((double)(diff+3840)*1e9/cfg->sample_rate);
      //    tv_nsec = 500000L;
      old_ts = ts;
      rt_sleep(&sleep_time,tv_nsec);
#ifdef DEBUG_EXMIMO
      printf("back\n");
#endif
      // get new timestamp, in case we have to sleep again
knopp's avatar
knopp committed
602
      pthread_mutex_lock(&exm->watchdog_mutex);
603
604
605
606
607
608
      ts = exm->ts;
      pthread_mutex_unlock(&exm->watchdog_mutex);
      if (old_ts == ts) {
	printf("ts stopped, returning\n");
	return(0);
      }
Raymond Knopp's avatar
Raymond Knopp committed
609
    }
Raymond Knopp's avatar
Raymond Knopp committed
610

611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
  
  
    if (cfg->mmapped_dma == 0) {  // if buff is not the dma buffer, do a memcpy, otherwise do nothing
      for (i=0;i<cc;i++) {
#ifdef DEBUG_EXMIMO
	printf("copying to %p (%lu), from %llu\n",buff[i]+(ntot*sizeof(int)),ntot*sizeof(int),(exm->last_ts_rx % exm->samples_per_frame));
#endif
	if ((n+(exm->last_ts_rx%exm->samples_per_frame))<exm->samples_per_frame) {
	  memcpy(buff[i]+(ntot*sizeof(int)),
		 (void*)(openair0_exmimo_pci[0].adc_head[i]+(exm->last_ts_rx % exm->samples_per_frame)),
		 n*sizeof(int));
 	}
	else {
	  first_len =  (exm->samples_per_frame-(exm->last_ts_rx%exm->samples_per_frame));
#ifdef DEBUG_EXMIMO
	  printf("split: first_len %d, remainder %d\n",first_len,n-first_len);
#endif
	  memcpy(buff[i]+(ntot*sizeof(int)),
		 (void*)(openair0_exmimo_pci[0].adc_head[i]+(exm->last_ts_rx % exm->samples_per_frame)),
		 first_len*sizeof(int));
	  memcpy(buff[i]+(ntot+first_len)*sizeof(int),
		 (void*)openair0_exmimo_pci[0].adc_head[i],
		 (n-first_len)*sizeof(int));
	}
      }
636
    }
knopp's avatar
knopp committed
637
    pthread_mutex_lock(&exm->watchdog_mutex);
638
639
640
641
642
643
644
    exm->last_ts_rx += n;
    pthread_mutex_unlock(&exm->watchdog_mutex);    
    if (n==n1) {
      *ptimestamp=exm->last_ts_rx;
    }
    ntot+=n;
   }
645
  
646

647

Raymond Knopp's avatar
Raymond Knopp committed
648

Raymond Knopp's avatar
Raymond Knopp committed
649
  return(nsamps);
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
}

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

}

673
674
675
676
677
678
679
int trx_exmimo_stop(openair0_device* device) {

  exmimo_state_t *exm=device->priv;

  printf("Stopping ...\n");
  exm->daq_state = idle;  
  openair0_stop(0);
680
681
682
683
684

  return(0);

}

685
int trx_exmimo_set_freq(openair0_device* device, openair0_config_t *openair0_cfg,int exmimo_dump_config) {
686

687
  openair0_set_frequencies(device,openair0_cfg,0);
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  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;

}

704
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
knopp's avatar
   
knopp committed
705
706

  // Initialize card
707
  //  exmimo_config_t         *p_exmimo_config;
708
  exmimo_id_t             *p_exmimo_id;
knopp's avatar
   
knopp committed
709
  int ret;
710
  exmimo_state_t *exm = (exmimo_state_t *)malloc(sizeof(exmimo_state_t));
knopp's avatar
knopp committed
711
  int card,ant;
knopp's avatar
   
knopp committed
712

knopp's avatar
   
knopp committed
713
  ret = openair0_open();
714
 
knopp's avatar
   
knopp committed
715
716
717
  if ( ret != 0 ) {
    if (ret == -1)
      printf("Error opening /dev/openair0");
718

knopp's avatar
   
knopp committed
719
720
    if (ret == -2)
      printf("Error mapping bigshm");
721

knopp's avatar
   
knopp committed
722
723
    if (ret == -3)
      printf("Error mapping RX or TX buffer");
724

knopp's avatar
   
knopp committed
725
726
727
    return(ret);
  }

728
729
  if (openair0_num_detected_cards>MAX_CARDS) {
    printf ("Detected %d number of cards, but MAX_CARDS=%d\n", openair0_num_detected_cards, MAX_CARDS);
730
  } else {
731
732
733
    printf ("Detected %d number of cards, %d number of antennas.\n", openair0_num_detected_cards, openair0_num_antennas[0]);
  }

Xiwen JIANG's avatar
Xiwen JIANG committed
734
735
736
  for (card=0; card<openair0_num_detected_cards; card++) {
    //  p_exmimo_config = openair0_exmimo_pci[0].exmimo_config_ptr;
    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
737

Xiwen JIANG's avatar
Xiwen JIANG committed
738
    printf("Card %d: ExpressMIMO %d, HW Rev %d, SW Rev 0x%d\n", card, p_exmimo_id->board_exmimoversion, p_exmimo_id->board_hwrev, p_exmimo_id->board_swrev);
knopp's avatar
   
knopp committed
739

Xiwen JIANG's avatar
Xiwen JIANG committed
740
741
742
743
744
    // 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);
      return(-1);
    }
745
  }
knopp's avatar
   
knopp committed
746

747
748
  device->type             = EXMIMO_DEV; 

749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  // 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;

764

knopp's avatar
knopp committed
765
766
767
768
769
770
  printf("EXMIMO2: Getting addresses for memory-mapped DMA\n");
  for (card=0; card<openair0_num_detected_cards; card++) {
    for (ant=0; ant<4; ant++) {
      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];
    }
Rohit Gupta's avatar
Rohit Gupta committed
771
    openair0_cfg[card].mmapped_dma = 1;
knopp's avatar
knopp committed
772
  }
Raymond Knopp's avatar
Raymond Knopp committed
773

774
775
  create_watchdog(device);

776
777
  return(0);
}
knopp's avatar
   
knopp committed
778

knopp's avatar
knopp committed
779
780
781
782
783
784
785
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};

786
int openair0_config(openair0_config_t *openair0_cfg, int UE_flag)
787
788
789
790
791
{
  int ret;
  int ant, card;
  int resampling_factor=2;
  int rx_filter=RXLPF25, tx_filter=TXLPF25;
792
  int ACTIVE_RF=0;
793
  int i;
794

795
796
  exmimo_config_t         *p_exmimo_config;
  exmimo_id_t             *p_exmimo_id;
797

798
799
800
  if (!openair0_cfg) {
    printf("Error, openair0_cfg is null!!\n");
    return(-1);
801
802
  }

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

805
806
    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
807

808
    if (p_exmimo_id->board_swrev>=9)
809
810
      p_exmimo_config->framing.eNB_flag   = 0;
    else
811
      p_exmimo_config->framing.eNB_flag   = !UE_flag;
812

813
814
815
816
817
818
    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;
819

820
821
822
823
824
    /* device specific */
    openair0_cfg[card].iq_txshift = 4;//shift
    openair0_cfg[card].iq_rxrescale = 15;//rescale iqs


825
826
827
828
    if (openair0_cfg[card].sample_rate==30.72e6) {
      resampling_factor = 0;
      rx_filter = RXLPF10;
      tx_filter = TXLPF10;
829
    } else if (openair0_cfg[card].sample_rate==15.36e6) {
830
831
832
      resampling_factor = 1;
      rx_filter = RXLPF5;
      tx_filter = TXLPF5;
833
    } else if (openair0_cfg[card].sample_rate==7.68e6) {
834
835
836
      resampling_factor = 2;
      rx_filter = RXLPF25;
      tx_filter = TXLPF25;
837
    } else {
838
839
840
841
      printf("Sampling rate not supported, using default 7.68MHz");
      resampling_factor = 2;
      rx_filter = RXLPF25;
      tx_filter = TXLPF25;
842

knopp's avatar
   
knopp committed
843
    }
844

845
#if (BOARD_SWREV_CNTL2>=0x0A)
846

847
848
    for (ant=0; ant<4; ant++)
      p_exmimo_config->framing.resampling_factor[ant] = resampling_factor;
849

850
851
852
#else
    p_exmimo_config->framing.resampling_factor = resampling_factor;
#endif
853
854

    for (ant=0; ant<4; ant++) {
Xiwen JIANG's avatar
Xiwen JIANG committed
855
856
857
858
859
860
      p_exmimo_config->rf.rf_freq_rx[ant] = 0;
      p_exmimo_config->rf.rf_freq_tx[ant] = 0;
      p_exmimo_config->rf.rf_mode[ant] = 0;
      p_exmimo_config->rf.rx_gain[ant][0] = 0;
      p_exmimo_config->rf.tx_gain[ant][0] = 0;

Raymond Knopp's avatar
Raymond Knopp committed
861
862
863
      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];

864
      if (openair0_cfg[card].rx_freq[ant] || openair0_cfg[card].tx_freq[ant]) {
865
	ACTIVE_RF += (1<<ant)<<5;
866
        p_exmimo_config->rf.rf_mode[ant] = RF_MODE_BASE;
867
        p_exmimo_config->rf.do_autocal[ant] = 1;//openair0_cfg[card].autocal[ant];
Xiwen JIANG's avatar
Xiwen JIANG committed
868
	printf("card %d, antenna %d, autocal %d\n",card,ant,p_exmimo_config->rf.do_autocal[ant]);
869
      }
870

Raymond Knopp's avatar
Raymond Knopp committed
871
      if (openair0_cfg[card].tx_freq[ant]>0) {
872
873
874
        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
875
        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]);
876
877

	printf("Setting TX buffer to all-RX\n");
878

879
880
881
	for (i=0;i<307200;i++) {
	  ((uint32_t*)openair0_exmimo_pci[card].dac_head[ant])[i] = 0x00010001;
	}
882
      }
883

Raymond Knopp's avatar
Raymond Knopp committed
884
      if (openair0_cfg[card].rx_freq[ant]>0) {
885
886
887
        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
888

889
890
891
892
893
894
        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
895
896
897
898
899
900
901
	  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);
	  }
902
903
904
905
          break;

        case med_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAMed;
knopp's avatar
knopp committed
906
907
908
909
910
911
912
	  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);
	  }
913
914
915
916
          break;

        case byp_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAByp;
knopp's avatar
knopp committed
917
918
919
920
921
922
923
	  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);
	  }
924
925
          break;
        }
Xiwen JIANG's avatar
Xiwen JIANG committed
926
      } 
927

928
929
      p_exmimo_config->rf.rf_local[ant]   = rf_local[ant];
      p_exmimo_config->rf.rf_rxdc[ant]    = rf_rxdc[ant];
930

931
      if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 790000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 865000000)) {
932
933
934
935
936
937
938
939
        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;
940
941
      }
    }
942

943
    if (openair0_cfg[card].duplex_mode==duplex_mode_FDD) {
944
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD;// + TXRXSWITCH_LSB + TXRXSWITCH_LSB + ACTIVE_RF+ ACTIVE_RF;
945
946
947
948
949
950
951
      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);
    }

952
    ret = ioctl(openair0_fd, openair_DUMP_CONFIG, card);
953

954
955
    if (ret!=0)
      return(-1);
956

knopp's avatar
   
knopp committed
957
  }
958

knopp's avatar
   
knopp committed
959
  return(0);
knopp's avatar
   
knopp committed
960
961
}

962
963
int openair0_reconfig(openair0_config_t *openair0_cfg)
{
964

965
966
967
  int ant, card;

  exmimo_config_t         *p_exmimo_config;
968
  //  exmimo_id_t             *p_exmimo_id;
969
970
971
972
973
974

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

975
976
977
#ifdef DEBUG_EXMIMO
  printf("Reconfiguration of gains/frequencies\n");
#endif
978
979
980
  for (card=0; card<openair0_num_detected_cards; card++) {

    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
981
    //    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
982
983

    for (ant=0; ant<4; ant++) {
984
      if (openair0_cfg[card].tx_freq[ant]) {
985
986
        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];
987
988
989
#ifdef DEBUG_EXMIMO
        printf("openair0 -  %d : programming 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]);
#endif
990
      }
991

Raymond Knopp's avatar
Raymond Knopp committed
992

993
      if (openair0_cfg[card].rx_freq[ant]) {
994
995
        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];
996
997
998
#ifdef DEBUG_EXMIMO
        printf("openair0 -  %d : programming 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]);
#endif
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
        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;
        }
1013
1014
1015
      }
    }
  }
1016

1017
1018
1019
  return(0);
}

1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
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);
  
}
1032

1033
1034
1035
1036
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg){
  return(0);
}

1037
unsigned int *openair0_daq_cnt(void) {
knopp's avatar
   
knopp committed
1038
1039
1040
1041

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

}