openair0_lib.c 33.7 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>
Raymond Knopp's avatar
 
Raymond 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"
Raymond Knopp's avatar
 
Raymond Knopp committed
55
#include "common_lib.h"
56 57 58

#include <pthread.h>

Raymond Knopp's avatar
Raymond Knopp committed
59

Raymond Knopp's avatar
 
Raymond 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;

Raymond Knopp's avatar
 
Raymond 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
Raymond Knopp's avatar
 
Raymond 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

extern volatile int                    oai_exit;


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

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

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

96 97 98 99 100
  return ans ;
}

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

104 105
  int card;
  int ant;
Raymond Knopp's avatar
 
Raymond Knopp committed
106

107
  PAGE_SHIFT = log2_int( sysconf( _SC_PAGESIZE ) );
Raymond Knopp's avatar
 
Raymond Knopp committed
108

109

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

114
  ioctl(openair0_fd, openair_GET_NUM_DETECTED_CARDS, &openair0_num_detected_cards);
Raymond Knopp's avatar
 
Raymond Knopp committed
115

116 117


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

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

  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
Raymond Knopp's avatar
 
Raymond 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]);
Raymond Knopp's avatar
 
Raymond 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]);
Raymond Knopp's avatar
 
Raymond 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;
      }
    */
Raymond Knopp's avatar
 
Raymond 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++) {
Raymond Knopp's avatar
 
Raymond 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]);
Raymond Knopp's avatar
 
Raymond 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]);
Raymond Knopp's avatar
 
Raymond 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
}
Raymond Knopp's avatar
 
Raymond 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)
Raymond Knopp's avatar
 
Raymond 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
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);
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) {

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

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

533
  ret = pthread_mutex_lock(&exm->watchdog_mutex);
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 560

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

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

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

Raymond Knopp's avatar
Raymond Knopp committed
580
#ifdef DEBUG_EXMIMO
581
  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
582
#endif
583 584 585 586 587 588
  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
589
#ifdef DEBUG_EXMIMO
590 591
      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
592
#endif
593 594 595 596 597 598 599 600
      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
601
      pthread_mutex_lock(&exm->watchdog_mutex);
602 603 604 605 606 607
      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
608
    }
Raymond Knopp's avatar
Raymond Knopp committed
609

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
  
  
    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));
	}
      }
635
    }
636
    pthread_mutex_lock(&exm->watchdog_mutex);
637 638 639 640 641 642 643
    exm->last_ts_rx += n;
    pthread_mutex_unlock(&exm->watchdog_mutex);    
    if (n==n1) {
      *ptimestamp=exm->last_ts_rx;
    }
    ntot+=n;
   }
644
  
645

646

Raymond Knopp's avatar
Raymond Knopp committed
647

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

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

}

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

  exmimo_state_t *exm=device->priv;

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

  return(0);

}

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

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

}

703
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
Raymond Knopp's avatar
 
Raymond Knopp committed
704 705

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

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

Raymond Knopp's avatar
 
Raymond Knopp committed
718 719
    if (ret == -2)
      printf("Error mapping bigshm");
720

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

Raymond Knopp's avatar
 
Raymond Knopp committed
724 725 726
    return(ret);
  }

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

733 734 735
  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;
736

737
    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);
Raymond Knopp's avatar
 
Raymond Knopp committed
738

739 740 741 742 743
    // 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);
    }
744
  }
Raymond Knopp's avatar
 
Raymond Knopp committed
745

746 747
  device->type             = EXMIMO_DEV; 

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

763

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

773 774
  create_watchdog(device);

775 776
  return(0);
}
Raymond Knopp's avatar
 
Raymond Knopp committed
777

778 779 780 781 782 783 784
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};

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

794 795
  exmimo_config_t         *p_exmimo_config;
  exmimo_id_t             *p_exmimo_id;
796

797 798 799
  if (!openair0_cfg) {
    printf("Error, openair0_cfg is null!!\n");
    return(-1);
800 801 802 803 804 805 806 807 808 809
  }


  /* device specific */
  for (card=0; card<openair0_num_detected_cards; card++) {
    openair0_cfg[card].iq_txshift = 4;//shift
    openair0_cfg[card].iq_rxrescale = 15;//rescale iqs
  }

  if (openair0_cfg[0].tdd_recip_calib == 1) {
810 811
    printf("Warning, doing TDD reciprocity calibration, configuration has been done in Octave!!\n");
    return(-1);
812 813
  }

814
  for (card=0; card<openair0_num_detected_cards; card++) {
Xiwen JIANG's avatar
Xiwen JIANG committed
815
    ACTIVE_RF=0;
Raymond Knopp's avatar
 
Raymond Knopp committed
816

817 818
    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
819

820
    if (p_exmimo_id->board_swrev>=9)
821 822
      p_exmimo_config->framing.eNB_flag   = 0;
    else
823
      p_exmimo_config->framing.eNB_flag   = !UE_flag;
824

825 826 827 828 829 830
    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;
831

832

833 834
    if (openair0_cfg[card].sample_rate==30.72e6) {
      resampling_factor = 0;
835
      if (openair0_cfg[card].duplex_mode==duplex_mode_TDD_workaround) {
836 837
        printf("Warning: TDD workaround may not work for bw 20");
      }
838 839
      rx_filter = RXLPF10;
      tx_filter = TXLPF10;
840
    } else if (openair0_cfg[card].sample_rate==15.36e6) {
841
      resampling_factor = 1;
842
      if (openair0_cfg[card].duplex_mode==duplex_mode_TDD_workaround) 
843 844 845
        rx_filter = RXLPF10;
      else
        rx_filter = RXLPF5;
846
      tx_filter = TXLPF5;
847
    } else if (openair0_cfg[card].sample_rate==7.68e6) {
848
      resampling_factor = 2;
849
      if (openair0_cfg[card].duplex_mode==duplex_mode_TDD_workaround) 
Xiwen JIANG's avatar
Xiwen JIANG committed
850 851
        rx_filter = RXLPF5;
      else 
852
        rx_filter = RXLPF25;
853
      tx_filter = TXLPF25;
854
    } else {
855 856
      printf("Sampling rate not supported, using default 7.68MHz");
      resampling_factor = 2;
857
      if (openair0_cfg[card].duplex_mode==duplex_mode_TDD_workaround) 
858 859 860
        rx_filter = RXLPF5;
      else
        rx_filter = RXLPF25;
861
      tx_filter = TXLPF25;
862

Raymond Knopp's avatar
 
Raymond Knopp committed
863
    }
864

865
#if (BOARD_SWREV_CNTL2>=0x0A)
866

867 868
    for (ant=0; ant<4; ant++)
      p_exmimo_config->framing.resampling_factor[ant] = resampling_factor;
869

870 871 872
#else
    p_exmimo_config->framing.resampling_factor = resampling_factor;
#endif
873 874

    for (ant=0; ant<4; ant++) {
875 876 877 878 879 880
      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
881 882 883
      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];

884
      if (openair0_cfg[card].rx_freq[ant] || openair0_cfg[card].tx_freq[ant]) {
885
	ACTIVE_RF += (1<<ant)<<5;
886
        p_exmimo_config->rf.rf_mode[ant] = RF_MODE_BASE;
887
        p_exmimo_config->rf.do_autocal[ant] = 1;//openair0_cfg[card].autocal[ant];
888
	printf("card %d, antenna %d, autocal %d\n",card,ant,p_exmimo_config->rf.do_autocal[ant]);
889
      }
890

Raymond Knopp's avatar
Raymond Knopp committed
891
      if (openair0_cfg[card].tx_freq[ant]>0) {
892 893 894
        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
895
        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]);
896 897

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

899 900 901
	for (i=0;i<307200;i++) {
	  ((uint32_t*)openair0_exmimo_pci[card].dac_head[ant])[i] = 0x00010001;
	}
902
      }
903

Raymond Knopp's avatar
Raymond Knopp committed
904
      if (openair0_cfg[card].rx_freq[ant]>0) {
905 906
        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];
907 908
       
        // TDD workaround
909
        if (openair0_cfg[card].duplex_mode==duplex_mode_TDD_workaround)
910
          p_exmimo_config->rf.rf_freq_rx[ant] += openair0_cfg[card].sample_rate/4; 
911

912 913 914 915
        switch (openair0_cfg[card].rxg_mode[ant]) {
        default:
        case max_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAMax;
916 917 918 919 920 921 922
	  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);
	  }
923 924 925 926
          break;

        case med_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAMed;
927 928 929 930 931 932 933
	  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);
	  }
934 935 936 937
          break;

        case byp_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAByp;
938 939 940 941 942 943 944
	  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);
	  }
945 946
          break;
        }
947 948
        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]);

949 950 951
      } else {
        p_exmimo_config->rf.rf_mode[ant] = 0;
        p_exmimo_config->rf.do_autocal[ant] = 0;
952
      }
953

954 955
      p_exmimo_config->rf.rf_local[ant]   = rf_local[ant];
      p_exmimo_config->rf.rf_rxdc[ant]    = rf_rxdc[ant];
956

957
      if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 790000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 865000000)) {
958 959 960 961 962 963 964 965
        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;
966 967
      }
    }
968

969
    if (openair0_cfg[card].duplex_mode==duplex_mode_FDD) {
970
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD;// + TXRXSWITCH_LSB + TXRXSWITCH_LSB + ACTIVE_RF+ ACTIVE_RF;
971 972
      printf("!!!!!setting FDD (tdd_config=%d)\n",p_exmimo_config->framing.tdd_config);
    } 
973 974
    else if (openair0_cfg[card].duplex_mode==duplex_mode_TDD) {
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_TDD + TXRXSWITCH_LSB + ACTIVE_RF;
975
      printf("!!!!!setting TDD (tdd_config=%d)\n",p_exmimo_config->framing.tdd_config);
976 977 978
    } else {
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD + TXRXSWITCH_LSB;
      printf("!!!!!setting TDD WORKAROUND (tdd_config=%d)\n",p_exmimo_config->framing.tdd_config);
979 980
    }

981
    ret = ioctl(openair0_fd, openair_DUMP_CONFIG, card);
982

983 984
    if (ret!=0)
      return(-1);
985

Raymond Knopp's avatar
 
Raymond Knopp committed
986
  }
987

Raymond Knopp's avatar
 
Raymond Knopp committed
988
  return(0);
Raymond Knopp's avatar
 
Raymond Knopp committed
989 990
}

991 992
int openair0_reconfig(openair0_config_t *openair0_cfg)
{
993

994 995 996
  int ant, card;

  exmimo_config_t         *p_exmimo_config;
997
  //  exmimo_id_t             *p_exmimo_id;
998 999 1000 1001 1002 1003

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

1004 1005 1006
#ifdef DEBUG_EXMIMO
  printf("Reconfiguration of gains/frequencies\n");
#endif
1007 1008 1009
  for (card=0; card<openair0_num_detected_cards; card++) {

    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
1010
    //    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
1011 1012

    for (ant=0; ant<4; ant++) {
1013
      if (openair0_cfg[card].tx_freq[ant]) {
1014 1015
        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];
1016 1017 1018
#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
1019
      }
1020

Raymond Knopp's avatar
Raymond Knopp committed
1021

1022
      if (openair0_cfg[card].rx_freq[ant]) {
1023 1024
        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];
1025 1026 1027
#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
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
        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;
        }
1042 1043 1044
      }
    }
  }
1045

1046 1047 1048
  return(0);
}

1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
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);
  
}
1061

1062 1063 1064 1065
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg){
  return(0);
}

1066
unsigned int *openair0_daq_cnt(void) {
Raymond Knopp's avatar
 
Raymond Knopp committed
1067 1068 1069 1070

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

}