Skip to content
Snippets Groups Projects
nr-softmodem.c 46.9 KiB
Newer Older
        }
      }
    }

    // TODO: assign the MeasData every granulPeriod
    for (size_t i = 0; i < msg->MeasData_len; i++) {
      adapter_MeasDataItem_t* item = &msg->MeasData[i];

      // TODO: assign measRecord_len according to
      //  (1) the length of Measurements Information List IE (format1) or
      //  (2) Measurements Information Condition UE List IE (format2)
      //  from the action definition or subscription request

      // TODO: only support KPM format 1, and it only can handle one UE's information
      //  assume to record one data: DL resource utilization
      item->measRecord_len = 1;
      if (item->measRecord_len > 0) {
        item->measRecord = calloc(item->measRecord_len, sizeof(adapter_MeasRecord_t));
        assert(item->measRecord != NULL && "Memory exhausted");
      }

      UE_iterator(UE_info->list, UE)
      {
        int dl_rb_usage = 0;
        if (is_xlsch_in_slot(RC.nrmac[mod_id]->dlsch_slot_bitmap[cur_slot / 64], cur_slot))
          dl_rb_usage = UE->mac_stats.dl.current_rbs*100/n_rb_sched;

        // TODO: go through the measRecord according to the Measurements Information (format 1) or Information Condition UE (format 2) List IE
        adapter_MeasRecord_t *record_PrbDlUsage = &item->measRecord[0];
        record_PrbDlUsage->type = MeasRecord_int;
        record_PrbDlUsage->int_val = dl_rb_usage;
      }

      // incompleteFlag = -1, the data is reliable
      item->incompleteFlag = -1;
    }

    // TODO: assign MeasInfo_len according to the action definition or subscription request
    msg->MeasInfo_len = 1;
    if (msg->MeasInfo_len > 0) {
      msg->MeasInfo = calloc(msg->MeasInfo_len, sizeof(MeasInfo_t));
      assert(msg->MeasInfo != NULL && "Memory exhausted" );

      MeasInfo_t* info = &msg->MeasInfo[0];
      info->meas_type = KPM_V2_MEASUREMENT_TYPE_NAME;
      char* measName = "PrbDlUsage";
      info->measName.len = strlen(measName);
      info->measName.buf = malloc(strlen(measName));
      assert(info->measName.buf != NULL && "memory exhausted");
      memcpy(info->measName.buf, measName, msg->MeasInfo[0].measName.len);

      // TODO: assign labelInfo_len according to the action definition (?)
      info->labelInfo_len = 1;
      info->labelInfo = calloc(info->labelInfo_len, sizeof(adapter_LabelInfoItem_t));
      assert(info->labelInfo != NULL && "memory exhausted");
      adapter_LabelInfoItem_t* label = &info->labelInfo[0];
      label->noLabel = calloc(1, sizeof(long));
      assert(label->noLabel != NULL && "memory exhausted");
      *(label->noLabel) = 0;
    }
  } else {
    for (size_t i = 0; i < msg->MeasData_len; i++) {
      adapter_MeasDataItem_t* item = &msg->MeasData[i];
      item->measRecord_len = 1;
      if (item->measRecord_len > 0) {
        item->measRecord = calloc(item->measRecord_len, sizeof(adapter_MeasRecord_t));
        assert(item->measRecord != NULL && "Memory exhausted");
      }

      adapter_MeasRecord_t *record_nodata = &item->measRecord[0];
      record_nodata->type = MeasRecord_int;
      record_nodata->int_val = 0;

      // incompleteFlag = 0, the data is not reliable
      item->incompleteFlag = 0;
    }
    msg->MeasInfo_len = 0;
    msg->MeasInfo = NULL;
  }

  msg->granulPeriod = NULL;
}



static
void read_RAN(sm_ag_if_rd_t* data)
{
  assert(data != NULL);
  assert(data->type == MAC_STATS_V0
        || data->type == RLC_STATS_V0
        || data->type == PDCP_STATS_V0
        || data->type == GTP_STATS_V0
        || data->type == KPM_STATS_V0
        );

  if(data->type == MAC_STATS_V0 ){
    read_mac_sm(&data->mac_stats.msg);
  }else if(data->type == RLC_STATS_V0) {
    read_rlc_sm(&data->rlc_stats.msg);
  } else if(data->type == PDCP_STATS_V0){
    read_pdcp_sm(&data->pdcp_stats.msg);
  } else if(data->type == GTP_STATS_V0){
    read_gtp_sm(&data->gtp_stats.msg);
  } else if(data->type == KPM_STATS_V0){
    read_kpm_sm(&data->kpm_stats);
  } else {
    assert(0!=0 && "Unknown data type!");
  }

}

static
sm_ag_if_ans_t write_RAN(sm_ag_if_wr_t const* data)
{
  assert(data != NULL);
  assert(0!=0 && "Not implemented");
  sm_ag_if_ans_t ans = {.type = MAC_AGENT_IF_CTRL_ANS_V0 };

  return ans;
}

int main( int argc, char **argv ) {
  int ru_id, CC_id = 0;
  start_background_system();

  ///static configuration for NR at the moment
  if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == NULL) {
    exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
  }

  set_softmodem_sighandler();
#ifdef DEBUG_CONSOLE
  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);
#endif
  mode = normal_txrx;
  memset(&openair0_cfg[0],0,sizeof(openair0_config_t)*MAX_CARDS);
  memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs);
  logInit();
  set_latency_target();
  printf("Reading in command-line options\n");
  get_options ();

  EPC_MODE_ENABLED = !IS_SOFTMODEM_NOS1;

  if (CONFIG_ISFLAGSET(CONFIG_ABORT) ) {
    fprintf(stderr,"Getting configuration failed\n");
    exit(-1);
  }


  openair0_cfg[0].threequarter_fs = threequarter_fs;

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

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

#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();
  itti_init(TASK_MAX, tasks_info);
  // initialize mscgen log after ITTI
  init_opt();
  if(PDCP_USE_NETLINK && !IS_SOFTMODEM_NOS1) {
    netlink_init();
    if (get_softmodem_params()->nsa) {
      init_pdcp();
    }
  }
#ifndef PACKAGE_VERSION
#  define PACKAGE_VERSION "UNKNOWN-EXPERIMENTAL"
#endif
  LOG_I(HW, "Version: %s\n", PACKAGE_VERSION);

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

  // don't create if node doesn't connect to RRC/S1/GTP
  int ret=create_gNB_tasks(1);
  AssertFatal(ret==0,"cannot create ITTI tasks\n");

  /* Start the agent. If it is turned off in the configuration, it won't start */
  /*
  RCconfig_nr_flexran();

  for (i = 0; i < RC.nb_nr_L1_inst; i++) {
    flexran_agent_start(i);
  }
  */
  // init UE_PF_PO and mutex lock
  pthread_mutex_init(&ue_pf_po_mutex, NULL);
  memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs);
  mlockall(MCL_CURRENT | MCL_FUTURE);
  pthread_cond_init(&sync_cond,NULL);
  pthread_mutex_init(&sync_mutex, NULL);
  usleep(1000);

  if (NFAPI_MODE) {
    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);
  }

  const char *nfapi_mode_str = "<UNKNOWN>";

  switch(NFAPI_MODE) {
    case 0:
      nfapi_mode_str = "MONOLITHIC";
      break;

    case 1:
      nfapi_mode_str = "PNF";
      break;

    case 2:
      nfapi_mode_str = "VNF";
      break;

    default:
      nfapi_mode_str = "<UNKNOWN NFAPI MODE>";
      break;
  }

  printf("NFAPI MODE:%s\n", nfapi_mode_str);

  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);
  int sl_ahead=6;
  if (RC.nb_RU >0) {
    printf("Initializing RU threads\n");
    init_NR_RU(get_softmodem_params()->rf_config_file);

    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;
      if (ru_id==0) sl_ahead = RC.ru[ru_id]->sl_ahead;	
      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);
    }
    
  }

  config_sync_var=0;

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

  sleep(2);
  const gNB_RRC_INST* rrc = RC.nrrrc[mod_id];
  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) {
    nb_id = rrc->configuration.cell_identity;
  } else if (node_type == ngran_gNB_DU) {
    cu_du_id = rrc->configuration.cell_identity;
    nb_id = rrc->configuration.cell_identity;
  } else if (node_type == ngran_gNB_CU) {
    cu_du_id = rrc->node_id;
    nb_id = rrc->node_id;
  } else {
    LOG_E(NR_RRC, "not supported ran type detect\n");
  }
  sm_io_ag_t io = {.read = read_RAN, .write = write_RAN};
  printf("[E2 NODE]: mcc = %d mnc = %d mnc_digit = %d nd_id = %d \n", mcc, mnc, mnc_digit_len, nb_id);

  // TODO: need to fix, parse the FlexRIC config in runtime
  int const agent_argc = 1;
  char** agent_argv = NULL;
  fr_args_t ric_args = init_fr_args(agent_argc, agent_argv);
  // TODO: integrate with oai config
  char* conf_dir = getenv("FLEXRIC_CONF");
  char* lib_dir = getenv("FLEXRIC_LIB_DIR");

  if (conf_dir != NULL)
    strcpy(ric_args.conf_file, conf_dir);
  else
    strcpy(ric_args.conf_file, "/usr/local/etc/flexric/flexric.conf");
  if (lib_dir != NULL)
    strcpy(ric_args.libs_dir, lib_dir);
  else
    strcpy(ric_args.libs_dir, "/usr/local/lib/flexric/");

  init_agent_api( mcc, mnc, mnc_digit_len, nb_id, cu_du_id, node_type, io, &ric_args);
//////////////////////////////////
//////////////////////////////////

  if (NFAPI_MODE==NFAPI_MODE_PNF) {
    wait_nfapi_init("main?");
  }

  if (RC.nb_nr_L1_inst > 0) {
    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");

    for (int idx=0;idx<RC.nb_nr_L1_inst;idx++) RC.gNB[idx]->if_inst->sl_ahead = sl_ahead;
    if(IS_SOFTMODEM_DOSCOPE) {
      sleep(1);
      scopeParms_t p;
      p.argc=&argc;
      p.argv=argv;
      p.gNB=RC.gNB[0];
      p.ru=RC.ru[0];
      load_softscope("nr",&p);
    }

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

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

  // wait for end of program
  printf("Entering ITTI signals handler\n");
  printf("TYPE <CTRL-C> TO TERMINATE\n");
  itti_wait_tasks_end();
  printf("Returned from ITTI signal handler\n");
  oai_exit=1;
  printf("oai_exit=%d\n",oai_exit);

  // cleanup
  if (RC.nb_nr_L1_inst > 0)
    stop_gNB(RC.nb_nr_L1_inst);

  if (RC.nb_RU > 0)
    stop_RU(RC.nb_RU);

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

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

  pthread_cond_destroy(&sync_cond);
  pthread_mutex_destroy(&sync_mutex);
  pthread_cond_destroy(&nfapi_sync_cond);
  pthread_mutex_destroy(&nfapi_sync_mutex);
  pthread_mutex_destroy(&ue_pf_po_mutex);

  // *** Handle per CC_id openair0

  for(ru_id = 0; ru_id < RC.nb_RU; ru_id++) {
    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;
}