simulator.c 21.9 KB
Newer Older
laurent's avatar
laurent committed
1 2 3 4 5
/*
  Author: Laurent THOMAS, Open Cells for Nokia
  copyleft: OpenAirInterface Software Alliance and it's licence
*/

6
/*
7 8 9 10 11
 * Open issues and limitations
 * The read and write should be called in the same thread, that is not new USRP UHD design
 * When the opposite side switch from passive reading to active R+Write, the synchro is not fully deterministic
 */

laurent's avatar
laurent committed
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/epoll.h>
#include <string.h>

#include <common/utils/assertions.h>
#include <common/utils/LOG/log.h>
#include "common_lib.h"
#include <openair1/PHY/defs_eNB.h>
#include "openair1/PHY/defs_UE.h"
30
#include <openair1/SIMULATION/TOOLS/sim.h>
laurent's avatar
laurent committed
31 32 33 34 35 36

#define PORT 4043 //TCP port for this simulator
#define CirSize 3072000 // 100ms is enough
#define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
#define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))

37 38 39 40 41 42 43 44 45 46
#define MAX_SIMULATION_CONNECTED_NODES 5
#define GENERATE_CHANNEL 10 //each frame in DL

// Fixme: datamodel, external variables in .h files, ...
#include <common/ran_context.h>
extern double snr_dB;
extern RAN_CONTEXT_t RC;
//

pthread_mutex_t Sockmutex;
laurent's avatar
laurent committed
47 48 49

typedef struct buffer_s {
  int conn_sock;
laurent's avatar
laurent committed
50
  bool alreadyRead;
laurent's avatar
laurent committed
51 52
  uint64_t lastReceivedTS;
  bool headerMode;
53
  samplesBlockHeader_t th;
laurent's avatar
laurent committed
54 55 56 57
  char *transferPtr;
  uint64_t remainToTransfer;
  char *circularBufEnd;
  sample_t *circularBuf;
58
  channel_desc_t *channel_model;
laurent's avatar
laurent committed
59 60 61 62 63 64 65
} buffer_t;

typedef struct {
  int listen_sock, epollfd;
  uint64_t nextTimestamp;
  uint64_t typeStamp;
  char *ip;
66
  int saveIQfile;
laurent's avatar
laurent committed
67
  buffer_t buf[FD_SETSIZE];
68 69 70 71
  int rx_num_channels;
  int tx_num_channels;
  double sample_rate;
  double tx_bw;
laurent's avatar
laurent committed
72 73
} rfsimulator_state_t;

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
/*
  Legacy study:
  The parameters are:
  gain&loss (decay, signal power, ...)
  either a fixed gain in dB, a target power in dBm or ACG (automatic control gain) to a target average
  => don't redo the AGC, as it was used in UE case, that must have a AGC inside the UE
  will be better to handle the "set_gain()" called by UE to apply it's gain (enable test of UE power loop)
  lin_amp = pow(10.0,.05*txpwr_dBm)/sqrt(nb_tx_antennas);
  a lot of operations in legacy, grouped in one simulation signal decay: txgain*decay*rxgain

  multi_path (auto convolution, ISI, ...)
  either we regenerate the channel (call again random_channel(desc,0)), or we keep it over subframes
  legacy: we regenerate each sub frame in UL, and each frame only in DL
*/
void rxAddInput( struct complex16 *input_sig, struct complex16 *after_channel_sig,
                 int rxAnt,
                 channel_desc_t *channelDesc,
                 int nbSamples,
                 uint64_t TS
               ) {
  // channelDesc->path_loss_dB should contain the total path gain
  // so, in actual RF: tx gain + path loss + rx gain (+antenna gain, ...)
  // UE and NB gain control to be added
  // Fixme: not sure when it is "volts" so dB is 20*log10(...) or "power", so dB is 10*log10(...)
  const double pathLossLinear = pow(10,channelDesc->path_loss_dB/20.0);
  // Energy in one sample to calibrate input noise
  //Fixme: modified the N0W computation, not understand the origin value
  const double KT=1.38e-23*290; //Boltzman*temperature
  // sampling rate is linked to acquisition band (the input pass band filter)
  const double noise_figure_watt = KT*channelDesc->sampling_rate;
  // Fixme: how to convert a noise in Watt into a 12 bits value out of the RF ADC ?
  // the parameter "-s" is declared as SNR, but the input power is not well defined
  // −132.24 dBm is a LTE subcarrier noise, that was used in origin code (15KHz BW thermal noise)
107
  const double rxGain= 132.24 - snr_dB;
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
  const double noise_per_sample = sqrt(0.5*noise_figure_watt) * pow(10,rxGain/20);
  // Fixme: we don't fill the offset length samples at begining ?
  // anyway, in today code, channel_offset=0
  const int dd = abs(channelDesc->channel_offset);
  const int nbTx=channelDesc->nb_tx;

  for (int i=0; i<((int)nbSamples-dd); i++) {
    struct complex16 *out_ptr=after_channel_sig+dd+i;
    struct complex rx_tmp= {0};

    for (int txAnt=0; txAnt < nbTx; txAnt++) {
      const struct complex *channelModel= channelDesc->ch[rxAnt+(txAnt*channelDesc->nb_rx)];

      //const struct complex *channelModelEnd=channelModel+channelDesc->channel_length;
      for (int l = 0; l<(int)channelDesc->channel_length; l++) {
        // let's assume TS+i >= l
        // fixme: the rfsimulator current structure is interleaved antennas
        // this has been designed to not have to wait a full block transmission
        // but it is not very usefull
        // it would be better to split out each antenna in a separate flow
        // that will allow to mix ru antennas freely
        struct complex16 tx16=input_sig[((TS+i-l)*nbTx+txAnt)%CirSize];
        rx_tmp.x += tx16.r * channelModel[l].x - tx16.i * channelModel[l].y;
        rx_tmp.y += tx16.i * channelModel[l].x + tx16.r * channelModel[l].y;
      } //l
    }

    out_ptr->r += round(rx_tmp.x*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
    /*
      printf("in: %d, out %d= %f*%f + %f*%f\n",
138
      input_sig[((TS+i)*nbTx)%CirSize].r, out_ptr->r , rx_tmp.x,
139 140 141 142 143
      pathLossLinear, noise_per_sample,gaussdouble(0.0,1.0));
    */
    out_ptr->i += round(rx_tmp.y*pathLossLinear + noise_per_sample*gaussdouble(0.0,1.0));
    out_ptr++;
  }
144

145 146
  if ( (TS*nbTx)%CirSize+nbSamples <= CirSize )
    // Cast to a wrong type for compatibility !
147 148 149 150 151
    LOG_D(HW,"Input power %f, output power: %f, channel path loss %f, noise coeff: %f \n",
          10*log10((double)signal_energy((int32_t *)&input_sig[(TS*nbTx)%CirSize], nbSamples)),
          10*log10((double)signal_energy((int32_t *)after_channel_sig, nbSamples)),
          channelDesc->path_loss_dB,
          10*log10(noise_per_sample));
152 153
}

laurent's avatar
laurent committed
154 155 156 157 158
void allocCirBuf(rfsimulator_state_t *bridge, int sock) {
  buffer_t *ptr=&bridge->buf[sock];
  AssertFatal ( (ptr->circularBuf=(sample_t *) malloc(sampleToByte(CirSize,1))) != NULL, "");
  ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1);
  ptr->conn_sock=sock;
159 160
  ptr->alreadyRead=false;
  ptr->lastReceivedTS=0;
laurent's avatar
laurent committed
161 162
  ptr->headerMode=true;
  ptr->transferPtr=(char *)&ptr->th;
163
  ptr->remainToTransfer=sizeof(samplesBlockHeader_t);
laurent's avatar
laurent committed
164 165 166 167 168 169
  int sendbuff=1000*1000*10;
  AssertFatal ( setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) == 0, "");
  struct epoll_event ev= {0};
  ev.events = EPOLLIN | EPOLLRDHUP;
  ev.data.fd = sock;
  AssertFatal(epoll_ctl(bridge->epollfd, EPOLL_CTL_ADD,  sock, &ev) != -1, "");
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
  // create channel simulation model for this mode reception
  // snr_dB is pure global, coming from configuration paramter "-s"
  // Fixme: referenceSignalPower should come from the right place
  // but the datamodel is inconsistant
  // legacy: RC.ru[ru_id]->frame_parms.pdsch_config_common.referenceSignalPower
  // (must not come from ru[]->frame_parms as it doesn't belong to ru !!!)
  // Legacy sets it as:
  // ptr->channel_model->path_loss_dB = -132.24 + snr_dB - RC.ru[0]->frame_parms->pdsch_config_common.referenceSignalPower;
  // we use directly the paramter passed on the command line ("-s")
  // the value channel_model->path_loss_dB seems only a storage place (new_channel_desc_scm() only copy the passed value)
  // Legacy changes directlty the variable channel_model->path_loss_dB place to place
  // while calling new_channel_desc_scm() with path losses = 0
  ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
                                          AWGN,
                                          bridge->sample_rate,
                                          bridge->tx_bw,
                                          0.0, // forgetting_factor
                                          0, // maybe used for TA
                                          0); // path_loss in dB
  random_channel(ptr->channel_model,false);
laurent's avatar
laurent committed
190 191 192 193 194 195
}

void removeCirBuf(rfsimulator_state_t *bridge, int sock) {
  AssertFatal( epoll_ctl(bridge->epollfd, EPOLL_CTL_DEL,  sock, NULL) != -1, "");
  close(sock);
  free(bridge->buf[sock].circularBuf);
196 197 198
  // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented
  // a lot of mem leaks
  free(bridge->buf[sock].channel_model);
laurent's avatar
laurent committed
199 200 201 202
  memset(&bridge->buf[sock], 0, sizeof(buffer_t));
  bridge->buf[sock].conn_sock=-1;
}

laurent's avatar
laurent committed
203 204 205 206 207
void socketError(rfsimulator_state_t *bridge, int sock) {
  if (bridge->buf[sock].conn_sock!=-1) {
    LOG_W(HW,"Lost socket \n");
    removeCirBuf(bridge, sock);

208
    if (bridge->typeStamp==UE_MAGICDL_FDD)
laurent's avatar
laurent committed
209 210 211 212
      exit(1);
  }
}

laurent's avatar
laurent committed
213 214 215 216 217 218 219
#define helpTxt "\
\x1b[31m\
rfsimulator: error: you have to run one UE and one eNB\n\
For this, export RFSIMULATOR=enb (eNB case) or \n\
                 RFSIMULATOR=<an ip address> (UE case)\n\
\x1b[m"

laurent's avatar
laurent committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
enum  blocking_t {
  notBlocking,
  blocking
};

void setblocking(int sock, enum blocking_t active) {
  int opts;
  AssertFatal( (opts = fcntl(sock, F_GETFL)) >= 0,"");

  if (active==blocking)
    opts = opts & ~O_NONBLOCK;
  else
    opts = opts | O_NONBLOCK;

  AssertFatal(fcntl(sock, F_SETFL, opts) >= 0, "");
}

237
static bool flushInput(rfsimulator_state_t *t, int timeout);
laurent's avatar
laurent committed
238

239
void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) {
240 241 242 243 244
  if (t->saveIQfile != -1) {
    if (write(t->saveIQfile, _buf, count) != count )
      LOG_E(HW,"write in save iq file failed (%s)\n",strerror(errno));
  }

245
  AssertFatal(fd>=0 && _buf && count >0 && t,
246
              "Bug: %d/%p/%zd/%p", fd, _buf, count, t);
laurent's avatar
laurent committed
247
  char *buf = _buf;
248
  ssize_t l;
laurent's avatar
laurent committed
249
  setblocking(fd, notBlocking);
laurent's avatar
laurent committed
250 251 252

  while (count) {
    l = write(fd, buf, count);
laurent's avatar
laurent committed
253

laurent's avatar
laurent committed
254
    if (l <= 0) {
laurent's avatar
laurent committed
255
      if (errno==EINTR)
laurent's avatar
laurent committed
256
        continue;
laurent's avatar
laurent committed
257

laurent's avatar
laurent committed
258
      if(errno==EAGAIN) {
259 260
        // The opposite side is saturated
        // we read incoming sockets meawhile waiting
261
        flushInput(t, 5);
laurent's avatar
laurent committed
262 263 264
        continue;
      } else
        return;
laurent's avatar
laurent committed
265 266 267 268 269 270 271 272 273
    }

    count -= l;
    buf += l;
  }
}

int server_start(openair0_device *device) {
  rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv;
274
  t->typeStamp=ENB_MAGICDL_FDD;
laurent's avatar
laurent committed
275 276 277 278
  AssertFatal((t->listen_sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
  int enable = 1;
  AssertFatal(setsockopt(t->listen_sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) == 0, "");
  struct sockaddr_in addr = {
laurent's avatar
laurent committed
279 280 281 282 283 284
sin_family:
    AF_INET,
sin_port:
    htons(PORT),
sin_addr:
    { s_addr: INADDR_ANY }
laurent's avatar
laurent committed
285 286 287 288 289 290 291 292 293 294 295 296
  };
  bind(t->listen_sock, (struct sockaddr *)&addr, sizeof(addr));
  AssertFatal(listen(t->listen_sock, 5) == 0, "");
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = t->listen_sock;
  AssertFatal(epoll_ctl(t->epollfd, EPOLL_CTL_ADD,  t->listen_sock, &ev) != -1, "");
  return 0;
}

int start_ue(openair0_device *device) {
  rfsimulator_state_t *t = device->priv;
297
  t->typeStamp=UE_MAGICDL_FDD;
laurent's avatar
laurent committed
298 299 300
  int sock;
  AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
  struct sockaddr_in addr = {
laurent's avatar
laurent committed
301 302 303 304 305 306
sin_family:
    AF_INET,
sin_port:
    htons(PORT),
sin_addr:
    { s_addr: INADDR_ANY }
laurent's avatar
laurent committed
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
  };
  addr.sin_addr.s_addr = inet_addr(t->ip);
  bool connected=false;

  while(!connected) {
    LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", t->ip, PORT);

    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
      LOG_I(HW,"rfsimulator: connection established\n");
      connected=true;
    }

    perror("rfsimulator");
    sleep(1);
  }

  setblocking(sock, notBlocking);
  allocCirBuf(t, sock);
laurent's avatar
laurent committed
325
  t->buf[sock].alreadyRead=true; // UE will start blocking on read
laurent's avatar
laurent committed
326 327
  return 0;
}
328

laurent's avatar
laurent committed
329
uint64_t lastW=-1;
laurent's avatar
laurent committed
330 331
int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
  rfsimulator_state_t *t = device->priv;
Laurent's avatar
Laurent committed
332
  LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp);
laurent's avatar
laurent committed
333 334 335 336 337

  for (int i=0; i<FD_SETSIZE; i++) {
    buffer_t *ptr=&t->buf[i];

    if (ptr->conn_sock >= 0 ) {
338
      samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp};
laurent's avatar
laurent committed
339
      fullwrite(ptr->conn_sock,&header, sizeof(header), t);
laurent's avatar
laurent committed
340 341 342 343 344 345 346 347 348
      sample_t tmpSamples[nsamps][nbAnt];

      for(int a=0; a<nbAnt; a++) {
        sample_t *in=(sample_t *)samplesVoid[a];

        for(int s=0; s<nsamps; s++)
          tmpSamples[s][a]=in[s];
      }

laurent's avatar
laurent committed
349 350
      if (ptr->conn_sock >= 0 )
        fullwrite(ptr->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t);
laurent's avatar
laurent committed
351 352
    }
  }
353

laurent's avatar
laurent committed
354
  lastW=timestamp;
laurent's avatar
laurent committed
355 356
  LOG_D(HW,"sent %d samples at time: %ld->%ld, energy in first antenna: %d\n",
        nsamps, timestamp, timestamp+nsamps, signal_energy(samplesVoid[0], nsamps) );
357 358
  // Let's verify we don't have incoming data
  // This is mandatory when the opposite side don't transmit
359
  // This is mandatory when the opposite side don't transmit
360
  flushInput(t, 0);
361
  pthread_mutex_unlock(&Sockmutex);
laurent's avatar
laurent committed
362 363 364
  return nsamps;
}

365
static bool flushInput(rfsimulator_state_t *t, int timeout) {
laurent's avatar
laurent committed
366 367 368
  // Process all incoming events on sockets
  // store the data in lists
  struct epoll_event events[FD_SETSIZE]= {0};
369
  int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, timeout);
laurent's avatar
laurent committed
370 371

  if ( nfds==-1 ) {
372
    if ( errno==EINTR || errno==EAGAIN ) {
laurent's avatar
laurent committed
373
      return false;
374
    } else
laurent's avatar
laurent committed
375 376 377 378 379 380 381 382 383
      AssertFatal(false,"error in epoll_wait\n");
  }

  for (int nbEv = 0; nbEv < nfds; ++nbEv) {
    int fd=events[nbEv].data.fd;

    if (events[nbEv].events & EPOLLIN && fd == t->listen_sock) {
      int conn_sock;
      AssertFatal( (conn_sock = accept(t->listen_sock,NULL,NULL)) != -1, "");
laurent's avatar
laurent committed
384
      setblocking(conn_sock, notBlocking);
laurent's avatar
laurent committed
385 386 387 388
      allocCirBuf(t, conn_sock);
      LOG_I(HW,"A ue connected\n");
    } else {
      if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) {
laurent's avatar
laurent committed
389
        socketError(t,fd);
laurent's avatar
laurent committed
390 391 392 393 394 395 396 397 398 399
        continue;
      }

      buffer_t *b=&t->buf[fd];

      if ( b->circularBuf == NULL ) {
        LOG_E(HW, "received data on not connected socket %d\n", events[nbEv].data.fd);
        continue;
      }

400
      ssize_t blockSz;
laurent's avatar
laurent committed
401 402 403 404 405 406 407 408

      if ( b->headerMode)
        blockSz=b->remainToTransfer;
      else
        blockSz= b->transferPtr+b->remainToTransfer < b->circularBufEnd ?
                 b->remainToTransfer :
                 b->circularBufEnd - 1 - b->transferPtr ;

409
      ssize_t sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
laurent's avatar
laurent committed
410 411 412 413 414 415 416 417 418

      if ( sz < 0 ) {
        if ( errno != EAGAIN ) {
          LOG_E(HW,"socket failed %s\n", strerror(errno));
          abort();
        }
      } else if ( sz == 0 )
        continue;

419
      LOG_D(HW, "Socket rcv %zd bytes\n", sz);
laurent's avatar
laurent committed
420 421 422 423 424 425 426 427
      AssertFatal((b->remainToTransfer-=sz) >= 0, "");
      b->transferPtr+=sz;

      if (b->transferPtr==b->circularBufEnd - 1)
        b->transferPtr=(char *)b->circularBuf;

      // check the header and start block transfer
      if ( b->headerMode==true && b->remainToTransfer==0) {
428 429
        AssertFatal( (t->typeStamp == UE_MAGICDL_FDD  && b->th.magic==ENB_MAGICDL_FDD) ||
                     (t->typeStamp == ENB_MAGICDL_FDD && b->th.magic==UE_MAGICDL_FDD), "Socket Error in protocol");
laurent's avatar
laurent committed
430
        b->headerMode=false;
laurent's avatar
laurent committed
431 432
        b->alreadyRead=true;

laurent's avatar
laurent committed
433 434 435
        if ( b->lastReceivedTS != b->th.timestamp) {
          int nbAnt= b->th.nbAnt;

436 437 438 439 440 441
          for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) {
            for (int a=0; a < nbAnt; a++) {
              b->circularBuf[(index*nbAnt+a)%CirSize].r=0;
              b->circularBuf[(index*nbAnt+a)%CirSize].i=0;
            }
          }
laurent's avatar
laurent committed
442 443 444 445 446

          LOG_W(HW,"gap of: %ld in reception\n", b->th.timestamp-b->lastReceivedTS );
        }

        b->lastReceivedTS=b->th.timestamp;
447 448
        AssertFatal(lastW == -1 || ( abs((double)lastW-b->lastReceivedTS) < (double)CirSize),
                    "Tx/Rx shift too large Tx:%lu, Rx:%lu\n", lastW, b->lastReceivedTS);
laurent's avatar
laurent committed
449 450 451 452 453
        b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize];
        b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
      }

      if ( b->headerMode==false ) {
454
        LOG_D(HW,"Set b->lastReceivedTS %ld\n", b->lastReceivedTS);
laurent's avatar
laurent committed
455
        b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt);
456 457 458 459 460

        // First block in UE, resync with the eNB current TS
        if ( t->nextTimestamp == 0 )
          t->nextTimestamp=b->lastReceivedTS-b->th.size;

laurent's avatar
laurent committed
461 462 463 464
        if ( b->remainToTransfer==0) {
          LOG_D(HW,"Completed block reception: %ld\n", b->lastReceivedTS);
          b->headerMode=true;
          b->transferPtr=(char *)&b->th;
465
          b->remainToTransfer=sizeof(samplesBlockHeader_t);
laurent's avatar
laurent committed
466 467 468 469 470 471 472 473 474 475
          b->th.magic=-1;
        }
      }
    }
  }

  return nfds>0;
}

int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) {
laurent's avatar
laurent committed
476
  if (nbAnt != 1) {
477
    LOG_W(HW, "rfsimulator: only 1 antenna tested\n");
laurent's avatar
laurent committed
478
  }
laurent's avatar
laurent committed
479

480
  pthread_mutex_lock(&Sockmutex);
laurent's avatar
laurent committed
481 482 483 484 485 486 487 488 489 490 491 492
  rfsimulator_state_t *t = device->priv;
  LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld\n", nsamps, t->nextTimestamp+nsamps);
  // deliver data from received data
  // check if a UE is connected
  int first_sock;

  for (first_sock=0; first_sock<FD_SETSIZE; first_sock++)
    if (t->buf[first_sock].circularBuf != NULL )
      break;

  if ( first_sock ==  FD_SETSIZE ) {
    // no connected device (we are eNB, no UE is connected)
493
    if (!flushInput(t, 10)) {
laurent's avatar
laurent committed
494 495 496 497 498 499
      for (int x=0; x < nbAnt; x++)
        memset(samplesVoid[x],0,sampleToByte(nsamps,1));

      t->nextTimestamp+=nsamps;
      LOG_W(HW,"Generated void samples for Rx: %ld\n", t->nextTimestamp);
      *ptimestamp = t->nextTimestamp-nsamps;
500
      pthread_mutex_unlock(&Sockmutex);
laurent's avatar
laurent committed
501 502 503 504 505 506 507 508
      return nsamps;
    }
  } else {
    bool have_to_wait;

    do {
      have_to_wait=false;

Laurent's avatar
Laurent committed
509
      for ( int sock=0; sock<FD_SETSIZE; sock++) {
510
        if ( t->buf[sock].circularBuf && t->buf[sock].alreadyRead )
511 512 513 514 515
          if ( t->buf[sock].lastReceivedTS == 0 ||
               (t->nextTimestamp+nsamps) > t->buf[sock].lastReceivedTS ) {
            have_to_wait=true;
            break;
          }
Laurent's avatar
Laurent committed
516
      }
laurent's avatar
laurent committed
517 518 519 520 521 522

      if (have_to_wait)
        /*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n",
          ptr->lastReceivedTS,
          t->nextTimestamp+nsamps);
        */
523
        flushInput(t, 3);
laurent's avatar
laurent committed
524 525 526 527
    } while (have_to_wait);
  }

  // Clear the output buffer
laurent's avatar
laurent committed
528 529
  for (int a=0; a<nbAnt; a++)
    memset(samplesVoid[a],0,sampleToByte(nsamps,1));
laurent's avatar
laurent committed
530

531
  // Add all input nodes signal in the output buffer
laurent's avatar
laurent committed
532 533 534
  for (int sock=0; sock<FD_SETSIZE; sock++) {
    buffer_t *ptr=&t->buf[sock];

laurent's avatar
laurent committed
535
    if ( ptr->circularBuf && ptr->alreadyRead ) {
536 537 538 539 540 541 542
      bool reGenerateChannel=false;

      //fixme: when do we regenerate
      // it seems legacy behavior is: never in UL, each frame in DL
      if (reGenerateChannel)
        random_channel(ptr->channel_model,0);

543 544
      for (int a=0; a<nbAnt; a++)
        rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
545 546 547 548 549
                    a,
                    ptr->channel_model,
                    nsamps,
                    t->nextTimestamp
                  );
laurent's avatar
laurent committed
550 551 552 553 554 555 556 557 558
    }
  }

  *ptimestamp = t->nextTimestamp; // return the time of the first sample
  t->nextTimestamp+=nsamps;
  LOG_D(HW,"Rx to upper layer: %d from %ld to %ld, energy in first antenna %d\n",
        nsamps,
        *ptimestamp, t->nextTimestamp,
        signal_energy(samplesVoid[0], nsamps));
559
  pthread_mutex_unlock(&Sockmutex);
laurent's avatar
laurent committed
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
  return nsamps;
}
int rfsimulator_request(openair0_device *device, void *msg, ssize_t msg_len) {
  abort();
  return 0;
}
int rfsimulator_reply(openair0_device *device, void *msg, ssize_t msg_len) {
  abort();
  return 0;
}
int rfsimulator_get_stats(openair0_device *device) {
  return 0;
}
int rfsimulator_reset_stats(openair0_device *device) {
  return 0;
}
void rfsimulator_end(openair0_device *device) {}
int rfsimulator_stop(openair0_device *device) {
  return 0;
}
int rfsimulator_set_freq(openair0_device *device, openair0_config_t *openair0_cfg,int exmimo_dump_config) {
  return 0;
}
int rfsimulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) {
  return 0;
}
__attribute__((__visibility__("default")))
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
588 589 590
  // to change the log level, use this on command line
  // --log_config.hw_log_level debug
  // (for phy layer, replace "hw" by "phy"
laurent's avatar
laurent committed
591 592 593 594 595 596 597
  rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);

  if ((rfsimulator->ip=getenv("RFSIMULATOR")) == NULL ) {
    LOG_E(HW,helpTxt);
    exit(1);
  }

598 599
  pthread_mutex_init(&Sockmutex, NULL);

600 601 602 603 604
  if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 ||
       strncasecmp(rfsimulator->ip,"server",3) == 0 )
    rfsimulator->typeStamp = ENB_MAGICDL_FDD;
  else
    rfsimulator->typeStamp = UE_MAGICDL_FDD;
605

606
  LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "(eg)NB" : "UE");
607 608 609 610 611 612 613 614 615 616 617 618 619
  char *saveF;

  if ((saveF=getenv("saveIQfile")) != NULL) {
    rfsimulator->saveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666);

    if ( rfsimulator->saveIQfile != -1 )
      LOG_I(HW,"rfsimulator: will save written IQ samples  in %s\n", saveF);
    else
      LOG_E(HW, "can't open %s for IQ saving (%s)\n", saveF, strerror(errno));
  } else
    rfsimulator->saveIQfile = -1;

  device->trx_start_func       = rfsimulator->typeStamp == ENB_MAGICDL_FDD ?
laurent's avatar
laurent committed
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
                                 server_start :
                                 start_ue;
  device->trx_get_stats_func   = rfsimulator_get_stats;
  device->trx_reset_stats_func = rfsimulator_reset_stats;
  device->trx_end_func         = rfsimulator_end;
  device->trx_stop_func        = rfsimulator_stop;
  device->trx_set_freq_func    = rfsimulator_set_freq;
  device->trx_set_gains_func   = rfsimulator_set_gains;
  device->trx_write_func       = rfsimulator_write;
  device->trx_read_func      = rfsimulator_read;
  /* let's pretend to be a b2x0 */
  device->type = USRP_B200_DEV;
  device->openair0_cfg=&openair0_cfg[0];
  device->priv = rfsimulator;

  for (int i=0; i<FD_SETSIZE; i++)
    rfsimulator->buf[i].conn_sock=-1;

  AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1,"");
639 640 641 642 643 644 645
  // initialize channel simulation
  rfsimulator->tx_num_channels=openair0_cfg->tx_num_channels;
  rfsimulator->rx_num_channels=openair0_cfg->rx_num_channels;
  rfsimulator->sample_rate=openair0_cfg->sample_rate;
  rfsimulator->tx_bw=openair0_cfg->tx_bw;
  randominit(0);
  set_taus_seed(0);
laurent's avatar
laurent committed
646 647
  return 0;
}