nr-softmodem.c 26.7 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 31 32 33 34 35
/*
 * 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>

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

#include "PHY/defs_gNB.h"
36
#include "PHY/defs_common.h"
laurent's avatar
laurent committed
37 38 39 40 41
#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
42
#include "radio/COMMON/common_lib.h"
43
#include "radio/ETHERNET/if_defs.h"
laurent's avatar
laurent committed
44 45 46 47 48 49 50

//#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"
51
#include "SIMULATION/TOOLS/sim.h"
52
#include "executables/lte-softmodem.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"
laurent's avatar
laurent committed
83

84 85 86 87 88 89
#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
90 91 92 93
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
94
extern uint8_t nfapi_mode; // Default to monolithic mode
95
THREAD_STRUCT thread_struct;
laurent's avatar
laurent committed
96 97 98 99 100
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;

101
volatile int             start_gNB = 0;
102
int oai_exit = 0;
laurent's avatar
laurent committed
103

laurent's avatar
laurent committed
104 105
int NB_UE_INST = 0;

laurent's avatar
laurent committed
106 107
static int wait_for_sync = 0;

108 109
unsigned int mmapped_dma=0;
int single_thread_flag=1;
laurent's avatar
laurent committed
110

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

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

runmode_t mode = normal_txrx;

#if MAX_NUM_CCs == 1
121
rx_gain_t rx_gain_mode[MAX_NUM_CCs][4] = {{max_gain,max_gain,max_gain,max_gain}};
laurent's avatar
laurent committed
122 123 124
double tx_gain[MAX_NUM_CCs][4] = {{20,0,0,0}};
double rx_gain[MAX_NUM_CCs][4] = {{110,0,0,0}};
#else
125
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
126 127 128 129 130 131
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;

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


int chain_offset=0;
136

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

141 142 143
int rx_input_level_dBm;

int otg_enabled;
laurent's avatar
laurent committed
144 145 146

uint64_t num_missed_slots=0; // counter for the number of missed slots

rmagueta's avatar
rmagueta committed
147 148
#include <SIMULATION/ETH_TRANSPORT/proto.h>

laurent's avatar
laurent committed
149 150 151
extern void reset_opp_meas(void);
extern void print_opp_meas(void);

152
extern void *udp_eNB_task(void *args_p);
laurent's avatar
laurent committed
153 154 155 156 157

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

158

159 160
static char *parallel_config = NULL;
static char *worker_config = NULL;
laurent's avatar
laurent committed
161 162 163 164 165 166

/* struct for ethernet specific parameters given in eNB conf file */
eth_params_t *eth_params;

double cpuf;

167 168 169 170 171 172
/* 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
173 174 175 176 177 178 179

/* see file openair2/LAYER2/MAC/main.c for why abstraction_flag is needed
 * this is very hackish - find a proper solution
 */
uint8_t abstraction_flag=0;

/* forward declarations */
180
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
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 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

/*---------------------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;
}

void print_difftimes(void) {
#ifdef DEBUG
  printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
#else
  LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
#endif
}

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

240

laurent's avatar
laurent committed
241 242 243 244 245 246
#define KNRM  "\x1B[0m"
#define KRED  "\x1B[31m"
#define KGRN  "\x1B[32m"
#define KBLU  "\x1B[34m"
#define RESET "\033[0m"

247 248
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
laurent's avatar
laurent committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
  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;
    }
  }

272 273 274
  if (assert) {
    abort();
  } else {
275
    sleep(1); // allow nr-softmodem threads to exit first
276 277
    exit(EXIT_SUCCESS);
  }
laurent's avatar
laurent committed
278 279
}

280
static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cfg)
281
{
282 283 284
  uint32_t                        gnb_nb = RC.nb_nr_inst; 
  uint32_t                        gnb_id_start = 0;
  uint32_t                        gnb_id_end = gnb_id_start + gnb_nb;
285
  LOG_D(GNB_APP, "%s(gnb_nb:%d)\n", __FUNCTION__, gnb_nb);
laurent's avatar
laurent committed
286
  itti_wait_ready(1);
287 288
  LOG_I(PHY, "%s() Task ready initialize structures\n", __FUNCTION__);

289
  RCconfig_verify(cfg, node_type);
290

291 292
  RCconfig_nr_prs();

293 294
  if (RC.nb_nr_macrlc_inst > 0)
    RCconfig_nr_macrlc(cfg);
295 296 297 298 299 300 301 302 303 304 305

  LOG_I(PHY, "%s() RC.nb_nr_L1_inst:%d\n", __FUNCTION__, RC.nb_nr_L1_inst);

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

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

306 307 308 309 310
  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]);
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
  }

  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
333 334

  if (gnb_nb > 0) {
335
    if(itti_create_task(TASK_SCTP, sctp_eNB_task, NULL) < 0) {
zhenghuangkun's avatar
zhenghuangkun committed
336 337
      LOG_E(SCTP, "Create task for SCTP failed\n");
      return -1;
338
    }
339

340
    if (is_x2ap_enabled()) {
341 342 343 344
      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
345
      LOG_I(X2AP, "X2AP is disabled.\n");
346
    }
laurent's avatar
laurent committed
347
  }
348

349 350
  if (get_softmodem_params()->sa &&
      !NODE_IS_DU(node_type)) {
351

352 353 354 355
    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;
356 357 358
    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);
359 360
    config_get(cfg, NETParams, sizeofArray(NETParams), aprefix);

361 362
    for(int i = GNB_INTERFACE_NAME_FOR_NG_AMF_IDX; i <= GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX; i++) {
      if( NETParams[i].strptr == NULL) {
363 364
        LOG_E(NGAP, "No AMF configuration in the file.\n");
        exit(1);
365
      } else {
366
        LOG_D(NGAP, "Configuration in the file: %s.\n",*NETParams[i].strptr);
367
      }
368
    }
369
    
370
    if (gnb_nb > 0) {
371 372 373
      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
374
      }
375
    }
376
  }
377

laurent's avatar
laurent committed
378
  if (gnb_nb > 0) {
379
    if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) {
zhenghuangkun's avatar
zhenghuangkun committed
380 381 382
      LOG_E(GNB_APP, "Create task for gNB APP failed\n");
      return -1;
    }
383

384 385 386 387 388
    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;
      }
389
    }
390

391
    // E1AP initialisation, whether the node is a CU or has integrated CU
392
    if (node_type == ngran_gNB_CU || node_type == ngran_gNB) {
393
      MessageDef *msg = RCconfig_NR_CU_E1(NULL);
394
      instance_t inst = 0;
395
      createE1inst(UPtype, inst, E1AP_REGISTER_REQ(msg).gnb_id, &E1AP_REGISTER_REQ(msg).net_config, NULL);
396 397
      cuup_init_n3(inst);
      RC.nrrrc[gnb_id_start]->e1_inst = inst; // stupid instance !!!*/
398 399 400 401

      /* 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;
402
      new_msg->ittiMsgHeader.originInstance = -1; /* meaning, it is local */
403 404
      itti_send_msg_to_task(TASK_RRC_GNB, 0 /*unused by callee*/, new_msg);
      itti_free(TASK_UNKNOWN, msg);
405 406 407 408
    }

    //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
409
      if (itti_create_task (TASK_GTPV1_U, &gtpv1uTask, NULL) < 0) {
410 411 412
        LOG_E(GTPU, "Create task for GTPV1U failed\n");
        return -1;
      }
413
    }
Xue Song's avatar
Xue Song committed
414
  }
laurent's avatar
laurent committed
415 416 417 418

  return 0;
}

419 420
static void get_options(configmodule_interface_t *cfg)
{
421
  paramdef_t cmdline_params[] = CMDLINE_PARAMS_DESC_GNB ;
422
  CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
423 424
  get_common_options(cfg, SOFTMODEM_GNB_BIT);
  config_process_cmdline(cfg, cmdline_params, sizeofArray(cmdline_params), NULL);
425 426
  CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP);

laurent's avatar
laurent committed
427 428 429 430 431 432
  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;
433
    printf("Configuration: nb_rrc_inst %d, nb_nr_L1_inst %d, nb_ru %hhu\n",NB_gNB_INST,RC.nb_nr_L1_inst,NB_RU);
laurent's avatar
laurent committed
434 435 436 437
  }

  if(parallel_config != NULL) set_parallel_conf(parallel_config);

438
  if(worker_config != NULL) set_worker_conf(worker_config);
laurent's avatar
laurent committed
439 440
}

441
void set_default_frame_parms(nfapi_nr_config_request_scf_t *config[MAX_NUM_CCs],
442
                             NR_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) {
443
  for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
laurent's avatar
laurent committed
444
    frame_parms[CC_id] = (NR_DL_FRAME_PARMS *) malloc(sizeof(NR_DL_FRAME_PARMS));
445 446 447 448 449 450 451
    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
452 453 454 455 456 457 458 459 460 461 462
    ///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;
463
        frame_parms[CC_id]->nb_antenna_ports_gNB  = 1;
laurent's avatar
laurent committed
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
        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];
        //printf("Downlink for CC_id %d frequency set to %u\n", CC_id, downlink_frequency[CC_id][0]);
        frame_parms[CC_id]->dl_CarrierFreq=downlink_frequency[CC_id][0];
    */
  }
}

void wait_RUs(void) {
  LOG_I(PHY,"Waiting for RUs to be configured ... RC.ru_mask:%02lx\n", RC.ru_mask);
  // 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);
    printf("RC.ru_mask:%02lx\n", RC.ru_mask);
  }

  pthread_mutex_unlock(&RC.ru_mutex);
  LOG_I(PHY,"RUs configured\n");
}

void wait_gNBs(void) {
Francesco Mani's avatar
Francesco Mani committed
508
  int i;
laurent's avatar
laurent committed
509 510 511 512 513 514 515 516
  int waiting=1;

  while (waiting==1) {
    printf("Waiting for gNB L1 instances to all get configured ... sleeping 50ms (nb_nr_sL1_inst %d)\n",RC.nb_nr_L1_inst);
    usleep(50*1000);
    waiting=0;

    for (i=0; i<RC.nb_nr_L1_inst; i++) {
517
      if (RC.gNB[i]->configured==0) {
518 519
        waiting=1;
        break;
laurent's avatar
laurent committed
520 521 522 523 524 525 526 527 528 529 530
      }
    }
  }

  printf("gNB L1 are configured\n");
}

/*
 * helper function to terminate a certain ITTI task
 */
void terminate_task(task_id_t task_id, module_id_t mod_id) {
531
  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
532
  MessageDef *msg;
533
  msg = itti_alloc_new_message (TASK_ENB_APP, 0, TERMINATE_MESSAGE);
laurent's avatar
laurent committed
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
  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 *);

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

551
void init_pdcp(void) {
552 553 554 555
  uint32_t pdcp_initmask = (IS_SOFTMODEM_NOS1) ?
    PDCP_USE_NETLINK_BIT | LINK_ENB_PDCP_TO_IP_DRIVER_BIT | ENB_NAS_USE_TUN_BIT | SOFTMODEM_NOKRNMOD_BIT:
    LINK_ENB_PDCP_TO_GTPV1U_BIT;
  
556
  if (!NODE_IS_DU(get_node_type())) {
557
    nr_pdcp_layer_init(get_node_type() == ngran_gNB_CUCP);
558
    nr_pdcp_module_init(pdcp_initmask, 0);
Xue Song's avatar
Xue Song committed
559
  }
560
}
561

562
#ifdef E2_AGENT
563
#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" // need to get info from MAC
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
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) {
585
    nb_id = rrc->node_id;
586
  } else if (node_type == ngran_gNB_DU) {
587 588 589 590
    const gNB_MAC_INST* mac = RC.nrmac[0];
    AssertFatal(mac != NULL, "MAC not initialized\n");
    cu_du_id = mac->f1_config.gnb_id;
    nb_id = mac->f1_config.setup_req->gNB_DU_id;
Teodora's avatar
Teodora committed
591
  } else if (node_type == ngran_gNB_CU || node_type == ngran_gNB_CUCP) {
592 593 594
    // 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;
595 596 597 598 599 600 601 602 603 604 605 606 607 608
    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

609
configmodule_interface_t *uniqCfg = NULL;
610
int main( int argc, char **argv ) {
Francesco Mani's avatar
Francesco Mani committed
611
  int ru_id, CC_id = 0;
laurent's avatar
laurent committed
612 613 614
  start_background_system();

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

619
  set_softmodem_sighandler();
laurent's avatar
laurent committed
620 621 622 623 624 625 626
#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();
627
  set_latency_target();
laurent's avatar
laurent committed
628
  printf("Reading in command-line options\n");
629
  get_options(uniqCfg);
laurent's avatar
laurent committed
630

631 632
  EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1;

laurent's avatar
laurent committed
633 634 635 636 637
  if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) {
    fprintf(stderr,"Getting configuration failed\n");
    exit(-1);
  }

638 639
  if (get_softmodem_params()->do_ra)
    AssertFatal(get_softmodem_params()->phy_test == 0,"RA and phy_test are mutually exclusive\n");
640

641 642 643
  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
644 645 646 647 648 649 650 651 652 653 654 655
#if T_TRACER
  T_Config_Init();
#endif
  //randominit (0);
  set_taus_seed (0);
  printf("configuring for RAU/RRU\n");

  if (opp_enabled ==1) {
    reset_opp_meas();
  }

  cpuf=get_cpu_freq_GHz();
Laurent Thomas's avatar
Laurent Thomas committed
656
  itti_init(TASK_MAX, tasks_info);
laurent's avatar
laurent committed
657
  // initialize mscgen log after ITTI
laurent's avatar
laurent committed
658
  init_opt();
659
  if(PDCP_USE_NETLINK && !IS_SOFTMODEM_NOS1) {
Melissa Elkadi's avatar
Melissa Elkadi committed
660
    netlink_init();
661 662 663
    if (get_softmodem_params()->nsa) {
      init_pdcp();
    }
Melissa Elkadi's avatar
Melissa Elkadi committed
664
  }
laurent's avatar
laurent committed
665 666 667 668
#ifndef PACKAGE_VERSION
#  define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL"
#endif
  LOG_I(HW, "Version: %s\n", PACKAGE_VERSION);
Cedric Roux's avatar
Cedric Roux committed
669

670

671
  // don't create if node doesn't connect to RRC/S1/GTP
672
  const ngran_node_t node_type = get_node_type();
673 674 675 676

  if (RC.nb_nr_L1_inst > 0)
    RCconfig_NR_L1();

677
  if (NFAPI_MODE != NFAPI_MODE_PNF) {
678
    int ret = create_gNB_tasks(node_type, uniqCfg);
679 680
    AssertFatal(ret == 0, "cannot create ITTI tasks\n");
  }
681

laurent's avatar
laurent committed
682 683 684
  mlockall(MCL_CURRENT | MCL_FUTURE);
  pthread_cond_init(&sync_cond,NULL);
  pthread_mutex_init(&sync_mutex, NULL);
685
  usleep(1000);
laurent's avatar
laurent committed
686

687
  if (NFAPI_MODE) {
laurent's avatar
laurent committed
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
    printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n");
    pthread_cond_init(&sync_cond,NULL);
    pthread_mutex_init(&sync_mutex, NULL);
  }

  printf("START MAIN THREADS\n");
  // start the main threads
  number_of_cards = 1;
  printf("RC.nb_nr_L1_inst:%d\n", RC.nb_nr_L1_inst);

  if (RC.nb_nr_L1_inst > 0) {
    printf("Initializing gNB threads single_thread_flag:%d wait_for_sync:%d\n", single_thread_flag,wait_for_sync);
    init_gNB(single_thread_flag,wait_for_sync);
  }

  printf("wait_gNBs()\n");
  wait_gNBs();
  printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU);
706
  int sl_ahead=6;
laurent's avatar
laurent committed
707 708
  if (RC.nb_RU >0) {
    printf("Initializing RU threads\n");
709
    init_NR_RU(uniqCfg, get_softmodem_params()->rf_config_file);
laurent's avatar
laurent committed
710 711 712 713

    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;
714
      if (ru_id==0) sl_ahead = RC.ru[ru_id]->sl_ahead;	
715
      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
716
    }
717
    
laurent's avatar
laurent committed
718 719 720 721
  }

  config_sync_var=0;

722 723 724 725 726 727

#ifdef E2_AGENT

//////////////////////////////////
//////////////////////////////////
//// Init the E2 Agent
728

729 730
  // OAI Wrapper 
  e2_agent_args_t oai_args = RCconfig_NR_E2agent();
731

732 733
  if (oai_args.enabled) {
    initialize_agent(node_type, oai_args);
734 735 736 737 738
  }

#endif // E2_AGENT


Mahesh's avatar
Mahesh committed
739
  if (NFAPI_MODE==NFAPI_MODE_PNF) {
laurent's avatar
laurent committed
740 741 742
    wait_nfapi_init("main?");
  }

743 744 745 746 747 748 749
  // 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();

750
  if (RC.nb_nr_L1_inst > 0) {
Xue Song's avatar
Xue Song committed
751 752 753 754 755 756
    printf("wait RUs\n");
    wait_RUs();
    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");
757

758
    for (int idx=0;idx<RC.nb_nr_L1_inst;idx++) RC.gNB[idx]->if_inst->sl_ahead = sl_ahead;
759 760
    if(IS_SOFTMODEM_DOSCOPE) {
      sleep(1);
Xue Song's avatar
Xue Song committed
761 762 763 764 765 766 767
      scopeParms_t p;
      p.argc=&argc;
      p.argv=argv;
      p.gNB=RC.gNB[0];
      p.ru=RC.ru[0];
      load_softscope("nr",&p);
    }
768

769 770 771 772 773 774 775 776 777
    if(IS_SOFTMODEM_DOSCOPE_QT) {
      scopeParms_t p;
      p.argc = &argc;
      p.argv = argv;
      p.gNB  = RC.gNB[0];
      p.ru   = RC.ru[0];
      load_softscope("nrqt", &p);
    }

778 779 780 781 782 783
    if (NFAPI_MODE != NFAPI_MODE_PNF && NFAPI_MODE != NFAPI_MODE_VNF) {
      printf("Not NFAPI mode - call init_eNB_afterRU()\n");
      init_eNB_afterRU();
    } else {
      printf("NFAPI mode - DO NOT call init_gNB_afterRU()\n");
    }
784

Xue Song's avatar
Xue Song committed
785 786 787 788 789 790 791 792
    printf("ALL RUs ready - ALL gNBs ready\n");
    // connect the TX/RX buffers
    printf("Sending sync to all threads\n");
    pthread_mutex_lock(&sync_mutex);
    sync_var=0;
    pthread_cond_broadcast(&sync_cond);
    pthread_mutex_unlock(&sync_mutex);
  }
793

laurent's avatar
laurent committed
794 795
  // wait for end of program
  printf("Entering ITTI signals handler\n");
796
  printf("TYPE <CTRL-C> TO TERMINATE\n");
797
  itti_wait_tasks_end(NULL);
laurent's avatar
laurent committed
798 799 800
  printf("Returned from ITTI signal handler\n");
  oai_exit=1;
  printf("oai_exit=%d\n",oai_exit);
801

laurent's avatar
laurent committed
802
  // cleanup
803 804
  if (RC.nb_nr_L1_inst > 0)
    stop_gNB(RC.nb_nr_L1_inst);
Xue Song's avatar
Xue Song committed
805

806 807
  if (RC.nb_RU > 0)
    stop_RU(RC.nb_RU);
laurent's avatar
laurent committed
808 809 810

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

815
  for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) {
816 817 818
    phy_free_nr_gNB(RC.gNB[inst]);
  }

laurent's avatar
laurent committed
819 820 821 822 823 824 825
  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

826
  for(ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
laurent's avatar
laurent committed
827 828 829 830 831 832 833 834
    if (RC.ru[ru_id]->ifdevice.trx_end_func)
      RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice);
  }

  logClean();
  printf("Bye.\n");
  return 0;
}