lte-ru.c 92 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
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"
knopp's avatar
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

#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"

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

102
103
104
#include "ENB_APP/enb_paramdef.h"
#include "common/config/config_userapi.h"

knopp's avatar
knopp committed
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#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
120

knopp's avatar
knopp committed
121
extern volatile int                    oai_exit;
122
extern int emulate_rf;
123
extern int numerology;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
124
extern int fepw;
knopp's avatar
knopp committed
125
126


knopp's avatar
knopp committed
127
extern void  phy_init_RU(RU_t*);
128
extern void  phy_free_RU(RU_t*);
knopp's avatar
knopp committed
129

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

knopp's avatar
knopp committed
134
135
136
137
138
139
140
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
141

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

144
extern uint16_t sf_ahead;
145

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

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

knopp's avatar
knopp committed
151
152
153
154
155
156
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
157
  wait_eNBs();
knopp's avatar
knopp committed
158
159
160
  // Wait for capabilities
  while (received_capabilities==0) {
    
161
    memset((void*)&rru_config_msg,0,sizeof(rru_config_msg));
knopp's avatar
knopp committed
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
208
    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]);

209

knopp's avatar
knopp committed
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
267
  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++) {
268
269
	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
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
308
    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
309
310
311
312
313
/*************************************************************/
/* Southbound Fronthaul functions, RCC/RAU                   */

// southbound IF5 fronthaul for 16-bit OAI format
static inline void fh_if5_south_out(RU_t *ru) {
314
315
  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);
knopp's avatar
knopp committed
316
317
318
319
}

// southbound IF5 fronthaul for Mobipass packet format
static inline void fh_if5_mobipass_south_out(RU_t *ru) {
320
321
  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); 
knopp's avatar
knopp committed
322
323
324
325
}

// southbound IF4p5 fronthaul
static inline void fh_if4p5_south_out(RU_t *ru) {
326
  if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff );
327
  LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx);
328
329
  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);
knopp's avatar
knopp committed
330
331
332
333
334
335
336
337
338
}

/*************************************************************/
/* 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;
339
  RU_proc_t *proc = &ru->proc;
knopp's avatar
knopp committed
340

341
  recv_IF5(ru, &proc->timestamp_rx, *subframe, IF5_RRH_GW_UL); 
knopp's avatar
knopp committed
342
343
344
345
346
347

  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){
348
      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);
knopp's avatar
knopp committed
349
350
351
352
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
353
      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
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
      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;
370
371
  RU_proc_t *proc = &ru->proc;
  int f,sf;
knopp's avatar
knopp committed
372
373
374
375


  uint16_t packet_type;
  uint32_t symbol_number=0;
376
377
378
379
380
381
  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
382

383
  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
384
  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
385
    recv_IF4p5(ru, &f, &sf, &packet_type, &symbol_number);
knopp's avatar
knopp committed
386

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

  //caculate timestamp_rx, timestamp_tx based on frame and subframe
400
401
  proc->subframe_rx  = sf;
  proc->frame_rx     = f;
402
  proc->timestamp_rx = ((proc->frame_rx * 10)  + proc->subframe_rx ) * fp->samples_per_tti ;
403
  //  proc->timestamp_tx = proc->timestamp_rx +  (4*fp->samples_per_tti);
404
405
  proc->subframe_tx  = (sf+sf_ahead)%10;
  proc->frame_tx     = (sf>(9-sf_ahead)) ? (f+1)&1023 : f;
knopp's avatar
knopp committed
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
 
  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;        
  }
421

422
423
424
425
426
427
428
  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 );
  }

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

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

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

  
}

449
450
// 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
451

452
453
  RU_proc_t *proc       = &ru->proc;
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
knopp's avatar
knopp committed
454

455
456
457
458
459
460
  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;
knopp's avatar
knopp committed
461

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

465
466
  if (proc->first_rx == 1) {
    proc->first_rx =2;
knopp's avatar
knopp committed
467
468
    *subframe = proc->subframe_rx;
    *frame    = proc->frame_rx; 
469
    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);
knopp's avatar
knopp committed
470
471
472
  }
  else {
    if (proc->subframe_rx != *subframe) {
473
474
475
        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");
knopp's avatar
knopp committed
476
477
    }
    if (proc->frame_rx != *frame) {
478
479
480
        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
481
    }
482
483
484
    // temporary solution
      *subframe = proc->subframe_rx;
      *frame    = proc->frame_rx;
knopp's avatar
knopp committed
485
  }
486
487
488
489

  pthread_mutex_unlock(&proc->mutex_asynch_rxtx);


knopp's avatar
knopp committed
490
491
492
493
494
495
} // 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;
496
  RU_proc_t *proc       = &ru->proc;
knopp's avatar
knopp committed
497
498

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

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

  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
    recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number);
508
509
510
511
512
    // 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;
    }
knopp's avatar
knopp committed
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
    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");
      }
    }
528
529
530
531
532
533
534
535
536
    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 
knopp's avatar
knopp committed
537
538
539
540
541
542
543
544
545
546
547
} 





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

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

554

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

565
566
  // dump VCD output for first RU in list
  if (ru == RC.ru[0]) {
567
568
    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 );
knopp's avatar
knopp committed
569
570
571
572
573
574
  }
}

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

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
575
  RU_proc_t *proc        = &ru->proc;
knopp's avatar
knopp committed
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
  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 {
591
592
593
594
    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);
knopp's avatar
knopp committed
595
596
597
598
599
600
  }
}

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

  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
601
  RU_proc_t *proc        = &ru->proc;
knopp's avatar
knopp committed
602
603
604
605
606

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

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

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

636
637
638
639
  proc->subframe_tx  = subframe_tx;
  proc->frame_tx     = frame_tx;

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

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

643
  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);
644
645
646
647
648
    // 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 );
  }
knopp's avatar
knopp committed
649

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

654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
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;
672
  if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_rx );
673
674
675

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

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

}
685
686
687
688
689
690

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
691
  req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
692
693
694
695
696
697
698
699
700
701
702
  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);
  
703
704
705
706
707
708
709
710
711
712
713
  wait_sync("emulatedRF_thread");
  while(!oai_exit){
    nanosleep(&req, (struct timespec *)NULL);
    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
714
715
void rx_rf(RU_t *ru,int *frame,int *subframe) {

716
  RU_proc_t *proc = &ru->proc;
knopp's avatar
knopp committed
717
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
718
  void *rxp[ru->nb_rx];
719
  unsigned int rxs;
knopp's avatar
knopp committed
720
  int i;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
721
  openair0_timestamp ts=0,old_ts=0;
knopp's avatar
knopp committed
722
    
723
  for (i=0; i<ru->nb_rx; i++)
724
    rxp[i] = (void*)&ru->common.rxdata[i][*subframe*fp->samples_per_tti];
725

knopp's avatar
knopp committed
726
727
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 );

728
  old_ts = proc->timestamp_rx;
729
730
731
732
733
734
735
  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,
736
				   &ts,
knopp's avatar
knopp committed
737
738
				   rxp,
				   fp->samples_per_tti,
739
				   ru->nb_rx);
740
  }
knopp's avatar
knopp committed
741
742
743
  
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 );
 
744
  proc->timestamp_rx = ts-ru->ts_offset;
745

746
747
748
  //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);
749
750

  if (proc->first_rx == 1) {
751
    ru->ts_offset = proc->timestamp_rx;
752
753
754
755
    proc->timestamp_rx = 0;
  }
  else {
    if (proc->timestamp_rx - old_ts != fp->samples_per_tti) {
Wang Tsu-Han's avatar
Wang Tsu-Han committed
756
      //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);
757
      ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti);
758
      proc->timestamp_rx = ts-ru->ts_offset;
759
760
761
762
763
    }

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

766
767
768
  //proc->timestamp_tx = proc->timestamp_rx+(sf_ahead*fp->samples_per_tti);
  //proc->subframe_tx  = (proc->subframe_rx+sf_ahead)%10;
  //proc->frame_tx     = (proc->subframe_rx>(9-sf_ahead)) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
769
770
771
772
773
774
  
  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);
775

776
777
778
779
780
    // 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 );
  }
knopp's avatar
knopp committed
781
782
783
  
  if (proc->first_rx == 0) {
    if (proc->subframe_rx != *subframe){
784
      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);
knopp's avatar
knopp committed
785
786
787
788
      exit_fun("Exiting");
    }
    
    if (proc->frame_rx != *frame) {
789
      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
790
791
792
793
794
795
796
797
798
799
      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);
  
800
  VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff );
knopp's avatar
knopp committed
801
802
  
  if (rxs != fp->samples_per_tti)
803
804
  {
    //exit_fun( "problem receiving samples" );
Cedric Roux's avatar
Cedric Roux committed
805
    LOG_E(PHY, "problem receiving samples");
806
  }
knopp's avatar
knopp committed
807
808
809
}


810
811
812
813
void tx_rf(RU_t *ru) {

  RU_proc_t *proc = &ru->proc;
  LTE_DL_FRAME_PARMS *fp = &ru->frame_parms;
814
  void *txp[ru->nb_tx]; 
815
816
817
  unsigned int txs;
  int i;

Cedric Roux's avatar
Cedric Roux committed
818
819
820
  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));

821
822
823
  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);
824
825
  int sf_extension = 0;

826
827
828
829
830
831
832
833
834
835
836
837
  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) &&
838
	(nextSF_type == SF_DL)) { 
839
      flags = 2; // start of burst
840
841
      sf_extension = ru->N_TA_offset<<1;
    }
842
843
844
845
    
    if ((fp->frame_type == TDD) &&
	(SF_type == SF_DL)&&
	(prevSF_type == SF_UL) &&
846
	(nextSF_type == SF_UL)) {
847
      flags = 4; // start of burst and end of burst (only one DL SF between two UL)
848
849
850
851
852
853
      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];

knopp's avatar
knopp committed
854
855
    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 );
856
    
857
858
859
860
861
    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,
862
				      proc->timestamp_tx+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension,
863
				      txp,
864
				      siglen+sf_extension,
865
866
867
868
				      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,
knopp's avatar
knopp committed
869
	  (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx);
870
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
871
    
872
    
873
    AssertFatal(txs ==  siglen+sf_extension,"TX : Timeout (sent %d/%d)\n",txs, siglen);
874

875
  }
876
877
878
}


knopp's avatar
knopp committed
879
880
881
882
883
884
885
886
887
888
/*!
 * \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;

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

knopp's avatar
knopp committed
892
893
894
895


  int subframe=0, frame=0; 

Wang Tsu-Han's avatar
Wang Tsu-Han committed
896
  thread_top_init("ru_thread_asynch_rxtx",1,870000,1000000,1000000);
knopp's avatar
knopp committed
897
898
899

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

900
  wait_sync("ru_thread_asynch_rxtx");
knopp's avatar
knopp committed
901
902

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

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

907
  printf( "devices ok (ru_thread_asynch_rx)\n");
knopp's avatar
knopp committed
908
909
910
911
912
913
914
915
916
917
918
919
920


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

    if (subframe==9) { 
      subframe=0;
      frame++;
      frame&=1023;
    } else {
      subframe++;
    }      
921
    LOG_D(PHY,"ru_thread_asynch_rxtx: Waiting on incoming fronthaul\n");
Wang Tsu-Han's avatar
Wang Tsu-Han committed
922
	// asynchronous receive from south (Mobipass)
923
924
    if (ru->fh_south_asynch_in) ru->fh_south_asynch_in(ru,&frame,&subframe);
    // asynchronous receive from north (RRU IF4/IF5)
925
926
927
928
    else if (ru->fh_north_asynch_in) {
       if (subframe_select(&ru->frame_parms,subframe)!=SF_UL)
         ru->fh_north_asynch_in(ru,&frame,&subframe);
    }
929
    else AssertFatal(1==0,"Unknown function in ru_thread_asynch_rxtx\n");
knopp's avatar
knopp committed
930
931
932
933
934
935
936
937
938
  }

  ru_thread_asynch_rxtx_status=0;
  return(&ru_thread_asynch_rxtx_status);
}




939
void wakeup_slaves(RU_proc_t *proc) {
knopp's avatar
knopp committed
940
941
942
943
944
945
946
947

  int i;
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
  
  for (i=0;i<proc->num_slaves;i++) {
948
    //printf("////////////////////calling for slave thrads\n");////////////////////////********
949
    RU_proc_t *slave_proc = proc->slave_proc[i];
knopp's avatar
knopp committed
950
951
952
    // 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) {
953
      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
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
      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) {
969
	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
970
971
972
973
          exit_fun( "ERROR pthread_cond_signal" );
	  break;
      }
    } else {
974
      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
975
976
977
978
979
980
981
982
      exit_fun( "FH thread busy" );
      break;
    }             
  }
}

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

knopp's avatar
knopp committed
988
989
  static int ru_thread_prach_status;

990
991
  RU_t *ru        = (RU_t*)param;
  RU_proc_t *proc = (RU_proc_t*)&ru->proc;
knopp's avatar
knopp committed
992
993

  // set default return value
994
  ru_thread_prach_status = 0;
knopp's avatar
knopp committed
995

Wang Tsu-Han's avatar
Wang Tsu-Han committed
996
  thread_top_init("ru_thread_prach",1,500000,1000000,20000000);
997
  //wait_sync("ru_thread_prach");
knopp's avatar
knopp committed
998

999
1000
1001
1002
1003
1004
  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
1005
1006
1007
  while (!oai_exit) {
    
    if (oai_exit) break;
1008
    if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
1009
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 1 );      
1010
1011
    if (ru->eNB_list[0]){
      prach_procedures(
1012
        ru->eNB_list[0]
1013
#ifdef Rel14
1014
        ,0
1015
#endif
1016
        );
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
    }
    else {
       rx_prach(NULL,
  	        ru,
	        NULL,
                NULL,
                NULL,
                proc->frame_prach,
                0
#ifdef Rel14
	        ,0
#endif
	        );
    } 
1031
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 );      
1032
    if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
knopp's avatar
knopp committed
1033
1034
  }

1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
  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;

Wang Tsu-Han's avatar
Wang Tsu-Han committed
1052
  thread_top_init("ru_thread_prach_br",1,500000,1000000,20000000);
1053
  //wait_sync("ru_thread_prach_br");
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070

  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");
knopp's avatar
knopp committed
1071

1072
1073
  ru_thread_prach_status = 0;
  return &ru_thread_prach_status;
knopp's avatar
knopp committed
1074
}
1075
#endif
knopp's avatar
knopp committed
1076

1077
int wakeup_synch(RU_t *ru){
knopp's avatar
knopp committed
1078

1079
1080
1081
1082
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
knopp's avatar
knopp committed
1083

1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
  // 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;
knopp's avatar
knopp committed
1111
1112
  void *rxp[2],*rxp2[2];
  int32_t dummy_rx[ru->nb_rx][fp->samples_per_tti] __attribute__((aligned(32)));
1113
1114
  int rxs;
  int ic;
knopp's avatar
knopp committed
1115
1116
1117

  // initialize the synchronization buffer to the common_vars.rxdata
  for (int i=0;i<ru->nb_rx;i++)
1118
    rxp[i] = &ru->common.rxdata[i][0];
knopp's avatar
knopp committed
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134

  double temp_freq1 = ru->rfdevice.openair0_cfg->rx_freq[0];
  double temp_freq2 = ru->rfdevice.openair0_cfg->tx_freq[0];
  for (i=0;i<4;i++) {
    ru->rfdevice.openair0_cfg->rx_freq[i] = ru->rfdevice.openair0_cfg->tx_freq[i];
    ru->rfdevice.openair0_cfg->tx_freq[i] = temp_freq1;
  }
  ru->rfdevice.trx_set_freq_func(&ru->rfdevice,ru->rfdevice.openair0_cfg,0);
  
  while ((ru->in_synch ==0)&&(!oai_exit)) {
    // read in frame
    rxs = ru->rfdevice.trx_read_func(&ru->rfdevice,
				     &(proc->timestamp_rx),
				     rxp,
				     fp->samples_per_tti*10,
				     ru->nb_rx);
1135
1136
    if (rxs != fp->samples_per_tti*10) LOG_E(PHY,"requested %d samples, got %d\n",fp->samples_per_tti*10,rxs);
 
knopp's avatar
knopp committed
1137
1138
1139
1140
1141
1142
1143
1144
    // 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
      
1145
      for (i=0; i<ru->nb_rx; i++)
knopp's avatar
knopp committed
1146
1147
1148
1149
1150
1151
1152
	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);
1153
1154
1155
      pthread_mutex_lock(&ru->proc.mutex_synch);
      ic = ru->proc.instance_cnt_synch;
      pthread_mutex_unlock(&ru->proc.mutex_synch);
knopp's avatar
knopp committed
1156
1157
1158
1159
1160
1161
1162
1163
    } // 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,
1164
				   ru->nb_rx);
knopp's avatar
knopp committed
1165
1166
1167
1168
1169
1170
1171
1172
1173
  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);

}

1174
1175
1176
1177
1178
1179
1180


void wakeup_eNBs(RU_t *ru) {

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

Cedric Roux's avatar
Cedric Roux committed
1181
  LOG_D(PHY,"wakeup_eNBs (num %d) for RU %d ru->eNB_top:%p\n",ru->num_eNB,ru->idx, ru->eNB_top);
1182

1183

1184
  if (ru->num_eNB==1 && ru->eNB_top!=0 && get_nprocs() <= 4) {
1185
    // call eNB function directly
1186
  
1187
1188
    char string[20];
    sprintf(string,"Incoming RU %d",ru->idx);
Cedric Roux's avatar
Cedric Roux committed
1189
    LOG_D(PHY,"RU %d Call eNB_top\n",ru->idx);
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1190
    ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.subframe_rx,string,ru);
1191
1192
1193
  }
  else {

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

1196
    for (i=0;i<ru->num_eNB;i++)
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1197
    {
1198
      LOG_D(PHY,"ru->wakeup_rxtx:%p\n", ru->wakeup_rxtx);
1199
      eNB_list[i]->proc.ru_proc = &ru->proc;
1200
1201
      if (ru->wakeup_rxtx!=0 && ru->wakeup_rxtx(eNB_list[i],ru) < 0)
      {
1202
	LOG_E(PHY,"could not wakeup eNB rxtx process for subframe %d\n", ru->proc.subframe_rx);
1203
      }
Wang Tsu-Han's avatar
Wang Tsu-Han committed
1204
    }
1205
1206
1207
  }
}

1208
static inline int wakeup_prach_ru(RU_t *ru) {
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219

  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);
  }
1220
1221
1222
1223
  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;
1224

1225
    // DJP - think prach_procedures() is looking at eNB frame_prach
1226
1227
1228
1229
    if (ru->eNB_list[0]) {
      ru->eNB_list[0]->proc.frame_prach = ru->proc.frame_rx;
      ru->eNB_list[0]->proc.subframe_prach = ru->proc.subframe_rx;
    }
1230
    LOG_I(PHY,"RU %d: waking up PRACH thread\n",ru->idx);
1231
1232
    // 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");
1233
  }
1234
  else LOG_W(PHY,"RU prach thread busy, skipping\n");
1235
1236
1237
1238
1239
  pthread_mutex_unlock( &ru->proc.mutex_prach );

  return(0);
}

1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
#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

knopp's avatar
knopp committed
1269
1270
1271
1272
1273
1274
1275
// 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;
1276
  //printf("////////////////numerology in config = %d\n",numerology);
knopp's avatar
knopp committed
1277
1278

  if(fp->N_RB_DL