mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
448 lines
13 KiB
C
448 lines
13 KiB
C
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "common_lib.h"
|
|
#include "radio/ETHERNET/ethernet_lib.h"
|
|
#include "oran_isolate.h"
|
|
#include "oran-init.h"
|
|
#include "xran_fh_o_du.h"
|
|
#include "xran_sync_api.h"
|
|
|
|
#include "common/utils/LOG/log.h"
|
|
#include "openair1/PHY/defs_gNB.h"
|
|
#include "oaioran.h"
|
|
#include "oran-config.h"
|
|
|
|
// include the following file for VERSIONX, version of xran lib, to print it during
|
|
// startup. Only relevant for printing, if it ever makes problem, remove this
|
|
// line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api
|
|
#include "../../app/src/common.h"
|
|
|
|
#ifdef OAI_MPLANE
|
|
#include "mplane/init-mplane.h"
|
|
#include "mplane/connect-mplane.h"
|
|
#endif
|
|
|
|
typedef struct {
|
|
eth_state_t e;
|
|
rru_config_msg_type_t last_msg;
|
|
int capabilities_sent;
|
|
void *oran_priv;
|
|
void *mplane_priv;
|
|
uint32_t nCC;
|
|
uint32_t num_ports;
|
|
} oran_eth_state_t;
|
|
|
|
notifiedFIFO_t oran_sync_fifo;
|
|
notifiedFIFO_t oran_sync_fifo_prach;
|
|
|
|
int trx_oran_start(openair0_device_t *device)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
|
|
oran_eth_state_t *s = device->priv;
|
|
|
|
// Start ORAN
|
|
if (xran_timingsource_start() != 0) {
|
|
printf("%s:%d:%s: Start timing source failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__);
|
|
exit(1);
|
|
} else {
|
|
printf("Start timing source. Done\n");
|
|
}
|
|
|
|
if (xran_start_worker_threads() != 0) {
|
|
printf("%s:%d:%s: Start worker thread failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__);
|
|
exit(1);
|
|
} else {
|
|
printf("Start worker thread. Done\n");
|
|
}
|
|
|
|
xran_mem_mgr_leak_detector_display(0);
|
|
|
|
for (int32_t port_id = 0; port_id < s->num_ports; port_id++) {
|
|
if (xran_start(((void **)s->oran_priv)[port_id]) != 0) {
|
|
printf("%s:%d:%s: Start ORAN port ID %d failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__, port_id);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
printf("Start ORAN. Done\n");
|
|
|
|
for (int32_t cc_id = 0; cc_id < s->nCC; cc_id++) {
|
|
for (int32_t port_id = 0; port_id < s->num_ports; port_id++) {
|
|
if (xran_activate_cc(port_id, cc_id) != 0) {
|
|
printf("%s:%d:%s: Activate CC failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__);
|
|
exit(1);
|
|
} else {
|
|
printf("Activate CC. Done\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void trx_oran_end(openair0_device_t *device)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
oran_eth_state_t *s = device->priv;
|
|
xran_shutdown(s->oran_priv);
|
|
xran_close(s->oran_priv);
|
|
xran_cleanup();
|
|
xran_mem_mgr_leak_detector_destroy();
|
|
}
|
|
|
|
int trx_oran_stop(openair0_device_t *device)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
oran_eth_state_t *s = device->priv;
|
|
|
|
for (int32_t cc_id = 0; cc_id < s->nCC; cc_id++) {
|
|
for (int32_t port_id = 0; port_id < s->num_ports; port_id++) {
|
|
xran_deactivate_cc(port_id, cc_id);
|
|
}
|
|
}
|
|
|
|
xran_timingsource_stop();
|
|
|
|
for (int32_t port_id = 0; port_id < s->num_ports; port_id++) {
|
|
xran_stop(((void **)s->oran_priv)[port_id]);
|
|
}
|
|
|
|
#ifdef OAI_MPLANE
|
|
printf("[MPLANE] Stopping M-plane.\n");
|
|
disconnect_mplane(s->mplane_priv);
|
|
free(s->mplane_priv);
|
|
#endif
|
|
return (0);
|
|
}
|
|
|
|
int trx_oran_set_freq(openair0_device_t *device, openair0_config_t *openair0_cfg)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
return (0);
|
|
}
|
|
|
|
int trx_oran_set_gains(openair0_device_t *device, openair0_config_t *openair0_cfg)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
return (0);
|
|
}
|
|
|
|
int trx_oran_get_stats(openair0_device_t *device)
|
|
{
|
|
uint64_t total_time, used_time;
|
|
uint32_t num_core_used, core_used[64];
|
|
uint32_t ret = xran_get_time_stats(&total_time, &used_time, &num_core_used, &core_used[0], 0);
|
|
if (ret == 0)
|
|
LOG_I(HW, "xran_get_time_stats(): total thread time %ld, total time essential tasks %ld, num cores used %d\n", total_time, used_time, num_core_used);
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
return (0);
|
|
}
|
|
|
|
int trx_oran_reset_stats(openair0_device_t *device)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
return (0);
|
|
}
|
|
|
|
int ethernet_tune(openair0_device_t *device, unsigned int option, int value)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
int trx_oran_write_raw(openair0_device_t *device, openair0_timestamp_t timestamp, void **buff, int nsamps, int cc, int flags)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
int trx_oran_read_raw(openair0_device_t *device, openair0_timestamp_t *timestamp, void **buff, int nsamps, int cc)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
char *msg_type(int t)
|
|
{
|
|
static char *s[12] = {
|
|
"RAU_tick",
|
|
"RRU_capabilities",
|
|
"RRU_config",
|
|
"RRU_config_ok",
|
|
"RRU_start",
|
|
"RRU_stop",
|
|
"RRU_sync_ok",
|
|
"RRU_frame_resynch",
|
|
"RRU_MSG_max_num",
|
|
"RRU_check_sync",
|
|
"RRU_config_update",
|
|
"RRU_config_update_ok",
|
|
};
|
|
|
|
if (t < 0 || t > 11)
|
|
return "UNKNOWN";
|
|
return s[t];
|
|
}
|
|
|
|
int trx_oran_ctlsend(openair0_device_t *device, void *msg, ssize_t msg_len)
|
|
{
|
|
RRU_CONFIG_msg_t *rru_config_msg = msg;
|
|
oran_eth_state_t *s = device->priv;
|
|
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
|
|
printf(" rru_config_msg->type %d [%s]\n", rru_config_msg->type, msg_type(rru_config_msg->type));
|
|
|
|
s->last_msg = rru_config_msg->type;
|
|
|
|
return msg_len;
|
|
}
|
|
|
|
int trx_oran_ctlrecv(openair0_device_t *device, void *msg, ssize_t msg_len)
|
|
{
|
|
RRU_CONFIG_msg_t *rru_config_msg = msg;
|
|
oran_eth_state_t *s = device->priv;
|
|
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
|
|
if (s->last_msg == RAU_tick && s->capabilities_sent == 0) {
|
|
printf("ORAN ctrlrcv RRU_tick received and send capabilities hard coded\n");
|
|
RRU_capabilities_t *cap;
|
|
rru_config_msg->type = RRU_capabilities;
|
|
rru_config_msg->len = sizeof(RRU_CONFIG_msg_t) - MAX_RRU_CONFIG_SIZE + sizeof(RRU_capabilities_t);
|
|
// Fill RRU capabilities (see openair1/PHY/defs_RU.h)
|
|
// For now they are hard coded - try to retreive the params from openari device
|
|
|
|
cap = (RRU_capabilities_t *)&rru_config_msg->msg[0];
|
|
cap->FH_fmt = OAI_IF4p5_only;
|
|
cap->num_bands = 1;
|
|
cap->band_list[0] = 78;
|
|
// cap->num_concurrent_bands = 1; component carriers
|
|
cap->nb_rx[0] = 1; // device->openair0_cfg->rx_num_channels;
|
|
cap->nb_tx[0] = 1; // device->openair0_cfg->tx_num_channels;
|
|
cap->max_pdschReferenceSignalPower[0] = -27;
|
|
cap->max_rxgain[0] = 90;
|
|
cap->N_RB_DL[0] = 106;
|
|
cap->N_RB_UL[0] = 106;
|
|
|
|
s->capabilities_sent = 1;
|
|
|
|
return rru_config_msg->len;
|
|
}
|
|
if (s->last_msg == RRU_config) {
|
|
printf("Oran RRU_config\n");
|
|
rru_config_msg->type = RRU_config_ok;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
|
|
{
|
|
int ret = 0; // return code for PUSCH/PRACH processing
|
|
|
|
ru_info_t ru_info = {
|
|
.nb_rx = ru->nb_rx,
|
|
.nb_tx = ru->nb_tx,
|
|
.rxdataF = ru->common.rxdataF,
|
|
.beam_id = ru->common.beam_id,
|
|
.prach_buf = NULL,
|
|
};
|
|
|
|
/* Firstly, process PUSCH packets */
|
|
RU_proc_t *proc = &ru->proc; // to check if (frame,slot) combination corresponds to the expected PUSCH one
|
|
int f, sl;
|
|
LOG_D(HW, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]);
|
|
start_meas(&ru->rx_fhaul);
|
|
ret = xran_fh_rx_read_slot(&ru_info, &f, &sl);
|
|
stop_meas(&ru->rx_fhaul);
|
|
LOG_D(HW, "Read %d.%d rxdataF %p,%p\n", f, sl, ru_info.rxdataF[0], ru_info.rxdataF[1]);
|
|
if (ret != 0) {
|
|
printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl);
|
|
}
|
|
|
|
/* Secondly, process PRACH packets */
|
|
int f_prach, sl_prach;
|
|
ret = xran_fh_rx_prach_read_slot(ru->gNB_list[0], &ru_info, &f_prach, &sl_prach);
|
|
if (ret != 0) {
|
|
printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX PRACH function \n", f_prach, sl_prach);
|
|
}
|
|
|
|
int slots_per_frame = 10 << (ru->openair0_cfg.nr_scs_for_raster);
|
|
proc->tti_rx = sl;
|
|
proc->frame_rx = f;
|
|
proc->tti_tx = (sl + ru->sl_ahead) % slots_per_frame;
|
|
proc->frame_tx = (sl > (slots_per_frame - 1 - ru->sl_ahead)) ? (f + 1) & 1023 : f;
|
|
|
|
if (proc->first_rx == 0) {
|
|
print_fhi_counters(&ru_info, proc->frame_rx, proc->tti_rx);
|
|
if (proc->tti_rx != *slot) {
|
|
LOG_E(HW,
|
|
"Received Time doesn't correspond to the time we think it is (slot mismatch, received %d.%d, expected %d.%d)\n",
|
|
proc->frame_rx,
|
|
proc->tti_rx,
|
|
*frame,
|
|
*slot);
|
|
*slot = proc->tti_rx;
|
|
}
|
|
|
|
if (proc->frame_rx != *frame) {
|
|
LOG_E(HW,
|
|
"Received Time doesn't correspond to the time we think it is (frame mismatch, %d.%d , expected %d.%d)\n",
|
|
proc->frame_rx,
|
|
proc->tti_rx,
|
|
*frame,
|
|
*slot);
|
|
*frame = proc->frame_rx;
|
|
}
|
|
} else {
|
|
proc->first_rx = 0;
|
|
LOG_I(HW, "before adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
|
|
*frame = proc->frame_rx;
|
|
*slot = proc->tti_rx;
|
|
LOG_I(HW, "After adjusting, OAI: frame=%d slot=%d, XRAN: frame=%d slot=%d\n", *frame, *slot, proc->frame_rx, proc->tti_rx);
|
|
}
|
|
}
|
|
|
|
void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
|
|
{
|
|
start_meas(&ru->tx_fhaul);
|
|
ru_info_t ru_info = {
|
|
.nb_rx = ru->nb_rx,
|
|
.nb_tx = ru->nb_tx,
|
|
.txdataF_BF = ru->common.txdataF_BF,
|
|
.beam_id = ru->common.beam_id,
|
|
};
|
|
|
|
// printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp);
|
|
|
|
int ret = xran_fh_tx_send_slot(&ru_info, frame, slot, timestamp);
|
|
if (ret != 0) {
|
|
printf("ORAN: ORAN_fh_if4p5_south_out ERROR in TX function \n");
|
|
}
|
|
stop_meas(&ru->tx_fhaul);
|
|
}
|
|
|
|
void *get_internal_parameter(char *name)
|
|
{
|
|
printf("ORAN: %s\n", __FUNCTION__);
|
|
|
|
if (!strcmp(name, "fh_if4p5_south_in"))
|
|
return (void *)oran_fh_if4p5_south_in;
|
|
if (!strcmp(name, "fh_if4p5_south_out"))
|
|
return (void *)oran_fh_if4p5_south_out;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
__attribute__((__visibility__("default"))) int transport_init(openair0_device_t *device,
|
|
openair0_config_t *openair0_cfg,
|
|
eth_params_t *eth_params)
|
|
{
|
|
oran_eth_state_t *eth = calloc_or_fail(1, sizeof(*eth));
|
|
|
|
struct xran_fh_init fh_init = {0};
|
|
struct xran_fh_config fh_config[XRAN_PORTS_NUM] = {0};
|
|
|
|
bool success = false;
|
|
#ifdef OAI_MPLANE
|
|
ru_session_list_t *ru_session_list = calloc(1, sizeof(*ru_session_list));
|
|
assert(ru_session_list != NULL && "Memory exhausted");
|
|
success = init_mplane(ru_session_list);
|
|
AssertFatal(success, "[MPLANE] Cannot initialize M-plane.\n");
|
|
|
|
bool ru_configured[ru_session_list->num_rus];
|
|
for (size_t i = 0; i < ru_session_list->num_rus; i++) {
|
|
ru_session_t *ru_session = &ru_session_list->ru_session[i];
|
|
ru_configured[i] = connect_mplane(ru_session);
|
|
if (!ru_configured[i]) {
|
|
continue;
|
|
}
|
|
ru_configured[i] = manage_ru(ru_session, openair0_cfg, ru_session_list->num_rus);
|
|
}
|
|
|
|
bool all_ok = true;
|
|
bool ru_ready[ru_session_list->num_rus];
|
|
for (size_t i = 0; i < ru_session_list->num_rus; i++) {
|
|
if (!ru_configured[i]) {
|
|
MP_LOG_I("RU with IP %s couldn't be configured.\n", ru_session_list->ru_session[i].ru_ip_add);
|
|
all_ok = false;
|
|
}
|
|
ru_ready[i] = false;
|
|
}
|
|
|
|
if (!all_ok) {
|
|
disconnect_mplane(ru_session_list);
|
|
AssertFatal(false, "[MPLANE] Stopping M-plane.\n");
|
|
}
|
|
|
|
while (true) {
|
|
sleep(1);
|
|
bool all_rus_ready = true;
|
|
for (int i = 0; i < ru_session_list->num_rus; i++) {
|
|
ru_session_t *ru_session = &ru_session_list->ru_session[i];
|
|
if (!ru_ready[i] && ru_session->ru_notif.config_change && !ru_session->ru_notif.rx_carrier_state && !ru_session->ru_notif.tx_carrier_state) {
|
|
MP_LOG_I("RU \"%s\" is now ready.\n", ru_session->ru_ip_add);
|
|
ru_ready[i] = true;
|
|
if (!ru_session->pm_stats.start_up_timing) {
|
|
success = pm_conf(ru_session, "true");
|
|
if (success)
|
|
MP_LOG_I("Sucessfully activated PM after start-up procedure for RU \"%s\".\n", ru_session->ru_ip_add);
|
|
}
|
|
} else {
|
|
all_rus_ready = false;
|
|
break;
|
|
}
|
|
}
|
|
if (all_rus_ready) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
eth->mplane_priv = ru_session_list;
|
|
|
|
success = get_xran_config(ru_session_list, openair0_cfg, &fh_init, fh_config);
|
|
AssertFatal(success, "[MPLANE] Cannot configure xran with M-plane info.\n");
|
|
#else
|
|
success = get_xran_config(NULL, openair0_cfg, &fh_init, fh_config);
|
|
AssertFatal(success, "cannot get configuration for xran\n");
|
|
#endif
|
|
|
|
LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX);
|
|
eth->oran_priv = oai_oran_initialize(&fh_init, fh_config);
|
|
AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul");
|
|
// create message queues for ORAN sync
|
|
|
|
initNotifiedFIFO(&oran_sync_fifo);
|
|
initNotifiedFIFO(&oran_sync_fifo_prach);
|
|
|
|
eth->e.flags = ETH_RAW_IF4p5_MODE;
|
|
eth->e.compression = NO_COMPRESS;
|
|
eth->e.if_name = eth_params->local_if_name;
|
|
eth->last_msg = (rru_config_msg_type_t)-1;
|
|
eth->nCC = fh_config->nCC;
|
|
eth->num_ports = fh_init.xran_ports;
|
|
|
|
device->transp_type = ETHERNET_TP;
|
|
device->trx_start_func = trx_oran_start;
|
|
device->trx_get_stats_func = trx_oran_get_stats;
|
|
device->trx_reset_stats_func = trx_oran_reset_stats;
|
|
device->trx_end_func = trx_oran_end;
|
|
device->trx_stop_func = trx_oran_stop;
|
|
device->trx_set_freq_func = trx_oran_set_freq;
|
|
device->trx_set_gains_func = trx_oran_set_gains;
|
|
device->trx_write_func = trx_oran_write_raw;
|
|
device->trx_read_func = trx_oran_read_raw;
|
|
device->trx_ctlsend_func = trx_oran_ctlsend;
|
|
device->trx_ctlrecv_func = trx_oran_ctlrecv;
|
|
device->get_internal_parameter = get_internal_parameter;
|
|
device->priv = eth;
|
|
device->openair0_cfg = &openair0_cfg[0];
|
|
|
|
return 0;
|
|
}
|