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
  } else if (openair0_cfg[0].tdd_recip_calib == 1) {
    printf("Warning, doing TDD reciprocity calibration, configuration has been done in Octave!!\n");
    return(-1);
803 804
  }

805
  for (card=0; card<openair0_num_detected_cards; card++) {
Xiwen JIANG's avatar
Xiwen JIANG committed
806
    ACTIVE_RF=0;
Raymond Knopp's avatar
 
Raymond Knopp committed
807

808 809
    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
810

811
    if (p_exmimo_id->board_swrev>=9)
812 813
      p_exmimo_config->framing.eNB_flag   = 0;
    else
814
      p_exmimo_config->framing.eNB_flag   = !UE_flag;
815

816 817 818 819 820 821
    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;
822

823 824 825 826 827
    /* device specific */
    openair0_cfg[card].iq_txshift = 4;//shift
    openair0_cfg[card].iq_rxrescale = 15;//rescale iqs


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

Raymond Knopp's avatar
 
Raymond Knopp committed
858
    }
859

860
#if (BOARD_SWREV_CNTL2>=0x0A)
861

862 863
    for (ant=0; ant<4; ant++)
      p_exmimo_config->framing.resampling_factor[ant] = resampling_factor;
864

865 866 867
#else
    p_exmimo_config->framing.resampling_factor = resampling_factor;
#endif
868 869

    for (ant=0; ant<4; ant++) {
870 871 872 873 874 875
      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
876 877 878
      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];

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

Raymond Knopp's avatar
Raymond Knopp committed
886
      if (openair0_cfg[card].tx_freq[ant]>0) {
887 888 889
        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
890
        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]);
891 892

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

894 895 896
	for (i=0;i<307200;i++) {
	  ((uint32_t*)openair0_exmimo_pci[card].dac_head[ant])[i] = 0x00010001;
	}
897
      }
898

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

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

        case med_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAMed;
922 923 924 925 926 927 928
	  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);
	  }
929 930 931 932
          break;

        case byp_gain:
          p_exmimo_config->rf.rf_mode[ant] += LNAByp;
933 934 935 936 937 938 939
	  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);
	  }
940 941
          break;
        }
942 943
        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]);

944 945 946
      } else {
        p_exmimo_config->rf.rf_mode[ant] = 0;
        p_exmimo_config->rf.do_autocal[ant] = 0;
947
      }
948

949 950
      p_exmimo_config->rf.rf_local[ant]   = rf_local[ant];
      p_exmimo_config->rf.rf_rxdc[ant]    = rf_rxdc[ant];
951

952
      if (( p_exmimo_config->rf.rf_freq_tx[ant] >= 790000000) && ( p_exmimo_config->rf.rf_freq_tx[ant] <= 865000000)) {
953 954 955 956 957 958 959 960
        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;
961 962
      }
    }
963

964
    if (openair0_cfg[card].duplex_mode==duplex_mode_FDD) {
965
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_FDD;// + TXRXSWITCH_LSB + TXRXSWITCH_LSB + ACTIVE_RF+ ACTIVE_RF;
966 967
      printf("!!!!!setting FDD (tdd_config=%d)\n",p_exmimo_config->framing.tdd_config);
    } 
968 969
    else if (openair0_cfg[card].duplex_mode==duplex_mode_TDD) {
      p_exmimo_config->framing.tdd_config = DUPLEXMODE_TDD + TXRXSWITCH_LSB + ACTIVE_RF;
970
      printf("!!!!!setting TDD (tdd_config=%d)\n",p_exmimo_config->framing.tdd_config);
971 972 973
    } 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);
974 975
    }

976
    ret = ioctl(openair0_fd, openair_DUMP_CONFIG, card);
977

978 979
    if (ret!=0)
      return(-1);
980

Raymond Knopp's avatar
 
Raymond Knopp committed
981
  }
982

Raymond Knopp's avatar
 
Raymond Knopp committed
983
  return(0);
Raymond Knopp's avatar
 
Raymond Knopp committed
984 985
}

986 987
int openair0_reconfig(openair0_config_t *openair0_cfg)
{
988

989 990 991
  int ant, card;

  exmimo_config_t         *p_exmimo_config;
992
  //  exmimo_id_t             *p_exmimo_id;
993 994 995 996 997 998

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

999 1000 1001
#ifdef DEBUG_EXMIMO
  printf("Reconfiguration of gains/frequencies\n");
#endif
1002 1003 1004
  for (card=0; card<openair0_num_detected_cards; card++) {

    p_exmimo_config = openair0_exmimo_pci[card].exmimo_config_ptr;
1005
    //    p_exmimo_id     = openair0_exmimo_pci[card].exmimo_id_ptr;
1006 1007

    for (ant=0; ant<4; ant++) {
1008
      if (openair0_cfg[card].tx_freq[ant]) {
1009 1010
        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];
1011 1012 1013
#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
1014
      }
1015

Raymond Knopp's avatar
Raymond Knopp committed
1016

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

1041 1042 1043
  return(0);
}

1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
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);
  
}
1056

1057 1058 1059 1060
int openair0_set_gains(openair0_device* device, openair0_config_t *openair0_cfg){
  return(0);
}

1061
unsigned int *openair0_daq_cnt(void) {
Raymond Knopp's avatar
 
Raymond Knopp committed
1062 1063 1064 1065

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

}