openair0_lib.c 32.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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
 */

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 67 68 69 70 71 72 73

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
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 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
  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
145
#if __x86_64
146 147 148 149
    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
150
#else
151 152 153 154
    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
155 156
#endif

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

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

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

ghaddab's avatar
 
ghaddab committed
178

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

215 216 217
  } // end for(card)

  return 0;
218
}
219 220


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

  return 0;
242 243 244 245
}

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

Raymond Knopp's avatar
Raymond Knopp committed
431

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

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

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

508 509


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

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

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

528 529 530 531 532 533 534 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
  if (exm->daq_state == idle) {
    tv_nsec=(unsigned long)((double)(nsamps)*1e9/cfg->sample_rate);
    return(0);
  }


  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
560 561 562

  ret = pthread_mutex_lock(&exm->watchdog_mutex);

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

734
  //  p_exmimo_config = openair0_exmimo_pci[0].exmimo_config_ptr;
knopp's avatar
 
knopp committed
735
  p_exmimo_id     = openair0_exmimo_pci[0].exmimo_id_ptr;
736

knopp's avatar
 
knopp committed
737 738 739 740 741
  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);
742 743
    return(-1);
  }
knopp's avatar
 
knopp committed
744

745 746
  device->type             = EXMIMO_DEV; 

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

762

knopp's avatar
knopp committed
763 764 765 766 767 768
  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
769
    openair0_cfg[card].mmapped_dma = 1;
knopp's avatar
knopp committed
770
  }
Raymond Knopp's avatar
Raymond Knopp committed
771

772 773
  create_watchdog(device);

774 775
  return(0);
}
knopp's avatar
 
knopp committed
776

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

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

793 794
  exmimo_config_t         *p_exmimo_config;
  exmimo_id_t             *p_exmimo_id;
795

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

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

803 804
    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
805

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

811 812 813 814 815 816
    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;
817

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


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

knopp's avatar
 
knopp committed
841
    }
842

843
#if (BOARD_SWREV_CNTL2>=0x0A)
844

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

848 849 850
#else
    p_exmimo_config->framing.resampling_factor = resampling_factor;
#endif
851 852

    for (ant=0; ant<4; ant++) {
Raymond Knopp's avatar
Raymond Knopp committed
853 854 855 856

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

857
      if (openair0_cfg[card].rx_freq[ant] || openair0_cfg[card].tx_freq[ant]) {
858
	ACTIVE_RF += (1<<ant)<<5;
859
        p_exmimo_config->rf.rf_mode[ant] = RF_MODE_BASE;
860 861
        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]);
862
      }
863

Raymond Knopp's avatar
Raymond Knopp committed
864
      if (openair0_cfg[card].tx_freq[ant]>0) {
865 866 867
        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
868
        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]);
869 870

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

872 873 874
	for (i=0;i<307200;i++) {
	  ((uint32_t*)openair0_exmimo_pci[card].dac_head[ant])[i] = 0x00010001;
	}
875
      }
876

Raymond Knopp's avatar
Raymond Knopp committed
877
      if (openair0_cfg[card].rx_freq[ant]>0) {
878 879
        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
880

881 882 883 884
        switch (openair0_cfg[card].rxg_mode[ant]) {
        default:
        case max_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAMax;
knopp's avatar
knopp committed
885 886 887 888 889 890 891
	  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);
	  }
892 893 894 895
          break;

        case med_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAMed;
knopp's avatar
knopp committed
896 897 898 899 900 901 902
	  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);
	  }
903 904 905 906
          break;

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

918 919 920
      } else {
        p_exmimo_config->rf.rf_mode[ant] = 0;
        p_exmimo_config->rf.do_autocal[ant] = 0;
921
      }
922

923 924
      p_exmimo_config->rf.rf_local[ant]   = rf_local[ant];
      p_exmimo_config->rf.rf_rxdc[ant]    = rf_rxdc[ant];
925

926
      if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 790000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 865000000)) {
927 928 929 930 931 932 933 934
        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;
935 936
      }
    }
937

938
    if (openair0_cfg[card].duplex_mode==duplex_mode_FDD) {
939
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD;// + TXRXSWITCH_LSB + TXRXSWITCH_LSB + ACTIVE_RF+ ACTIVE_RF;
940 941 942 943 944 945 946
      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);
    }

947
    ret = ioctl(openair0_fd, openair_DUMP_CONFIG, card);
948

949 950
    if (ret!=0)
      return(-1);
951

knopp's avatar
 
knopp committed
952
  }
953

knopp's avatar
 
knopp committed
954
  return(0);
knopp's avatar
 
knopp committed
955 956
}

957 958
int openair0_reconfig(openair0_config_t *openair0_cfg)
{
959

960 961 962
  int ant, card;

  exmimo_config_t         *p_exmimo_config;
963
  //  exmimo_id_t             *p_exmimo_id;
964 965 966 967 968 969

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

970 971 972
#ifdef DEBUG_EXMIMO
  printf("Reconfiguration of gains/frequencies\n");
#endif
973 974 975
  for (card=0; card<openair0_num_detected_cards; card++) {

    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
976
    //    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
977 978

    for (ant=0; ant<4; ant++) {
979
      if (openair0_cfg[card].tx_freq[ant]) {
980 981
        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];
982 983 984
#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
985
      }
986

Raymond Knopp's avatar
Raymond Knopp committed
987

988
      if (openair0_cfg[card].rx_freq[ant]) {
989 990
        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];
991 992 993
#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
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
        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;
        }
1008 1009 1010
      }
    }
  }
1011

1012 1013 1014
  return(0);
}

1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
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);
  
}
1027

1028 1029 1030 1031
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg){
  return(0);
}

1032
unsigned int *openair0_daq_cnt(void) {
knopp's avatar
 
knopp committed
1033 1034 1035 1036

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

}