simulator.c 30 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>
54
#include <targets/ARCH/rfsimulator/rfsimulator.h>
55

56
#define PORT 4043 //default TCP port for this simulator
57
#define CirSize 6144000 // 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
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
frtabu's avatar
frtabu committed
93
static telnetshell_cmddef_t rfsimu_cmdarray[] = {
94
  {"setmodel","<model name>",(cmdfunc_t)rfsimu_setchanmod_cmd,TELNETSRV_CMDFLAG_PUSHINTPOOLQ},
frtabu's avatar
frtabu committed
95 96 97 98 99
  {"","",NULL},
};

static telnetshell_vardef_t rfsimu_vardef[] = {
  {"",0,NULL}
100
};
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
170
    static bool init_done=false;
laurent's avatar
laurent committed
171

172
    if (!init_done) {
173 174 175
      uint64_t rand;
      FILE *h=fopen("/dev/random","r");

176 177
      if ( 1 != fread(&rand,sizeof(rand),1,h) )
        LOG_W(HW, "Simulator can't read /dev/random\n");
178 179

      fclose(h);
laurent's avatar
laurent committed
180
      randominit(rand);
laurent's avatar
laurent committed
181
      tableNor(rand);
182 183
      init_done=true;
    }
laurent's avatar
laurent committed
184

185
    ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
186
                                            bridge->channelmod,
187 188
                                            bridge->sample_rate,
                                            bridge->tx_bw,
189
                                            30e-9,  // TDL delay-spread parameter
190
                                            bridge->chan_forgetfact, // forgetting_factor
191
                                            bridge->chan_offset, // maybe used for TA
192
                                            bridge->chan_pathloss); // path_loss in dB
193
    set_channeldesc_owner(ptr->channel_model, RFSIMU_MODULEID);
194 195
    random_channel(ptr->channel_model,false);
  }
196 197 198 199 200 201
}

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);
202 203 204
  // Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented
  // a lot of mem leaks
  free(bridge->buf[sock].channel_model);
205 206 207 208 209 210 211 212 213
  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);

214
    if (bridge->typeStamp==UE_MAGICDL_FDD)
215 216 217 218 219 220 221 222 223
      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\
224
                 or use rfsimulator.serveraddr configuration option\n\
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
\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, "");
}

244
static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps);
245 246 247 248 249 250

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

252 253
  AssertFatal(fd>=0 && _buf && count >0 && t,
              "Bug: %d/%p/%zd/%p", fd, _buf, count, t);
254
  char *buf = _buf;
255
  ssize_t l;
256 257 258 259 260 261 262 263 264 265
  setblocking(fd, notBlocking);

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

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

      if(errno==EAGAIN) {
266 267
        // The opposite side is saturated
        // we read incoming sockets meawhile waiting
268 269
        //flushInput(t, 5);
        usleep(500);
270 271 272 273 274 275 276 277 278
        continue;
      } else
        return;
    }

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

280
void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) {
281
  char *saveF=NULL;
282
  char *modelname=NULL;
283
  paramdef_t rfsimu_params[] = RFSIMULATOR_PARAMS_DESC;
284 285 286
  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");
287 288
  rfsimulator->saveIQfile = -1;

289
  for(int i=0; i<rfsimu_params[p].numelt ; i++) {
290 291 292 293 294 295 296 297 298 299
    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) {
300 301
      init_channelmod();
      rfsimulator->channelmod=modelid_fromname(modelname);
302 303 304 305
    } else {
      fprintf(stderr,"Unknown rfsimulator option: %s\n",rfsimu_params[p].strlistptr[i]);
      exit(-1);
    }
306
  }
307

308 309
  /* for compatibility keep environment variable usage */
  if ( getenv("RFSIMULATOR") != NULL ) {
310
    rfsimulator->ip=getenv("RFSIMULATOR");
311
  }
312

313
  if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 ||
314
       strncasecmp(rfsimulator->ip,"server",3) == 0 )
315 316 317 318
    rfsimulator->typeStamp = ENB_MAGICDL_FDD;
  else
    rfsimulator->typeStamp = UE_MAGICDL_FDD;
}
319

320
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg) {
321
  char *modelname=NULL;
frtabu's avatar
frtabu committed
322
  int s = sscanf(buff,"%ms\n",&modelname);
323

324 325
  if (s == 1) {
    int channelmod=modelid_fromname(modelname);
326

327 328 329
    if (channelmod<0)
      prnt("ERROR: model %s unknown\n",modelname);
    else {
330 331 332
      rfsimulator_state_t *t = (rfsimulator_state_t *)arg;

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

335 336
        if (b->conn_sock >= 0 ) {
          channel_desc_t *newmodel=new_channel_desc_scm(t->tx_num_channels,t->rx_num_channels,
337 338 339 340 341 342 343
                                   channelmod,
                                   t->sample_rate,
                                   t->tx_bw,
                                   30e-9,  // TDL delay-spread parameter
                                   t->chan_forgetfact, // forgetting_factor
                                   t->chan_offset, // maybe used for TA
                                   t->chan_pathloss); // path_loss in dB
344 345 346 347 348 349 350 351 352 353
          set_channeldesc_owner(newmodel, RFSIMU_MODULEID);
          random_channel(newmodel,false);
          channel_desc_t *oldmodel=b->channel_model;
          b->channel_model=newmodel;
          free_channel_desc_scm(oldmodel);
          prnt("New model %s applied to channel connected to sock %d\n",modelname,i);
        }
      }
    }
  } else {
354
    prnt("ERROR: no model specified\n");
frtabu's avatar
frtabu committed
355
  }
356

357
  free(modelname);
frtabu's avatar
frtabu committed
358 359 360
  return CMDSTATUS_FOUND;
}

361 362
int server_start(openair0_device *device) {
  rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv;
363
  t->typeStamp=ENB_MAGICDL_FDD;
364 365 366 367 368 369 370
  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:
371
    htons(t->port),
372 373 374 375 376
sin_addr:
    { s_addr: INADDR_ANY }
  };
  bind(t->listen_sock, (struct sockaddr *)&addr, sizeof(addr));
  AssertFatal(listen(t->listen_sock, 5) == 0, "");
377
  struct epoll_event ev= {0};
378 379 380 381 382 383 384 385
  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;
386
  t->typeStamp=UE_MAGICDL_FDD;
387 388 389 390 391 392
  int sock;
  AssertFatal((sock = socket(AF_INET, SOCK_STREAM, 0)) >= 0, "");
  struct sockaddr_in addr = {
sin_family:
    AF_INET,
sin_port:
393
    htons(t->port),
394 395 396 397 398 399 400
sin_addr:
    { s_addr: INADDR_ANY }
  };
  addr.sin_addr.s_addr = inet_addr(t->ip);
  bool connected=false;

  while(!connected) {
401
    LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", t->ip, t->port);
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416

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

417 418 419 420
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);

421
  LOG_D(HW,"sending %d samples at time: %ld\n", nsamps, timestamp);
422 423

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

laurent's avatar
laurent committed
426
    if (b->conn_sock >= 0 ) {
427
      samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp};
laurent's avatar
laurent committed
428
      fullwrite(b->conn_sock,&header, sizeof(header), t);
429 430 431 432 433 434 435 436 437
      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
438 439 440
      if (b->conn_sock >= 0 ) {
        fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t);
      }
441 442 443
    }
  }

444 445 446
  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
447
  if (t->lastWroteTS > timestamp+nsamps)
448
    LOG_E(HW,"Not supported to send Tx out of order (same in USRP) %lu, %lu\n",
449
          t->lastWroteTS, timestamp);
laurent's avatar
laurent committed
450

451 452 453 454 455
  t->lastWroteTS=timestamp+nsamps;

  if (!alreadyLocked)
    pthread_mutex_unlock(&Sockmutex);

456 457 458 459 460
  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;
}

461
int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
462
  return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags, false);
463 464 465
}

static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) {
466 467
  // Process all incoming events on sockets
  // store the data in lists
468
  struct epoll_event events[FD_SETSIZE]= {{0}};
469
  int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, timeout);
470 471

  if ( nfds==-1 ) {
472
    if ( errno==EINTR || errno==EAGAIN ) {
473
      return false;
474
    } else
475 476 477 478 479 480 481 482 483 484 485
      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);
486 487 488 489 490 491 492
      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;

493
      rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS-1 : 0,
494
                                 samplesVoid, 1,
495
                                 t->tx_num_channels, 1, false);
496 497 498 499 500 501 502 503 504 505 506 507 508
    } 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;
      }

509
      ssize_t blockSz;
510 511 512 513

      if ( b->headerMode)
        blockSz=b->remainToTransfer;
      else
514
        blockSz= b->transferPtr + b->remainToTransfer <= b->circularBufEnd ?
515
                 b->remainToTransfer :
516
                 b->circularBufEnd - b->transferPtr ;
517

518
      ssize_t sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
519 520 521 522

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

528
      LOG_D(HW, "Socket rcv %zd bytes\n", sz);
529 530 531
      AssertFatal((b->remainToTransfer-=sz) >= 0, "");
      b->transferPtr+=sz;

532
      if (b->transferPtr==b->circularBufEnd )
533 534 535 536
        b->transferPtr=(char *)b->circularBuf;

      // check the header and start block transfer
      if ( b->headerMode==true && b->remainToTransfer==0) {
537 538
        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");
539 540
        b->headerMode=false;

541
        if ( t->nextTimestamp == 0 ) { // First block in UE, resync with the eNB current TS
542 543 544 545 546 547 548 549 550
          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) {
551
          int nbAnt= b->th.nbAnt;
laurent's avatar
laurent committed
552

553
          if ( b->th.timestamp-b->lastReceivedTS < CirSize ) {
laurent's avatar
laurent committed
554 555 556 557 558
            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;
              }
559
            }
560
          } else {
561 562
            memset(b->circularBuf, 0, sampleToByte(CirSize,1));
          }
laurent's avatar
laurent committed
563

564
          if (b->lastReceivedTS != 0 && b->th.timestamp-b->lastReceivedTS < 1000)
565
            LOG_W(HW,"UEsock: %d gap of: %ld in reception\n", fd, b->th.timestamp-b->lastReceivedTS );
566

laurent's avatar
laurent committed
567
          b->lastReceivedTS=b->th.timestamp;
568
        } else if ( b->lastReceivedTS > b->th.timestamp && b->th.size == 1 ) {
569 570 571 572 573
          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
574
          LOG_E(HW, "received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp);
575
          b->trashingPacket=true;
laurent's avatar
laurent committed
576
        }
577

578 579
        pthread_mutex_lock(&Sockmutex);

580 581
        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);
582 583

        pthread_mutex_unlock(&Sockmutex);
584
        b->transferPtr=(char *)&b->circularBuf[(b->lastReceivedTS*b->th.nbAnt)%CirSize];
585 586 587 588
        b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
      }

      if ( b->headerMode==false ) {
589 590
        if ( ! b->trashingPacket ) {
          b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt);
591
          LOG_D(HW,"UEsock: %d Set b->lastReceivedTS %ld\n", fd, b->lastReceivedTS);
592
        }
593

laurent's avatar
laurent committed
594
        if ( b->remainToTransfer==0) {
595
          LOG_D(HW,"UEsock: %d Completed block reception: %ld\n", fd, b->lastReceivedTS);
laurent's avatar
laurent committed
596 597
          b->headerMode=true;
          b->transferPtr=(char *)&b->th;
598
          b->remainToTransfer=sizeof(samplesBlockHeader_t);
laurent's avatar
laurent committed
599
          b->th.magic=-1;
600
          b->trashingPacket=false;
601 602 603 604 605 606 607 608 609 610
        }
      }
    }
  }

  return nfds>0;
}

int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) {
  if (nbAnt != 1) {
611
    LOG_W(HW, "rfsimulator: only 1 antenna tested\n");
612 613 614 615 616 617 618 619 620 621 622 623 624 625
  }

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

629
    if (!flushInput(t, 10,  nsamps)) {
630 631 632 633
      for (int x=0; x < nbAnt; x++)
        memset(samplesVoid[x],0,sampleToByte(nsamps,1));

      t->nextTimestamp+=nsamps;
634

635
      if ( ((t->nextTimestamp/nsamps)%100) == 0)
636
        LOG_D(HW,"No UE, Generated void samples for Rx: %ld\n", t->nextTimestamp);
637

638 639 640 641
      *ptimestamp = t->nextTimestamp-nsamps;
      return nsamps;
    }
  } else {
642 643 644 645 646 647
    pthread_mutex_lock(&Sockmutex);

    if ( t->nextTimestamp > 0 && t->lastWroteTS < t->nextTimestamp) {
      pthread_mutex_unlock(&Sockmutex);
      usleep(10000);
      pthread_mutex_lock(&Sockmutex);
648

649 650 651 652 653
      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
654 655
        // We send timestamp for nb samples required
        // assuming this should have been done earlier if a Tx would exist
656 657
        pthread_mutex_unlock(&Sockmutex);
        struct complex16 v= {0};
658
        void *dummyS[t->tx_num_channels];
659 660

        for ( int i=0; i < t->tx_num_channels; i++)
661
          dummyS[i]=(void *)&v;
662 663 664

        LOG_I(HW, "No samples Tx occured, so we send 1 sample to notify it: Tx:%lu, Rx:%lu\n",
              t->lastWroteTS, t->nextTimestamp);
665
        rfsimulator_write_internal(t, t->nextTimestamp,
666
                                   dummyS, 1,
667 668
                                   t->tx_num_channels, 1, true);
      } else {
669
        pthread_mutex_unlock(&Sockmutex);
670 671 672 673
        LOG_W(HW, "trx_write came from another thread\n");
      }
    } else
      pthread_mutex_unlock(&Sockmutex);
674

675 676 677 678 679
    bool have_to_wait;

    do {
      have_to_wait=false;

680
      for ( int sock=0; sock<FD_SETSIZE; sock++) {
681 682
        buffer_t *b=&t->buf[sock];

laurent's avatar
laurent committed
683 684
        if ( b->circularBuf )
          if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) {
laurent's avatar
laurent committed
685 686
            have_to_wait=true;
            break;
687
          }
laurent's avatar
laurent committed
688
      }
689 690 691 692 693 694

      if (have_to_wait)
        /*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n",
          ptr->lastReceivedTS,
          t->nextTimestamp+nsamps);
        */
695
        flushInput(t, 3, nsamps);
696 697 698 699 700 701 702
    } 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
703
  // Add all input nodes signal in the output buffer
704 705 706
  for (int sock=0; sock<FD_SETSIZE; sock++) {
    buffer_t *ptr=&t->buf[sock];

laurent's avatar
laurent committed
707
    if ( ptr->circularBuf ) {
708 709 710 711 712 713
      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);
714

715
      if (t->poll_telnetcmdq)
716
        t->poll_telnetcmdq(t->telnetcmd_qid,t);
717

718
      for (int a=0; a<nbAnt; a++) {//loop over number of Rx antennas
719
        if ( ptr->channel_model != NULL ) // apply a channel model
720 721 722 723
          rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
                      a,
                      ptr->channel_model,
                      nsamps,
724 725
                      t->nextTimestamp,
                      CirSize
726 727 728
                    );
        else { // no channel modeling
          sample_t *out=(sample_t *)samplesVoid[a];
729
          int nbAnt_tx = ptr->th.nbAnt;//number of Tx antennas
730

731 732
          //LOG_I(HW, "nbAnt_tx %d\n",nbAnt_tx);
          for (int i=0; i < nsamps; i++) {//loop over nsamps
733 734 735 736
            for (int a_tx=0; a_tx<nbAnt_tx; a_tx++) { //sum up signals from nbAnt_tx antennas
              out[i].r+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt_tx+a_tx)%CirSize].r;
              out[i].i+=ptr->circularBuf[((t->nextTimestamp+i)*nbAnt_tx+a_tx)%CirSize].i;
            } // end for a_tx
737
          } // end for i (number of samps)
738
        } // end of no channel modeling
739
      } // end for a (number of rx antennas)
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
    }
  }

  *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;
}
laurent's avatar
laurent committed
775
int rfsimulator_write_init(openair0_device *device) {
WANG Tsu-Han's avatar
WANG Tsu-Han committed
776 777
  return 0;
}
778 779
__attribute__((__visibility__("default")))
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
780 781
  // to change the log level, use this on command line
  // --log_config.hw_log_level debug
782
  rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);
783
  rfsimulator_readconfig(rfsimulator);
784 785 786
  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 ?
787 788 789 790 791 792 793 794 795 796 797 798 799 800
                                 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
801
  device->trx_write_init = rfsimulator_write_init;
802 803 804 805 806

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

  AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1,"");
807 808 809 810 811
  // 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;
812
  //randominit(0);
813
  set_taus_seed(0);
814
  /* look for telnet server, if it is loaded, add the channel modeling commands to it */
frtabu's avatar
frtabu committed
815
  add_telnetcmd_func_t addcmd = (add_telnetcmd_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_ADDCMD_FNAME);
816

frtabu's avatar
frtabu committed
817
  if (addcmd != NULL) {
818
    rfsimulator->poll_telnetcmdq =  (poll_telnetcmdq_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_POLLCMDQ_FNAME);
frtabu's avatar
frtabu committed
819
    addcmd("rfsimu",rfsimu_vardef,rfsimu_cmdarray);
820

frtabu's avatar
frtabu committed
821
    for(int i=0; rfsimu_cmdarray[i].cmdfunc != NULL; i++) {
822
      if (  rfsimu_cmdarray[i].qptr != NULL) {
frtabu's avatar
frtabu committed
823 824 825
        rfsimulator->telnetcmd_qid = rfsimu_cmdarray[i].qptr;
        break;
      }
826 827 828
    }
  }

829 830
  return 0;
}