simulator.c 28.9 KB
Newer Older
1
/*
laurent's avatar
laurent committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1  (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
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
*      contact@openairinterface.org
22 23
*/

laurent's avatar
laurent committed
24

laurent's avatar
laurent committed
25 26 27 28 29 30
/*
 * 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
 */

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
#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>
46
#include <common/utils/load_module_shlib.h>
frtabu's avatar
frtabu committed
47
#include <common/utils/telnetsrv/telnetsrv.h>
48
#include <common/config/config_userapi.h>
49 50 51
#include "common_lib.h"
#include <openair1/PHY/defs_eNB.h>
#include "openair1/PHY/defs_UE.h"
52
#define CHANNELMOD_DYNAMICLOAD
53
#include <openair1/SIMULATION/TOOLS/sim.h>
laurent's avatar
laurent committed
54
#include <targets/ARCH/rfsimulator/rfsimulator.h>
55

56
#define PORT 4043 //default TCP port for this simulator
57
#define CirSize 307200 // 100ms is enough
58 59 60
#define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t))
#define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b)))

61 62 63 64 65
#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>
66

67 68
extern RAN_CONTEXT_t RC;
//
69

70 71 72 73 74
#define RFSIMU_SECTION    "rfsimulator"
#define RFSIMU_OPTIONS_PARAMNAME "options"
# define RFSIM_CONFIG_HELP_OPTIONS     " list of comma separated options to enable rf simulator functionalities. Available options: \n"\
  "        chanmod:   enable channel modelisation\n"\
  "        saviq:     enable saving written iqs to a file\n"
75 76 77 78
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/*                                            configuration parameters for the rfsimulator device                                                                              */
/*   optname                     helpstr                     paramflags           XXXptr                               defXXXval                          type         numelt  */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
79
#define RFSIMULATOR_PARAMS_DESC {\
80 81
    {"serveraddr",             "<ip address to connect to>\n",          0,         strptr:&(rfsimulator->ip),              defstrval:"127.0.0.1",           TYPE_STRING,    0 },\
    {"serverport",             "<port to connect to>\n",                0,         u16ptr:&(rfsimulator->port),            defuintval:PORT,                 TYPE_UINT16,    0 },\
82
    {RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS,               0,         strlistptr:NULL,                        defstrlistval:NULL,              TYPE_STRINGLIST,0 },\
83
    {"IQfile",                 "<file path to use when saving IQs>\n",  0,         strptr:&(saveF),                        defstrval:"/tmp/rfsimulator.iqs",TYPE_STRING,    0 },\
84 85
    {"modelname",              "<channel model name>\n",                0,         strptr:&(modelname),                    defstrval:"AWGN",                TYPE_STRING,    0 },\
    {"ploss",                  "<channel path loss in dB>\n",           0,         dblptr:&(rfsimulator->chan_pathloss),   defdblval:0,                     TYPE_DOUBLE,    0 },\
86 87
    {"forgetfact",             "<channel forget factor ((0 to 1)>\n",   0,         dblptr:&(rfsimulator->chan_forgetfact), defdblval:0,                     TYPE_DOUBLE,    0 },\
    {"offset",                 "<channel offset in samps>\n",           0,         iptr:&(rfsimulator->chan_offset),       defintval:0,                     TYPE_INT,       0 }\
88
  };
89

frtabu's avatar
frtabu committed
90 91 92 93 94 95 96 97 98 99 100


static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt);
static telnetshell_cmddef_t rfsimu_cmdarray[] = {
  {"setmodel","<model name>",rfsimu_setchanmod_cmd,TELNETSRV_CMDFLAG_PUSHINTPOOLQ},  
  {"","",NULL},
};

static telnetshell_vardef_t rfsimu_vardef[] = {
  {"",0,NULL}
};  
101
pthread_mutex_t Sockmutex;
102

103
typedef struct complex16 sample_t; // 2*16 bits complex number
104

105 106
typedef struct buffer_s {
  int conn_sock;
laurent's avatar
laurent committed
107
  openair0_timestamp lastReceivedTS;
108
  bool headerMode;
109
  bool trashingPacket;
110
  samplesBlockHeader_t th;
111 112 113 114
  char *transferPtr;
  uint64_t remainToTransfer;
  char *circularBufEnd;
  sample_t *circularBuf;
115
  channel_desc_t *channel_model;
116 117 118 119
} buffer_t;

typedef struct {
  int listen_sock, epollfd;
laurent's avatar
laurent committed
120
  openair0_timestamp nextTimestamp;
121
  openair0_timestamp lastWroteTS;
122 123
  uint64_t typeStamp;
  char *ip;
124
  uint16_t port;
125
  int saveIQfile;
126
  buffer_t buf[FD_SETSIZE];
127 128 129 130
  int rx_num_channels;
  int tx_num_channels;
  double sample_rate;
  double tx_bw;
131
  int channelmod;
132 133
  double chan_pathloss;
  double chan_forgetfact;
134
  int    chan_offset;
frtabu's avatar
frtabu committed
135 136
  void *telnetcmd_qid;
  poll_telnetcmdq_func_t poll_telnetcmdq;
137 138
} rfsimulator_state_t;

139

140 141 142 143 144
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;
145
  ptr->lastReceivedTS=0;
146
  ptr->headerMode=true;
147
  ptr->trashingPacket=false;
148
  ptr->transferPtr=(char *)&ptr->th;
149
  ptr->remainToTransfer=sizeof(samplesBlockHeader_t);
150
  int sendbuff=1000*1000*100;
151 152 153 154 155
  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, "");
156

157
  if ( bridge->channelmod > 0) {
158 159 160 161 162 163 164 165 166 167 168 169
    // 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
laurent's avatar
laurent committed
170 171
    static bool init_done=false;
    if (!init_done) {
172 173
	    uint64_t rand;
	    FILE *h=fopen("/dev/random","r");
frtabu's avatar
frtabu committed
174 175
        int st=fread(&rand,sizeof(rand),1,h);
        AssertFatal(st != -1, "Error reading random int %s\n",strerror(errno));
176 177 178
	    fclose(h);
      randominit(rand);
      tableNor(rand);
laurent's avatar
laurent committed
179 180
      init_done=true;
    }
181
    ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
182
                                            bridge->channelmod,
183 184
                                            bridge->sample_rate,
                                            bridge->tx_bw,
185
                                            bridge->chan_forgetfact, // forgetting_factor
186
                                            bridge->chan_offset, // maybe used for TA
187
                                            bridge->chan_pathloss); // path_loss in dB
188 189
    random_channel(ptr->channel_model,false);
  }
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);
199 200 201 202 203 204 205 206 207
  memset(&bridge->buf[sock], 0, sizeof(buffer_t));
  bridge->buf[sock].conn_sock=-1;
}

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)
209 210 211 212 213 214 215 216 217
      exit(1);
  }
}

#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\
218
                 or use rfsimulator.serveraddr configuration option\n\
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
\x1b[m"

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, "");
}

238
static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps);
239 240 241 242 243 244

void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) {
  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

246 247
  AssertFatal(fd>=0 && _buf && count >0 && t,
              "Bug: %d/%p/%zd/%p", fd, _buf, count, t);
248
  char *buf = _buf;
249
  ssize_t l;
250 251 252 253 254 255 256 257 258 259
  setblocking(fd, notBlocking);

  while (count) {
    l = write(fd, buf, count);

    if (l <= 0) {
      if (errno==EINTR)
        continue;

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

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

274
void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) {
275
  char *saveF=NULL;
276
  char *modelname=NULL;
277
  paramdef_t rfsimu_params[] = RFSIMULATOR_PARAMS_DESC;
278 279 280
  int p = config_paramidx_fromname(rfsimu_params,sizeof(rfsimu_params)/sizeof(paramdef_t), RFSIMU_OPTIONS_PARAMNAME) ;
  int ret = config_get( rfsimu_params,sizeof(rfsimu_params)/sizeof(paramdef_t),RFSIMU_SECTION);
  AssertFatal(ret >= 0, "configuration couldn't be performed");
281 282
  rfsimulator->saveIQfile = -1;

283
  for(int i=0; i<rfsimu_params[p].numelt ; i++) {
284 285 286 287 288 289 290 291 292 293
    if (strcmp(rfsimu_params[p].strlistptr[i],"saviq") == 0) {
      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));

      break;
    } else if (strcmp(rfsimu_params[p].strlistptr[i],"chanmod") == 0) {
294 295
      init_channelmod();
      rfsimulator->channelmod=modelid_fromname(modelname);
296 297 298 299
    } else {
      fprintf(stderr,"Unknown rfsimulator option: %s\n",rfsimu_params[p].strlistptr[i]);
      exit(-1);
    }
300
  }
301

302 303
  /* for compatibility keep environment variable usage */
  if ( getenv("RFSIMULATOR") != NULL ) {
304
    rfsimulator->ip=getenv("RFSIMULATOR");
305
  }
306

307
  if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 ||
308
       strncasecmp(rfsimulator->ip,"server",3) == 0 )
309 310 311 312
    rfsimulator->typeStamp = ENB_MAGICDL_FDD;
  else
    rfsimulator->typeStamp = UE_MAGICDL_FDD;
}
313

frtabu's avatar
frtabu committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt) {
  char *modelname=NULL; 
  int s = sscanf(buff,"%ms\n",&modelname);
  int channelmod=modelid_fromname(modelname);
  for (int i=0; i<FD_SETSIZE; i++) {
/*    if(rfsimulator->buf[i].conn_sock > 0) {
       channel_desc_t *cm = rfsimulator->buf[i].channel_model;

       rfsimulator->buf[i].channel_model=new_channel_desc_scm(cm->nb_tx,cm->nb_rx,
                                            channelmod,
                                            cm->sampling_rate,
                                            cm->channel_bandwidth,
                                            cm->forgetting_factor, // forgetting_factor
                                            cm->channel_offset, // maybe used for TA
                                            cm-> path_loss_dB); // path_loss in dB
	   free_channel_desc_scm(cm);
       random_channel(ptr->channel_model,false);	   
	}	*/
  }
  return CMDSTATUS_FOUND;
}

336 337
int server_start(openair0_device *device) {
  rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv;
338
  t->typeStamp=ENB_MAGICDL_FDD;
339 340 341 342 343 344 345
  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 = {
sin_family:
    AF_INET,
sin_port:
346
    htons(t->port),
347 348 349 350 351
sin_addr:
    { s_addr: INADDR_ANY }
  };
  bind(t->listen_sock, (struct sockaddr *)&addr, sizeof(addr));
  AssertFatal(listen(t->listen_sock, 5) == 0, "");
laurent's avatar
laurent committed
352
  struct epoll_event ev={0};
353 354 355 356 357 358 359 360
  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;
361
  t->typeStamp=UE_MAGICDL_FDD;
362 363 364 365 366 367
  int sock;
  AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
  struct sockaddr_in addr = {
sin_family:
    AF_INET,
sin_port:
368
    htons(t->port),
369 370 371 372 373 374 375
sin_addr:
    { s_addr: INADDR_ANY }
  };
  addr.sin_addr.s_addr = inet_addr(t->ip);
  bool connected=false;

  while(!connected) {
376
    LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", t->ip, t->port);
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

    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);
  return 0;
}

392 393 394 395
static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags, bool alreadyLocked) {
  if (!alreadyLocked)
    pthread_mutex_lock(&Sockmutex);

396
  LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp);
397 398

  for (int i=0; i<FD_SETSIZE; i++) {
laurent's avatar
laurent committed
399
    buffer_t *b=&t->buf[i];
400

laurent's avatar
laurent committed
401
    if (b->conn_sock >= 0 ) {
402
      samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp};
laurent's avatar
laurent committed
403
      fullwrite(b->conn_sock,&header, sizeof(header), t);
404 405 406 407 408 409 410 411 412
      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
413 414 415
      if (b->conn_sock >= 0 ) {
        fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t);
      }
416 417 418
    }
  }

419 420 421
  if ( t->lastWroteTS != 0 && abs((double)t->lastWroteTS-timestamp) > (double)CirSize)
    LOG_E(HW,"Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp);

laurent's avatar
laurent committed
422
  if (t->lastWroteTS > timestamp+nsamps)
423
    LOG_E(HW,"Not supported to send Tx out of order (same in USRP) %lu, %lu\n",
424 425 426 427 428 429
              t->lastWroteTS, timestamp);
  t->lastWroteTS=timestamp+nsamps;

  if (!alreadyLocked)
    pthread_mutex_unlock(&Sockmutex);

430 431 432 433 434
  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) );
  return nsamps;
}

435
int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
436
  return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags, false);
437 438 439
}

static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) {
440 441 442
  // Process all incoming events on sockets
  // store the data in lists
  struct epoll_event events[FD_SETSIZE]= {0};
443
  int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, timeout);
444 445

  if ( nfds==-1 ) {
446
    if ( errno==EINTR || errno==EAGAIN ) {
447
      return false;
448
    } else
449 450 451 452 453 454 455 456 457 458 459
      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, "");
      setblocking(conn_sock, notBlocking);
      allocCirBuf(t, conn_sock);
460 461 462 463 464 465 466
      LOG_I(HW,"A ue connected, sending the current time\n");
      struct complex16 v= {0};
      void *samplesVoid[t->tx_num_channels];

      for ( int i=0; i < t->tx_num_channels; i++)
        samplesVoid[i]=(void *)&v;

467
      rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS-1 : 0,
468
                                 samplesVoid, 1,
469
                                 t->tx_num_channels, 1, false);
470 471 472 473 474 475 476 477 478 479 480 481 482
    } else {
      if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) {
        socketError(t,fd);
        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;
      }

483
      ssize_t blockSz;
484 485 486 487 488 489 490 491

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

492
      ssize_t sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
493 494 495 496

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

502
      LOG_D(HW, "Socket rcv %zd bytes\n", sz);
503 504 505 506 507 508 509 510
      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) {
511 512
        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");
513 514
        b->headerMode=false;

515 516 517 518 519 520 521 522 523 524
        if ( t->nextTimestamp == 0 ) { // First block in UE, resync with the eNB current TS
	  t->nextTimestamp=b->th.timestamp> nsamps_for_initial ?
	    b->th.timestamp -  nsamps_for_initial :
	    0;
	  b->lastReceivedTS=b->th.timestamp> nsamps_for_initial ?
	    b->th.timestamp :
	    nsamps_for_initial;
	  LOG_W(HW,"UE got first timestamp: starting at %lu\n",  t->nextTimestamp);
	  b->trashingPacket=true;
	} else if ( b->lastReceivedTS < b->th.timestamp) {
525
          int nbAnt= b->th.nbAnt;
laurent's avatar
laurent committed
526
          if ( b->th.timestamp-b->lastReceivedTS < CirSize ) {
527 528
          for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) {
            for (int a=0; a < nbAnt; a++) {
529 530
              b->circularBuf[(index*nbAnt+a)%CirSize].r = 0;
              b->circularBuf[(index*nbAnt+a)%CirSize].i = 0;
531 532
            }
          }
laurent's avatar
laurent committed
533 534 535
          } else {
	    memset(b->circularBuf, 0, sampleToByte(CirSize,1));
	  }
536
          if (b->lastReceivedTS != 0 && b->th.timestamp-b->lastReceivedTS > 50 )
537
            LOG_W(HW,"UEsock: %d gap of: %ld in reception\n", fd, b->th.timestamp-b->lastReceivedTS );
538
          b->lastReceivedTS=b->th.timestamp;
539 540
	  
        } else if ( b->lastReceivedTS > b->th.timestamp && b->th.size == 1 ) {
541 542 543 544 545
          LOG_W(HW,"Received Rx/Tx synchro out of order\n");
          b->trashingPacket=true;
        } else if ( b->lastReceivedTS == b->th.timestamp ) {
          // normal case
        } else {
laurent's avatar
laurent committed
546 547
          LOG_E(HW, "received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp);
	  b->trashingPacket=true;
laurent's avatar
laurent committed
548
        }
549

550 551
        pthread_mutex_lock(&Sockmutex);

552 553
        if (t->lastWroteTS != 0 && ( abs((double)t->lastWroteTS-b->lastReceivedTS) > (double)CirSize))
          LOG_E(HW,"UEsock: %d Tx/Rx shift too large Tx:%lu, Rx:%lu\n", fd, t->lastWroteTS, b->lastReceivedTS);
554 555

        pthread_mutex_unlock(&Sockmutex);
556 557 558 559 560
        b->transferPtr=(char *)&b->circularBuf[b->lastReceivedTS%CirSize];
        b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
      }

      if ( b->headerMode==false ) {
561 562
        if ( ! b->trashingPacket ) {
          b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt);
563
          LOG_D(HW,"UEsock: %d Set b->lastReceivedTS %ld\n", fd, b->lastReceivedTS);
564
        }
565

laurent's avatar
laurent committed
566
        if ( b->remainToTransfer==0) {
567
          LOG_D(HW,"UEsock: %d Completed block reception: %ld\n", fd, b->lastReceivedTS);
laurent's avatar
laurent committed
568 569
          b->headerMode=true;
          b->transferPtr=(char *)&b->th;
570
          b->remainToTransfer=sizeof(samplesBlockHeader_t);
laurent's avatar
laurent committed
571
          b->th.magic=-1;
572
          b->trashingPacket=false;
573 574 575 576 577 578 579 580 581 582
        }
      }
    }
  }

  return nfds>0;
}

int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) {
  if (nbAnt != 1) {
583
    LOG_W(HW, "rfsimulator: only 1 antenna tested\n");
584 585 586 587 588 589 590 591 592 593 594 595 596 597
  }

  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)
598 599
    if ( t->nextTimestamp == 0)
      LOG_W(HW,"No connected device, generating void samples...\n");
600

601
    if (!flushInput(t, 10,  nsamps)) {
602 603 604 605
      for (int x=0; x < nbAnt; x++)
        memset(samplesVoid[x],0,sampleToByte(nsamps,1));

      t->nextTimestamp+=nsamps;
606

607
      if ( ((t->nextTimestamp/nsamps)%100) == 0)
608
        LOG_W(HW,"No UE, Generated void samples for Rx: %ld\n", t->nextTimestamp);
609

610 611 612 613
      *ptimestamp = t->nextTimestamp-nsamps;
      return nsamps;
    }
  } else {
614 615 616 617 618 619
    pthread_mutex_lock(&Sockmutex);

    if ( t->nextTimestamp > 0 && t->lastWroteTS < t->nextTimestamp) {
      pthread_mutex_unlock(&Sockmutex);
      usleep(10000);
      pthread_mutex_lock(&Sockmutex);
laurent's avatar
laurent committed
620

621 622 623 624 625 626 627 628 629 630 631 632 633
      if ( t->lastWroteTS < t->nextTimestamp ) {
        // Assuming Tx is not done fully in another thread
        // We can never write is the past from the received time
        // So, the node perform receive but will never write these symbols
        // let's tell this to the opposite node
	// We send timestamp for nb samples required
	// assuming this should have been done earlier if a Tx would exist
        pthread_mutex_unlock(&Sockmutex);
        struct complex16 v= {0};
        void *samplesVoid[t->tx_num_channels];

        for ( int i=0; i < t->tx_num_channels; i++)
          samplesVoid[i]=(void *)&v;
laurent's avatar
laurent committed
634

635 636 637 638 639 640 641 642 643 644 645 646
	LOG_I(HW, "No samples Tx occured, so we send 1 sample to notify it: Tx:%lu, Rx:%lu\n",
	      t->lastWroteTS, t->nextTimestamp);
        rfsimulator_write_internal(t, t->nextTimestamp,
                                   samplesVoid, 1,
                                   t->tx_num_channels, 1, true);
      } else {
	pthread_mutex_unlock(&Sockmutex);
        LOG_W(HW, "trx_write came from another thread\n");
      }
    } else
      pthread_mutex_unlock(&Sockmutex);
    
647 648 649 650 651
    bool have_to_wait;

    do {
      have_to_wait=false;

652
      for ( int sock=0; sock<FD_SETSIZE; sock++) {
653 654
        buffer_t *b=&t->buf[sock];

laurent's avatar
laurent committed
655 656
        if ( b->circularBuf )
          if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) {
laurent's avatar
laurent committed
657 658
            have_to_wait=true;
            break;
659
          }
laurent's avatar
laurent committed
660
      }
661 662 663 664 665 666

      if (have_to_wait)
        /*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n",
          ptr->lastReceivedTS,
          t->nextTimestamp+nsamps);
        */
667
        flushInput(t, 3, nsamps);
668 669 670 671 672 673 674
    } while (have_to_wait);
  }

  // Clear the output buffer
  for (int a=0; a<nbAnt; a++)
    memset(samplesVoid[a],0,sampleToByte(nsamps,1));

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

laurent's avatar
laurent committed
679
    if ( ptr->circularBuf ) {
680 681 682 683 684 685
      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);
frtabu's avatar
frtabu committed
686
      t->poll_telnetcmdq(t->telnetcmd_qid);
687
      for (int a=0; a<nbAnt; a++) {
688
        if ( ptr->channel_model != NULL ) // apply a channel model
689 690 691 692
          rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
                      a,
                      ptr->channel_model,
                      nsamps,
693 694
                      t->nextTimestamp,
                      CirSize
695 696 697
                    );
        else { // no channel modeling
          sample_t *out=(sample_t *)samplesVoid[a];
laurent's avatar
laurent committed
698
          const int64_t base=t->nextTimestamp*nbAnt+a;
699
          for ( int i=0; i < nsamps; i++ ) {
laurent's avatar
laurent committed
700 701 702
	    const int idx=(i*nbAnt+base)%CirSize;
            out[i].r+=ptr->circularBuf[idx].r;
            out[i].i+=ptr->circularBuf[idx].i;
703 704 705
          }
        } // end of no channel modeling
      } // end for a...
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
    }
  }

  *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));
  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;
}
WANG Tsu-Han's avatar
WANG Tsu-Han committed
741 742 743
int rfsimulator_write_init(openair0_device *device){
  return 0;
}
744 745
__attribute__((__visibility__("default")))
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
746 747
  // to change the log level, use this on command line
  // --log_config.hw_log_level debug
748
  rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);
749
  rfsimulator_readconfig(rfsimulator);
750 751 752
  pthread_mutex_init(&Sockmutex, NULL);
  LOG_I(HW,"rfsimulator: running as %s\n", rfsimulator-> typeStamp == ENB_MAGICDL_FDD ? "(eg)NB" : "UE");
  device->trx_start_func       = rfsimulator->typeStamp == ENB_MAGICDL_FDD ?
753 754 755 756 757 758 759 760 761 762 763 764 765 766
                                 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;
WANG Tsu-Han's avatar
WANG Tsu-Han committed
767
  device->trx_write_init = rfsimulator_write_init;
768 769 770 771 772

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

  AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1,"");
773 774 775 776 777
  // 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;
laurent's avatar
laurent committed
778
  //randominit(0);
779
  set_taus_seed(0);
frtabu's avatar
frtabu committed
780 781 782 783 784 785 786 787 788 789 790 791 792
   /* look for telnet server, if it is loaded, add the channel modeling commands to it */
  add_telnetcmd_func_t addcmd = (add_telnetcmd_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_ADDCMD_FNAME);
 
  if (addcmd != NULL) {
    rfsimulator->poll_telnetcmdq =  (poll_telnetcmdq_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_POLLCMDQ_FNAME);  
    addcmd("rfsimu",rfsimu_vardef,rfsimu_cmdarray);
    for(int i=0; rfsimu_cmdarray[i].cmdfunc != NULL; i++) {
      if (	rfsimu_cmdarray[i].qptr != NULL) {
        rfsimulator->telnetcmd_qid = rfsimu_cmdarray[i].qptr;
        break;
      }
    }    
  } 
793 794
  return 0;
}