simulator.c 31.6 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 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
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 100
  {"","",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
170
    static bool init_done=false;
laurent's avatar
laurent committed
171

172
    if (!init_done) {
173 174 175 176 177
	  uint64_t rand;
	  FILE *h=fopen("/dev/random","r");
      if ( 1 != fread(&rand,sizeof(rand),1,h) )
        LOG_W(HW, "Simulator can't read /dev/random\n");
	  fclose(h);
laurent's avatar
laurent committed
178
      randominit(rand);
laurent's avatar
laurent committed
179
      tableNor(rand);
180 181
      init_done=true;
    }
laurent's avatar
laurent committed
182

183
    ptr->channel_model=new_channel_desc_scm(bridge->tx_num_channels,bridge->rx_num_channels,
184
                                            bridge->channelmod,
185 186
                                            bridge->sample_rate,
                                            bridge->tx_bw,
187
                                            30e-9,  // TDL delay-spread parameter
188
                                            bridge->chan_forgetfact, // forgetting_factor
189
                                            bridge->chan_offset, // maybe used for TA
190
                                            bridge->chan_pathloss); // path_loss in dB
191
    set_channeldesc_owner(ptr->channel_model, RFSIMU_MODULEID);
192

193 194
    random_channel(ptr->channel_model,false);
  }
195 196 197 198 199 200
}

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

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

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

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

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

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

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

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

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

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

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

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

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

319
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg) {
frtabu's avatar
frtabu committed
320 321
  char *modelname=NULL; 
  int s = sscanf(buff,"%ms\n",&modelname);
322 323 324 325 326 327 328 329 330 331 332 333 334
  if (s == 1) {
    int channelmod=modelid_fromname(modelname);
    if (channelmod<0)
      prnt("ERROR: model %s unknown\n",modelname);
    else {
  	  rfsimulator_state_t *t = (rfsimulator_state_t *)arg;
  	  for (int i=0; i<FD_SETSIZE; i++) {
        buffer_t *b=&t->buf[i];
        if (b->conn_sock >= 0 ) {
          channel_desc_t *newmodel=new_channel_desc_scm(t->tx_num_channels,t->rx_num_channels,
                                                channelmod,
                                                t->sample_rate,
                                                t->tx_bw,
335
                                                30e-9,  // TDL delay-spread parameter
336 337 338 339 340 341 342 343 344 345 346 347 348 349
                                                t->chan_forgetfact, // forgetting_factor
                                                t->chan_offset, // maybe used for TA
                                                t->chan_pathloss); // path_loss in dB
          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 {
  	  prnt("ERROR: no model specified\n");  
frtabu's avatar
frtabu committed
350
  }
351
  free(modelname);
frtabu's avatar
frtabu committed
352 353 354
  return CMDSTATUS_FOUND;
}

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

  while(!connected) {
395
    LOG_I(HW,"rfsimulator: trying to connect to %s:%d\n", t->ip, t->port);
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410

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

411 412 413 414
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);

415 416 417 418
  int flags_lsb = flags&0xff;
  int flags_msb = (flags>>8)&0xff;
  int beam_enabled = (flags_msb>>3)&1;
  int beam_id = flags_msb&7;
419 420 421 422 423 424 425 426
  if(t->typeStamp == ENB_MAGICDL_FDD){
  LOG_I(HW,"sending %d timestamp: %ld, beam_enabled %d, beam_id %d\n", nsamps, timestamp, beam_enabled, beam_id);
  }


	


427

428 429

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

laurent's avatar
laurent committed
432
    if (b->conn_sock >= 0 ) {
433
      samplesBlockHeader_t header= {t->typeStamp, nsamps, nbAnt, timestamp, beam_id};
laurent's avatar
laurent committed
434
      fullwrite(b->conn_sock,&header, sizeof(header), t);
435
     // LOG_I(HW,"Hello,World %d \n",header.beam_id);
436 437 438 439 440 441 442 443 444
      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
445 446 447
      if (b->conn_sock >= 0 ) {
        fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps,nbAnt), t);
      }
448 449 450
    }
  }

451 452 453
  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
454
  if (t->lastWroteTS > timestamp+nsamps)
455
    LOG_E(HW,"Not supported to send Tx out of order (same in USRP) %lu, %lu\n",
456
              t->lastWroteTS, timestamp);
laurent's avatar
laurent committed
457

458 459 460 461 462
  t->lastWroteTS=timestamp+nsamps;

  if (!alreadyLocked)
    pthread_mutex_unlock(&Sockmutex);

463 464 465 466 467
  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;
}

468
int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
469
  return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags, false);
470 471 472
}

static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) {
473 474
  // Process all incoming events on sockets
  // store the data in lists
475
  struct epoll_event events[FD_SETSIZE]= {{0}};
476
  int nfds = epoll_wait(t->epollfd, events, FD_SETSIZE, timeout);
477
  if ( nfds==-1 ) {
478
    if ( errno==EINTR || errno==EAGAIN ) {
479
      return false;
480
    } else
481 482 483 484 485 486 487 488 489 490 491
      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);
492 493 494 495 496 497 498
      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;

499
      rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS-1 : 0,
500
                                 samplesVoid, 1,
501
                                 t->tx_num_channels, 1, false);
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];
509 510
        
      //LOG_I(HW,"======= beam index ==========\n", b);
511 512 513 514 515 516

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

517
      ssize_t blockSz;
518

519 520 521 522 523 524 525 526 527 528 529
      if(t->typeStamp == ENB_MAGICDL_FDD){

	      LOG_I(HW,"Server side info: Beam index %d, path loss %lf\n", b->th.option_value, t->chan_pathloss);
      }else {
	      LOG_I(HW,"Receiver side info: Beam index %d, path loss %lf\n", b->th.option_value,t->chan_pathloss);
      }

     //pathloss = beam_id*10
      t->chan_pathloss = b->th.option_value * 10;

      if ( b->headerMode){
530
        blockSz=b->remainToTransfer;
531 532
        //LOG_I(HW,"====== Timestamp %lu  ===== Beam Index ======  %d , path loss %lf \n ", b->th.timestamp, b->th.option_value, t->chan_pathloss);
	}
533 534 535 536 537
      else
        blockSz= b->transferPtr+b->remainToTransfer < b->circularBufEnd ?
                 b->remainToTransfer :
                 b->circularBufEnd - 1 - b->transferPtr ;

538
      ssize_t sz=recv(fd, b->transferPtr, blockSz, MSG_DONTWAIT);
539 540 541 542

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

548
      LOG_D(HW, "Socket rcv %zd bytes\n", sz);
549 550 551
      AssertFatal((b->remainToTransfer-=sz) >= 0, "");
      b->transferPtr+=sz;

552
      if (b->transferPtr==b->circularBufEnd - 1)         b->transferPtr=(char *)b->circularBuf;
553 554 555

      // check the header and start block transfer
      if ( b->headerMode==true && b->remainToTransfer==0) {
556 557
        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");
558 559
        b->headerMode=false;

560
        if ( t->nextTimestamp == 0 ) { // First block in UE, resync with the eNB current TS
561 562 563 564 565 566 567 568
          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;
569 570 571 572 573 574 575 576 577 578 579 580 581

        }









 
 else if ( b->lastReceivedTS < b->th.timestamp) {
582
          int nbAnt= b->th.nbAnt;
laurent's avatar
laurent committed
583

584
          if ( b->th.timestamp-b->lastReceivedTS < CirSize ) {
laurent's avatar
laurent committed
585 586 587 588 589
            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;
              }
590
            }
591 592 593
       
         
 } else {
laurent's avatar
laurent committed
594 595
	    memset(b->circularBuf, 0, sampleToByte(CirSize,1));
	  }
laurent's avatar
laurent committed
596

597
          if (b->lastReceivedTS != 0 && b->th.timestamp-b->lastReceivedTS > 50 )
598
            LOG_W(HW,"UEsock: %d gap of: %ld in reception\n", fd, b->th.timestamp-b->lastReceivedTS );
599

laurent's avatar
laurent committed
600
          b->lastReceivedTS=b->th.timestamp;
601 602
	  
        } else if ( b->lastReceivedTS > b->th.timestamp && b->th.size == 1 ) {
603 604 605 606 607
          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
608
          LOG_E(HW, "received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp);
609
          b->trashingPacket=true;
laurent's avatar
laurent committed
610
        }
611

612 613
        pthread_mutex_lock(&Sockmutex);

614 615
        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);
616 617

        pthread_mutex_unlock(&Sockmutex);
618
        b->transferPtr=(char *)&b->circularBuf[(b->lastReceivedTS*b->th.nbAnt)%CirSize];
619 620 621 622
        b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
      }

      if ( b->headerMode==false ) {
623 624
        if ( ! b->trashingPacket ) {
          b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt);
625
          LOG_D(HW,"UEsock: %d Set b->lastReceivedTS %ld\n", fd, b->lastReceivedTS);
626
        }
627

laurent's avatar
laurent committed
628
        if ( b->remainToTransfer==0) {
629
          LOG_D(HW,"UEsock: %d Completed block reception: %ld\n", fd, b->lastReceivedTS);
laurent's avatar
laurent committed
630 631
          b->headerMode=true;
          b->transferPtr=(char *)&b->th;
632
          b->remainToTransfer=sizeof(samplesBlockHeader_t);
laurent's avatar
laurent committed
633
          b->th.magic=-1;
634
          b->trashingPacket=false;
635 636 637 638 639 640 641 642 643 644
        }
      }
    }
  }

  return nfds>0;
}

int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) {
  if (nbAnt != 1) {
645
    LOG_W(HW, "rfsimulator: only 1 antenna tested\n");
646 647
  }
  rfsimulator_state_t *t = device->priv;
648 649 650 651 652 653 654 655 656 657 658 659 660
  for(int sock=0;sock<FD_SETSIZE;sock++){
  buffer_t *b=&t->buf[sock];
  //LOG_W(HW,"beam index %d",b->th.option_value);
  }


 //Printing the pathloss
  if(t->typeStamp == UE_MAGICDL_FDD){
  LOG_I(HW," RX side, pathLoss-defualt %lf\n", t->chan_pathloss);
  }



661 662 663 664 665 666 667 668 669 670 671
  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)
672 673
    if ( t->nextTimestamp == 0)
      LOG_W(HW,"No connected device, generating void samples...\n");
674

675
    if (!flushInput(t, 10,  nsamps)) {
676 677 678 679
      for (int x=0; x < nbAnt; x++)
        memset(samplesVoid[x],0,sampleToByte(nsamps,1));

      t->nextTimestamp+=nsamps;
680

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

684 685 686 687
      *ptimestamp = t->nextTimestamp-nsamps;
      return nsamps;
    }
  } else {
688
    pthread_mutex_lock(&Sockmutex);
689
    
690 691 692 693
    if ( t->nextTimestamp > 0 && t->lastWroteTS < t->nextTimestamp) {
      pthread_mutex_unlock(&Sockmutex);
      usleep(10000);
      pthread_mutex_lock(&Sockmutex);
694

695 696 697 698 699
      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
700 701
        // We send timestamp for nb samples required
        // assuming this should have been done earlier if a Tx would exist
702 703 704 705 706 707
        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;
708 709 710

        LOG_I(HW, "No samples Tx occured, so we send 1 sample to notify it: Tx:%lu, Rx:%lu\n",
              t->lastWroteTS, t->nextTimestamp);
711
        //LOG_I(HW,"Testing Log");
712 713 714 715
        rfsimulator_write_internal(t, t->nextTimestamp,
                                   samplesVoid, 1,
                                   t->tx_num_channels, 1, true);
      } else {
716
        pthread_mutex_unlock(&Sockmutex);
717 718 719 720
        LOG_W(HW, "trx_write came from another thread\n");
      }
    } else
      pthread_mutex_unlock(&Sockmutex);
721

722 723 724 725 726
    bool have_to_wait;

    do {
      have_to_wait=false;

727
      for ( int sock=0; sock<FD_SETSIZE; sock++) {
728 729
        buffer_t *b=&t->buf[sock];

laurent's avatar
laurent committed
730 731
        if ( b->circularBuf )
          if ( t->nextTimestamp+nsamps > b->lastReceivedTS ) {
laurent's avatar
laurent committed
732 733
            have_to_wait=true;
            break;
734
          }
laurent's avatar
laurent committed
735
      }
736 737 738 739 740 741

      if (have_to_wait)
        /*printf("Waiting on socket, current last ts: %ld, expected at least : %ld\n",
          ptr->lastReceivedTS,
          t->nextTimestamp+nsamps);
        */
742
        flushInput(t, 3, nsamps);
743 744 745 746 747 748 749
    } 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
750
  // Add all input nodes signal in the output buffer
751 752
  for (int sock=0; sock<FD_SETSIZE; sock++) {
    buffer_t *ptr=&t->buf[sock];
753 754
    //LOG_I(HW,"Beam id %d\n", ptr->th.option_value);
    
755

laurent's avatar
laurent committed
756
    if ( ptr->circularBuf ) {
757 758 759 760 761
      bool reGenerateChannel=false;

      //fixme: when do we regenerate
      // it seems legacy behavior is: never in UL, each frame in DL
      if (reGenerateChannel)
762 763 764
        {
	  random_channel(ptr->channel_model,0);
        }
765 766
      if (t->poll_telnetcmdq)
      	  t->poll_telnetcmdq(t->telnetcmd_qid,t);
767

768
      for (int a=0; a<nbAnt; a++) {//loop over number of Rx antennas
769
        if ( ptr->channel_model != NULL ) // apply a channel model
770 771 772 773


  {
        rxAddInput( ptr->circularBuf, (struct complex16 *) samplesVoid[a],
774 775 776
                      a,
                      ptr->channel_model,
                      nsamps,
777 778
                      t->nextTimestamp,
                      CirSize
779
                    );
780 781 782 783 784
buffer_t *b=&t->buf[a];
//ptr->channel_model->path_loss_dB=-132.24+10* b->th.option_value -RC.ru[0]->frame_parms->pdsch_config_common.referenceSignalPower; 
//LOG_I(HW,"====== path loss in dB %f  \n ", ptr->channel_model->path_loss_dB); 
}
       else { // no channel modeling
785
          sample_t *out=(sample_t *)samplesVoid[a];
786
          int nbAnt_tx = ptr->th.nbAnt;//number of Tx antennas
787 788
          //int UEbeam_id = ptr->th.beam_id;
          //LOG_I(HW, "***** beam id at UE **** %d\n",UEbeam_id);
789 790 791 792 793 794
          for (int i=0; i < nsamps; i++) {//loop over nsamps
        	  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
          } // end for i (number of samps)
795
        } // end of no channel modeling
796
      } // end for a (number of rx antennas)
797 798 799 800 801 802 803 804 805 806
    }
  }

  *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;
807

808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
}
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
833
int rfsimulator_write_init(openair0_device *device) {
WANG Tsu-Han's avatar
WANG Tsu-Han committed
834 835
  return 0;
}
836 837
__attribute__((__visibility__("default")))
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
838 839
  // to change the log level, use this on command line
  // --log_config.hw_log_level debug
840
  rfsimulator_state_t *rfsimulator = (rfsimulator_state_t *)calloc(sizeof(rfsimulator_state_t),1);
841
  rfsimulator_readconfig(rfsimulator);
842 843 844
  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 ?
845 846 847 848 849 850 851 852 853 854 855 856 857 858
                                 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
859
  device->trx_write_init = rfsimulator_write_init;
860 861 862 863 864

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

  AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1,"");
865 866 867 868 869
  // 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;
870
  //randominit(0);
871
  set_taus_seed(0);
frtabu's avatar
frtabu committed
872 873 874 875 876 877 878 879 880 881 882 883 884
   /* 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;
      }
    }    
  } 
885 886
  return 0;
}