nr-softmodem.c 24.9 KB
Newer Older
laurent's avatar
laurent committed
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
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */


#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sched.h>


#include "T.h"

#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
#include <common/utils/assertions.h>
31
#include "common/oai_version.h"
laurent's avatar
laurent committed
32 33 34 35 36

#include "PHY/types.h"
#include "common/ran_context.h"

#include "PHY/defs_gNB.h"
37
#include "PHY/defs_common.h"
laurent's avatar
laurent committed
38 39 40 41 42
#include "common/config/config_userapi.h"
#include "common/utils/load_module_shlib.h"
#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all
//#undef FRAME_LENGTH_COMPLEX_SAMPLES //there are two conflicting definitions, so we better make sure we don't use it at all

francescomani's avatar
francescomani committed
43
#include "radio/COMMON/common_lib.h"
44
#include "radio/ETHERNET/if_defs.h"
laurent's avatar
laurent committed
45 46 47 48 49 50 51

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

#include "PHY/phy_vars.h"
#include "RRC/LTE/rrc_vars.h"
#include "PHY_INTERFACE/phy_interface_vars.h"
#include "gnb_config.h"
52
#include "SIMULATION/TOOLS/sim.h"
laurent's avatar
laurent committed
53 54 55 56 57 58 59 60 61

#ifdef SMBV
#include "PHY/TOOLS/smbv.h"
unsigned short config_frames[4] = {2,9,11,13};
#endif

#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "UTIL/OPT/opt.h"
62
#include "LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
laurent's avatar
laurent committed
63

64
#include "intertask_interface.h"
laurent's avatar
laurent committed
65

66
#include "PHY/INIT/nr_phy_init.h"
laurent's avatar
laurent committed
67 68 69

#include "system.h"
#include <openair2/GNB_APP/gnb_app.h>
70
#include "PHY/TOOLS/phy_scope_interface.h"
71
#include "PHY/TOOLS/nr_phy_scope.h"
laurent's avatar
laurent committed
72
#include "nr-softmodem.h"
73 74
#include "executables/softmodem-common.h"
#include "executables/thread-common.h"
laurent's avatar
laurent committed
75
#include "NB_IoT_interface.h"
76
#include "x2ap_eNB.h"
heshanyun's avatar
heshanyun committed
77
#include "ngap_gNB.h"
78
#include "gnb_paramdef.h"
79
#include <openair3/ocp-gtpu/gtp_itf.h>
Mahesh's avatar
Mahesh committed
80
#include "nfapi/oai_integration/vendor_ext.h"
81 82
#include "gnb_config.h"
#include "openair2/E1AP/e1ap_common.h"
83
#include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h"
84 85 86
#ifdef ENABLE_AERIAL
#include "nfapi/oai_integration/aerial/fapi_nvIPC.h"
#endif
87 88 89 90 91
#ifdef E2_AGENT
#include "openair2/E2AP/flexric/src/agent/e2_agent_api.h"
#include "openair2/E2AP/RAN_FUNCTION/init_ran_func.h"
#endif

laurent's avatar
laurent committed
92 93 94 95
pthread_cond_t nfapi_sync_cond;
pthread_mutex_t nfapi_sync_mutex;
int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex

Mahesh's avatar
Mahesh committed
96
extern uint8_t nfapi_mode; // Default to monolithic mode
97
THREAD_STRUCT thread_struct;
laurent's avatar
laurent committed
98 99 100 101 102
pthread_cond_t sync_cond;
pthread_mutex_t sync_mutex;
int sync_var=-1; //!< protected by mutex \ref sync_mutex.
int config_sync_var=-1;

103
volatile int             start_gNB = 0;
104
int oai_exit = 0;
laurent's avatar
laurent committed
105

laurent's avatar
laurent committed
106 107
int NB_UE_INST = 0;

laurent's avatar
laurent committed
108 109
static int wait_for_sync = 0;

110
unsigned int mmapped_dma=0;
laurent's avatar
laurent committed
111

112
uint64_t downlink_frequency[MAX_NUM_CCs][4];
113
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
laurent's avatar
laurent committed
114

115
//Temp fix for inexistent NR upper layer
laurent's avatar
laurent committed
116
unsigned char NB_gNB_INST = 1;
117
char *uecap_file;
laurent's avatar
laurent committed
118 119 120 121

runmode_t mode = normal_txrx;

#if MAX_NUM_CCs == 1
122
rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}};
laurent's avatar
laurent committed
123 124 125
double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}};
#else
126
rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain},{max_gain,max_gain,max_gain,max_gain}};
laurent's avatar
laurent committed
127 128 129 130 131 132
double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0},{20,0,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0},{20,0,0,0}};
#endif

double rx_gain_off = 0.0;

133
static int tx_max_power[MAX_NUM_CCs]; /* =  {0,0}*/;
laurent's avatar
laurent committed
134 135 136


int chain_offset=0;
137

laurent's avatar
laurent committed
138 139 140 141
uint8_t dci_Format = 0;
uint8_t nb_antenna_tx = 1;
uint8_t nb_antenna_rx = 1;

142
int otg_enabled;
laurent's avatar
laurent committed
143

144
extern void *udp_eNB_task(void *args_p);
laurent's avatar
laurent committed
145 146 147 148 149

int transmission_mode=1;
int emulate_rf = 0;
int numerology = 0;

150

laurent's avatar
laurent committed
151 152 153 154 155
/* struct for ethernet specific parameters given in eNB conf file */
eth_params_t *eth_params;

double cpuf;

156 157 158 159 160 161
/* hack: pdcp_run() is required by 4G scheduler which is compiled into
 * nr-softmodem because of linker issues */
void pdcp_run(const protocol_ctxt_t *const ctxt_pP)
{
  abort();
}
laurent's avatar
laurent committed
162 163

/* forward declarations */
164
void set_default_frame_parms(nfapi_nr_config_request_scf_t *config[MAX_NUM_CCs], NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]);
laurent's avatar
laurent committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184

/*---------------------BMC: timespec helpers -----------------------------*/

struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 };
struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 };

struct timespec clock_difftime(struct timespec start, struct timespec end) {
  struct timespec temp;

  if ((end.tv_nsec-start.tv_nsec)<0) {
    temp.tv_sec = end.tv_sec-start.tv_sec-1;
    temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
  } else {
    temp.tv_sec = end.tv_sec-start.tv_sec;
    temp.tv_nsec = end.tv_nsec-start.tv_nsec;
  }

  return temp;
}

185 186 187
void print_difftimes(void)
{
  LOG_I(HW, "difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
laurent's avatar
laurent committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
}

void update_difftimes(struct timespec start, struct timespec end) {
  struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 };
  int             changed = 0;
  diff_time = clock_difftime(start, end);

  if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) {
    min_diff_time.tv_nsec = diff_time.tv_nsec;
    changed = 1;
  }

  if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) {
    max_diff_time.tv_nsec = diff_time.tv_nsec;
    changed = 1;
  }

#if 1

  if (changed) print_difftimes();

#endif
}

/*------------------------------------------------------------------------*/

unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) {
  return (txi + (txq<<6) + (rxi<<12) + (rxq<<18));
}
unsigned int build_rfdc(int dcoff_i_rxfe, int dcoff_q_rxfe) {
  return (dcoff_i_rxfe + (dcoff_q_rxfe<<8));
}

221

laurent's avatar
laurent committed
222 223 224 225 226 227
#define KNRM  "\x1B[0m"
#define KRED  "\x1B[31m"
#define KGRN  "\x1B[32m"
#define KBLU  "\x1B[34m"
#define RESET "\033[0m"

228 229
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
laurent's avatar
laurent committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
  int ru_id;

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

  oai_exit = 1;

  if (RC.ru == NULL)
    exit(-1); // likely init not completed, prevent crash or hang, exit now...

  for (ru_id=0; ru_id<RC.nb_RU; ru_id++) {
    if (RC.ru[ru_id] && RC.ru[ru_id]->rfdevice.trx_end_func) {
      RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice);
      RC.ru[ru_id]->rfdevice.trx_end_func = NULL;
    }

    if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) {
      RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
      RC.ru[ru_id]->ifdevice.trx_end_func = NULL;
    }
  }

253 254 255
  if (assert) {
    abort();
  } else {
256
    sleep(1); // allow nr-softmodem threads to exit first
257 258
    exit(EXIT_SUCCESS);
  }
laurent's avatar
laurent committed
259 260
}

261
static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cfg)
262
{
263 264 265
  uint32_t                        gnb_nb = RC.nb_nr_inst; 
  uint32_t                        gnb_id_start = 0;
  uint32_t                        gnb_id_end = gnb_id_start + gnb_nb;
266
  LOG_D(GNB_APP, "%s(gnb_nb:%d)\n", __FUNCTION__, gnb_nb);
laurent's avatar
laurent committed
267
  itti_wait_ready(1);
268
  LOG_D(PHY, "%s() Task ready initialize structures\n", __FUNCTION__);
269

270 271 272 273
#ifdef ENABLE_AERIAL
  AssertFatal(NFAPI_MODE == NFAPI_MODE_AERIAL,"Can only be run with '--nfapi AERIAL' when compiled with AERIAL support, if you want to run other (n)FAPI modes, please run ./build_oai without -w AERIAL");
#endif

274
  RCconfig_verify(cfg, node_type);
275

276 277 278
  if(NFAPI_MODE != NFAPI_MODE_AERIAL){
    RCconfig_nr_prs();
  }
279

280 281
  if (RC.nb_nr_macrlc_inst > 0)
    RCconfig_nr_macrlc(cfg);
282

283
  LOG_D(PHY, "%s() RC.nb_nr_L1_inst:%d\n", __FUNCTION__, RC.nb_nr_L1_inst);
284 285 286 287 288 289 290

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

  AssertFatal (gnb_nb <= RC.nb_nr_inst,
               "Number of gNB is greater than gNB defined in configuration file (%d/%d)!",
               gnb_nb, RC.nb_nr_inst);

291
  LOG_D(GNB_APP, "Allocating gNB_RRC_INST for %d instances\n", RC.nb_nr_inst);
292

293 294 295 296 297
  if (RC.nb_nr_inst > 0) {
    AssertFatal(RC.nb_nr_inst == 1, "multiple RRC instances are not supported\n");
    RC.nrrrc = calloc(1, sizeof(*RC.nrrrc));
    RC.nrrrc[0] = calloc(1,sizeof(gNB_RRC_INST));
    RCconfig_NRRRC(RC.nrrrc[0]);
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
  }

  if (RC.nb_nr_inst > 0 &&
      !get_softmodem_params()->nsa &&
      !(node_type == ngran_gNB_DU))  {
    // we start pdcp in both cuup (for drb) and cucp (for srb)
    init_pdcp();
  }

  if (is_x2ap_enabled() ) { //&& !NODE_IS_DU(node_type)
	  LOG_I(X2AP, "X2AP enabled \n");
	  __attribute__((unused)) uint32_t x2_register_gnb_pending = gNB_app_register_x2 (gnb_id_start, gnb_id_end);
  }

  /* For the CU case the gNB registration with the AMF might have to take place after the F1 setup, as the PLMN info
     * can originate from the DU. Add check on whether x2ap is enabled to account for ENDC NSA scenario.*/
  if ((get_softmodem_params()->sa || is_x2ap_enabled()) &&
      !NODE_IS_DU(node_type)) {
    /* Try to register each gNB */
    //registered_gnb = 0;
    __attribute__((unused)) uint32_t register_gnb_pending = gNB_app_register (gnb_id_start, gnb_id_end);
  }
laurent's avatar
laurent committed
320 321

  if (gnb_nb > 0) {
322
    if(itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0) {
zhenghuangkun's avatar
zhenghuangkun committed
323 324
      LOG_E(SCTP, "Create task for SCTP failed\n");
      return -1;
325
    }
326

327
    if (is_x2ap_enabled()) {
328 329 330 331
      if(itti_create_task(TASK_X2AP, x2ap_task, NULL) < 0) {
        LOG_E(X2AP, "Create task for X2AP failed\n");
      }
    } else {
zhenghuangkun's avatar
zhenghuangkun committed
332
      LOG_I(X2AP, "X2AP is disabled.\n");
333
    }
laurent's avatar
laurent committed
334
  }
335

336 337
  if (get_softmodem_params()->sa &&
      !NODE_IS_DU(node_type)) {
338

339 340 341 342
    char*             gnb_ipv4_address_for_NGU      = NULL;
    uint32_t          gnb_port_for_NGU              = 0;
    char*             gnb_ipv4_address_for_S1U      = NULL;
    uint32_t          gnb_port_for_S1U              = 0;
343 344 345
    paramdef_t NETParams[]  =  GNBNETPARAMS_DESC;
    char aprefix[MAX_OPTNAME_SIZE*2 + 8];
    sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
346 347
    config_get(cfg, NETParams, sizeofArray(NETParams), aprefix);

348
    if (gnb_nb > 0) {
349 350 351
      if (itti_create_task (TASK_NGAP, ngap_gNB_task, NULL) < 0) {
        LOG_E(NGAP, "Create task for NGAP failed\n");
        return -1;
zhenghuangkun's avatar
zhenghuangkun committed
352
      }
353
    }
354
  }
355

laurent's avatar
laurent committed
356
  if (gnb_nb > 0) {
357
    if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) {
zhenghuangkun's avatar
zhenghuangkun committed
358 359 360
      LOG_E(GNB_APP, "Create task for gNB APP failed\n");
      return -1;
    }
361

362 363 364 365 366
    if (!NODE_IS_DU(node_type)) {
      if (itti_create_task (TASK_RRC_GNB, rrc_gnb_task, NULL) < 0) {
        LOG_E(NR_RRC, "Create task for NR RRC gNB failed\n");
        return -1;
      }
367
    }
368

369
    // E1AP initialisation, whether the node is a CU or has integrated CU
370
    if (node_type == ngran_gNB_CU || node_type == ngran_gNB) {
371
      MessageDef *msg = RCconfig_NR_CU_E1(NULL);
372
      instance_t inst = 0;
373
      createE1inst(UPtype, inst, E1AP_REGISTER_REQ(msg).gnb_id, &E1AP_REGISTER_REQ(msg).net_config, NULL);
374 375
      cuup_init_n3(inst);
      RC.nrrrc[gnb_id_start]->e1_inst = inst; // stupid instance !!!*/
376 377 378 379

      /* send E1 Setup Request to RRC */
      MessageDef *new_msg = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_SETUP_REQ);
      E1AP_SETUP_REQ(new_msg) = E1AP_REGISTER_REQ(msg).setup_req;
380
      new_msg->ittiMsgHeader.originInstance = -1; /* meaning, it is local */
381 382
      itti_send_msg_to_task(TASK_RRC_GNB, 0 /*unused by callee*/, new_msg);
      itti_free(TASK_UNKNOWN, msg);
383 384 385 386
    }

    //Use check on x2ap to consider the NSA scenario 
    if((is_x2ap_enabled() || get_softmodem_params()->sa) && (node_type != ngran_gNB_CUCP)) {
Laurent THOMAS's avatar
Laurent THOMAS committed
387
      if (itti_create_task (TASK_GTPV1_U, &gtpv1uTask, NULL) < 0) {
388 389 390
        LOG_E(GTPU, "Create task for GTPV1U failed\n");
        return -1;
      }
391
    }
Xue Song's avatar
Xue Song committed
392
  }
laurent's avatar
laurent committed
393 394 395 396

  return 0;
}

397 398
static void get_options(configmodule_interface_t *cfg)
{
399
  paramdef_t cmdline_params[] = CMDLINE_PARAMS_DESC_GNB ;
400
  CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
401 402
  get_common_options(cfg, SOFTMODEM_GNB_BIT);
  config_process_cmdline(cfg, cmdline_params, sizeofArray(cmdline_params), NULL);
403 404
  CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP);

laurent's avatar
laurent committed
405 406 407 408 409 410 411 412 413
  if ( !(CONFIG_ISFLAGSET(CONFIG_ABORT)) ) {
    memset((void *)&RC,0,sizeof(RC));
    /* Read RC configuration file */
    NRRCConfig();
    NB_gNB_INST = RC.nb_nr_inst;
    NB_RU   = RC.nb_RU;
  }
}

414
void set_default_frame_parms(nfapi_nr_config_request_scf_t *config[MAX_NUM_CCs],
415
                             NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
416
  for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
laurent's avatar
laurent committed
417
    frame_parms[CC_id] = (NR_DL_FRAME_PARMS *) malloc(sizeof(NR_DL_FRAME_PARMS));
418 419 420 421 422 423 424
    config[CC_id] = (nfapi_nr_config_request_scf_t *) malloc(sizeof(nfapi_nr_config_request_scf_t));
    config[CC_id]->ssb_config.scs_common.value = 1;
    config[CC_id]->cell_config.frame_duplex_type.value = 1; //FDD
    //config[CC_id]->subframe_config.dl_cyclic_prefix_type.value = 0; //NORMAL
    config[CC_id]->carrier_config.dl_grid_size[1].value = 106;
    config[CC_id]->carrier_config.ul_grid_size[1].value = 106;
    config[CC_id]->cell_config.phy_cell_id.value = 0;
laurent's avatar
laurent committed
425 426 427 428 429 430 431 432 433 434 435
    ///dl frequency to be filled in
    /*  //Set some default values that may be overwritten while reading options
        frame_parms[CC_id]->frame_type          = FDD;
        frame_parms[CC_id]->tdd_config          = 3;
        frame_parms[CC_id]->tdd_config_S        = 0;
        frame_parms[CC_id]->N_RB_DL             = 100;
        frame_parms[CC_id]->N_RB_UL             = 100;
        frame_parms[CC_id]->Ncp                 = NORMAL;
        frame_parms[CC_id]->Ncp_UL              = NORMAL;
        frame_parms[CC_id]->Nid_cell            = 0;
        frame_parms[CC_id]->num_MBSFN_config    = 0;
436
        frame_parms[CC_id]->nb_antenna_ports_gNB  = 1;
laurent's avatar
laurent committed
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
        frame_parms[CC_id]->nb_antennas_tx      = 1;
        frame_parms[CC_id]->nb_antennas_rx      = 1;

        frame_parms[CC_id]->nushift             = 0;

        frame_parms[CC_id]->phich_config_common.phich_resource = oneSixth;
        frame_parms[CC_id]->phich_config_common.phich_duration = normal;
        // UL RS Config
        frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.cyclicShift = 0;//n_DMRS1 set to 0
        frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupHoppingEnabled = 0;
        frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.sequenceHoppingEnabled = 0;
        frame_parms[CC_id]->pusch_config_common.ul_ReferenceSignalsPUSCH.groupAssignmentPUSCH = 0;

        frame_parms[CC_id]->prach_config_common.rootSequenceIndex=22;
        frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig=1;
        frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_ConfigIndex=0;
        frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.highSpeedFlag=0;
        frame_parms[CC_id]->prach_config_common.prach_ConfigInfo.prach_FreqOffset=0;

    //    downlink_frequency[CC_id][0] = 2680000000; // Use float to avoid issue with frequency over 2^31.
    //    downlink_frequency[CC_id][1] = downlink_frequency[CC_id][0];
    //    downlink_frequency[CC_id][2] = downlink_frequency[CC_id][0];
    //    downlink_frequency[CC_id][3] = downlink_frequency[CC_id][0];
        frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0];
    */
  }
}

void wait_RUs(void) {
466
  LOG_D(PHY, "Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask);
laurent's avatar
laurent committed
467 468 469 470 471 472 473 474
  // wait for all RUs to be configured over fronthaul
  pthread_mutex_lock(&RC.ru_mutex);

  while (RC.ru_mask>0) {
    pthread_cond_wait(&RC.ru_cond,&RC.ru_mutex);
  }

  pthread_mutex_unlock(&RC.ru_mutex);
475
  LOG_D(PHY, "RUs configured\n");
laurent's avatar
laurent committed
476 477 478
}

void wait_gNBs(void) {
Francesco Mani's avatar
Francesco Mani committed
479
  int i;
laurent's avatar
laurent committed
480 481 482
  int waiting=1;

  while (waiting==1) {
483
    LOG_D(GNB_APP, "Waiting for gNB L1 instances to all get configured ... sleeping 50ms (nb_nr_sL1_inst %d)\n", RC.nb_nr_L1_inst);
laurent's avatar
laurent committed
484 485 486 487
    usleep(50*1000);
    waiting=0;

    for (i=0; i<RC.nb_nr_L1_inst; i++) {
488
      if (RC.gNB[i]->configured==0) {
489 490
        waiting=1;
        break;
laurent's avatar
laurent committed
491 492 493 494
      }
    }
  }

495
  LOG_D(GNB_APP, "gNB L1 are configured\n");
laurent's avatar
laurent committed
496 497 498 499 500 501
}

/*
 * helper function to terminate a certain ITTI task
 */
void terminate_task(task_id_t task_id, module_id_t mod_id) {
502
  LOG_I(GNB_APP, "sending TERMINATE_MESSAGE to task %s (%d)\n", itti_get_task_name(task_id), task_id);
laurent's avatar
laurent committed
503
  MessageDef *msg;
504
  msg = itti_alloc_new_message (TASK_ENB_APP, 0, TERMINATE_MESSAGE);
laurent's avatar
laurent committed
505 506 507 508 509 510
  itti_send_msg_to_task (task_id, ENB_MODULE_ID_TO_INSTANCE(mod_id), msg);
}

//extern void  free_transport(PHY_VARS_gNB *);
extern void  nr_phy_free_RU(RU_t *);

511 512
static  void wait_nfapi_init(char *thread_name)
{
laurent's avatar
laurent committed
513 514 515 516 517 518 519 520
  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);
}

521
void init_pdcp(void) {
522 523
  uint32_t pdcp_initmask = IS_SOFTMODEM_NOS1 ? ENB_NAS_USE_TUN_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT;

524
  if (!NODE_IS_DU(get_node_type())) {
525
    nr_pdcp_layer_init();
526
    nr_pdcp_module_init(pdcp_initmask, 0);
Xue Song's avatar
Xue Song committed
527
  }
528
}
529

530
#ifdef E2_AGENT
531
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" // need to get info from MAC
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args)
{
  AssertFatal(oai_args.sm_dir != NULL , "Please, specify the directory where the SMs are located in the config file, i.e., add in config file the next line: e2_agent = {near_ric_ip_addr = \"127.0.0.1\"; sm_dir = \"/usr/local/lib/flexric/\");} ");
  AssertFatal(oai_args.ip != NULL , "Please, specify the IP address of the nearRT-RIC in the config file, i.e., e2_agent = {near_ric_ip_addr = \"127.0.0.1\"; sm_dir = \"/usr/local/lib/flexric/\"");

  printf("After RCconfig_NR_E2agent %s %s \n",oai_args.sm_dir, oai_args.ip  );

  fr_args_t args = { .ip = oai_args.ip }; // init_fr_args(0, NULL);
  memcpy(args.libs_dir, oai_args.sm_dir, 128);

  sleep(1);
  const gNB_RRC_INST* rrc = RC.nrrrc[0];
  assert(rrc != NULL && "rrc cannot be NULL");

  const int mcc = rrc->configuration.mcc[0];
  const int mnc = rrc->configuration.mnc[0];
  const int mnc_digit_len = rrc->configuration.mnc_digit_length[0];
  // const ngran_node_t node_type = rrc->node_type;
  int nb_id = 0;
  int cu_du_id = 0;
  if (node_type == ngran_gNB) {
553
    nb_id = rrc->node_id;
554
  } else if (node_type == ngran_gNB_DU) {
555
    const gNB_MAC_INST* mac = RC.nrmac[0];
francescomani's avatar
francescomani committed
556
    AssertFatal(mac, "MAC not initialized\n");
557 558
    cu_du_id = mac->f1_config.gnb_id;
    nb_id = mac->f1_config.setup_req->gNB_DU_id;
Teodora's avatar
Teodora committed
559
  } else if (node_type == ngran_gNB_CU || node_type == ngran_gNB_CUCP) {
560 561 562
    // agent buggy: the CU has no second ID, it is the CU-UP ID
    // however, that is not a problem her for us, so put the same ID twice
    nb_id = rrc->node_id;
563 564 565 566 567 568 569 570 571 572 573 574 575 576
    cu_du_id = rrc->node_id;
  } else {
    LOG_E(NR_RRC, "not supported ran type detect\n");
  }

  printf("[E2 NODE]: mcc = %d mnc = %d mnc_digit = %d nb_id = %d \n", mcc, mnc, mnc_digit_len, nb_id);

  printf("[E2 NODE]: Args %s %s \n", args.ip, args.libs_dir);

  sm_io_ag_ran_t io = init_ran_func_ag();
  init_agent_api(mcc, mnc, mnc_digit_len, nb_id, cu_du_id, node_type, io, &args);
}
#endif

577
void init_eNB_afterRU(void);
578
configmodule_interface_t *uniqCfg = NULL;
579
int main( int argc, char **argv ) {
Francesco Mani's avatar
Francesco Mani committed
580
  int ru_id, CC_id = 0;
laurent's avatar
laurent committed
581 582 583
  start_background_system();

  ///static configuration for NR at the moment
584
  if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == NULL) {
laurent's avatar
laurent committed
585 586
    exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
  }
587

588
  set_softmodem_sighandler();
laurent's avatar
laurent committed
589 590 591 592 593 594 595
#ifdef DEBUG_CONSOLE
  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);
#endif
  mode = normal_txrx;
  memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs);
  logInit();
596
  lock_memory_to_ram();
597
  get_options(uniqCfg);
laurent's avatar
laurent committed
598

599 600
  EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1;

laurent's avatar
laurent committed
601 602 603 604 605
  if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) {
    fprintf(stderr,"Getting configuration failed\n");
    exit(-1);
  }

606 607 608 609
  if (!has_cap_sys_nice())
    LOG_W(UTIL,
          "no SYS_NICE capability: cannot set thread priority and affinity, consider running with sudo for optimum performance\n");

610 611
  if (get_softmodem_params()->do_ra)
    AssertFatal(get_softmodem_params()->phy_test == 0,"RA and phy_test are mutually exclusive\n");
612

613 614 615
  if (get_softmodem_params()->sa)
    AssertFatal(get_softmodem_params()->phy_test == 0,"Standalone mode and phy_test are mutually exclusive\n");

laurent's avatar
laurent committed
616 617 618 619 620 621 622
#if T_TRACER
  T_Config_Init();
#endif
  //randominit (0);
  set_taus_seed (0);

  cpuf=get_cpu_freq_GHz();
Laurent Thomas's avatar
Laurent Thomas committed
623
  itti_init(TASK_MAX, tasks_info);
laurent's avatar
laurent committed
624
  // initialize mscgen log after ITTI
laurent's avatar
laurent committed
625
  init_opt();
626

627
  // strdup to put the sring in the core file for post mortem identification
628
  char *pckg = strdup(OAI_PACKAGE_VERSION);
629
  LOG_I(HW, "Version: %s\n", pckg);
630

631
  // don't create if node doesn't connect to RRC/S1/GTP
632
  const ngran_node_t node_type = get_node_type();
633

634 635 636 637
  if (RC.nb_nr_L1_inst > 0) {
    // Initialize gNB structure in RAN context
    init_gNB(wait_for_sync);
    // Initialize L1
638
    RCconfig_NR_L1();
639
  }
640

641
  if (NFAPI_MODE != NFAPI_MODE_PNF) {
642
    int ret = create_gNB_tasks(node_type, uniqCfg);
643 644
    AssertFatal(ret == 0, "cannot create ITTI tasks\n");
  }
645

laurent's avatar
laurent committed
646 647
  pthread_cond_init(&sync_cond,NULL);
  pthread_mutex_init(&sync_mutex, NULL);
648
  usleep(1000);
laurent's avatar
laurent committed
649

650
  if (NFAPI_MODE && NFAPI_MODE != NFAPI_MODE_AERIAL) {
laurent's avatar
laurent committed
651 652 653 654 655 656 657 658
    pthread_cond_init(&sync_cond,NULL);
    pthread_mutex_init(&sync_mutex, NULL);
  }

  // start the main threads
  number_of_cards = 1;

  wait_gNBs();
659
  int sl_ahead = NFAPI_MODE == NFAPI_MODE_AERIAL ? 0 : 6;
laurent's avatar
laurent committed
660
  if (RC.nb_RU >0) {
661
    init_NR_RU(uniqCfg, get_softmodem_params()->rf_config_file);
laurent's avatar
laurent committed
662 663 664 665

    for (ru_id=0; ru_id<RC.nb_RU; ru_id++) {
      RC.ru[ru_id]->rf_map.card=0;
      RC.ru[ru_id]->rf_map.chain=CC_id+chain_offset;
666
      if (ru_id==0) sl_ahead = RC.ru[ru_id]->sl_ahead;	
667
      else AssertFatal(RC.ru[ru_id]->sl_ahead != RC.ru[0]->sl_ahead,"RU %d has different sl_ahead %d than RU 0 %d\n",ru_id,RC.ru[ru_id]->sl_ahead,RC.ru[0]->sl_ahead);
laurent's avatar
laurent committed
668
    }
669
    
laurent's avatar
laurent committed
670 671 672 673
  }

  config_sync_var=0;

674 675 676 677 678 679

#ifdef E2_AGENT

//////////////////////////////////
//////////////////////////////////
//// Init the E2 Agent
680

681 682
  // OAI Wrapper 
  e2_agent_args_t oai_args = RCconfig_NR_E2agent();
683

684 685
  if (oai_args.enabled) {
    initialize_agent(node_type, oai_args);
686 687 688 689 690
  }

#endif // E2_AGENT


Mahesh's avatar
Mahesh committed
691
  if (NFAPI_MODE==NFAPI_MODE_PNF) {
laurent's avatar
laurent committed
692 693 694
    wait_nfapi_init("main?");
  }

695 696 697 698 699 700
  // wait for F1 Setup Response before starting L1 for real
  if (NODE_IS_DU(node_type) || NODE_IS_MONOLITHIC(node_type))
    wait_f1_setup_response();

  if (RC.nb_RU > 0)
    start_NR_RU();
701
#ifdef ENABLE_AERIAL
702 703
  gNB_MAC_INST *nrmac = RC.nrmac[0];
  nvIPC_Init(nrmac->nvipc_params_s);
704
#endif
705
  if (RC.nb_nr_L1_inst > 0) {
Xue Song's avatar
Xue Song committed
706 707
    wait_RUs();
    // once all RUs are ready initialize the rest of the gNBs ((dependence on final RU parameters after configuration)
708

709
    for (int idx=0;idx<RC.nb_nr_L1_inst;idx++) RC.gNB[idx]->if_inst->sl_ahead = sl_ahead;
710
    if (IS_SOFTMODEM_DOSCOPE || IS_SOFTMODEM_IMSCOPE_ENABLED) {
711
      sleep(1);
Xue Song's avatar
Xue Song committed
712
      scopeParms_t p;
Bartosz Podrygajlo's avatar
Bartosz Podrygajlo committed
713 714 715 716
      p.argc = &argc;
      p.argv = argv;
      p.gNB = RC.gNB[0];
      p.ru = RC.ru[0];
717 718 719 720 721 722
      if (IS_SOFTMODEM_DOSCOPE) {
        load_softscope("nr", &p);
      }
      if (IS_SOFTMODEM_IMSCOPE_ENABLED) {
        load_softscope("im", &p);
      }
Xue Song's avatar
Xue Song committed
723
    }
724

725
    if (NFAPI_MODE != NFAPI_MODE_PNF && NFAPI_MODE != NFAPI_MODE_VNF && NFAPI_MODE != NFAPI_MODE_AERIAL) {
726 727
      init_eNB_afterRU();
    }
728

Xue Song's avatar
Xue Song committed
729 730 731 732 733 734
    // connect the TX/RX buffers
    pthread_mutex_lock(&sync_mutex);
    sync_var=0;
    pthread_cond_broadcast(&sync_cond);
    pthread_mutex_unlock(&sync_mutex);
  }
735

laurent's avatar
laurent committed
736
  // wait for end of program
737
  printf("TYPE <CTRL-C> TO TERMINATE\n");
738
  itti_wait_tasks_end(NULL);
laurent's avatar
laurent committed
739 740
  printf("Returned from ITTI signal handler\n");
  oai_exit=1;
741

laurent's avatar
laurent committed
742
  // cleanup
743 744
  if (RC.nb_nr_L1_inst > 0)
    stop_gNB(RC.nb_nr_L1_inst);
Xue Song's avatar
Xue Song committed
745

746 747
  if (RC.nb_RU > 0)
    stop_RU(RC.nb_RU);
laurent's avatar
laurent committed
748 749 750

  /* release memory used by the RU/gNB threads (incomplete), after all
   * threads have been stopped (they partially use the same memory) */
751
  for (int inst = 0; inst < RC.nb_RU; inst++) {
laurent's avatar
laurent committed
752 753 754
    nr_phy_free_RU(RC.ru[inst]);
  }

755
  for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
756 757 758
    phy_free_nr_gNB(RC.gNB[inst]);
  }

laurent's avatar
laurent committed
759 760 761 762 763 764 765
  pthread_cond_destroy(&sync_cond);
  pthread_mutex_destroy(&sync_mutex);
  pthread_cond_destroy(&nfapi_sync_cond);
  pthread_mutex_destroy(&nfapi_sync_mutex);

  // *** Handle per CC_id openair0

766
  for(ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
laurent's avatar
laurent committed
767 768 769 770
    if (RC.ru[ru_id]->ifdevice.trx_end_func)
      RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
  }

771
  free(pckg);
laurent's avatar
laurent committed
772 773 774 775
  logClean();
  printf("Bye.\n");
  return 0;
}