lte-ru.c 110 KB
Newer Older
Raymond Knopp's avatar
Raymond Knopp committed
1 2 3
/*******************************************************************************
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom
4
 
Raymond Knopp's avatar
Raymond Knopp committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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
    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
    see <http://www.gnu.org/licenses/>.

   Contact Information
   OpenAirInterface Admin: openair_admin@eurecom.fr
   OpenAirInterface Tech : openair_tech@eurecom.fr
   OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr

   Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE

*******************************************************************************/

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

63
#include "PHY/defs_common.h"
Raymond Knopp's avatar
Raymond Knopp committed
64 65 66 67
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all


#include "../../ARCH/COMMON/common_lib.h"
68
#include "../../ARCH/ETHERNET/USERSPACE/LIB/ethernet_lib.h"
Raymond Knopp's avatar
Raymond Knopp committed
69 70 71 72

#include "PHY/LTE_TRANSPORT/if4_tools.h"
#include "PHY/LTE_TRANSPORT/if5_tools.h"

73 74
#include "PHY/phy_extern.h"
#include "LAYER2/MAC/mac_extern.h"
75 76 77 78
#include "PHY/LTE_TRANSPORT/transport_proto.h"
#include "SCHED/sched_eNB.h"
#include "PHY/LTE_ESTIMATION/lte_estimation.h"
#include "PHY/INIT/phy_init.h"
Raymond Knopp's avatar
Raymond Knopp committed
79

80 81 82 83 84
#include "LAYER2/MAC/mac.h"
#include "LAYER2/MAC/mac_extern.h"
#include "LAYER2/MAC/mac_proto.h"
#include "RRC/LTE/rrc_extern.h"
#include "PHY_INTERFACE/phy_interface.h"
Raymond Knopp's avatar
Raymond Knopp committed
85

86
#include "common/utils/LOG/log.h"
Raymond Knopp's avatar
Raymond Knopp committed
87 88 89
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/OTG/otg_externs.h"
#include "UTIL/MATH/oml.h"
90
#include "common/utils/LOG/vcd_signal_dumper.h"
Raymond Knopp's avatar
Raymond Knopp committed
91 92
#include "UTIL/OPT/opt.h"
#include "enb_config.h"
93
#include "targets/RT/USER/lte-softmodem.h" 
Raymond Knopp's avatar
Raymond Knopp committed
94 95
//#include "PHY/TOOLS/time_meas.h"

Cedric Roux's avatar
Cedric Roux committed
96 97 98 99
/* these variables have to be defined before including ENB_APP/enb_paramdef.h */
static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};

100 101 102
#include "ENB_APP/enb_paramdef.h"
#include "common/config/config_userapi.h"

Raymond Knopp's avatar
Raymond Knopp committed
103 104 105 106
#ifndef OPENAIR2
#include "UTIL/OTG/otg_extern.h"
#endif

107 108 109 110
#include "s1ap_eNB.h"
#include "SIMULATION/ETH_TRANSPORT/proto.h"


Raymond Knopp's avatar
Raymond Knopp committed
111 112 113

#include "T.h"

Wang Tsu-Han's avatar
Wang Tsu-Han committed
114
#include "pdcp.h"
Raymond Knopp's avatar
Raymond Knopp committed
115 116

extern volatile int                    oai_exit;
117
extern int emulate_rf;
118
extern int numerology;
119
extern clock_source_t clock_source;
120
extern uint8_t dlsch_ue_select_tbl_in_use;
121
extern uint8_t nfapi_mode;
Raymond Knopp's avatar
Raymond Knopp committed
122

123 124
extern PARALLEL_CONF_t get_thread_parallel_conf(void);
extern WORKER_CONF_t   get_thread_worker_conf(void);
125
extern void  phy_init_RU(RU_t*);
126
extern void  phy_free_RU(RU_t*);
127

128

Robert Schmidt's avatar
Robert Schmidt committed
129
void stop_RU(int nb_ru);
130
void do_ru_sync(RU_t *ru);
Raymond Knopp's avatar
Raymond Knopp committed
131

132 133 134 135 136 137 138
void configure_ru(int idx,
		  void *arg);

void configure_rru(int idx,
		   void *arg);

int attach_rru(RU_t *ru);
Raymond Knopp's avatar
Raymond Knopp committed
139

140
int connect_rau(RU_t *ru);
Raymond Knopp's avatar
Raymond Knopp committed
141

142
extern uint16_t sf_ahead;
143

144 145 146 147 148
#if defined(PRE_SCD_THREAD)
void init_ru_vnf(void);
#endif


149 150 151
/*************************************************************/
/* Functions to attach and configure RRU                     */

Raymond Knopp's avatar
Raymond Knopp committed
152
extern void wait_eNBs(void);
153

154 155 156 157 158 159
int attach_rru(RU_t *ru) {
  
  ssize_t      msg_len,len;
  RRU_CONFIG_msg_t rru_config_msg;
  int received_capabilities=0;

Raymond Knopp's avatar
Raymond Knopp committed
160
  wait_eNBs();
161 162 163
  // Wait for capabilities
  while (received_capabilities==0) {
    
164
    memset((void*)&rru_config_msg,0,sizeof(rru_config_msg));
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    rru_config_msg.type = RAU_tick; 
    rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE;
    LOG_I(PHY,"Sending RAU tick to RRU %d\n",ru->idx);
    AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
		"RU %d cannot access remote radio\n",ru->idx);

    msg_len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);

    // wait for answer with timeout  
    if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
					     &rru_config_msg,
					     msg_len))<0) {
      LOG_I(PHY,"Waiting for RRU %d\n",ru->idx);     
    }
    else if (rru_config_msg.type == RRU_capabilities) {
      AssertFatal(rru_config_msg.len==msg_len,"Received capabilities with incorrect length (%d!=%d)\n",(int)rru_config_msg.len,(int)msg_len);
      LOG_I(PHY,"Received capabilities from RRU %d (len %d/%d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",ru->idx,
	    (int)rru_config_msg.len,(int)msg_len,
	     ((RRU_capabilities_t*)&rru_config_msg.msg[0])->num_bands,
	     ((RRU_capabilities_t*)&rru_config_msg.msg[0])->max_pdschReferenceSignalPower[0],
	     ((RRU_capabilities_t*)&rru_config_msg.msg[0])->max_rxgain[0],
	     ((RRU_capabilities_t*)&rru_config_msg.msg[0])->nb_tx[0],
	     ((RRU_capabilities_t*)&rru_config_msg.msg[0])->nb_rx[0]);
      received_capabilities=1;
    }
    else {
      LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx); 
    }
  }
  configure_ru(ru->idx,
	       (RRU_capabilities_t *)&rru_config_msg.msg[0]);
		    
  rru_config_msg.type = RRU_config;
  rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t);
  LOG_I(PHY,"Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",ru->idx,
	((RRU_config_t *)&rru_config_msg.msg[0])->num_bands,
	((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0],
	((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);

212

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 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 264 265 266 267 268 269 270
  AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
	      "RU %d failed send configuration to remote radio\n",ru->idx);

  return 0;
}

int connect_rau(RU_t *ru) {

  RRU_CONFIG_msg_t   rru_config_msg;
  ssize_t	     msg_len;
  int                tick_received          = 0;
  int                configuration_received = 0;
  RRU_capabilities_t *cap;
  int                i;
  int                len;

  // wait for RAU_tick
  while (tick_received == 0) {

    msg_len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE;

    if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
					     &rru_config_msg,
					     msg_len))<0) {
      LOG_I(PHY,"Waiting for RAU\n");     
    }
    else {
      if (rru_config_msg.type == RAU_tick) {
	LOG_I(PHY,"Tick received from RAU\n");
	tick_received = 1;
      }
      else LOG_E(PHY,"Received erroneous message (%d)from RAU, expected RAU_tick\n",rru_config_msg.type);
    }
  }

  // send capabilities

  rru_config_msg.type = RRU_capabilities; 
  rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);
  cap                 = (RRU_capabilities_t*)&rru_config_msg.msg[0];
  LOG_I(PHY,"Sending Capabilities (len %d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",
	(int)rru_config_msg.len,ru->num_bands,ru->max_pdschReferenceSignalPower,ru->max_rxgain,ru->nb_tx,ru->nb_rx);
  switch (ru->function) {
  case NGFI_RRU_IF4p5:
    cap->FH_fmt                                   = OAI_IF4p5_only;
    break;
  case NGFI_RRU_IF5:
    cap->FH_fmt                                   = OAI_IF5_only;
    break;
  case MBP_RRU_IF5:
    cap->FH_fmt                                   = MBP_IF5;
    break;
  default:
    AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function);
    break;
  }
  cap->num_bands                                  = ru->num_bands;
  for (i=0;i<ru->num_bands;i++) {
271 272
	LOG_I(PHY,"Band %d: nb_rx %d nb_tx %d pdschReferenceSignalPower %d rxgain %d\n",
	ru->band[i],ru->nb_rx,ru->nb_tx,ru->max_pdschReferenceSignalPower,ru->max_rxgain);
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    cap->band_list[i]                             = ru->band[i];
    cap->nb_rx[i]                                 = ru->nb_rx;
    cap->nb_tx[i]                                 = ru->nb_tx;
    cap->max_pdschReferenceSignalPower[i]         = ru->max_pdschReferenceSignalPower;
    cap->max_rxgain[i]                            = ru->max_rxgain;
  }
  AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
	      "RU %d failed send capabilities to RAU\n",ru->idx);

  // wait for configuration
  rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t);
  while (configuration_received == 0) {

    if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
					     &rru_config_msg,
					     rru_config_msg.len))<0) {
      LOG_I(PHY,"Waiting for configuration from RAU\n");     
    }    
    else {
      LOG_I(PHY,"Configuration received from RAU  (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",
	    ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands,
	    ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0],
	    ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]);
      
      configure_rru(ru->idx,
		    (void*)&rru_config_msg.msg[0]);
      configuration_received = 1;
    }
  }
  return 0;
}
Raymond Knopp's avatar
Raymond Knopp committed
312 313 314 315 316
/*************************************************************/
/* Southbound Fronthaul functions, RCC/RAU                   */

// southbound IF5 fronthaul for 16-bit OAI format
static inline void fh_if5_south_out(RU_t *ru) {
317 318
  if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
  send_IF5(ru, ru->proc.timestamp_tx, ru->proc.subframe_tx, &ru->seqno, IF5_RRH_GW_DL);
Raymond Knopp's avatar
Raymond Knopp committed
319 320 321 322
}

// southbound IF5 fronthaul for Mobipass packet format
static inline void fh_if5_mobipass_south_out(RU_t *ru) {
323 324
  if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
  send_IF5(ru, ru->proc.timestamp_tx, ru->proc.subframe_tx, &ru->seqno, IF5_MOBIPASS); 
Raymond Knopp's avatar
Raymond Knopp committed
325 326 327 328
}

// southbound IF4p5 fronthaul
static inline void fh_if4p5_south_out(RU_t *ru) {
329
  if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
330
  LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx);
331 332
  if (subframe_select(&ru->frame_parms,ru->proc.subframe_tx)!=SF_UL) 
    send_IF4p5(ru,ru->proc.frame_tx, ru->proc.subframe_tx, IF4p5_PDLFFT);
Raymond Knopp's avatar
Raymond Knopp committed
333 334 335 336 337 338 339 340 341
}

/*************************************************************/
/* Input Fronthaul from south RCC/RAU                        */

// Synchronous if5 from south 
void fh_if5_south_in(RU_t *ru,int *frame, int *subframe) {

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
342
  RU_proc_t *proc = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
343

344
  recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); 
Raymond Knopp's avatar
Raymond Knopp committed
345 346 347 348 349 350

  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) {
    if (proc->subframe_rx != *subframe){
351
      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);
Raymond Knopp's avatar
Raymond Knopp committed
352 353 354 355
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
356
      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);
Raymond Knopp's avatar
Raymond Knopp committed
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
      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 );

}

// Synchronous if4p5 from south 
void fh_if4p5_south_in(RU_t *ru,int *frame,int *subframe) {

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
373 374
  RU_proc_t *proc = &ru->proc;
  int f,sf;
Raymond Knopp's avatar
Raymond Knopp committed
375 376 377 378


  uint16_t packet_type;
  uint32_t symbol_number=0;
379 380 381 382 383 384
  uint32_t symbol_mask_full;

  if ((fp->frame_type == TDD) && (subframe_select(fp,*subframe)==SF_S))  
    symbol_mask_full = (1<<fp->ul_symbols_in_S_subframe)-1;   
  else     
    symbol_mask_full = (1<<fp->symbols_per_tti)-1; 
Raymond Knopp's avatar
Raymond Knopp committed
385

386
  AssertFatal(proc->symbol_mask[*subframe]==0,"rx_fh_if4p5: proc->symbol_mask[%d] = %x\n",*subframe,proc->symbol_mask[*subframe]);
Raymond Knopp's avatar
Raymond Knopp committed
387
  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
388
    recv_IF4p5(ru, &f, &sf, &packet_type, &symbol_number);
Raymond Knopp's avatar
Raymond Knopp committed
389

390 391 392 393
    if (packet_type == IF4p5_PULFFT) proc->symbol_mask[sf] = proc->symbol_mask[sf] | (1<<symbol_number);
    else if (packet_type == IF4p5_PULTICK) {           
      if ((proc->first_rx==0) && (f!=*frame)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received frame %d != expected %d\n",f,*frame);       
      if ((proc->first_rx==0) && (sf!=*subframe)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n",sf,*subframe,proc->first_rx);       
394
      break;     
395
      
Raymond Knopp's avatar
Raymond Knopp committed
396
    } else if (packet_type == IF4p5_PRACH) {
397
      // nothing in RU for RAU
Raymond Knopp's avatar
Raymond Knopp committed
398
    }
399
    LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*subframe,proc->symbol_mask[*subframe]);
400
  } while(proc->symbol_mask[*subframe] != symbol_mask_full);    
Raymond Knopp's avatar
Raymond Knopp committed
401 402

  //caculate timestamp_rx, timestamp_tx based on frame and subframe
403 404
  proc->subframe_rx  = sf;
  proc->frame_rx     = f;
405
  proc->timestamp_rx = ((proc->frame_rx * 10)  + proc->subframe_rx ) * fp->samples_per_tti ;
406
  //  proc->timestamp_tx = proc->timestamp_rx +  (4*fp->samples_per_tti);
407 408
  proc->subframe_tx  = (sf+sf_ahead)%10;
  proc->frame_tx     = (sf>(9-sf_ahead)) ? (f+1)&1023 : f;
Raymond Knopp's avatar
Raymond Knopp committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423
 
  if (proc->first_rx == 0) {
    if (proc->subframe_rx != *subframe){
      LOG_E(PHY,"Received Timestamp (IF4p5) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",proc->subframe_rx,*subframe);
      exit_fun("Exiting");
    }
    if (proc->frame_rx != *frame) {
      LOG_E(PHY,"Received Timestamp (IF4p5) 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;
    *frame = proc->frame_rx;
    *subframe = proc->subframe_rx;        
  }
424

425 426 427 428 429 430 431
  if (ru == RC.ru[0]) {
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, f );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, sf );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU, proc->subframe_tx );
  }

432
  proc->symbol_mask[sf] = 0;  
Raymond Knopp's avatar
Raymond Knopp committed
433
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
434 435
  LOG_D(PHY,"RU %d: fh_if4p5_south_in sleeping ...\n",ru->idx);
  usleep(100);
Raymond Knopp's avatar
Raymond Knopp committed
436 437 438 439 440 441
}

// Dummy FH from south for getting synchronization from master RU
void fh_slave_south_in(RU_t *ru,int *frame,int *subframe) {
  // This case is for synchronization to another thread
  // it just waits for an external event.  The actual rx_fh is handle by the asynchronous RX thread
442
  RU_proc_t *proc=&ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
443 444 445 446 447 448 449 450 451

  if (wait_on_condition(&proc->mutex_FH,&proc->cond_FH,&proc->instance_cnt_FH,"fh_slave_south_in") < 0)
    return;

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

  
}

452 453
// asynchronous inbound if5 fronthaul from south (Mobipass)
void fh_if5_south_asynch_in_mobipass(RU_t *ru,int *frame,int *subframe) {
Raymond Knopp's avatar
Raymond Knopp committed
454

455 456
  RU_proc_t *proc       = &ru->proc;
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
Raymond Knopp's avatar
Raymond Knopp committed
457

458 459 460 461 462 463
  recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_MOBIPASS); 
  pthread_mutex_lock(&proc->mutex_asynch_rxtx);
  int offset_mobipass = 40120;
  pthread_mutex_lock(&proc->mutex_asynch_rxtx);
  proc->subframe_rx = ((proc->timestamp_rx-offset_mobipass)/fp->samples_per_tti)%10;
  proc->frame_rx    = ((proc->timestamp_rx-offset_mobipass)/(fp->samples_per_tti*10))&1023;
Raymond Knopp's avatar
Raymond Knopp committed
464

465 466
  proc->subframe_rx = (proc->timestamp_rx/fp->samples_per_tti)%10;
  proc->frame_rx    = (proc->timestamp_rx/(10*fp->samples_per_tti))&1023;
Raymond Knopp's avatar
Raymond Knopp committed
467

468 469
  if (proc->first_rx == 1) {
    proc->first_rx =2;
Raymond Knopp's avatar
Raymond Knopp committed
470 471
    *subframe = proc->subframe_rx;
    *frame    = proc->frame_rx; 
472
    LOG_E(PHY,"[Mobipass]timestamp_rx:%llu, frame_rx %d, subframe: %d\n",(unsigned long long int)proc->timestamp_rx,proc->frame_rx,proc->subframe_rx);
Raymond Knopp's avatar
Raymond Knopp committed
473 474 475
  }
  else {
    if (proc->subframe_rx != *subframe) {
476 477 478
        proc->first_rx++;
	LOG_E(PHY,"[Mobipass]timestamp:%llu, subframe_rx %d is not what we expect %d, first_rx:%d\n",(unsigned long long int)proc->timestamp_rx, proc->subframe_rx,*subframe, proc->first_rx);
      //exit_fun("Exiting");
Raymond Knopp's avatar
Raymond Knopp committed
479 480
    }
    if (proc->frame_rx != *frame) {
481 482 483
        proc->first_rx++;
       LOG_E(PHY,"[Mobipass]timestamp:%llu, frame_rx %d is not what we expect %d, first_rx:%d\n",(unsigned long long int)proc->timestamp_rx,proc->frame_rx,*frame, proc->first_rx);  
     // exit_fun("Exiting");
Raymond Knopp's avatar
Raymond Knopp committed
484
    }
485 486 487
    // temporary solution
      *subframe = proc->subframe_rx;
      *frame    = proc->frame_rx;
Raymond Knopp's avatar
Raymond Knopp committed
488
  }
489 490 491 492

  pthread_mutex_unlock(&proc->mutex_asynch_rxtx);


Raymond Knopp's avatar
Raymond Knopp committed
493 494 495 496 497 498
} // eNodeB_3GPP_BBU 

// asynchronous inbound if4p5 fronthaul from south
void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *subframe) {

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
499
  RU_proc_t *proc       = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
500 501

  uint16_t packet_type;
Raymond Knopp's avatar
Raymond Knopp committed
502
  uint32_t symbol_number,symbol_mask,prach_rx;
503
  uint32_t got_prach_info=0;
Raymond Knopp's avatar
Raymond Knopp committed
504 505

  symbol_number = 0;
506 507
  symbol_mask   = (1<<fp->symbols_per_tti)-1;
  prach_rx      = 0;
Raymond Knopp's avatar
Raymond Knopp committed
508 509 510

  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
    recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number);
511 512 513 514 515
    // grab first prach information for this new subframe
    if (got_prach_info==0) {
      prach_rx       = is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx);
      got_prach_info = 1;
    }
Raymond Knopp's avatar
Raymond Knopp committed
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    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");
      }
    }
531 532
    if      (packet_type == IF4p5_PULFFT)       symbol_mask &= (~(1<<symbol_number));
    else if (packet_type == IF4p5_PRACH)        prach_rx    &= (~0x1);
533
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
534 535 536 537 538 539
    else if (packet_type == IF4p5_PRACH_BR_CE0) prach_rx    &= (~0x2);
    else if (packet_type == IF4p5_PRACH_BR_CE1) prach_rx    &= (~0x4);
    else if (packet_type == IF4p5_PRACH_BR_CE2) prach_rx    &= (~0x8);
    else if (packet_type == IF4p5_PRACH_BR_CE3) prach_rx    &= (~0x10);
#endif
  } while( (symbol_mask > 0) || (prach_rx >0));   // haven't received all PUSCH symbols and PRACH information 
Raymond Knopp's avatar
Raymond Knopp committed
540 541 542 543 544 545 546 547 548 549 550
} 





/*************************************************************/
/* Input Fronthaul from North RRU                            */
  
// RRU IF4p5 TX fronthaul receiver. Assumes an if_device on input and if or rf device on output 
// receives one subframe's worth of IF4p5 OFDM symbols and OFDM modulates
551
void fh_if4p5_north_in(RU_t *ru,int *frame,int *subframe) {
Raymond Knopp's avatar
Raymond Knopp committed
552 553 554 555 556

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

557

Raymond Knopp's avatar
Raymond Knopp committed
558 559 560 561 562 563
  /// **** incoming IF4p5 from remote RCC/RAU **** ///             
  symbol_number = 0;
  symbol_mask = 0;
  symbol_mask_full = (1<<ru->frame_parms.symbols_per_tti)-1;
  
  do { 
564
    recv_IF4p5(ru, frame, subframe, &packet_type, &symbol_number);
Raymond Knopp's avatar
Raymond Knopp committed
565 566 567
    symbol_mask = symbol_mask | (1<<symbol_number);
  } while (symbol_mask != symbol_mask_full); 

568 569
  // dump VCD output for first RU in list
  if (ru == RC.ru[0]) {
570 571
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, *frame );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU, *subframe );
Raymond Knopp's avatar
Raymond Knopp committed
572 573 574 575 576 577
  }
}

void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *subframe) {

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
578
  RU_proc_t *proc        = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
  int subframe_tx,frame_tx;
  openair0_timestamp timestamp_tx;

  recv_IF5(ru, &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 {
594 595 596 597
    AssertFatal(subframe_tx == *subframe,
                "subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe);
    AssertFatal(frame_tx == *frame, 
                "frame_tx %d is not what we expect %d\n",frame_tx,*frame);
Raymond Knopp's avatar
Raymond Knopp committed
598 599 600 601 602 603
  }
}

void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *subframe) {

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
604
  RU_proc_t *proc        = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
605 606 607 608 609

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

Cedric Roux's avatar
Cedric Roux committed
610
  LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru);
Raymond Knopp's avatar
Raymond Knopp committed
611 612
  symbol_number = 0;
  symbol_mask = 0;
613
  symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<<fp->dl_symbols_in_S_subframe) : (1<<fp->symbols_per_tti))-1;
Raymond Knopp's avatar
Raymond Knopp committed
614 615
  do {   
    recv_IF4p5(ru, &frame_tx, &subframe_tx, &packet_type, &symbol_number);
616
    if ((subframe_select(fp,subframe_tx) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul);
617 618
    LOG_D(PHY,"subframe %d (%d): frame %d, subframe %d, symbol %d\n",
         *subframe,subframe_select(fp,*subframe),frame_tx,subframe_tx,symbol_number);
Raymond Knopp's avatar
Raymond Knopp committed
619 620 621 622
    if (proc->first_tx != 0) {
      *frame    = frame_tx;
      *subframe = subframe_tx;
      proc->first_tx = 0;
623
      symbol_mask_full = ((subframe_select(fp,*subframe) == SF_S) ? (1<<fp->dl_symbols_in_S_subframe) : (1<<fp->symbols_per_tti))-1;
Raymond Knopp's avatar
Raymond Knopp committed
624 625
    }
    else {
626 627 628 629
      AssertFatal(frame_tx == *frame,
	          "frame_tx %d is not what we expect %d\n",frame_tx,*frame);
      AssertFatal(subframe_tx == *subframe,
		  "subframe_tx %d is not what we expect %d\n",subframe_tx,*subframe);
Raymond Knopp's avatar
Raymond Knopp committed
630 631 632 633
    }
    if (packet_type == IF4p5_PDLFFT) {
      symbol_mask = symbol_mask | (1<<symbol_number);
    }
634
    else AssertFatal(1==0,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type);
Raymond Knopp's avatar
Raymond Knopp committed
635
  } while (symbol_mask != symbol_mask_full);    
636

637
  if (subframe_select(fp,subframe_tx) == SF_DL) stop_meas(&ru->rx_fhaul);
638

639 640 641 642
  proc->subframe_tx  = subframe_tx;
  proc->frame_tx     = frame_tx;

  if ((frame_tx == 0)&&(subframe_tx == 0)) proc->frame_tx_unwrap += 1024;
643

644 645
  proc->timestamp_tx = ((((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * 10) + (uint64_t)subframe_tx) * (uint64_t)fp->samples_per_tti;

646
  LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,subframe_tx);
647 648 649 650 651
    // dump VCD output for first RU in list
  if (ru == RC.ru[0]) {
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame_tx );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU, subframe_tx );
  }
652

653 654
  if (ru->feptx_ofdm) ru->feptx_ofdm(ru);
  if (ru->fh_south_out) ru->fh_south_out(ru);
Raymond Knopp's avatar
Raymond Knopp committed
655 656
} 

657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
void fh_if5_north_out(RU_t *ru) {

  RU_proc_t *proc=&ru->proc;
  uint8_t seqno=0;

  /// **** send_IF5 of rxdata to BBU **** ///       
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 );  
  send_IF5(ru, proc->timestamp_rx, proc->subframe_rx, &seqno, IF5_RRH_GW_UL);
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 );          

}

// RRU IF4p5 northbound interface (RX)
void fh_if4p5_north_out(RU_t *ru) {

  RU_proc_t *proc=&ru->proc;
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
  const int subframe     = proc->subframe_rx;
675
  if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_rx );
676 677 678

  if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) {
    /// **** in TDD during DL send_IF4 of ULTICK to RCC **** ///
679
    send_IF4p5(ru, proc->frame_rx, proc->subframe_rx, IF4p5_PULTICK);
680 681 682
    return;
  }

683 684 685
  start_meas(&ru->tx_fhaul);
  send_IF4p5(ru, proc->frame_rx, proc->subframe_rx, IF4p5_PULFFT);
  stop_meas(&ru->tx_fhaul);
686 687

}
688

Wang Tsu-Han's avatar
Wang Tsu-Han committed
689 690 691 692 693 694 695 696 697 698 699 700 701
/* add fail safe for late command */
typedef enum {
	STATE_BURST_NORMAL = 0,
	STATE_BURST_TERMINATE = 1,
	STATE_BURST_STOP_1 = 2,
	STATE_BURST_STOP_2 = 3,
	STATE_BURST_RESTART = 4,
} late_control_e;

volatile late_control_e late_control=STATE_BURST_NORMAL;

/* add fail safe for late command end */

702 703 704 705
static void* emulatedRF_thread(void* param) {
  RU_proc_t *proc = (RU_proc_t *) param;
  int microsec = 500; // length of time to sleep, in miliseconds
  struct timespec req = {0};
706
  int numerology = get_softmodem_params()->numerology;
707
  req.tv_sec = 0;
Eurecom's avatar
Eurecom committed
708
  req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2;
709 710 711 712 713 714 715 716 717 718 719
  cpu_set_t cpuset;
  CPU_SET(1,&cpuset);
  pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
  
  int policy;
  struct sched_param sparam;
  memset(&sparam, 0, sizeof(sparam));
  sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
  policy = SCHED_FIFO ; 
  pthread_setschedparam(pthread_self(), policy, &sparam);
  
720 721 722
  wait_sync("emulatedRF_thread");
  while(!oai_exit){
    nanosleep(&req, (struct timespec *)NULL);
723 724 725 726 727
    if(proc->emulate_rf_busy )
    {
      LOG_E(PHY,"rf being delayed in emulated RF\n");
    }
    proc->emulate_rf_busy = 1;
728 729 730 731 732 733 734 735
    pthread_mutex_lock(&proc->mutex_emulateRF);
    ++proc->instance_cnt_emulateRF;
    pthread_mutex_unlock(&proc->mutex_emulateRF);
    pthread_cond_signal(&proc->cond_emulateRF);
  }
  return 0;
}

Raymond Knopp's avatar
Raymond Knopp committed
736 737
void rx_rf(RU_t *ru,int *frame,int *subframe) {

738
  RU_proc_t *proc = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
739
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
740
  void *rxp[ru->nb_rx];
741
  unsigned int rxs;
Raymond Knopp's avatar
Raymond Knopp committed
742
  int i;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
743
  openair0_timestamp ts=0,old_ts=0;
Raymond Knopp's avatar
Raymond Knopp committed
744
    
745
  for (i=0; i<ru->nb_rx; i++)
746
    rxp[i] = (void*)&ru->common.rxdata[i][*subframe*fp->samples_per_tti];
747

Raymond Knopp's avatar
Raymond Knopp committed
748 749
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );

750
  old_ts = proc->timestamp_rx;
751
  if(get_softmodem_params()->emulate_rf){
752 753 754 755 756 757
    wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
    release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
    rxs = fp->samples_per_tti;
  }
  else{
    rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
758
				   &ts,
Raymond Knopp's avatar
Raymond Knopp committed
759 760
				   rxp,
				   fp->samples_per_tti,
761
				   ru->nb_rx);
762
  }
Raymond Knopp's avatar
Raymond Knopp committed
763 764 765
  
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
 
766 767
  proc->timestamp_rx = ts-ru->ts_offset;

Wang Tsu-Han's avatar
Wang Tsu-Han committed
768
//  AssertFatal(rxs == fp->samples_per_tti,
769
//	      "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
770
  if(rxs != fp->samples_per_tti){
771
    LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
772 773
    late_control=STATE_BURST_TERMINATE;
  }
774 775

  if (proc->first_rx == 1) {
776
    ru->ts_offset = proc->timestamp_rx;
777 778 779 780
    proc->timestamp_rx = 0;
  }
  else {
    if (proc->timestamp_rx - old_ts != fp->samples_per_tti) {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
781
      //LOG_I(PHY,"rx_rf: rfdevice timing drift of %"PRId64" samples (ts_off %"PRId64")\n",proc->timestamp_rx - old_ts - fp->samples_per_tti,ru->ts_offset);
782 783 784 785 786 787 788
      ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti);
      proc->timestamp_rx = ts-ru->ts_offset;
    }

  }
  proc->frame_rx     = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
  proc->subframe_rx  = (proc->timestamp_rx / fp->samples_per_tti)%10;
Raymond Knopp's avatar
Raymond Knopp committed
789 790
  // synchronize first reception to frame 0 subframe 0

Wang Tsu-Han's avatar
Wang Tsu-Han committed
791 792 793 794 795 796 797 798 799 800
#ifdef PHY_TX_THREAD
  proc->timestamp_phy_tx = proc->timestamp_rx+((sf_ahead-1)*fp->samples_per_tti);
  proc->subframe_phy_tx  = (proc->subframe_rx+(sf_ahead-1))%10;  
  proc->frame_phy_tx     = (proc->subframe_rx>(9-(sf_ahead-1))) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
#else
  proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti);
  proc->subframe_tx  = (proc->subframe_rx+sf_ahead)%10;
  proc->frame_tx     = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
#endif

801 802 803
  //proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti);
  //proc->subframe_tx  = (proc->subframe_rx+sf_ahead)%10;
  //proc->frame_tx     = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
804 805 806 807 808 809
  
  LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, subframe %d\n",
	ru->idx, 
	0, 
	(unsigned long long int)proc->timestamp_rx,
	(int)ru->ts_offset,proc->frame_rx,proc->subframe_rx);
810

811 812 813 814 815
    // dump VCD output for first RU in list
  if (ru == RC.ru[0]) {
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, proc->frame_rx );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_rx );
  }
Raymond Knopp's avatar
Raymond Knopp committed
816 817 818
  
  if (proc->first_rx == 0) {
    if (proc->subframe_rx != *subframe){
819
      LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->subframe_rx %d, subframe %d)\n",(long long unsigned int)proc->timestamp_rx,proc->subframe_rx,*subframe);
Raymond Knopp's avatar
Raymond Knopp committed
820 821 822 823
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
824
      LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d)\n",(long long unsigned int)proc->timestamp_rx,proc->frame_rx,*frame);
Raymond Knopp's avatar
Raymond Knopp committed
825 826 827 828 829 830 831 832 833 834
      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",ru->timestamp_rx,proc->frame_rx,frame,proc->subframe_rx,subframe);
  
835
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
Raymond Knopp's avatar
Raymond Knopp committed
836 837
  
  if (rxs != fp->samples_per_tti)
838
  {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
839 840 841
#if defined(USRP_REC_PLAY)
    exit_fun("Exiting IQ record/playback");
#else    
842
    //exit_fun( "problem receiving samples" );
Cedric Roux's avatar
Cedric Roux committed
843
    LOG_E(PHY, "problem receiving samples");
Wang Tsu-Han's avatar
Wang Tsu-Han committed
844
#endif    
845
  }
Raymond Knopp's avatar
Raymond Knopp committed
846 847 848
}


849 850 851 852
void tx_rf(RU_t *ru) {

  RU_proc_t *proc = &ru->proc;
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
853
  void *txp[ru->nb_tx]; 
854 855 856
  unsigned int txs;
  int i;

Cedric Roux's avatar
Cedric Roux committed
857 858 859
  T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), T_INT(proc->frame_tx), T_INT(proc->subframe_tx),
    T_INT(0), T_BUFFER(&ru->common.txdata[0][proc->subframe_tx * fp->samples_per_tti], fp->samples_per_tti * 4));

860 861 862
  lte_subframe_t SF_type     = subframe_select(fp,proc->subframe_tx%10);
  lte_subframe_t prevSF_type = subframe_select(fp,(proc->subframe_tx+9)%10);
  lte_subframe_t nextSF_type = subframe_select(fp,(proc->subframe_tx+1)%10);
863 864
  int sf_extension = 0;

865 866 867 868 869 870 871 872 873 874 875 876
  if ((SF_type == SF_DL) ||
      (SF_type == SF_S)) {
    
    int siglen=fp->samples_per_tti,flags=1;
    
    if (SF_type == SF_S) {
      siglen = fp->dl_symbols_in_S_subframe*(fp->ofdm_symbol_size+fp->nb_prefix_samples0);
      flags=3; // end of burst
    }
    if ((fp->frame_type == TDD) &&
	(SF_type == SF_DL)&&
	(prevSF_type == SF_UL) &&
877
	(nextSF_type == SF_DL)) { 
878
      flags = 2; // start of burst
Wang Tsu-Han's avatar
Wang Tsu-Han committed
879
      sf_extension = ru->N_TA_offset;
880
    }
881 882 883 884
    
    if ((fp->frame_type == TDD) &&
	(SF_type == SF_DL)&&
	(prevSF_type == SF_UL) &&
885
	(nextSF_type == SF_UL)) {
886
      flags = 4; // start of burst and end of burst (only one DL SF between two UL)
Wang Tsu-Han's avatar
Wang Tsu-Han committed
887
      sf_extension = ru->N_TA_offset;
888
    } 
Wang Tsu-Han's avatar
Wang Tsu-Han committed
889 890 891 892 893 894 895 896 897 898
#if defined(__x86_64) || defined(__i386__)
#ifdef __AVX2__
  sf_extension = (sf_extension)&0xfffffff8;
#else
  sf_extension = (sf_extension)&0xfffffffc;
#endif
#elif defined(__arm__)
  sf_extension = (sf_extension)&0xfffffffc;
#endif
    
899 900 901
    for (i=0; i<ru->nb_tx; i++)
      txp[i] = (void*)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension];

Wang Tsu-Han's avatar
Wang Tsu-Han committed
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
    /* add fail safe for late command */
    if(late_control!=STATE_BURST_NORMAL){//stop burst
      switch (late_control) {
      case STATE_BURST_TERMINATE:
        flags=10; // end of burst and no time spec
        late_control=STATE_BURST_STOP_1;
        break;
      
      case STATE_BURST_STOP_1:
        flags=0; // no send
        late_control=STATE_BURST_STOP_2;
        return;//no send
       break;
      
      case STATE_BURST_STOP_2:
        flags=0; // no send
        late_control=STATE_BURST_RESTART;
        return;//no send
        break;
      
      case STATE_BURST_RESTART:
        flags=2; // start burst
        late_control=STATE_BURST_NORMAL;
        break;
      default:
        LOG_D(PHY,"[TXPATH] RU %d late_control %d not implemented\n",ru->idx, late_control);
      break;
      }
    }
    /* add fail safe for late command end */

Raymond Knopp's avatar
Raymond Knopp committed
933 934
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_TX0_RU, proc->subframe_tx );
Wang Tsu-Han's avatar
Wang Tsu-Han committed
935

936 937 938 939 940
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (proc->timestamp_tx-ru->openair0_cfg.tx_sample_advance)&0xffffffff );
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1 );
    // prepare tx buffer pointers
    
    txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
941
				      proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension,
942
				      txp,
943
				      siglen+sf_extension,
944 945 946 947
				      ru->nb_tx,
				      flags);
    
    LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, subframe %d\n",ru->idx,
Raymond Knopp's avatar
Raymond Knopp committed
948
	  (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx);
949
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
950
    
951
    
Wang Tsu-Han's avatar
Wang Tsu-Han committed
952 953 954 955 956
//    AssertFatal(txs ==  siglen+sf_extension,"TX : Timeout (sent %d/%d)\n",txs, siglen);
    if( (txs !=  siglen+sf_extension) && (late_control==STATE_BURST_NORMAL) ){ /* add fail safe for late command */
      late_control=STATE_BURST_TERMINATE;
      LOG_E(PHY,"TX : Timeout (sent %d/%d) state =%d\n",txs, siglen,late_control);
    }
957
  }
958 959 960
}


Raymond Knopp's avatar
Raymond Knopp committed
961 962 963
/*!
 * \brief The Asynchronous RX/TX FH thread of RAU/RCC/eNB/RRU.
 * This handles the RX FH for an asynchronous RRU/UE
964
 * \param param is a \ref L1_proc_t structure which contains the info what to process.
Raymond Knopp's avatar
Raymond Knopp committed
965 966 967 968 969 970
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
static void* ru_thread_asynch_rxtx( void* param ) {

  static int ru_thread_asynch_rxtx_status;

971 972 973
  RU_t *ru         = (RU_t*)param;
  RU_proc_t *proc  = &ru->proc;

Raymond Knopp's avatar
Raymond Knopp committed
974 975 976 977


  int subframe=0, frame=0; 

978
  thread_top_init("ru_thread_asynch_rxtx",1,870000,1000000,1000000);
Raymond Knopp's avatar
Raymond Knopp committed
979 980 981

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

982
  wait_sync("ru_thread_asynch_rxtx");
Raymond Knopp's avatar
Raymond Knopp committed
983 984

  // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe
985
  printf( "waiting for devices (ru_thread_asynch_rx)\n");
Raymond Knopp's avatar
Raymond Knopp committed
986 987 988

  wait_on_condition(&proc->mutex_asynch_rxtx,&proc->cond_asynch_rxtx,&proc->instance_cnt_asynch_rxtx,"thread_asynch");

989
  printf( "devices ok (ru_thread_asynch_rx)\n");
Raymond Knopp's avatar
Raymond Knopp committed
990 991 992 993 994 995 996 997 998 999 1000 1001 1002


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

    if (subframe==9) { 
      subframe=0;
      frame++;
      frame&=1023;
    } else {
      subframe++;
    }      
1003
    LOG_D(PHY,"ru_thread_asynch_rxtx: Waiting on incoming fronthaul\n");
1004
	// asynchronous receive from south (Mobipass)
1005 1006
    if (ru->fh_south_asynch_in) ru->fh_south_asynch_in(ru,&frame,&subframe);
    // asynchronous receive from north (RRU IF4/IF5)
1007 1008 1009 1010
    else if (ru->fh_north_asynch_in) {
       if (subframe_select(&ru->frame_parms,subframe)!=SF_UL)
         ru->fh_north_asynch_in(ru,&frame,&subframe);
    }
1011
    else AssertFatal(1==0,"Unknown function in ru_thread_asynch_rxtx\n");
Raymond Knopp's avatar
Raymond Knopp committed
1012 1013 1014 1015 1016 1017 1018 1019 1020
  }

  ru_thread_asynch_rxtx_status=0;
  return(&ru_thread_asynch_rxtx_status);
}




1021
void wakeup_slaves(RU_proc_t *proc) {
Raymond Knopp's avatar
Raymond Knopp committed
1022 1023 1024 1025 1026 1027 1028 1029

  int i;
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
  
  for (i=0;i<proc->num_slaves;i++) {
1030
    RU_proc_t *slave_proc = proc->slave_proc[i];
Raymond Knopp's avatar
Raymond Knopp committed
1031 1032 1033
    // 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) {
1034
      LOG_E( PHY, "ERROR pthread_mutex_lock for RU %d slave %d (IC %d)\n",proc->ru->idx,slave_proc->ru->idx,slave_proc->instance_cnt_FH);
Raymond Knopp's avatar
Raymond Knopp committed
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
      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;
    slave_proc->timestamp_tx = proc->timestamp_tx; 

    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) {
1050
	LOG_E( PHY, "ERROR pthread_cond_signal for RU %d, slave RU %d\n",proc->ru->idx,slave_proc->ru->idx);
Raymond Knopp's avatar
Raymond Knopp committed
1051 1052 1053 1054
          exit_fun( "ERROR pthread_cond_signal" );
	  break;
      }
    } else {
1055
      LOG_W( PHY,"[RU] Frame %d, slave %d thread busy!! (cnt_FH %i)\n",slave_proc->frame_rx,slave_proc->ru->idx, cnt_slave);
Raymond Knopp's avatar
Raymond Knopp committed
1056 1057 1058 1059 1060 1061 1062 1063
      exit_fun( "FH thread busy" );
      break;
    }             
  }
}

/*!
 * \brief The prach receive thread of RU.
1064
 * \param param is a \ref RU_proc_t structure which contains the info what to process.
Raymond Knopp's avatar
Raymond Knopp committed
1065 1066 1067
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
static void* ru_thread_prach( void* param ) {
1068

Raymond Knopp's avatar
Raymond Knopp committed
1069 1070
  static int ru_thread_prach_status;

1071 1072
  RU_t *ru        = (RU_t*)param;
  RU_proc_t *proc = (RU_proc_t*)&ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
1073 1074

  // set default return value
1075
  ru_thread_prach_status = 0;
Raymond Knopp's avatar
Raymond Knopp committed
1076

1077
  thread_top_init("ru_thread_prach",1,500000,1000000,20000000);
1078
  //wait_sync("ru_thread_prach");
Raymond Knopp's avatar
Raymond Knopp committed
1079

1080 1081 1082 1083 1084
  while (RC.ru_mask>0) {
    usleep(1e6);
    LOG_I(PHY,"%s() RACH waiting for RU to be configured\n", __FUNCTION__);
  }
  LOG_I(PHY,"%s() RU configured - RACH processing thread running\n", __FUNCTION__);
Raymond Knopp's avatar
Raymond Knopp committed
1085 1086 1087

  while (!oai_exit) {
    
1088
    if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
1089
    if (oai_exit) break;
1090
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );      
1091 1092
    if (ru->eNB_list[0]){
      prach_procedures(
1093
        ru->eNB_list[0]
1094
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
1095
        ,0
1096
#endif
1097
        );
1098 1099 1100 1101 1102 1103 1104 1105 1106
    }
    else {
       rx_prach(NULL,
  	        ru,
	        NULL,
                NULL,
                NULL,
                proc->frame_prach,
                0
1107
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
1108
	        ,0
1109
#endif
1110 1111
	        );
    } 
1112
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 );      
1113
    if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
Raymond Knopp's avatar
Raymond Knopp committed
1114 1115
  }

1116 1117 1118 1119 1120 1121
  LOG_I(PHY, "Exiting RU thread PRACH\n");

  ru_thread_prach_status = 0;
  return &ru_thread_prach_status;
}

1122
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
static void* ru_thread_prach_br( void* param ) {

  static int ru_thread_prach_status;

  RU_t *ru        = (RU_t*)param;
  RU_proc_t *proc = (RU_proc_t*)&ru->proc;

  // set default return value
  ru_thread_prach_status = 0;

1133
  thread_top_init("ru_thread_prach_br",1,500000,1000000,20000000);
1134
  //wait_sync("ru_thread_prach_br");
1135 1136 1137 1138

  while (!oai_exit) {
    
    if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break;
1139
    if (oai_exit) break;
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
    rx_prach(NULL,
	     ru,
	     NULL,
             NULL,
             NULL,
             proc->frame_prach_br,
             0,
	     1);
    if (release_thread(&proc->mutex_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break;
  }

  LOG_I(PHY, "Exiting RU thread PRACH BR\n");
Raymond Knopp's avatar
Raymond Knopp committed
1152

1153 1154
  ru_thread_prach_status = 0;
  return &ru_thread_prach_status;
Raymond Knopp's avatar
Raymond Knopp committed
1155
}
1156
#endif
Raymond Knopp's avatar
Raymond Knopp committed
1157

1158
int wakeup_synch(RU_t *ru){
Raymond Knopp's avatar
Raymond Knopp committed
1159

1160 1161 1162 1163
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
Raymond Knopp's avatar
Raymond Knopp committed
1164

1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
  // wake up synch thread
  // lock the synch mutex and make sure the thread is ready
  if (pthread_mutex_timedlock(&ru->proc.mutex_synch,&wait) != 0) {
    LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU synch thread (IC %d)\n", ru->proc.instance_cnt_synch );
    exit_fun( "error locking mutex_synch" );
    return(-1);
  }
  
  ++ru->proc.instance_cnt_synch;
  
  // the thread can now be woken up
  if (pthread_cond_signal(&ru->proc.cond_synch) != 0) {
    LOG_E( PHY, "[RU] ERROR pthread_cond_signal for RU synch thread\n");
    exit_fun( "ERROR pthread_cond_signal" );
    return(-1);
  }
  
  pthread_mutex_unlock( &ru->proc.mutex_synch );

  return(0);
}

void do_ru_synch(RU_t *ru) {

  LTE_DL_FRAME_PARMS *fp  = &ru->frame_parms;
  RU_proc_t *proc         = &ru->proc;
  int i;
Raymond Knopp's avatar
Raymond Knopp committed
1192 1193
  void *rxp[2],*rxp2[2];
  int32_t dummy_rx[ru->nb_rx][fp->samples_per_tti] __attribute__((aligned(32)));
1194 1195
  int rxs;
  int ic;
Raymond Knopp's avatar
Raymond Knopp committed
1196 1197 1198

  // initialize the synchronization buffer to the common_vars.rxdata
  for (int i=0;i<ru->nb_rx;i++)
1199
    rxp[i] = &ru->common.rxdata[i][0];
Raymond Knopp's avatar
Raymond Knopp committed
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215

  double temp_freq1 = ru->rfdevice.openair0_cfg->rx_freq[0];
  double temp_freq2 = ru->rfdevice.openair0_cfg->tx_freq[0];
  for (i=0;i<4;i++) {
    ru->rfdevice.openair0_cfg->rx_freq[i] = ru->rfdevice.openair0_cfg->tx_freq[i];
    ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq1;
  }
  ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0);
  
  while ((ru->in_synch ==0)&&(!oai_exit)) {
    // read in frame
    rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
				     &(proc->timestamp_rx),
				     rxp,
				     fp->samples_per_tti*10,
				     ru->nb_rx);
1216 1217
    if (rxs != fp->samples_per_tti*10) LOG_E(PHY,"requested %d samples, got %d\n",fp->samples_per_tti*10,rxs);
 
Raymond Knopp's avatar
Raymond Knopp committed
1218 1219 1220 1221 1222 1223 1224 1225
    // wakeup synchronization processing thread
    wakeup_synch(ru);
    ic=0;
    
    while ((ic>=0)&&(!oai_exit)) {
      // continuously read in frames, 1ms at a time, 
      // until we are done with the synchronization procedure
      
1226
      for (i=0; i<ru->nb_rx; i++)
Raymond Knopp's avatar
Raymond Knopp committed
1227 1228 1229 1230 1231 1232 1233
	rxp2[i] = (void*)&dummy_rx[i][0];
      for (i=0;i<10;i++)
	rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
					 &(proc->timestamp_rx),
					 rxp2,
					 fp->samples_per_tti,
					 ru->nb_rx);
1234 1235 1236
      pthread_mutex_lock(&ru->proc.mutex_synch);
      ic = ru->proc.instance_cnt_synch;
      pthread_mutex_unlock(&ru->proc.mutex_synch);
Raymond Knopp's avatar
Raymond Knopp committed
1237 1238 1239 1240 1241 1242 1243 1244
    } // ic>=0
  } // in_synch==0
    // read in rx_offset samples
  LOG_I(PHY,"Resynchronizing by %d samples\n",ru->rx_offset);
  rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
				   &(proc->timestamp_rx),
				   rxp,
				   ru->rx_offset,
1245
				   ru->nb_rx);
Raymond Knopp's avatar
Raymond Knopp committed
1246 1247 1248 1249 1250 1251 1252 1253 1254
  for (i=0;i<4;i++) {
    ru->rfdevice.openair0_cfg->rx_freq[i] = temp_freq1;
    ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq2;
  }

  ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0);

}

1255 1256


1257
void wakeup_L1s(RU_t *ru) {
1258 1259 1260 1261

  int i;
  PHY_VARS_eNB **eNB_list = ru->eNB_list;

1262
  LOG_D(PHY,"wakeup_L1s (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top);
1263

1264

1265
  if (ru->num_eNB==1 && ru->eNB_top!=0 && get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD) {
1266
    // call eNB function directly
1267
  
1268 1269
    char string[20];
    sprintf(string,"Incoming RU %d",ru->idx);
Cedric Roux's avatar
Cedric Roux committed
1270
    LOG_D(PHY,"RU %d Call eNB_top\n",ru->idx);
1271
    ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string,ru);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1272
    ru->proc.emulate_rf_busy = 0;
1273 1274 1275
  }
  else {

1276 1277
    LOG_D(PHY,"ru->num_eNB:%d\n", ru->num_eNB);

1278
    for (i=0;i<ru->num_eNB;i++)
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1279
    {
1280
      LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->wakeup_rxtx);
1281
      if (ru->wakeup_rxtx!=0 && ru->wakeup_rxtx(eNB_list[i],ru) < 0)
1282
      {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1283
        LOG_E(PHY,"could not wakeup eNB rxtx process for subframe %d\n", ru->proc.subframe_rx);
1284
      }
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1285
      ru->proc.emulate_rf_busy = 0;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1286
    }
1287 1288 1289
  }
}

1290
static inline int wakeup_prach_ru(RU_t *ru) {
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301

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

  if (pthread_mutex_timedlock(&ru->proc.mutex_prach,&wait) !=0) {
    LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread (IC %d)\n", ru->proc.instance_cnt_prach);
    exit_fun( "error locking mutex_rxtx" );
    return(-1);
  }
1302 1303 1304 1305
  if (ru->proc.instance_cnt_prach==-1) {
    ++ru->proc.instance_cnt_prach;
    ru->proc.frame_prach    = ru->proc.frame_rx;
    ru->proc.subframe_prach = ru->proc.subframe_rx;
1306

1307
    // DJP - think prach_procedures() is looking at eNB frame_prach
1308 1309 1310 1311
    if (ru->eNB_list[0]) {
      ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx;
      ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx;
    }
1312
    LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx);
1313 1314
    // the thread can now be woken up
    AssertFatal(pthread_cond_signal(&ru->proc.cond_prach) == 0, "ERROR pthread_cond_signal for RU prach thread\n");
1315
  }
1316
  else LOG_W(PHY,"RU prach thread busy, skipping\n");
1317 1318 1319 1320 1321
  pthread_mutex_unlock( &ru->proc.mutex_prach );

  return(0);
}

1322
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350
static inline int wakeup_prach_ru_br(RU_t *ru) {

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

  if (pthread_mutex_timedlock(&ru->proc.mutex_prach_br,&wait) !=0) {
    LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for RU prach thread BR (IC %d)\n", ru->proc.instance_cnt_prach_br);
    exit_fun( "error locking mutex_rxtx" );
    return(-1);
  }
  if (ru->proc.instance_cnt_prach_br==-1) {
    ++ru->proc.instance_cnt_prach_br;
    ru->proc.frame_prach_br    = ru->proc.frame_rx;
    ru->proc.subframe_prach_br = ru->proc.subframe_rx;

    LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx);
    // the thread can now be woken up
    AssertFatal(pthread_cond_signal(&ru->proc.cond_prach_br) == 0, "ERROR pthread_cond_signal for RU prach thread BR\n");
  }
  else LOG_W(PHY,"RU prach thread busy, skipping\n");
  pthread_mutex_unlock( &ru->proc.mutex_prach_br );

  return(0);
}
#endif

Raymond Knopp's avatar
Raymond Knopp committed
1351 1352 1353 1354 1355 1356 1357
// this is for RU with local RF unit
void fill_rf_config(RU_t *ru, char *rf_config_file) {

  int i;

  LTE_DL_FRAME_PARMS *fp   = &ru->frame_parms;
  openair0_config_t *cfg   = &ru->openair0_cfg;
1358
  //printf("////////////////numerology in config = %d\n",numerology);
1359
  int numerology = get_softmodem_params()->numerology;
Raymond Knopp's avatar
Raymond Knopp committed
1360
  if(fp->N_RB_DL == 100) {
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
    if(numerology == 0){
      if (fp->threequarter_fs) {
        cfg->sample_rate=23.04e6;
        cfg->samples_per_frame = 230400; 
        cfg->tx_bw = 10e6;
        cfg->rx_bw = 10e6;
      }
      else {
        cfg->sample_rate=30.72e6;
        cfg->samples_per_frame = 307200; 
        cfg->tx_bw = 10e6;
        cfg->rx_bw = 10e6;
      }
	}else if(numerology == 1){
	  cfg->sample_rate=61.44e6;
      cfg->samples_per_frame = 307200; 
      cfg->tx_bw = 20e6;
      cfg->rx_bw = 20e6;
	}else if(numerology == 2){
	  cfg->sample_rate=122.88e6;
      cfg->samples_per_frame = 307200; 
      cfg->tx_bw = 40e6;
      cfg->rx_bw = 40e6;
	}else{
	  printf("Wrong input for numerology %d\n setting to 20MHz normal CP configuration",numerology);
	  cfg->sample_rate=30.72e6;
Raymond Knopp's avatar
Raymond Knopp committed
1387 1388 1389
      cfg->samples_per_frame = 307200; 
      cfg->tx_bw = 10e6;
      cfg->rx_bw = 10e6;
1390
	}
Raymond Knopp's avatar
Raymond Knopp committed
1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
  } else if(fp->N_RB_DL == 50) {
    cfg->sample_rate=15.36e6;
    cfg->samples_per_frame = 153600;
    cfg->tx_bw = 5e6;
    cfg->rx_bw = 5e6;
  } else if (fp->N_RB_DL == 25) {
    cfg->sample_rate=7.68e6;
    cfg->samples_per_frame = 76800;
    cfg->tx_bw = 2.5e6;
    cfg->rx_bw = 2.5e6;
  } else if (fp->N_RB_DL == 6) {
    cfg->sample_rate=1.92e6;
    cfg->samples_per_frame = 19200;
    cfg->tx_bw = 1.5e6;
    cfg->rx_bw = 1.5e6;
  }
  else AssertFatal(1==0,"Unknown N_RB_DL %d\n",fp->N_RB_DL);

  if (fp->frame_type==TDD)
    cfg->duplex_mode = duplex_mode_TDD;
  else //FDD
    cfg->duplex_mode = duplex_mode_FDD;

  cfg->Mod_id = 0;
  cfg->num_rb_dl=fp->N_RB_DL;
  cfg->tx_num_channels=ru->nb_tx;
  cfg->rx_num_channels=ru->nb_rx;
1418
  cfg->clock_source=get_softmodem_params()->clock_source;
1419

Raymond Knopp's avatar
Raymond Knopp committed
1420 1421 1422 1423 1424
  for (i=0; i<ru->nb_tx; i++) {
    
    cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
    cfg->rx_freq[i] = (double)fp->ul_CarrierFreq;

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1425 1426
    cfg->tx_gain[i] = (double)ru->att_tx;
    cfg->rx_gain[i] = ru->max_rxgain-(double)ru->att_rx;
Raymond Knopp's avatar
Raymond Knopp committed
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454


    cfg->configFilename = rf_config_file;
    printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n",
	   i, cfg->tx_gain[i],
	   cfg->rx_gain[i],
	   cfg->tx_freq[i],
	   cfg->rx_freq[i]);
  }
}

/* this function maps the RU 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 antenna port, on which rf chain the mapping should start. Multiple
   antennas are mapped to successive RF chains on the same card. */
int setup_RU_buffers(RU_t *ru) {

  int i,j; 
  int card,ant;

  //uint16_t N_TA_offset = 0;

  LTE_DL_FRAME_PARMS *frame_parms;
  
  if (ru) {
    frame_parms = &ru->frame_parms;
    printf("setup_RU_buffers: frame_parms = %p\n",frame_parms);
  } else {
1455
    printf("RU not initialized (NULL pointer)\n");
Raymond Knopp's avatar
Raymond Knopp committed
1456 1457 1458 1459
    return(-1);
  }
  
  
1460 1461 1462 1463
  if (frame_parms->frame_type == TDD) {
    if      (frame_parms->N_RB_DL == 100) ru->N_TA_offset = 624;
    else if (frame_parms->N_RB_DL == 50)  ru->N_TA_offset = 624/2;
    else if (frame_parms->N_RB_DL == 25)  ru->N_TA_offset = 624/4;
1464 1465 1466 1467 1468 1469
#if BASIC_SIMULATOR
    /* this is required for the basic simulator in TDD mode
     * TODO: find a proper cleaner solution
     */
    ru->N_TA_offset = 0;
#endif
1470
  } 
Raymond Knopp's avatar
Raymond Knopp committed
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
  if (ru->openair0_cfg.mmapped_dma == 1) {
    // replace RX signal buffers with mmaped HW versions
    
    for (i=0; i<ru->nb_rx; i++) {
      card = i/4;
      ant = i%4;
      printf("Mapping RU id %d, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
      free(ru->common.rxdata[i]);
      ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant];
      
      printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]);
      for (j=0; j<16; j++) {
	printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]);
	ru->common.rxdata[i][j] = 16-j;
      }
    }
    
    for (i=0; i<ru->nb_tx; i++) {
      card = i/4;
      ant = i%4;
      printf("Mapping RU id %d, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
      free(ru->common.txdata[i]);
      ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant];
      
      printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]);
      
      for (j=0; j<16; j++) {
	printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]);
	ru->common.txdata[i][j] = 16-j;
      }
    }
  }
  else {  // not memory-mapped DMA 
    //nothing to do, everything already allocated in lte_init
  }
  return(0);
}

1509 1510 1511 1512 1513 1514 1515
static void* ru_stats_thread(void* param) {

  RU_t               *ru      = (RU_t*)param;
  wait_sync("ru_stats_thread");

  while (!oai_exit) {
     sleep(1);
1516
     if (opp_enabled) {
1517 1518
       if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx",NULL,NULL);
       if (ru->feptx_ofdm) print_meas(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL);
1519
       if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL);
1520 1521 1522 1523 1524
       if (ru->fh_north_out) {
          print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL);
          print_meas(&ru->compression,"compression",NULL,NULL);
          print_meas(&ru->transport,"transport",NULL,NULL);
       }
1525 1526
     }
  }
1527
  return(NULL);
1528 1529
}

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1530 1531 1532 1533 1534 1535
#ifdef PHY_TX_THREAD
int first_phy_tx = 1;
volatile int16_t phy_tx_txdataF_end;
volatile int16_t phy_tx_end;
#endif

1536
static void* ru_thread_tx( void* param ) {
1537 1538 1539
  RU_t *ru              = (RU_t*)param;
  RU_proc_t *proc       = &ru->proc;
  PHY_VARS_eNB *eNB;
1540 1541
  L1_proc_t *eNB_proc;
  L1_rxtx_proc_t *L1_proc;
1542

1543 1544 1545
  cpu_set_t cpuset;
  CPU_ZERO(&cpuset);

1546

1547
  thread_top_init("ru_thread_tx",1,400000,500000,500000);
1548

1549 1550
  //CPU_SET(5, &cpuset);
  //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
1551
  //wait_sync("ru_thread_tx");
1552

1553
  wait_on_condition(&proc->mutex_FH1,&proc->cond_FH1,&proc->instance_cnt_FH1,"ru_thread_tx");
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1554
  
1555 1556 1557

  printf( "ru_thread_tx ready\n");
  while (!oai_exit) { 
1558 1559

    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD_TX,sched_getcpu());   
1560 1561
    if (oai_exit) break;   

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1562

1563 1564
    LOG_D(PHY,"ru_thread_tx: Waiting for TX processing\n");
    // wait until eNBs are finished subframe RX n and TX n+4
1565
    wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx");
WANG Tsu-Han's avatar
WANG Tsu-Han committed
1566
    if (oai_exit) break;
1567
  	       
1568 1569
    // do TX front-end processing if needed (precoding and/or IDFTs)
    if (ru->feptx_prec) ru->feptx_prec(ru);
1570
  	  
1571 1572
    // do OFDM if needed
    if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
1573
    if(!(get_softmodem_params()->emulate_rf)){    
1574 1575 1576 1577 1578
      // do outgoing fronthaul (south) if needed
      if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
  	      
      if (ru->fh_north_out) ru->fh_north_out(ru);
	}
1579
    release_thread(&proc->mutex_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx");
1580 1581 1582 1583 1584
    for(int i = 0; i<ru->num_eNB; i++)
    {
      eNB       = ru->eNB_list[i];
      eNB_proc  = &eNB->proc;
      L1_proc   = (get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)? &eNB_proc->L1_proc_tx : &eNB_proc->L1_proc;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1585 1586 1587
      pthread_mutex_lock(&eNB_proc->mutex_RU_tx);
      for (int j=0;j<eNB->num_RU;j++) {
        if (ru == eNB->RU_list[j]) {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1588
          if ((eNB_proc->RU_mask_tx&(1<<j)) > 0)
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1589 1590
            LOG_E(PHY,"eNB %d frame %d, subframe %d : previous information from RU tx %d (num_RU %d,mask %x) has not been served yet!\n",
	      eNB->Mod_id,eNB_proc->frame_rx,eNB_proc->subframe_rx,ru->idx,eNB->num_RU,eNB_proc->RU_mask_tx);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1591
          eNB_proc->RU_mask_tx |= (1<<j);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
        }
      }
      if (eNB_proc->RU_mask_tx != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
        pthread_mutex_unlock(&eNB_proc->mutex_RU_tx);
      }
      else { // all RUs TX are finished so send the ready signal to eNB processing
        eNB_proc->RU_mask_tx = 0;
        pthread_mutex_unlock(&eNB_proc->mutex_RU_tx);

        pthread_mutex_lock( &L1_proc->mutex_RUs);
        L1_proc->instance_cnt_RUs = 0;
        // the thread can now be woken up
        if (pthread_cond_signal(&L1_proc->cond_RUs) != 0) {
          LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB TXnp4 thread\n");
          exit_fun( "ERROR pthread_cond_signal" );
        }
        pthread_mutex_unlock( &L1_proc->mutex_RUs );
1609
      }
1610
    }
1611
  }
1612
  release_thread(&proc->mutex_FH1,&proc->instance_cnt_FH1,"ru_thread_tx");
1613 1614 1615
  return 0;
}

Raymond Knopp's avatar
Raymond Knopp committed
1616 1617 1618 1619
static void* ru_thread( void* param ) {

  static int ru_thread_status;

1620 1621 1622 1623
  RU_t               *ru      = (RU_t*)param;
  RU_proc_t          *proc    = &ru->proc;
  LTE_DL_FRAME_PARMS *fp      = &ru->frame_parms;
  int                ret;
1624 1625
  int                subframe =9;
  int                frame    =1023; 
1626 1627 1628
  cpu_set_t cpuset;
  CPU_ZERO(&cpuset);

Raymond Knopp's avatar
Raymond Knopp committed
1629 1630 1631

  // set default return value
  ru_thread_status = 0;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1632 1633 1634
#if defined(PRE_SCD_THREAD)
  dlsch_ue_select_tbl_in_use = 1;
#endif
Raymond Knopp's avatar
Raymond Knopp committed
1635 1636 1637


  // set default return value
1638
  thread_top_init("ru_thread",1,400000,500000,500000);
Raymond Knopp's avatar
Raymond Knopp committed
1639

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1640 1641
  //CPU_SET(1, &cpuset);
  //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
1642 1643
  pthread_setname_np( pthread_self(),"ru thread");
  LOG_I(PHY,"thread ru created id=%ld\n", syscall(__NR_gettid));
1644 1645 1646

  LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]);

1647
  if(get_softmodem_params()->emulate_rf){
1648 1649 1650 1651 1652 1653 1654
    fill_rf_config(ru,ru->rf_config_file);
    init_frame_parms(&ru->frame_parms,1);
    phy_init_RU(ru);
    if (setup_RU_buffers(ru)!=0) {
          printf("Exiting, cannot initialize RU Buffers\n");
          exit(-1);
    }
1655
  }
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676
  else{
    // Start IF device if any
    if (ru->start_if) {
      LOG_I(PHY,"Starting IF interface for RU %d\n",ru->idx);
      AssertFatal(ru->start_if(ru,NULL) == 0, "Could not start the IF device\n");
      if (ru->if_south == LOCAL_RF) ret = connect_rau(ru);
      else ret = attach_rru(ru);
      AssertFatal(ret==0,"Cannot connect to radio\n");
    }
    if (ru->if_south == LOCAL_RF) { // configure RF parameters only 
          fill_rf_config(ru,ru->rf_config_file);
          init_frame_parms(&ru->frame_parms,1);
          phy_init_RU(ru);
    
    
          ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
    }
    if (setup_RU_buffers(ru)!=0) {
          printf("Exiting, cannot initialize RU Buffers\n");
          exit(-1);
    }
1677
  }
1678

1679 1680 1681 1682 1683
  LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx);
  pthread_mutex_lock(&RC.ru_mutex);
  RC.ru_mask &= ~(1<<ru->idx);
  pthread_cond_signal(&RC.ru_cond);
  pthread_mutex_unlock(&RC.ru_mutex);
1684
  
1685
  
1686 1687 1688 1689
  pthread_mutex_lock(&proc->mutex_FH1);
  proc->instance_cnt_FH1 = 0;
  pthread_mutex_unlock(&proc->mutex_FH1);
  pthread_cond_signal(&proc->cond_FH1);
1690

1691
  wait_sync("ru_thread");
Raymond Knopp's avatar
Raymond Knopp committed
1692

1693
  if(!(get_softmodem_params()->emulate_rf)){
1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714
    // Start RF device if any
    if (ru->start_rf) {
      if (ru->start_rf(ru) != 0)
        LOG_E(HW,"Could not start the RF device\n");
      else LOG_I(PHY,"RU %d rf device ready\n",ru->idx);
    }
    else LOG_I(PHY,"RU %d no rf device\n",ru->idx);
    
    // if an asnych_rxtx thread exists
    // wakeup the thread because the devices are ready at this point
    
    if ((ru->fh_south_asynch_in)||(ru->fh_north_asynch_in)) {
      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);
    }
    else LOG_I(PHY,"RU %d no asynch_south interface\n",ru->idx);
    
    // if this is a slave RRU, try to synchronize on the DL frequency
    if ((ru->is_slave) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru);
1715 1716 1717 1718 1719
  }




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

1723 1724
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_CPUID_RU_THREAD,sched_getcpu());

Raymond Knopp's avatar
Raymond Knopp committed
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735
    // 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++;
    }      

    // synchronization on input FH interface, acquire signals/data and block
1736
    if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe);
Raymond Knopp's avatar
Raymond Knopp committed
1737 1738
    else AssertFatal(1==0, "No fronthaul interface at south port");

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
#ifdef PHY_TX_THREAD
    if(first_phy_tx == 0)
    {
        phy_tx_end = 0;
        phy_tx_txdataF_end = 0;
        if(pthread_mutex_lock(&ru->proc.mutex_phy_tx) != 0){
          LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for phy tx thread (IC %d)\n", ru->proc.instance_cnt_phy_tx);
          exit_fun( "error locking mutex_rxtx" );
        }
        if (ru->proc.instance_cnt_phy_tx==-1) {
          ++ru->proc.instance_cnt_phy_tx;

          // the thread can now be woken up
          AssertFatal(pthread_cond_signal(&ru->proc.cond_phy_tx) == 0, "ERROR pthread_cond_signal for phy_tx thread\n");
        }else{
          LOG_E(PHY,"phy tx thread busy, skipping\n");
          ++ru->proc.instance_cnt_phy_tx;
        }
        pthread_mutex_unlock( &ru->proc.mutex_phy_tx );
    } else {
        phy_tx_end = 1;
        phy_tx_txdataF_end = 1;
    }
    first_phy_tx = 0;
#endif
1764

1765 1766 1767 1768 1769

      LOG_D(PHY,"RU thread (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n",
          ru->do_prach,
          is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx),
          proc->frame_rx,proc->subframe_rx);
Cedric Roux's avatar
Cedric Roux committed
1770
    if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) {
1771 1772
      wakeup_prach_ru(ru);
    }
1773
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
1774 1775 1776
    else if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>1)) {
      wakeup_prach_ru_br(ru);
    }
1777
#endif
1778 1779 1780 1781 1782

    // adjust for timing offset between RU
    if (ru->idx!=0) proc->frame_tx = (proc->frame_tx+proc->frame_offset)&1023;


Raymond Knopp's avatar
Raymond Knopp committed
1783
    // do RX front-end processing (frequency-shift, dft) if needed
1784
    if (ru->feprx) ru->feprx(ru);
Raymond Knopp's avatar
Raymond Knopp committed
1785 1786 1787 1788 1789

    // 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);

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1790 1791 1792 1793 1794 1795 1796 1797 1798
#if defined(PRE_SCD_THREAD)
    new_dlsch_ue_select_tbl_in_use = dlsch_ue_select_tbl_in_use;
    dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use;
    memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX);
    memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX);
    if (pthread_mutex_lock(&ru->proc.mutex_pre_scd)!= 0) {
        LOG_E( PHY, "[eNB] error locking proc mutex for eNB pre scd\n");
        exit_fun("error locking mutex_time");
    }
1799

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1800
    ru->proc.instance_pre_scd++;
Raymond Knopp's avatar
Raymond Knopp committed
1801

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1802 1803 1804 1805 1806 1807 1808 1809 1810
    if (ru->proc.instance_pre_scd == 0) {
        if (pthread_cond_signal(&ru->proc.cond_pre_scd) != 0) {
            LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB pre scd\n" );
            exit_fun( "ERROR pthread_cond_signal cond_pre_scd" );
        }
    }else{
        LOG_E( PHY, "[eNB] frame %d subframe %d rxtx busy instance_pre_scd %d\n",
               frame,subframe,ru->proc.instance_pre_scd );
    }
1811

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1812 1813 1814 1815 1816
    if (pthread_mutex_unlock(&ru->proc.mutex_pre_scd)!= 0) {
        LOG_E( PHY, "[eNB] error unlocking mutex_pre_scd mutex for eNB pre scd\n");
        exit_fun("error unlocking mutex_pre_scd");
    }
#endif
1817

Raymond Knopp's avatar
Raymond Knopp committed
1818
    // wakeup all eNB processes waiting for this RU
1819
    if (ru->num_eNB>0) wakeup_L1s(ru);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1820
    
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1821
#ifndef PHY_TX_THREAD
1822
    if(get_thread_parallel_conf() == PARALLEL_SINGLE_THREAD || ru->num_eNB==0){
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1823 1824 1825 1826 1827
      // do TX front-end processing if needed (precoding and/or IDFTs)
      if (ru->feptx_prec) ru->feptx_prec(ru);
      
      // do OFDM if needed
      if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
1828
      if(!(get_softmodem_params()->emulate_rf)){
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1829 1830 1831 1832
        // do outgoing fronthaul (south) if needed
        if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);
        
        if (ru->fh_north_out) ru->fh_north_out(ru);
1833
      }
1834
      proc->emulate_rf_busy = 0;
1835
    }
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845
#else
    struct timespec time_req, time_rem;
    time_req.tv_sec = 0;
    time_req.tv_nsec = 10000;

    while((!oai_exit)&&(phy_tx_end == 0)){
        nanosleep(&time_req,&time_rem);
        continue;
    }
#endif
Raymond Knopp's avatar
Raymond Knopp committed
1846 1847 1848 1849
  }
  

  printf( "Exiting ru_thread \n");
1850

1851
  if (!(get_softmodem_params()->emulate_rf)){
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1852 1853 1854 1855 1856
    if (ru->stop_rf != NULL) {
      if (ru->stop_rf(ru) != 0)
        LOG_E(HW,"Could not stop the RF device\n");
      else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx);
    }
1857 1858
  }

Raymond Knopp's avatar
Raymond Knopp committed
1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872
  ru_thread_status = 0;
  return &ru_thread_status;

}


// This thread run the initial synchronization like a UE
void *ru_thread_synch(void *arg) {

  RU_t *ru = (RU_t*)arg;
  LTE_DL_FRAME_PARMS *fp=&ru->frame_parms;
  int32_t sync_pos,sync_pos2;
  uint32_t peak_val;
  uint32_t sync_corr[307200] __attribute__((aligned(32)));
1873
  static int ru_thread_synch_status;
Raymond Knopp's avatar
Raymond Knopp committed
1874 1875 1876 1877 1878 1879 1880


  thread_top_init("ru_thread_synch",0,5000000,10000000,10000000);

  wait_sync("ru_thread_synch");

  // initialize variables for PSS detection
1881
  lte_sync_time_init(&ru->frame_parms);
Raymond Knopp's avatar
Raymond Knopp committed
1882 1883 1884 1885

  while (!oai_exit) {

    // wait to be woken up
1886
    if (wait_on_condition(&ru->proc.mutex_synch,&ru->proc.cond_synch,&ru->proc.instance_cnt_synch,"ru_thread_synch")<0) break;
Raymond Knopp's avatar
Raymond Knopp committed
1887 1888 1889 1890 1891 1892

    // if we're not in synch, then run initial synch
    if (ru->in_synch == 0) { 
      // run intial synch like UE
      LOG_I(PHY,"Running initial synchronization\n");
      
1893
      sync_pos = lte_sync_time_eNB(ru->common.rxdata,
Raymond Knopp's avatar
Raymond Knopp committed
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
				   fp,
				   fp->samples_per_tti*5,
				   &peak_val,
				   sync_corr);
      LOG_I(PHY,"RU synch: %d, val %d\n",sync_pos,peak_val);

      if (sync_pos >= 0) {
	if (sync_pos >= fp->nb_prefix_samples)
	  sync_pos2 = sync_pos - fp->nb_prefix_samples;
	else
	  sync_pos2 = sync_pos + (fp->samples_per_tti*10) - fp->nb_prefix_samples;
	
	if (fp->frame_type == FDD) {
	  
	  // PSS is hypothesized in last symbol of first slot in Frame
	  int sync_pos_slot = (fp->samples_per_tti>>1) - fp->ofdm_symbol_size - fp->nb_prefix_samples;
	  
	  if (sync_pos2 >= sync_pos_slot)
	    ru->rx_offset = sync_pos2 - sync_pos_slot;
	  else
	    ru->rx_offset = (fp->samples_per_tti*10) + sync_pos2 - sync_pos_slot;
	}
	else {
	  
	}

	LOG_I(PHY,"Estimated sync_pos %d, peak_val %d => timing offset %d\n",sync_pos,peak_val,ru->rx_offset);
	
1922 1923 1924 1925 1926 1927 1928
        if (LOG_DEBUGFLAG(RU)) {	
	  if ((peak_val > 300000) && (sync_pos > 0)) {
	     LOG_M("ru_sync.m","sync",(void*)&sync_corr[0],fp->samples_per_tti*5,1,2);
	     LOG_M("ru_rx.m","rxs",&(ru->eNB_list[0]->common_vars.rxdata[0][0]),fp->samples_per_tti*10,1,1);
	  exit(-1);
	  }
        }
Raymond Knopp's avatar
Raymond Knopp committed
1929 1930 1931 1932 1933 1934 1935
	ru->in_synch=1;
      }
    }

    if (release_thread(&ru->proc.mutex_synch,&ru->proc.instance_cnt_synch,"ru_synch_thread") < 0) break;
  } // oai_exit

1936 1937 1938
  ru_thread_synch_status = 0;
  return &ru_thread_synch_status;

Raymond Knopp's avatar
Raymond Knopp committed
1939 1940
}

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1941 1942 1943 1944 1945 1946 1947 1948 1949 1950
#if defined(PRE_SCD_THREAD)
void* pre_scd_thread( void* param ){
    static int              eNB_pre_scd_status;
    protocol_ctxt_t         ctxt;
    int                     frame;
    int                     subframe;
    int                     min_rb_unit[MAX_NUM_CCs];
    int                     CC_id;
    int                     Mod_id;
    RU_t               *ru      = (RU_t*)param;
1951 1952 1953 1954 1955 1956

    // L2-emulator can work only one eNB
    if( nfapi_mode == 2)
       Mod_id = 0;
    else 
       Mod_id = ru->eNB_list[0]->Mod_id;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001

    frame = 0;
    subframe = 4;
    thread_top_init("pre_scd_thread",0,870000,1000000,1000000);

    while (!oai_exit) {
        if(oai_exit){
            break;
        }
        pthread_mutex_lock(&ru->proc.mutex_pre_scd );
        if (ru->proc.instance_pre_scd < 0) {
          pthread_cond_wait(&ru->proc.cond_pre_scd, &ru->proc.mutex_pre_scd);
        }
        pthread_mutex_unlock(&ru->proc.mutex_pre_scd);
        PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, Mod_id, ENB_FLAG_YES,
                 NOT_A_RNTI, frame, subframe,Mod_id);
        pdcp_run(&ctxt);

        for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {

          rrc_rx_tx(&ctxt, CC_id);
          min_rb_unit[CC_id] = get_min_rb_unit(Mod_id, CC_id);
        }

        pre_scd_nb_rbs_required(Mod_id, frame, subframe,min_rb_unit,pre_nb_rbs_required[new_dlsch_ue_select_tbl_in_use]);

        if (subframe==9) {
          subframe=0;
          frame++;
          frame&=1023;
        } else {
          subframe++;
        }
        pthread_mutex_lock(&ru->proc.mutex_pre_scd );
        ru->proc.instance_pre_scd--;
        pthread_mutex_unlock(&ru->proc.mutex_pre_scd);
    }
    eNB_pre_scd_status = 0;
    return &eNB_pre_scd_status;
}
#endif

#ifdef PHY_TX_THREAD
/*!
 * \brief The phy tx thread of eNB.
2002
 * \param param is a \ref L1_proc_t structure which contains the info what to process.
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
static void* eNB_thread_phy_tx( void* param ) {
  static int eNB_thread_phy_tx_status;


  RU_t *ru      = (RU_t*)param;
  RU_proc_t *proc = &ru->proc;
  PHY_VARS_eNB **eNB_list = ru->eNB_list;

2013
  L1_rxtx_proc_t L1_proc;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029

  // set default return value
  eNB_thread_phy_tx_status = 0;

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


  while (!oai_exit) {

    if (oai_exit) break;


    if (wait_on_condition(&proc->mutex_phy_tx,&proc->cond_phy_tx,&proc->instance_cnt_phy_tx,"eNB_phy_tx_thread") < 0) break;

    LOG_D(PHY,"Running eNB phy tx procedures\n");
    if(ru->num_eNB == 1){
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2030 2031 2032
       L1_proc.subframe_tx = proc->subframe_phy_tx;
       L1_proc.frame_tx = proc->frame_phy_tx;
       phy_procedures_eNB_TX(eNB_list[0], &L1_proc, 1);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107
       phy_tx_txdataF_end = 1;
       if(pthread_mutex_lock(&ru->proc.mutex_rf_tx) != 0){
          LOG_E( PHY, "[RU] ERROR pthread_mutex_lock for rf tx thread (IC %d)\n", ru->proc.instance_cnt_rf_tx);
          exit_fun( "error locking mutex_rf_tx" );
        }
        if (ru->proc.instance_cnt_rf_tx==-1) {
          ++ru->proc.instance_cnt_rf_tx;
          ru->proc.frame_tx = proc->frame_phy_tx;
          ru->proc.subframe_tx = proc->subframe_phy_tx;
          ru->proc.timestamp_tx = proc->timestamp_phy_tx;

          // the thread can now be woken up
          AssertFatal(pthread_cond_signal(&ru->proc.cond_rf_tx) == 0, "ERROR pthread_cond_signal for rf_tx thread\n");
        }else{
          LOG_E(PHY,"rf tx thread busy, skipping\n");
          late_control=STATE_BURST_TERMINATE;
        }
        pthread_mutex_unlock( &ru->proc.mutex_rf_tx );
    }
    if (release_thread(&proc->mutex_phy_tx,&proc->instance_cnt_phy_tx,"eNB_thread_phy_tx") < 0) break;
    phy_tx_end = 1;
  }

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

  eNB_thread_phy_tx_status = 0;
  return &eNB_thread_phy_tx_status;
}


static void* rf_tx( void* param ) {
  static int rf_tx_status;

  RU_t *ru      = (RU_t*)param;
  RU_proc_t *proc = &ru->proc;

  // set default return value
  rf_tx_status = 0;

  thread_top_init("rf_tx",1,500000L,1000000L,20000000L);
  
  while (!oai_exit) {

    if (oai_exit) break;


    if (wait_on_condition(&proc->mutex_rf_tx,&proc->cond_rf_tx,&proc->instance_cnt_rf_tx,"rf_tx_thread") < 0) break;

    LOG_D(PHY,"Running eNB rf tx procedures\n");
    if(ru->num_eNB == 1){
       // do TX front-end processing if needed (precoding and/or IDFTs)
       if (ru->feptx_prec) ru->feptx_prec(ru);
       // do OFDM if needed
       if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru);
       if(!emulate_rf){
         // do outgoing fronthaul (south) if needed
         if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru);

         if (ru->fh_north_out) ru->fh_north_out(ru);
       }
    }
    if (release_thread(&proc->mutex_rf_tx,&proc->instance_cnt_rf_tx,"rf_tx") < 0) break;
    if(proc->instance_cnt_rf_tx >= 0){
      late_control=STATE_BURST_TERMINATE;
      LOG_E(PHY,"detect rf tx busy change mode TX failsafe\n");
    }
  }

  LOG_I(PHY, "Exiting rf TX\n");

  rf_tx_status = 0;
  return &rf_tx_status;
}
#endif

Raymond Knopp's avatar
Raymond Knopp committed
2108

2109 2110 2111 2112 2113 2114 2115 2116 2117
 
int start_if(struct RU_t_s *ru,struct PHY_VARS_eNB_s *eNB) {
  return(ru->ifdevice.trx_start_func(&ru->ifdevice));
}

int start_rf(RU_t *ru) {
  return(ru->rfdevice.trx_start_func(&ru->rfdevice));
}

2118 2119 2120 2121 2122 2123
int stop_rf(RU_t *ru)
{
  ru->rfdevice.trx_end_func(&ru->rfdevice);
  return 0;
}

2124
extern void fep_full(RU_t *ru);
2125
extern void ru_fep_full_2thread(RU_t *ru);
2126
extern void feptx_ofdm(RU_t *ru);
2127
extern void feptx_ofdm_2thread(RU_t *ru);
2128
extern void feptx_prec(RU_t *ru);
2129 2130
extern void init_fep_thread(RU_t *ru,pthread_attr_t *attr);
extern void init_feptx_thread(RU_t *ru,pthread_attr_t *attr);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2131 2132
extern void kill_fep_thread(RU_t *ru);
extern void kill_feptx_thread(RU_t *ru);
2133 2134 2135 2136 2137

void init_RU_proc(RU_t *ru) {
   
  int i=0;
  RU_proc_t *proc;
2138
  pthread_attr_t *attr_FH=NULL,*attr_FH1=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_synch=NULL,*attr_emulateRF=NULL;
2139
  //pthread_attr_t *attr_fep=NULL;
2140
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
2141 2142
  pthread_attr_t *attr_prach_br=NULL;
#endif
2143 2144 2145
  char name[100];

#ifndef OCP_FRAMEWORK
2146
  LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]);
2147 2148 2149 2150 2151 2152
#endif
  proc = &ru->proc;
  memset((void*)proc,0,sizeof(RU_proc_t));

  proc->ru = ru;
  proc->instance_cnt_prach       = -1;
2153
  proc->instance_cnt_synch       = -1;
2154
  proc->instance_cnt_FH          = -1;
2155
  proc->instance_cnt_FH1         = -1;
2156
  proc->instance_cnt_emulateRF   = -1;
2157
  proc->instance_cnt_asynch_rxtx = -1;
2158
  proc->instance_cnt_eNBs        = -1;
2159 2160 2161 2162
  proc->first_rx                 = 1;
  proc->first_tx                 = 1;
  proc->frame_offset             = 0;
  proc->num_slaves               = 0;
2163 2164
  proc->frame_tx_unwrap          = 0;

2165
  for (i=0;i<10;i++) proc->symbol_mask[i]=0;
Raymond Knopp's avatar
Raymond Knopp committed
2166
  
2167 2168 2169 2170
  pthread_mutex_init( &proc->mutex_prach, NULL);
  pthread_mutex_init( &proc->mutex_asynch_rxtx, NULL);
  pthread_mutex_init( &proc->mutex_synch,NULL);
  pthread_mutex_init( &proc->mutex_FH,NULL);
2171
  pthread_mutex_init( &proc->mutex_FH1,NULL);
2172
  pthread_mutex_init( &proc->mutex_emulateRF,NULL);
2173
  pthread_mutex_init( &proc->mutex_eNBs, NULL);
2174 2175 2176
  
  pthread_cond_init( &proc->cond_prach, NULL);
  pthread_cond_init( &proc->cond_FH, NULL);
2177
  pthread_cond_init( &proc->cond_FH1, NULL);
2178
  pthread_cond_init( &proc->cond_emulateRF, NULL);
2179 2180
  pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
  pthread_cond_init( &proc->cond_synch,NULL);
2181
  pthread_cond_init( &proc->cond_eNBs, NULL);
2182 2183
  
  pthread_attr_init( &proc->attr_FH);
2184
  pthread_attr_init( &proc->attr_FH1);
2185
  pthread_attr_init( &proc->attr_emulateRF);
2186 2187 2188 2189
  pthread_attr_init( &proc->attr_prach);
  pthread_attr_init( &proc->attr_synch);
  pthread_attr_init( &proc->attr_asynch_rxtx);
  pthread_attr_init( &proc->attr_fep);
2190

2191
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
2192 2193 2194 2195 2196
  proc->instance_cnt_prach_br       = -1;
  pthread_mutex_init( &proc->mutex_prach_br, NULL);
  pthread_cond_init( &proc->cond_prach_br, NULL);
  pthread_attr_init( &proc->attr_prach_br);
#endif  
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2197 2198 2199 2200 2201 2202 2203 2204 2205

#ifdef PHY_TX_THREAD
  proc->instance_cnt_phy_tx       = -1;
  pthread_mutex_init( &proc->mutex_phy_tx, NULL);
  pthread_cond_init( &proc->cond_phy_tx, NULL);
  proc->instance_cnt_rf_tx       = -1;
  pthread_mutex_init( &proc->mutex_rf_tx, NULL);
  pthread_cond_init( &proc->cond_rf_tx, NULL);
#endif
2206 2207
  
#ifndef DEADLINE_SCHEDULER
2208
  attr_FH        = &proc->attr_FH;
2209
  attr_FH1       = &proc->attr_FH1;
2210 2211 2212
  attr_prach     = &proc->attr_prach;
  attr_synch     = &proc->attr_synch;
  attr_asynch    = &proc->attr_asynch_rxtx;
2213
  attr_emulateRF = &proc->attr_emulateRF;
2214
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
2215 2216
  attr_prach_br  = &proc->attr_prach_br;
#endif
2217 2218 2219
#endif
  
  pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void*)ru );
Raymond Knopp's avatar
Raymond Knopp committed
2220

Wang Tsu-Han's avatar
Wang Tsu-Han committed
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234
#if defined(PRE_SCD_THREAD)
    proc->instance_pre_scd = -1;
    pthread_mutex_init( &proc->mutex_pre_scd, NULL);
    pthread_cond_init( &proc->cond_pre_scd, NULL);
    pthread_create(&proc->pthread_pre_scd, NULL, pre_scd_thread, (void*)ru);
    pthread_setname_np(proc->pthread_pre_scd, "pre_scd_thread");
#endif

#ifdef PHY_TX_THREAD
    pthread_create( &proc->pthread_phy_tx, NULL, eNB_thread_phy_tx, (void*)ru );
    pthread_setname_np( proc->pthread_phy_tx, "phy_tx_thread" );
    pthread_create( &proc->pthread_rf_tx, NULL, rf_tx, (void*)ru );
#endif

2235
  if(get_softmodem_params()->emulate_rf)
2236
    pthread_create( &proc->pthread_emulateRF, attr_emulateRF, emulatedRF_thread, (void*)proc );
2237

2238
  if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)
2239
    pthread_create( &proc->pthread_FH1, attr_FH1, ru_thread_tx, (void*)ru );
Raymond Knopp's avatar
Raymond Knopp committed
2240

2241 2242
  if (ru->function == NGFI_RRU_IF4p5) {
    pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru );
2243
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))  
2244 2245
    pthread_create( &proc->pthread_prach_br, attr_prach_br, ru_thread_prach_br, (void*)ru );
#endif
2246 2247 2248 2249 2250
    if (ru->is_slave == 1) pthread_create( &proc->pthread_synch, attr_synch, ru_thread_synch, (void*)ru);
    
    
    if ((ru->if_timing == synch_to_other) ||
	(ru->function == NGFI_RRU_IF5) ||
2251 2252 2253 2254
	(ru->function == NGFI_RRU_IF4p5)) 
	{
		pthread_create( &proc->pthread_asynch_rxtx, attr_asynch, ru_thread_asynch_rxtx, (void*)ru );
	}
2255 2256 2257 2258
    
    snprintf( name, sizeof(name), "ru_thread_FH %d", ru->idx );
    pthread_setname_np( proc->pthread_FH, name );
    
Raymond Knopp's avatar
Raymond Knopp committed
2259
  }
2260
  else if (ru->function == eNodeB_3GPP && ru->if_south == LOCAL_RF) { // DJP - need something else to distinguish between monolithic and PNF
Cedric Roux's avatar
Cedric Roux committed
2261
    LOG_I(PHY,"%s() DJP - added creation of pthread_prach\n", __FUNCTION__);
2262 2263
    pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru );
  }
2264

2265
  if (get_thread_worker_conf() == WORKER_ENABLE) { 
2266 2267
    init_fep_thread(ru,NULL); 
    init_feptx_thread(ru,NULL);
2268
  } 
2269
  if (opp_enabled == 1) pthread_create(&ru->ru_stats_thread,NULL,ru_stats_thread,(void*)ru); 
Raymond Knopp's avatar
Raymond Knopp committed
2270
  
2271 2272
}

Robert Schmidt's avatar
Robert Schmidt committed
2273
void kill_RU_proc(RU_t *ru)
Robert Schmidt's avatar
Robert Schmidt committed
2274 2275 2276
{
  RU_proc_t *proc = &ru->proc;

Robert Schmidt's avatar
Robert Schmidt committed
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302
#if defined(PRE_SCD_THREAD)
  pthread_mutex_lock(&proc->mutex_pre_scd);
  ru->proc.instance_pre_scd = 0;
  pthread_cond_signal(&proc->cond_pre_scd);
  pthread_mutex_unlock(&proc->mutex_pre_scd);
  pthread_join(proc->pthread_pre_scd, NULL);
  pthread_mutex_destroy(&proc->mutex_pre_scd);
  pthread_cond_destroy(&proc->cond_pre_scd);
#endif
#ifdef PHY_TX_THREAD
  pthread_mutex_lock(&proc->mutex_phy_tx);
  proc->instance_cnt_phy_tx = 0;
  pthread_cond_signal(&proc->cond_phy_tx);
  pthread_mutex_unlock(&proc->mutex_phy_tx);
  pthread_join(ru->proc.pthread_phy_tx, NULL);
  pthread_mutex_destroy( &proc->mutex_phy_tx);
  pthread_cond_destroy( &proc->cond_phy_tx);
  pthread_mutex_lock(&proc->mutex_rf_tx);
  proc->instance_cnt_rf_tx = 0;
  pthread_cond_signal(&proc->cond_rf_tx);
  pthread_mutex_unlock(&proc->mutex_rf_tx);
  pthread_join(proc->pthread_rf_tx, NULL);
  pthread_mutex_destroy( &proc->mutex_rf_tx);
  pthread_cond_destroy( &proc->cond_rf_tx);
#endif

2303
  if (get_thread_worker_conf() == WORKER_ENABLE) {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2304 2305 2306 2307 2308 2309
      LOG_D(PHY, "killing FEP thread\n"); 
      kill_fep_thread(ru);
      LOG_D(PHY, "killing FEP TX thread\n"); 
      kill_feptx_thread(ru);
  }

Robert Schmidt's avatar
Robert Schmidt committed
2310 2311 2312
  pthread_mutex_lock(&proc->mutex_FH);
  proc->instance_cnt_FH = 0;
  pthread_cond_signal(&proc->cond_FH);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2313 2314 2315 2316 2317 2318
  pthread_mutex_unlock(&proc->mutex_FH);

  pthread_mutex_lock(&proc->mutex_FH1);
  proc->instance_cnt_FH1 = 0;
  pthread_cond_signal(&proc->cond_FH1);
  pthread_mutex_unlock(&proc->mutex_FH1);
2319

Robert Schmidt's avatar
Robert Schmidt committed
2320 2321 2322
  pthread_mutex_lock(&proc->mutex_prach);
  proc->instance_cnt_prach = 0;
  pthread_cond_signal(&proc->cond_prach);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2323
  pthread_mutex_unlock(&proc->mutex_prach);
Robert Schmidt's avatar
Robert Schmidt committed
2324

2325
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
Robert Schmidt's avatar
Robert Schmidt committed
2326 2327 2328
  pthread_mutex_lock(&proc->mutex_prach_br);
  proc->instance_cnt_prach_br = 0;
  pthread_cond_signal(&proc->cond_prach_br);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2329
  pthread_mutex_unlock(&proc->mutex_prach_br);
Robert Schmidt's avatar
Robert Schmidt committed
2330
#endif
2331

Robert Schmidt's avatar
Robert Schmidt committed
2332 2333 2334
  pthread_mutex_lock(&proc->mutex_synch);
  proc->instance_cnt_synch = 0;
  pthread_cond_signal(&proc->cond_synch);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2335
  pthread_mutex_unlock(&proc->mutex_synch);
2336

Robert Schmidt's avatar
Robert Schmidt committed
2337
  pthread_mutex_lock(&proc->mutex_eNBs);
Robert Schmidt's avatar
Robert Schmidt committed
2338 2339 2340 2341
  proc->instance_cnt_eNBs = 1;
  // cond_eNBs is used by both ru_thread and ru_thread_tx, so we need to send
  // a broadcast to wake up both threads
  pthread_cond_broadcast(&proc->cond_eNBs);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2342
  pthread_mutex_unlock(&proc->mutex_eNBs);
2343

Robert Schmidt's avatar
Robert Schmidt committed
2344 2345 2346
  pthread_mutex_lock(&proc->mutex_asynch_rxtx);
  proc->instance_cnt_asynch_rxtx = 0;
  pthread_cond_signal(&proc->cond_asynch_rxtx);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2347
  pthread_mutex_unlock(&proc->mutex_asynch_rxtx);
Robert Schmidt's avatar
Robert Schmidt committed
2348

Robert Schmidt's avatar
Robert Schmidt committed
2349
  LOG_D(PHY, "Joining pthread_FH\n");
Robert Schmidt's avatar
Robert Schmidt committed
2350
  pthread_join(proc->pthread_FH, NULL);
2351
  if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) {
Robert Schmidt's avatar
Robert Schmidt committed
2352 2353 2354
    LOG_D(PHY, "Joining pthread_FHTX\n");
    pthread_join(proc->pthread_FH1, NULL);
  }
Robert Schmidt's avatar
Robert Schmidt committed
2355 2356 2357
  if (ru->function == NGFI_RRU_IF4p5) {
    LOG_D(PHY, "Joining pthread_prach\n");
    pthread_join(proc->pthread_prach, NULL);
2358
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
Robert Schmidt's avatar
Robert Schmidt committed
2359 2360 2361 2362 2363 2364 2365
    LOG_D(PHY, "Joining pthread_prach_br\n");
    pthread_join(proc->pthread_prach_br, NULL);
#endif
    if (ru->is_slave) {
      LOG_D(PHY, "Joining pthread_\n");
      pthread_join(proc->pthread_synch, NULL);
    }
2366

Robert Schmidt's avatar
Robert Schmidt committed
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382
    if ((ru->if_timing == synch_to_other) ||
        (ru->function == NGFI_RRU_IF5) ||
        (ru->function == NGFI_RRU_IF4p5)) {
      LOG_D(PHY, "Joining pthread_asynch_rxtx\n");
      pthread_join(proc->pthread_asynch_rxtx, NULL);
    }
  }
  if (opp_enabled) {
    LOG_D(PHY, "Joining ru_stats_thread\n");
    pthread_join(ru->ru_stats_thread, NULL);
  }

  pthread_mutex_destroy(&proc->mutex_prach);
  pthread_mutex_destroy(&proc->mutex_asynch_rxtx);
  pthread_mutex_destroy(&proc->mutex_synch);
  pthread_mutex_destroy(&proc->mutex_FH);
2383
  pthread_mutex_destroy(&proc->mutex_FH1);
Robert Schmidt's avatar
Robert Schmidt committed
2384
  pthread_mutex_destroy(&proc->mutex_eNBs);
2385

Robert Schmidt's avatar
Robert Schmidt committed
2386 2387
  pthread_cond_destroy(&proc->cond_prach);
  pthread_cond_destroy(&proc->cond_FH);
2388
  pthread_cond_destroy(&proc->cond_FH1);
Robert Schmidt's avatar
Robert Schmidt committed
2389 2390 2391
  pthread_cond_destroy(&proc->cond_asynch_rxtx);
  pthread_cond_destroy(&proc->cond_synch);
  pthread_cond_destroy(&proc->cond_eNBs);
2392

Robert Schmidt's avatar
Robert Schmidt committed
2393
  pthread_attr_destroy(&proc->attr_FH);
2394
  pthread_attr_destroy(&proc->attr_FH1);
Robert Schmidt's avatar
Robert Schmidt committed
2395 2396 2397 2398 2399
  pthread_attr_destroy(&proc->attr_prach);
  pthread_attr_destroy(&proc->attr_synch);
  pthread_attr_destroy(&proc->attr_asynch_rxtx);
  pthread_attr_destroy(&proc->attr_fep);

2400
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
Robert Schmidt's avatar
Robert Schmidt committed
2401 2402 2403 2404 2405
  pthread_mutex_destroy(&proc->mutex_prach_br);
  pthread_cond_destroy(&proc->cond_prach_br);
  pthread_attr_destroy(&proc->attr_prach_br);
#endif
}
Raymond Knopp's avatar
Raymond Knopp committed
2406

2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446
int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) {

  FH_fmt_options_t fmt = cap->FH_fmt;

  int i;
  int found_band=0;

  LOG_I(PHY,"RRU %d, num_bands %d, looking for band %d\n",ru->idx,cap->num_bands,ru->frame_parms.eutra_band);
  for (i=0;i<cap->num_bands;i++) {
    LOG_I(PHY,"band %d on RRU %d\n",cap->band_list[i],ru->idx);
    if (ru->frame_parms.eutra_band == cap->band_list[i]) {
      found_band=1;
      break;
    }
  }

  if (found_band == 0) {
    LOG_I(PHY,"Couldn't find target EUTRA band %d on RRU %d\n",ru->frame_parms.eutra_band,ru->idx);
    return(-1);
  }

  switch (ru->if_south) {
  case LOCAL_RF:
    AssertFatal(1==0, "This RU should not have a local RF, exiting\n");
    return(0);
    break;
  case REMOTE_IF5:
    if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5) return(0);
    break;
  case REMOTE_IF4p5:
    if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5) return(0);
    break;
  case REMOTE_MBP_IF5:
    if (fmt == MBP_IF5) return(0);
    break;
  default:
    LOG_I(PHY,"No compatible Fronthaul interface found for RRU %d\n", ru->idx);
    return(-1);
  }

Raymond Knopp's avatar
Raymond Knopp committed
2447
  return(-1);
Raymond Knopp's avatar
Raymond Knopp committed
2448 2449 2450
}


2451
char rru_format_options[4][20] = {"OAI_IF5_only","OAI_IF4p5_only","OAI_IF5_and_IF4p5","MBP_IF5"};
2452

2453
char rru_formats[3][20] = {"OAI_IF5","MBP_IF5","OAI_IF4p5"};
2454
char ru_if_formats[4][20] = {"LOCAL_RF","REMOTE_OAI_IF5","REMOTE_MBP_IF5","REMOTE_OAI_IF4p5"};
2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467

void configure_ru(int idx,
		  void *arg) {

  RU_t               *ru           = RC.ru[idx];
  RRU_config_t       *config       = (RRU_config_t *)arg;
  RRU_capabilities_t *capabilities = (RRU_capabilities_t*)arg;
  int ret;

  LOG_I(PHY, "Received capabilities from RRU %d\n",idx);


  if (capabilities->FH_fmt < MAX_FH_FMTs) LOG_I(PHY, "RU FH options %s\n",rru_format_options[capabilities->FH_fmt]);
2468 2469
  ret=check_capabilities(ru,capabilities);
  AssertFatal((ret == 0),
Raymond Knopp's avatar
Raymond Knopp committed
2470
	      "Cannot configure RRU %d, check_capabilities returned %d\n", idx,ret);
2471 2472 2473 2474
  // take antenna capabilities of RRU
  ru->nb_tx                      = capabilities->nb_tx[0];
  ru->nb_rx                      = capabilities->nb_rx[0];

Raymond Knopp's avatar
Raymond Knopp committed
2475 2476 2477 2478 2479 2480 2481 2482
  // Pass configuration to RRU
  LOG_I(PHY, "Using %s fronthaul (%d), band %d \n",ru_if_formats[ru->if_south],ru->if_south,ru->frame_parms.eutra_band);
  // wait for configuration 
  config->FH_fmt                 = ru->if_south;
  config->num_bands              = 1;
  config->band_list[0]           = ru->frame_parms.eutra_band;
  config->tx_freq[0]             = ru->frame_parms.dl_CarrierFreq;      
  config->rx_freq[0]             = ru->frame_parms.ul_CarrierFreq;      
2483 2484
  config->tdd_config[0]          = ru->frame_parms.tdd_config;
  config->tdd_config_S[0]        = ru->frame_parms.tdd_config_S;
Raymond Knopp's avatar
Raymond Knopp committed
2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495
  config->att_tx[0]              = ru->att_tx;
  config->att_rx[0]              = ru->att_rx;
  config->N_RB_DL[0]             = ru->frame_parms.N_RB_DL;
  config->N_RB_UL[0]             = ru->frame_parms.N_RB_UL;
  config->threequarter_fs[0]     = ru->frame_parms.threequarter_fs;
  if (ru->if_south==REMOTE_IF4p5) {
    config->prach_FreqOffset[0]  = ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset;
    config->prach_ConfigIndex[0] = ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
    LOG_I(PHY,"REMOTE_IF4p5: prach_FrequOffset %d, prach_ConfigIndex %d\n",
	  config->prach_FreqOffset[0],config->prach_ConfigIndex[0]);
    
2496
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
Cedric Roux's avatar
Cedric Roux committed
2497
    int i;
Raymond Knopp's avatar
Raymond Knopp committed
2498 2499 2500 2501
    for (i=0;i<4;i++) {
      config->emtc_prach_CElevel_enable[0][i]  = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i];
      config->emtc_prach_FreqOffset[0][i]      = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i];
      config->emtc_prach_ConfigIndex[0][i]     = ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i];
2502
    }
Raymond Knopp's avatar
Raymond Knopp committed
2503
#endif
2504 2505 2506 2507 2508 2509
  }

  init_frame_parms(&ru->frame_parms,1);
  phy_init_RU(ru);
}

2510 2511
void configure_rru(int idx,
		   void *arg) {
2512 2513 2514 2515 2516 2517 2518

  RRU_config_t *config = (RRU_config_t *)arg;
  RU_t         *ru         = RC.ru[idx];

  ru->frame_parms.eutra_band                                               = config->band_list[0];
  ru->frame_parms.dl_CarrierFreq                                           = config->tx_freq[0];
  ru->frame_parms.ul_CarrierFreq                                           = config->rx_freq[0];
2519
  if (ru->frame_parms.dl_CarrierFreq == ru->frame_parms.ul_CarrierFreq) {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2520 2521 2522 2523
    LOG_I(PHY,"Setting RRU to TDD frame type\n");
    ru->frame_parms.frame_type                                            = TDD;
    ru->frame_parms.tdd_config                                            = config->tdd_config[0];
    ru->frame_parms.tdd_config_S                                          = config->tdd_config_S[0]; 
2524
  }
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2525
  else ru->frame_parms.frame_type                                            = FDD;
2526 2527 2528 2529 2530 2531 2532
  ru->att_tx                                                               = config->att_tx[0];
  ru->att_rx                                                               = config->att_rx[0];
  ru->frame_parms.N_RB_DL                                                  = config->N_RB_DL[0];
  ru->frame_parms.N_RB_UL                                                  = config->N_RB_UL[0];
  ru->frame_parms.threequarter_fs                                          = config->threequarter_fs[0];
  ru->frame_parms.pdsch_config_common.referenceSignalPower                 = ru->max_pdschReferenceSignalPower-config->att_tx[0];
  if (ru->function==NGFI_RRU_IF4p5) {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
2533 2534 2535
    ru->frame_parms.att_rx = ru->att_rx;
    ru->frame_parms.att_tx = ru->att_tx;
    
2536 2537
    LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d, att (%d,%d)\n",
	  config->prach_FreqOffset[0],config->prach_ConfigIndex[0],ru->att_tx,ru->att_rx);
2538 2539
    ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset  = config->prach_FreqOffset[0]; 
    ru->frame_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; 
2540
#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
2541 2542 2543 2544 2545 2546
    for (int i=0;i<4;i++) {
      ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[i] = config->emtc_prach_CElevel_enable[0][i];
      ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_FreqOffset[i]     = config->emtc_prach_FreqOffset[0][i];
      ru->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_ConfigIndex[i]    = config->emtc_prach_ConfigIndex[0][i];
    }
#endif
2547 2548 2549 2550
  }
  
  init_frame_parms(&ru->frame_parms,1);

2551 2552
  fill_rf_config(ru,ru->rf_config_file);

2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569

  phy_init_RU(ru);

}

void init_precoding_weights(PHY_VARS_eNB *eNB) {

  int layer,ru_id,aa,re,ue,tb;
  LTE_DL_FRAME_PARMS *fp=&eNB->frame_parms;
  RU_t *ru;
  LTE_eNB_DLSCH_t *dlsch;

  // init precoding weigths
  for (ue=0;ue<NUMBER_OF_UE_MAX;ue++) {
    for (tb=0;tb<2;tb++) {
      dlsch = eNB->dlsch[ue][tb];
      for (layer=0; layer<4; layer++) {
2570 2571
	int nb_tx=0;
	for (ru_id=0;ru_id<RC.nb_RU;ru_id++) { 
2572
	  ru = RC.ru[ru_id];
2573 2574 2575
	  nb_tx+=ru->nb_tx;
	}
	dlsch->ue_spec_bf_weights[layer] = (int32_t**)malloc16(nb_tx*sizeof(int32_t*));
2576
	  
2577 2578 2579 2580
	for (aa=0; aa<nb_tx; aa++) {
	  dlsch->ue_spec_bf_weights[layer][aa] = (int32_t *)malloc16(fp->ofdm_symbol_size*sizeof(int32_t));
	  for (re=0;re<fp->ofdm_symbol_size; re++) {
	    dlsch->ue_spec_bf_weights[layer][aa][re] = 0x00007fff;
2581
	  }
2582
	}	
2583 2584 2585 2586 2587
      }
    }
  }
}

2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624
void set_function_spec_param(RU_t *ru)
{
  int ret;

  switch (ru->if_south) {
  case LOCAL_RF:   // this is an RU with integrated RF (RRU, eNB)
    if (ru->function ==  NGFI_RRU_IF5) {                 // IF5 RRU
      ru->do_prach              = 0;                      // no prach processing in RU
      ru->fh_north_in           = NULL;                   // no shynchronous incoming fronthaul from north
      ru->fh_north_out          = fh_if5_north_out;       // need only to do send_IF5  reception
      ru->fh_south_out          = tx_rf;                  // send output to RF
      ru->fh_north_asynch_in    = fh_if5_north_asynch_in; // TX packets come asynchronously
      ru->feprx                 = NULL;                   // nothing (this is a time-domain signal)
      ru->feptx_ofdm            = NULL;                   // nothing (this is a time-domain signal)
      ru->feptx_prec            = NULL;                   // nothing (this is a time-domain signal)
      ru->start_if              = start_if;               // need to start the if interface for if5
      ru->ifdevice.host_type    = RRU_HOST;
      ru->rfdevice.host_type    = RRU_HOST;
      ru->ifdevice.eth_params   = &ru->eth_params;
      reset_meas(&ru->rx_fhaul);
      reset_meas(&ru->tx_fhaul);
      reset_meas(&ru->compression);
      reset_meas(&ru->transport);

      ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
      printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
      if (ret<0) {
        printf("Exiting, cannot initialize transport protocol\n");
        exit(-1);
      }
    }
    else if (ru->function == NGFI_RRU_IF4p5) {
      ru->do_prach              = 1;                        // do part of prach processing in RU
      ru->fh_north_in           = NULL;                     // no synchronous incoming fronthaul from north
      ru->fh_north_out          = fh_if4p5_north_out;       // send_IF4p5 on reception
      ru->fh_south_out          = tx_rf;                    // send output to RF
      ru->fh_north_asynch_in    = fh_if4p5_north_asynch_in; // TX packets come asynchronously
2625 2626
      ru->feprx                 = (get_thread_worker_conf() == WORKER_DISABLE) ? fep_full :ru_fep_full_2thread;                 // RX DFTs
      ru->feptx_ofdm            = (get_thread_worker_conf() == WORKER_DISABLE) ? feptx_ofdm : feptx_ofdm_2thread;               // this is fep with idft only (no precoding in RRU)
2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646
      ru->feptx_prec            = NULL;
      ru->start_if              = start_if;                 // need to start the if interface for if4p5
      ru->ifdevice.host_type    = RRU_HOST;
      ru->rfdevice.host_type    = RRU_HOST;
      ru->ifdevice.eth_params   = &ru->eth_params;
      reset_meas(&ru->rx_fhaul);
      reset_meas(&ru->tx_fhaul);
      reset_meas(&ru->compression);
      reset_meas(&ru->transport);

      ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
      printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
      if (ret<0) {
        printf("Exiting, cannot initialize transport protocol\n");
        exit(-1);
      }
      malloc_IF4p5_buffer(ru);
    }
    else if (ru->function == eNodeB_3GPP) {
      ru->do_prach             = 0;                       // no prach processing in RU
2647 2648
      ru->feprx                = (get_thread_worker_conf() == WORKER_DISABLE) ? fep_full : ru_fep_full_2thread;                // RX DFTs
      ru->feptx_ofdm           = (get_thread_worker_conf() == WORKER_DISABLE) ? feptx_ofdm : feptx_ofdm_2thread;              // this is fep with idft and precoding
2649 2650 2651 2652 2653 2654 2655 2656 2657
      ru->feptx_prec           = feptx_prec;              // this is fep with idft and precoding
      ru->fh_north_in          = NULL;                    // no incoming fronthaul from north
      ru->fh_north_out         = NULL;                    // no outgoing fronthaul to north
      ru->start_if             = NULL;                    // no if interface
      ru->rfdevice.host_type   = RAU_HOST;
    }
    ru->fh_south_in            = rx_rf;                               // local synchronous RF RX
    ru->fh_south_out           = tx_rf;                               // local synchronous RF TX
    ru->start_rf               = start_rf;                            // need to start the local RF interface
2658
    ru->stop_rf                = stop_rf;
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675
    printf("configuring ru_id %d (start_rf %p)\n", ru->idx, start_rf);
/*
    if (ru->function == eNodeB_3GPP) { // configure RF parameters only for 3GPP eNodeB, we need to get them from RAU otherwise
      fill_rf_config(ru,rf_config_file);
      init_frame_parms(&ru->frame_parms,1);
      phy_init_RU(ru);
    }

    ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
    if (setup_RU_buffers(ru)!=0) {
      printf("Exiting, cannot initialize RU Buffers\n");
      exit(-1);
    }*/
    break;

  case REMOTE_IF5: // the remote unit is IF5 RRU
    ru->do_prach               = 0;
2676
    ru->feprx                  = (get_thread_worker_conf() == WORKER_DISABLE) ? fep_full : fep_full;                   // this is frequency-shift + DFTs
2677
    ru->feptx_prec             = feptx_prec;                 // need to do transmit Precoding + IDFTs
2678
    ru->feptx_ofdm             = (get_thread_worker_conf() == WORKER_DISABLE) ? feptx_ofdm : feptx_ofdm_2thread;                 // need to do transmit Precoding + IDFTs
2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689
    if (ru->if_timing == synch_to_other) {
      ru->fh_south_in          = fh_slave_south_in;                  // synchronize to master
      ru->fh_south_out         = fh_if5_mobipass_south_out;          // use send_IF5 for mobipass
      ru->fh_south_asynch_in   = fh_if5_south_asynch_in_mobipass;    // UL is asynchronous
    }
    else {
      ru->fh_south_in          = fh_if5_south_in;     // synchronous IF5 reception
      ru->fh_south_out         = fh_if5_south_out;    // synchronous IF5 transmission
      ru->fh_south_asynch_in   = NULL;                // no asynchronous UL
    }
    ru->start_rf               = NULL;                 // no local RF
2690
    ru->stop_rf                = NULL;
2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714
    ru->start_if               = start_if;             // need to start if interface for IF5
    ru->ifdevice.host_type     = RAU_HOST;
    ru->ifdevice.eth_params    = &ru->eth_params;
    ru->ifdevice.configure_rru = configure_ru;

    ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
    printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
    if (ret<0) {
      printf("Exiting, cannot initialize transport protocol\n");
      exit(-1);
    }
    break;

  case REMOTE_IF4p5:
    ru->do_prach               = 0;
    ru->feprx                  = NULL;                // DFTs
    ru->feptx_prec             = feptx_prec;          // Precoding operation
    ru->feptx_ofdm             = NULL;                // no OFDM mod
    ru->fh_south_in            = fh_if4p5_south_in;   // synchronous IF4p5 reception
    ru->fh_south_out           = fh_if4p5_south_out;  // synchronous IF4p5 transmission
    ru->fh_south_asynch_in     = (ru->if_timing == synch_to_other) ? fh_if4p5_south_in : NULL;                // asynchronous UL if synch_to_other
    ru->fh_north_out           = NULL;
    ru->fh_north_asynch_in     = NULL;
    ru->start_rf               = NULL;                // no local RF
2715
    ru->stop_rf                = NULL;
2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737
    ru->start_if               = start_if;            // need to start if interface for IF4p5
    ru->ifdevice.host_type     = RAU_HOST;
    ru->ifdevice.eth_params    = &ru->eth_params;
    ru->ifdevice.configure_rru = configure_ru;

    ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
    printf("openair0_transport_init returns %d for ru_id %d\n", ret, ru->idx);
    if (ret<0) {
      printf("Exiting, cannot initialize transport protocol\n");
      exit(-1);
    }

    malloc_IF4p5_buffer(ru);

    break;

  default:
    LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south);
    break;
  } // switch on interface type
}

Wang Tsu-Han's avatar
Wang Tsu-Han committed
2738
//extern void RCconfig_RU(void);
Raymond Knopp's avatar
Raymond Knopp committed
2739 2740

void init_RU(char *rf_config_file) {
Raymond Knopp's avatar
Raymond Knopp committed
2741 2742
  
  int ru_id;
2743
  RU_t *ru;
2744
  PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL;
2745 2746 2747 2748 2749 2750 2751 2752
  int i;
  int CC_id;

  // create status mask
  RC.ru_mask = 0;
  pthread_mutex_init(&RC.ru_mutex,NULL);
  pthread_cond_init(&RC.ru_cond,NULL);

2753 2754
  // read in configuration file)
  printf("configuring RU from file\n");
2755
  RCconfig_RU();
2756
  LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs());
2757

2758 2759 2760
  if (RC.nb_CC != 0)
    for (i=0;i<RC.nb_L1_inst;i++) 
      for (CC_id=0;CC_id<RC.nb_CC[i];CC_id++) RC.eNB[i][CC_id]->num_RU=0;
2761

Cedric Roux's avatar
Cedric Roux committed
2762
  LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);
2763
  for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
Cedric Roux's avatar
Cedric Roux committed
2764
    LOG_D(PHY,"Process RC.ru[%d]\n",ru_id);
2765
    ru               = RC.ru[ru_id];
2766
    ru->rf_config_file = rf_config_file;
2767 2768 2769 2770
    ru->idx          = ru_id;              
    ru->ts_offset    = 0;
    // use eNB_list[0] as a reference for RU frame parameters
    // NOTE: multiple CC_id are not handled here yet!
Raymond Knopp's avatar
Raymond Knopp committed
2771

2772

2773 2774
    if (ru->num_eNB > 0) {
      LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file);
2775

2776 2777 2778 2779 2780
      if (ru->eNB_list[0] == 0)
      {
        LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__);
        ru->eNB_list[0] = RC.eNB[0][0];
        ru->num_eNB=1;
2781 2782 2783
      //
      // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU
      //
2784

Raymond Knopp's avatar
Raymond Knopp committed
2785
      }
2786 2787 2788
      else
      {
        LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__);
Raymond Knopp's avatar
Raymond Knopp committed
2789
      }
2790
    }
2791
    eNB0             = ru->eNB_list[0];
Cedric Roux's avatar
Cedric Roux committed
2792 2793
    LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
    LOG_D(PHY, "eNB0:%p\n", eNB0);
2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
    if (eNB0)
    {
      if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5))
        AssertFatal(eNB0!=NULL,"eNB0 is null!\n");

      if (eNB0) {
        LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx);
        memcpy((void*)&ru->frame_parms,(void*)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS));

        // attach all RU to all eNBs in its list/
Cedric Roux's avatar
Cedric Roux committed
2804
        LOG_D(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU);
2805 2806 2807 2808
        for (i=0;i<ru->num_eNB;i++) {
          eNB0 = ru->eNB_list[i];
          eNB0->RU_list[eNB0->num_RU++] = ru;
        }
Raymond Knopp's avatar
Raymond Knopp committed
2809
      }
2810
    }
2811
        LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function);
Raymond Knopp's avatar
Raymond Knopp committed
2812

2813
    set_function_spec_param(ru);
2814 2815 2816 2817 2818 2819
    LOG_I(PHY,"Starting ru_thread %d\n",ru_id);

    init_RU_proc(ru);



Raymond Knopp's avatar
Raymond Knopp committed
2820 2821
  } // for ru_id

2822
  //  sleep(1);
2823
  LOG_D(HW,"[lte-softmodem.c] RU threads created\n");
Raymond Knopp's avatar
Raymond Knopp committed
2824 2825 2826 2827
  

}

Robert Schmidt's avatar
Robert Schmidt committed
2828 2829 2830 2831
void stop_RU(int nb_ru)
{
  for (int inst = 0; inst < nb_ru; inst++) {
    LOG_I(PHY, "Stopping RU %d processing threads\n", inst);
Robert Schmidt's avatar
Robert Schmidt committed
2832
    kill_RU_proc(RC.ru[inst]);
Robert Schmidt's avatar
Robert Schmidt committed
2833
  }
Raymond Knopp's avatar
Raymond Knopp committed
2834 2835
}

2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943
//Some of the member of ru pointer is used in pre_scd.
//This funtion is for initializing ru pointer for L2 FAPI simulator.
#if defined(PRE_SCD_THREAD)
void init_ru_vnf(void) {
  
  int ru_id;
  RU_t *ru;
  RU_proc_t *proc;
//  PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL;
  int i;
  int CC_id;


  dlsch_ue_select_tbl_in_use = 1;


  // create status mask
  RC.ru_mask = 0;
  pthread_mutex_init(&RC.ru_mutex,NULL);
  pthread_cond_init(&RC.ru_cond,NULL);

  // read in configuration file)
  printf("configuring RU from file\n");
  RCconfig_RU();
  LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs());

  if (RC.nb_CC != 0)
    for (i=0;i<RC.nb_L1_inst;i++) 
      for (CC_id=0;CC_id<RC.nb_CC[i];CC_id++) RC.eNB[i][CC_id]->num_RU=0;

  LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);
  for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
    LOG_D(PHY,"Process RC.ru[%d]\n",ru_id);
    ru               = RC.ru[ru_id];
//    ru->rf_config_file = rf_config_file;
    ru->idx          = ru_id;              
    ru->ts_offset    = 0;
    // use eNB_list[0] as a reference for RU frame parameters
    // NOTE: multiple CC_id are not handled here yet!

    if (ru->num_eNB > 0) {
//      LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file);

      if (ru->eNB_list[0] == 0)
      {
        LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__);
        ru->eNB_list[0] = RC.eNB[0][0];
        ru->num_eNB=1;
      //
      // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU
      //
      }
      else
      {
        LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__);
      }
    }

// frame_parms is not used in L2 FAPI simulator
/*
    eNB0             = ru->eNB_list[0];
    LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
    LOG_D(PHY, "eNB0:%p\n", eNB0);
    if (eNB0)
    {
      if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5))
        AssertFatal(eNB0!=NULL,"eNB0 is null!\n");

      if (eNB0) {
        LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx);
        memcpy((void*)&ru->frame_parms,(void*)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS));

        // attach all RU to all eNBs in its list/
        LOG_D(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU);
        for (i=0;i<ru->num_eNB;i++) {
          eNB0 = ru->eNB_list[i];
          eNB0->RU_list[eNB0->num_RU++] = ru;
        }
      }
    }
*/
    LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function);

//    set_function_spec_param(ru);
    LOG_I(PHY,"Starting ru_thread %d\n",ru_id);

//    init_RU_proc(ru);
  
    proc = &ru->proc;
    memset((void*)proc,0,sizeof(RU_proc_t));

    proc->instance_pre_scd = -1;
    pthread_mutex_init( &proc->mutex_pre_scd, NULL);
    pthread_cond_init( &proc->cond_pre_scd, NULL);
    pthread_create(&proc->pthread_pre_scd, NULL, pre_scd_thread, (void*)ru);
    pthread_setname_np(proc->pthread_pre_scd, "pre_scd_thread");

  } // for ru_id
  


  //  sleep(1);
  LOG_D(HW,"[lte-softmodem.c] RU threads created\n");
  

}
#endif

Raymond Knopp's avatar
Raymond Knopp committed
2944

2945 2946 2947
/* --------------------------------------------------------*/
/* from here function to use configuration module          */
void RCconfig_RU(void) {
Raymond Knopp's avatar
Raymond Knopp committed
2948
  
2949 2950
  int               j                             = 0;
  int               i                             = 0;
2951

2952 2953 2954
  
  paramdef_t RUParams[] = RUPARAMS_DESC;
  paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
Raymond Knopp's avatar
Raymond Knopp committed
2955 2956


2957 2958
  config_getlist( &RUParamList,RUParams,sizeof(RUParams)/sizeof(paramdef_t), NULL);  

Raymond Knopp's avatar
Raymond Knopp committed
2959
  
2960
  if ( RUParamList.numelt > 0) {
2961

2962 2963 2964 2965 2966
    RC.ru = (RU_t**)malloc(RC.nb_RU*sizeof(RU_t*));
   



Wang Tsu-Han's avatar
Wang Tsu-Han committed
2967
    RC.ru_mask=(1<<RC.nb_RU) - 1;
2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984
    printf("Set RU mask to %lx\n",RC.ru_mask);

    for (j = 0; j < RC.nb_RU; j++) {

      RC.ru[j]                                    = (RU_t*)malloc(sizeof(RU_t));
      memset((void*)RC.ru[j],0,sizeof(RU_t));
      RC.ru[j]->idx                                 = j;

      printf("Creating RC.ru[%d]:%p\n", j, RC.ru[j]);

      RC.ru[j]->if_timing                           = synch_to_ext_device;
      if (RC.nb_L1_inst >0)
        RC.ru[j]->num_eNB                           = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt;
      else
	    RC.ru[j]->num_eNB                           = 0;
      for (i=0;i<RC.ru[j]->num_eNB;i++) RC.ru[j]->eNB_list[i] = RC.eNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0];     

2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002
      if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) {
        RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr));
      }

      if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) {
        if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) {
          RC.ru[j]->openair0_cfg.clock_source = internal;
          LOG_D(PHY, "RU clock source set as internal\n");
        } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) {
          RC.ru[j]->openair0_cfg.clock_source = external;
          LOG_D(PHY, "RU clock source set as external\n");
        } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) {
          RC.ru[j]->openair0_cfg.clock_source = gpsdo;
          LOG_D(PHY, "RU clock source set as gpsdo\n");
        } else {
          LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr));
        }
      }
3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082

      if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) {
	if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) {
	  RC.ru[j]->if_south                        = LOCAL_RF;
	  RC.ru[j]->function                        = eNodeB_3GPP;
	  printf("Setting function for RU %d to eNodeB_3GPP\n",j);
        }
        else { 
          RC.ru[j]->eth_params.local_if_name            = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));    
          RC.ru[j]->eth_params.my_addr                  = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); 
          RC.ru[j]->eth_params.remote_addr              = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
          RC.ru[j]->eth_params.my_portc                 = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
          RC.ru[j]->eth_params.remote_portc             = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
          RC.ru[j]->eth_params.my_portd                 = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
          RC.ru[j]->eth_params.remote_portd             = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);

	  if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) {
	    RC.ru[j]->if_south                        = LOCAL_RF;
	    RC.ru[j]->function                        = NGFI_RRU_IF5;
	    RC.ru[j]->eth_params.transp_preference    = ETH_UDP_MODE;
	    printf("Setting function for RU %d to NGFI_RRU_IF5 (udp)\n",j);
	  } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
	    RC.ru[j]->if_south                        = LOCAL_RF;
	    RC.ru[j]->function                        = NGFI_RRU_IF5;
	    RC.ru[j]->eth_params.transp_preference    = ETH_RAW_MODE;
	    printf("Setting function for RU %d to NGFI_RRU_IF5 (raw)\n",j);
	  } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
	    RC.ru[j]->if_south                        = LOCAL_RF;
	    RC.ru[j]->function                        = NGFI_RRU_IF4p5;
	    RC.ru[j]->eth_params.transp_preference    = ETH_UDP_IF4p5_MODE;
	    printf("Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n",j);
	  } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
	    RC.ru[j]->if_south                        = LOCAL_RF;
	    RC.ru[j]->function                        = NGFI_RRU_IF4p5;
	    RC.ru[j]->eth_params.transp_preference    = ETH_RAW_IF4p5_MODE;
	    printf("Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n",j);
	  }
	}
	RC.ru[j]->max_pdschReferenceSignalPower     = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);;
	RC.ru[j]->max_rxgain                        = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr);
	RC.ru[j]->num_bands                         = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt;
	for (i=0;i<RC.ru[j]->num_bands;i++) RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; 
      } //strcmp(local_rf, "yes") == 0
      else {
	printf("RU %d: Transport %s\n",j,*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr));

        RC.ru[j]->eth_params.local_if_name	      = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr));    
        RC.ru[j]->eth_params.my_addr		      = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); 
        RC.ru[j]->eth_params.remote_addr	      = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr));
        RC.ru[j]->eth_params.my_portc		      = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr);
        RC.ru[j]->eth_params.remote_portc	      = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr);
        RC.ru[j]->eth_params.my_portd		      = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr);
        RC.ru[j]->eth_params.remote_portd	      = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr);
	if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) {
	  RC.ru[j]->if_south                     = REMOTE_IF5;
	  RC.ru[j]->function                     = NGFI_RAU_IF5;
	  RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE;
	} else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) {
	  RC.ru[j]->if_south                     = REMOTE_IF5;
	  RC.ru[j]->function                     = NGFI_RAU_IF5;
	  RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE;
	} else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) {
	  RC.ru[j]->if_south                     = REMOTE_IF4p5;
	  RC.ru[j]->function                     = NGFI_RAU_IF4p5;
	  RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE;
	} else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) {
	  RC.ru[j]->if_south                     = REMOTE_IF4p5;
	  RC.ru[j]->function                     = NGFI_RAU_IF4p5;
	  RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE;
	} else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if5_mobipass") == 0) {
	  RC.ru[j]->if_south                     = REMOTE_IF5;
	  RC.ru[j]->function                     = NGFI_RAU_IF5;
	  RC.ru[j]->if_timing                    = synch_to_other;
	  RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF5_MOBIPASS;
	}
      }  /* strcmp(local_rf, "yes") != 0 */

      RC.ru[j]->nb_tx                             = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr);
      RC.ru[j]->nb_rx                             = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr);
      
3083 3084
      RC.ru[j]->att_tx                            = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr);
      RC.ru[j]->att_rx                            = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr);
3085 3086 3087 3088 3089 3090 3091 3092
    }// j=0..num_rus
  } else {
    RC.nb_RU = 0;	    
  } // setting != NULL

  return;
  
}