lte-ru.c 106 KB
Newer Older
knopp's avatar
knopp committed
1
2
3
/*******************************************************************************
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom
knopp's avatar
knopp committed
4
 
knopp's avatar
knopp committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


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

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

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

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

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

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

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

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

#include "PHY/types.h"

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


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

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

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

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

86
#include "common/utils/LOG/log.h"
knopp's avatar
knopp committed
87
88
89
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/OTG/otg_externs.h"
#include "UTIL/MATH/oml.h"
90
#include "common/utils/LOG/vcd_signal_dumper.h"
knopp's avatar
knopp committed
91
92
93
94
#include "UTIL/OPT/opt.h"
#include "enb_config.h"
//#include "PHY/TOOLS/time_meas.h"

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

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

knopp's avatar
knopp committed
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#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"

Wang Tsu-Han's avatar
Wang Tsu-Han committed
117
#include "pdcp.h"
Wang Tsu-Han's avatar
Wang Tsu-Han committed
118

knopp's avatar
knopp committed
119
extern volatile int                    oai_exit;
120
extern int emulate_rf;
121
extern int numerology;
Konstantinos Alexandris's avatar
Konstantinos Alexandris committed
122
extern clock_source_t clock_source;
knopp's avatar
knopp committed
123

Wang Tsu-Han's avatar
Wang Tsu-Han committed
124
125
extern PARALLEL_CONF_t get_thread_parallel_conf(void);
extern WORKER_CONF_t   get_thread_worker_conf(void);
knopp's avatar
knopp committed
126
extern void  phy_init_RU(RU_t*);
127
extern void  phy_free_RU(RU_t*);
knopp's avatar
knopp committed
128

knopp's avatar
knopp committed
129
void init_RU(char*);
Robert Schmidt's avatar
Robert Schmidt committed
130
void stop_RU(int nb_ru);
131
void do_ru_sync(RU_t *ru);
knopp's avatar
knopp committed
132

knopp's avatar
knopp committed
133
134
135
136
137
138
139
void configure_ru(int idx,
		  void *arg);

void configure_rru(int idx,
		   void *arg);

int attach_rru(RU_t *ru);
knopp's avatar
knopp committed
140

knopp's avatar
knopp committed
141
int connect_rau(RU_t *ru);
knopp's avatar
knopp committed
142

143
extern uint16_t sf_ahead;
144

knopp's avatar
knopp committed
145
146
147
/*************************************************************/
/* Functions to attach and configure RRU                     */

knopp's avatar
knopp committed
148
extern void wait_eNBs(void);
149

knopp's avatar
knopp committed
150
151
152
153
154
155
int attach_rru(RU_t *ru) {
  
  ssize_t      msg_len,len;
  RRU_CONFIG_msg_t rru_config_msg;
  int received_capabilities=0;

knopp's avatar
knopp committed
156
  wait_eNBs();
knopp's avatar
knopp committed
157
158
159
  // Wait for capabilities
  while (received_capabilities==0) {
    
160
    memset((void*)&rru_config_msg,0,sizeof(rru_config_msg));
knopp's avatar
knopp committed
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
    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]);

208

knopp's avatar
knopp committed
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
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
  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++) {
267
268
	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);
knopp's avatar
knopp committed
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
    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;
}
knopp's avatar
knopp committed
308
309
310
311
312
/*************************************************************/
/* Southbound Fronthaul functions, RCC/RAU                   */

// southbound IF5 fronthaul for 16-bit OAI format
static inline void fh_if5_south_out(RU_t *ru) {
313
  if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
314
  send_IF5(ru, ru->proc.timestamp_tx, ru->proc.tti_tx, &ru->seqno, IF5_RRH_GW_DL);
knopp's avatar
knopp committed
315
316
317
318
}

// southbound IF5 fronthaul for Mobipass packet format
static inline void fh_if5_mobipass_south_out(RU_t *ru) {
319
  if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
320
  send_IF5(ru, ru->proc.timestamp_tx, ru->proc.tti_tx, &ru->seqno, IF5_MOBIPASS); 
knopp's avatar
knopp committed
321
322
323
324
}

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

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

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

Guy De Souza's avatar
Guy De Souza committed
337
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
338
  RU_proc_t *proc = &ru->proc;
knopp's avatar
knopp committed
339

340
  recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); 
knopp's avatar
knopp committed
341
342

  proc->frame_rx    = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
343
  proc->tti_rx = (proc->timestamp_rx / fp->samples_per_tti)%10;
knopp's avatar
knopp committed
344
345
  
  if (proc->first_rx == 0) {
346
347
    if (proc->tti_rx != *subframe){
      LOG_E(PHY,"Received Timestamp doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",proc->tti_rx,*subframe);
knopp's avatar
knopp committed
348
349
350
351
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
352
      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);
knopp's avatar
knopp committed
353
354
355
356
357
      exit_fun("Exiting");
    }
  } else {
    proc->first_rx = 0;
    *frame = proc->frame_rx;
358
    *subframe = proc->tti_rx;        
knopp's avatar
knopp committed
359
360
361
362
363
364
365
366
367
  }      
  
  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) {

Guy De Souza's avatar
Guy De Souza committed
368
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
369
370
  RU_proc_t *proc = &ru->proc;
  int f,sf;
knopp's avatar
knopp committed
371
372
373
374


  uint16_t packet_type;
  uint32_t symbol_number=0;
375
376
377
378
379
380
  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; 
knopp's avatar
knopp committed
381

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

386
387
388
389
    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);       
390
      break;     
391
      
knopp's avatar
knopp committed
392
    } else if (packet_type == IF4p5_PRACH) {
393
      // nothing in RU for RAU
knopp's avatar
knopp committed
394
    }
395
    LOG_D(PHY,"rx_fh_if4p5: subframe %d symbol mask %x\n",*subframe,proc->symbol_mask[*subframe]);
396
  } while(proc->symbol_mask[*subframe] != symbol_mask_full);    
knopp's avatar
knopp committed
397
398

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

421
422
  if (ru == RC.ru[0]) {
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_RX0_RU, f );
423
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, sf );
424
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
425
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, proc->tti_tx );
426
427
  }

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

// 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
438
  RU_proc_t *proc=&ru->proc;
knopp's avatar
knopp committed
439
440
441
442
443
444
445
446
447

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

  
}

448
449
// asynchronous inbound if5 fronthaul from south (Mobipass)
void fh_if5_south_asynch_in_mobipass(RU_t *ru,int *frame,int *subframe) {
knopp's avatar
knopp committed
450

451
  RU_proc_t *proc       = &ru->proc;
Guy De Souza's avatar
Guy De Souza committed
452
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
knopp's avatar
knopp committed
453

454
455
456
457
  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);
458
  proc->tti_rx = ((proc->timestamp_rx-offset_mobipass)/fp->samples_per_tti)%10;
459
  proc->frame_rx    = ((proc->timestamp_rx-offset_mobipass)/(fp->samples_per_tti*10))&1023;
knopp's avatar
knopp committed
460

461
  proc->tti_rx = (proc->timestamp_rx/fp->samples_per_tti)%10;
462
  proc->frame_rx    = (proc->timestamp_rx/(10*fp->samples_per_tti))&1023;
knopp's avatar
knopp committed
463

464
465
  if (proc->first_rx == 1) {
    proc->first_rx =2;
466
    *subframe = proc->tti_rx;
knopp's avatar
knopp committed
467
    *frame    = proc->frame_rx; 
468
    LOG_E(PHY,"[Mobipass]timestamp_rx:%llu, frame_rx %d, subframe: %d\n",(unsigned long long int)proc->timestamp_rx,proc->frame_rx,proc->tti_rx);
knopp's avatar
knopp committed
469
470
  }
  else {
471
    if (proc->tti_rx != *subframe) {
472
        proc->first_rx++;
473
	LOG_E(PHY,"[Mobipass]timestamp:%llu, tti_rx %d is not what we expect %d, first_rx:%d\n",(unsigned long long int)proc->timestamp_rx, proc->tti_rx,*subframe, proc->first_rx);
474
      //exit_fun("Exiting");
knopp's avatar
knopp committed
475
476
    }
    if (proc->frame_rx != *frame) {
477
478
479
        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");
knopp's avatar
knopp committed
480
    }
481
    // temporary solution
482
      *subframe = proc->tti_rx;
483
      *frame    = proc->frame_rx;
knopp's avatar
knopp committed
484
  }
485
486
487
488

  pthread_mutex_unlock(&proc->mutex_asynch_rxtx);


knopp's avatar
knopp committed
489
490
491
492
493
} // eNodeB_3GPP_BBU 

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

Guy De Souza's avatar
Guy De Souza committed
494
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
495
  RU_proc_t *proc       = &ru->proc;
knopp's avatar
knopp committed
496
497

  uint16_t packet_type;
knopp's avatar
knopp committed
498
  uint32_t symbol_number,symbol_mask,prach_rx;
499
  uint32_t got_prach_info=0;
knopp's avatar
knopp committed
500
501

  symbol_number = 0;
502
503
  symbol_mask   = (1<<fp->symbols_per_tti)-1;
  prach_rx      = 0;
knopp's avatar
knopp committed
504
505

  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
506
    recv_IF4p5(ru, &proc->frame_rx, &proc->tti_rx, &packet_type, &symbol_number);
507
508
    // grab first prach information for this new subframe
    if (got_prach_info==0) {
509
      prach_rx       = is_prach_subframe(fp, proc->frame_rx, proc->tti_rx);
510
511
      got_prach_info = 1;
    }
knopp's avatar
knopp committed
512
513
    if (proc->first_rx != 0) {
      *frame = proc->frame_rx;
514
      *subframe = proc->tti_rx;
knopp's avatar
knopp committed
515
516
517
518
519
520
521
      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");
      }
522
523
      if (proc->tti_rx != *subframe) {
	LOG_E(PHY,"tti_rx %d is not what we expect %d\n",proc->tti_rx,*subframe);
knopp's avatar
knopp committed
524
525
526
	exit_fun("Exiting");
      }
    }
527
528
    if      (packet_type == IF4p5_PULFFT)       symbol_mask &= (~(1<<symbol_number));
    else if (packet_type == IF4p5_PRACH)        prach_rx    &= (~0x1);
529
#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
530
531
532
533
534
535
    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 
knopp's avatar
knopp committed
536
537
538
539
540
541
542
543
544
545
546
} 





/*************************************************************/
/* 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
547
void fh_if4p5_north_in(RU_t *ru,int *frame,int *subframe) {
knopp's avatar
knopp committed
548
549
550
551
552

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

553

knopp's avatar
knopp committed
554
555
556
  /// **** incoming IF4p5 from remote RCC/RAU **** ///             
  symbol_number = 0;
  symbol_mask = 0;
557
  symbol_mask_full = (1<<ru->frame_parms->symbols_per_tti)-1;
knopp's avatar
knopp committed
558
559
  
  do { 
560
    recv_IF4p5(ru, frame, subframe, &packet_type, &symbol_number);
knopp's avatar
knopp committed
561
562
563
    symbol_mask = symbol_mask | (1<<symbol_number);
  } while (symbol_mask != symbol_mask_full); 

564
565
  // dump VCD output for first RU in list
  if (ru == RC.ru[0]) {
566
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, *frame );
567
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, *subframe );
knopp's avatar
knopp committed
568
569
570
571
572
  }
}

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

Guy De Souza's avatar
Guy De Souza committed
573
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
574
  RU_proc_t *proc        = &ru->proc;
575
  int tti_tx,frame_tx;
knopp's avatar
knopp committed
576
577
578
  openair0_timestamp timestamp_tx;

  recv_IF5(ru, &timestamp_tx, *subframe, IF5_RRH_GW_DL); 
579
      //      printf("Received subframe %d (TS %llu) from RCC\n",tti_tx,timestamp_tx);
knopp's avatar
knopp committed
580

581
  tti_tx = (timestamp_tx/fp->samples_per_tti)%10;
knopp's avatar
knopp committed
582
583
584
  frame_tx    = (timestamp_tx/(fp->samples_per_tti*10))&1023;

  if (proc->first_tx != 0) {
585
    *subframe = tti_tx;
knopp's avatar
knopp committed
586
587
588
589
    *frame    = frame_tx;
    proc->first_tx = 0;
  }
  else {
590
591
    AssertFatal(tti_tx == *subframe,
                "tti_tx %d is not what we expect %d\n",tti_tx,*subframe);
592
593
    AssertFatal(frame_tx == *frame, 
                "frame_tx %d is not what we expect %d\n",frame_tx,*frame);
knopp's avatar
knopp committed
594
595
596
597
598
  }
}

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

Guy De Souza's avatar
Guy De Souza committed
599
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
600
  RU_proc_t *proc        = &ru->proc;
knopp's avatar
knopp committed
601
602
603

  uint16_t packet_type;
  uint32_t symbol_number,symbol_mask,symbol_mask_full;
604
  int tti_tx,frame_tx;
knopp's avatar
knopp committed
605

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

633
  if (subframe_select(fp,tti_tx) == SF_DL) stop_meas(&ru->rx_fhaul);
634

635
  proc->tti_tx  = tti_tx;
636
637
  proc->frame_tx     = frame_tx;

638
  if ((frame_tx == 0)&&(tti_tx == 0)) proc->frame_tx_unwrap += 1024;
639

640
  proc->timestamp_tx = ((((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * 10) + (uint64_t)tti_tx) * (uint64_t)fp->samples_per_tti;
641

642
  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,tti_tx);
643
644
645
    // 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 );
646
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, tti_tx );
647
  }
knopp's avatar
knopp committed
648

649
650
  if (ru->feptx_ofdm) ru->feptx_ofdm(ru);
  if (ru->fh_south_out) ru->fh_south_out(ru);
knopp's avatar
knopp committed
651
652
} 

653
654
655
656
657
658
659
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 );  
660
  send_IF5(ru, proc->timestamp_rx, proc->tti_rx, &seqno, IF5_RRH_GW_UL);
661
662
663
664
665
666
667
668
  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;
Guy De Souza's avatar
Guy De Souza committed
669
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
670
671
  const int subframe     = proc->tti_rx;
  if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx );
672
673
674

  if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) {
    /// **** in TDD during DL send_IF4 of ULTICK to RCC **** ///
675
    send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULTICK);
676
677
678
    return;
  }

679
  start_meas(&ru->tx_fhaul);
680
  send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULFFT);
681
  stop_meas(&ru->tx_fhaul);
682
683

}
684

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

volatile late_control_e late_control=STATE_BURST_NORMAL;

/* add fail safe for late command end */

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

knopp's avatar
knopp committed
731
732
void rx_rf(RU_t *ru,int *frame,int *subframe) {

733
  RU_proc_t *proc = &ru->proc;
Guy De Souza's avatar
Guy De Souza committed
734
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
735
  void *rxp[ru->nb_rx];
736
  unsigned int rxs;
knopp's avatar
knopp committed
737
  int i;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
738
  openair0_timestamp ts=0,old_ts=0;
knopp's avatar
knopp committed
739
    
740
  for (i=0; i<ru->nb_rx; i++)
741
    rxp[i] = (void*)&ru->common.rxdata[i][*subframe*fp->samples_per_tti];
742

knopp's avatar
knopp committed
743
744
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );

745
  old_ts = proc->timestamp_rx;
746
747
748
749
750
751
752
  if(emulate_rf){
    wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
    release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread");
    rxs = fp->samples_per_tti;
  }
  else{
    rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
753
				   &ts,
knopp's avatar
knopp committed
754
755
				   rxp,
				   fp->samples_per_tti,
756
				   ru->nb_rx);
757
  }
knopp's avatar
knopp committed
758
759
760
  
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
 
761
  proc->timestamp_rx = ts-ru->ts_offset;
762

Wang Tsu-Han's avatar
Wang Tsu-Han committed
763
764
765
766
767
768
//  AssertFatal(rxs == fp->samples_per_tti,
//	      "rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs);
  if(rxs != fp->samples_per_tti){
    LOG_E(PHY,"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_tti,rxs);
    late_control=STATE_BURST_TERMINATE;
  }
769
770

  if (proc->first_rx == 1) {
771
    ru->ts_offset = proc->timestamp_rx;
772
773
774
775
    proc->timestamp_rx = 0;
  }
  else {
    if (proc->timestamp_rx - old_ts != fp->samples_per_tti) {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
776
      //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);
777
      ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti);
778
      proc->timestamp_rx = ts-ru->ts_offset;
779
780
781
782
    }

  }
  proc->frame_rx     = (proc->timestamp_rx / (fp->samples_per_tti*10))&1023;
783
  proc->tti_rx  = (proc->timestamp_rx / fp->samples_per_tti)%10;
knopp's avatar
knopp committed
784
785
  // synchronize first reception to frame 0 subframe 0

Wang Tsu-Han's avatar
Wang Tsu-Han committed
786
787
#ifdef PHY_TX_THREAD
  proc->timestamp_phy_tx = proc->timestamp_rx+((sf_ahead-1)*fp->samples_per_tti);
788
789
  proc->subframe_phy_tx  = (proc->tti_rx+(sf_ahead-1))%10;  
  proc->frame_phy_tx     = (proc->tti_rx>(9-(sf_ahead-1))) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
790
791
#else
  proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti);
792
793
  proc->tti_tx  = (proc->tti_rx+sf_ahead)%10;
  proc->frame_tx     = (proc->tti_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
794
795
#endif

796
  //proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti);
797
798
  //proc->subframe_tx  = (proc->tti_rx+sf_ahead)%10;
  //proc->frame_tx     = (proc->tti_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
799
800
801
802
803
  
  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,
804
	(int)ru->ts_offset,proc->frame_rx,proc->tti_rx);
805

806
807
808
    // 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 );
809
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx );
810
  }
knopp's avatar
knopp committed
811
812
  
  if (proc->first_rx == 0) {
813
814
    if (proc->tti_rx != *subframe){
      LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->tti_rx %d, subframe %d)\n",(long long unsigned int)proc->timestamp_rx,proc->tti_rx,*subframe);
knopp's avatar
knopp committed
815
816
817
818
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
819
      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);
knopp's avatar
knopp committed
820
821
822
823
824
      exit_fun("Exiting");
    }
  } else {
    proc->first_rx = 0;
    *frame = proc->frame_rx;
825
    *subframe = proc->tti_rx;        
knopp's avatar
knopp committed
826
827
  }
  
828
  //printf("timestamp_rx %lu, frame %d(%d), subframe %d(%d)\n",ru->timestamp_rx,proc->frame_rx,frame,proc->tti_rx,subframe);
knopp's avatar
knopp committed
829
  
830
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
knopp's avatar
knopp committed
831
832
  
  if (rxs != fp->samples_per_tti)
833
  {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
834
835
836
#if defined(USRP_REC_PLAY)
    exit_fun("Exiting IQ record/playback");
#else    
837
    //exit_fun( "problem receiving samples" );
Cedric Roux's avatar
Cedric Roux committed
838
    LOG_E(PHY, "problem receiving samples");
Wang Tsu-Han's avatar
Wang Tsu-Han committed
839
#endif    
840
  }
knopp's avatar
knopp committed
841
842
843
}


844
845
846
void tx_rf(RU_t *ru) {

  RU_proc_t *proc = &ru->proc;
Guy De Souza's avatar
Guy De Souza committed
847
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
848
  void *txp[ru->nb_tx]; 
849
850
851
  unsigned int txs;
  int i;

852
853
  T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), T_INT(proc->frame_tx), T_INT(proc->tti_tx),
    T_INT(0), T_BUFFER(&ru->common.txdata[0][proc->tti_tx * fp->samples_per_tti], fp->samples_per_tti * 4));
Cedric Roux's avatar
Cedric Roux committed
854

855
856
857
  lte_subframe_t SF_type     = subframe_select(fp,proc->tti_tx%10);
  lte_subframe_t prevSF_type = subframe_select(fp,(proc->tti_tx+9)%10);
  lte_subframe_t nextSF_type = subframe_select(fp,(proc->tti_tx+1)%10);
858
859
  int sf_extension = 0;

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

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

knopp's avatar
knopp committed
928
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, proc->frame_tx );
929
    VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, proc->tti_tx );
Wang Tsu-Han's avatar
Wang Tsu-Han committed
930

931
932
933
934
935
    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,
936
				      proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension,
937
				      txp,
938
				      siglen+sf_extension,
939
940
941
942
				      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,
943
	  (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->tti_tx);
944
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
945
    
946
    
Wang Tsu-Han's avatar
Wang Tsu-Han committed
947
948
949
950
951
//    AssertFatal(txs ==  siglen+sf_extension,"TX : Timeout (sent %d/%d)\n",txs, siglen);
    if( (txs !=  siglen+sf_extension) && (late_control==STATE_BURST_NORMAL) ){ /* add fail safe for late command */
      late_control=STATE_BURST_TERMINATE;
      LOG_E(PHY,"TX : Timeout (sent %d/%d) state =%d\n",txs, siglen,late_control);
    }
952
  }
953
954
955
}


knopp's avatar
knopp committed
956
957
958
959
960
961
962
963
964
965
/*!
 * \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;

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

knopp's avatar
knopp committed
969
970
971
972


  int subframe=0, frame=0; 

Wang Tsu-Han's avatar
Wang Tsu-Han committed
973
  thread_top_init("ru_thread_asynch_rxtx",1,870000,1000000,1000000);
knopp's avatar
knopp committed
974
975
976

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

977
  wait_sync("ru_thread_asynch_rxtx");
knopp's avatar
knopp committed
978
979

  // wait for top-level synchronization and do one acquisition to get timestamp for setting frame/subframe
980
  printf( "waiting for devices (ru_thread_asynch_rx)\n");
knopp's avatar
knopp committed
981
982
983

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

984
  printf( "devices ok (ru_thread_asynch_rx)\n");
knopp's avatar
knopp committed
985
986
987
988
989
990
991
992
993
994
995
996
997


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

    if (subframe==9) { 
      subframe=0;
      frame++;
      frame&=1023;
    } else {
      subframe++;
    }      
998
    LOG_D(PHY,"ru_thread_asynch_rxtx: Waiting on incoming fronthaul\n");
Wang Tsu-Han's avatar
Wang Tsu-Han committed
999
	// asynchronous receive from south (Mobipass)
1000
1001
    if (ru->fh_south_asynch_in) ru->fh_south_asynch_in(ru,&frame,&subframe);
    // asynchronous receive from north (RRU IF4/IF5)
1002
    else if (ru->fh_north_asynch_in) {
Guy De Souza's avatar
Guy De Souza committed
1003
       if (subframe_select(ru->frame_parms,subframe)!=SF_UL)
1004
1005
         ru->fh_north_asynch_in(ru,&frame,&subframe);
    }
1006
    else AssertFatal(1==0,"Unknown function in ru_thread_asynch_rxtx\n");
knopp's avatar
knopp committed
1007
1008
1009
1010
1011
1012
1013
1014
1015
  }

  ru_thread_asynch_rxtx_status=0;
  return(&ru_thread_asynch_rxtx_status);
}




1016
void wakeup_slaves(RU_proc_t *proc) {
knopp's avatar
knopp committed
1017
1018
1019
1020
1021
1022
1023
1024

  int i;
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
  
  for (i=0;i<proc->num_slaves;i++) {
1025
    RU_proc_t *slave_proc = proc->slave_proc[i];
knopp's avatar
knopp committed
1026
1027
1028
    // 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) {
1029
      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);
knopp's avatar
knopp committed
1030
1031
1032
1033
1034
1035
      exit_fun( "error locking mutex_rxtx" );
      break;
    }
    
    int cnt_slave            = ++slave_proc->instance_cnt_FH;
    slave_proc->frame_rx     = proc->frame_rx;
1036
    slave_proc->tti_rx  = proc->tti_rx;
knopp's avatar
knopp committed
1037
1038
1039
1040
1041
1042
1043
1044
    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) {
1045
	LOG_E( PHY, "ERROR pthread_cond_signal for RU %d, slave RU %d\n",proc->ru->idx,slave_proc->ru->idx);
knopp's avatar
knopp committed
1046
1047
1048
1049
          exit_fun( "ERROR pthread_cond_signal" );
	  break;
      }
    } else {
1050
      LOG_W( PHY,"[RU] Frame %d, slave %d thread busy!! (cnt_FH %i)\n",slave_proc->frame_rx,slave_proc->ru->idx, cnt_slave);
knopp's avatar
knopp committed
1051
1052
1053
1054
1055
1056
1057
1058
      exit_fun( "FH thread busy" );
      break;
    }             
  }
}

/*!
 * \brief The prach receive thread of RU.
1059
 * \param param is a \ref RU_proc_t structure which contains the info what to process.
knopp's avatar
knopp committed
1060
1061
1062
 * \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 ) {
1063

knopp's avatar
knopp committed
1064
1065
  static int ru_thread_prach_status;

1066
1067
  RU_t *ru        = (RU_t*)param;
  RU_proc_t *proc = (RU_proc_t*)&ru->proc;
knopp's avatar
knopp committed
1068
1069

  // set default return value
1070
  ru_thread_prach_status = 0;
knopp's avatar
knopp committed
1071

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1072
  thread_top_init("ru_thread_prach",1,500000,1000000,20000000);
1073
  //wait_sync("ru_thread_prach");
knopp's avatar
knopp committed
1074

1075
1076
1077
1078
1079
1080
  while (RC.ru_mask>0) {
    usleep(1e6);
    LOG_I(PHY,"%s() RACH waiting for RU to be configured\n", __FUNCTION__);
  }
  LOG_I(PHY,"%s() RU configured - RACH processing thread running\n", __FUNCTION__);

knopp's avatar
knopp committed
1081
1082
  while (!oai_exit) {
    
1083
    if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
1084
    if (oai_exit) break;
1085
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );      
1086
1087
    if (ru->eNB_list[0]){
      prach_procedures(
1088
        ru->eNB_list[0]
1089
#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
1090
        ,0
1091
#endif
1092
        );
1093
1094
1095
1096
1097
1098
1099
1100
1101
    }
    else {
       rx_prach(NULL,
  	        ru,
	        NULL,
                NULL,
                NULL,
                proc->frame_prach,
                0
Bi-Ruei, Chiu's avatar