lte-ru.c 83.3 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 63 64 65 66 67
    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"

#include "PHY/defs.h"
#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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

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

#include "PHY/extern.h"
#include "SCHED/extern.h"
#include "LAYER2/MAC/extern.h"

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

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

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

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

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

#include "T.h"

extern volatile int                    oai_exit;


116 117
extern void  phy_init_RU(RU_t*);

Raymond Knopp's avatar
Raymond Knopp committed
118
void init_RU(char*);
Raymond Knopp's avatar
Raymond Knopp committed
119
void stop_RU(RU_t *ru);
120
void do_ru_sync(RU_t *ru);
Raymond Knopp's avatar
Raymond Knopp committed
121

122 123 124 125 126 127 128
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
129

130
int connect_rau(RU_t *ru);
Raymond Knopp's avatar
Raymond Knopp committed
131

132

133 134 135
/*************************************************************/
/* Functions to attach and configure RRU                     */

Raymond Knopp's avatar
Raymond Knopp committed
136
extern void wait_eNBs(void);
137

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
int send_tick(RU_t *ru){
  
  ssize_t      msg_len,len;
  RRU_CONFIG_msg_t rru_config_msg;

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

  return 0;
}

153
int send_config(RU_t *ru, RRU_CONFIG_msg_t rru_config_msg){
154

155
	ssize_t      msg_len,len;
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182

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


  	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 send_capab(RU_t *ru){

183
	RRU_CONFIG_msg_t rru_config_msg; 
184 185 186
	RRU_capabilities_t *cap;
	int i=0;

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 212 213 214 215 216 217 218 219 220 221 222
	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++) {
		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);
	    	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);

	return 0;

}

223 224 225 226 227 228
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
229
  wait_eNBs();
230 231 232
  // Wait for capabilities
  while (received_capabilities==0) {
    
233
    memset((void*)&rru_config_msg,0,sizeof(rru_config_msg));
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 271 272 273 274 275 276 277 278 279 280
    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]);

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 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
  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++) {
340 341
	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);
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
    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
381 382 383 384 385
/*************************************************************/
/* Southbound Fronthaul functions, RCC/RAU                   */

// southbound IF5 fronthaul for 16-bit OAI format
static inline void fh_if5_south_out(RU_t *ru) {
386 387
  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
388 389 390 391
}

// southbound IF5 fronthaul for Mobipass packet format
static inline void fh_if5_mobipass_south_out(RU_t *ru) {
392 393
  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
394 395 396 397
}

// southbound IF4p5 fronthaul
static inline void fh_if4p5_south_out(RU_t *ru) {
398
  if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
399
  LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx);
400 401
  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
402 403 404 405 406 407 408 409 410
}

/*************************************************************/
/* 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;
411
  RU_proc_t *proc = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
412

413
  recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); 
Raymond Knopp's avatar
Raymond Knopp committed
414 415 416 417 418 419

  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){
420
      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
421 422 423 424
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
425
      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
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
      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;
442 443
  RU_proc_t *proc = &ru->proc;
  int f,sf;
Raymond Knopp's avatar
Raymond Knopp committed
444 445 446 447


  uint16_t packet_type;
  uint32_t symbol_number=0;
448 449 450 451 452 453
  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
454

455
  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
456
  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
457
    recv_IF4p5(ru, &f, &sf, &packet_type, &symbol_number);
Raymond Knopp's avatar
Raymond Knopp committed
458

459 460 461 462
    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);       
463
      break;     
464
      
Raymond Knopp's avatar
Raymond Knopp committed
465
    } else if (packet_type == IF4p5_PRACH) {
466
      // nothing in RU for RAU
Raymond Knopp's avatar
Raymond Knopp committed
467
    }
468
    LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*subframe,proc->symbol_mask[*subframe]);
469
  } while(proc->symbol_mask[*subframe] != symbol_mask_full);    
Raymond Knopp's avatar
Raymond Knopp committed
470 471

  //caculate timestamp_rx, timestamp_tx based on frame and subframe
472 473
  proc->subframe_rx  = sf;
  proc->frame_rx     = f;
474
  proc->timestamp_rx = ((proc->frame_rx * 10)  + proc->subframe_rx ) * fp->samples_per_tti ;
475 476 477
  //  proc->timestamp_tx = proc->timestamp_rx +  (4*fp->samples_per_tti);
  proc->subframe_tx  = (sf+4)%10;
  proc->frame_tx     = (sf>5) ? (f+1)&1023 : f;
Raymond Knopp's avatar
Raymond Knopp committed
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
 
  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;        
  }
493

494 495 496 497 498 499 500
  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 );
  }

501
  proc->symbol_mask[sf] = 0;  
Raymond Knopp's avatar
Raymond Knopp committed
502
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
503 504
  LOG_D(PHY,"RU %d: fh_if4p5_south_in sleeping ...\n",ru->idx);
  usleep(100);
Raymond Knopp's avatar
Raymond Knopp committed
505 506 507 508 509 510
}

// 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
511
  RU_proc_t *proc=&ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
512 513 514 515 516 517 518 519 520

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

  
}

521 522
// 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
523

524 525
  RU_proc_t *proc       = &ru->proc;
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
Raymond Knopp's avatar
Raymond Knopp committed
526

527 528 529 530 531 532
  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
533

534 535
  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
536

537 538
  if (proc->first_rx == 1) {
    proc->first_rx =2;
Raymond Knopp's avatar
Raymond Knopp committed
539 540
    *subframe = proc->subframe_rx;
    *frame    = proc->frame_rx; 
541
    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
542 543 544
  }
  else {
    if (proc->subframe_rx != *subframe) {
545 546 547
        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
548 549
    }
    if (proc->frame_rx != *frame) {
550 551 552
        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
553
    }
554 555 556
    // temporary solution
      *subframe = proc->subframe_rx;
      *frame    = proc->frame_rx;
Raymond Knopp's avatar
Raymond Knopp committed
557
  }
558 559 560 561

  pthread_mutex_unlock(&proc->mutex_asynch_rxtx);


Raymond Knopp's avatar
Raymond Knopp committed
562 563 564 565 566 567
} // 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;
568
  RU_proc_t *proc       = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
569 570

  uint16_t packet_type;
Raymond Knopp's avatar
Raymond Knopp committed
571
  uint32_t symbol_number,symbol_mask,prach_rx;
572
  uint32_t got_prach_info=0;
Raymond Knopp's avatar
Raymond Knopp committed
573 574

  symbol_number = 0;
575 576
  symbol_mask   = (1<<fp->symbols_per_tti)-1;
  prach_rx      = 0;
Raymond Knopp's avatar
Raymond Knopp committed
577 578 579

  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
    recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number);
580 581 582 583 584
    // 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
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
    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");
      }
    }
600 601 602 603 604 605 606 607 608
    if      (packet_type == IF4p5_PULFFT)       symbol_mask &= (~(1<<symbol_number));
    else if (packet_type == IF4p5_PRACH)        prach_rx    &= (~0x1);
#ifdef Rel14
    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
609 610 611 612 613 614 615 616 617 618 619
} 





/*************************************************************/
/* 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
620
void fh_if4p5_north_in(RU_t *ru,int *frame,int *subframe) {
Raymond Knopp's avatar
Raymond Knopp committed
621 622 623 624 625

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

626

Raymond Knopp's avatar
Raymond Knopp committed
627 628 629 630 631 632
  /// **** incoming IF4p5 from remote RCC/RAU **** ///             
  symbol_number = 0;
  symbol_mask = 0;
  symbol_mask_full = (1<<ru->frame_parms.symbols_per_tti)-1;
  
  do { 
633
    recv_IF4p5(ru, frame, subframe, &packet_type, &symbol_number);
Raymond Knopp's avatar
Raymond Knopp committed
634 635 636
    symbol_mask = symbol_mask | (1<<symbol_number);
  } while (symbol_mask != symbol_mask_full); 

637 638
  // dump VCD output for first RU in list
  if (ru == RC.ru[0]) {
639 640
    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
641 642 643 644 645 646
  }
}

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

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
647
  RU_proc_t *proc        = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
  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 {
663 664 665 666
    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
667 668 669 670 671 672
  }
}

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

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
673
  RU_proc_t *proc        = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
674 675 676 677 678 679 680

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

  symbol_number = 0;
  symbol_mask = 0;
681
  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
682 683
  do {   
    recv_IF4p5(ru, &frame_tx, &subframe_tx, &packet_type, &symbol_number);
684
    if ((subframe_select(fp,subframe_tx) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul);
685 686
    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
687 688 689 690
    if (proc->first_tx != 0) {
      *frame    = frame_tx;
      *subframe = subframe_tx;
      proc->first_tx = 0;
691
      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
692 693
    }
    else {
694 695 696 697
      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
698 699 700 701
    }
    if (packet_type == IF4p5_PDLFFT) {
      symbol_mask = symbol_mask | (1<<symbol_number);
    }
702
    else AssertFatal(1==0,"Illegal IF4p5 packet type (should only be IF4p5_PDLFFT%d\n",packet_type);
Raymond Knopp's avatar
Raymond Knopp committed
703
  } while (symbol_mask != symbol_mask_full);    
704

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

707 708 709 710
  proc->subframe_tx  = subframe_tx;
  proc->frame_tx     = frame_tx;

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

712
  proc->timestamp_tx = (((frame_tx + proc->frame_tx_unwrap) * 10) + subframe_tx) * fp->samples_per_tti;
713
  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);
714 715 716 717 718
    // 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 );
  }
719

720 721
  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
722 723
} 

724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
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;
742
  if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_rx );
743 744 745

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

750 751 752
  start_meas(&ru->tx_fhaul);
  send_IF4p5(ru, proc->frame_rx, proc->subframe_rx, IF4p5_PULFFT);
  stop_meas(&ru->tx_fhaul);
753 754

}
Raymond Knopp's avatar
Raymond Knopp committed
755 756
void rx_rf(RU_t *ru,int *frame,int *subframe) {

757
  RU_proc_t *proc = &ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
758
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
759
  void *rxp[ru->nb_rx];
760
  unsigned int rxs;
Raymond Knopp's avatar
Raymond Knopp committed
761
  int i;
762
  openair0_timestamp ts,old_ts;
Raymond Knopp's avatar
Raymond Knopp committed
763
    
764
  for (i=0; i<ru->nb_rx; i++)
765
    rxp[i] = (void*)&ru->common.rxdata[i][*subframe*fp->samples_per_tti];
Raymond Knopp's avatar
Raymond Knopp committed
766 767 768
  
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );

769 770
  old_ts = proc->timestamp_rx;

Raymond Knopp's avatar
Raymond Knopp committed
771
  rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
772
				   &ts,
Raymond Knopp's avatar
Raymond Knopp committed
773 774
				   rxp,
				   fp->samples_per_tti,
775
				   ru->nb_rx);
Raymond Knopp's avatar
Raymond Knopp committed
776 777 778
  
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
 
779 780
  proc->timestamp_rx = ts-ru->ts_offset;

781 782
  AssertFatal(rxs == fp->samples_per_tti,
	      "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs);
783 784

  if (proc->first_rx == 1) {
785
    ru->ts_offset = proc->timestamp_rx;
786 787 788 789 790 791 792 793 794 795 796 797
    proc->timestamp_rx = 0;
  }
  else {
    if (proc->timestamp_rx - old_ts != fp->samples_per_tti) {
      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);
      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
798 799
  // synchronize first reception to frame 0 subframe 0

800 801 802
  proc->timestamp_tx = proc->timestamp_rx+(4*fp->samples_per_tti);
  proc->subframe_tx  = (proc->subframe_rx+4)%10;
  proc->frame_tx     = (proc->subframe_rx>5) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
803 804 805 806 807 808
  
  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);
809

810 811 812 813
    // 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
814 815
    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 );
816
  }
Raymond Knopp's avatar
Raymond Knopp committed
817 818 819
  
  if (proc->first_rx == 0) {
    if (proc->subframe_rx != *subframe){
820
      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
821 822 823 824
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
825
      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
826 827 828 829 830 831 832 833 834 835
      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);
  
836
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
Raymond Knopp's avatar
Raymond Knopp committed
837 838 839 840 841 842 843 844 845
  
  if (rxs != fp->samples_per_tti)
    exit_fun( "problem receiving samples" );
  

  
}


846 847 848 849
void tx_rf(RU_t *ru) {

  RU_proc_t *proc = &ru->proc;
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
850
  void *txp[ru->nb_tx]; 
851 852 853
  unsigned int txs;
  int i;

Cedric Roux's avatar
Cedric Roux committed
854 855 856
  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));

857 858 859
  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);
860 861
  int sf_extension = 0;

862 863 864 865 866 867 868 869 870 871 872 873 874
  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) &&
875
	(nextSF_type == SF_DL)) { 
876
      flags = 2; // start of burst
877 878
      sf_extension = ru->N_TA_offset<<1;
    }
879 880 881 882
    
    if ((fp->frame_type == TDD) &&
	(SF_type == SF_DL)&&
	(prevSF_type == SF_UL) &&
883
	(nextSF_type == SF_UL)) {
884
      flags = 4; // start of burst and end of burst (only one DL SF between two UL)
885 886 887 888 889 890
      sf_extension = ru->N_TA_offset<<1;
    } 

    for (i=0; i<ru->nb_tx; i++)
      txp[i] = (void*)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension];

891
    
892 893 894 895 896
    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,
897
				      proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension,
898
				      txp,
899
				      siglen+sf_extension,
900 901 902 903
				      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
904
	  (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx);
905
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
906
    
907
    
908
    AssertFatal(txs ==  siglen+sf_extension,"TX : Timeout (sent %d/%d)\n",txs, siglen);
909

910
  }
911 912 913
}


Raymond Knopp's avatar
Raymond Knopp committed
914 915 916 917 918 919 920 921 922 923
/*!
 * \brief The Asynchronous RX/TX FH thread of RAU/RCC/eNB/RRU.
 * This handles the RX FH for an asynchronous RRU/UE
 * \param param is a \ref eNB_proc_t structure which contains the info what to process.
 * \returns a pointer to an int. The storage is not on the heap and must not be freed.
 */
static void* ru_thread_asynch_rxtx( void* param ) {

  static int ru_thread_asynch_rxtx_status;

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

Raymond Knopp's avatar
Raymond Knopp committed
927 928 929 930


  int subframe=0, frame=0; 

931
  thread_top_init("ru_thread_asynch_rxtx",1,870000L,1000000L,1000000L);
Raymond Knopp's avatar
Raymond Knopp committed
932 933 934

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

935
  wait_sync("ru_thread_asynch_rxtx");
Raymond Knopp's avatar
Raymond Knopp committed
936 937

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

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

942
  printf( "devices ok (ru_thread_asynch_rx)\n");
Raymond Knopp's avatar
Raymond Knopp committed
943 944 945 946 947 948 949 950 951 952 953 954 955


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

    if (subframe==9) { 
      subframe=0;
      frame++;
      frame&=1023;
    } else {
      subframe++;
    }      
956
    LOG_D(PHY,"ru_thread_asynch_rxtx: Waiting on incoming fronthaul\n");
957 958 959
    // asynchronous receive from south (Mobipass)
    if (ru->fh_south_asynch_in) ru->fh_south_asynch_in(ru,&frame,&subframe);
    // asynchronous receive from north (RRU IF4/IF5)
960 961 962 963
    else if (ru->fh_north_asynch_in) {
       if (subframe_select(&ru->frame_parms,subframe)!=SF_UL)
         ru->fh_north_asynch_in(ru,&frame,&subframe);
    }
964
    else AssertFatal(1==0,"Unknown function in ru_thread_asynch_rxtx\n");
Raymond Knopp's avatar
Raymond Knopp committed
965 966 967 968 969 970 971 972 973
  }

  ru_thread_asynch_rxtx_status=0;
  return(&ru_thread_asynch_rxtx_status);
}




974
void wakeup_slaves(RU_proc_t *proc) {
Raymond Knopp's avatar
Raymond Knopp committed
975 976 977 978 979 980 981 982

  int i;
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
  
  for (i=0;i<proc->num_slaves;i++) {
983
    RU_proc_t *slave_proc = proc->slave_proc[i];
Raymond Knopp's avatar
Raymond Knopp committed
984 985 986
    // 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) {
987
      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
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
      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) {
1003
	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
1004 1005 1006 1007
          exit_fun( "ERROR pthread_cond_signal" );
	  break;
      }
    } else {
1008
      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
1009 1010 1011 1012 1013 1014 1015 1016
      exit_fun( "FH thread busy" );
      break;
    }             
  }
}

/*!
 * \brief The prach receive thread of RU.
1017
 * \param param is a \ref RU_proc_t structure which contains the info what to process.
Raymond Knopp's avatar
Raymond Knopp committed
1018 1019 1020
 * \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 ) {
1021

Raymond Knopp's avatar
Raymond Knopp committed
1022 1023
  static int ru_thread_prach_status;

1024 1025
  RU_t *ru        = (RU_t*)param;
  RU_proc_t *proc = (RU_proc_t*)&ru->proc;
Raymond Knopp's avatar
Raymond Knopp committed
1026 1027

  // set default return value
1028
  ru_thread_prach_status = 0;
Raymond Knopp's avatar
Raymond Knopp committed
1029

1030
  thread_top_init("ru_thread_prach",1,500000L,1000000L,20000000L);
Raymond Knopp's avatar
Raymond Knopp committed
1031 1032 1033 1034

  while (!oai_exit) {
    
    if (oai_exit) break;
1035
    if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
1036
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );      
1037 1038
    rx_prach(NULL,
	     ru,
1039
	     NULL,
1040 1041 1042
             NULL,
             NULL,
             proc->frame_prach,
1043 1044 1045 1046 1047
             0
#ifdef Rel14
	     ,0
#endif
	     );
1048
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 );      
1049
    if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
Raymond Knopp's avatar
Raymond Knopp committed
1050 1051
  }

1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
  LOG_I(PHY, "Exiting RU thread PRACH\n");

  ru_thread_prach_status = 0;
  return &ru_thread_prach_status;
}

#ifdef Rel14
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;

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

  while (!oai_exit) {
    
    if (oai_exit) break;
    if (wait_on_condition(&proc->mutex_prach_br,&proc->cond_prach_br,&proc->instance_cnt_prach_br,"ru_prach_thread_br") < 0) break;
    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
1087

1088 1089
  ru_thread_prach_status = 0;
  return &ru_thread_prach_status;
Raymond Knopp's avatar
Raymond Knopp committed
1090
}
1091
#endif
Raymond Knopp's avatar
Raymond Knopp committed
1092

1093
int wakeup_synch(RU_t *ru){
Raymond Knopp's avatar
Raymond Knopp committed
1094

1095 1096 1097 1098
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
Raymond Knopp's avatar
Raymond Knopp committed
1099

1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
  // 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
1127 1128
  void *rxp[2],*rxp2[2];
  int32_t dummy_rx[ru->nb_rx][fp->samples_per_tti] __attribute__((aligned(32)));
1129 1130
  int rxs;
  int ic;
Raymond Knopp's avatar
Raymond Knopp committed
1131 1132 1133

  // initialize the synchronization buffer to the common_vars.rxdata
  for (int i=0;i<ru->nb_rx;i++)
1134
    rxp[i] = &ru->common.rxdata[i][0];
Raymond Knopp's avatar
Raymond Knopp committed
1135 1136 1137 1138 1139 1140 1141 1142 1143

  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);
  
1144 1145
  LOG_I(PHY,"Entering synch routine\n");
  
Raymond Knopp's avatar
Raymond Knopp committed
1146 1147 1148 1149 1150 1151 1152
  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);
1153 1154
    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
1155 1156 1157 1158 1159 1160 1161 1162
    // 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
      
1163
      for (i=0; i<ru->nb_rx; i++)
Raymond Knopp's avatar
Raymond Knopp committed
1164 1165 1166 1167 1168 1169 1170
	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);
1171 1172 1173
      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
1174 1175 1176 1177 1178 1179 1180 1181
    } // 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,
1182
				   ru->nb_rx);
Raymond Knopp's avatar
Raymond Knopp committed
1183 1184 1185 1186 1187 1188 1189
  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);

1190
  LOG_I(PHY,"Exiting synch routine\n");
Raymond Knopp's avatar
Raymond Knopp committed
1191 1192
}

1193 1194 1195 1196 1197 1198


void wakeup_eNBs(RU_t *ru) {

  int i;
  PHY_VARS_eNB **eNB_list = ru->eNB_list;
1199 1200
  PHY_VARS_eNB *eNB=eNB_list[0];
  eNB_proc_t *proc = &eNB->proc;
1201

Eurecom's avatar
Eurecom committed
1202
  LOG_I(PHY,"wakeup_eNBs (num %d) for RU %d\n",ru->num_eNB,ru->idx);
1203

1204 1205 1206 1207 1208
  if (ru->num_eNB==1) {
    // call eNB function directly

    char string[20];
    sprintf(string,"Incoming RU %d",ru->idx);
1209 1210 1211 1212
    LOG_D(PHY,"Frame %d, Subframe %d: RU %d Waking up eNB,RU_mask %x\n",ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,proc->RU_mask);
    
    pthread_mutex_lock(&proc->mutex_RU);
    for (i=0;i<eNB->num_RU;i++) {
khadraou's avatar
khadraou committed
1213 1214 1215 1216
      if (ru->state == RU_SYNC){
	proc->RU_mask |= (1<<i);
	break;
      }
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
      if (ru == eNB->RU_list[i]) {
        //AssertFatal(((proc->RU_mask&(1<<i)) == 0) ,
        if ((proc->RU_mask&(1<<i)) > 0)            
		LOG_E(PHY, "eNB %d frame %d, subframe %d : previous information from RU %d (num_RU %d,mask %x) has not been served yet!\n",eNB->Mod_id,ru->proc.frame_rx,ru->proc.subframe_rx,ru->idx,eNB->num_RU,proc->RU_mask);
        proc->RU_mask |= (1<<i);
      }
    }
    if (proc->RU_mask != (1<<eNB->num_RU)-1) {  // not all RUs have provided their information so return
      pthread_mutex_unlock(&proc->mutex_RU);
      return(0);
    }
    else { // all RUs have provided their information so continue on and wakeup eNB processing
      proc->RU_mask = 0;
      pthread_mutex_unlock(&proc->mutex_RU);
    }

khadraou's avatar
khadraou committed
1233
    LOG_I(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.subframe_rx);
1234 1235 1236 1237 1238
    ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string);
  }
  else {

    for (i=0;i<ru->num_eNB;i++)
Raymond Knopp's avatar
Raymond Knopp committed
1239
      if (ru->wakeup_rxtx(eNB_list[i],ru) < 0)
1240 1241 1242 1243
	LOG_E(PHY,"could not wakeup eNB rxtx process for subframe %d\n", ru->proc.subframe_rx);
  }
}

1244
static inline int wakeup_prach_ru(RU_t *ru) {
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255

  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);
  }
1256 1257 1258 1259
  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;
1260 1261

    LOG_D(PHY,"RU %d: waking up PRACH thread\n",ru->idx);
1262 1263
    // 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");
1264
  }
1265
  else LOG_W(PHY,"RU prach thread busy, skipping\n");
1266 1267 1268 1269 1270
  pthread_mutex_unlock( &ru->proc.mutex_prach );

  return(0);
}

1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
#ifdef Rel14
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
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 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 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 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 1387
// 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;

  if(fp->N_RB_DL == 100) {
    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(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;
  
  for (i=0; i<ru->nb_tx; i++) {
    
    cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
    cfg->rx_freq[i] = (double)fp->ul_CarrierFreq;

    cfg->tx_gain[i] = (double)fp->att_tx;
    cfg->rx_gain[i] = ru->max_rxgain-(double)fp->att_rx;

    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 {
    printf("RU[%d] not initialized\n", ru->idx);
    return(-1);
  }
  
  
1388 1389 1390 1391 1392
  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;
  } 
Raymond Knopp's avatar
Raymond Knopp committed
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 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
  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);
}

1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
static void* ru_stats_thread(void* param) {

  RU_t               *ru      = (RU_t*)param;

  wait_sync("ru_stats_thread");

  while (!oai_exit) {
     sleep(1);
     if (opp_enabled == 1) {
       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);
1442
       if (ru->fh_north_asynch_in) print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL);
1443 1444 1445 1446 1447
       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);
       }
1448 1449
     }
  }
1450
  return(NULL);
Younes's avatar
Younes committed
1451 1452
}

1453 1454


Younes's avatar
Younes committed
1455 1456
static void* ru_thread_control( void* param ) {

1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
  static int ru_thread_status;

  RU_t               *ru      = (RU_t*)param;
  RU_proc_t          *proc    = &ru->proc;
  RRU_CONFIG_msg_t   rru_config_msg;
  ssize_t	     msg_len;
  int                tick_received          = 0;
  int                configuration_received = 0;
  int                start_received = 0;
  RRU_capabilities_t *cap;
  int                i;
khadraou's avatar
khadraou committed
1468
  int                ret;
1469 1470
  int                len;

khadraou's avatar
khadraou committed
1471

1472 1473 1474 1475
  // 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");
khadraou's avatar
khadraou committed
1476 1477

    if (ru->if_south != LOCAL_RF) wait_eNBs();
1478 1479
  }

khadraou's avatar
khadraou committed
1480
  
1481
  ru->state = RU_IDLE;
khadraou's avatar
khadraou committed
1482
  LOG_I(PHY,"Control channel ON for RU %d\n", ru->idx);
1483 1484

  while (!oai_exit) // Change the cond
1485
  {
1486
	msg_len  = sizeof(RRU_CONFIG_msg_t); // TODO : check what should be the msg len
1487

khadraou's avatar
khadraou committed
1488
	if (ru->state == RU_IDLE && ru->if_south != LOCAL_RF)
khadraou's avatar
khadraou committed
1489 1490
		send_tick(ru);

khadraou's avatar
khadraou committed
1491
	
1492 1493 1494
    	if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice,
					     	&rru_config_msg,
					     	msg_len))<0) {
1495
      		LOG_D(PHY,"Waiting msg for RU %d\n", ru->idx);     
1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
    	}
	else
	{
		switch(rru_config_msg.type)
		{
			case RAU_tick:  // RRU
				if (ru->if_south != LOCAL_RF){
					LOG_I(PHY,"Received Tick msg...Ignoring\n");
				}else{
					LOG_I(PHY,"Tick received from RAU\n");
				
					if (send_capab(ru) == 0) ru->state = RU_CONFIG;
				}				
				break;

			case RRU_capabilities: // RAU
				if (ru->if_south == LOCAL_RF){
					LOG_I(PHY,"Received RRU_capab msg...Ignoring\n");
				}
				else{
khadraou's avatar
khadraou committed
1516 1517
					msg_len  = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t);

1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
					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]);

					configure_ru(ru->idx,(RRU_capabilities_t *)&rru_config_msg.msg[0]);

					// send config
					if (send_config(ru,rru_config_msg) == 0) ru->state = RU_CONFIG;
				}

				break;
				
			case RRU_config: // RRU
				if (ru->if_south == LOCAL_RF){
					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]);

khadraou's avatar
khadraou committed
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
 					  
					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);
					}

1565 1566
					// send CONFIG_OK

1567 1568
	  				rru_config_msg.type = RRU_config_ok; 
	  				rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t);
1569 1570
	  				LOG_I(PHY,"Sending CONFIG_OK to RRU %d\n", ru->idx);

1571
	  				AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),
1572 1573 1574 1575 1576 1577 1578 1579 1580
		      					"RU %d failed send CONFIG_OK to RAU\n",ru->idx);

					ru->state = RU_READY;
				}else{
					LOG_I(PHY,"Received RRU_config msg...Ignoring\n");
				}	
				break;	

			case RRU_config_ok: // RAU
1581 1582 1583
				if (ru->if_south == LOCAL_RF){
					LOG_I(PHY,"Received RRU_config_ok msg...Ignoring\n");
				}else{
khadraou's avatar
khadraou committed
1584 1585 1586 1587 1588 1589

					if (setup_RU_buffers(ru)!=0) {
						printf("Exiting, cannot initialize RU Buffers\n");
						exit(-1);
					}

khadraou's avatar
khadraou committed
1590 1591
					// Set state to RUN for Master RU, Others on SYNC
					ru->state = (ru->is_slave == 1) ? RU_SYNC : RU_RUN ;
1592
					
khadraou's avatar
khadraou committed
1593

khadraou's avatar
khadraou committed
1594 1595 1596 1597 1598
  					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);
khadraou's avatar
khadraou committed
1599
					  
khadraou's avatar
khadraou committed
1600
					wait_sync("ru_thread");
khadraou's avatar
khadraou committed
1601

1602 1603 1604 1605 1606
					// send start
                                        rru_config_msg.type = RRU_start;
                                        rru_config_msg.len  = sizeof(RRU_CONFIG_msg_t); // TODO: set to correct msg len
 
                                        LOG_I(PHY,"Sending Start to RRU\n", ru->idx);
khadraou's avatar
khadraou committed
1607
                                        AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1),"Failed to send msg to RU %d\n",ru->idx);
1608

khadraou's avatar
khadraou committed
1609
					
khadraou's avatar
khadraou committed
1610 1611 1612 1613 1614 1615
					proc->instance_cnt_ru = 1;
					if (pthread_cond_signal(&proc->cond_ru_thread) != 0) {
						LOG_E( PHY, "ERROR pthread_cond_signal for RU %d\n",ru->idx);
						exit_fun( "ERROR pthread_cond_signal" );
						break;
					}
1616
				}		
1617 1618 1619 1620 1621 1622 1623
				break;

			case RRU_start: // RRU
				if (ru->if_south == LOCAL_RF){
					LOG_I(PHY,"Start received from RAU\n");
				
					if (ru->state == RU_READY){
khadraou's avatar
khadraou committed
1624 1625

						LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx);
khadraou's avatar
khadraou committed
1626 1627 1628 1629
						pthread_mutex_lock(&RC.ru_mutex);
						RC.ru_mask &= ~(1<<ru->idx);
						pthread_cond_signal(&RC.ru_cond);
						pthread_mutex_unlock(&RC.ru_mutex);
khadraou's avatar
khadraou committed
1630
						  
khadraou's avatar
khadraou committed
1631 1632 1633 1634
						wait_sync("ru_thread");
						
						ru->state = (ru->is_slave == 1) ? RU_SYNC : RU_RUN ;
	
khadraou's avatar
khadraou committed
1635 1636 1637 1638 1639 1640
						proc->instance_cnt_ru = 1;
						if (pthread_cond_signal(&proc->cond_ru_thread) != 0) {
							LOG_E( PHY, "ERROR pthread_cond_signal for RU %d\n",ru->idx);
							exit_fun( "ERROR pthread_cond_signal" );
							break;
						}
1641 1642
					}
					else{
1643
						LOG_I(PHY,"RRU not ready, cannot start\n"); 
1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658
					}
				}else{
					LOG_I(PHY,"Received RRU_start msg...Ignoring\n");
				}

				break;

			case RRU_stop: // RRU
				if (ru->if_south == LOCAL_RF){
					LOG_I(PHY,"Stop received from RAU\n");

					if (ru->state == RU_RUN || ru->state == RU_ERROR){

						LOG_I(PHY,"Stopping RRU\n");
						ru->state = RU_READY;
1659
						// TODO: stop ru_thread
1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676
					}else{
						LOG_I(PHY,"RRU not running, can't stop\n"); 
					}
				}else{
					LOG_I(PHY,"Received RRU_stop msg...Ignoring\n");
				}
				break;

			default:
				if (ru->if_south != LOCAL_RF){
					if (ru->state == RU_IDLE){
						// Keep sending TICK
						send_tick(ru);
					}
				}

				break;
khadraou's avatar
khadraou committed
1677 1678
		} // switch	
	} //else
Younes's avatar
Younes committed
1679 1680


khadraou's avatar
khadraou committed
1681
  }//while
Younes's avatar
Younes committed
1682

1683 1684
}

khadraou's avatar
khadraou committed
1685

Raymond Knopp's avatar
Raymond Knopp committed
1686 1687 1688 1689
static void* ru_thread( void* param ) {

  static int ru_thread_status;

1690 1691 1692
  RU_t               *ru      = (RU_t*)param;
  RU_proc_t          *proc    = &ru->proc;
  LTE_DL_FRAME_PARMS *fp      = &ru->frame_parms;
1693 1694
  int                subframe =9;
  int                frame    =1023; 
Raymond Knopp's avatar
Raymond Knopp committed
1695 1696 1697 1698 1699 1700 1701 1702

  // set default return value
  ru_thread_status = 0;


  // set default return value
  thread_top_init("ru_thread",0,870000,1000000,1000000);

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

khadraou's avatar
khadraou committed
1705

1706 1707
	
  while (!oai_exit) {
1708
  
khadraou's avatar
khadraou committed
1709

1710
          // wait to be woken up
1711
          if (wait_on_condition(&ru->proc.mutex_ru,&ru->proc.cond_ru_thread,&ru->proc.instance_cnt_ru,"ru_thread")<0) break;
1712
	  
Raymond Knopp's avatar
Raymond Knopp committed
1713

1714 1715 1716 1717 1718 1719 1720
	  // 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);
Raymond Knopp's avatar
Raymond Knopp committed
1721

1722

1723 1724 1725 1726 1727 1728 1729 1730 1731 1732
	  // 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);
1733

1734
	  // if this is a slave RRU, try to synchronize on the DL frequency
1735
	  if ((ru->is_slave == 1) && (ru->if_south == LOCAL_RF)) do_ru_synch(ru);
1736 1737


1738 1739
	  // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
	  while (ru->state == RU_RUN) {
1740

1741 1742 1743 1744 1745 1746 1747 1748 1749
	    // 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++;
	    }      
Raymond Knopp's avatar
Raymond Knopp committed
1750

1751 1752
	    LOG_D(PHY,"RU thread %d, frame %d (%p), subframe %d (%p)\n",
		  ru->idx, frame,&frame,subframe,&subframe);
Raymond Knopp's avatar
Raymond Knopp committed
1753

1754

1755 1756 1757
	    // synchronization on input FH interface, acquire signals/data and block
	    if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&subframe);
	    else AssertFatal(1==0, "No fronthaul interface at south port");
1758

Raymond Knopp's avatar
Raymond Knopp committed
1759

1760 1761
	    LOG_D(PHY,"RU thread %d (do_prach %d, is_prach_subframe %d), received frame %d, subframe %d\n",
		  ru->idx,ru->do_prach,
1762 1763 1764 1765 1766 1767 1768
		  is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx),
		  proc->frame_rx,proc->subframe_rx);
	 
	    if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)==1)) wakeup_prach_ru(ru);
	#ifdef Rel14
	    else if ((ru->do_prach>0) && (is_prach_subframe(fp, proc->frame_rx, proc->subframe_rx)>1)) wakeup_prach_ru_br(ru);
	#endif
1769

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


1774 1775
	    // do RX front-end processing (frequency-shift, dft) if needed
	    if (ru->feprx) ru->feprx(ru);
1776

1777 1778 1779
	    // 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);
Raymond Knopp's avatar
Raymond Knopp committed
1780

1781 1782
	    // wakeup all eNB processes waiting for this RU
	    if (ru->num_eNB>0) wakeup_eNBs(ru);
Raymond Knopp's avatar
Raymond Knopp committed
1783

1784 1785
	    // wait until eNBs are finished subframe RX n and TX n+4
	    wait_on_condition(&proc->mutex_eNBs,&proc->cond_eNBs,&proc->instance_cnt_eNBs,"ru_thread");
1786

Raymond Knopp's avatar
Raymond Knopp committed
1787

1788 1789 1790 1791 1792 1793 1794 1795 1796
	    // 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);
	    // 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);
1797

1798
	  }
1799

1800
  } // while !oai_exit
Raymond Knopp's avatar
Raymond Knopp committed
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818
  

  printf( "Exiting ru_thread \n");
 
  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)));
1819
  static int ru_thread_synch_status;
Raymond Knopp's avatar
Raymond Knopp committed
1820 1821 1822 1823 1824 1825 1826


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

  wait_sync("ru_thread_synch");

  // initialize variables for PSS detection
1827
  lte_sync_time_init(&ru->frame_parms);
Raymond Knopp's avatar
Raymond Knopp committed
1828 1829 1830 1831

  while (!oai_exit) {

    // wait to be woken up
1832
    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
1833 1834 1835 1836 1837 1838

    // 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");
      
1839
      sync_pos = lte_sync_time_eNB(ru->common.rxdata,
Raymond Knopp's avatar
Raymond Knopp committed
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
				   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);
	
	/*
	if ((peak_val > 300000) && (sync_pos > 0)) {
	//      if (sync_pos++ > 3) {
	write_output("ru_sync.m","sync",(void*)&sync_corr[0],fp->samples_per_tti*5,1,2);
	write_output("ru_rx.m","rxs",(void*)ru->ru_time.rxdata[0][0],fp->samples_per_tti*10,1,1);
	exit(-1);
	}
	*/
khadraou's avatar
khadraou committed
1876 1877
	ru->in_synch = 1;
	ru->state    = RU_SYNC;
Eurecom's avatar
Eurecom committed
1878 1879 1880
      } // symc_pos > 0
      else {
        write_output("ru_sync.m","sync",(void*)&sync_corr[0],fp->samples_per_tti*5,1,2);
Eurecom's avatar
Eurecom committed
1881
        write_output("ru_rx.m","rxs",(void*)ru->common.rxdata[0],fp->samples_per_tti*10,1,1);
Eurecom's avatar
Eurecom committed
1882 1883
        exit(1); 
     }
Eurecom's avatar
Eurecom committed
1884
    } // ru->in_synch==0
Raymond Knopp's avatar
Raymond Knopp committed
1885 1886 1887 1888 1889 1890

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

  lte_sync_time_free();

1891 1892 1893
  ru_thread_synch_status = 0;
  return &ru_thread_synch_status;

Raymond Knopp's avatar
Raymond Knopp committed
1894 1895 1896
}


1897 1898 1899 1900 1901 1902 1903 1904 1905 1906
 
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));
}

extern void fep_full(RU_t *ru);
1907
extern void ru_fep_full_2thread(RU_t *ru);
1908
extern void feptx_ofdm(RU_t *ru);
1909
extern void feptx_ofdm_2thread(RU_t *ru);
1910
extern void feptx_prec(RU_t *ru);
1911 1912
extern void init_fep_thread(RU_t *ru,pthread_attr_t *attr);
extern void init_feptx_thread(RU_t *ru,pthread_attr_t *attr);
1913 1914 1915 1916 1917

void init_RU_proc(RU_t *ru) {
   
  int i=0;
  RU_proc_t *proc;
1918
  pthread_attr_t *attr_FH=NULL,*attr_prach=NULL,*attr_asynch=NULL,*attr_synch=NULL, *attr_ctrl=NULL;
1919
  //pthread_attr_t *attr_fep=NULL;
1920 1921 1922
#ifdef Rel14
  pthread_attr_t *attr_prach_br=NULL;
#endif
1923 1924 1925
  char name[100];

#ifndef OCP_FRAMEWORK
1926
  LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,eNB_functions[ru->function],eNB_timing[ru->if_timing]);
1927 1928 1929 1930 1931 1932
#endif
  proc = &ru->proc;
  memset((void*)proc,0,sizeof(RU_proc_t));

  proc->ru = ru;
  proc->instance_cnt_prach       = -1;
1933
  proc->instance_cnt_synch       = -1;     ;
1934 1935
  proc->instance_cnt_FH          = -1;
  proc->instance_cnt_asynch_rxtx = -1;
khadraou's avatar
khadraou committed
1936
  proc->instance_cnt_ru 	 = -1;
1937 1938 1939 1940
  proc->first_rx                 = 1;
  proc->first_tx                 = 1;
  proc->frame_offset             = 0;
  proc->num_slaves               = 0;
1941 1942
  proc->frame_tx_unwrap          = 0;

1943
  for (i=0;i<10;i++) proc->symbol_mask[i]=0;
Raymond Knopp's avatar
Raymond Knopp committed
1944
  
1945 1946 1947 1948
  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);
1949
  pthread_mutex_init( &proc->mutex_ru,NULL);
1950 1951 1952 1953 1954
  
  pthread_cond_init( &proc->cond_prach, NULL);
  pthread_cond_init( &proc->cond_FH, NULL);
  pthread_cond_init( &proc->cond_asynch_rxtx, NULL);
  pthread_cond_init( &proc->cond_synch,NULL);
1955
  pthread_cond_init( &proc->cond_ru_thread,NULL);
1956 1957 1958 1959 1960 1961
  
  pthread_attr_init( &proc->attr_FH);
  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);
1962 1963 1964 1965 1966 1967 1968

#ifdef Rel14
  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  
1969 1970
  
#ifndef DEADLINE_SCHEDULER
1971 1972 1973 1974 1975 1976 1977
  attr_FH        = &proc->attr_FH;
  attr_prach     = &proc->attr_prach;
  attr_synch     = &proc->attr_synch;
  attr_asynch    = &proc->attr_asynch_rxtx;
#ifdef Rel14
  attr_prach_br  = &proc->attr_prach_br;
#endif
1978 1979
#endif
  
1980
  pthread_create( &proc->pthread_ctrl, attr_ctrl, ru_thread_control, (void*)ru );
khadraou's avatar
khadraou committed
1981
  pthread_create( &proc->pthread_FH, attr_FH, ru_thread, (void*)ru );
1982
  
Raymond Knopp's avatar
Raymond Knopp committed
1983

1984 1985
  if (ru->function == NGFI_RRU_IF4p5) {
    pthread_create( &proc->pthread_prach, attr_prach, ru_thread_prach, (void*)ru );
1986 1987 1988
#ifdef Rel14  
    pthread_create( &proc->pthread_prach_br, attr_prach_br, ru_thread_prach_br, (void*)ru );
#endif
1989 1990 1991 1992 1993
    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) ||
1994
	(ru->function == NGFI_RRU_IF4p5)) pthread_create( &proc->pthread_asynch_rxtx, attr_asynch, ru_thread_asynch_rxtx, (void*)ru );
1995 1996 1997 1998
    
    snprintf( name, sizeof(name), "ru_thread_FH %d", ru->idx );
    pthread_setname_np( proc->pthread_FH, name );
    
Raymond Knopp's avatar
Raymond Knopp committed
1999
  }
2000

2001 2002 2003 2004
  if (get_nprocs()>=2) { 
    if (ru->feprx) init_fep_thread(ru,NULL); 
    if (ru->feptx_ofdm) init_feptx_thread(ru,NULL);
  } 
2005
  if (opp_enabled == 1) pthread_create(&ru->ru_stats_thread,NULL,ru_stats_thread,(void*)ru); 
Raymond Knopp's avatar
Raymond Knopp committed
2006
  
2007 2008
}

2009

2010 2011


Raymond Knopp's avatar
Raymond Knopp committed
2012

2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
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
2053
  return(-1);
Raymond Knopp's avatar
Raymond Knopp committed
2054 2055 2056
}


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

2059
char rru_formats[3][20] = {"OAI_IF5","MBP_IF5","OAI_IF4p5"};
2060
char ru_if_formats[4][20] = {"LOCAL_RF","REMOTE_OAI_IF5","REMOTE_MBP_IF5","REMOTE_OAI_IF4p5"};
2061 2062 2063 2064 2065 2066 2067 2068

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;
2069
  int i;
2070 2071 2072 2073 2074

  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]);
2075

Raymond Knopp's avatar
Raymond Knopp committed
2076 2077
  AssertFatal((ret=check_capabilities(ru,capabilities)) == 0,
	      "Cannot configure RRU %d, check_capabilities returned %d\n", idx,ret);
2078 2079 2080 2081
  // 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
2082 2083 2084 2085 2086 2087 2088 2089
  // 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;      
2090 2091
  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
2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102
  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]);
    
2103
#ifdef Rel14
Raymond Knopp's avatar
Raymond Knopp committed
2104 2105 2106 2107
    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];
2108
    }
Raymond Knopp's avatar
Raymond Knopp committed
2109
#endif
2110 2111 2112 2113 2114 2115
  }

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

2116 2117
void configure_rru(int idx,
		   void *arg) {
2118 2119 2120 2121 2122 2123 2124

  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];
2125 2126 2127 2128 2129 2130 2131
  if (ru->frame_parms.dl_CarrierFreq == ru->frame_parms.ul_CarrierFreq) {
     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]; 
  }
  else
     ru->frame_parms.frame_type                                            = FDD;
2132 2133 2134 2135 2136 2137 2138
  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) {
2139 2140
    LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d\n",
	  config->prach_FreqOffset[0],config->prach_ConfigIndex[0]);
2141 2142
    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]; 
2143 2144 2145 2146 2147 2148 2149
#ifdef Rel14
    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
2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170
  }
  
  init_frame_parms(&ru->frame_parms,1);


  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++) {
2171 2172
	int nb_tx=0;
	for (ru_id=0;ru_id<RC.nb_RU;ru_id++) { 
2173
	  ru = RC.ru[ru_id];
2174 2175 2176
	  nb_tx+=ru->nb_tx;
	}
	dlsch->ue_spec_bf_weights[layer] = (int32_t**)malloc16(nb_tx*sizeof(int32_t*));
2177
	  
2178 2179 2180 2181
	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;
2182
	  }
2183
	}	
2184 2185 2186 2187 2188
      }
    }
  }
}

Raymond Knopp's avatar
Raymond Knopp committed
2189 2190 2191
extern void RCconfig_RU(void);

void init_RU(char *rf_config_file) {
Raymond Knopp's avatar
Raymond Knopp committed
2192 2193
  
  int ru_id;
2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204
  RU_t *ru;
  int ret;
  PHY_VARS_eNB *eNB0;
  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);

2205 2206
  // read in configuration file)
  printf("configuring RU from file\n");
2207
  RCconfig_RU();
2208
  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());
2209

2210
  for (i=0;i<RC.nb_L1_inst;i++) 
2211 2212 2213 2214
    for (CC_id=0;CC_id<RC.nb_CC[i];CC_id++) RC.eNB[i][CC_id]->num_RU=0;

  for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
    ru               = RC.ru[ru_id];
2215
    ru->rf_config_file = rf_config_file;
2216 2217
    ru->idx          = ru_id;              
    ru->ts_offset    = 0;
2218
    ru->in_synch     = (ru->is_slave == 1) ? 0 : 1;
2219 2220
    // 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
2221 2222

    
2223
    eNB0             = ru->eNB_list[0];
2224
    if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5))
2225
      AssertFatal(eNB0!=NULL,"eNB0 is null!\n");
2226

2227 2228 2229
    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));
2230 2231 2232 2233 2234 2235

      // attach all RU to all eNBs in its list/
      for (i=0;i<ru->num_eNB;i++) {
	eNB0 = ru->eNB_list[i];
	eNB0->RU_list[eNB0->num_RU++] = ru;
      }
2236
    }
2237
    //    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);
2238 2239 2240

    
    switch (ru->if_south) {
Raymond Knopp's avatar
Raymond Knopp committed
2241
    case LOCAL_RF:   // this is an RU with integrated RF (RRU, eNB)
2242 2243
      if (ru->function ==  NGFI_RRU_IF5) {                 // IF5 RRU
	ru->do_prach              = 0;                      // no prach processing in RU
2244
	ru->fh_north_in           = NULL;                   // no shynchronous incoming fronthaul from north
2245 2246 2247 2248 2249 2250
	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)
Raymond Knopp's avatar
Raymond Knopp committed
2251
	ru->start_if              = start_if;               // need to start the if interface for if5
2252 2253 2254
	ru->ifdevice.host_type    = RRU_HOST;
	ru->rfdevice.host_type    = RRU_HOST;
	ru->ifdevice.eth_params   = &ru->eth_params;
2255 2256
    reset_meas(&ru->rx_fhaul);
    reset_meas(&ru->tx_fhaul);
2257 2258
    reset_meas(&ru->compression);
    reset_meas(&ru->transport);
2259 2260 2261 2262 2263 2264 2265

	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_id);
	if (ret<0) {
	  printf("Exiting, cannot initialize transport protocol\n");
	  exit(-1);
	}
Raymond Knopp's avatar
Raymond Knopp committed
2266
      }
2267 2268 2269 2270 2271 2272
      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
2273 2274
	ru->feprx                 = (get_nprocs()<=2) ? fep_full :ru_fep_full_2thread;                 // RX DFTs
	ru->feptx_ofdm            = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread;               // this is fep with idft only (no precoding in RRU)
2275
	ru->feptx_prec            = NULL;
2276
	ru->start_if              = start_if;                 // need to start the if interfacef for if4p5
2277 2278 2279
	ru->ifdevice.host_type    = RRU_HOST;
	ru->rfdevice.host_type    = RRU_HOST;
	ru->ifdevice.eth_params   = &ru->eth_params;
2280 2281
    reset_meas(&ru->rx_fhaul);
    reset_meas(&ru->tx_fhaul);
2282 2283
    reset_meas(&ru->compression);
    reset_meas(&ru->transport);
2284 2285 2286 2287 2288 2289 2290 2291

	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_id);
	if (ret<0) {
	  printf("Exiting, cannot initialize transport protocol\n");
	  exit(-1);
	}
	malloc_IF4p5_buffer(ru);
Raymond Knopp's avatar
Raymond Knopp committed
2292
      }
2293 2294
      else if (ru->function == eNodeB_3GPP) {  
	ru->do_prach             = 0;                       // no prach processing in RU            
2295 2296
	ru->feprx                = (get_nprocs()<=2) ? fep_full : ru_fep_full_2thread;                // RX DFTs
	ru->feptx_ofdm           = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread;              // this is fep with idft and precoding
2297
	ru->feptx_prec           = feptx_prec;              // this is fep with idft and precoding
Raymond Knopp's avatar
Raymond Knopp committed
2298 2299 2300
	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
2301
	ru->rfdevice.host_type   = RAU_HOST;
Raymond Knopp's avatar
Raymond Knopp committed
2302 2303
      }
      ru->fh_south_in            = rx_rf;                               // local synchronous RF RX
2304
      ru->fh_south_out           = tx_rf;                               // local synchronous RF TX
Raymond Knopp's avatar
Raymond Knopp committed
2305
      ru->start_rf               = start_rf;                            // need to start the local RF interface
2306
      printf("configuring ru_id %d (start_rf %p)\n",ru_id,start_rf);
2307
/*
2308 2309 2310 2311 2312
      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);
      }
Raymond Knopp's avatar
Raymond Knopp committed
2313

2314 2315 2316
      ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg);
      if (setup_RU_buffers(ru)!=0) {
	printf("Exiting, cannot initialize RU Buffers\n");
Raymond Knopp's avatar
Raymond Knopp committed
2317
	exit(-1);
2318
      }*/
Raymond Knopp's avatar
Raymond Knopp committed
2319 2320 2321
      break;

    case REMOTE_IF5: // the remote unit is IF5 RRU
2322
      ru->do_prach               = 0;
2323
      ru->feprx                  = (get_nprocs()<=2) ? fep_full : fep_full;                   // this is frequency-shift + DFTs
2324
      ru->feptx_prec             = feptx_prec;                 // need to do transmit Precoding + IDFTs 
2325
      ru->feptx_ofdm             = (get_nprocs()<=2) ? feptx_ofdm : feptx_ofdm_2thread;                 // need to do transmit Precoding + IDFTs 
2326 2327 2328 2329
      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
Raymond Knopp's avatar
Raymond Knopp committed
2330 2331
      }
      else {
2332 2333 2334
	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
Raymond Knopp's avatar
Raymond Knopp committed
2335
      }
2336 2337 2338 2339 2340
      ru->start_rf               = NULL;                 // no local RF
      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;
Raymond Knopp's avatar
Raymond Knopp committed
2341

2342
      ret = openair0_transport_load(&ru->ifdevice,&ru->openair0_cfg,&ru->eth_params);
Raymond Knopp's avatar
Raymond Knopp committed
2343 2344 2345 2346 2347 2348 2349 2350
      printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id);
      if (ret<0) {
	printf("Exiting, cannot initialize transport protocol\n");
	exit(-1);
      }
      break;

    case REMOTE_IF4p5:
2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366
      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
      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);
Raymond Knopp's avatar
Raymond Knopp committed
2367
      printf("openair0_transport_init returns %d for ru_id %d\n",ret,ru_id);
khadraou's avatar
khadraou committed
2368
      
Raymond Knopp's avatar
Raymond Knopp committed
2369 2370 2371 2372 2373
      if (ret<0) {
	printf("Exiting, cannot initialize transport protocol\n");
	exit(-1);
      }
      
2374
      malloc_IF4p5_buffer(ru);
Raymond Knopp's avatar
Raymond Knopp committed
2375 2376 2377
      
      break;

2378 2379
    default:
      LOG_E(PHY,"RU with invalid or unknown southbound interface type %d\n",ru->if_south);
Raymond Knopp's avatar
Raymond Knopp committed
2380 2381 2382
      break;
    } // switch on interface type 

2383 2384 2385 2386 2387 2388
    LOG_I(PHY,"Starting ru_thread %d\n",ru_id);

    init_RU_proc(ru);



Raymond Knopp's avatar
Raymond Knopp committed
2389 2390
  } // for ru_id

2391
  //  sleep(1);
2392
  LOG_D(HW,"[lte-softmodem.c] RU threads created\n");
Raymond Knopp's avatar
Raymond Knopp committed
2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404
  

}




void stop_ru(RU_t *ru) {

  printf("Stopping RU %p processing threads\n",(void*)ru);
  
}
2405