ocp-gnb.c 42 KB
Newer Older
1 2 3 4 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
/*
 * Author: Laurent Thomas, Open Cells Project
 * all rights reserved
 */

#define _GNU_SOURCE
#include <pthread.h>
#include "assertions.h"
#include <common/utils/LOG/log.h>
#include <common/utils/system.h>

#include "PHY/types.h"

#include "PHY/INIT/phy_init.h"

#include "PHY/defs_gNB.h"
#include "SCHED/sched_eNB.h"
#include "SCHED_NR/sched_nr.h"
#include "SCHED_NR/fapi_nr_l1.h"
#include "PHY/LTE_TRANSPORT/transport_proto.h"
#include "../../ARCH/COMMON/common_lib.h"

#include "PHY/phy_extern.h"
#include "LAYER2/MAC/mac.h"
#include "LAYER2/NR_MAC_COMMON/nr_mac_extern.h"
#include "LAYER2/MAC/mac_proto.h"
#include "RRC/LTE/rrc_extern.h"
#include "PHY_INTERFACE/phy_interface.h"
#include "common/utils/LOG/log_extern.h"
#include "UTIL/OTG/otg_tx.h"
#include "UTIL/OTG/otg_externs.h"
#include "UTIL/MATH/oml.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
#include "enb_config.h"
#include "s1ap_eNB.h"
#include "SIMULATION/ETH_TRANSPORT/proto.h"
#include <executables/nr-softmodem.h>
#include <openair2/GNB_APP/gnb_config.h>
#include <executables/softmodem-common.h>
#include <openair2/GNB_APP/gnb_app.h>
#include <openair2/RRC/NR/nr_rrc_extern.h>
Laurent's avatar
Laurent committed
43
#include <openair2/X2AP/x2ap_eNB.h>
laurent's avatar
laurent committed
44
#include <openair1/PHY/NR_TRANSPORT/nr_transport_proto.h>
Laurent's avatar
Laurent committed
45
#include <nfapi/oai_integration/nfapi_pnf.h>
46 47 48 49 50

// should be in a shared lib
#include <forms.h>
#include <executables/stats.h>
#include <openair1/PHY/TOOLS/nr_phy_scope.h>
Laurent's avatar
Laurent committed
51
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

// Global vars
#include <openair2/LAYER2/MAC/mac_vars.h>
#include <openair1/PHY/phy_vars.h>
#include <openair2/RRC/LTE/rrc_vars.h>
#include <openair1/SCHED/sched_common_vars.h>
volatile int oai_exit;
int single_thread_flag=1;
uint32_t do_forms=0;
unsigned int mmapped_dma=0;
int8_t threequarter_fs=0;

int chain_offset=0;
uint16_t sl_ahead=6;
uint16_t sf_ahead=6;
uint32_t timing_advance = 0;
int transmission_mode=1;
int emulate_rf = 0;
int numerology = 0;


int config_sync_var=-1;
pthread_mutex_t nfapi_sync_mutex;
pthread_cond_t nfapi_sync_cond;
int nfapi_sync_var=-1;
double cpuf;

79
THREAD_STRUCT thread_struct;
80 81 82

pthread_cond_t sync_cond;
pthread_mutex_t sync_mutex;
83
int sync_var=-1; //!< protected by mutex \ref sync_mutex.
84 85 86 87


uint64_t downlink_frequency[MAX_NUM_CCs][4];
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
88 89 90 91 92
time_stats_t softmodem_stats_mt; // main thread
time_stats_t softmodem_stats_hw; //  hw acquisition
time_stats_t softmodem_stats_rxtx_sf; // total tx time
time_stats_t nfapi_meas; // total tx time
time_stats_t softmodem_stats_rx_sf; // total rx time
Laurent's avatar
Laurent committed
93 94
// not used but needed for link
openair0_config_t openair0_cfg[MAX_CARDS];
Laurent THOMAS's avatar
Laurent THOMAS committed
95
uint16_t slot_ahead=6;
96 97 98 99 100 101 102 103 104
AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB];
AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB];
int flexran_agent_start(mid_t mod_id) {
  memset (agent_rrc_xface, 0, sizeof(agent_rrc_xface));
  memset (agent_mac_xface, 0, sizeof(agent_mac_xface));
  return 0;
}
void flexran_agent_slice_update(mid_t module_idP) {
}
laurent's avatar
laurent committed
105 106
int proto_agent_start(mod_id_t mod_id, const cudu_params_t *p) {
  return 0;
107
}
laurent's avatar
laurent committed
108
void proto_agent_stop(mod_id_t mod_id) {
109
}
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
int split73=0;
void sendFs6Ul(PHY_VARS_eNB *eNB, int UE_id, int harq_pid, int segmentID, int16_t *data, int dataLen, int r_offset) {
  AssertFatal(false, "Must not be called in this context\n");
}
int stop_L1L2(module_id_t gnb_id) {
  AssertFatal(false, "Must not be called in this context\n");
}
int restart_L1L2(module_id_t gnb_id) {
  AssertFatal(false, "Must not be called in this context\n");
}

static int wait_for_sync = 0;
static double snr_dB=20;
static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};

extern double cpuf;

short nr_mod_table[NR_MOD_TABLE_SIZE_SHORT] = {0,0,16384,16384,-16384,-16384,16384,16384,16384,-16384,-16384,16384,-16384,-16384,7327,7327,7327,21981,21981,7327,21981,21981,7327,-7327,7327,-21981,21981,-7327,21981,-21981,-7327,7327,-7327,21981,-21981,7327,-21981,21981,-7327,-7327,-7327,-21981,-21981,-7327,-21981,-21981,10726,10726,10726,3576,3576,10726,3576,3576,10726,17876,10726,25027,3576,17876,3576,25027,17876,10726,17876,3576,25027,10726,25027,3576,17876,17876,17876,25027,25027,17876,25027,25027,10726,-10726,10726,-3576,3576,-10726,3576,-3576,10726,-17876,10726,-25027,3576,-17876,3576,-25027,17876,-10726,17876,-3576,25027,-10726,25027,-3576,17876,-17876,17876,-25027,25027,-17876,25027,-25027,-10726,10726,-10726,3576,-3576,10726,-3576,3576,-10726,17876,-10726,25027,-3576,17876,-3576,25027,-17876,10726,-17876,3576,-25027,10726,-25027,3576,-17876,17876,-17876,25027,-25027,17876,-25027,25027,-10726,-10726,-10726,-3576,-3576,-10726,-3576,-3576,-10726,-17876,-10726,-25027,-3576,-17876,-3576,-25027,-17876,-10726,-17876,-3576,-25027,-10726,-25027,-3576,-17876,-17876,-17876,-25027,-25027,-17876,-25027,-25027,8886,8886,8886,12439,12439,8886,12439,12439,8886,5332,8886,1778,12439,5332,12439,1778,5332,8886,5332,12439,1778,8886,1778,12439,5332,5332,5332,1778,1778,5332,1778,1778,8886,19547,8886,15993,12439,19547,12439,15993,8886,23101,8886,26655,12439,23101,12439,26655,5332,19547,5332,15993,1778,19547,1778,15993,5332,23101,5332,26655,1778,23101,1778,26655,19547,8886,19547,12439,15993,8886,15993,12439,19547,5332,19547,1778,15993,5332,15993,1778,23101,8886,23101,12439,26655,8886,26655,12439,23101,5332,23101,1778,26655,5332,26655,1778,19547,19547,19547,15993,15993,19547,15993,15993,19547,23101,19547,26655,15993,23101,15993,26655,23101,19547,23101,15993,26655,19547,26655,15993,23101,23101,23101,26655,26655,23101,26655,26655,8886,-8886,8886,-12439,12439,-8886,12439,-12439,8886,-5332,8886,-1778,12439,-5332,12439,-1778,5332,-8886,5332,-12439,1778,-8886,1778,-12439,5332,-5332,5332,-1778,1778,-5332,1778,-1778,8886,-19547,8886,-15993,12439,-19547,12439,-15993,8886,-23101,8886,-26655,12439,-23101,12439,-26655,5332,-19547,5332,-15993,1778,-19547,1778,-15993,5332,-23101,5332,-26655,1778,-23101,1778,-26655,19547,-8886,19547,-12439,15993,-8886,15993,-12439,19547,-5332,19547,-1778,15993,-5332,15993,-1778,23101,-8886,23101,-12439,26655,-8886,26655,-12439,23101,-5332,23101,-1778,26655,-5332,26655,-1778,19547,-19547,19547,-15993,15993,-19547,15993,-15993,19547,-23101,19547,-26655,15993,-23101,15993,-26655,23101,-19547,23101,-15993,26655,-19547,26655,-15993,23101,-23101,23101,-26655,26655,-23101,26655,-26655,-8886,8886,-8886,12439,-12439,8886,-12439,12439,-8886,5332,-8886,1778,-12439,5332,-12439,1778,-5332,8886,-5332,12439,-1778,8886,-1778,12439,-5332,5332,-5332,1778,-1778,5332,-1778,1778,-8886,19547,-8886,15993,-12439,19547,-12439,15993,-8886,23101,-8886,26655,-12439,23101,-12439,26655,-5332,19547,-5332,15993,-1778,19547,-1778,15993,-5332,23101,-5332,26655,-1778,23101,-1778,26655,-19547,8886,-19547,12439,-15993,8886,-15993,12439,-19547,5332,-19547,1778,-15993,5332,-15993,1778,-23101,8886,-23101,12439,-26655,8886,-26655,12439,-23101,5332,-23101,1778,-26655,5332,-26655,1778,-19547,19547,-19547,15993,-15993,19547,-15993,15993,-19547,23101,-19547,26655,-15993,23101,-15993,26655,-23101,19547,-23101,15993,-26655,19547,-26655,15993,-23101,23101,-23101,26655,-26655,23101,-26655,26655,-8886,-8886,-8886,-12439,-12439,-8886,-12439,-12439,-8886,-5332,-8886,-1778,-12439,-5332,-12439,-1778,-5332,-8886,-5332,-12439,-1778,-8886,-1778,-12439,-5332,-5332,-5332,-1778,-1778,-5332,-1778,-1778,-8886,-19547,-8886,-15993,-12439,-19547,-12439,-15993,-8886,-23101,-8886,-26655,-12439,-23101,-12439,-26655,-5332,-19547,-5332,-15993,-1778,-19547,-1778,-15993,-5332,-23101,-5332,-26655,-1778,-23101,-1778,-26655,-19547,-8886,-19547,-12439,-15993,-8886,-15993,-12439,-19547,-5332,-19547,-1778,-15993,-5332,-15993,-1778,-23101,-8886,-23101,-12439,-26655,-8886,-26655,-12439,-23101,-5332,-23101,-1778,-26655,-5332,-26655,-1778,-19547,-19547,-19547,-15993,-15993,-19547,-15993,-15993,-19547,-23101,-19547,-26655,-15993,-23101,-15993,-26655,-23101,-19547,-23101,-15993,-26655,-19547,-26655,-15993,-23101,-23101,-23101,-26655,-26655,-23101,-26655,-26655};

Laurent's avatar
Laurent committed
131
static inline int ocp_rxtx(PHY_VARS_gNB *gNB, gNB_L1_rxtx_proc_t *proc) {
132
  nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
133 134 135 136 137 138 139 140 141 142
  start_meas(&softmodem_stats_rxtx_sf);

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

  if (nfapi_mode == NFAPI_MODE_PNF) {
    // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick
    //add_subframe(&frame, &subframe, 4);
    //oai_subframe_ind(proc->frame_tx, proc->subframe_tx);
    //LOG_D(PHY, "oai_subframe_ind(frame:%u, subframe:%d) - NOT CALLED ********\n", frame, subframe);
    start_meas(&nfapi_meas);
143
    oai_subframe_ind(proc->frame_rx, proc->slot_rx);
144
    stop_meas(&nfapi_meas);
laurent's avatar
laurent committed
145
    /*if (gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus||
146 147 148 149 150
      gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs ||
      gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs ||
      gNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles ||
      gNB->UL_INFO.cqi_ind.number_of_cqis
      ) {
151
      LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d preambles:%05d:%d cqis:%d] RX:%04d%d TX:%04d%d \n",
152 153 154 155 156 157 158 159
      NFAPI_SFNSF2DEC(gNB->UL_INFO.rx_ind.sfn_sf),   gNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus,
      NFAPI_SFNSF2DEC(gNB->UL_INFO.harq_ind.sfn_sf), gNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs,
      NFAPI_SFNSF2DEC(gNB->UL_INFO.crc_ind.sfn_sf),  gNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs,
      NFAPI_SFNSF2DEC(gNB->UL_INFO.rach_ind.sfn_sf), gNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles,
      gNB->UL_INFO.cqi_ind.number_of_cqis,
      frame_rx, slot_rx,
      frame_tx, slot_tx);
      }*/
160 161 162 163 164 165
  }

  /// NR disabling
  // ****************************************
  // Common RX procedures subframe n
  pthread_mutex_lock(&gNB->UL_INFO_mutex);
166 167
  gNB->UL_INFO.frame     = proc->frame_rx;
  gNB->UL_INFO.slot      = proc->slot_rx;
168 169 170 171
  gNB->UL_INFO.module_id = gNB->Mod_id;
  gNB->UL_INFO.CC_id     = gNB->CC_id;
  gNB->if_inst->NR_UL_indication(&gNB->UL_INFO);
  pthread_mutex_unlock(&gNB->UL_INFO_mutex);
172
  // RX processing
173 174
  int tx_slot_type         = nr_slot_select(cfg,proc->frame_tx,proc->slot_tx);
  int rx_slot_type         = nr_slot_select(cfg,proc->frame_rx,proc->slot_rx);
175 176

  if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
laurent's avatar
laurent committed
177
    // Do PRACH RU processing
Laurent's avatar
Laurent committed
178
    L1_nr_prach_procedures(gNB,proc->frame_rx,proc->slot_rx);
179
    phy_procedures_gNB_uespec_RX(gNB, proc->frame_rx, proc->slot_rx);
180
  }
181

182
  if (oai_exit) return(-1);
183

184 185 186 187 188 189 190
  // *****************************************
  // TX processing for subframe n+sf_ahead
  // run PHY TX procedures the one after the other for all CCs to avoid race conditions
  // (may be relaxed in the future for performance reasons)
  // *****************************************

  if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT) {
191
    phy_procedures_gNB_TX(gNB, proc->frame_tx,proc->slot_tx, 1);
192
  }
193 194

  stop_meas( &softmodem_stats_rxtx_sf );
195
  LOG_D(PHY,"%s() Exit proc[rx:%d%d tx:%d%d]\n", __FUNCTION__, proc->frame_rx, proc->slot_rx, proc->frame_tx, proc->slot_tx);
196 197 198 199 200 201 202 203 204
  return(0);
}


static void *process_stats_thread(void *param) {
  PHY_VARS_gNB *gNB  = (PHY_VARS_gNB *)param;
  reset_meas(&gNB->dlsch_encoding_stats);
  reset_meas(&gNB->dlsch_scrambling_stats);
  reset_meas(&gNB->dlsch_modulation_stats);
205

206 207 208 209 210 211
  while(!oai_exit) {
    sleep(1);
    print_meas(&gNB->dlsch_encoding_stats, "pdsch_encoding", NULL, NULL);
    print_meas(&gNB->dlsch_scrambling_stats, "pdsch_scrambling", NULL, NULL);
    print_meas(&gNB->dlsch_modulation_stats, "pdsch_modulation", NULL, NULL);
  }
212

213 214 215 216
  return(NULL);
}

void init_gNB_proc(int inst) {
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
  PHY_VARS_gNB *gNB = RC.gNB[inst];
  gNB_L1_proc_t *proc = &gNB->proc;
  gNB_L1_rxtx_proc_t *L1_proc    = &proc->L1_proc;
  gNB_L1_rxtx_proc_t *L1_proc_tx = &proc->L1_proc_tx;
  L1_proc->instance_cnt          = -1;
  L1_proc_tx->instance_cnt       = -1;
  L1_proc->instance_cnt_RUs      = 0;
  L1_proc_tx->instance_cnt_RUs   = 0;
  proc->instance_cnt_prach       = -1;
  proc->instance_cnt_asynch_rxtx = -1;
  proc->CC_id                    = 0;
  proc->first_rx                 =1;
  proc->first_tx                 =1;
  proc->RU_mask                  =0;
  proc->RU_mask_tx               = (1<<gNB->num_RU)-1;
  proc->RU_mask_prach            =0;
  pthread_mutex_init( &gNB->UL_INFO_mutex, NULL);
Laurent's avatar
Laurent committed
234 235
  gNB->threadPool = (tpool_t *)malloc(sizeof(tpool_t));
  gNB->respDecode = (notifiedFIFO_t *) malloc(sizeof(notifiedFIFO_t));
Laurent's avatar
Laurent committed
236 237 238
  char ul_pool[] = "-1,-1";
  initTpool(ul_pool, gNB->threadPool, false);
  initNotifiedFIFO(gNB->respDecode);
239 240 241
}

/// eNB kept in function name for nffapi calls, TO FIX
242
void init_gNB_phase2(RU_t *ru) {
243
  int inst;
244 245 246
  LOG_I(PHY,"%s() RC.nb_nr_inst:%d\n", __FUNCTION__, RC.nb_nr_inst);

  for (inst=0; inst<RC.nb_nr_inst; inst++) {
247
    LOG_I(PHY,"RC.nb_nr_CC[inst:%d]:%p\n", inst, RC.gNB[inst]);
248 249
    PHY_VARS_gNB *gNB =  RC.gNB[inst];
    LOG_E(PHY,"hard coded gNB->num_RU:%d\n", gNB->num_RU);
250
    phy_init_nr_gNB(gNB,0,0);
251 252
    RC.gNB[inst]->num_RU=1;
    RC.gNB[inst]->RU_list[0]=ru;
253
    //init_precoding_weights(RC.gNB[inst][CC_id]);
254 255 256 257
  }
}

void init_gNB(int single_thread_flag,int wait_for_sync) {
258
  for (int inst=0; inst<RC.nb_nr_L1_inst; inst++) {
259
    AssertFatal( RC.gNB[inst] != NULL, "Must be allocated in init_main_gNB->RCconfig_NR_L1\n");
260 261 262 263
    PHY_VARS_gNB *gNB= RC.gNB[inst];
    gNB->abstraction_flag   = false;
    gNB->single_thread_flag = true;
    /*nr_polar_init(&gNB->nrPolar_params,
264 265 266
      NR_POLAR_PBCH_MESSAGE_TYPE,
      NR_POLAR_PBCH_PAYLOAD_BITS,
      NR_POLAR_PBCH_AGGREGATION_LEVEL);*/
267
    LOG_I(PHY,"Registering with MAC interface module\n");
268
    AssertFatal((gNB->if_inst = NR_IF_Module_init(inst))!=NULL,"Cannot register interface");
269 270 271 272 273 274
    gNB->if_inst->NR_Schedule_response   = nr_schedule_response;
    gNB->if_inst->NR_PHY_config_req      = nr_phy_config_request;
    memset((void *)&gNB->UL_INFO,0,sizeof(gNB->UL_INFO));
    memset((void *)&gNB->UL_tti_req,0,sizeof(nfapi_nr_ul_tti_request_t));
    //memset((void *)&gNB->Sched_INFO,0,sizeof(gNB->Sched_INFO));
    LOG_I(PHY,"Setting indication lists\n");
laurent's avatar
laurent committed
275 276 277
    gNB->UL_INFO.rx_ind.pdu_list = gNB->rx_pdu_list;
    gNB->UL_INFO.crc_ind.crc_list = gNB->crc_pdu_list;
    /*gNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = gNB->sr_pdu_list;
278 279 280
      gNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = gNB->harq_pdu_list;
      gNB->UL_INFO.cqi_ind.cqi_pdu_list = gNB->cqi_pdu_list;
      gNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = gNB->cqi_raw_pdu_list;*/
281
    gNB->prach_energy_counter = 0;
282
  }
283

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
  LOG_I(PHY,"[nr-softmodem.c] gNB structure allocated\n");
}


void stop_gNB(int nb_inst) {
}

static void get_options(void) {
  paramdef_t cmdline_params[] = CMDLINE_PARAMS_DESC_GNB ;
  config_process_cmdline( cmdline_params,sizeof(cmdline_params)/sizeof(paramdef_t),NULL);

  if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) {
    memset((void *)&RC,0,sizeof(RC));
    /* Read RC configuration file */
    NRRCConfig();
Laurent's avatar
Laurent committed
299
    printf("Configuration: nb_rrc_inst %d, nb_nr_L1_inst %d, nb_ru %hhd\n", RC.nb_nr_inst,RC.nb_nr_L1_inst,RC.nb_RU);
300
  }
301 302

  AssertFatal(RC.nb_nr_L1_inst == 1 && RC.nb_RU == 1, "Only one gNB, one RU and one carrier is supported\n");
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
}

void set_default_frame_parms(nfapi_nr_config_request_t *config[MAX_NUM_CCs],
                             NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
  for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
    frame_parms[CC_id] = (NR_DL_FRAME_PARMS *) malloc(sizeof(NR_DL_FRAME_PARMS));
    config[CC_id] = (nfapi_nr_config_request_t *) malloc(sizeof(nfapi_nr_config_request_t));
    config[CC_id]->subframe_config.numerology_index_mu.value =1;
    config[CC_id]->subframe_config.duplex_mode.value = 1; //FDD
    config[CC_id]->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL
    config[CC_id]->rf_config.dl_carrier_bandwidth.value = 106;
    config[CC_id]->rf_config.ul_carrier_bandwidth.value = 106;
    config[CC_id]->sch_config.physical_cell_id.value = 0;
  }
}

static void init_pdcp(void) {
  //if (!NODE_IS_DU(RC.rrc[0]->node_type)) {
  pdcp_layer_init();
  uint32_t pdcp_initmask = (IS_SOFTMODEM_NOS1) ?
                           (PDCP_USE_NETLINK_BIT | LINK_ENB_PDCP_TO_IP_DRIVER_BIT) : LINK_ENB_PDCP_TO_GTPV1U_BIT;

  if (IS_SOFTMODEM_NOS1) {
    printf("IS_SOFTMODEM_NOS1 option enabled \n");
    pdcp_initmask = pdcp_initmask | ENB_NAS_USE_TUN_BIT | SOFTMODEM_NOKRNMOD_BIT  ;
  }

330
  nr_pdcp_module_init(pdcp_initmask, 0);
331 332
  pdcp_set_rlc_data_req_func(rlc_data_req);
  pdcp_set_pdcp_data_ind_func(pdcp_data_ind);
333 334 335 336 337
}

void init_main_gNB(void) {
  RCconfig_NR_L1();
  RCconfig_nr_macrlc();
338

339 340
  if (RC.nb_nr_L1_inst>0)
    AssertFatal(l1_north_init_gNB()==0,"could not initialize L1 north interface\n");
341

342
  LOG_I(GNB_APP,"Allocating gNB_RRC_INST for %d instances\n",RC.nb_nr_inst);
343
  RC.nrrrc = (gNB_RRC_INST **)calloc(RC.nb_nr_inst*sizeof(gNB_RRC_INST *),1);
344 345
  LOG_I(PHY, "%s() RC.nb_nr_inst:%d RC.nrrrc:%p\n", __FUNCTION__, RC.nb_nr_inst, RC.nrrrc);
  int gnb_id=0; // only 1 gnb per process, index 0 for now
346
  RC.nrrrc[gnb_id] = (gNB_RRC_INST *)calloc(sizeof(gNB_RRC_INST),1);
347
  MessageDef *msg_p = itti_alloc_new_message (TASK_GNB_APP, 0, NRRRC_CONFIGURATION_REQ);
348
  RCconfig_NRRRC(msg_p,gnb_id, RC.nrrrc[gnb_id]);
349
  openair_rrc_gNB_configuration(GNB_INSTANCE_TO_MODULE_ID(ITTI_MSG_DESTINATION_INSTANCE(msg_p)), &NRRRC_CONFIGURATION_REQ(msg_p));
Laurent's avatar
Laurent committed
350 351 352
  //AssertFatal(itti_create_task(TASK_GNB_APP, gNB_app_task, NULL) >= 0, "");
  AssertFatal(itti_create_task(TASK_RRC_GNB, rrc_gnb_task, NULL) >= 0, "");
  //AssertFatal(itti_create_task(TASK_X2AP, x2ap_task, NULL) >= 0, "");
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
}

static  void wait_nfapi_init(char *thread_name) {
  printf( "waiting for NFAPI PNF connection and population of global structure (%s)\n",thread_name);
  pthread_mutex_lock( &nfapi_sync_mutex );

  while (nfapi_sync_var<0)
    pthread_cond_wait( &nfapi_sync_cond, &nfapi_sync_mutex );

  pthread_mutex_unlock(&nfapi_sync_mutex);
  printf( "NFAPI: got sync (%s)\n", thread_name);
}

void exit_function(const char *file, const char *function, const int line, const char *s) {
  if (s != NULL) {
    printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s);
  }

  oai_exit = 1;
  sleep(1); //allow lte-softmodem threads to exit first
  exit(1);
}

void stop_RU(int nb_ru) {
377
  return;
378 379
}

380 381
void OCPconfig_RU(RU_t *ru) {
  int i = 0, j = 0; // Ru and gNB cardinality
382 383 384
  paramdef_t RUParams[] = RUPARAMS_DESC;
  paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
  config_getlist( &RUParamList, RUParams, sizeof(RUParams)/sizeof(paramdef_t), NULL);
385 386
  AssertFatal( RUParamList.numelt == 1 && RC.nb_nr_L1_inst ==1,""  );
  ru->idx=0;
laurent's avatar
laurent committed
387 388
  ru->nr_frame_parms                      = (NR_DL_FRAME_PARMS *)calloc(sizeof(NR_DL_FRAME_PARMS),1);
  ru->frame_parms                         = (LTE_DL_FRAME_PARMS *)calloc(sizeof(LTE_DL_FRAME_PARMS),1);
389 390 391 392 393 394 395
  ru->if_timing                           = synch_to_ext_device;
  ru->num_gNB                           = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt;
  ru->gNB_list[i] = &RC.gNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]][0];

  if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) {
    ru->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr));
  }
396

397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
  if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) {
    if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) {
      ru->openair0_cfg.clock_source = internal;
      LOG_D(PHY, "RU clock source set as internal\n");
    } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) {
      ru->openair0_cfg.clock_source = external;
      LOG_D(PHY, "RU clock source set as external\n");
    } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) {
      ru->openair0_cfg.clock_source = gpsdo;
      LOG_D(PHY, "RU clock source set as gpsdo\n");
    } else {
      LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr));
    }
  } else {
    ru->openair0_cfg.clock_source = unset;
  }
413

414 415
  if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) {
    if ( !(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX)) ) {
laurent's avatar
laurent committed
416
      ru->if_south                        = REMOTE_IF5; //TBD: max value to avoid to call "ru" functions
417 418 419 420
      ru->function                        = gNodeB_3GPP;
      printf("Setting function for RU %d to gNodeB_3GPP\n",j);
    } else {
    }
421

422 423 424
    ru->max_pdschReferenceSignalPower     = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);;
    ru->max_rxgain                        = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr);
    ru->num_bands                         = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt;
425

426 427 428 429
    for (i=0; i<ru->num_bands; i++) ru->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i];
  } //strcmp(local_rf, "yes") == 0
  else {
  }
430

431 432 433 434
  ru->nb_tx                             = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr);
  ru->nb_rx                             = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr);
  ru->att_tx                            = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr);
  ru->att_rx                            = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr);
435

436 437
  if (config_isparamset(RUParamList.paramarray[j], RU_BF_WEIGHTS_LIST_IDX)) {
    ru->nb_bfw = RUParamList.paramarray[j][RU_BF_WEIGHTS_LIST_IDX].numelt;
438

439 440
    for (i=0; i<ru->num_gNB; i++)  {
      ru->bw_list[i] = (int32_t *)malloc16_clear((ru->nb_bfw)*sizeof(int32_t));
441

442 443 444
      for (int b=0; b<ru->nb_bfw; b++) ru->bw_list[i][b] = RUParamList.paramarray[j][RU_BF_WEIGHTS_LIST_IDX].iptr[b];
    }
  }
445 446 447 448 449 450 451

  return;
}

// this is for RU with local RF unit
void fill_rf_config(RU_t *ru, char *rf_config_file) {
  int i;
Laurent's avatar
Laurent committed
452
  NR_DL_FRAME_PARMS *fp   = ru->nr_frame_parms;
453
  nfapi_nr_config_request_scf_t *gNB_config = &ru->gNB_list[0]->gNB_config; //tmp index
454
  openair0_config_t *cfg   = &ru->openair0_cfg;
455 456 457
  int mu = gNB_config->ssb_config.scs_common.value;
  int N_RB = gNB_config->carrier_config.dl_grid_size[gNB_config->ssb_config.scs_common.value].value;
  fp->threequarter_fs=threequarter_fs;
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524

  if (mu == NR_MU_0) { //or if LTE
    if(N_RB == 100) {
      if (fp->threequarter_fs) {
        cfg->sample_rate=23.04e6;
        cfg->samples_per_frame = 230400;
        cfg->tx_bw = 10e6;
        cfg->rx_bw = 10e6;
      } else {
        cfg->sample_rate=30.72e6;
        cfg->samples_per_frame = 307200;
        cfg->tx_bw = 10e6;
        cfg->rx_bw = 10e6;
      }
    } else if(N_RB == 50) {
      cfg->sample_rate=15.36e6;
      cfg->samples_per_frame = 153600;
      cfg->tx_bw = 5e6;
      cfg->rx_bw = 5e6;
    } else if (N_RB == 25) {
      cfg->sample_rate=7.68e6;
      cfg->samples_per_frame = 76800;
      cfg->tx_bw = 2.5e6;
      cfg->rx_bw = 2.5e6;
    } else if (N_RB == 6) {
      cfg->sample_rate=1.92e6;
      cfg->samples_per_frame = 19200;
      cfg->tx_bw = 1.5e6;
      cfg->rx_bw = 1.5e6;
    } else AssertFatal(1==0,"Unknown N_RB %d\n",N_RB);
  } else if (mu == NR_MU_1) {
    if(N_RB == 273) {
      if (fp->threequarter_fs) {
        AssertFatal(0 == 1,"three quarter sampling not supported for N_RB 273\n");
      } else {
        cfg->sample_rate=122.88e6;
        cfg->samples_per_frame = 1228800;
        cfg->tx_bw = 100e6;
        cfg->rx_bw = 100e6;
      }
    } else if(N_RB == 217) {
      if (fp->threequarter_fs) {
        cfg->sample_rate=92.16e6;
        cfg->samples_per_frame = 921600;
        cfg->tx_bw = 80e6;
        cfg->rx_bw = 80e6;
      } else {
        cfg->sample_rate=122.88e6;
        cfg->samples_per_frame = 1228800;
        cfg->tx_bw = 80e6;
        cfg->rx_bw = 80e6;
      }
    } else if(N_RB == 106) {
      if (fp->threequarter_fs) {
        cfg->sample_rate=46.08e6;
        cfg->samples_per_frame = 460800;
        cfg->tx_bw = 40e6;
        cfg->rx_bw = 40e6;
      } else {
        cfg->sample_rate=61.44e6;
        cfg->samples_per_frame = 614400;
        cfg->tx_bw = 40e6;
        cfg->rx_bw = 40e6;
      }
    } else {
      AssertFatal(0==1,"N_RB %d not yet supported for numerology %d\n",N_RB,mu);
    }
525 526 527 528 529 530 531 532 533 534 535 536
  } else if (mu == NR_MU_3) {
    if (N_RB == 66) {
      cfg->sample_rate = 122.88e6;
      cfg->samples_per_frame = 1228800;
      cfg->tx_bw = 100e6;
      cfg->rx_bw = 100e6;
    } else if(N_RB == 32) {
      cfg->sample_rate=61.44e6;
      cfg->samples_per_frame = 614400;
      cfg->tx_bw = 50e6;
      cfg->rx_bw = 50e6;
    }
537 538 539 540
  } else {
    AssertFatal(0 == 1,"Numerology %d not supported for the moment\n",mu);
  }

541
  if (gNB_config->cell_config.frame_duplex_type.value==TDD)
542 543 544 545 546 547 548 549 550 551
    cfg->duplex_mode = duplex_mode_TDD;
  else //FDD
    cfg->duplex_mode = duplex_mode_FDD;

  cfg->Mod_id = 0;
  cfg->num_rb_dl=N_RB;
  cfg->tx_num_channels=ru->nb_tx;
  cfg->rx_num_channels=ru->nb_rx;

  for (i=0; i<ru->nb_tx; i++) {
552 553 554 555 556 557 558 559
    if (ru->if_frequency == 0) {
      cfg->tx_freq[i] = (double)fp->dl_CarrierFreq;
      cfg->rx_freq[i] = (double)fp->ul_CarrierFreq;
    } else {
      cfg->tx_freq[i] = (double)ru->if_frequency;
      cfg->rx_freq[i] = (double)(ru->if_frequency+fp->ul_CarrierFreq-fp->dl_CarrierFreq);
    }

560 561 562 563 564 565 566 567 568 569
    cfg->tx_gain[i] = ru->att_tx;
    cfg->rx_gain[i] = ru->max_rxgain-ru->att_rx;
    cfg->configFilename = rf_config_file;
    printf("channel %d, Setting tx_gain offset %f, rx_gain offset %f, tx_freq %f, rx_freq %f\n",
           i, cfg->tx_gain[i],
           cfg->rx_gain[i],
           cfg->tx_freq[i],
           cfg->rx_freq[i]);
  }
}
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680

/* this function maps the RU tx and rx buffers to the available rf chains.
   Each rf chain is is addressed by the card number and the chain on the card. The
   rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple
   antennas are mapped to successive RF chains on the same card. */
int setup_RU_buffers(RU_t *ru) {
  int i,j;
  int card,ant;
  //uint16_t N_TA_offset = 0;
  NR_DL_FRAME_PARMS *frame_parms;
  nfapi_nr_config_request_scf_t *config = &ru->config;

  if (ru) {
    frame_parms = ru->nr_frame_parms;
    printf("setup_RU_buffers: frame_parms = %p\n",frame_parms);
  } else {
    printf("ru pointer is NULL\n");
    return(-1);
  }

  int mu = config->ssb_config.scs_common.value;
  int N_RB = config->carrier_config.dl_grid_size[config->ssb_config.scs_common.value].value;

  if (config->cell_config.frame_duplex_type.value == TDD) {
    int N_TA_offset =  config->carrier_config.uplink_frequency.value < 6000000 ? 400 : 431; // reference samples  for 25600Tc @ 30.72 Ms/s for FR1, same @ 61.44 Ms/s for FR2
    double factor=1;

    switch (mu) {
      case 0: //15 kHz scs
        AssertFatal(N_TA_offset == 400,"scs_common 15kHz only for FR1\n");

        if (N_RB <= 25) factor = .25;      // 7.68 Ms/s
        else if (N_RB <=50) factor = .5;   // 15.36 Ms/s
        else if (N_RB <=75) factor = 1.0;  // 30.72 Ms/s
        else if (N_RB <=100) factor = 1.0; // 30.72 Ms/s
        else AssertFatal(1==0,"Too many PRBS for mu=0\n");

        break;

      case 1: //30 kHz sc
        AssertFatal(N_TA_offset == 400,"scs_common 30kHz only for FR1\n");

        if (N_RB <= 106) factor = 2.0; // 61.44 Ms/s
        else if (N_RB <= 275) factor = 4.0; // 122.88 Ms/s

        break;

      case 2: //60 kHz scs
        AssertFatal(1==0,"scs_common should not be 60 kHz\n");
        break;

      case 3: //120 kHz scs
        AssertFatal(N_TA_offset == 431,"scs_common 120kHz only for FR2\n");
        break;

      case 4: //240 kHz scs
        AssertFatal(1==0,"scs_common should not be 60 kHz\n");

        if (N_RB <= 32) factor = 1.0; // 61.44 Ms/s
        else if (N_RB <= 66) factor = 2.0; // 122.88 Ms/s
        else AssertFatal(1==0,"N_RB %d is too big for curretn FR2 implementation\n",N_RB);

        break;

        if      (N_RB == 100) ru->N_TA_offset = 624;
        else if (N_RB == 50)  ru->N_TA_offset = 624/2;
        else if (N_RB == 25)  ru->N_TA_offset = 624/4;
    }

    if (frame_parms->threequarter_fs == 1) factor = factor*.75;

    ru->N_TA_offset = (int)(N_TA_offset * factor);
    LOG_I(PHY,"RU %d Setting N_TA_offset to %d samples (factor %f, UL Freq %d, N_RB %d)\n",ru->idx,ru->N_TA_offset,factor,
          config->carrier_config.uplink_frequency.value, N_RB);
  } else ru->N_TA_offset = 0;

  if (ru->openair0_cfg.mmapped_dma == 1) {
    // replace RX signal buffers with mmaped HW versions
    for (i=0; i<ru->nb_rx; i++) {
      card = i/4;
      ant = i%4;
      printf("Mapping RU id %u, rx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
      free(ru->common.rxdata[i]);
      ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain+ant];
      printf("rxdata[%d] @ %p\n",i,ru->common.rxdata[i]);

      for (j=0; j<16; j++) {
        printf("rxbuffer %d: %x\n",j,ru->common.rxdata[i][j]);
        ru->common.rxdata[i][j] = 16-j;
      }
    }

    for (i=0; i<ru->nb_tx; i++) {
      card = i/4;
      ant = i%4;
      printf("Mapping RU id %u, tx_ant %d, on card %d, chain %d\n",ru->idx,i,ru->rf_map.card+card, ru->rf_map.chain+ant);
      free(ru->common.txdata[i]);
      ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain+ant];
      printf("txdata[%d] @ %p\n",i,ru->common.txdata[i]);

      for (j=0; j<16; j++) {
        printf("txbuffer %d: %x\n",j,ru->common.txdata[i][j]);
        ru->common.txdata[i][j] = 16-j;
      }
    }
  } else { // not memory-mapped DMA
    //nothing to do, everything already allocated in lte_init
  }

  return(0);
}
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
int rx_rf(int rxBufOffet, int nbSamples, int nb_rx, int32_t **rxdata, openair0_device *rfdevice,  openair0_timestamp *HWtimeStamp) {
  void *rxp[nb_rx];

  for (int i=0; i<nb_rx; i++)
    rxp[i] = (void *)&rxdata[i][rxBufOffet];

  unsigned int rxs = rfdevice->trx_read_func(rfdevice,
                     HWtimeStamp,
                     rxp,
                     nbSamples,
                     nb_rx);

  if (rxs != nbSamples )
    LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n",nbSamples,rxs);

  return rxs;
}

void tx_rf(RU_t *ru,int frame,int slot, uint64_t timestamp) {
  RU_proc_t *proc = &ru->proc;
  NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
  nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config;
  int i,txsymb;
  int slot_type         = nr_slot_select(cfg,frame,slot%fp->slots_per_frame);
  int prevslot_type     = nr_slot_select(cfg,frame,(slot+(fp->slots_per_frame-1))%fp->slots_per_frame);
  int nextslot_type     = nr_slot_select(cfg,frame,(slot+1)%fp->slots_per_frame);
  int sf_extension  = 0;                 //sf_extension = ru->sf_extension;
  int siglen=fp->get_samples_per_slot(slot,fp);
  int flags=1;

  //nr_subframe_t SF_type     = nr_slot_select(cfg,slot%fp->slots_per_frame);
  if (slot_type == NR_DOWNLINK_SLOT || slot_type == NR_MIXED_SLOT || IS_SOFTMODEM_RFSIM) {
    if(slot_type == NR_MIXED_SLOT) {
      txsymb = 0;

      for(int symbol_count =0; symbol_count<NR_NUMBER_OF_SYMBOLS_PER_SLOT; symbol_count++) {
        if (cfg->tdd_table.max_tdd_periodicity_list[slot].max_num_of_symbol_per_slot_list[symbol_count].slot_config.value==0)
          txsymb++;
      }

      AssertFatal(txsymb>0,"illegal txsymb %d\n",txsymb);

      if(slot%(fp->slots_per_subframe/2))
        siglen = txsymb * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
      else
        siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);

      //+ ru->end_of_burst_delay;
      flags=3; // end of burst
    }

    if (cfg->cell_config.frame_duplex_type.value == TDD &&
        slot_type == NR_DOWNLINK_SLOT &&
        prevslot_type == NR_UPLINK_SLOT) {
      flags = 2; // start of burst
    }

    if (cfg->cell_config.frame_duplex_type.value == TDD &&
        slot_type == NR_DOWNLINK_SLOT &&
        nextslot_type == NR_UPLINK_SLOT) {
      flags = 3; // end of burst
    }

    if (fp->freq_range==nr_FR2) {
      // the beam index is written in bits 8-10 of the flags
      // bit 11 enables the gpio programming
      int beam=0;

      if (slot==0) beam = 11; //3 for boresight & 8 to enable

      /*
        if (slot==0 || slot==40) beam=0&8;
        if (slot==10 || slot==50) beam=1&8;
        if (slot==20 || slot==60) beam=2&8;
        if (slot==30 || slot==70) beam=3&8;
      */
      flags |= beam<<8;
    }

    void *txp[ru->nb_tx];

    for (i=0; i<ru->nb_tx; i++)
      txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot,fp,0)-sf_extension];
764

765 766 767 768 769 770 771 772 773 774 775 776
    // prepare tx buffer pointers
    unsigned int txs = ru->rfdevice.trx_write_func(&ru->rfdevice,
                       timestamp+ru->ts_offset-ru->openair0_cfg.tx_sample_advance-sf_extension,
                       txp,
                       siglen+sf_extension,
                       ru->nb_tx,
                       flags);
    LOG_D(PHY,"[TXPATH] RU %d tx_rf, writing to TS %llu, frame %d, unwrapped_frame %d, slot %d\n",ru->idx,
          (long long unsigned int)timestamp,frame,proc->frame_tx_unwrap,slot);
    AssertFatal(txs ==  siglen+sf_extension,"TX : Timeout (sent %u/%d)\n", txs, siglen);
  }
}
777

778 779 780 781 782
static void *ru_thread( void *param ) {
  RU_t               *ru      = (RU_t *)param;
  NR_DL_FRAME_PARMS  *fp      = ru->nr_frame_parms;
  LOG_I(PHY,"Starting RU %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]);
  nr_dump_frame_parms(fp);
783
  AssertFatal(openair0_device_load(&ru->rfdevice,&ru->openair0_cfg)==0,"Cannot connect to local radio\n");
784
  AssertFatal(ru->rfdevice.trx_start_func(&ru->rfdevice) == 0,"Could not start the RF device\n");
785
  int64_t slot=-1;
786
  int64_t nextHWTSshouldBe=0, nextRxTSlogical=0;
787
  // weird globals, used in NR_IF_Module.c
788
  sf_ahead = (uint16_t) ceil((float)6/(0x01<<fp->numerology_index));
789 790 791
  sl_ahead = sf_ahead*fp->slots_per_subframe;

  // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices
792

laurent's avatar
laurent committed
793
  while (!oai_exit) {
794 795 796 797 798
    int nextSlot=(slot+1)%fp->slots_per_frame;
    uint32_t samples_per_slot = fp->get_samples_per_slot(nextSlot,fp);
    int rxBuffOffset=fp->get_samples_slot_timestamp(nextSlot,fp,0);
    AssertFatal(rxBuffOffset + samples_per_slot <= fp->samples_per_frame, "Will read outside allocated buffer\n");
    int samples=fp->get_samples_per_slot(nextSlot,fp);
799
    openair0_timestamp HWtimeStamp=0; //for multi RU
800 801 802 803 804 805 806 807
    int rxs=rx_rf(rxBuffOffset,
                  samples,
                  ru->nb_rx,
                  ru->common.rxdata,
                  &ru->rfdevice,
                  &HWtimeStamp);
    LOG_D(PHY,"Reading %d samples for slot %d\n",samples_per_slot,nextSlot);

808 809 810 811
    if ( HWtimeStamp !=  nextHWTSshouldBe)
      LOG_E(HW,"reading a stream must be continuous, %ld, %ld\n", HWtimeStamp, nextHWTSshouldBe);

    nextHWTSshouldBe=HWtimeStamp+rxs;
Laurent's avatar
Laurent committed
812
    ru->proc.timestamp_rx=nextRxTSlogical;
813
    nextRxTSlogical+=samples_per_slot;
Laurent's avatar
Laurent committed
814 815 816 817 818 819 820
    int64_t HW_to_logical_RxTSoffset=(int64_t)HWtimeStamp-(int64_t)ru->proc.timestamp_rx;
    ru->proc.frame_rx    = (ru->proc.timestamp_rx / (fp->samples_per_subframe*10))&1023;
    uint32_t idx_sf = ru->proc.timestamp_rx / fp->samples_per_subframe;
    float offsetInSubframe=ru->proc.timestamp_rx % fp->samples_per_subframe;
    ru->proc.tti_rx = (idx_sf * fp->slots_per_subframe +
                       lroundf(offsetInSubframe / fp->samples_per_slot0))%
                      fp->slots_per_frame;
821 822
    LOG_D(PHY,"RU %d/%d TS %llu (off %d), frame %d, slot %d.%d / %d\n",
          ru->idx, 0,
Laurent's avatar
Laurent committed
823 824 825
          (unsigned long long int)ru->proc.timestamp_rx,
          (int)ru->ts_offset,ru->proc.frame_rx,ru->proc.tti_rx,ru->proc.tti_tx,fp->slots_per_frame);
    int slot_type = nr_slot_select(&ru->gNB_list[0]->gNB_config,ru->proc.frame_rx,ru->proc.tti_rx);
Laurent's avatar
Laurent committed
826

827
    if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) {
Laurent's avatar
Laurent committed
828
      nr_fep_full(ru,ru->proc.tti_rx);
829 830 831 832 833 834

      for (int aa=0; aa<ru->nb_rx; aa++)
        memcpy((void *)RC.gNB[0]->common_vars.rxdataF[aa],
               (void *)ru->common.rxdataF[aa], fp->symbols_per_slot*fp->ofdm_symbol_size*sizeof(int32_t));

      LOG_D(PHY, "rxdataF energy: %d\n", signal_energy(ru->common.rxdataF[0], fp->symbols_per_slot*fp->ofdm_symbol_size));
835
    }
Laurent's avatar
Laurent committed
836

Laurent's avatar
Laurent committed
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
    gNB_L1_proc_t *gNBproc=&RC.gNB[0][0].proc;
    gNB_L1_rxtx_proc_t *L1_proc = &gNBproc->L1_proc;
    NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
    gNBproc->timestamp_rx  = ru->proc.timestamp_rx;
    L1_proc->frame_rx = gNBproc->frame_rx = gNBproc->frame_prach = ru->proc.frame_rx =
        (ru->proc.timestamp_rx / (fp->samples_per_subframe*10))&1023;
    L1_proc->slot_rx = gNBproc->slot_rx = gNBproc->slot_prach =
                                            ru->proc.tti_rx; // computed before in caller function
    L1_proc->timestamp_tx = gNBproc->timestamp_tx = ru->proc.timestamp_tx =
                              ru->proc.timestamp_rx +
                              sf_ahead*fp->samples_per_subframe;
    L1_proc->frame_tx  = gNBproc->frame_tx = ru->proc.frame_tx =
                           (gNBproc->timestamp_tx / (fp->samples_per_subframe*10))&1023;
    L1_proc->slot_tx   =  ru->proc.tti_tx =
                            (L1_proc->slot_rx + sl_ahead)%fp->slots_per_frame;
Laurent's avatar
Laurent committed
852

Laurent's avatar
Laurent committed
853
    if (ocp_rxtx(&RC.gNB[0][0],L1_proc) < 0)
laurent's avatar
laurent committed
854 855
      LOG_E(PHY,"gNB %d CC_id %d failed during execution\n",RC.gNB[0][0].Mod_id,RC.gNB[0][0].CC_id);

856 857
    // do TX front-end processing if needed (precoding and/or IDFTs)
    //ru->feptx_prec(ru,proc->frame_tx,proc->tti_tx);
Laurent's avatar
Laurent committed
858
    nr_feptx_prec(ru,ru->proc.frame_tx,ru->proc.tti_tx);
859 860
    // do OFDM with/without TX front-end processing  if needed
    //ru->feptx_ofdm
861 862
    nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config;

Laurent's avatar
Laurent committed
863
    if (nr_slot_select(cfg,ru->proc.frame_tx, ru->proc.tti_tx ) != NR_UPLINK_SLOT) {
864 865
      int aa=0; // antenna 0 hardcoded
      NR_DL_FRAME_PARMS *fp=ru->nr_frame_parms;
Laurent's avatar
Laurent committed
866 867
      nr_feptx0(ru,ru->proc.tti_tx,0,fp->symbols_per_slot,aa);
      int *txdata = &ru->common.txdata[aa][fp->get_samples_slot_timestamp(ru->proc.tti_tx,fp,0)];
868 869 870
      int slot_sizeF = (fp->ofdm_symbol_size)*
                       ((NFAPI_CP_NORMAL == 1) ? 12 : 14);
      LOG_D(PHY,"feptx_ofdm (TXPATH): frame %d, slot %d: txp (time %ld) %d dB, txp (freq) %d dB\n",
Laurent's avatar
Laurent committed
871 872 873
            ru->proc.frame_tx,ru->proc.tti_tx,ru->proc.timestamp_tx,
            dB_fixed(signal_energy((int32_t *)txdata,fp->get_samples_per_slot(ru->proc.tti_tx,fp))),
            dB_fixed(signal_energy_nodc(ru->common.txdataF_BF[aa],2*slot_sizeF)));
874
    }
Laurent's avatar
Laurent committed
875

876
    // do outgoing fronthaul (south) if needed
Laurent's avatar
Laurent committed
877
    tx_rf(ru,ru->proc.frame_tx,ru->proc.tti_tx,ru->proc.timestamp_tx+HW_to_logical_RxTSoffset);
878
    slot++;
879
  }
880

881 882 883 884 885
  printf( "Exiting ru_thread \n");
  ru->rfdevice.trx_end_func(&ru->rfdevice);
  static int ru_thread_status = 0;
  return &ru_thread_status;
}
886

887
void launch_NR_RU(RU_t *ru, char *rf_config_file) {
888
  LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",
889
        RC.nb_nr_L1_inst,RC.nb_RU,get_nprocs());
890 891 892 893 894 895 896 897 898
  LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);

  for (int ru_id=0; ru_id<RC.nb_RU; ru_id++) {
    LOG_D(PHY,"Process RC.ru[%d]\n",ru_id);
    ru->rf_config_file = rf_config_file;
    ru->idx            = ru_id;
    ru->ts_offset      = 0;
    // use gNB_list[0] as a reference for RU frame parameters
    // NOTE: multiple CC_id are not handled here yet!
899 900
    LOG_D(PHY, "%s() RC.ru[%d].num_gNB:%d ru->gNB_list[0]:%p rf_config_file:%s\n",
          __FUNCTION__, ru_id, ru->num_gNB, ru->gNB_list[0],  ru->rf_config_file);
901
    LOG_E(PHY,"ru->gNB_list ru->num_gNB hardcoded: one RU connected to carrier 0 of gNB 0\n");
902
    ru->gNB_list[0] = &RC.gNB[0][0];
903 904 905
    ru->num_gNB=1;
    LOG_I(PHY,"Copying frame parms from gNB in RC to ru %d and frame_parms in ru\n",ru->idx);
    RU_proc_t *proc = &ru->proc;
906
    threadCreate( &proc->pthread_FH, ru_thread, (void *)ru, "MainLoop", -1, OAI_PRIORITY_RT_MAX );
907
  }
908
}
909

laurent's avatar
laurent committed
910
void init_eNB_afterRU(void) {
911 912 913
  AssertFatal(false,"");
}

914 915
int main( int argc, char **argv ) {
  AssertFatal(load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY),
916
              "[SOFTMODEM] Error, configuration module init failed\n");
917 918 919 920 921
  logInit();
#ifndef PACKAGE_VERSION
#  define PACKAGE_VERSION "UNKNOWN"
#endif
  LOG_I(HW, "Version: %s\n", PACKAGE_VERSION);
922
  set_latency_target();
923 924
  get_options ();
  get_common_options(SOFTMODEM_GNB_BIT );
925
  AssertFatal(!CONFIG_ISFLAGSET(CONFIG_ABORT),"Getting configuration failed\n");
926
  cpuf=get_cpu_freq_GHz();
Laurent Thomas's avatar
Laurent Thomas committed
927
  itti_init(TASK_MAX, tasks_info);
928 929
  set_taus_seed (0);
  init_opt();
930
  init_pdcp();
931
  init_main_gNB();
932
  init_gNB(true, wait_for_sync);
933 934
  /* Start the agent. If it is turned off in the configuration, it won't start */
  RCconfig_nr_flexran();
935

936 937 938 939
  for (int i = 0; i < RC.nb_nr_L1_inst; i++) {
    flexran_agent_start(i);
  }

940 941 942
  /*
   *nfapi stuff very buggy in 4G, not yet implemented in 5G
   */
943 944 945 946 947 948
  // init UE_PF_PO and mutex lock (paging from S1AP)
  pthread_mutex_init(&ue_pf_po_mutex, NULL);
  printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n");
  pthread_cond_init(&nfapi_sync_cond,NULL);
  pthread_mutex_init(&nfapi_sync_mutex, NULL);
  const char *nfapi_mode_str[] = {
949 950
    "MONOLITHIC", "PNF", "VNF",
  };
951 952
  AssertFatal(nfapi_mode < 3,"");
  printf("NFAPI MODE:%s\n", nfapi_mode_str[nfapi_mode]);
953

954 955 956
  if (nfapi_mode==NFAPI_MODE_VNF) // VNF
    wait_nfapi_init("main?");

957 958 959
  for (int i=0; i<RC.nb_nr_L1_inst; i++)
    AssertFatal(RC.gNB[i]->configured, "Remain threads to manage\n");

960 961 962 963 964 965 966 967 968 969 970 971
  printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU);
  config_sync_var=0;

  if (nfapi_mode==NFAPI_MODE_PNF) { // PNF
    wait_nfapi_init("main?");
  }

  printf("wait RUs\n");
  printf("ALL RUs READY!\n");
  printf("RC.nb_RU:%d\n", RC.nb_RU);
  // once all RUs are ready initialize the rest of the gNBs ((dependence on final RU parameters after configuration)
  printf("ALL RUs ready - init gNBs\n");
972
  LOG_E(PHY,"configuring RU from file,  hardcoded one gNB for one RU, one carrier\n");
laurent's avatar
laurent committed
973
  RU_t ru= {0};
974 975 976
  OCPconfig_RU(&ru);
  ru.nr_frame_parms->threequarter_fs=threequarter_fs;
  fill_rf_config(&ru,ru.rf_config_file);
977
  init_gNB_phase2(&ru);
978
  memcpy((void *)ru.nr_frame_parms,&RC.gNB[0][0].frame_parms,sizeof(NR_DL_FRAME_PARMS));
979 980
  memcpy((void *)&ru.config,(void *)&RC.gNB[0]->gNB_config,sizeof(ru.config));
  AssertFatal(setup_RU_buffers(&ru)==0,"Inconsistent configuration");
981
  nr_phy_init_RU(&ru);
982
  init_gNB_proc(0); // only instance 0 (one gNB per process)
983

984 985
  if (RC.nb_RU >0) {
    printf("Initializing RU threads\n");
986
    launch_NR_RU(&ru, get_softmodem_params()->rf_config_file);
987 988 989 990 991
  }

  if (opp_enabled ==1) {
    pthread_t t;
    threadCreate(&t, process_stats_thread,
992
                 (void *)NULL, "time_meas", -1, OAI_PRIORITY_RT_LOW);
993 994
  }

995
  if(IS_SOFTMODEM_DOSCOPE) {
996
    scopeParms_t tmp= {&argc, argv, &ru, RC.gNB[0]};
Laurent's avatar
Laurent committed
997
    load_softscope("nr",&tmp);
998 999 1000 1001
  }

  while(!oai_exit)
    sleep(1);
1002

1003 1004 1005 1006
  logClean();
  printf("Bye.\n");
  return 0;
}