lte-enb.c 60.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.0  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

/*! \file lte-enb.c
 * \brief Top-level threads for eNodeB
 * \author R. Knopp, F. Kaltenberger, Navid Nikaein
 * \date 2012
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr, navid.nikaein@eurecom.fr
 * \note
 * \warning
 */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <sys/sysinfo.h>
#include "rt_wrapper.h"

#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all

#include "assertions.h"
#include "msc.h"

#include "PHY/types.h"

#include "PHY/defs.h"
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all

#include "../../ARCH/COMMON/common_lib.h"

//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all

63
#include "PHY/LTE_TRANSPORT/if4_tools.h"
64
#include "PHY/LTE_TRANSPORT/if5_tools.h"
65

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
#include "PHY/extern.h"
#include "SCHED/extern.h"
#include "LAYER2/MAC/extern.h"

#include "../../SIMU/USER/init_lte.h"

#include "LAYER2/MAC/defs.h"
#include "LAYER2/MAC/extern.h"
#include "LAYER2/MAC/proto.h"
#include "RRC/LITE/extern.h"
#include "PHY_INTERFACE/extern.h"

#ifdef SMBV
#include "PHY/TOOLS/smbv.h"
unsigned short config_frames[4] = {2,9,11,13};
#endif
#include "UTIL/LOG/log_extern.h"
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/OTG/otg_externs.h"
#include "UTIL/MATH/oml.h"
#include "UTIL/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "enb_config.h"
//#include "PHY/TOOLS/time_meas.h"

#ifndef OPENAIR2
#include "UTIL/OTG/otg_extern.h"
#endif

#if defined(ENABLE_ITTI)
# if defined(ENABLE_USE_MME)
#   include "s1ap_eNB.h"
#ifdef PDCP_USE_NETLINK
#   include "SIMULATION/ETH_TRANSPORT/proto.h"
#endif
# endif
#endif

Rohit Gupta's avatar
Rohit Gupta committed
104 105
#include "T.h"

106 107 108 109 110 111 112 113 114 115
//#define DEBUG_THREADS 1

//#define USRP_DEBUG 1
struct timing_info_t {
  //unsigned int frame, hw_slot, last_slot, next_slot;
  RTIME time_min, time_max, time_avg, time_last, time_now;
  //unsigned int mbox0, mbox1, mbox2, mbox_target;
  unsigned int n_samples;
} timing_info;

116 117
// Fix per CC openair rf/if device update
// extern openair0_device openair0;
118 119 120 121 122 123 124 125 126 127 128 129 130

#if defined(ENABLE_ITTI)
extern volatile int             start_eNB;
extern volatile int             start_UE;
#endif
extern volatile int                    oai_exit;

extern openair0_config_t openair0_cfg[MAX_CARDS];

extern pthread_cond_t sync_cond;
extern pthread_mutex_t sync_mutex;
extern int sync_var;

131 132
extern transmission_mode;

133
//pthread_t                       main_eNB_thread;
134 135 136

time_stats_t softmodem_stats_mt; // main thread
time_stats_t softmodem_stats_hw; //  hw acquisition
137
time_stats_t softmodem_stats_rxtx_sf; // total tx time
138
time_stats_t softmodem_stats_rx_sf; // total rx time
139 140
//int32_t **rxdata;
//int32_t **txdata;
141

142 143
uint8_t seqno; //sequence number

144 145 146 147 148 149 150 151 152 153
static int                      time_offset[4] = {0,0,0,0};

/* mutex, cond and variable to serialize phy proc TX calls
 * (this mechanism may be relaxed in the future for better
 * performances)
 */
static struct {
  pthread_mutex_t  mutex_phy_proc_tx;
  pthread_cond_t   cond_phy_proc_tx;
  volatile uint8_t phy_proc_CC_id;
154
} sync_phy_proc;
155

156 157
extern double cpuf;

158 159
void exit_fun(const char* s);

Raymond Knopp's avatar
Raymond Knopp committed
160
void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst,eth_params_t *,int);
161
void stop_eNB(int nb_inst);
162 163


Raymond Knopp's avatar
Raymond Knopp committed
164
static inline void thread_top_init(char *thread_name,
165
				   int affinity,
Raymond Knopp's avatar
Raymond Knopp committed
166 167 168
				   uint64_t runtime,
				   uint64_t deadline,
				   uint64_t period) {
Raymond Knopp's avatar
Raymond Knopp committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

  MSC_START_USE();

#ifdef DEADLINE_SCHEDULER
  struct sched_attr attr;

  unsigned int flags = 0;

  attr.size = sizeof(attr);
  attr.sched_flags = 0;
  attr.sched_nice = 0;
  attr.sched_priority = 0;

  attr.sched_policy   = SCHED_DEADLINE;
  attr.sched_runtime  = runtime;
  attr.sched_deadline = deadline;
  attr.sched_period   = period; 

  if (sched_setattr(0, &attr, flags) < 0 ) {
    perror("[SCHED] eNB tx thread: sched_setattr failed\n");
laurent's avatar
laurent committed
189
    exit(1);
Raymond Knopp's avatar
Raymond Knopp committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
  }

#else //LOW_LATENCY
  int policy, s, j;
  struct sched_param sparam;
  char cpu_affinity[1024];
  cpu_set_t cpuset;

  /* Set affinity mask to include CPUs 1 to MAX_CPUS */
  /* CPU 0 is reserved for UHD threads */
  /* CPU 1 is reserved for all RX_TX threads */
  /* Enable CPU Affinity only if number of CPUs >2 */
  CPU_ZERO(&cpuset);

#ifdef CPU_AFFINITY
  if (get_nprocs() > 2)
  {
207 208 209 210
    if (affinity == 0)
      CPU_SET(0,&cpuset);
    else
      for (j = 1; j < get_nprocs(); j++)
Raymond Knopp's avatar
Raymond Knopp committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
        CPU_SET(j, &cpuset);
    s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
    if (s != 0)
    {
      perror( "pthread_setaffinity_np");
      exit_fun("Error setting processor affinity");
    }
  }
#endif //CPU_AFFINITY

  /* Check the actual affinity mask assigned to the thread */
  s = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
  if (s != 0) {
    perror( "pthread_getaffinity_np");
    exit_fun("Error getting processor affinity ");
  }
  memset(cpu_affinity,0,sizeof(cpu_affinity));
  for (j = 0; j < CPU_SETSIZE; j++)
    if (CPU_ISSET(j, &cpuset)) {  
      char temp[1024];
      sprintf (temp, " CPU_%d", j);
      strcat(cpu_affinity, temp);
    }

  memset(&sparam, 0, sizeof(sparam));
236
  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
Raymond Knopp's avatar
Raymond Knopp committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
  policy = SCHED_FIFO ; 
  
  s = pthread_setschedparam(pthread_self(), policy, &sparam);
  if (s != 0) {
    perror("pthread_setschedparam : ");
    exit_fun("Error setting thread priority");
  }
  
  s = pthread_getschedparam(pthread_self(), &policy, &sparam);
  if (s != 0) {
    perror("pthread_getschedparam : ");
    exit_fun("Error getting thread priority");
  }

  LOG_I(HW, "[SCHED][eNB] %s started on CPU %d TID %ld, sched_policy = %s , priority = %d, CPU Affinity=%s \n",thread_name,sched_getcpu(),gettid(),
                   (policy == SCHED_FIFO)  ? "SCHED_FIFO" :
                   (policy == SCHED_RR)    ? "SCHED_RR" :
                   (policy == SCHED_OTHER) ? "SCHED_OTHER" :
                   "???",
                   sparam.sched_priority, cpu_affinity );

#endif //LOW_LATENCY

  mlockall(MCL_CURRENT | MCL_FUTURE);

}

Raymond Knopp's avatar
Raymond Knopp committed
264
static inline void wait_sync(char *thread_name) {
Raymond Knopp's avatar
Raymond Knopp committed
265 266 267 268 269 270 271 272 273 274 275 276 277

  printf( "waiting for sync (%s)\n",thread_name);
  pthread_mutex_lock( &sync_mutex );
  
  while (sync_var<0)
    pthread_cond_wait( &sync_cond, &sync_mutex );
  
  pthread_mutex_unlock(&sync_mutex);
  
  printf( "got sync (%s)\n", thread_name);

}

278 279 280 281

void do_OFDM_mod_rt(int subframe,PHY_VARS_eNB *phy_vars_eNB)
{

282 283
  unsigned int aa,slot_offset;
  //int dummy_tx_b[7680*4] __attribute__((aligned(32)));
284
  int i, tx_offset;
285
  //int slot_sizeF = (phy_vars_eNB->frame_parms.ofdm_symbol_size)* ((phy_vars_eNB->frame_parms.Ncp==1) ? 6 : 7);
286
  int len;
287
  //int slot_offset_F = (subframe<<1)*slot_sizeF;
288

289
  slot_offset = subframe*phy_vars_eNB->frame_parms.samples_per_tti;
290

291
  
292 293
  if ((subframe_select(&phy_vars_eNB->frame_parms,subframe)==SF_DL)||
      ((subframe_select(&phy_vars_eNB->frame_parms,subframe)==SF_S))) {
294 295
    //    LOG_D(HW,"Frame %d: Generating slot %d\n",frame,next_slot);

296 297
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION,1);

298
    do_OFDM_mod_symbol(&phy_vars_eNB->common_vars,
299 300
                  0,
                  subframe<<1,
301
                  &phy_vars_eNB->frame_parms);
302 303
 
    // if S-subframe generate first slot only 
304 305
    if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_DL) {
      do_OFDM_mod_symbol(&phy_vars_eNB->common_vars,
306 307
                    0,
                    1+(subframe<<1),
308
                    &phy_vars_eNB->frame_parms);
309 310 311 312 313 314
    }

    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_OFDM_MODULATION,0);
    

/*
315 316 317
    for (aa=0; aa<phy_vars_eNB->frame_parms.nb_antennas_tx; aa++) {
      if (phy_vars_eNB->frame_parms.Ncp == EXTENDED) {
        PHY_ofdm_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F],
318
                     dummy_tx_b,
319
                     phy_vars_eNB->frame_parms.ofdm_symbol_size,
320
                     6,
321
                     phy_vars_eNB->frame_parms.nb_prefix_samples,
322
                     CYCLIC_PREFIX);
323 324 325 326 327 328 329
	if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_DL) 
	  PHY_ofdm_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF],
		       dummy_tx_b+(phy_vars_eNB->frame_parms.samples_per_tti>>1),
		       phy_vars_eNB->frame_parms.ofdm_symbol_size,
		       6,
		       phy_vars_eNB->frame_parms.nb_prefix_samples,
		       CYCLIC_PREFIX);
330
      } else {
331
        normal_prefix_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F],
332 333
                          dummy_tx_b,
                          7,
334
                          &(phy_vars_eNB->frame_parms));
335
	// if S-subframe generate first slot only
336 337 338
	if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_DL)
	  normal_prefix_mod(&phy_vars_eNB->common_vars.txdataF[0][aa][slot_offset_F+slot_sizeF],
			    dummy_tx_b+(phy_vars_eNB->frame_parms.samples_per_tti>>1),
339
			    7,
340
			    &(phy_vars_eNB->frame_parms));
341
      }
342
    } */
343

344
    for (aa=0; aa<phy_vars_eNB->frame_parms.nb_antennas_tx; aa++) {
345
      // if S-subframe generate first slot only
346 347
      if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_S)
	len = phy_vars_eNB->frame_parms.samples_per_tti>>1;
348
      else
349
	len = phy_vars_eNB->frame_parms.samples_per_tti;
350 351 352 353 354 355 356
      /*
      for (i=0;i<len;i+=4) {
	dummy_tx_b[i] = 0x100;
	dummy_tx_b[i+1] = 0x01000000;
	dummy_tx_b[i+2] = 0xff00;
	dummy_tx_b[i+3] = 0xff000000;
	}*/
357 358
      for (i=0; i<len; i++) {
        tx_offset = (int)slot_offset+time_offset[aa]+i;
359

360 361
	
        if (tx_offset<0)
362
          tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
363

364 365
        if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti))
          tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
366

367
/*	((short*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset])[0] = ((short*)dummy_tx_b)[2*i]<<openair0_cfg[0].iq_txshift;
368
	
369
	((short*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset])[1] = ((short*)dummy_tx_b)[2*i+1]<<openair0_cfg[0].iq_txshift; */
370

371
	((short*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset])[0] = ((short*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset])[0]<<openair0_cfg[0].iq_txshift;
372
	
373
	((short*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset])[1] = ((short*)&phy_vars_eNB->common_vars.txdata[0][aa][tx_offset])[1]<<openair0_cfg[0].iq_txshift;
374
     }
375
     // if S-subframe switch to RX in second subframe
376
     if (subframe_select(&phy_vars_eNB->frame_parms,subframe) == SF_S) {
377
       for (i=0; i<len; i++) {
378
	 phy_vars_eNB->common_vars.txdata[0][aa][tx_offset++] = 0x00010001;
379 380
       }
     }
381

382 383 384 385
     if ((((phy_vars_eNB->frame_parms.tdd_config==0) ||
	  (phy_vars_eNB->frame_parms.tdd_config==1) ||
	  (phy_vars_eNB->frame_parms.tdd_config==2) ||
	  (phy_vars_eNB->frame_parms.tdd_config==6)) && 
386
	  (subframe==0)) || (subframe==5)) {
387 388 389
       // turn on tx switch N_TA_offset before
       //LOG_D(HW,"subframe %d, time to switch to tx (N_TA_offset %d, slot_offset %d) \n",subframe,phy_vars_eNB->N_TA_offset,slot_offset);
       for (i=0; i<phy_vars_eNB->N_TA_offset; i++) {
390
         tx_offset = (int)slot_offset+time_offset[aa]+i-phy_vars_eNB->N_TA_offset;
391 392
         if (tx_offset<0)
           tx_offset += LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
393
	 
394 395
	 if (tx_offset>=(LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti))
	   tx_offset -= LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*phy_vars_eNB->frame_parms.samples_per_tti;
396
	 
397
	 phy_vars_eNB->common_vars.txdata[0][aa][tx_offset] = 0x00000000;
398 399 400 401
       }
     }
    }
  }
402 403
}

404

405
void tx_fh_if5(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) {
406
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, proc->timestamp_tx&0xffffffff );
407 408 409
  send_IF5(eNB, proc->timestamp_tx, proc->subframe_tx, &seqno, IF5_RRH_GW_DL);
}

410 411 412 413 414
void tx_fh_if5_mobipass(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) {
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, proc->timestamp_tx&0xffffffff );
  send_IF5(eNB, proc->timestamp_tx, proc->subframe_tx, &seqno, IF5_MOBIPASS); 
}

415 416 417 418
void tx_fh_if4p5(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) {    
  send_IF4p5(eNB,proc->frame_tx, proc->subframe_tx, IF4p5_PDLFFT, 0);
}

419 420 421 422
void proc_tx_high0(PHY_VARS_eNB *eNB,
		   eNB_rxtx_proc_t *proc,
		   relaying_type_t r_type,
		   PHY_VARS_RN *rn) {
423

Raymond Knopp's avatar
Raymond Knopp committed
424 425 426
  int offset = proc == &eNB->proc.proc_rxtx[0] ? 0 : 1;

  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_ENB+offset, proc->frame_tx );
427
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_ENB+offset, proc->subframe_tx );
Raymond Knopp's avatar
Raymond Knopp committed
428

429
  phy_procedures_eNB_TX(eNB,proc,r_type,rn,1);
430 431 432 433 434 435 436 437 438 439 440 441 442 443

  /* we're done, let the next one proceed */
  if (pthread_mutex_lock(&sync_phy_proc.mutex_phy_proc_tx) != 0) {
    LOG_E(PHY, "[SCHED][eNB] error locking PHY proc mutex for eNB TX proc\n");
    exit_fun("nothing to add");
  }	
  sync_phy_proc.phy_proc_CC_id++;
  sync_phy_proc.phy_proc_CC_id %= MAX_NUM_CCs;
  pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx);
  if (pthread_mutex_unlock(&sync_phy_proc.mutex_phy_proc_tx) != 0) {
    LOG_E(PHY, "[SCHED][eNB] error unlocking PHY proc mutex for eNB TX proc\n");
    exit_fun("nothing to add");
  }

444 445 446 447 448 449
}

void proc_tx_high(PHY_VARS_eNB *eNB,
		  eNB_rxtx_proc_t *proc,
		  relaying_type_t r_type,
		  PHY_VARS_RN *rn) {
450

Raymond Knopp's avatar
Raymond Knopp committed
451

452 453 454 455 456 457 458 459 460 461 462 463
  // do PHY high
  proc_tx_high0(eNB,proc,r_type,rn);

  // if TX fronthaul go ahead 
  if (eNB->tx_fh) eNB->tx_fh(eNB,proc);

}

void proc_tx_full(PHY_VARS_eNB *eNB,
		  eNB_rxtx_proc_t *proc,
		  relaying_type_t r_type,
		  PHY_VARS_RN *rn) {
464

465 466 467 468 469 470

  // do PHY high
  proc_tx_high0(eNB,proc,r_type,rn);
  // do OFDM modulation
  do_OFDM_mod_rt(proc->subframe_tx,eNB);
  // if TX fronthaul go ahead 
471 472
  if (eNB->tx_fh) eNB->tx_fh(eNB,proc);

473 474 475 476 477 478 479 480 481 482 483
  /*
  if (proc->frame_tx>1000) {
    write_output("/tmp/txsig0.m","txs0", &eNB->common_vars.txdata[eNB->Mod_id][0][0], eNB->frame_parms.samples_per_tti*10,1,1);
    write_output("/tmp/txsigF0.m","txsF0", &eNB->common_vars.txdataF[eNB->Mod_id][0][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1);
    write_output("/tmp/txsig1.m","txs1", &eNB->common_vars.txdata[eNB->Mod_id][1][0], eNB->frame_parms.samples_per_tti*10,1,1);
    write_output("/tmp/txsigF1.m","txsF1", &eNB->common_vars.txdataF[eNB->Mod_id][1][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1);
    if (transmission_mode == 7) 
      write_output("/tmp/txsigF5.m","txsF5", &eNB->common_vars.txdataF[eNB->Mod_id][5][0],eNB->frame_parms.symbols_per_tti*eNB->frame_parms.ofdm_symbol_size*10,1,1);
    exit_fun("");
  }
  */
484 485
}

486 487 488 489
void proc_tx_rru_if4p5(PHY_VARS_eNB *eNB,
		       eNB_rxtx_proc_t *proc,
		       relaying_type_t r_type,
		       PHY_VARS_RN *rn) {
490 491 492 493 494

  uint32_t symbol_number=0;
  uint32_t symbol_mask, symbol_mask_full;
  uint16_t packet_type;

Raymond Knopp's avatar
Raymond Knopp committed
495 496 497
  int offset = proc == &eNB->proc.proc_rxtx[0] ? 0 : 1;

  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_ENB+offset, proc->frame_tx );
498
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_ENB+offset, proc->subframe_tx );
Raymond Knopp's avatar
Raymond Knopp committed
499

500 501 502 503 504
  /// **** recv_IF4 of txdataF from RCC **** ///             
  symbol_number = 0;
  symbol_mask = 0;
  symbol_mask_full = (1<<eNB->frame_parms.symbols_per_tti)-1;
  
Raymond Knopp's avatar
Raymond Knopp committed
505

506 507 508 509 510 511 512 513 514
  do { 
    recv_IF4p5(eNB, &proc->frame_tx, &proc->subframe_tx, &packet_type, &symbol_number);
    symbol_mask = symbol_mask | (1<<symbol_number);
  } while (symbol_mask != symbol_mask_full); 

  do_OFDM_mod_rt(proc->subframe_tx, eNB);
}

void proc_tx_rru_if5(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc) {
Raymond Knopp's avatar
Raymond Knopp committed
515 516 517
  int offset = proc == &eNB->proc.proc_rxtx[0] ? 0 : 1;

  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_ENB+offset, proc->frame_tx );
518
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_ENB+offset, proc->subframe_tx );
519 520
  /// **** recv_IF5 of txdata from BBU **** ///       
  recv_IF5(eNB, &proc->timestamp_tx, proc->subframe_tx, IF5_RRH_GW_DL);
521 522
}

523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
int wait_CCs(eNB_rxtx_proc_t *proc) {

  struct timespec wait;

  wait.tv_sec=0;
  wait.tv_nsec=5000000L;

  if (pthread_mutex_timedlock(&sync_phy_proc.mutex_phy_proc_tx,&wait) != 0) {
    LOG_E(PHY, "[SCHED][eNB] error locking PHY proc mutex for eNB TX\n");
    exit_fun("nothing to add");
    return(-1);
  }
  
  // wait for our turn or oai_exit
  while (sync_phy_proc.phy_proc_CC_id != proc->CC_id && !oai_exit) {
    pthread_cond_wait(&sync_phy_proc.cond_phy_proc_tx,
		      &sync_phy_proc.mutex_phy_proc_tx);
  }
  
  if (pthread_mutex_unlock(&sync_phy_proc.mutex_phy_proc_tx) != 0) {
    LOG_E(PHY, "[SCHED][eNB] error unlocking PHY proc mutex for eNB TX\n");
    exit_fun("nothing to add");
    return(-1);
  }
  return(0);
}
549

Raymond Knopp's avatar
Raymond Knopp committed
550 551 552
static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_name) {

  start_meas(&softmodem_stats_rxtx_sf);
553 554

// ****************************************
Raymond Knopp's avatar
Raymond Knopp committed
555 556 557 558 559 560 561 562 563 564 565
  // Common RX procedures subframe n
  phy_procedures_eNB_common_RX(eNB);
  
  // UE-specific RX processing for subframe n
  if (eNB->proc_uespec_rx) eNB->proc_uespec_rx(eNB, proc, no_relay );
  
  // *****************************************
  // TX processing for subframe n+4
  // run PHY TX procedures the one after the other for all CCs to avoid race conditions
  // (may be relaxed in the future for performance reasons)
  // *****************************************
566
  //if (wait_CCs(proc)<0) return(-1);
Raymond Knopp's avatar
Raymond Knopp committed
567 568 569 570 571 572 573 574 575 576 577 578
  
  if (oai_exit) return(-1);
  
  if (eNB->proc_tx)	eNB->proc_tx(eNB, proc, no_relay, NULL );
  
  if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) return(-1);

  stop_meas( &softmodem_stats_rxtx_sf );
  
  return(0);
}

579
/*!
580
 * \brief The RX UE-specific and TX thread of eNB.
581 582 583
 * \param param is a \ref eNB_proc_t structure which contains the info what to process.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
584 585
static void* eNB_thread_rxtx( void* param ) {

586
  static int eNB_thread_rxtx_status;
587

588
  eNB_rxtx_proc_t *proc = (eNB_rxtx_proc_t*)param;
589 590
  PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id];

Raymond Knopp's avatar
Raymond Knopp committed
591 592
  char thread_name[100];

593

594
  // set default return value
595
  eNB_thread_rxtx_status = 0;
596 597


Raymond Knopp's avatar
Raymond Knopp committed
598
  sprintf(thread_name,"RXn_TXnp4_%d\n",&eNB->proc.proc_rxtx[0] == proc ? 0 : 1);
599
  thread_top_init(thread_name,1,850000L,1000000L,2000000L);
600 601

  while (!oai_exit) {
602
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
603

Raymond Knopp's avatar
Raymond Knopp committed
604
    if (wait_on_condition(&proc->mutex_rxtx,&proc->cond_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) break;
605

606
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 );
607

Raymond Knopp's avatar
Raymond Knopp committed
608
    
609
  
610 611
    if (oai_exit) break;

Raymond Knopp's avatar
Raymond Knopp committed
612
    if (rxtx(eNB,proc,thread_name) < 0) break;
613

Raymond Knopp's avatar
Raymond Knopp committed
614
  } // while !oai_exit
615

616
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
617

Raymond Knopp's avatar
Raymond Knopp committed
618
  printf( "Exiting eNB thread RXn_TXnp4\n");
619

620 621
  eNB_thread_rxtx_status = 0;
  return &eNB_thread_rxtx_status;
622 623
}

624
#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME)
625 626 627
/* Wait for eNB application initialization to be complete (eNB registration to MME) */
static void wait_system_ready (char *message, volatile int *start_flag) {
  
628
  static char *indicator[] = {".    ", "..   ", "...  ", ".... ", ".....",
629
			      " ....", "  ...", "   ..", "    .", "     "};
630 631 632 633 634 635 636
  int i = 0;
  
  while ((!oai_exit) && (*start_flag == 0)) {
    LOG_N(EMU, message, indicator[i]);
    fflush(stdout);
    i = (i + 1) % (sizeof(indicator) / sizeof(indicator[0]));
    usleep(200000);
637
  }
638 639
  
  LOG_D(EMU,"\n");
640 641
}
#endif
642

Raymond Knopp's avatar
Raymond Knopp committed
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 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 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 775 776 777 778 779 780 781 782 783 784 785 786 787

// asynchronous UL with IF4p5 (RCC,RAU,eNodeB_BBU)
void fh_if5_asynch_UL(PHY_VARS_eNB *eNB,int *frame,int *subframe) {

  eNB_proc_t *proc       = &eNB->proc;
  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;

  recv_IF5(eNB, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); 

  proc->subframe_rx = (proc->timestamp_rx/fp->samples_per_tti)%10;
  proc->frame_rx    = (proc->timestamp_rx/(10*fp->samples_per_tti))&1023;

  if (proc->first_rx != 0) {
    proc->first_rx = 0;
    *subframe = proc->subframe_rx;
    *frame    = proc->frame_rx; 
  }
  else {
    if (proc->subframe_rx != *subframe) {
      LOG_E(PHY,"subframe_rx %d is not what we expect %d\n",proc->subframe_rx,*subframe);
      exit_fun("Exiting");
    }
    if (proc->frame_rx != *frame) {
      LOG_E(PHY,"subframe_rx %d is not what we expect %d\n",proc->frame_rx,*frame);  
      exit_fun("Exiting");
    }
  }
} // eNodeB_3GPP_BBU 

// asynchronous UL with IF4p5 (RCC,RAU,eNodeB_BBU)
void fh_if4p5_asynch_UL(PHY_VARS_eNB *eNB,int *frame,int *subframe) {

  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
  eNB_proc_t *proc       = &eNB->proc;

  uint16_t packet_type;
  uint32_t symbol_number,symbol_mask,symbol_mask_full,prach_rx;


  symbol_number = 0;
  symbol_mask = 0;
  symbol_mask_full = (1<<fp->symbols_per_tti)-1;
  prach_rx = 0;

  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
    recv_IF4p5(eNB, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number);
    if (proc->first_rx != 0) {
      *frame = proc->frame_rx;
      *subframe = proc->subframe_rx;
      proc->first_rx = 0;
    }
    else {
      if (proc->frame_rx != *frame) {
	LOG_E(PHY,"frame_rx %d is not what we expect %d\n",proc->frame_rx,*frame);
	exit_fun("Exiting");
      }
      if (proc->subframe_rx != *subframe) {
	LOG_E(PHY,"subframe_rx %d is not what we expect %d\n",proc->subframe_rx,*subframe);
	exit_fun("Exiting");
      }
    }
    if (packet_type == IF4p5_PULFFT) {
      symbol_mask = symbol_mask | (1<<symbol_number);
      prach_rx = (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>0) ? 1 : 0;                            
    } else if (packet_type == IF4p5_PRACH) {
      prach_rx = 0;
    }
  } while( (symbol_mask != symbol_mask_full) || (prach_rx == 1));    
  

} 


void fh_if5_asynch_DL(PHY_VARS_eNB *eNB,int *frame,int *subframe) {

  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
  eNB_proc_t *proc       = &eNB->proc;
  int subframe_tx,frame_tx;
  openair0_timestamp timestamp_tx;

  recv_IF5(eNB, &timestamp_tx, *subframe, IF5_RRH_GW_DL); 
      //      printf("Received subframe %d (TS %llu) from RCC\n",subframe_tx,timestamp_tx);

  subframe_tx = (timestamp_tx/fp->samples_per_tti)%10;
  frame_tx    = (timestamp_tx/(fp->samples_per_tti*10))&1023;

  if (proc->first_tx != 0) {
    *subframe = subframe_tx;
    *frame    = frame_tx;
    proc->first_tx = 0;
  }
  else {
    if (subframe_tx != *subframe) {
      LOG_E(PHY,"subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe);
      exit_fun("Exiting");
    }
    if (frame_tx != *frame) { 
      LOG_E(PHY,"frame_tx %d is not what we expect %d\n",frame_tx,*frame);
      exit_fun("Exiting");
    }
  }
}

void fh_if4p5_asynch_DL(PHY_VARS_eNB *eNB,int *frame,int *subframe) {

  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
  eNB_proc_t *proc       = &eNB->proc;

  uint16_t packet_type;
  uint32_t symbol_number,symbol_mask,symbol_mask_full;
  int subframe_tx,frame_tx;

  symbol_number = 0;
  symbol_mask = 0;
  symbol_mask_full = (1<<fp->symbols_per_tti)-1;

  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
    recv_IF4p5(eNB, &frame_tx, &subframe_tx, &packet_type, &symbol_number);
    if (proc->first_tx != 0) {
      *frame    = frame_tx;
      *subframe = subframe_tx;
      proc->first_tx = 0;
    }
    else {
      if (frame_tx != *frame) {
	LOG_E(PHY,"frame_tx %d is not what we expect %d\n",frame_tx,*frame);
	exit_fun("Exiting");
      }
      if (subframe_tx != *subframe) {
	LOG_E(PHY,"subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe);
	exit_fun("Exiting");
      }
    }
    if (packet_type == IF4p5_PDLFFT) {
      symbol_mask = symbol_mask | (1<<symbol_number);
    }
    else {
      LOG_E(PHY,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type);
      exit_fun("Exiting");
    }
  } while (symbol_mask != symbol_mask_full);    
  
  do_OFDM_mod_rt(subframe_tx, eNB);
} 

788
/*!
789
 * \brief The Asynchronous RX/TX FH thread of RAU/RCC/eNB/RRU.
790 791 792 793
 * This handles the RX FH for an asynchronous RRU/UE
 * \param param is a \ref eNB_proc_t structure which contains the info what to process.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
794
static void* eNB_thread_asynch_rxtx( void* param ) {
795

796
  static int eNB_thread_asynch_rxtx_status;
797

798 799
  eNB_proc_t *proc = (eNB_proc_t*)param;
  PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id];
Raymond Knopp's avatar
Raymond Knopp committed
800 801


802

Raymond Knopp's avatar
Raymond Knopp committed
803
  int subframe=0, frame=0; 
804

805
  thread_top_init("thread_asynch",1,870000L,1000000L,1000000L);
806 807 808

  // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe

Raymond Knopp's avatar
Raymond Knopp committed
809
  wait_sync("thread_asynch");
810 811 812 813

  // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe
  printf( "waiting for devices (eNB_thread_asynch_rx)\n");

Raymond Knopp's avatar
Raymond Knopp committed
814
  wait_on_condition(&proc->mutex_asynch_rxtx,&proc->cond_asynch_rxtx,&proc->instance_cnt_asynch_rxtx,"thread_asynch");
815 816 817 818

  printf( "devices ok (eNB_thread_asynch_rx)\n");


Raymond Knopp's avatar
Raymond Knopp committed
819 820 821
  while (!oai_exit) { 
   
    if (oai_exit) break;   
822

Raymond Knopp's avatar
Raymond Knopp committed
823 824 825 826 827 828 829
    if (subframe==9) { 
      subframe=0;
      frame++;
      frame&=1023;
    } else {
      subframe++;
    }      
830

Raymond Knopp's avatar
Raymond Knopp committed
831 832 833
    if (eNB->fh_asynch) eNB->fh_asynch(eNB,&frame,&subframe);
    else AssertFatal(1==0, "Unknown eNB->node_function %d",eNB->node_function);
    
834
  }
Raymond Knopp's avatar
Raymond Knopp committed
835

836 837
  eNB_thread_asynch_rxtx_status=0;
  return(&eNB_thread_asynch_rxtx_status);
838
}
839

840

Raymond Knopp's avatar
Raymond Knopp committed
841 842 843 844 845 846



void rx_rf(PHY_VARS_eNB *eNB,int *frame,int *subframe) {

  eNB_proc_t *proc = &eNB->proc;
847 848 849 850
  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
  void *rxp[fp->nb_antennas_rx],*txp[fp->nb_antennas_tx]; 
  unsigned int rxs,txs;
  int i;
851
  int tx_sfoffset = 3;//(eNB->single_thread_flag == 1) ? 3 : 3;
852 853
  if (proc->first_rx==0) {
    
854
    // Transmit TX buffer based on timestamp from RX
855
    //    printf("trx_write -> USRP TS %llu (sf %d)\n", (proc->timestamp_rx+(3*fp->samples_per_tti)),(proc->subframe_rx+2)%10);
856
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_rx+(tx_sfoffset*fp->samples_per_tti)-openair0_cfg[0].tx_sample_advance)&0xffffffff );
857 858 859 860
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
    // prepare tx buffer pointers
	
    for (i=0; i<fp->nb_antennas_tx; i++)
861
      txp[i] = (void*)&eNB->common_vars.txdata[0][i][((proc->subframe_rx+tx_sfoffset)%10)*fp->samples_per_tti];
862 863
    
    txs = eNB->rfdevice.trx_write_func(&eNB->rfdevice,
864
				       proc->timestamp_rx+(tx_sfoffset*fp->samples_per_tti)-openair0_cfg[0].tx_sample_advance,
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
				       txp,
				       fp->samples_per_tti,
				       fp->nb_antennas_tx,
				       1);
    
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
    
    
    
    if (txs !=  fp->samples_per_tti) {
      LOG_E(PHY,"TX : Timeout (sent %d/%d)\n",txs, fp->samples_per_tti);
      exit_fun( "problem transmitting samples" );
    }	
  }
  
  for (i=0; i<fp->nb_antennas_rx; i++)
    rxp[i] = (void*)&eNB->common_vars.rxdata[0][i][*subframe*fp->samples_per_tti];
  
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );
884

885 886 887 888 889
  rxs = eNB->rfdevice.trx_read_func(&eNB->rfdevice,
				    &(proc->timestamp_rx),
				    rxp,
				    fp->samples_per_tti,
				    fp->nb_antennas_rx);
890 891

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
892 893 894
  
  proc->frame_rx    = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
  proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
895
  proc->timestamp_tx = proc->timestamp_rx+(4*fp->samples_per_tti);
896
  //  printf("trx_read <- USRP TS %llu (sf %d, first_rx %d)\n", proc->timestamp_rx,proc->subframe_rx,proc->first_rx);  
897 898 899
  
  if (proc->first_rx == 0) {
    if (proc->subframe_rx != *subframe){
900
      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",proc->subframe_rx,*subframe);
901 902 903 904
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
905
      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame);
906 907 908 909 910 911 912 913 914 915 916 917
      exit_fun("Exiting");
    }
  } else {
    proc->first_rx = 0;
    *frame = proc->frame_rx;
    *subframe = proc->subframe_rx;        
  }
  
  //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",proc->timestamp_rx,proc->frame_rx,frame,proc->subframe_rx,subframe);
  
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
  
918 919 920 921 922
  if (rxs != fp->samples_per_tti)
    exit_fun( "problem receiving samples" );
  

  
923 924
}

Raymond Knopp's avatar
Raymond Knopp committed
925
void rx_fh_if5(PHY_VARS_eNB *eNB,int *frame, int *subframe) {
926 927

  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
Raymond Knopp's avatar
Raymond Knopp committed
928
  eNB_proc_t *proc = &eNB->proc;
929 930 931 932 933 934 935

  recv_IF5(eNB, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); 

  proc->frame_rx    = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
  proc->subframe_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
  
  if (proc->first_rx == 0) {
936
    if (proc->subframe_rx != *subframe){
937 938 939 940
      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",proc->subframe_rx,subframe);
      exit_fun("Exiting");
    }
    
941
    if (proc->frame_rx != *frame) {
942 943 944 945 946
      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,frame);
      exit_fun("Exiting");
    }
  } else {
    proc->first_rx = 0;
947 948
    *frame = proc->frame_rx;
    *subframe = proc->subframe_rx;        
949 950 951 952 953 954
  }      
  
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );

}

Raymond Knopp's avatar
Raymond Knopp committed
955

956
void rx_fh_if4p5(PHY_VARS_eNB *eNB,int *frame,int *subframe) {
957 958

  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
959
  eNB_proc_t *proc = &eNB->proc;
960 961 962 963 964 965 966 967 968 969

  int prach_rx;

  uint16_t packet_type;
  uint32_t symbol_number=0;
  uint32_t symbol_mask, symbol_mask_full;

  symbol_mask = 0;
  symbol_mask_full = (1<<fp->symbols_per_tti)-1;
  prach_rx = 0;
970

971 972
  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
    recv_IF4p5(eNB, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number);
973

974 975 976 977 978 979
    if (packet_type == IF4p5_PULFFT) {
      symbol_mask = symbol_mask | (1<<symbol_number);
      prach_rx = (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>0) ? 1 : 0;                            
    } else if (packet_type == IF4p5_PRACH) {
      prach_rx = 0;
    }
980

981
  } while( (symbol_mask != symbol_mask_full) || (prach_rx == 1));    
982 983 984 985 986 987

  //caculate timestamp_rx, timestamp_tx based on frame and subframe
   proc->timestamp_rx = ((proc->frame_rx * 10)  + proc->subframe_rx ) * fp->samples_per_tti ;
   proc->timestamp_tx = proc->timestamp_rx +  (4*fp->samples_per_tti);
 
 
988 989
  if (proc->first_rx == 0) {
    if (proc->subframe_rx != *subframe){
990
      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",proc->subframe_rx,*subframe);
991 992 993
      exit_fun("Exiting");
    }
    if (proc->frame_rx != *frame) {
994
      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",proc->frame_rx,*frame);
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
      exit_fun("Exiting");
    }
  } else {
    proc->first_rx = 0;
    *frame = proc->frame_rx;
    *subframe = proc->subframe_rx;        
  }
  
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
  
}

Raymond Knopp's avatar
Raymond Knopp committed
1007 1008
void rx_fh_slave(PHY_VARS_eNB *eNB,int *frame,int *subframe) {
  // This case is for synchronization to another thread
1009
  // it just waits for an external event.  The actual rx_fh is handle by the asynchronous RX thread
Raymond Knopp's avatar
Raymond Knopp committed
1010 1011
  eNB_proc_t *proc=&eNB->proc;

Raymond Knopp's avatar
Raymond Knopp committed
1012 1013 1014 1015 1016
  if (wait_on_condition(&proc->mutex_FH,&proc->cond_FH,&proc->instance_cnt_FH,"rx_fh_slave") < 0)
    return;

  release_thread(&proc->mutex_FH,&proc->instance_cnt_FH,"rx_fh_slave");

Raymond Knopp's avatar
Raymond Knopp committed
1017 1018 1019 1020
  
}


1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
int wakeup_rxtx(eNB_proc_t *proc,eNB_rxtx_proc_t *proc_rxtx,LTE_DL_FRAME_PARMS *fp) {

  int i;
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;

  /* accept some delay in processing - up to 5ms */
  for (i = 0; i < 10 && proc_rxtx->instance_cnt_rxtx == 0; i++) {
    LOG_W( PHY,"[eNB] Frame %d, eNB RXn-TXnp4 thread busy!! (cnt_rxtx %i)\n", proc_rxtx->frame_tx, proc_rxtx->instance_cnt_rxtx);
    usleep(500);
  }
  if (proc_rxtx->instance_cnt_rxtx == 0) {
    exit_fun( "TX thread busy" );
    return(-1);
  }

  // wake up TX for subframe n+4
  // lock the TX mutex and make sure the thread is ready
  if (pthread_mutex_timedlock(&proc_rxtx->mutex_rxtx,&wait) != 0) {
    LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB RXTX thread %d (IC %d)\n", proc_rxtx->subframe_rx&1,proc_rxtx->instance_cnt_rxtx );
    exit_fun( "error locking mutex_rxtx" );
    return(-1);
  }
  
  ++proc_rxtx->instance_cnt_rxtx;
  
  // We have just received and processed the common part of a subframe, say n. 
  // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired 
  // transmitted timestamp of the next TX slot (first).
  // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, 
Raymond Knopp's avatar
Raymond Knopp committed
1053 1054
  // we want to generate subframe (n+4), so TS_tx = TX_rx+4*samples_per_tti,
  // and proc->subframe_tx = proc->subframe_rx+4
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
  proc_rxtx->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_tti);
  proc_rxtx->frame_rx     = proc->frame_rx;
  proc_rxtx->subframe_rx  = proc->subframe_rx;
  proc_rxtx->frame_tx     = (proc_rxtx->subframe_rx > 5) ? (proc_rxtx->frame_rx+1)&1023 : proc_rxtx->frame_rx;
  proc_rxtx->subframe_tx  = (proc_rxtx->subframe_rx + 4)%10;
  
  // the thread can now be woken up
  if (pthread_cond_signal(&proc_rxtx->cond_rxtx) != 0) {
    LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB RXn-TXnp4 thread\n");
    exit_fun( "ERROR pthread_cond_signal" );
    return(-1);
  }
  
  pthread_mutex_unlock( &proc_rxtx->mutex_rxtx );

  return(0);
}

void wakeup_slaves(eNB_proc_t *proc) {

  int i;
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
  
  for (i=0;i<proc->num_slaves;i++) {
    eNB_proc_t *slave_proc = proc->slave_proc[i];
    // wake up slave FH thread
    // lock the FH mutex and make sure the thread is ready
    if (pthread_mutex_timedlock(&slave_proc->mutex_FH,&wait) != 0) {
      LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB CCid %d slave CCid %d (IC %d)\n",proc->CC_id,slave_proc->CC_id);
      exit_fun( "error locking mutex_rxtx" );
      break;
    }
    
    int cnt_slave            = ++slave_proc->instance_cnt_FH;
    slave_proc->frame_rx     = proc->frame_rx;
    slave_proc->subframe_rx  = proc->subframe_rx;
    slave_proc->timestamp_rx = proc->timestamp_rx;
1095 1096
    slave_proc->timestamp_tx = proc->timestamp_tx; 

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
    pthread_mutex_unlock( &slave_proc->mutex_FH );
    
    if (cnt_slave == 0) {
      // the thread was presumably waiting where it should and can now be woken up
      if (pthread_cond_signal(&slave_proc->cond_FH) != 0) {
	LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB CCid %d, slave CCid %d\n",proc->CC_id,slave_proc->CC_id);
          exit_fun( "ERROR pthread_cond_signal" );
	  break;
      }
    } else {
1107
      LOG_W( PHY,"[eNB] Frame %d, slave CC_id %d thread busy!! (cnt_FH %i)\n",slave_proc->frame_rx,slave_proc->CC_id, cnt_slave);
1108 1109 1110 1111 1112 1113
      exit_fun( "FH thread busy" );
      break;
    }             
  }
}

1114
/*!
1115 1116 1117
 * \brief The Fronthaul thread of RRU/RAU/RCC/eNB
 * In the case of RRU/eNB, handles interface with external RF
 * In the case of RAU/RCC, handles fronthaul interface with RRU/RAU
1118 1119 1120
 * \param param is a \ref eNB_proc_t structure which contains the info what to process.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
Raymond Knopp's avatar
Raymond Knopp committed
1121

1122
static void* eNB_thread_FH( void* param ) {
1123
  
1124
  static int eNB_thread_FH_status;
1125 1126

  eNB_proc_t *proc = (eNB_proc_t*)param;
1127 1128
  PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id];
  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
1129

Sandeep Kumar's avatar
Sandeep Kumar committed
1130
  int subframe=0, frame=0; 
1131

1132
  // set default return value
1133
  eNB_thread_FH_status = 0;
1134

1135
  thread_top_init("eNB_thread_FH",0,870000,1000000,1000000);
1136

Raymond Knopp's avatar
Raymond Knopp committed
1137
  wait_sync("eNB_thread_FH");
1138

1139
#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME)
Raymond Knopp's avatar
Raymond Knopp committed
1140 1141
  if (eNB->node_function < NGFI_RRU_IF5)
    wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
1142
#endif 
1143

1144 1145 1146
  // Start IF device if any
  if (eNB->start_if) 
    if (eNB->start_if(eNB) != 0)
1147
      LOG_E(HW,"Could not start the IF device\n");
1148

Raymond Knopp's avatar
Raymond Knopp committed
1149 1150 1151 1152 1153
  // Start RF device if any
  if (eNB->start_rf)
    if (eNB->start_rf(eNB) != 0)
      LOG_E(HW,"Could not start the RF device\n");

Raymond Knopp's avatar
Raymond Knopp committed
1154
  // wakeup asnych_rxtx thread because the devices are ready at this point
1155 1156 1157 1158 1159
  pthread_mutex_lock(&proc->mutex_asynch_rxtx);
  proc->instance_cnt_asynch_rxtx=0;
  pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
  pthread_cond_signal(&proc->cond_asynch_rxtx);

1160 1161
  // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
  while (!oai_exit) {
1162

Raymond Knopp's avatar
Raymond Knopp committed
1163 1164
    // these are local subframe/frame counters to check that we are in synch with the fronthaul timing.
    // They are set on the first rx/tx in the underly FH routines.
1165 1166 1167 1168 1169 1170 1171 1172
    if (subframe==9) { 
      subframe=0;
      frame++;
      frame&=1023;
    } else {
      subframe++;
    }      

Raymond Knopp's avatar
Raymond Knopp committed
1173 1174 1175 1176
 
    // synchronization on FH interface, acquire signals/data and block
    if (eNB->rx_fh) eNB->rx_fh(eNB,&frame,&subframe);
    else AssertFatal(1==0, "No fronthaul interface : eNB->node_function %d",eNB->node_function);
1177

Cedric Roux's avatar
Cedric Roux committed
1178 1179
    T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx));

1180 1181
    // At this point, all information for subframe has been received on FH interface
    // If this proc is to provide synchronization, do so
1182
    wakeup_slaves(proc);
1183 1184
      
    // wake up RXn_TXnp4 thread for the subframe
1185
    // choose even or odd thread for RXn-TXnp4 processing 
1186
    if (wakeup_rxtx(proc,&proc->proc_rxtx[proc->subframe_rx&1],fp) < 0)
1187
      break;
1188

Raymond Knopp's avatar
Raymond Knopp committed
1189
    // artifical sleep for very slow fronthaul
1190 1191
    if (eNB->frame_parms.N_RB_DL==6)
      rt_sleep_ns(800000LL);
1192 1193 1194
  }
    
  printf( "Exiting FH thread \n");
Raymond Knopp's avatar
Raymond Knopp committed
1195
 
1196 1197
  eNB_thread_FH_status = 0;
  return &eNB_thread_FH_status;
1198 1199 1200 1201 1202 1203 1204 1205
}


/*!
 * \brief The prach receive thread of eNB.
 * \param param is a \ref eNB_proc_t structure which contains the info what to process.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
1206
static void* eNB_thread_prach( void* param ) {
1207 1208 1209 1210
  static int eNB_thread_prach_status;

  eNB_proc_t *proc = (eNB_proc_t*)param;
  PHY_VARS_eNB *eNB= PHY_vars_eNB_g[0][proc->CC_id];
Raymond Knopp's avatar
Raymond Knopp committed
1211

1212 1213 1214
  // set default return value
  eNB_thread_prach_status = 0;

1215
  thread_top_init("eNB_thread_prach",1,500000L,1000000L,20000000L);
1216

1217 1218 1219
  while (!oai_exit) {
    
    if (oai_exit) break;
1220

Raymond Knopp's avatar
Raymond Knopp committed
1221
    if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break;
Raymond Knopp's avatar
Raymond Knopp committed
1222
    
1223
    prach_procedures(eNB);
1224
    
Raymond Knopp's avatar
Raymond Knopp committed
1225
    if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break;
1226 1227 1228 1229 1230 1231
  }

  printf( "Exiting eNB thread PRACH\n");

  eNB_thread_prach_status = 0;
  return &eNB_thread_prach_status;
1232
}
1233

Raymond Knopp's avatar
Raymond Knopp committed
1234
static void* eNB_thread_single( void* param ) {
1235

Raymond Knopp's avatar
Raymond Knopp committed
1236
  static int eNB_thread_single_status;
1237

Raymond Knopp's avatar
Raymond Knopp committed
1238 1239 1240
  eNB_proc_t *proc = (eNB_proc_t*)param;
  eNB_rxtx_proc_t *proc_rxtx = &proc->proc_rxtx[0];
  PHY_VARS_eNB *eNB = PHY_vars_eNB_g[0][proc->CC_id];
1241

Raymond Knopp's avatar
Raymond Knopp committed
1242
  int subframe=0, frame=0; 
1243

Raymond Knopp's avatar
Raymond Knopp committed
1244 1245
  // set default return value
  eNB_thread_single_status = 0;
1246

1247
  thread_top_init("eNB_thread_single",0,870000,1000000,1000000);
1248

Raymond Knopp's avatar
Raymond Knopp committed
1249
  wait_sync("eNB_thread_single");
1250

1251
#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME)
Raymond Knopp's avatar
Raymond Knopp committed
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
  if (eNB->node_function < NGFI_RRU_IF5)
    wait_system_ready ("Waiting for eNB application to be ready %s\r", &start_eNB);
#endif 

  // Start IF device if any
  if (eNB->start_if) 
    if (eNB->start_if(eNB) != 0)
      LOG_E(HW,"Could not start the IF device\n");

  // Start RF device if any
  if (eNB->start_rf)
    if (eNB->start_rf(eNB) != 0)
      LOG_E(HW,"Could not start the RF device\n");

  // wakeup asnych_rxtx thread because the devices are ready at this point
  pthread_mutex_lock(&proc->mutex_asynch_rxtx);
  proc->instance_cnt_asynch_rxtx=0;
  pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
  pthread_cond_signal(&proc->cond_asynch_rxtx);
1271

Raymond Knopp's avatar
Raymond Knopp committed
1272
  // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
1273 1274
  while (!oai_exit) {

Raymond Knopp's avatar
Raymond Knopp committed
1275 1276 1277 1278 1279 1280 1281 1282 1283
    // these are local subframe/frame counters to check that we are in synch with the fronthaul timing.
    // They are set on the first rx/tx in the underly FH routines.
    if (subframe==9) { 
      subframe=0;
      frame++;
      frame&=1023;
    } else {
      subframe++;
    }      
1284

1285
    LOG_D(PHY,"eNB Fronthaul thread, frame %d, subframe %d\n",frame,subframe);
Raymond Knopp's avatar
Raymond Knopp committed
1286 1287 1288 1289 1290 1291 1292
 
    // synchronization on FH interface, acquire signals/data and block
    if (eNB->rx_fh) eNB->rx_fh(eNB,&frame,&subframe);
    else AssertFatal(1==0, "No fronthaul interface : eNB->node_function %d",eNB->node_function);

    T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx));

1293 1294 1295 1296 1297
    proc_rxtx->subframe_rx = proc->subframe_rx;
    proc_rxtx->frame_rx    = proc->frame_rx;
    proc_rxtx->subframe_tx = (proc->subframe_rx+4)%10;
    proc_rxtx->frame_tx    = (proc->subframe_rx < 6) ? proc->frame_rx : (proc->frame_rx+1)&1023; 
    proc_rxtx->timestamp_tx = proc->timestamp_tx;
1298

Raymond Knopp's avatar
Raymond Knopp committed
1299 1300 1301 1302 1303
    // At this point, all information for subframe has been received on FH interface
    // If this proc is to provide synchronization, do so
    wakeup_slaves(proc);

    if (rxtx(eNB,proc_rxtx,"eNB_thread_single") < 0) break;
1304
  }
Raymond Knopp's avatar
Raymond Knopp committed
1305
  
1306

Raymond Knopp's avatar
Raymond Knopp committed
1307 1308 1309 1310
  printf( "Exiting eNB_single thread \n");
 
  eNB_thread_single_status = 0;
  return &eNB_thread_single_status;
Raymond Knopp's avatar
Raymond Knopp committed
1311

1312 1313
}

1314
extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *);
1315 1316
extern void init_td_thread(PHY_VARS_eNB *, pthread_attr_t *);
extern void init_te_thread(PHY_VARS_eNB *, pthread_attr_t *);
1317

1318
void init_eNB_proc(int inst) {
1319
  
Rohit Gupta's avatar
Rohit Gupta committed
1320
  int i=0;
1321
  int CC_id;
1322 1323
  PHY_VARS_eNB *eNB;
  eNB_proc_t *proc;
1324
  eNB_rxtx_proc_t *proc_rxtx;
1325
  pthread_attr_t *attr0=NULL,*attr1=NULL,*attr_FH=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_single=NULL,*attr_fep=NULL,*attr_td=NULL,*attr_te;
Raymond Knopp's avatar
Raymond Knopp committed
1326

1327 1328
  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
    eNB = PHY_vars_eNB_g[inst][CC_id];
laurent's avatar
laurent committed
1329
#ifndef OCP_FRAMEWORK
1330
    LOG_I(PHY,"Initializing eNB %d CC_id %d (%s,%s),\n",inst,CC_id,eNB_functions[eNB->node_function],eNB_timing[eNB->node_timing]);
laurent's avatar
laurent committed
1331
#endif
1332
    proc = &eNB->proc;
Raymond Knopp's avatar
Raymond Knopp committed
1333

1334 1335 1336
    proc_rxtx = proc->proc_rxtx;
    proc_rxtx[0].instance_cnt_rxtx = -1;
    proc_rxtx[1].instance_cnt_rxtx = -1;
1337 1338
    proc->instance_cnt_prach       = -1;
    proc->instance_cnt_FH          = -1;
1339
    proc->instance_cnt_asynch_rxtx = -1;
1340
    proc->CC_id = CC_id;    
1341
    
Raymond Knopp's avatar
Raymond Knopp committed
1342 1343 1344
    proc->first_rx=1;
    proc->first_tx=1;

1345 1346 1347 1348
    pthread_mutex_init( &proc_rxtx[0].mutex_rxtx, NULL);
    pthread_mutex_init( &proc_rxtx[1].mutex_rxtx, NULL);
    pthread_cond_init( &proc_rxtx[0].cond_rxtx, NULL);
    pthread_cond_init( &proc_rxtx[1].cond_rxtx, NULL);
Raymond Knopp's avatar
Raymond Knopp committed
1349 1350 1351 1352

    pthread_mutex_init( &proc->mutex_prach, NULL);
    pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL);

1353 1354
    pthread_cond_init( &proc->cond_prach, NULL);
    pthread_cond_init( &proc->cond_FH, NULL);
1355
    pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
1356 1357 1358 1359 1360 1361

    pthread_attr_init( &proc->attr_FH);
    pthread_attr_init( &proc->attr_prach);
    pthread_attr_init( &proc->attr_asynch_rxtx);
    pthread_attr_init( &proc->attr_single);
    pthread_attr_init( &proc->attr_fep);
1362 1363
    pthread_attr_init( &proc->attr_td);
    pthread_attr_init( &proc->attr_te);
1364 1365
    pthread_attr_init( &proc_rxtx[0].attr_rxtx);
    pthread_attr_init( &proc_rxtx[1].attr_rxtx);
1366
#ifndef DEADLINE_SCHEDULER
Raymond Knopp's avatar
Raymond Knopp committed
1367 1368 1369 1370 1371 1372
    attr0       = &proc_rxtx[0].attr_rxtx;
    attr1       = &proc_rxtx[1].attr_rxtx;
    attr_FH     = &proc->attr_FH;
    attr_prach  = &proc->attr_prach;
    attr_asynch = &proc->attr_asynch_rxtx;
    attr_single = &proc->attr_single;
1373
    attr_fep    = &proc->attr_fep;
1374 1375
    attr_td     = &proc->attr_td;
    attr_te     = &proc->attr_te; 
Raymond Knopp's avatar
Raymond Knopp committed
1376 1377 1378 1379 1380 1381 1382
#endif

    if (eNB->single_thread_flag==0) {
      pthread_create( &proc_rxtx[0].pthread_rxtx, attr0, eNB_thread_rxtx, &proc_rxtx[0] );
      pthread_create( &proc_rxtx[1].pthread_rxtx, attr1, eNB_thread_rxtx, &proc_rxtx[1] );
      pthread_create( &proc->pthread_FH, attr_FH, eNB_thread_FH, &eNB->proc );
    }
1383
    else {
Raymond Knopp's avatar
Raymond Knopp committed
1384
      pthread_create(&proc->pthread_single, attr_single, eNB_thread_single, &eNB->proc);
1385
      init_fep_thread(eNB,attr_fep);
1386 1387
      init_td_thread(eNB,attr_td);
      init_te_thread(eNB,attr_te);
1388
    }
Raymond Knopp's avatar
Raymond Knopp committed
1389
    pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach, &eNB->proc );
1390
    if ((eNB->node_timing == synch_to_other) ||
Raymond Knopp's avatar
Raymond Knopp committed
1391 1392
	(eNB->node_function == NGFI_RRU_IF5) ||
	(eNB->node_function == NGFI_RRU_IF4p5))
1393 1394


Raymond Knopp's avatar
Raymond Knopp committed
1395 1396
      pthread_create( &proc->pthread_asynch_rxtx, attr_asynch, eNB_thread_asynch_rxtx, &eNB->proc );

1397
    char name[16];
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
    if (eNB->single_thread_flag == 0) {
      snprintf( name, sizeof(name), "RXTX0 %d", i );
      pthread_setname_np( proc_rxtx[0].pthread_rxtx, name );
      snprintf( name, sizeof(name), "RXTX1 %d", i );
      pthread_setname_np( proc_rxtx[1].pthread_rxtx, name );
      snprintf( name, sizeof(name), "FH %d", i );
      pthread_setname_np( proc->pthread_FH, name );
    }
    else {
      snprintf( name, sizeof(name), " %d", i );
      pthread_setname_np( proc->pthread_single, name );
    }
1410
  }
1411

1412 1413
  //for multiple CCs: setup master and slaves
  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
1414 1415
    eNB = PHY_vars_eNB_g[inst][CC_id];

1416
    if (eNB->node_timing == synch_to_ext_device) { //master
1417 1418 1419 1420
      eNB->proc.num_slaves = MAX_NUM_CCs-1;
      eNB->proc.slave_proc = (eNB_proc_t**)malloc(eNB->proc.num_slaves*sizeof(eNB_proc_t*));

      for (i=0; i< eNB->proc.num_slaves; i++) {
1421 1422
        if (i < CC_id)  eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i]->proc);
        if (i >= CC_id)  eNB->proc.slave_proc[i] = &(PHY_vars_eNB_g[inst][i+1]->proc);
1423 1424 1425 1426 1427
      }
    }
  }


1428 1429 1430 1431
  /* setup PHY proc TX sync mechanism */
  pthread_mutex_init(&sync_phy_proc.mutex_phy_proc_tx, NULL);
  pthread_cond_init(&sync_phy_proc.cond_phy_proc_tx, NULL);
  sync_phy_proc.phy_proc_CC_id = 0;
1432 1433
}

1434

1435

1436 1437 1438
/*!
 * \brief Terminate eNB TX and RX threads.
 */
1439
void kill_eNB_proc(int inst) {
1440

1441
  int *status;
1442 1443
  PHY_VARS_eNB *eNB;
  eNB_proc_t *proc;
1444
  eNB_rxtx_proc_t *proc_rxtx;
1445
  for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
1446
    eNB=PHY_vars_eNB_g[inst][CC_id];
1447 1448
    
    proc = &eNB->proc;
1449
    proc_rxtx = &proc->proc_rxtx[0];
1450
    
1451
#ifdef DEBUG_THREADS
1452
    printf( "Killing TX CC_id %d thread %d\n", CC_id, i );
1453
#endif
1454
    
1455 1456
    proc_rxtx[0].instance_cnt_rxtx = 0; // FIXME data race!
    proc_rxtx[1].instance_cnt_rxtx = 0; // FIXME data race!
Raymond Knopp's avatar
Raymond Knopp committed
1457
    proc->instance_cnt_prach = 0;
1458
    proc->instance_cnt_FH = 0;
1459
    pthread_cond_signal( &proc_rxtx[0].cond_rxtx );    
Raymond Knopp's avatar
Raymond Knopp committed
1460 1461
    pthread_cond_signal( &proc_rxtx[1].cond_rxtx );
    pthread_cond_signal( &proc->cond_prach );
1462
    pthread_cond_signal( &proc->cond_FH );
1463
    pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx);
Raymond Knopp's avatar
Raymond Knopp committed
1464

1465 1466 1467 1468 1469 1470 1471
    pthread_join( proc->pthread_FH, (void**)&status ); 
    pthread_mutex_destroy( &proc->mutex_FH );
    pthread_cond_destroy( &proc->cond_FH );
            
    pthread_join( proc->pthread_prach, (void**)&status );    
    pthread_mutex_destroy( &proc->mutex_prach );
    pthread_cond_destroy( &proc->cond_prach );         
1472

1473
    int i;
Raymond Knopp's avatar
Raymond Knopp committed
1474
    for (i=0;i<2;i++) {
1475 1476 1477 1478
      pthread_join( proc_rxtx[i].pthread_rxtx, (void**)&status );
      pthread_mutex_destroy( &proc_rxtx[i].mutex_rxtx );
      pthread_cond_destroy( &proc_rxtx[i].cond_rxtx );
    }
1479
  }
1480 1481
}

1482

1483 1484 1485 1486
/* this function maps the phy_vars_eNB tx and rx buffers to the available rf chains.
   Each rf chain is is addressed by the card number and the chain on the card. The
   rf_map specifies for each CC, on which rf chain the mapping should start. Multiple
   antennas are mapped to successive RF chains on the same card. */
1487
int setup_eNB_buffers(PHY_VARS_eNB **phy_vars_eNB, openair0_config_t *openair0_cfg) {
1488

1489 1490
  int i,j; 
  int CC_id,card,ant;
1491

1492
  //uint16_t N_TA_offset = 0;
1493

1494 1495 1496 1497
  LTE_DL_FRAME_PARMS *frame_parms;

  for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
    if (phy_vars_eNB[CC_id]) {
1498
      frame_parms = &(phy_vars_eNB[CC_id]->frame_parms);
1499 1500 1501 1502 1503 1504
      printf("setup_eNB_buffers: frame_parms = %p\n",frame_parms);
    } else {
      printf("phy_vars_eNB[%d] not initialized\n", CC_id);
      return(-1);
    }

1505
    /*
1506 1507 1508 1509 1510 1511 1512 1513
    if (frame_parms->frame_type == TDD) {
      if (frame_parms->N_RB_DL == 100)
        N_TA_offset = 624;
      else if (frame_parms->N_RB_DL == 50)
        N_TA_offset = 624/2;
      else if (frame_parms->N_RB_DL == 25)
        N_TA_offset = 624/4;
    }
1514
    */
Raymond Knopp's avatar
Raymond Knopp committed
1515
 
1516

Raymond Knopp's avatar
Raymond Knopp committed
1517
    if (openair0_cfg[CC_id].mmapped_dma == 1) {
1518
    // replace RX signal buffers with mmaped HW versions
Raymond Knopp's avatar
Raymond Knopp committed
1519 1520
      
      for (i=0; i<frame_parms->nb_antennas_rx; i++) {
1521 1522 1523
	card = i/4;
	ant = i%4;
	printf("Mapping eNB CC_id %d, rx_ant %d, on card %d, chain %d\n",CC_id,i,phy_vars_eNB[CC_id]->rf_map.card+card, phy_vars_eNB[CC_id]->rf_map.chain+ant);
Raymond Knopp's avatar
Raymond Knopp committed
1524
	free(phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]);
1525
	phy_vars_eNB[CC_id]->common_vars.rxdata[0][i] = openair0_cfg[phy_vars_eNB[CC_id]->rf_map.card+card].rxbase[phy_vars_eNB[CC_id]->rf_map.chain+ant];
Raymond Knopp's avatar
Raymond Knopp committed
1526 1527 1528 1529 1530 1531
	
	printf("rxdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]);
	for (j=0; j<16; j++) {
	  printf("rxbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->common_vars.rxdata[0][i][j]);
	  phy_vars_eNB[CC_id]->common_vars.rxdata[0][i][j] = 16-j;
	}
1532
      }
Raymond Knopp's avatar
Raymond Knopp committed
1533 1534
      
      for (i=0; i<frame_parms->nb_antennas_tx; i++) {
1535 1536 1537
	card = i/4;
	ant = i%4;
	printf("Mapping eNB CC_id %d, tx_ant %d, on card %d, chain %d\n",CC_id,i,phy_vars_eNB[CC_id]->rf_map.card+card, phy_vars_eNB[CC_id]->rf_map.chain+ant);
Raymond Knopp's avatar
Raymond Knopp committed
1538
	free(phy_vars_eNB[CC_id]->common_vars.txdata[0][i]);
1539
	phy_vars_eNB[CC_id]->common_vars.txdata[0][i] = openair0_cfg[phy_vars_eNB[CC_id]->rf_map.card+card].txbase[phy_vars_eNB[CC_id]->rf_map.chain+ant];
Raymond Knopp's avatar
Raymond Knopp committed
1540 1541 1542 1543 1544 1545 1546
	
	printf("txdata[%d] @ %p\n",i,phy_vars_eNB[CC_id]->common_vars.txdata[0][i]);
	
	for (j=0; j<16; j++) {
	  printf("txbuffer %d: %x\n",j,phy_vars_eNB[CC_id]->common_vars.txdata[0][i][j]);
	  phy_vars_eNB[CC_id]->common_vars.txdata[0][i][j] = 16-j;
	}
1547 1548
      }
    }
Raymond Knopp's avatar
Raymond Knopp committed
1549
    else {  // not memory-mapped DMA 
1550 1551
      //nothing to do, everything already allocated in lte_init
      /*
Raymond Knopp's avatar
Raymond Knopp committed
1552 1553 1554 1555 1556
      rxdata = (int32_t**)malloc16(frame_parms->nb_antennas_rx*sizeof(int32_t*));
      txdata = (int32_t**)malloc16(frame_parms->nb_antennas_tx*sizeof(int32_t*));
      
      for (i=0; i<frame_parms->nb_antennas_rx; i++) {
	free(phy_vars_eNB[CC_id]->common_vars.rxdata[0][i]);
1557
	rxdata[i] = (int32_t*)(32 + malloc16(32+frame_parms->samples_per_tti*10*sizeof(int32_t))); // FIXME broken memory allocation
1558
	phy_vars_eNB[CC_id]->common_vars.rxdata[0][i] = rxdata[i]; //-N_TA_offset; // N_TA offset for TDD         FIXME! N_TA_offset > 16 => access of unallocated memory
1559
	memset(rxdata[i], 0, frame_parms->samples_per_tti*10*sizeof(int32_t));
Raymond Knopp's avatar
Raymond Knopp committed
1560
	printf("rxdata[%d] @ %p (%p) (N_TA_OFFSET %d)\n", i, phy_vars_eNB[CC_id]->common_vars.rxdata[0][i],rxdata[i],N_TA_offset);      
1561 1562
      }
      
Raymond Knopp's avatar
Raymond Knopp committed
1563 1564
      for (i=0; i<frame_parms->nb_antennas_tx; i++) {
	free(phy_vars_eNB[CC_id]->common_vars.txdata[0][i]);
1565
	txdata[i] = (int32_t*)(32 + malloc16(32 + frame_parms->samples_per_tti*10*sizeof(int32_t))); // FIXME broken memory allocation
Raymond Knopp's avatar
Raymond Knopp committed
1566
	phy_vars_eNB[CC_id]->common_vars.txdata[0][i] = txdata[i];
1567
	memset(txdata[i],0, frame_parms->samples_per_tti*10*sizeof(int32_t));
Raymond Knopp's avatar
Raymond Knopp committed
1568
	printf("txdata[%d] @ %p\n", i, phy_vars_eNB[CC_id]->common_vars.txdata[0][i]);
1569
      }
1570
      */
1571 1572 1573 1574 1575 1576 1577 1578
    }
  }

  return(0);
}


void reset_opp_meas(void) {
1579

1580 1581 1582 1583 1584
  int sfn;
  reset_meas(&softmodem_stats_mt);
  reset_meas(&softmodem_stats_hw);
  
  for (sfn=0; sfn < 10; sfn++) {
1585
    reset_meas(&softmodem_stats_rxtx_sf);
1586
    reset_meas(&softmodem_stats_rx_sf);
1587 1588 1589
  }
}

1590

1591 1592 1593 1594 1595 1596 1597
void print_opp_meas(void) {

  int sfn=0;
  print_meas(&softmodem_stats_mt, "Main ENB Thread", NULL, NULL);
  print_meas(&softmodem_stats_hw, "HW Acquisation", NULL, NULL);
  
  for (sfn=0; sfn < 10; sfn++) {
1598
    print_meas(&softmodem_stats_rxtx_sf,"[eNB][total_phy_proc_rxtx]",NULL, NULL);
1599
    print_meas(&softmodem_stats_rx_sf,"[eNB][total_phy_proc_rx]",NULL,NULL);
1600 1601
  }
}
1602
 
1603 1604 1605 1606 1607 1608 1609
int start_if(PHY_VARS_eNB *eNB) {
  return(eNB->ifdevice.trx_start_func(&eNB->ifdevice));
}

int start_rf(PHY_VARS_eNB *eNB) {
  return(eNB->rfdevice.trx_start_func(&eNB->rfdevice));
}
1610

Raymond Knopp's avatar
Raymond Knopp committed
1611 1612
extern void eNB_fep_rru_if5(PHY_VARS_eNB *eNB);
extern void eNB_fep_full(PHY_VARS_eNB *eNB);
1613
extern void eNB_fep_full_2thread(PHY_VARS_eNB *eNB);
Raymond Knopp's avatar
Raymond Knopp committed
1614
extern void do_prach(PHY_VARS_eNB *eNB);
1615

Raymond Knopp's avatar
Raymond Knopp committed
1616
void init_eNB(eNB_func_t node_function[], eNB_timing_t node_timing[],int nb_inst,eth_params_t *eth_params,int single_thread_flag) {
1617
  
1618
  int CC_id;
1619
  int inst;
1620
  PHY_VARS_eNB *eNB;
Raymond Knopp's avatar
Raymond Knopp committed
1621 1622
  int ret;

1623 1624
  for (inst=0;inst<nb_inst;inst++) {
    for (CC_id=0;CC_id<MAX_NUM_CCs;CC_id++) {
1625 1626 1627 1628
      eNB = PHY_vars_eNB_g[inst][CC_id]; 
      eNB->node_function      = node_function[CC_id];
      eNB->node_timing        = node_timing[CC_id];
      eNB->abstraction_flag   = 0;
Raymond Knopp's avatar
Raymond Knopp committed
1629
      eNB->single_thread_flag = single_thread_flag;
laurent's avatar
laurent committed
1630
#ifndef OCP_FRAMEWORK
1631
      LOG_I(PHY,"Initializing eNB %d CC_id %d : (%s,%s)\n",inst,CC_id,eNB_functions[node_function[CC_id]],eNB_timing[node_timing[CC_id]]);
laurent's avatar
laurent committed
1632
#endif
Raymond Knopp's avatar
Raymond Knopp committed
1633

1634 1635
      switch (node_function[CC_id]) {
      case NGFI_RRU_IF5:
Raymond Knopp's avatar
Raymond Knopp committed
1636 1637
	eNB->do_prach             = NULL;
	eNB->fep                  = eNB_fep_rru_if5;
1638 1639
	eNB->td                   = NULL;
	eNB->te                   = NULL;
Raymond Knopp's avatar
Raymond Knopp committed
1640
	eNB->proc_uespec_rx       = NULL;
1641
	eNB->proc_tx              = NULL;
Raymond Knopp's avatar
Raymond Knopp committed
1642 1643 1644 1645
	eNB->tx_fh                = NULL;
	eNB->rx_fh                = rx_rf;
	eNB->start_rf             = start_rf;
	eNB->start_if             = start_if;
Raymond Knopp's avatar
Raymond Knopp committed
1646
	eNB->fh_asynch            = fh_if5_asynch_DL;
1647
	ret = openair0_device_load(&eNB->rfdevice, &openair0_cfg[CC_id]);
Raymond Knopp's avatar
Raymond Knopp committed
1648 1649 1650 1651 1652 1653
        if (ret<0) {
          printf("Exiting, cannot initialize rf device\n");
          exit(-1);
        }
	eNB->rfdevice.host_type   = RRH_HOST;
	eNB->ifdevice.host_type   = RRH_HOST;
1654
        ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], (eth_params+CC_id));
Raymond Knopp's avatar
Raymond Knopp committed
1655 1656 1657 1658 1659
	printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id);
        if (ret<0) {
          printf("Exiting, cannot initialize transport protocol\n");
          exit(-1);
        }
1660 1661
	break;
      case NGFI_RRU_IF4p5:
Raymond Knopp's avatar
Raymond Knopp committed
1662
	eNB->do_prach             = do_prach;
hutch's avatar
hutch committed
1663
	eNB->fep                  = eNB_fep_full;//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full;
1664 1665
	eNB->td                   = NULL;
	eNB->te                   = NULL;
Raymond Knopp's avatar
Raymond Knopp committed
1666
	eNB->proc_uespec_rx       = NULL;
Raymond Knopp's avatar
Raymond Knopp committed
1667
	eNB->proc_tx              = NULL;//proc_tx_rru_if4p5;
Raymond Knopp's avatar
Raymond Knopp committed
1668 1669
	eNB->tx_fh                = NULL;
	eNB->rx_fh                = rx_rf;
Raymond Knopp's avatar
Raymond Knopp committed
1670
	eNB->fh_asynch            = fh_if4p5_asynch_DL;
Raymond Knopp's avatar
Raymond Knopp committed
1671 1672
	eNB->start_rf             = start_rf;
	eNB->start_if             = start_if;
1673
	ret = openair0_device_load(&eNB->rfdevice, &openair0_cfg[CC_id]);
Raymond Knopp's avatar
Raymond Knopp committed
1674 1675 1676 1677 1678 1679
        if (ret<0) {
          printf("Exiting, cannot initialize rf device\n");
          exit(-1);
        }
	eNB->rfdevice.host_type   = RRH_HOST;
	eNB->ifdevice.host_type   = RRH_HOST;
1680
        ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], (eth_params+CC_id));
Raymond Knopp's avatar
Raymond Knopp committed
1681 1682 1683 1684 1685 1686
	printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id);
        if (ret<0) {
          printf("Exiting, cannot initialize transport protocol\n");
          exit(-1);
        }

1687
	malloc_IF4p5_buffer(eNB);
Raymond Knopp's avatar
Raymond Knopp committed
1688

1689 1690
	break;
      case eNodeB_3GPP:
Raymond Knopp's avatar
Raymond Knopp committed
1691
	eNB->do_prach             = do_prach;
hutch's avatar
hutch committed
1692
	eNB->fep                  = eNB_fep_full;//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full;
1693 1694
	eNB->td                   = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data;
	eNB->te                   = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;
Raymond Knopp's avatar
Raymond Knopp committed
1695 1696 1697 1698 1699 1700
	eNB->proc_uespec_rx       = phy_procedures_eNB_uespec_RX;
	eNB->proc_tx              = proc_tx_full;
	eNB->tx_fh                = NULL;
	eNB->rx_fh                = rx_rf;
	eNB->start_rf             = start_rf;
	eNB->start_if             = NULL;
Raymond Knopp's avatar
Raymond Knopp committed
1701
        eNB->fh_asynch            = NULL;
1702
	ret = openair0_device_load(&eNB->rfdevice, &openair0_cfg[CC_id]);
Raymond Knopp's avatar
Raymond Knopp committed
1703 1704 1705 1706 1707 1708
        if (ret<0) {
          printf("Exiting, cannot initialize rf device\n");
          exit(-1);
        }
	eNB->rfdevice.host_type   = BBU_HOST;
	eNB->ifdevice.host_type   = BBU_HOST;
1709 1710 1711
	break;
      case eNodeB_3GPP_BBU:
	eNB->do_prach       = do_prach;
hutch's avatar
hutch committed
1712 1713 1714
	eNB->fep            = eNB_fep_full;//(single_thread_flag==1) ? eNB_fep_full_2thread : eNB_fep_full;
	eNB->td             = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data;
	eNB->te             = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;
1715 1716
	eNB->proc_uespec_rx = phy_procedures_eNB_uespec_RX;
	eNB->proc_tx        = proc_tx_full;
1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
        if (eNB->node_timing == synch_to_other) {
           eNB->tx_fh          = tx_fh_if5_mobipass;
           eNB->rx_fh          = rx_fh_slave;
           eNB->fh_asynch      = fh_if5_asynch_UL;

        }
        else {
           eNB->tx_fh          = tx_fh_if5;
           eNB->rx_fh          = rx_fh_if5;
           eNB->fh_asynch      = NULL;
        }
Raymond Knopp's avatar
Raymond Knopp committed
1728

1729 1730
	eNB->start_rf       = NULL;
	eNB->start_if       = start_if;
Raymond Knopp's avatar
Raymond Knopp committed
1731 1732 1733
	eNB->rfdevice.host_type   = BBU_HOST;

	eNB->ifdevice.host_type   = BBU_HOST;
Raymond Knopp's avatar
Raymond Knopp committed
1734

1735
        ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], (eth_params+CC_id));
Raymond Knopp's avatar
Raymond Knopp committed
1736 1737 1738 1739 1740
        printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id);
        if (ret<0) {
          printf("Exiting, cannot initialize transport protocol\n");
          exit(-1);
        }
1741 1742
	break;
      case NGFI_RCC_IF4p5:
Raymond Knopp's avatar
Raymond Knopp committed
1743 1744
	eNB->do_prach             = do_prach;
	eNB->fep                  = NULL;
hutch's avatar
hutch committed
1745 1746
	eNB->td                   = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data;
	eNB->te                   = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;
Raymond Knopp's avatar
Raymond Knopp committed
1747 1748 1749 1750 1751 1752 1753
	eNB->proc_uespec_rx       = phy_procedures_eNB_uespec_RX;
	eNB->proc_tx              = proc_tx_high;
	eNB->tx_fh                = tx_fh_if4p5;
	eNB->rx_fh                = rx_fh_if4p5;
	eNB->start_rf             = NULL;
	eNB->start_if             = start_if;
        eNB->fh_asynch            = (eNB->node_timing == synch_to_other) ? fh_if4p5_asynch_UL : NULL;
Raymond Knopp's avatar
Raymond Knopp committed
1754 1755
	eNB->rfdevice.host_type   = BBU_HOST;
	eNB->ifdevice.host_type   = BBU_HOST;
1756
        ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], (eth_params+CC_id));
Raymond Knopp's avatar
Raymond Knopp committed
1757 1758 1759 1760 1761
        printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id);
        if (ret<0) {
          printf("Exiting, cannot initialize transport protocol\n");
          exit(-1);
        }
1762
	malloc_IF4p5_buffer(eNB);
Raymond Knopp's avatar
Raymond Knopp committed
1763

1764 1765 1766
	break;
      case NGFI_RAU_IF4p5:
	eNB->do_prach       = do_prach;
1767
	eNB->fep            = NULL;
1768

hutch's avatar
hutch committed
1769 1770
	eNB->td             = ulsch_decoding_data;//(single_thread_flag==1) ? ulsch_decoding_data_2thread : ulsch_decoding_data;
	eNB->te             = dlsch_encoding;//(single_thread_flag==1) ? dlsch_encoding_2threads : dlsch_encoding;
1771
	eNB->proc_uespec_rx = phy_procedures_eNB_uespec_RX;
1772
	eNB->proc_tx        = proc_tx_high;
1773 1774
	eNB->tx_fh          = tx_fh_if4p5; 
	eNB->rx_fh          = rx_fh_if4p5; 
Raymond Knopp's avatar
Raymond Knopp committed
1775
        eNB->fh_asynch      = (eNB->node_timing == synch_to_other) ? fh_if4p5_asynch_UL : NULL;
1776 1777
	eNB->start_rf       = NULL;
	eNB->start_if       = start_if;
Raymond Knopp's avatar
Raymond Knopp committed
1778 1779 1780

	eNB->rfdevice.host_type   = BBU_HOST;
	eNB->ifdevice.host_type   = BBU_HOST;
1781
        ret = openair0_transport_load(&eNB->ifdevice, &openair0_cfg[CC_id], (eth_params+CC_id));
Raymond Knopp's avatar
Raymond Knopp committed
1782 1783 1784 1785 1786
        printf("openair0_transport_init returns %d for CC_id %d\n",ret,CC_id);
        if (ret<0) {
          printf("Exiting, cannot initialize transport protocol\n");
          exit(-1);
        }
1787
	break;	
Raymond Knopp's avatar
Raymond Knopp committed
1788 1789
	malloc_IF4p5_buffer(eNB);

1790
      }
1791
    }
1792

Florian Kaltenberger's avatar
Florian Kaltenberger committed
1793
    if (setup_eNB_buffers(PHY_vars_eNB_g[inst],&openair0_cfg[0])!=0) {
1794 1795 1796 1797
      printf("Exiting, cannot initialize eNodeB Buffers\n");
      exit(-1);
    }

1798
    init_eNB_proc(inst);
1799
  }
1800

1801 1802 1803
  sleep(1);
  LOG_D(HW,"[lte-softmodem.c] eNB threads created\n");
  
Raymond Knopp's avatar
Raymond Knopp committed
1804

1805 1806 1807
}


1808
void stop_eNB(int nb_inst) {
1809

1810 1811 1812 1813
  for (int inst=0;inst<nb_inst;inst++) {
    printf("Killing eNB %d processing threads\n",inst);
    kill_eNB_proc(inst);
  }
1814
}