lte-ru.c 105 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"

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;
Wang Tsu-Han's avatar
Wang Tsu-Han committed
122
extern int fepw;
123
extern int single_thread_flag;
Konstantinos Alexandris's avatar
Konstantinos Alexandris committed
124
extern clock_source_t clock_source;
knopp's avatar
knopp committed
125

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
314
  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
315
316
317
318
}

// southbound IF5 fronthaul for Mobipass packet format
static inline void fh_if5_mobipass_south_out(RU_t *ru) {
319
320
  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
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
  LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.subframe_tx);
Guy De Souza's avatar
Guy De Souza committed
327
  if (subframe_select(ru->frame_parms,ru->proc.subframe_tx)!=SF_UL) 
328
    send_IF4p5(ru,ru->proc.frame_tx, ru->proc.subframe_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
343
344
345
346

  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){
347
      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
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
358
359
360
361
362
363
364
365
366
367
      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) {

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

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

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
458
459
  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
460

461
462
  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
463

464
465
  if (proc->first_rx == 1) {
    proc->first_rx =2;
knopp's avatar
knopp committed
466
467
    *subframe = proc->subframe_rx;
    *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->subframe_rx);
knopp's avatar
knopp committed
469
470
471
  }
  else {
    if (proc->subframe_rx != *subframe) {
472
473
474
        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
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
482
483
    // temporary solution
      *subframe = proc->subframe_rx;
      *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
506

  do {   // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!!
    recv_IF4p5(ru, &proc->frame_rx, &proc->subframe_rx, &packet_type, &symbol_number);
507
508
509
510
511
    // 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
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
    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");
      }
    }
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
567
    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
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;
knopp's avatar
knopp committed
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
  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 {
590
591
592
593
    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
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
604
605

  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
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
611
  do {   
    recv_IF4p5(ru, &frame_tx, &subframe_tx, &packet_type, &symbol_number);
612
    if ((subframe_select(fp,subframe_tx) == SF_DL) && (symbol_number == 0)) start_meas(&ru->rx_fhaul);
613
614
    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
615
616
617
618
    if (proc->first_tx != 0) {
      *frame    = frame_tx;
      *subframe = subframe_tx;
      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
624
625
      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
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,subframe_tx) == SF_DL) stop_meas(&ru->rx_fhaul);
634

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

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

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

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,subframe_tx);
643
644
645
646
647
    // 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
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
660
661
662
663
664
665
666
667
668
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;
Guy De Souza's avatar
Guy De Souza committed
669
  LTE_DL_FRAME_PARMS *fp = ru->frame_parms;
670
  const int subframe     = proc->subframe_rx;
671
  if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_SUBFRAME_NUMBER_RX0_RU, proc->subframe_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->subframe_rx, IF4p5_PULTICK);
676
677
678
    return;
  }

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

}
684

Xu Bo's avatar
Xu Bo 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
762
  proc->timestamp_rx = ts-ru->ts_offset;

Xu Bo's avatar
Xu Bo 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
778
779
780
781
782
783
      ru->ts_offset += (proc->timestamp_rx - old_ts - fp->samples_per_tti);
      proc->timestamp_rx = ts-ru->ts_offset;
    }

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

786
#ifdef PHY_TX_THREAD
787
788
789
  proc->timestamp_phy_tx = proc->timestamp_rx+((sf_ahead-1)*fp->samples_per_tti);
  proc->subframe_phy_tx  = (proc->subframe_rx+(sf_ahead-1))%10;  
  proc->frame_phy_tx     = (proc->subframe_rx>(9-(sf_ahead-1))) ? (proc->frame_rx+1)&1023 : proc->frame_rx;
790
#else
791
792
793
  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;
794
795
#endif

796
797
798
  //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;
799
800
801
802
803
804
  
  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);
805

806
807
808
809
810
    // 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
811
812
813
  
  if (proc->first_rx == 0) {
    if (proc->subframe_rx != *subframe){
814
      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
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
825
826
827
828
829
      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);
  
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
  {
Mongazon's avatar
Mongazon 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");
Mongazon's avatar
Mongazon 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;

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

855
856
857
  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);
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
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)
882
      sf_extension = ru->N_TA_offset;
883
    } 
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
895
896
    for (i=0; i<ru->nb_tx; i++)
      txp[i] = (void*)&ru->common.txdata[i][(proc->subframe_tx*fp->samples_per_tti)-sf_extension];

Xu Bo's avatar
Xu Bo 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
    /* 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;
921
922
923
      default:
        LOG_D(PHY,"[TXPATH] RU %d late_control %d not implemented\n",ru->idx, late_control);
      break;
Xu Bo's avatar
Xu Bo committed
924
925
926
      }
    }
    /* add fail safe for late command end */
927

knopp's avatar
knopp committed
928
929
    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 );
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,
knopp's avatar
knopp committed
943
	  (long long unsigned int)proc->timestamp_tx,proc->frame_tx,proc->frame_tx_unwrap,proc->subframe_tx);
944
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0 );
945
    
946
    
Xu Bo's avatar
Xu Bo 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
1036
1037
1038
1039
1040
1041
1042
1043
1044
      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) {
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
1083
  while (!oai_exit) {
    
    if (oai_exit) break;
1084
    if (wait_on_condition(&proc->mutex_prach,&proc->cond_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) 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
1102
#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
1103
1104
1105
1106
	        ,0
#endif
	        );
    } 
1107
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_RU_PRACH_RX, 0 );      
1108
    if (release_thread(&proc->mutex_prach,&proc->instance_cnt_prach,"ru_prach_thread") < 0) break;
knopp's avatar
knopp committed
1109
1110
  }

1111
1112
1113
1114
1115
1116
  LOG_I(PHY, "Exiting RU thread PRACH\n");

  ru_thread_prach_status = 0;
  return &ru_thread_prach_status;
}

1117
#if (RRC_VERSION >= MAKE_VERSION(14, 0, 0))
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
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
1128
  thread_top_init("ru_thread_prach_br",1,500000,1000000,20000000);
1129
  //wait_sync("ru_thread_prach_br");
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146

  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
1147

1148
1149
  ru_thread_prach_status = 0;
  return &ru_thread_prach_status;
knopp's avatar
knopp committed
1150
}
1151
#endif
knopp's avatar
knopp committed
1152

1153
int wakeup_synch(RU_t *ru){
knopp's avatar
knopp committed
1154

1155
1156
1157
1158
  struct timespec wait;
  
  wait.tv_sec=0;
  wait.tv_nsec=5000000L;
knopp's avatar
knopp committed
1159

1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
  // 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) {

Guy De Souza's avatar
Guy De Souza committed
1184
  LTE_DL_FRAME_PARMS *fp  = ru->frame_parms;
1185
1186
  RU_proc_t *proc         = &ru->proc;
  int i;
knopp's avatar
knopp committed
1187
1188
  void *rxp[2],*rxp2[2];
  int32_t dummy_rx[ru->nb_rx][fp->samples_per_tti] __attribute__((aligned(32)));
1189
1190
  int rxs;
  int ic;
knopp's avatar
knopp committed
1191
1192
1193

  // initialize the synchronization buffer to the common_vars.rxdata
  for (int i=0;i<ru->nb_rx;i++)
1194
    rxp[i] = &ru->common.rxdata[i][0];
knopp's avatar
knopp committed
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210

  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);
1211
1212
    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
1213
1214
1215
1216
1217
1218
1219
1220
    // 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
      
1221
      for (i=0; i<ru->nb_rx; i++)
knopp's avatar
knopp committed
1222
1223
1224
1225
1226
1227
1228
	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);
1229
1230
1231
      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