lte-enb.c 30.3 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

/*! \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
 */
32

33

34 35
#include "time_utils.h"

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

38 39
#include "rt_wrapper.h"

40
#include "assertions.h"
41

42 43 44 45 46 47 48 49 50 51 52

#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

53
#include "PHY/LTE_TRANSPORT/if4_tools.h"
54
#include "PHY/LTE_TRANSPORT/if5_tools.h"
55

56 57 58 59 60 61 62 63 64 65 66
#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"
67
#include "PHY_INTERFACE/defs.h"
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
#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
94 95
#include "T.h"

96 97 98 99 100 101 102 103 104 105
//#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;

106 107
// Fix per CC openair rf/if device update
// extern openair0_device openair0;
108

109

110 111 112 113 114 115 116 117
#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];

Cedric Roux's avatar
Cedric Roux committed
118
extern int transmission_mode;
119

120 121
extern int oaisim_flag;

122
//pthread_t                       main_eNB_thread;
123 124 125

time_stats_t softmodem_stats_mt; // main thread
time_stats_t softmodem_stats_hw; //  hw acquisition
126
time_stats_t softmodem_stats_rxtx_sf; // total tx time
127
time_stats_t softmodem_stats_rx_sf; // total rx time
128 129 130 131 132 133 134 135 136

/* 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;
137
} sync_phy_proc;
138

139 140
extern double cpuf;

141 142
void exit_fun(const char* s);

143
void init_eNB(int,int);
144
void stop_eNB(int nb_inst);
145

146
void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe);
147 148 149
#ifdef Rel14
void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe);
#endif
150

Raymond Knopp's avatar
Raymond Knopp committed
151 152 153
static inline int rxtx(PHY_VARS_eNB *eNB,eNB_rxtx_proc_t *proc, char *thread_name) {

  start_meas(&softmodem_stats_rxtx_sf);
154

Raymond Knopp's avatar
Raymond Knopp committed
155 156
  // ****************************************
  // Common RX procedures subframe n
157

158
  // if this is IF5 or 3GPP_eNB
159 160 161 162 163 164
  if (eNB->RU_list[0]->function < NGFI_RAU_IF4p5) {
    wakeup_prach_eNB(eNB,NULL,proc->frame_rx,proc->subframe_rx);
#ifdef Rel14
    wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx);
#endif
  }
Raymond Knopp's avatar
Raymond Knopp committed
165
  // UE-specific RX processing for subframe n
166
  phy_procedures_eNB_uespec_RX(eNB, proc, no_relay );
167 168

  pthread_mutex_lock(&eNB->UL_INFO_mutex);
169 170 171 172 173
  eNB->UL_INFO.frame     = proc->frame_rx;
  eNB->UL_INFO.subframe  = proc->subframe_rx;
  eNB->UL_INFO.module_id = eNB->Mod_id;
  eNB->UL_INFO.CC_id     = eNB->CC_id;
  eNB->if_inst->UL_indication(&eNB->UL_INFO);
174
  pthread_mutex_unlock(&eNB->UL_INFO_mutex);
Raymond Knopp's avatar
Raymond Knopp committed
175 176 177 178 179
  // *****************************************
  // 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)
  // *****************************************
180
  //if (wait_CCs(proc)<0) return(-1);
Raymond Knopp's avatar
Raymond Knopp committed
181
  
182 183

  
Raymond Knopp's avatar
Raymond Knopp committed
184 185
  if (oai_exit) return(-1);
  
186
  phy_procedures_eNB_TX(eNB, proc, no_relay, NULL, 1);
Raymond Knopp's avatar
Raymond Knopp committed
187 188 189 190 191 192 193 194
  
  if (release_thread(&proc->mutex_rxtx,&proc->instance_cnt_rxtx,thread_name)<0) return(-1);

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

195

196
/*!
197
 * \brief The RX UE-specific and TX thread of eNB.
198 199 200
 * \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.
 */
201

202 203
static void* eNB_thread_rxtx( void* param ) {

204
  static int eNB_thread_rxtx_status;
205

206
  eNB_rxtx_proc_t *proc = (eNB_rxtx_proc_t*)param;
207
  PHY_VARS_eNB *eNB = RC.eNB[0][proc->CC_id];
208

Raymond Knopp's avatar
Raymond Knopp committed
209 210
  char thread_name[100];

211

212
  // set default return value
213
  eNB_thread_rxtx_status = 0;
214 215


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

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

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

224
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 1 );
225

Raymond Knopp's avatar
Raymond Knopp committed
226
    
227
  
228 229
    if (oai_exit) break;

230 231
    if (eNB->CC_id==0)
      if (rxtx(eNB,proc,thread_name) < 0) break;
232

Raymond Knopp's avatar
Raymond Knopp committed
233
  } // while !oai_exit
234

235
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_eNB_PROC_RXTX0+(proc->subframe_rx&1), 0 );
236

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

239 240
  eNB_thread_rxtx_status = 0;
  return &eNB_thread_rxtx_status;
241 242
}

243

244
#if defined(ENABLE_ITTI) && defined(ENABLE_USE_MME)
245 246 247
/* Wait for eNB application initialization to be complete (eNB registration to MME) */
static void wait_system_ready (char *message, volatile int *start_flag) {
  
248
  static char *indicator[] = {".    ", "..   ", "...  ", ".... ", ".....",
249
			      " ....", "  ...", "   ..", "    .", "     "};
250 251 252 253 254 255 256
  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);
257
  }
258 259
  
  LOG_D(EMU,"\n");
260 261
}
#endif
262

Raymond Knopp's avatar
Raymond Knopp committed
263 264


265

Raymond Knopp's avatar
Raymond Knopp committed
266

267
void eNB_top(PHY_VARS_eNB *eNB, int frame_rx, int subframe_rx, char *string) {
268

269

270 271
  eNB_proc_t *proc           = &eNB->proc;
  eNB_rxtx_proc_t *proc_rxtx = &proc->proc_rxtx[0];
272

273 274


Raymond Knopp's avatar
Raymond Knopp committed
275

276 277
  proc->frame_rx    = frame_rx;
  proc->subframe_rx = subframe_rx;
278
  
279 280
  if (!oai_exit) {

Raymond Knopp's avatar
Raymond Knopp committed
281

282 283
    LOG_D(PHY,"eNB_top in %p (proc %p, CC_id %d), frame %d, subframe %d, instance_cnt_prach %d\n",
	  pthread_self(), proc, eNB->CC_id, proc->frame_rx,proc->subframe_rx,proc->instance_cnt_prach);
284
 
Raymond Knopp's avatar
Raymond Knopp committed
285 286


287
    T(T_ENB_MASTER_TICK, T_INT(0), T_INT(proc->frame_rx), T_INT(proc->subframe_rx));
Raymond Knopp's avatar
Raymond Knopp committed
288

289 290 291 292 293 294
    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>5) ? (1+proc->frame_rx)&1023 : proc->frame_rx;
    proc->frame_tx         = proc_rxtx->frame_tx;
    proc_rxtx->timestamp_tx = proc->timestamp_tx;
Raymond Knopp's avatar
Raymond Knopp committed
295

296
    if (rxtx(eNB,proc_rxtx,string) < 0) LOG_E(PHY,"eNB %d CC_id %d failed during execution\n",eNB->Mod_id,eNB->CC_id);
297 298
    LOG_D(PHY,"eNB_top out %p (proc %p, CC_id %d), frame %d, subframe %d, instance_cnt_prach %d\n",
	  pthread_self(), proc, eNB->CC_id, proc->frame_rx,proc->subframe_rx,proc->instance_cnt_prach);
299
  }
Raymond Knopp's avatar
Raymond Knopp committed
300 301 302 303
  
}


304 305 306 307 308 309 310
int wakeup_rxtx(PHY_VARS_eNB *eNB,RU_t *ru) {

  eNB_proc_t *proc=&eNB->proc;

  eNB_rxtx_proc_t *proc_rxtx=&proc->proc_rxtx[proc->frame_rx&1];

  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
311 312 313 314

  int i;
  struct timespec wait;
  
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
  pthread_mutex_lock(&proc->mutex_RU);
  for (i=0;i<eNB->num_RU;i++) {
    if (ru == eNB->RU_list[i]) {
      if ((proc->RU_mask&(1<<i)) > 0)
	LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n",
	      eNB->Mod_id,proc->frame_rx,proc->subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask);
      proc->RU_mask |= (1<<i);
    }
  }
  if (proc->RU_mask != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
    pthread_mutex_unlock(&proc->mutex_RU);
    return(0);
  }
  else { // all RUs have provided their information so continue on and wakeup eNB processing
    proc->RU_mask = 0;
    pthread_mutex_unlock(&proc->mutex_RU);
  }




336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
  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
363 364
  // we want to generate subframe (n+4), so TS_tx = TX_rx+4*samples_per_tti,
  // and proc->subframe_tx = proc->subframe_rx+4
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
  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);
}

383
void wakeup_prach_eNB(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) {
384 385 386

  eNB_proc_t *proc = &eNB->proc;
  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
387
  int i;
388

389 390 391 392
  if (ru!=NULL) {
    pthread_mutex_lock(&proc->mutex_RU_PRACH);
    for (i=0;i<eNB->num_RU;i++) {
      if (ru == eNB->RU_list[i]) {
393
	LOG_I(PHY,"frame %d, subframe %d: RU %d for eNB %d signals PRACH (mask %x, num_RU %d)\n",frame,subframe,i,eNB->Mod_id,proc->RU_mask_prach,eNB->num_RU);
394 395
	if ((proc->RU_mask_prach&(1<<i)) > 0)
	  LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information (PRACH) from RU %d (num_RU %d, mask %x) has not been served yet!\n",
396
		eNB->Mod_id,frame,subframe,ru->idx,eNB->num_RU,proc->RU_mask_prach);
397 398 399 400 401 402 403 404 405 406 407 408 409
	proc->RU_mask_prach |= (1<<i);
      }
    }
    if (proc->RU_mask_prach != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
      pthread_mutex_unlock(&proc->mutex_RU_PRACH);
      return(0);
    }
    else { // all RUs have provided their information so continue on and wakeup eNB processing
      proc->RU_mask_prach = 0;
      pthread_mutex_unlock(&proc->mutex_RU_PRACH);
    }
  }
    
410
  // check if we have to detect PRACH first
411
  if (is_prach_subframe(fp,frame,subframe)>0) { 
412
    LOG_D(PHY,"Triggering prach processing, frame %d, subframe %d\n",frame,subframe);
413
    if (proc->instance_cnt_prach == 0) {
414
      LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH\n", frame,subframe);
415 416 417 418 419 420 421 422 423 424 425 426
      return;
    }
    
    // wake up thread for PRACH RX
    if (pthread_mutex_lock(&proc->mutex_prach) != 0) {
      LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach);
      exit_fun( "error locking mutex_prach" );
      return;
    }
    
    ++proc->instance_cnt_prach;
    // set timing for prach thread
427 428
    proc->frame_prach = frame;
    proc->subframe_prach = subframe;
429 430 431 432 433 434 435 436 437 438 439 440 441
    
    // the thread can now be woken up
    if (pthread_cond_signal(&proc->cond_prach) != 0) {
      LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH thread %d\n", proc->thread_index);
      exit_fun( "ERROR pthread_cond_signal" );
      return;
    }
    
    pthread_mutex_unlock( &proc->mutex_prach );
  }

}

442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
#ifdef Rel14
void wakeup_prach_eNB_br(PHY_VARS_eNB *eNB,RU_t *ru,int frame,int subframe) {

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

  if (ru!=NULL) {
    pthread_mutex_lock(&proc->mutex_RU_PRACH_br);
    for (i=0;i<eNB->num_RU;i++) {
      if (ru == eNB->RU_list[i]) {
	LOG_I(PHY,"frame %d, subframe %d: RU %d for eNB %d signals PRACH BR (mask %x, num_RU %d)\n",frame,subframe,i,eNB->Mod_id,proc->RU_mask_prach_br,eNB->num_RU);
	if ((proc->RU_mask_prach_br&(1<<i)) > 0)
	  LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information (PRACH BR) from RU %d (num_RU %d, mask %x) has not been served yet!\n",
		eNB->Mod_id,frame,subframe,ru->idx,eNB->num_RU,proc->RU_mask_prach_br);
	proc->RU_mask_prach_br |= (1<<i);
      }
    }
    if (proc->RU_mask_prach_br != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
      pthread_mutex_unlock(&proc->mutex_RU_PRACH_br);
      return(0);
    }
    else { // all RUs have provided their information so continue on and wakeup eNB processing
      proc->RU_mask_prach_br = 0;
      pthread_mutex_unlock(&proc->mutex_RU_PRACH_br);
    }
  }
    
  // check if we have to detect PRACH first
  if (is_prach_subframe(fp,frame,subframe)>0) { 
    LOG_D(PHY,"Triggering prach br processing, frame %d, subframe %d\n",frame,subframe);
    if (proc->instance_cnt_prach_br == 0) {
      LOG_W(PHY,"[eNB] Frame %d Subframe %d, dropping PRACH BR\n", frame,subframe);
      return;
    }
    
    // wake up thread for PRACH RX
    if (pthread_mutex_lock(&proc->mutex_prach_br) != 0) {
      LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB PRACH thread %d (IC %d)\n", proc->thread_index, proc->instance_cnt_prach_br);
      exit_fun( "error locking mutex_prach" );
      return;
    }
    
    ++proc->instance_cnt_prach_br;
    // set timing for prach thread
    proc->frame_prach_br = frame;
    proc->subframe_prach_br = subframe;
    
    // the thread can now be woken up
    if (pthread_cond_signal(&proc->cond_prach_br) != 0) {
      LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB PRACH BR thread %d\n", proc->thread_index);
      exit_fun( "ERROR pthread_cond_signal" );
      return;
    }
    
    pthread_mutex_unlock( &proc->mutex_prach_br );
  }

}
#endif

503 504 505 506 507
/*!
 * \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.
 */
508
static void* eNB_thread_prach( void* param ) {
509 510
  static int eNB_thread_prach_status;

511 512 513

  PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param;
  eNB_proc_t *proc = &eNB->proc;
Raymond Knopp's avatar
Raymond Knopp committed
514

515 516 517
  // set default return value
  eNB_thread_prach_status = 0;

518
  thread_top_init("eNB_thread_prach",1,500000L,1000000L,20000000L);
519

520 521 522
  while (!oai_exit) {
    
    if (oai_exit) break;
523
    
524

Raymond Knopp's avatar
Raymond Knopp committed
525
    if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break;
526 527

    LOG_D(PHY,"Running eNB prach procedures\n");
528 529 530 531 532
    prach_procedures(eNB
#ifdef Rel14
		     ,0
#endif
		     );
533
    
Raymond Knopp's avatar
Raymond Knopp committed
534
    if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"eNB_prach_thread") < 0) break;
535
  }
536

537
  LOG_I(PHY, "Exiting eNB thread PRACH\n");
Raymond Knopp's avatar
Raymond Knopp committed
538

539 540
  eNB_thread_prach_status = 0;
  return &eNB_thread_prach_status;
541 542
}

543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
#ifdef Rel14
/*!
 * \brief The prach receive thread of eNB for BL/CE UEs.
 * \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.
 */
static void* eNB_thread_prach_br( void* param ) {
  static int eNB_thread_prach_status;


  PHY_VARS_eNB *eNB= (PHY_VARS_eNB *)param;
  eNB_proc_t *proc = &eNB->proc;

  // set default return value
  eNB_thread_prach_status = 0;

  thread_top_init("eNB_thread_prach_br",1,500000L,1000000L,20000000L);

  while (!oai_exit) {
    
    if (oai_exit) break;
    

    if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break;

    LOG_D(PHY,"Running eNB prach procedures for BL/CE UEs\n");
    prach_procedures(eNB,1);
    
    if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"eNB_prach_thread_br") < 0) break;
  }

  LOG_I(PHY, "Exiting eNB thread PRACH BR\n");

  eNB_thread_prach_status = 0;
  return &eNB_thread_prach_status;
}

#endif
Raymond Knopp's avatar
Raymond Knopp committed
581

Raymond Knopp's avatar
Raymond Knopp committed
582

583
extern void init_fep_thread(PHY_VARS_eNB *, pthread_attr_t *);
584 585
extern void init_td_thread(PHY_VARS_eNB *, pthread_attr_t *);
extern void init_te_thread(PHY_VARS_eNB *, pthread_attr_t *);
586

587
void init_eNB_proc(int inst) {
588
  
Rohit Gupta's avatar
Rohit Gupta committed
589
  int i=0;
590
  int CC_id;
591 592
  PHY_VARS_eNB *eNB;
  eNB_proc_t *proc;
593
  eNB_rxtx_proc_t *proc_rxtx;
594
  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=NULL,*attr_synch=NULL;
595 596 597
#ifdef Rel14
  pthread_attr_t *attr_prach_br=NULL;
#endif
Raymond Knopp's avatar
Raymond Knopp committed
598

599
  for (CC_id=0; CC_id<RC.nb_CC[inst]; CC_id++) {
600
    eNB = RC.eNB[inst][CC_id];
laurent's avatar
laurent committed
601
#ifndef OCP_FRAMEWORK
602
    LOG_I(PHY,"Initializing eNB processes %d CC_id %d \n",inst,CC_id);
laurent's avatar
laurent committed
603
#endif
604
    proc = &eNB->proc;
Raymond Knopp's avatar
Raymond Knopp committed
605

606
    proc_rxtx                      = proc->proc_rxtx;
607 608
    proc_rxtx[0].instance_cnt_rxtx = -1;
    proc_rxtx[1].instance_cnt_rxtx = -1;
609
    proc->instance_cnt_prach       = -1;
610
    proc->instance_cnt_asynch_rxtx = -1;
611
    proc->CC_id                    = CC_id;    
612

Raymond Knopp's avatar
Raymond Knopp committed
613 614
    proc->first_rx=1;
    proc->first_tx=1;
615 616
    proc->RU_mask=0;
    proc->RU_mask_prach=0;
Raymond Knopp's avatar
Raymond Knopp committed
617

618
    pthread_mutex_init( &eNB->UL_INFO_mutex, NULL);
619 620 621 622
    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
623 624 625

    pthread_mutex_init( &proc->mutex_prach, NULL);
    pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL);
626 627
    pthread_mutex_init( &proc->mutex_RU,NULL);
    pthread_mutex_init( &proc->mutex_RU_PRACH,NULL);
Raymond Knopp's avatar
Raymond Knopp committed
628

629
    pthread_cond_init( &proc->cond_prach, NULL);
630
    pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
631 632 633 634

    pthread_attr_init( &proc->attr_prach);
    pthread_attr_init( &proc->attr_asynch_rxtx);
    pthread_attr_init( &proc->attr_single);
635 636
    pthread_attr_init( &proc->attr_td);
    pthread_attr_init( &proc->attr_te);
637 638
    pthread_attr_init( &proc_rxtx[0].attr_rxtx);
    pthread_attr_init( &proc_rxtx[1].attr_rxtx);
639 640 641 642 643 644 645 646
#ifdef Rel14
    proc->instance_cnt_prach_br    = -1;
    proc->RU_mask_prach_br=0;
    pthread_mutex_init( &proc->mutex_prach_br, NULL);
    pthread_mutex_init( &proc->mutex_RU_PRACH_br,NULL);
    pthread_cond_init( &proc->cond_prach_br, NULL);
    pthread_attr_init( &proc->attr_prach_br);
#endif
647
#ifndef DEADLINE_SCHEDULER
Raymond Knopp's avatar
Raymond Knopp committed
648 649 650
    attr0       = &proc_rxtx[0].attr_rxtx;
    attr1       = &proc_rxtx[1].attr_rxtx;
    attr_prach  = &proc->attr_prach;
651 652 653 654
#ifdef Rel14
    attr_prach_br  = &proc->attr_prach_br;
#endif

Raymond Knopp's avatar
Raymond Knopp committed
655 656
    attr_asynch = &proc->attr_asynch_rxtx;
    attr_single = &proc->attr_single;
657 658
    attr_td     = &proc->attr_td;
    attr_te     = &proc->attr_te; 
Raymond Knopp's avatar
Raymond Knopp committed
659 660
#endif

661 662 663 664
    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] );
    }
665
    pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach, eNB );
666 667 668
#ifdef Rel14
    pthread_create( &proc->pthread_prach_br, attr_prach_br, eNB_thread_prach_br, eNB );
#endif
669
    char name[16];
670 671 672 673 674 675
    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 );
    }
676 677 678

    AssertFatal(proc->instance_cnt_prach == -1,"instance_cnt_prach = %d\n",proc->instance_cnt_prach);

679
    
680
  }
681

682
  //for multiple CCs: setup master and slaves
683 684 685
  /* 
     for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
     eNB = PHY_vars_eNB_g[inst][CC_id];
686

687 688 689
     if (eNB->node_timing == synch_to_ext_device) { //master
     eNB->proc.num_slaves = MAX_NUM_CCs-1;
     eNB->proc.slave_proc = (eNB_proc_t**)malloc(eNB->proc.num_slaves*sizeof(eNB_proc_t*));
690

691 692 693 694 695 696 697
     for (i=0; i< eNB->proc.num_slaves; i++) {
     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);
     }
     }
     }
  */
698

699 700 701 702
  /* 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;
703 704
}

705

706

707 708 709
/*!
 * \brief Terminate eNB TX and RX threads.
 */
710
void kill_eNB_proc(int inst) {
711

712
  int *status;
713 714
  PHY_VARS_eNB *eNB;
  eNB_proc_t *proc;
715
  eNB_rxtx_proc_t *proc_rxtx;
716
  for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
717
    eNB=RC.eNB[inst][CC_id];
718 719
    
    proc = &eNB->proc;
720
    proc_rxtx = &proc->proc_rxtx[0];
721
    
722 723

    LOG_I(PHY, "Killing TX CC_id %d inst %d\n", CC_id, inst );
724
    
725 726
    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
727
    proc->instance_cnt_prach = 0;
728
    pthread_cond_signal( &proc_rxtx[0].cond_rxtx );    
Raymond Knopp's avatar
Raymond Knopp committed
729 730
    pthread_cond_signal( &proc_rxtx[1].cond_rxtx );
    pthread_cond_signal( &proc->cond_prach );
731

732
    pthread_cond_broadcast(&sync_phy_proc.cond_phy_proc_tx);
733
    pthread_join( proc->pthread_prach, (void**)&status );    
734

735
    pthread_mutex_destroy( &proc->mutex_prach );
736 737 738 739 740 741 742
    pthread_cond_destroy( &proc->cond_prach );
#ifdef Rel14
    pthread_cond_signal( &proc->cond_prach_br );
    pthread_join( proc->pthread_prach_br, (void**)&status );    
    pthread_mutex_destroy( &proc->mutex_prach_br );
    pthread_cond_destroy( &proc->cond_prach_br );
#endif         
743
    pthread_mutex_destroy(&eNB->UL_INFO_mutex);
744
    int i;
Raymond Knopp's avatar
Raymond Knopp committed
745
    for (i=0;i<2;i++) {
746 747 748 749
      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 );
    }
750
  }
751 752
}

753

754 755 756


void reset_opp_meas(void) {
757

758 759 760 761 762
  int sfn;
  reset_meas(&softmodem_stats_mt);
  reset_meas(&softmodem_stats_hw);
  
  for (sfn=0; sfn < 10; sfn++) {
763
    reset_meas(&softmodem_stats_rxtx_sf);
764
    reset_meas(&softmodem_stats_rx_sf);
765 766 767
  }
}

768

769 770 771 772 773 774 775
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++) {
776
    print_meas(&softmodem_stats_rxtx_sf,"[eNB][total_phy_proc_rxtx]",NULL, NULL);
777
    print_meas(&softmodem_stats_rx_sf,"[eNB][total_phy_proc_rx]",NULL,NULL);
778 779
  }
}
780

781
void init_transport(PHY_VARS_eNB *eNB) {
782

783 784 785
  int i;
  int j;
  LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
786

787 788 789 790 791 792
  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
    LOG_I(PHY,"Allocating Transport Channel Buffers for DLSCH, UE %d\n",i);
    for (j=0; j<2; j++) {
      eNB->dlsch[i][j] = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL,0,fp);
      if (!eNB->dlsch[i][j]) {
	LOG_E(PHY,"Can't get eNB dlsch structures for UE %d \n", i);
793
	exit(-1);
794 795 796
      } else {
	LOG_D(PHY,"dlsch[%d][%d] => %p\n",i,j,eNB->dlsch[i][j]);
	eNB->dlsch[i][j]->rnti=0;
797 798
      }
    }
799 800 801 802 803 804
    
    LOG_I(PHY,"Allocating Transport Channel Buffer for ULSCH, UE %d\n",i);
    eNB->ulsch[1+i] = new_eNB_ulsch(MAX_TURBO_ITERATIONS,fp->N_RB_UL, 0);
    
    if (!eNB->ulsch[1+i]) {
      LOG_E(PHY,"Can't get eNB ulsch structures\n");
805 806
      exit(-1);
    }
807 808 809 810
    
    // this is the transmission mode for the signalling channels
    // this will be overwritten with the real transmission mode by the RRC once the UE is connected
    eNB->transmission_mode[i] = fp->nb_antenna_ports_eNB==1 ? 1 : 2;
811
  }
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
  // ULSCH for RA
  eNB->ulsch[0] = new_eNB_ulsch(MAX_TURBO_ITERATIONS, fp->N_RB_UL, 0);
  
  if (!eNB->ulsch[0]) {
    LOG_E(PHY,"Can't get eNB ulsch structures\n");
    exit(-1);
  }
  eNB->dlsch_SI  = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
  LOG_D(PHY,"eNB %d.%d : SI %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_SI);
  eNB->dlsch_ra  = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
  LOG_D(PHY,"eNB %d.%d : RA %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_ra);
  eNB->dlsch_MCH = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
  LOG_D(PHY,"eNB %d.%d : MCH %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_MCH);
  
  
  eNB->rx_total_gain_dB=130;
828
  
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
  for(i=0; i<NUMBER_OF_UE_MAX; i++)
    eNB->mu_mimo_mode[i].dl_pow_off = 2;
  
  eNB->check_for_total_transmissions = 0;
  
  eNB->check_for_MUMIMO_transmissions = 0;
  
  eNB->FULL_MUMIMO_transmissions = 0;
  
  eNB->check_for_SUMIMO_transmissions = 0;
  
  fp->pucch_config_common.deltaPUCCH_Shift = 1;
    
} 
void init_eNB_afterRU() {
844

845 846
  int inst,CC_id,ru_id,i,aa;
  PHY_VARS_eNB *eNB;
847 848


849 850 851 852 853 854 855
  for (inst=0;inst<RC.nb_inst;inst++) {
    for (CC_id=0;CC_id<RC.nb_CC[inst];CC_id++) {
      eNB                                  =  RC.eNB[inst][CC_id];
      phy_init_lte_eNB(eNB,0,0);
      // map antennas and PRACH signals to eNB RX
      AssertFatal(eNB->num_RU>0,"Number of RU attached to eNB %d is zero\n",eNB->Mod_id);
      LOG_I(PHY,"Mapping RX ports from %d RUs to eNB %d\n",eNB->num_RU,eNB->Mod_id);
856
      eNB->frame_parms.nb_antennas_rx       = 0;
Raymond Knopp's avatar
Raymond Knopp committed
857 858
      eNB->prach_vars.rxsigF = (int16_t*)malloc16(64*sizeof(int16_t*));

859 860
      for (ru_id=0,aa=0;ru_id<eNB->num_RU;ru_id++) {
	eNB->frame_parms.nb_antennas_rx    += eNB->RU_list[ru_id]->nb_rx;
861 862 863 864 865 866 867 868 869

	AssertFatal(eNB->RU_list[ru_id]->common.rxdataF!=NULL,
		    "RU %d : common.rxdataF is NULL\n",
		    eNB->RU_list[ru_id]->idx);

	AssertFatal(eNB->RU_list[ru_id]->prach_rxsigF!=NULL,
		    "RU %d : prach_rxsigF is NULL\n",
		    eNB->RU_list[ru_id]->idx);

870 871 872 873 874 875
	for (i=0;i<eNB->RU_list[ru_id]->nb_rx;aa++,i++) { 
	  LOG_I(PHY,"Attaching RU %d antenna %d to eNB antenna %d\n",eNB->RU_list[ru_id]->idx,i,aa);
	  eNB->prach_vars.rxsigF[aa]       =  eNB->RU_list[ru_id]->prach_rxsigF[i];
	  eNB->common_vars.rxdataF[aa]     =  eNB->RU_list[ru_id]->common.rxdataF[i];
	}
      }
876 877 878
      AssertFatal(eNB->frame_parms.nb_antennas_rx >0,
		  "inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx);
      LOG_I(PHY,"inst %d, CC_id %d : nb_antennas_rx %d\n",inst,CC_id,eNB->frame_parms.nb_antennas_rx);
879 880 881 882 883 884 885 886 887 888 889 890

      AssertFatal(eNB->frame_parms.nb_antennas_rx <= sizeof(eNB->prach_vars.prach_ifft) / sizeof(eNB->prach_vars.prach_ifft[0]),
		  "nb_antennas_rx too large");
      for (i=0; i<eNB->frame_parms.nb_antennas_rx; i++) {
	eNB->prach_vars.prach_ifft[i] = (int16_t*)malloc16_clear(1024*2*sizeof(int16_t));
	LOG_D(PHY,"[INIT] prach_vars->prach_ifft[%d] = %p\n",i,eNB->prach_vars.prach_ifft[i]);
      }
      init_transport(eNB);
      init_precoding_weights(RC.eNB[inst][CC_id]);
    }
    init_eNB_proc(inst);
  }
891

892
  for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
893 894

    AssertFatal(RC.ru[ru_id]!=NULL,"ru_id %d is null\n",ru_id);
895
    
896 897 898 899
    RC.ru[ru_id]->wakeup_rxtx         = wakeup_rxtx;
    RC.ru[ru_id]->wakeup_prach_eNB    = wakeup_prach_eNB;
    RC.ru[ru_id]->wakeup_prach_eNB_br = wakeup_prach_eNB_br;
    RC.ru[ru_id]->eNB_top             = eNB_top;
900 901
  }
}
902

903
void init_eNB(int single_thread_flag,int wait_for_sync) {
904
  
905
  int CC_id;
906
  int inst;
907
  PHY_VARS_eNB *eNB;
Raymond Knopp's avatar
Raymond Knopp committed
908

909 910
  if (RC.eNB == NULL) RC.eNB = (PHY_VARS_eNB***) malloc(RC.nb_L1_inst*sizeof(PHY_VARS_eNB **));
  for (inst=0;inst<RC.nb_L1_inst;inst++) {
911
    if (RC.eNB[inst] == NULL) RC.eNB[inst] = (PHY_VARS_eNB**) malloc(RC.nb_CC[inst]*sizeof(PHY_VARS_eNB *));
912
    for (CC_id=0;CC_id<RC.nb_L1_CC[inst];CC_id++) {
913 914
      if (RC.eNB[inst][CC_id] == NULL) RC.eNB[inst][CC_id] = (PHY_VARS_eNB*) malloc(sizeof(PHY_VARS_eNB));
      eNB                     = RC.eNB[inst][CC_id]; 
915
      eNB->abstraction_flag   = 0;
Raymond Knopp's avatar
Raymond Knopp committed
916
      eNB->single_thread_flag = single_thread_flag;
917

918

laurent's avatar
laurent committed
919
#ifndef OCP_FRAMEWORK
920
      LOG_I(PHY,"Initializing eNB %d CC_id %d\n",inst,CC_id);
laurent's avatar
laurent committed
921
#endif
Raymond Knopp's avatar
Raymond Knopp committed
922 923


924 925
      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;
926

927
      
928
      LOG_I(PHY,"Registering with MAC interface module\n");
929 930 931 932 933 934 935 936
      AssertFatal((eNB->if_inst         = IF_Module_init(inst))!=NULL,"Cannot register interface");
      eNB->if_inst->schedule_response   = schedule_response;
      eNB->if_inst->PHY_config_req      = phy_config_request;
      memset((void*)&eNB->UL_INFO,0,sizeof(eNB->UL_INFO));
      memset((void*)&eNB->Sched_INFO,0,sizeof(eNB->Sched_INFO));
      LOG_I(PHY,"Setting indication lists\n");
      eNB->UL_INFO.rx_ind.rx_pdu_list   = eNB->rx_pdu_list;
      eNB->UL_INFO.crc_ind.crc_pdu_list = eNB->crc_pdu_list;
937 938
    }

939
  }
940

941

942
  LOG_I(PHY,"[lte-softmodem.c] eNB structure allocated\n");
943
  
944 945


946 947 948
}


949
void stop_eNB(int nb_inst) {
950

951
  for (int inst=0;inst<nb_inst;inst++) {
952
    LOG_I(PHY,"Killing eNB %d processing threads\n",inst);
953 954
    kill_eNB_proc(inst);
  }
955
}