Add O-RAN 7.2 FHI library
- Add the O-RAN 7.2 FHI library, interfacing with OSC xRAN library (E release) - Add Findxran.cmake to detect the library and headers, including version information - Test for numa and DPDK presence - Add patch for OSC xRAN to make interworking possible - Add sample config files for LiteOn, Benetel, and VVDN units. Documentation is provided in the next commit. Co-authored-by: Raymond Knopp <raymond.knopp@eurecom.fr> Co-authored-by: Cedric Roux <cedric.roux@eurecom.fr> Co-authored-by: Manish Kumar Singh <manish1.kumar@amd.com> Co-authored-by: thamizhselvan.k <thamizhselvan.k@vvdntech.in> Co-authored-by: rajeshwari.p <rajeshwari.p@vvdntech.in> Co-authored-by: Hongzhi Wang <hongzhi.wang@openairinterface.org> Co-authored-by: Sofia Pison <Sofia.Pison@eurecom.fr>
This commit is contained in:
co-authored by
Raymond Knopp
Cedric Roux
Manish Kumar Singh
thamizhselvan.k
rajeshwari.p
Hongzhi Wang
Sofia Pison
parent
eca56653c1
commit
baea11c35c
@@ -13,6 +13,11 @@ if(OAI_BLADERF)
|
||||
add_subdirectory(BLADERF)
|
||||
endif()
|
||||
|
||||
add_boolean_option(OAI_FHI72 OFF "Activate OAI's FHI 7.2 (xran/fhi_lib) driver" OFF)
|
||||
if(OAI_FHI72)
|
||||
add_subdirectory(fhi_72)
|
||||
endif()
|
||||
|
||||
add_boolean_option(OAI_IRIS OFF "Activate OAI's IRIS/SoapySDR driver" OFF)
|
||||
if(OAI_IRIS)
|
||||
add_subdirectory(IRIS)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# use env var PKG_CONFIG_PATH to override paths to libdpdk.pc
|
||||
pkg_check_modules(dpdk REQUIRED libdpdk)
|
||||
pkg_check_modules(numa REQUIRED numa)
|
||||
|
||||
find_package(xran 5.1.1 EXACT REQUIRED) # E release -> 5
|
||||
|
||||
# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress
|
||||
# alignment 1 of 'struct XYZ' is less than 2
|
||||
add_compile_options(-Wno-packed-not-aligned)
|
||||
|
||||
add_library(oran_fhlib_5g MODULE
|
||||
oran_isolate.c
|
||||
oaioran.c
|
||||
oran-config.c
|
||||
oran-init.c
|
||||
)
|
||||
|
||||
set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native")
|
||||
target_link_libraries(oran_fhlib_5g PRIVATE xran::xran)
|
||||
target_link_libraries(oran_fhlib_5g PRIVATE ${dpdk_LINK_LIBRARIES})
|
||||
target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS})
|
||||
target_link_libraries(oran_fhlib_5g PRIVATE pthread dl rt m numa)
|
||||
target_link_libraries(oran_fhlib_5g PRIVATE ${T_LIB})
|
||||
|
||||
# TODO: can be removed?
|
||||
target_include_directories(oran_fhlib_5g PRIVATE ${xran_INCLUDE_DIRS}/../src/)
|
||||
|
||||
set_target_properties(oran_fhlib_5g PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
add_custom_command(TARGET oran_fhlib_5g POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E create_symlink liboran_fhlib_5g.so liboai_transpro.so
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
@@ -0,0 +1,553 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "xran_fh_o_du.h"
|
||||
#include "xran_compression.h"
|
||||
|
||||
// xran_cp_api.h uses SIMD, but does not include it
|
||||
#include <immintrin.h>
|
||||
#include "xran_cp_api.h"
|
||||
#include "xran_sync_api.h"
|
||||
#include "oran_isolate.h"
|
||||
#include "oran-init.h"
|
||||
#include "xran_common.h"
|
||||
#include "oaioran.h"
|
||||
#include <rte_ethdev.h>
|
||||
|
||||
#include "oran-config.h" // for g_kbar
|
||||
|
||||
#define USE_POLLING 1
|
||||
// Declare variable useful for the send buffer function
|
||||
volatile uint8_t first_call_set = 0;
|
||||
volatile uint8_t first_rx_set = 0;
|
||||
volatile int first_read_set = 0;
|
||||
|
||||
// Variable declaration useful for fill IQ samples from file
|
||||
#define IQ_PLAYBACK_BUFFER_BYTES (XRAN_NUM_OF_SLOT_IN_TDD_LOOP * N_SYM_PER_SLOT * XRAN_MAX_PRBS * N_SC_PER_PRB * 4L)
|
||||
/*
|
||||
int rx_tti;
|
||||
int rx_sym;
|
||||
volatile uint32_t rx_cb_tti = 0;
|
||||
volatile uint32_t rx_cb_frame = 0;
|
||||
volatile uint32_t rx_cb_subframe = 0;
|
||||
volatile uint32_t rx_cb_slot = 0;
|
||||
*/
|
||||
|
||||
#define GetFrameNum(tti, SFNatSecStart, numSubFramePerSystemFrame, numSlotPerSubFrame) \
|
||||
((((uint32_t)tti / ((uint32_t)numSubFramePerSystemFrame * (uint32_t)numSlotPerSubFrame)) + SFNatSecStart) & 0x3FF)
|
||||
#define GetSlotNum(tti, numSlotPerSfn) ((uint32_t)tti % ((uint32_t)numSlotPerSfn))
|
||||
|
||||
int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id);
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
#ifndef USE_POLLING
|
||||
extern notifiedFIFO_t oran_sync_fifo;
|
||||
#else
|
||||
volatile oran_sync_info_t oran_sync_info;
|
||||
#endif
|
||||
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status)
|
||||
{
|
||||
struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag;
|
||||
uint64_t second;
|
||||
uint32_t tti;
|
||||
uint32_t frame;
|
||||
uint32_t subframe;
|
||||
uint32_t slot, slot2;
|
||||
uint32_t rx_sym;
|
||||
|
||||
static int32_t last_slot = -1;
|
||||
static int32_t last_frame = -1;
|
||||
struct xran_device_ctx *xran_ctx = xran_dev_get_ctx();
|
||||
const struct xran_fh_init *fh_init = &xran_ctx->fh_init;
|
||||
int num_ports = fh_init->xran_ports;
|
||||
static int rx_RU[XRAN_PORTS_NUM][20] = {0};
|
||||
uint32_t rx_tti = callback_tag->slotiId;
|
||||
|
||||
tti = xran_get_slot_idx_from_tti(rx_tti, &frame, &subframe, &slot, &second);
|
||||
|
||||
rx_sym = callback_tag->symbol;
|
||||
uint32_t ru_id = callback_tag->oXuId;
|
||||
if (rx_sym == 7) {
|
||||
if (first_call_set) {
|
||||
if (!first_rx_set) {
|
||||
LOG_I(NR_PHY, "first_rx is set (num_ports %d)\n", num_ports);
|
||||
}
|
||||
first_rx_set = 1;
|
||||
if (first_read_set == 1) {
|
||||
slot2 = slot + (subframe << 1);
|
||||
rx_RU[ru_id][slot2] = 1;
|
||||
if (last_frame > 0 && frame > 0
|
||||
&& ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023))))
|
||||
LOG_E(PHY, "Jump in frame counter last_frame %d => %d, slot %d\n", last_frame, frame, slot2);
|
||||
for (int i = 0; i < num_ports; i++) {
|
||||
if (rx_RU[i][slot2] == 0)
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < num_ports; i++)
|
||||
rx_RU[i][slot2] = 0;
|
||||
|
||||
if (last_slot == -1 || slot2 != last_slot) {
|
||||
#ifndef USE_POLLING
|
||||
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(oran_sync_info_t), 0, &oran_sync_fifo, NULL);
|
||||
oran_sync_info_t *info = (oran_sync_info_t *)NotifiedFifoData(req);
|
||||
info->sl = slot2;
|
||||
info->f = frame;
|
||||
LOG_D(PHY, "Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, info->sl, slot, ru_id, subframe, last_slot);
|
||||
#else
|
||||
LOG_D(PHY, "Writing %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
|
||||
oran_sync_info.tti = tti;
|
||||
oran_sync_info.sl = slot2;
|
||||
oran_sync_info.f = frame;
|
||||
#endif
|
||||
#ifndef USE_POLLING
|
||||
pushNotifiedFIFO(&oran_sync_fifo, req);
|
||||
#else
|
||||
#endif
|
||||
} else
|
||||
LOG_E(PHY, "Cannot Push %d.%d.%d (slot %d, subframe %d,last_slot %d)\n", frame, slot2, ru_id, slot, subframe, last_slot);
|
||||
last_slot = slot2;
|
||||
last_frame = frame;
|
||||
} // first_read_set == 1
|
||||
} // first_call_set
|
||||
} // rx_sym == 7
|
||||
}
|
||||
void oai_xran_fh_srs_callback(void *pCallbackTag, xran_status_t status)
|
||||
{
|
||||
rte_pause();
|
||||
}
|
||||
void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status)
|
||||
{
|
||||
rte_pause();
|
||||
}
|
||||
|
||||
int oai_physide_dl_tti_call_back(void *param)
|
||||
{
|
||||
if (!first_call_set)
|
||||
printf("first_call set from phy cb first_call_set=%p\n", &first_call_set);
|
||||
first_call_set = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oai_physide_ul_half_slot_call_back(void *param)
|
||||
{
|
||||
rte_pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oai_physide_ul_full_slot_call_back(void *param)
|
||||
{
|
||||
rte_pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_prach_data(ru_info_t *ru, int frame, int slot)
|
||||
{
|
||||
/* calculate tti and subframe_id from frame, slot num */
|
||||
int tti = 20 * (frame) + (slot);
|
||||
uint32_t subframe = XranGetSubFrameNum(tti, 2, 10);
|
||||
uint32_t is_prach_slot = xran_is_prach_slot(0, subframe, (slot % 2));
|
||||
int sym_idx = 0;
|
||||
|
||||
struct xran_device_ctx *xran_ctx = xran_dev_get_ctx();
|
||||
struct xran_prach_cp_config *pPrachCPConfig = &(xran_ctx->PrachCPConfig);
|
||||
struct xran_ru_config *ru_conf = &(xran_ctx->fh_cfg.ru_conf);
|
||||
|
||||
int nb_rx_per_ru = ru->nb_rx / xran_ctx->fh_init.xran_ports;
|
||||
/* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */
|
||||
if (is_prach_slot) {
|
||||
for (sym_idx = 0; sym_idx < pPrachCPConfig->numSymbol; sym_idx++) {
|
||||
for (int aa = 0; aa < ru->nb_rx; aa++) {
|
||||
int16_t *dst, *src;
|
||||
int idx = 0;
|
||||
xran_ctx = xran_dev_get_ctx_by_id(aa / nb_rx_per_ru);
|
||||
dst = ru->prach_buf[aa]; // + (sym_idx*576));
|
||||
src = (int16_t *)((uint8_t *)xran_ctx->sFHPrachRxBbuIoBufCtrlDecomp[tti % XRAN_N_FE_BUF_LEN][0][aa % nb_rx_per_ru]
|
||||
.sBufferList.pBuffers[sym_idx]
|
||||
.pData);
|
||||
|
||||
/* convert Network order to host order */
|
||||
if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) {
|
||||
if (sym_idx == 0) {
|
||||
for (idx = 0; idx < 139 * 2; idx++) {
|
||||
dst[idx] = ((int16_t)ntohs(src[idx + g_kbar]));
|
||||
}
|
||||
} else {
|
||||
for (idx = 0; idx < 139 * 2; idx++) {
|
||||
dst[idx] += ((int16_t)ntohs(src[idx + g_kbar]));
|
||||
}
|
||||
}
|
||||
} else if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_BLKFLOAT) {
|
||||
struct xranlib_decompress_request bfp_decom_req;
|
||||
struct xranlib_decompress_response bfp_decom_rsp;
|
||||
|
||||
int16_t local_dst[12 * 2 * N_SC_PER_PRB] __attribute__((aligned(64)));
|
||||
|
||||
int payload_len = (3 * ru_conf->iqWidth_PRACH + 1) * 12; // 12 = closest number of PRBs to 139 REs
|
||||
|
||||
memset(&bfp_decom_req, 0, sizeof(struct xranlib_decompress_request));
|
||||
memset(&bfp_decom_rsp, 0, sizeof(struct xranlib_decompress_response));
|
||||
|
||||
bfp_decom_req.data_in = (int8_t *)src;
|
||||
bfp_decom_req.numRBs = 12; // closest number of PRBs to 139 REs
|
||||
bfp_decom_req.len = payload_len;
|
||||
bfp_decom_req.compMethod = XRAN_COMPMETHOD_BLKFLOAT;
|
||||
bfp_decom_req.iqWidth = ru_conf->iqWidth_PRACH;
|
||||
|
||||
bfp_decom_rsp.data_out = (int16_t *)local_dst;
|
||||
bfp_decom_rsp.len = 0;
|
||||
xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp);
|
||||
// note: this is hardwired for 139 point PRACH sequence, kbar=2
|
||||
if (sym_idx == 0) //
|
||||
for (idx = 0; idx < (139 * 2); idx++)
|
||||
dst[idx] = local_dst[idx + g_kbar];
|
||||
else
|
||||
for (idx = 0; idx < (139 * 2); idx++)
|
||||
dst[idx] += (local_dst[idx + g_kbar]);
|
||||
} // COMPMETHOD_BLKFLOAT
|
||||
} // aa
|
||||
} // symb_indx
|
||||
} // is_prach_slot
|
||||
return (0);
|
||||
}
|
||||
|
||||
int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
|
||||
{
|
||||
void *ptr = NULL;
|
||||
int32_t *pos = NULL;
|
||||
int idx = 0;
|
||||
static int last_slot = -1;
|
||||
first_read_set = 1;
|
||||
|
||||
static int64_t old_rx_counter[XRAN_PORTS_NUM] = {0};
|
||||
static int64_t old_tx_counter[XRAN_PORTS_NUM] = {0};
|
||||
struct xran_common_counters x_counters[XRAN_PORTS_NUM];
|
||||
static int outcnt = 0;
|
||||
#ifndef USE_POLLING
|
||||
// pull next even from oran_sync_fifo
|
||||
notifiedFIFO_elt_t *res = pollNotifiedFIFO(&oran_sync_fifo);
|
||||
while (res == NULL) {
|
||||
res = pollNotifiedFIFO(&oran_sync_fifo);
|
||||
}
|
||||
oran_sync_info_t *info = (oran_sync_info_t *)NotifiedFifoData(res);
|
||||
|
||||
*slot = info->sl;
|
||||
*frame = info->f;
|
||||
delNotifiedFIFO_elt(res);
|
||||
#else
|
||||
LOG_D(PHY, "In xran_fh_rx_read_slot, first_rx_set %d\n", first_rx_set);
|
||||
while (first_rx_set == 0) {
|
||||
}
|
||||
|
||||
*slot = oran_sync_info.sl;
|
||||
*frame = oran_sync_info.f;
|
||||
uint32_t tti_in = oran_sync_info.tti;
|
||||
|
||||
LOG_D(PHY, "oran slot %d, last_slot %d\n", *slot, last_slot);
|
||||
int cnt = 0;
|
||||
// while (*slot == last_slot) {
|
||||
while (tti_in == oran_sync_info.tti) {
|
||||
//*slot = oran_sync_info.sl;
|
||||
cnt++;
|
||||
}
|
||||
LOG_D(PHY, "cnt %d, Reading %d.%d\n", cnt, *frame, *slot);
|
||||
last_slot = *slot;
|
||||
#endif
|
||||
// return(0);
|
||||
|
||||
int tti = (*frame * 20) + *slot;
|
||||
|
||||
read_prach_data(ru, *frame, *slot);
|
||||
|
||||
struct xran_device_ctx *xran_ctx = xran_dev_get_ctx();
|
||||
const struct xran_fh_init *fh_init = &xran_ctx->fh_init;
|
||||
int nPRBs = xran_ctx->fh_cfg.nULRBs;
|
||||
int fftsize = 1 << xran_ctx->fh_cfg.ru_conf.fftSize;
|
||||
|
||||
int slot_offset_rxdata = 3 & (*slot);
|
||||
uint32_t slot_size = 4 * 14 * 4096;
|
||||
uint8_t *rx_data = (uint8_t *)ru->rxdataF[0];
|
||||
uint8_t *start_ptr = NULL;
|
||||
int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports;
|
||||
for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet.
|
||||
for (uint8_t ant_id = 0; ant_id < ru->nb_rx; ant_id++) {
|
||||
rx_data = (uint8_t *)ru->rxdataF[ant_id];
|
||||
start_ptr = rx_data + (slot_size * slot_offset_rxdata);
|
||||
xran_ctx = xran_dev_get_ctx_by_id(ant_id / nb_rx_per_ru);
|
||||
const struct xran_fh_config *fh_config = &xran_ctx->fh_cfg;
|
||||
int tdd_period = fh_config->frame_conf.nTddPeriod;
|
||||
int slot_in_period = *slot % tdd_period;
|
||||
if (fh_config->frame_conf.sSlotConfig[slot_in_period].nSymbolType[XRAN_NUM_OF_SYMBOL_PER_SLOT - 1] == 0)
|
||||
continue;
|
||||
// skip processing this slot if the last symbol in the slot is TX
|
||||
// (no RX in this slot)
|
||||
// This loop would better be more inner to avoid confusion and maybe also errors.
|
||||
for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) {
|
||||
/* the callback is for mixed and UL slots. In mixed, we have to
|
||||
* skip DL and guard symbols. */
|
||||
if (fh_config->frame_conf.sSlotConfig[slot_in_period].nSymbolType[sym_idx] != 1 /* UL */)
|
||||
continue;
|
||||
|
||||
uint8_t *pData;
|
||||
uint8_t *pPrbMapData = xran_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_rx_per_ru]
|
||||
.sBufferList.pBuffers->pData;
|
||||
struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData;
|
||||
|
||||
struct xran_prb_elm *pRbElm = &pPrbMap->prbMap[0];
|
||||
struct xran_section_desc *p_sec_desc = pRbElm->p_sec_desc[sym_idx][0];
|
||||
uint32_t one_rb_size =
|
||||
(((pRbElm->iqWidth == 0) || (pRbElm->iqWidth == 16)) ? (N_SC_PER_PRB * 2 * 2) : (3 * pRbElm->iqWidth + 1));
|
||||
if (fh_init->mtu < pRbElm->nRBSize * one_rb_size)
|
||||
pData = xran_ctx->sFrontHaulRxBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_rx_per_ru]
|
||||
.sBufferList.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT]
|
||||
.pData;
|
||||
else
|
||||
pData = p_sec_desc->pData;
|
||||
ptr = pData;
|
||||
pos = (int32_t *)(start_ptr + (4 * sym_idx * 4096));
|
||||
|
||||
uint8_t *u8dptr;
|
||||
struct xran_prb_map *pRbMap = pPrbMap;
|
||||
AssertFatal(ptr != NULL, "ptr NULL\n");
|
||||
AssertFatal(pos != NULL, "pos NULL\n");
|
||||
if (1) {
|
||||
uint32_t idxElm = 0;
|
||||
u8dptr = (uint8_t *)ptr;
|
||||
int16_t payload_len = 0;
|
||||
|
||||
uint8_t *src = (uint8_t *)u8dptr;
|
||||
|
||||
LOG_D(PHY, "pRbMap->nPrbElm %d\n", pRbMap->nPrbElm);
|
||||
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
|
||||
LOG_D(PHY,
|
||||
"prbMap[%d] : PRBstart %d nPRBs %d\n",
|
||||
idxElm,
|
||||
pRbMap->prbMap[idxElm].nRBStart,
|
||||
pRbMap->prbMap[idxElm].nRBSize);
|
||||
pRbElm = &pRbMap->prbMap[idxElm];
|
||||
int pos_len = 0;
|
||||
int neg_len = 0;
|
||||
|
||||
if (pRbElm->nRBStart < (nPRBs >> 1)) // there are PRBs left of DC
|
||||
neg_len = min((nPRBs * 6) - (pRbElm->nRBStart * 12), pRbElm->nRBSize * N_SC_PER_PRB);
|
||||
pos_len = (pRbElm->nRBSize * N_SC_PER_PRB) - neg_len;
|
||||
|
||||
src = pData;
|
||||
// Calculation of the pointer for the section in the buffer.
|
||||
// positive half
|
||||
uint8_t *dst1 = (uint8_t *)(pos + (neg_len == 0 ? ((pRbElm->nRBStart * N_SC_PER_PRB) - (nPRBs * 6)) : 0));
|
||||
// negative half
|
||||
uint8_t *dst2 = (uint8_t *)(pos + (pRbElm->nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6));
|
||||
int32_t local_dst[pRbElm->nRBSize * N_SC_PER_PRB] __attribute__((aligned(64)));
|
||||
if (pRbElm->compMethod == XRAN_COMPMETHOD_NONE) {
|
||||
// NOTE: gcc 11 knows how to generate AVX2 for this!
|
||||
for (idx = 0; idx < pRbElm->nRBSize * N_SC_PER_PRB * 2; idx++)
|
||||
((int16_t *)local_dst)[idx] = ((int16_t)ntohs(((uint16_t *)src)[idx])) >> 2;
|
||||
memcpy((void *)dst2, (void *)local_dst, neg_len * 4);
|
||||
memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4);
|
||||
} else if (pRbElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) {
|
||||
struct xranlib_decompress_request bfp_decom_req;
|
||||
struct xranlib_decompress_response bfp_decom_rsp;
|
||||
|
||||
payload_len = (3 * pRbElm->iqWidth + 1) * pRbElm->nRBSize;
|
||||
|
||||
memset(&bfp_decom_req, 0, sizeof(struct xranlib_decompress_request));
|
||||
memset(&bfp_decom_rsp, 0, sizeof(struct xranlib_decompress_response));
|
||||
|
||||
bfp_decom_req.data_in = (int8_t *)src;
|
||||
bfp_decom_req.numRBs = pRbElm->nRBSize;
|
||||
bfp_decom_req.len = payload_len;
|
||||
bfp_decom_req.compMethod = pRbElm->compMethod;
|
||||
bfp_decom_req.iqWidth = pRbElm->iqWidth;
|
||||
|
||||
bfp_decom_rsp.data_out = (int16_t *)local_dst;
|
||||
bfp_decom_rsp.len = 0;
|
||||
|
||||
xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp);
|
||||
memcpy((void *)dst2, (void *)local_dst, neg_len * 4);
|
||||
memcpy((void *)dst1, (void *)&local_dst[neg_len], pos_len * 4);
|
||||
outcnt++;
|
||||
} else {
|
||||
printf("pRbElm->compMethod == %d is not supported\n", pRbElm->compMethod);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} // sym_ind
|
||||
} // ant_ind
|
||||
} // vv_inf
|
||||
if ((*frame & 0x7f) == 0 && *slot == 0 && xran_get_common_counters(gxran_handle, &x_counters[0]) == XRAN_STATUS_SUCCESS) {
|
||||
for (int o_xu_id = 0; o_xu_id < fh_init->xran_ports; o_xu_id++) {
|
||||
LOG_I(NR_PHY,
|
||||
"[%s%d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld][Total Msgs_Rcvd %ld]\n",
|
||||
"o-du ",
|
||||
o_xu_id,
|
||||
x_counters[o_xu_id].rx_counter,
|
||||
x_counters[o_xu_id].rx_counter - old_rx_counter[o_xu_id],
|
||||
x_counters[o_xu_id].rx_bytes_per_sec * 8 / 1000L,
|
||||
x_counters[o_xu_id].tx_counter,
|
||||
x_counters[o_xu_id].tx_counter - old_tx_counter[o_xu_id],
|
||||
x_counters[o_xu_id].tx_bytes_per_sec * 8 / 1000L,
|
||||
x_counters[o_xu_id].Total_msgs_rcvd);
|
||||
for (int rxant = 0; rxant < ru->nb_rx / fh_init->xran_ports; rxant++)
|
||||
LOG_I(NR_PHY,
|
||||
"[%s%d][pusch%d %7ld prach%d %7ld]\n",
|
||||
"o_du",
|
||||
o_xu_id,
|
||||
rxant,
|
||||
x_counters[o_xu_id].rx_pusch_packets[rxant],
|
||||
rxant,
|
||||
x_counters[o_xu_id].rx_prach_packets[rxant]);
|
||||
if (x_counters[o_xu_id].rx_counter > old_rx_counter[o_xu_id])
|
||||
old_rx_counter[o_xu_id] = x_counters[o_xu_id].rx_counter;
|
||||
if (x_counters[o_xu_id].tx_counter > old_tx_counter[o_xu_id])
|
||||
old_tx_counter[o_xu_id] = x_counters[o_xu_id].tx_counter;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp)
|
||||
{
|
||||
int tti = /*frame*SUBFRAMES_PER_SYSTEMFRAME*SLOTNUM_PER_SUBFRAME+*/ 20 * frame
|
||||
+ slot; // commented out temporarily to check that compilation of oran 5g is working.
|
||||
|
||||
void *ptr = NULL;
|
||||
int32_t *pos = NULL;
|
||||
int idx = 0;
|
||||
|
||||
struct xran_device_ctx *xran_ctx = xran_dev_get_ctx();
|
||||
const struct xran_fh_init *fh_init = &xran_ctx->fh_init;
|
||||
int nPRBs = xran_ctx->fh_cfg.nDLRBs;
|
||||
int fftsize = 1 << xran_ctx->fh_cfg.ru_conf.fftSize;
|
||||
int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports;
|
||||
|
||||
for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet.
|
||||
for (uint8_t ant_id = 0; ant_id < ru->nb_tx; ant_id++) {
|
||||
xran_ctx = xran_dev_get_ctx_by_id(ant_id / nb_tx_per_ru);
|
||||
// This loop would better be more inner to avoid confusion and maybe also errors.
|
||||
for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) {
|
||||
uint8_t *pData = xran_ctx->sFrontHaulTxBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_tx_per_ru]
|
||||
.sBufferList.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT]
|
||||
.pData;
|
||||
uint8_t *pPrbMapData = xran_ctx->sFrontHaulTxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_tx_per_ru]
|
||||
.sBufferList.pBuffers->pData;
|
||||
struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData;
|
||||
ptr = pData;
|
||||
pos =
|
||||
&ru->txdataF_BF[ant_id][sym_idx * 4096 /*fp->ofdm_symbol_size*/]; // We had to use a different ru structure than benetel
|
||||
// so the access to the buffer is not the same.
|
||||
|
||||
uint8_t *u8dptr;
|
||||
struct xran_prb_map *pRbMap = pPrbMap;
|
||||
int32_t sym_id = sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT;
|
||||
if (ptr && pos) {
|
||||
uint32_t idxElm = 0;
|
||||
u8dptr = (uint8_t *)ptr;
|
||||
int16_t payload_len = 0;
|
||||
|
||||
uint8_t *dst = (uint8_t *)u8dptr;
|
||||
|
||||
struct xran_prb_elm *p_prbMapElm = &pRbMap->prbMap[idxElm];
|
||||
|
||||
for (idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++) {
|
||||
struct xran_section_desc *p_sec_desc = NULL;
|
||||
p_prbMapElm = &pRbMap->prbMap[idxElm];
|
||||
p_sec_desc =
|
||||
// assumes one fragment per symbol
|
||||
p_prbMapElm->p_sec_desc[sym_id][0];
|
||||
|
||||
dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod);
|
||||
|
||||
if (p_sec_desc == NULL) {
|
||||
printf("p_sec_desc == NULL\n");
|
||||
exit(-1);
|
||||
}
|
||||
uint16_t *dst16 = (uint16_t *)dst;
|
||||
|
||||
int pos_len = 0;
|
||||
int neg_len = 0;
|
||||
|
||||
if (p_prbMapElm->nRBStart < (nPRBs >> 1)) // there are PRBs left of DC
|
||||
neg_len = min((nPRBs * 6) - (p_prbMapElm->nRBStart * 12), p_prbMapElm->nRBSize * N_SC_PER_PRB);
|
||||
pos_len = (p_prbMapElm->nRBSize * N_SC_PER_PRB) - neg_len;
|
||||
// Calculation of the pointer for the section in the buffer.
|
||||
// start of positive frequency component
|
||||
uint16_t *src1 = (uint16_t *)&pos[(neg_len == 0) ? ((p_prbMapElm->nRBStart * N_SC_PER_PRB) - (nPRBs * 6)) : 0];
|
||||
// start of negative frequency component
|
||||
uint16_t *src2 = (uint16_t *)&pos[(p_prbMapElm->nRBStart * N_SC_PER_PRB) + fftsize - (nPRBs * 6)];
|
||||
|
||||
uint32_t local_src[p_prbMapElm->nRBSize * N_SC_PER_PRB] __attribute__((aligned(64)));
|
||||
memcpy((void *)local_src, (void *)src2, neg_len * 4);
|
||||
memcpy((void *)&local_src[neg_len], (void *)src1, pos_len * 4);
|
||||
if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_NONE) {
|
||||
payload_len = p_prbMapElm->nRBSize * N_SC_PER_PRB * 4L;
|
||||
/* convert to Network order */
|
||||
// NOTE: ggc 11 knows how to generate AVX2 for this!
|
||||
for (idx = 0; idx < (pos_len + neg_len) * 2; idx++)
|
||||
((uint16_t *)dst16)[idx] = htons(((uint16_t *)local_src)[idx]);
|
||||
} else if (p_prbMapElm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) {
|
||||
struct xranlib_compress_request bfp_com_req;
|
||||
struct xranlib_compress_response bfp_com_rsp;
|
||||
payload_len = (3 * p_prbMapElm->iqWidth + 1) * p_prbMapElm->nRBSize;
|
||||
memset(&bfp_com_req, 0, sizeof(struct xranlib_compress_request));
|
||||
memset(&bfp_com_rsp, 0, sizeof(struct xranlib_compress_response));
|
||||
|
||||
bfp_com_req.data_in = (int16_t *)local_src;
|
||||
bfp_com_req.numRBs = p_prbMapElm->nRBSize;
|
||||
bfp_com_req.len = payload_len;
|
||||
bfp_com_req.compMethod = p_prbMapElm->compMethod;
|
||||
bfp_com_req.iqWidth = p_prbMapElm->iqWidth;
|
||||
|
||||
bfp_com_rsp.data_out = (int8_t *)dst;
|
||||
bfp_com_rsp.len = 0;
|
||||
|
||||
xranlib_compress_avx512(&bfp_com_req, &bfp_com_rsp);
|
||||
|
||||
} else {
|
||||
printf("p_prbMapElm->compMethod == %d is not supported\n", p_prbMapElm->compMethod);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
p_sec_desc->iq_buffer_offset = RTE_PTR_DIFF(dst, u8dptr);
|
||||
p_sec_desc->iq_buffer_len = payload_len;
|
||||
|
||||
dst += payload_len;
|
||||
dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod);
|
||||
}
|
||||
|
||||
// The tti should be updated as it increased.
|
||||
pRbMap->tti_id = tti;
|
||||
|
||||
} else {
|
||||
printf("ptr ==NULL\n");
|
||||
exit(-1); // fails here??
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef OAIORAN_H
|
||||
#define OAIORAN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "xran_fh_o_du.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t tti;
|
||||
uint32_t sl;
|
||||
uint32_t f;
|
||||
} oran_sync_info_t;
|
||||
|
||||
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status);
|
||||
int oai_physide_dl_tti_call_back(void *param);
|
||||
|
||||
#endif /* OAIORAN_H */
|
||||
@@ -0,0 +1,886 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "oran-config.h"
|
||||
#include "oran-params.h"
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common_lib.h"
|
||||
|
||||
#include "xran_fh_o_du.h"
|
||||
#include "xran_cp_api.h"
|
||||
#include "rte_ether.h"
|
||||
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
static void print_fh_eowd_cmn(unsigned index, const struct xran_ecpri_del_meas_cmn *eowd_cmn)
|
||||
{
|
||||
printf("\
|
||||
eowd_cmn[%d]:\n\
|
||||
initiator_en %d\n\
|
||||
numberOfSamples %d\n\
|
||||
filterType %d\n\
|
||||
responseTo %ld\n\
|
||||
measVf %d\n\
|
||||
measState %d\n\
|
||||
measId %d\n\
|
||||
measMethod %d\n\
|
||||
owdm_enable %d\n\
|
||||
owdm_PlLength %d\n",
|
||||
index,
|
||||
eowd_cmn->initiator_en,
|
||||
eowd_cmn->numberOfSamples,
|
||||
eowd_cmn->filterType,
|
||||
eowd_cmn->responseTo,
|
||||
eowd_cmn->measVf,
|
||||
eowd_cmn->measState,
|
||||
eowd_cmn->measId,
|
||||
eowd_cmn->measMethod,
|
||||
eowd_cmn->owdm_enable,
|
||||
eowd_cmn->owdm_PlLength);
|
||||
}
|
||||
|
||||
static void print_fh_eowd_port(unsigned index, unsigned vf, const struct xran_ecpri_del_meas_port *eowd_port)
|
||||
{
|
||||
printf("\
|
||||
eowd_port[%d][%d]:\n\
|
||||
t1 %ld\n\
|
||||
t2 %ld\n\
|
||||
tr %ld\n\
|
||||
delta %ld\n\
|
||||
portid %d\n\
|
||||
runMeas %d\n\
|
||||
currentMeasID %d\n\
|
||||
msState %d\n\
|
||||
numMeas %d\n\
|
||||
txDone %d\n\
|
||||
rspTimerIdx %ld\n\
|
||||
delaySamples [%ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld, %ld]\n\
|
||||
delayAvg %ld\n",
|
||||
index,
|
||||
vf,
|
||||
eowd_port->t1,
|
||||
eowd_port->t2,
|
||||
eowd_port->tr,
|
||||
eowd_port->delta,
|
||||
eowd_port->portid,
|
||||
eowd_port->runMeas,
|
||||
eowd_port->currentMeasID,
|
||||
eowd_port->msState,
|
||||
eowd_port->numMeas,
|
||||
eowd_port->txDone,
|
||||
eowd_port->rspTimerIdx,
|
||||
eowd_port->delaySamples[0],
|
||||
eowd_port->delaySamples[1],
|
||||
eowd_port->delaySamples[2],
|
||||
eowd_port->delaySamples[3],
|
||||
eowd_port->delaySamples[4],
|
||||
eowd_port->delaySamples[5],
|
||||
eowd_port->delaySamples[6],
|
||||
eowd_port->delaySamples[7],
|
||||
eowd_port->delaySamples[8],
|
||||
eowd_port->delaySamples[9],
|
||||
eowd_port->delaySamples[10],
|
||||
eowd_port->delaySamples[11],
|
||||
eowd_port->delaySamples[12],
|
||||
eowd_port->delaySamples[13],
|
||||
eowd_port->delaySamples[14],
|
||||
eowd_port->delaySamples[15],
|
||||
eowd_port->delayAvg);
|
||||
}
|
||||
|
||||
static void print_fh_init_io_cfg(const struct xran_io_cfg *io_cfg)
|
||||
{
|
||||
printf("\
|
||||
io_cfg:\n\
|
||||
id %d (%s)\n\
|
||||
num_vfs %d\n\
|
||||
num_rxq %d\n\
|
||||
dpdk_dev [%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s]\n\
|
||||
bbdev_dev %s\n\
|
||||
bbdev_mode %d\n\
|
||||
dpdkIoVaMode %d\n\
|
||||
dpdkMemorySize %d\n",
|
||||
io_cfg->id,
|
||||
io_cfg->id == 0 ? "O-DU" : "O-RU",
|
||||
io_cfg->num_vfs,
|
||||
io_cfg->num_rxq,
|
||||
io_cfg->dpdk_dev[XRAN_UP_VF],
|
||||
io_cfg->dpdk_dev[XRAN_CP_VF],
|
||||
io_cfg->dpdk_dev[XRAN_UP_VF1],
|
||||
io_cfg->dpdk_dev[XRAN_CP_VF1],
|
||||
io_cfg->dpdk_dev[XRAN_UP_VF2],
|
||||
io_cfg->dpdk_dev[XRAN_CP_VF2],
|
||||
io_cfg->dpdk_dev[XRAN_UP_VF3],
|
||||
io_cfg->dpdk_dev[XRAN_CP_VF3],
|
||||
io_cfg->dpdk_dev[XRAN_UP_VF4],
|
||||
io_cfg->dpdk_dev[XRAN_CP_VF4],
|
||||
io_cfg->dpdk_dev[XRAN_UP_VF5],
|
||||
io_cfg->dpdk_dev[XRAN_CP_VF5],
|
||||
io_cfg->dpdk_dev[XRAN_UP_VF6],
|
||||
io_cfg->dpdk_dev[XRAN_CP_VF6],
|
||||
io_cfg->dpdk_dev[XRAN_UP_VF7],
|
||||
io_cfg->dpdk_dev[XRAN_CP_VF7],
|
||||
io_cfg->bbdev_dev[0],
|
||||
io_cfg->bbdev_mode,
|
||||
io_cfg->dpdkIoVaMode,
|
||||
io_cfg->dpdkMemorySize);
|
||||
|
||||
printf("\
|
||||
core %d\n\
|
||||
system_core %d\n\
|
||||
pkt_proc_core %016lx\n\
|
||||
pkt_proc_core_64_127 %016lx\n\
|
||||
pkt_aux_core %d\n\
|
||||
timing_core %d\n\
|
||||
port [%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, ]\n\
|
||||
io_sleep %d\n\
|
||||
nEthLinePerPort %d\n\
|
||||
nEthLineSpeed %d\n\
|
||||
one_vf_cu_plane %d\n",
|
||||
io_cfg->core,
|
||||
io_cfg->system_core,
|
||||
io_cfg->pkt_proc_core,
|
||||
io_cfg->pkt_proc_core_64_127,
|
||||
io_cfg->pkt_aux_core,
|
||||
io_cfg->timing_core,
|
||||
io_cfg->port[XRAN_UP_VF],
|
||||
io_cfg->port[XRAN_CP_VF],
|
||||
io_cfg->port[XRAN_UP_VF1],
|
||||
io_cfg->port[XRAN_CP_VF1],
|
||||
io_cfg->port[XRAN_UP_VF2],
|
||||
io_cfg->port[XRAN_CP_VF2],
|
||||
io_cfg->port[XRAN_UP_VF3],
|
||||
io_cfg->port[XRAN_CP_VF3],
|
||||
io_cfg->port[XRAN_UP_VF4],
|
||||
io_cfg->port[XRAN_CP_VF4],
|
||||
io_cfg->port[XRAN_UP_VF5],
|
||||
io_cfg->port[XRAN_CP_VF5],
|
||||
io_cfg->port[XRAN_UP_VF6],
|
||||
io_cfg->port[XRAN_CP_VF6],
|
||||
io_cfg->port[XRAN_UP_VF7],
|
||||
io_cfg->port[XRAN_CP_VF7],
|
||||
io_cfg->io_sleep,
|
||||
io_cfg->nEthLinePerPort,
|
||||
io_cfg->nEthLineSpeed,
|
||||
io_cfg->one_vf_cu_plane);
|
||||
print_fh_eowd_cmn(0, &io_cfg->eowd_cmn[0]);
|
||||
print_fh_eowd_cmn(1, &io_cfg->eowd_cmn[1]);
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for (int v = 0; v < io_cfg->num_vfs; ++v)
|
||||
print_fh_eowd_port(i, v, &io_cfg->eowd_port[i][v]);
|
||||
}
|
||||
|
||||
static void print_fh_init_eaxcid_conf(const struct xran_eaxcid_config *eaxcid_conf)
|
||||
{
|
||||
printf("\
|
||||
eAxCId_conf:\n\
|
||||
mask_cuPortId 0x%04x\n\
|
||||
mask_bandSectorId 0x%04x\n\
|
||||
mask_ccId 0x%04x\n\
|
||||
mask_ruPortId 0x%04x\n\
|
||||
bit_cuPortId %d\n\
|
||||
bit_bandSectorId %d\n\
|
||||
bit_ccId %d\n\
|
||||
bit_ruPortId %d\n",
|
||||
eaxcid_conf->mask_cuPortId,
|
||||
eaxcid_conf->mask_bandSectorId,
|
||||
eaxcid_conf->mask_ccId,
|
||||
eaxcid_conf->mask_ruPortId,
|
||||
eaxcid_conf->bit_cuPortId,
|
||||
eaxcid_conf->bit_bandSectorId,
|
||||
eaxcid_conf->bit_ccId,
|
||||
eaxcid_conf->bit_ruPortId);
|
||||
}
|
||||
|
||||
static void print_ether_addr(const char *pre, int num_ether, const struct rte_ether_addr *addrs)
|
||||
{
|
||||
printf("%s [", pre);
|
||||
for (int i = 0; i < num_ether; ++i) {
|
||||
char buf[18];
|
||||
rte_ether_format_addr(buf, 18, &addrs[i]);
|
||||
printf("%s", buf);
|
||||
if (i != num_ether - 1)
|
||||
printf(", ");
|
||||
}
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void print_fh_init(const struct xran_fh_init *fh_init)
|
||||
{
|
||||
printf("xran_fh_init:\n");
|
||||
print_fh_init_io_cfg(&fh_init->io_cfg);
|
||||
print_fh_init_eaxcid_conf(&fh_init->eAxCId_conf);
|
||||
printf("\
|
||||
xran_ports %d\n\
|
||||
dpdkBasebandFecMode %d\n\
|
||||
dpdkBasebandDevice %s\n\
|
||||
filePrefix %s\n\
|
||||
mtu %d\n",
|
||||
fh_init->xran_ports,
|
||||
fh_init->dpdkBasebandFecMode,
|
||||
fh_init->dpdkBasebandDevice,
|
||||
fh_init->filePrefix,
|
||||
fh_init->mtu);
|
||||
print_ether_addr(" p_o_du_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_du_addr);
|
||||
print_ether_addr(" p_o_ru_addr", fh_init->xran_ports * fh_init->io_cfg.num_vfs, (struct rte_ether_addr *)fh_init->p_o_ru_addr);
|
||||
printf("\
|
||||
totalBfWeights %d\n",
|
||||
fh_init->totalBfWeights);
|
||||
}
|
||||
|
||||
static void print_prach_config(const struct xran_prach_config *prach_conf)
|
||||
{
|
||||
printf("\
|
||||
prach_config:\n\
|
||||
nPrachConfIdx %d\n\
|
||||
nPrachSubcSpacing %d\n\
|
||||
nPrachZeroCorrConf %d\n\
|
||||
nPrachRestrictSet %d\n\
|
||||
nPrachRootSeqIdx %d\n\
|
||||
nPrachFreqStart %d\n\
|
||||
nPrachFreqOffset %d\n\
|
||||
nPrachFilterIdx %d\n\
|
||||
startSymId %d\n\
|
||||
lastSymId %d\n\
|
||||
startPrbc %d\n\
|
||||
numPrbc %d\n\
|
||||
timeOffset %d\n\
|
||||
freqOffset %d\n\
|
||||
eAxC_offset %d\n",
|
||||
prach_conf->nPrachConfIdx,
|
||||
prach_conf->nPrachSubcSpacing,
|
||||
prach_conf->nPrachZeroCorrConf,
|
||||
prach_conf->nPrachRestrictSet,
|
||||
prach_conf->nPrachRootSeqIdx,
|
||||
prach_conf->nPrachFreqStart,
|
||||
prach_conf->nPrachFreqOffset,
|
||||
prach_conf->nPrachFilterIdx,
|
||||
prach_conf->startSymId,
|
||||
prach_conf->lastSymId,
|
||||
prach_conf->startPrbc,
|
||||
prach_conf->numPrbc,
|
||||
prach_conf->timeOffset,
|
||||
prach_conf->freqOffset,
|
||||
prach_conf->eAxC_offset);
|
||||
}
|
||||
|
||||
static void print_srs_config(const struct xran_srs_config *srs_conf)
|
||||
{
|
||||
printf("\
|
||||
srs_config:\n\
|
||||
symbMask %04x\n\
|
||||
eAxC_offset %d\n",
|
||||
srs_conf->symbMask,
|
||||
srs_conf->eAxC_offset);
|
||||
}
|
||||
|
||||
static void print_frame_config(const struct xran_frame_config *frame_conf)
|
||||
{
|
||||
printf("\
|
||||
frame_conf:\n\
|
||||
nFrameDuplexType %s\n\
|
||||
nNumerology %d\n\
|
||||
nTddPeriod %d\n",
|
||||
frame_conf->nFrameDuplexType == XRAN_TDD ? "TDD" : "FDD",
|
||||
frame_conf->nNumerology,
|
||||
frame_conf->nTddPeriod);
|
||||
for (int i = 0; i < frame_conf->nTddPeriod; ++i) {
|
||||
printf(" sSlotConfig[%d]: ", i);
|
||||
for (int s = 0; s < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++s) {
|
||||
uint8_t nSymbolType = frame_conf->sSlotConfig[i].nSymbolType[s];
|
||||
printf("%c", nSymbolType == 0 ? 'D' : (nSymbolType == 1 ? 'U' : 'G'));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void print_ru_config(const struct xran_ru_config *ru_conf)
|
||||
{
|
||||
printf("\
|
||||
ru_config:\n\
|
||||
xranTech %s\n\
|
||||
xranCat %s\n\
|
||||
xranCompHdrType %s\n\
|
||||
iqWidth %d\n\
|
||||
compMeth %d\n\
|
||||
iqWidth_PRACH %d\n\
|
||||
compMeth_PRACH %d\n\
|
||||
fftSize %d\n\
|
||||
byteOrder %s\n\
|
||||
iqOrder %s\n\
|
||||
xran_max_frame %d\n",
|
||||
ru_conf->xranTech == XRAN_RAN_5GNR ? "NR" : "LTE",
|
||||
ru_conf->xranCat == XRAN_CATEGORY_A ? "A" : "B",
|
||||
ru_conf->xranCompHdrType == XRAN_COMP_HDR_TYPE_DYNAMIC ? "dynamic" : "static",
|
||||
ru_conf->iqWidth,
|
||||
ru_conf->compMeth,
|
||||
ru_conf->iqWidth_PRACH,
|
||||
ru_conf->compMeth_PRACH,
|
||||
ru_conf->fftSize,
|
||||
ru_conf->byteOrder == XRAN_NE_BE_BYTE_ORDER ? "network/BE" : "CPU/LE",
|
||||
ru_conf->iqOrder == XRAN_I_Q_ORDER ? "I_Q" : "Q_I",
|
||||
ru_conf->xran_max_frame);
|
||||
}
|
||||
|
||||
void print_fh_config(const struct xran_fh_config *fh_config)
|
||||
{
|
||||
printf("xran_fh_config:\n");
|
||||
printf("\
|
||||
dpdk_port %d\n\
|
||||
sector_id %d\n\
|
||||
nCC %d\n\
|
||||
neAxc %d\n\
|
||||
neAxcUl %d\n\
|
||||
nAntElmTRx %d\n\
|
||||
nDLFftSize %d\n\
|
||||
nULFftSize %d\n\
|
||||
nDLRBs %d\n\
|
||||
nULRBs %d\n\
|
||||
nDLAbsFrePointA %d\n\
|
||||
nULAbsFrePointA %d\n\
|
||||
nDLCenterFreqARFCN %d\n\
|
||||
nULCenterFreqARFCN %d\n\
|
||||
ttiCb %p\n\
|
||||
ttiCbParam %p\n",
|
||||
fh_config->dpdk_port,
|
||||
fh_config->sector_id,
|
||||
fh_config->nCC,
|
||||
fh_config->neAxc,
|
||||
fh_config->neAxcUl,
|
||||
fh_config->nAntElmTRx,
|
||||
fh_config->nDLFftSize,
|
||||
fh_config->nULFftSize,
|
||||
fh_config->nDLRBs,
|
||||
fh_config->nULRBs,
|
||||
fh_config->nDLAbsFrePointA,
|
||||
fh_config->nULAbsFrePointA,
|
||||
fh_config->nDLCenterFreqARFCN,
|
||||
fh_config->nULCenterFreqARFCN,
|
||||
fh_config->ttiCb,
|
||||
fh_config->ttiCbParam);
|
||||
|
||||
printf("\
|
||||
Tadv_cp_dl %d\n\
|
||||
T2a_min_cp_dl %d\n\
|
||||
T2a_max_cp_dl %d\n\
|
||||
T2a_min_cp_ul %d\n\
|
||||
T2a_max_cp_ul %d\n\
|
||||
T2a_min_up %d\n\
|
||||
T2a_max_up %d\n\
|
||||
Ta3_min %d\n\
|
||||
Ta3_max %d\n\
|
||||
T1a_min_cp_dl %d\n\
|
||||
T1a_max_cp_dl %d\n\
|
||||
T1a_min_cp_ul %d\n\
|
||||
T1a_max_cp_ul %d\n\
|
||||
T1a_min_up %d\n\
|
||||
T1a_max_up %d\n\
|
||||
Ta4_min %d\n\
|
||||
Ta4_max %d\n",
|
||||
fh_config->Tadv_cp_dl,
|
||||
fh_config->T2a_min_cp_dl,
|
||||
fh_config->T2a_max_cp_dl,
|
||||
fh_config->T2a_min_cp_ul,
|
||||
fh_config->T2a_max_cp_ul,
|
||||
fh_config->T2a_min_up,
|
||||
fh_config->T2a_max_up,
|
||||
fh_config->Ta3_min,
|
||||
fh_config->Ta3_max,
|
||||
fh_config->T1a_min_cp_dl,
|
||||
fh_config->T1a_max_cp_dl,
|
||||
fh_config->T1a_min_cp_ul,
|
||||
fh_config->T1a_max_cp_ul,
|
||||
fh_config->T1a_min_up,
|
||||
fh_config->T1a_max_up,
|
||||
fh_config->Ta4_min,
|
||||
fh_config->Ta4_max);
|
||||
|
||||
printf("\
|
||||
enableCP %d\n\
|
||||
prachEnable %d\n\
|
||||
srsEnable %d\n\
|
||||
puschMaskEnable %d\n\
|
||||
puschMaskSlot %d\n\
|
||||
cp_vlan_tag %d\n\
|
||||
up_vlan_tag %d\n\
|
||||
debugStop %d\n\
|
||||
debugStopCount %d\n\
|
||||
DynamicSectionEna %d\n\
|
||||
GPS_Alpha %d\n\
|
||||
GPS_Beta %d\n",
|
||||
fh_config->enableCP,
|
||||
fh_config->prachEnable,
|
||||
fh_config->srsEnable,
|
||||
fh_config->puschMaskEnable,
|
||||
fh_config->puschMaskSlot,
|
||||
fh_config->cp_vlan_tag,
|
||||
fh_config->up_vlan_tag,
|
||||
fh_config->debugStop,
|
||||
fh_config->debugStopCount,
|
||||
fh_config->DynamicSectionEna,
|
||||
fh_config->GPS_Alpha,
|
||||
fh_config->GPS_Beta);
|
||||
|
||||
print_prach_config(&fh_config->prach_conf);
|
||||
print_srs_config(&fh_config->srs_conf);
|
||||
print_frame_config(&fh_config->frame_conf);
|
||||
print_ru_config(&fh_config->ru_conf);
|
||||
|
||||
printf("\
|
||||
bbdev_enc %p\n\
|
||||
bbdev_dec %p\n\
|
||||
tx_cp_eAxC2Vf [not implemented by fhi_lib]\n\
|
||||
tx_up_eAxC2Vf [not implemented by fhi_lib]\n\
|
||||
rx_cp_eAxC2Vf [not implemented by fhi_lib]\n\
|
||||
rx_up_eAxC2Vf [not implemented by fhi_lib]\n\
|
||||
log_level %d\n\
|
||||
max_sections_per_slot %d\n\
|
||||
max_sections_per_symbol %d\n",
|
||||
fh_config->bbdev_enc,
|
||||
fh_config->bbdev_dec,
|
||||
fh_config->log_level,
|
||||
fh_config->max_sections_per_slot,
|
||||
fh_config->max_sections_per_symbol);
|
||||
}
|
||||
|
||||
static const paramdef_t *gpd(const paramdef_t *pd, int num, const char *name)
|
||||
{
|
||||
/* the config module does not know const-correctness... */
|
||||
int idx = config_paramidx_fromname((paramdef_t *)pd, num, (char *)name);
|
||||
DevAssert(idx >= 0);
|
||||
return &pd[idx];
|
||||
}
|
||||
|
||||
static uint64_t get_u64_mask(const paramdef_t *pd)
|
||||
{
|
||||
DevAssert(pd != NULL);
|
||||
AssertFatal(pd->numelt > 0, "no entries for creation of mask\n");
|
||||
uint64_t mask = 0;
|
||||
for (int i = 0; i < pd->numelt; ++i) {
|
||||
int num = pd->iptr[i];
|
||||
AssertFatal(num >= 0 && num < 64, "cannot put element of %d in 64-bit mask\n", num);
|
||||
mask |= 1 << num;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump)
|
||||
{
|
||||
DevAssert(fhip != NULL);
|
||||
int num_dev = gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->numelt;
|
||||
AssertFatal(num_dev > 0, "need to provide DPDK devices for O-RAN 7.2 Fronthaul\n");
|
||||
AssertFatal(num_dev < 17, "too many DPDK devices for O-RAN 7.2 Fronthaul\n");
|
||||
|
||||
io_cfg->id = 0; // 0 = O-DU
|
||||
io_cfg->num_vfs = num_dev;
|
||||
io_cfg->num_rxq = 2; // Assume two HW RX queues per RU
|
||||
for (int i = 0; i < num_dev; ++i)
|
||||
io_cfg->dpdk_dev[i] = strdup(gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->strlistptr[i]);
|
||||
//io_cfg->bbdev_dev = NULL;
|
||||
io_cfg->bbdev_mode = XRAN_BBDEV_NOT_USED; // none
|
||||
io_cfg->dpdkIoVaMode = 0; /* IOVA mode */
|
||||
io_cfg->dpdkMemorySize = 0; /* DPDK memory size */
|
||||
io_cfg->core = *gpd(fhip, nump, ORAN_CONFIG_IO_CORE)->iptr;
|
||||
io_cfg->system_core = 0; /* TODO how called in sample app? */
|
||||
io_cfg->pkt_proc_core = get_u64_mask(gpd(fhip, nump, ORAN_CONFIG_WORKER_CORES));
|
||||
io_cfg->pkt_proc_core_64_127 = 0x0; // bitmap 0 -> no core
|
||||
io_cfg->pkt_aux_core = 0; /* sapmle app says 0 = "do not start" */
|
||||
io_cfg->timing_core = *gpd(fhip, nump, ORAN_CONFIG_IO_CORE)->iptr; /* sample app: equal to io_core */
|
||||
//io_cfg->port = {0}; // all 0
|
||||
io_cfg->io_sleep = 0; // no sleep
|
||||
io_cfg->nEthLinePerPort = *gpd(fhip, nump, ORAN_CONFIG_NETHPERPORT)->uptr;
|
||||
io_cfg->nEthLineSpeed = *gpd(fhip, nump, ORAN_CONFIG_NETHSPEED)->uptr;
|
||||
io_cfg->one_vf_cu_plane = 0; // false: C/U-plane don't share VF
|
||||
// io_cfg->eowd_cmn[0] // all 0
|
||||
// io_cfg->eowd_cmn[1] // all 0
|
||||
// io_cfg->eowd_port[0]... // all 0
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fh_eaxcid_conf(struct xran_eaxcid_config *eaxcid_conf, enum xran_category cat)
|
||||
{
|
||||
// values taken from sample app
|
||||
switch (cat) {
|
||||
case XRAN_CATEGORY_A:
|
||||
eaxcid_conf->mask_cuPortId = 0xf000;
|
||||
eaxcid_conf->mask_bandSectorId = 0x0f00;
|
||||
eaxcid_conf->mask_ccId = 0x00f0;
|
||||
eaxcid_conf->mask_ruPortId = 0x000f;
|
||||
eaxcid_conf->bit_cuPortId = 12;
|
||||
eaxcid_conf->bit_bandSectorId = 8;
|
||||
eaxcid_conf->bit_ccId = 4;
|
||||
eaxcid_conf->bit_ruPortId = 0;
|
||||
break;
|
||||
case XRAN_CATEGORY_B:
|
||||
eaxcid_conf->mask_cuPortId = 0xf000;
|
||||
eaxcid_conf->mask_bandSectorId = 0x0c00;
|
||||
eaxcid_conf->mask_ccId = 0x0300;
|
||||
eaxcid_conf->mask_ruPortId = 0x000f;
|
||||
eaxcid_conf->bit_cuPortId = 12;
|
||||
eaxcid_conf->bit_bandSectorId = 10;
|
||||
eaxcid_conf->bit_ccId = 8;
|
||||
eaxcid_conf->bit_ruPortId = 0;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *get_ether_addr(const char *addr, struct rte_ether_addr *ether_addr)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
// the following line disables the deprecated warning
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
int ret = rte_ether_unformat_addr(addr, ether_addr);
|
||||
#pragma GCC diagnostic pop
|
||||
if (ret == 0)
|
||||
return (uint8_t *)ether_addr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool set_fh_init(struct xran_fh_init *fh_init)
|
||||
{
|
||||
memset(fh_init, 0, sizeof(*fh_init));
|
||||
|
||||
// verify oran section is present: we don't have a list but the below returns
|
||||
// numelt > 0 if the block is there
|
||||
paramlist_def_t pl = {0};
|
||||
strncpy(pl.listname, CONFIG_STRING_ORAN, sizeof(pl.listname) - 1);
|
||||
config_getlist(config_get_if(), &pl, NULL, 0, /* prefix */ NULL);
|
||||
if (pl.numelt == 0) {
|
||||
printf("Configuration section \"%s\" not present: cannot initialize fhi_lib!\n", CONFIG_STRING_ORAN);
|
||||
return false;
|
||||
}
|
||||
|
||||
paramdef_t fhip[] = ORAN_GLOBALPARAMS_DESC;
|
||||
int nump = sizeofArray(fhip);
|
||||
int ret = config_get(config_get_if(), fhip, nump, CONFIG_STRING_ORAN);
|
||||
if (ret <= 0) {
|
||||
printf("problem reading section \"%s\"\n", CONFIG_STRING_ORAN);
|
||||
return false;
|
||||
}
|
||||
|
||||
paramdef_t FHconfigs[] = ORAN_FH_DESC;
|
||||
paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH};
|
||||
char aprefix[MAX_OPTNAME_SIZE] = {0};
|
||||
sprintf(aprefix, "%s", CONFIG_STRING_ORAN);
|
||||
const int nfh = sizeofArray(FHconfigs);
|
||||
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
|
||||
int num_rus = FH_ConfigList.numelt;
|
||||
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
|
||||
int num_du_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt;
|
||||
int num_vfs = gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->numelt;
|
||||
if (num_ru_addr != num_du_addr) {
|
||||
printf("need to have same number of DUs and RUs!\n");
|
||||
return false;
|
||||
}
|
||||
if (num_ru_addr != num_vfs) {
|
||||
printf("need to have as many RU/DU entries as DPDK devices (one VF for CP and UP each)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump))
|
||||
return false;
|
||||
if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, XRAN_CATEGORY_A))
|
||||
return false;
|
||||
|
||||
fh_init->xran_ports = num_rus;
|
||||
fh_init->dpdkBasebandFecMode = 0;
|
||||
fh_init->dpdkBasebandDevice = NULL;
|
||||
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr); // see DPDK --file-prefix
|
||||
fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr;
|
||||
|
||||
// if multiple RUs: xran_ethdi_init_dpdk_io() iterates over
|
||||
// &p_o_ru_addr[i]
|
||||
char **du_addrs = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr;
|
||||
fh_init->p_o_du_addr = calloc(num_du_addr, sizeof(struct rte_ether_addr));
|
||||
AssertFatal(fh_init->p_o_du_addr != NULL, "out of memory\n");
|
||||
for (int i = 0; i < num_du_addr; ++i) {
|
||||
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_du_addr;
|
||||
if (get_ether_addr(du_addrs[i], &ea[i]) == NULL) {
|
||||
printf("could not read ethernet address '%s' for DU!\n", du_addrs[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
|
||||
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
|
||||
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
|
||||
for (int i = 0; i < num_ru_addr; ++i) {
|
||||
struct rte_ether_addr *ea = (struct rte_ether_addr *)fh_init->p_o_ru_addr;
|
||||
if (get_ether_addr(ru_addrs[i], &ea[i]) == NULL) {
|
||||
printf("could not read ethernet address '%s' for RU!\n", ru_addrs[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fh_init->totalBfWeights = 32;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum xran_cp_filterindex get_prach_filterindex_fr1(duplex_mode_t mode, int prach_index)
|
||||
{
|
||||
if (mode == duplex_mode_TDD) {
|
||||
// 38.211 table 6.3.3.2-3 "unpaired spectrum" -> TDD
|
||||
switch (prach_index) {
|
||||
case 0 ... 39:
|
||||
case 256 ... 262:
|
||||
return XRAN_FILTERINDEX_PRACH_012;
|
||||
case 40 ... 66:
|
||||
return XRAN_FILTERINDEX_PRACH_3;
|
||||
case 67 ... 255:
|
||||
return XRAN_FILTERINDEX_PRACH_ABC;
|
||||
}
|
||||
} else if (mode == duplex_mode_FDD) {
|
||||
// 38.211 table 6.3.3.2-2 "paired spectrum" -> FDD
|
||||
switch (prach_index) {
|
||||
case 0 ... 59:
|
||||
return XRAN_FILTERINDEX_PRACH_012;
|
||||
case 60 ... 86:
|
||||
return XRAN_FILTERINDEX_PRACH_3;
|
||||
case 87 ... 255:
|
||||
return XRAN_FILTERINDEX_PRACH_ABC;
|
||||
default:
|
||||
AssertFatal(false, "unknown PRACH index %d\n", prach_index);
|
||||
}
|
||||
} else {
|
||||
AssertFatal(false, "unsupported duplex mode %d\n", mode);
|
||||
}
|
||||
return XRAN_FILTERINDEX_STANDARD;
|
||||
}
|
||||
|
||||
// PRACH guard interval. Raymond: "[it] is not in the configuration, (i.e. it
|
||||
// is deterministic depending on others). LiteON must hard-code this in the
|
||||
// O-RU itself, benetel doesn't (as O-RAN specifies). So we will need to tell
|
||||
// the driver what the case is and provide"
|
||||
// this is a hack
|
||||
int g_kbar;
|
||||
|
||||
static bool set_fh_prach_config(const openair0_config_t *oai0,
|
||||
const paramdef_t *prachp,
|
||||
int nprach,
|
||||
struct xran_prach_config *prach_config)
|
||||
{
|
||||
const split7_config_t *s7cfg = &oai0->split7;
|
||||
|
||||
// for FR2, need at least to update nPrachFilterIdx
|
||||
AssertFatal(oai0->nr_band < 100, "can only handle FR1!\n");
|
||||
|
||||
prach_config->nPrachConfIdx = s7cfg->prach_index;
|
||||
prach_config->nPrachSubcSpacing = oai0->nr_scs_for_raster;
|
||||
prach_config->nPrachZeroCorrConf = 0;
|
||||
prach_config->nPrachRestrictSet = 0;
|
||||
prach_config->nPrachRootSeqIdx = 0;
|
||||
prach_config->nPrachFreqStart = s7cfg->prach_freq_start;
|
||||
prach_config->nPrachFreqOffset = (s7cfg->prach_freq_start * 12 - oai0->num_rb_dl * 6) * 2;
|
||||
prach_config->nPrachFilterIdx = get_prach_filterindex_fr1(oai0->duplex_mode, s7cfg->prach_index);
|
||||
prach_config->startSymId = 0;
|
||||
prach_config->lastSymId = 0;
|
||||
prach_config->startPrbc = 0;
|
||||
prach_config->numPrbc = 0;
|
||||
prach_config->timeOffset = 0;
|
||||
prach_config->freqOffset = 0;
|
||||
prach_config->eAxC_offset = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_EAXC_OFFSET)->u8ptr;
|
||||
|
||||
g_kbar = *gpd(prachp, nprach, ORAN_PRACH_CONFIG_KBAR)->uptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fh_srs_config(struct xran_srs_config *srs_config)
|
||||
{
|
||||
srs_config->symbMask = 0;
|
||||
srs_config->eAxC_offset = 8;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame_config *frame_config)
|
||||
{
|
||||
const split7_config_t *s7cfg = &oai0->split7;
|
||||
frame_config->nFrameDuplexType = oai0->duplex_mode == duplex_mode_TDD ? XRAN_TDD : XRAN_FDD;
|
||||
frame_config->nNumerology = oai0->nr_scs_for_raster;
|
||||
frame_config->nTddPeriod = s7cfg->n_tdd_period;
|
||||
|
||||
struct xran_slot_config *sc = &frame_config->sSlotConfig[0];
|
||||
for (int slot = 0; slot < frame_config->nTddPeriod; ++slot)
|
||||
for (int sym = 0; sym < 14; ++sym)
|
||||
sc[slot].nSymbolType[sym] = s7cfg->slot_dirs[slot].sym_dir[sym];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fh_ru_config(const paramdef_t *rup, int nru, struct xran_ru_config *ru_config)
|
||||
{
|
||||
ru_config->xranTech = XRAN_RAN_5GNR;
|
||||
ru_config->xranCat = XRAN_CATEGORY_A;
|
||||
ru_config->xranCompHdrType = XRAN_COMP_HDR_TYPE_STATIC;
|
||||
ru_config->iqWidth = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH)->uptr;
|
||||
AssertFatal(ru_config->iqWidth <= 16, "IQ Width cannot be > 16!\n");
|
||||
ru_config->compMeth = ru_config->iqWidth < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE;
|
||||
ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr;
|
||||
AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n");
|
||||
ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE;
|
||||
ru_config->fftSize = *gpd(rup, nru, ORAN_RU_CONFIG_FFT_SIZE)->uptr;
|
||||
ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER;
|
||||
ru_config->iqOrder = XRAN_I_Q_ORDER;
|
||||
ru_config->xran_max_frame = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_maxmin_pd(const paramdef_t *pd, int num, const char *name, uint16_t *min, uint16_t *max)
|
||||
{
|
||||
const paramdef_t *p = gpd(pd, num, name);
|
||||
if (p->numelt != 2) {
|
||||
printf("parameter list \"%s\" should have exactly two parameters (max&min), but has %d\n", name, num);
|
||||
return false;
|
||||
}
|
||||
*min = p->uptr[0];
|
||||
*max = p->uptr[1];
|
||||
if (*min > *max) {
|
||||
printf("min parameter of \"%s\" is larger than max!\n", name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
extern uint32_t to_nrarfcn(int nr_bandP, uint64_t dl_CarrierFreq, uint8_t scs_index, uint32_t bw);
|
||||
bool set_fh_config(int ru_idx, int num_rus, const openair0_config_t *oai0, struct xran_fh_config *fh_config)
|
||||
{
|
||||
AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n");
|
||||
AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus);
|
||||
DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0);
|
||||
DevAssert(oai0->tx_bw > 0 && oai0->rx_bw > 0);
|
||||
//AssertFatal(oai0->tx_num_channels == oai0->rx_num_channels, "cannot handle unequal number of TX/RX channels\n");
|
||||
DevAssert(oai0->tx_freq[0] > 0);
|
||||
for (int i = 1; i < oai0->tx_num_channels; ++i)
|
||||
DevAssert(oai0->tx_freq[0] == oai0->tx_freq[i]);
|
||||
DevAssert(oai0->rx_freq[0] > 0);
|
||||
for (int i = 1; i < oai0->rx_num_channels; ++i)
|
||||
DevAssert(oai0->rx_freq[0] == oai0->rx_freq[i]);
|
||||
DevAssert(oai0->nr_band > 0);
|
||||
DevAssert(oai0->nr_scs_for_raster > 0);
|
||||
|
||||
// we simply assume that the loading process provides function to_nrarfcn()
|
||||
// to calculate the ARFCN numbers from frequency. That is not clean, but the
|
||||
// best we can do without copy-pasting the function.
|
||||
uint32_t nDLCenterFreqARFCN = to_nrarfcn(oai0->nr_band, oai0->tx_freq[0], oai0->nr_scs_for_raster, oai0->tx_bw);
|
||||
uint32_t nULCenterFreqARFCN = to_nrarfcn(oai0->nr_band, oai0->rx_freq[0], oai0->nr_scs_for_raster, oai0->rx_bw);
|
||||
|
||||
paramdef_t FHconfigs[] = ORAN_FH_DESC;
|
||||
paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH};
|
||||
char aprefix[MAX_OPTNAME_SIZE] = {0};
|
||||
sprintf(aprefix, "%s", CONFIG_STRING_ORAN);
|
||||
const int nfh = sizeofArray(FHconfigs);
|
||||
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
|
||||
if (FH_ConfigList.numelt == 0) {
|
||||
printf("No configuration section \"%s\" found inside \"%s\": cannot initialize fhi_lib!\n", CONFIG_STRING_ORAN_FH, aprefix);
|
||||
return false;
|
||||
}
|
||||
paramdef_t *fhp = FH_ConfigList.paramarray[ru_idx];
|
||||
|
||||
paramdef_t rup[] = ORAN_RU_DESC;
|
||||
int nru = sizeofArray(rup);
|
||||
sprintf(aprefix, "%s.%s.[%d].%s", CONFIG_STRING_ORAN, CONFIG_STRING_ORAN_FH, ru_idx, CONFIG_STRING_ORAN_RU);
|
||||
int ret = config_get(config_get_if(), rup, nru, aprefix);
|
||||
if (ret < 0) {
|
||||
printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix);
|
||||
return false;
|
||||
}
|
||||
paramdef_t prachp[] = ORAN_PRACH_DESC;
|
||||
int nprach = sizeofArray(prachp);
|
||||
sprintf(aprefix, "%s.%s.[%d].%s", CONFIG_STRING_ORAN, CONFIG_STRING_ORAN_FH, ru_idx, CONFIG_STRING_ORAN_PRACH);
|
||||
ret = config_get(config_get_if(), prachp, nprach, aprefix);
|
||||
if (ret < 0) {
|
||||
printf("No configuration section \"%s\": cannot initialize fhi_lib!\n", aprefix);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(fh_config, 0, sizeof(*fh_config));
|
||||
|
||||
fh_config->dpdk_port = ru_idx;
|
||||
fh_config->sector_id = 0;
|
||||
fh_config->nCC = 1;
|
||||
fh_config->neAxc = oai0->tx_num_channels / num_rus;
|
||||
fh_config->neAxcUl = oai0->rx_num_channels / num_rus;
|
||||
fh_config->nAntElmTRx = oai0->tx_num_channels / num_rus;
|
||||
fh_config->nDLFftSize = 0;
|
||||
fh_config->nULFftSize = 0;
|
||||
fh_config->nDLRBs = oai0->num_rb_dl;
|
||||
fh_config->nULRBs = oai0->num_rb_dl;
|
||||
fh_config->nDLAbsFrePointA = 0;
|
||||
fh_config->nULAbsFrePointA = 0;
|
||||
fh_config->nDLCenterFreqARFCN = nDLCenterFreqARFCN;
|
||||
fh_config->nULCenterFreqARFCN = nULCenterFreqARFCN;
|
||||
fh_config->ttiCb = NULL;
|
||||
fh_config->ttiCbParam = NULL;
|
||||
fh_config->Tadv_cp_dl = *gpd(fhp, nfh, ORAN_FH_CONFIG_TADV_CP_DL)->uptr;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_CP_DL, &fh_config->T2a_min_cp_dl, &fh_config->T2a_max_cp_dl))
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_CP_UL, &fh_config->T2a_min_cp_ul, &fh_config->T2a_max_cp_ul))
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_UP, &fh_config->T2a_min_up, &fh_config->T2a_max_up))
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA3, &fh_config->Ta3_min, &fh_config->Ta3_max))
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_DL, &fh_config->T1a_min_cp_dl, &fh_config->T1a_max_cp_dl))
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_CP_UL, &fh_config->T1a_min_cp_ul, &fh_config->T1a_max_cp_ul))
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T1A_UP, &fh_config->T1a_min_up, &fh_config->T1a_max_up))
|
||||
return false;
|
||||
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &fh_config->Ta4_min, &fh_config->Ta4_max))
|
||||
return false;
|
||||
fh_config->enableCP = 1;
|
||||
fh_config->prachEnable = 1;
|
||||
fh_config->srsEnable = 0;
|
||||
fh_config->puschMaskEnable = 0;
|
||||
fh_config->puschMaskSlot = 0;
|
||||
fh_config->cp_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_CP_VLAN_TAG)->uptr;
|
||||
fh_config->up_vlan_tag = *gpd(fhp, nfh, ORAN_FH_CONFIG_UP_VLAN_TAG)->uptr;
|
||||
fh_config->debugStop = 0;
|
||||
fh_config->debugStopCount = 0;
|
||||
fh_config->DynamicSectionEna = 0;
|
||||
fh_config->GPS_Alpha = 0;
|
||||
fh_config->GPS_Beta = 0;
|
||||
|
||||
if (!set_fh_prach_config(oai0, prachp, nprach, &fh_config->prach_conf))
|
||||
return false;
|
||||
if (!set_fh_srs_config(&fh_config->srs_conf))
|
||||
return false;
|
||||
if (!set_fh_frame_config(oai0, &fh_config->frame_conf))
|
||||
return false;
|
||||
if (!set_fh_ru_config(rup, nru, &fh_config->ru_conf))
|
||||
return false;
|
||||
|
||||
fh_config->bbdev_enc = NULL;
|
||||
fh_config->bbdev_dec = NULL;
|
||||
// fh_config->tx_cp_eAxC2Vf [not implemented by fhi_lib]
|
||||
// fh_config->tx_up_eAxC2Vf [not implemented by fhi_lib]
|
||||
// fh_config->rx_cp_eAxC2Vf [not implemented by fhi_lib]
|
||||
// fh_config->rx_up_eAxC2Vf [not implemented by fhi_lib]
|
||||
fh_config->log_level = 1;
|
||||
fh_config->max_sections_per_slot = 8;
|
||||
fh_config->max_sections_per_symbol = 8;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef ORAN_CONFIG_H
|
||||
#define ORAN_CONFIG_H
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "stdint.h"
|
||||
|
||||
struct xran_fh_init;
|
||||
void print_fh_init(const struct xran_fh_init *fh_init);
|
||||
struct xran_fh_config;
|
||||
void print_fh_config(const struct xran_fh_config *fh_config);
|
||||
|
||||
bool set_fh_init(struct xran_fh_init *fh_init);
|
||||
struct openair0_config;
|
||||
bool set_fh_config(int ru_idx, int num_rus, const struct openair0_config *oai0_cfg, struct xran_fh_config *fh_config);
|
||||
|
||||
// hack to workaround LiteOn limitation
|
||||
extern int g_kbar;
|
||||
|
||||
#endif /* ORAN_CONFIG_H */
|
||||
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "xran_fh_o_du.h"
|
||||
#include "xran_pkt.h"
|
||||
#include "xran_pkt_up.h"
|
||||
#include "rte_ether.h"
|
||||
|
||||
#include "oran-config.h"
|
||||
#include "oran-init.h"
|
||||
#include "oaioran.h"
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
#include "common_lib.h"
|
||||
|
||||
/* PRACH data samples are 32 bits wide (16bits for I/Q). Each packet contains
|
||||
* 840 samples for long sequence or 144 for short sequence. The payload length
|
||||
* is 840*16*2/8 octets.*/
|
||||
#ifdef FCN_1_2_6_EARLIER
|
||||
#define PRACH_PLAYBACK_BUFFER_BYTES (144 * 4L)
|
||||
#else
|
||||
#define PRACH_PLAYBACK_BUFFER_BYTES (840 * 4L)
|
||||
#endif
|
||||
|
||||
// structure holding allocated memory for ports (multiple DUs) and sectors
|
||||
// (multiple CCs)
|
||||
static oran_port_instance_t gPortInst[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR];
|
||||
void *gxran_handle;
|
||||
|
||||
static uint32_t get_nSW_ToFpga_FTH_TxBufferLen(int mu, int sections)
|
||||
{
|
||||
uint32_t xran_max_sections_per_slot = RTE_MAX(sections, XRAN_MIN_SECTIONS_PER_SLOT);
|
||||
uint32_t overhead = xran_max_sections_per_slot
|
||||
* (RTE_PKTMBUF_HEADROOM + sizeof(struct rte_ether_hdr) + sizeof(struct xran_ecpri_hdr)
|
||||
+ sizeof(struct radio_app_common_hdr) + sizeof(struct data_section_hdr));
|
||||
if (mu <= 1) {
|
||||
return 13168 + overhead; /* 273*12*4 + 64* + ETH AND ORAN HDRs */
|
||||
} else if (mu == 3) {
|
||||
return 3328 + overhead;
|
||||
} else {
|
||||
assert(false && "numerology not supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_nFpgaToSW_FTH_RxBufferLen(int mu)
|
||||
{
|
||||
/* note: previous code checked MTU:
|
||||
* mu <= 1: return mtu > XRAN_MTU_DEFAULT ? 13168 : XRAN_MTU_DEFAULT;
|
||||
* mu == 3: return mtu > XRAN_MTU_DEFAULT ? 3328 : XRAN_MTU_DEFAULT;
|
||||
* but I don't understand the interest: if the buffer is a big bigger, there
|
||||
* is no problem, or we could just set the MTU size as buffer size?!
|
||||
* Go with Max for the moment
|
||||
*/
|
||||
if (mu <= 1) {
|
||||
return 13168; /* 273*12*4 + 64*/
|
||||
} else if (mu == 3) {
|
||||
return 3328;
|
||||
} else {
|
||||
assert(false && "numerology not supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* is this necessary?
|
||||
int32_t set_main_core(uint32_t main_core)
|
||||
{
|
||||
struct sched_param sched_param;
|
||||
cpu_set_t cpuset;
|
||||
int32_t result = 0;
|
||||
memset(&sched_param, 0, sizeof(struct sched_param));
|
||||
// set main thread affinity mask to CPU2
|
||||
sched_param.sched_priority = 99;
|
||||
CPU_ZERO(&cpuset);
|
||||
|
||||
printf("This system has %d processors configured and %d processors available.\n", get_nprocs_conf(), get_nprocs());
|
||||
|
||||
if (main_core < get_nprocs_conf())
|
||||
CPU_SET(main_core, &cpuset);
|
||||
else
|
||||
return -1;
|
||||
|
||||
if ((result = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset))) {
|
||||
printf("pthread_setaffinity_np failed: coreId = 2, result = %d\n", result);
|
||||
}
|
||||
printf("%s [CPU %2d] [PID: %6d]\n", __FUNCTION__, sched_getcpu(), getpid());
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
static struct xran_prb_map get_xran_prb_map_dl(const struct xran_fh_config *f)
|
||||
{
|
||||
struct xran_prb_map prbmap = {
|
||||
.dir = XRAN_DIR_DL,
|
||||
.xran_port = 0,
|
||||
.band_id = 0,
|
||||
.cc_id = 0,
|
||||
.ru_port_id = 0,
|
||||
.tti_id = 0,
|
||||
.nPrbElm = 1,
|
||||
};
|
||||
struct xran_prb_elm *e = &prbmap.prbMap[0];
|
||||
e->nStartSymb = 0;
|
||||
e->numSymb = 14;
|
||||
e->nRBStart = 0;
|
||||
e->nRBSize = f->nDLRBs;
|
||||
e->nBeamIndex = 0;
|
||||
e->compMethod = f->ru_conf.compMeth;
|
||||
e->iqWidth = f->ru_conf.iqWidth;
|
||||
return prbmap;
|
||||
}
|
||||
|
||||
static struct xran_prb_map get_xran_prb_map_ul(const struct xran_fh_config *f)
|
||||
{
|
||||
struct xran_prb_map prbmap = {
|
||||
.dir = XRAN_DIR_UL,
|
||||
.xran_port = 0,
|
||||
.band_id = 0,
|
||||
.cc_id = 0,
|
||||
.ru_port_id = 0,
|
||||
.tti_id = 0,
|
||||
.start_sym_id = 0,
|
||||
.nPrbElm = 1,
|
||||
};
|
||||
struct xran_prb_elm *e = &prbmap.prbMap[0];
|
||||
e->nStartSymb = 0;
|
||||
e->numSymb = 14;
|
||||
e->nRBStart = 0;
|
||||
e->nRBSize = f->nULRBs;
|
||||
e->nBeamIndex = 0;
|
||||
e->compMethod = f->ru_conf.compMeth;
|
||||
e->iqWidth = f->ru_conf.iqWidth;
|
||||
return prbmap;
|
||||
}
|
||||
|
||||
static uint32_t oran_allocate_uplane_buffers(
|
||||
void *instHandle,
|
||||
struct xran_buffer_list list[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN],
|
||||
struct xran_flat_buffer buf[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT],
|
||||
uint32_t ant,
|
||||
uint32_t bufSize)
|
||||
{
|
||||
xran_status_t status;
|
||||
uint32_t pool;
|
||||
uint32_t numBufs = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT;
|
||||
status = xran_bm_init(instHandle, &pool, numBufs, bufSize);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
|
||||
printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, pool, numBufs, bufSize);
|
||||
int count = 0;
|
||||
for (uint32_t a = 0; a < ant; ++a) {
|
||||
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
|
||||
list[a][j].pBuffers = &buf[a][j][0];
|
||||
for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) {
|
||||
struct xran_flat_buffer *fb = &list[a][j].pBuffers[k];
|
||||
fb->nElementLenInBytes = bufSize;
|
||||
fb->nNumberOfElements = 1;
|
||||
fb->nOffsetInBytes = 0;
|
||||
void *ptr;
|
||||
void *mb;
|
||||
status = xran_bm_allocate_buffer(instHandle, pool, &ptr, &mb);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status && ptr != NULL && mb != NULL,
|
||||
"Failed at xran_bm_allocate_buffer(), status %d\n",
|
||||
status);
|
||||
count++;
|
||||
fb->pData = ptr;
|
||||
fb->pCtrl = mb;
|
||||
memset(ptr, 0, bufSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, pool, count);
|
||||
return pool;
|
||||
}
|
||||
|
||||
typedef struct oran_mixed_slot {
|
||||
uint32_t idx;
|
||||
uint32_t num_dlsym;
|
||||
uint32_t num_ulsym;
|
||||
uint32_t start_ulsym;
|
||||
} oran_mixed_slot_t;
|
||||
static oran_mixed_slot_t get_mixed_slot_info(const struct xran_frame_config *fconfig)
|
||||
{
|
||||
oran_mixed_slot_t info = {0};
|
||||
for (size_t sl = 0; sl < fconfig->nTddPeriod; ++sl) {
|
||||
info.num_dlsym = info.num_ulsym = 0;
|
||||
for (size_t sym = 0; sym < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++sym) {
|
||||
uint8_t t = fconfig->sSlotConfig[sl].nSymbolType[sym];
|
||||
if (t == 0 /* DL */) {
|
||||
info.num_dlsym++;
|
||||
} else if (t == 1 /* UL */) {
|
||||
if (info.num_ulsym == 0)
|
||||
info.start_ulsym = sym;
|
||||
info.num_ulsym++;
|
||||
} else if (t == 2 /* Mixed */) {
|
||||
info.idx = sl;
|
||||
} else {
|
||||
AssertFatal(false, "unknown symbol type %d\n", t);
|
||||
}
|
||||
}
|
||||
if (info.idx > 0)
|
||||
return info;
|
||||
}
|
||||
AssertFatal(false, "could not find mixed slot!\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
typedef struct oran_cplane_prb_config {
|
||||
uint8_t nTddPeriod;
|
||||
uint32_t mixed_slot_index;
|
||||
struct xran_prb_map slotMap;
|
||||
struct xran_prb_map mixedSlotMap;
|
||||
} oran_cplane_prb_config;
|
||||
|
||||
static void oran_allocate_cplane_buffers(void *instHandle,
|
||||
struct xran_buffer_list list[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN],
|
||||
struct xran_flat_buffer buf[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN],
|
||||
uint32_t ant,
|
||||
uint32_t sect,
|
||||
uint32_t size_of_prb_map,
|
||||
const oran_cplane_prb_config *prb_conf)
|
||||
{
|
||||
xran_status_t status;
|
||||
uint32_t poolSec;
|
||||
uint32_t numBufsSec = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT * sect * XRAN_MAX_FRAGMENT;
|
||||
uint32_t bufSizeSec = sizeof(struct xran_section_desc);
|
||||
status = xran_bm_init(instHandle, &poolSec, numBufsSec, bufSizeSec);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
|
||||
printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, poolSec, numBufsSec, bufSizeSec);
|
||||
|
||||
uint32_t poolPrb;
|
||||
uint32_t numBufsPrb = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT;
|
||||
uint32_t bufSizePrb = size_of_prb_map;
|
||||
status = xran_bm_init(instHandle, &poolPrb, numBufsPrb, bufSizePrb);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
|
||||
printf("xran_bm_init() hInstance %p poolIdx %d elements %d size %d\n", instHandle, poolPrb, numBufsPrb, bufSizePrb);
|
||||
|
||||
uint32_t count1 = 0;
|
||||
uint32_t count2 = 0;
|
||||
for (uint32_t a = 0; a < ant; a++) {
|
||||
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
|
||||
list[a][j].pBuffers = &buf[a][j];
|
||||
struct xran_flat_buffer *fb = list[a][j].pBuffers;
|
||||
fb->nElementLenInBytes = bufSizePrb;
|
||||
fb->nNumberOfElements = 1;
|
||||
fb->nOffsetInBytes = 0;
|
||||
void *ptr;
|
||||
void *mb;
|
||||
status = xran_bm_allocate_buffer(instHandle, poolPrb, &ptr, &mb);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status && ptr != NULL && mb != NULL,
|
||||
"Failed at xran_bm_allocate_buffer(), status %d\n",
|
||||
status);
|
||||
count1++;
|
||||
fb->pData = ptr;
|
||||
fb->pCtrl = mb;
|
||||
|
||||
// the original sample app code copies up to size_of_prb_map, but I think
|
||||
// this is wrong because the way it is computed leads to a number larger
|
||||
// than sizeof(map)
|
||||
struct xran_prb_map *p_rb_map = (struct xran_prb_map *)ptr;
|
||||
const struct xran_prb_map *src = &prb_conf->slotMap;
|
||||
if ((j % prb_conf->nTddPeriod) == prb_conf->mixed_slot_index)
|
||||
src = &prb_conf->mixedSlotMap;
|
||||
memcpy(p_rb_map, src, sizeof(*src));
|
||||
|
||||
for (uint32_t elm_id = 0; elm_id < p_rb_map->nPrbElm; ++elm_id) {
|
||||
struct xran_prb_elm *pPrbElem = &p_rb_map->prbMap[elm_id];
|
||||
for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) {
|
||||
for (uint32_t m = 0; m < XRAN_MAX_FRAGMENT; ++m) {
|
||||
void *sd_ptr;
|
||||
void *sd_mb;
|
||||
status = xran_bm_allocate_buffer(instHandle, poolSec, &sd_ptr, &sd_mb);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status,
|
||||
"Failed at xran_bm_allocate_buffer(), status %d m %d k %d elm_id %d\n",
|
||||
status,
|
||||
m,
|
||||
k,
|
||||
elm_id);
|
||||
count2++;
|
||||
pPrbElem->p_sec_desc[k][m] = sd_ptr;
|
||||
memset(sd_ptr, 0, sizeof(struct xran_section_desc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, poolPrb, count1);
|
||||
printf("xran_bm_allocate_buffer() hInstance %p poolIdx %d count %d\n", instHandle, poolSec, count2);
|
||||
}
|
||||
|
||||
/* callback not actively used */
|
||||
static void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t status)
|
||||
{
|
||||
rte_pause();
|
||||
}
|
||||
|
||||
static void oran_allocate_buffers(void *handle,
|
||||
int xran_inst,
|
||||
int num_sectors,
|
||||
oran_port_instance_t *portInstances,
|
||||
const struct xran_fh_config *fh_config)
|
||||
{
|
||||
AssertFatal(num_sectors == 1, "only support one sector at the moment\n");
|
||||
oran_port_instance_t *pi = &portInstances[0];
|
||||
AssertFatal(handle != NULL, "no handle provided\n");
|
||||
uint32_t xran_max_antenna_nr = RTE_MAX(fh_config->neAxc, fh_config->neAxcUl);
|
||||
uint32_t xran_max_sections_per_slot = RTE_MAX(fh_config->max_sections_per_slot, XRAN_MIN_SECTIONS_PER_SLOT);
|
||||
uint32_t size_of_prb_map = sizeof(struct xran_prb_map) + sizeof(struct xran_prb_elm) * (xran_max_sections_per_slot - 1);
|
||||
|
||||
pi->buf_list = _mm_malloc(sizeof(*pi->buf_list), 256);
|
||||
AssertFatal(pi->buf_list != NULL, "out of memory\n");
|
||||
oran_buf_list_t *bl = pi->buf_list;
|
||||
|
||||
xran_status_t status;
|
||||
printf("xran_sector_get_instances() o_xu_id %d xran_handle %p\n", xran_inst, handle);
|
||||
status = xran_sector_get_instances(xran_inst, handle, num_sectors, &pi->instanceHandle);
|
||||
printf("-> hInstance %p\n", pi->instanceHandle);
|
||||
AssertFatal(status == XRAN_STATUS_SUCCESS, "get sector instance failed for XRAN nInstanceNum %d\n", xran_inst);
|
||||
|
||||
const uint32_t txBufSize = get_nSW_ToFpga_FTH_TxBufferLen(fh_config->frame_conf.nNumerology, fh_config->max_sections_per_slot);
|
||||
oran_allocate_uplane_buffers(pi->instanceHandle, bl->src, bl->bufs.tx, xran_max_antenna_nr, txBufSize);
|
||||
|
||||
oran_mixed_slot_t info = get_mixed_slot_info(&fh_config->frame_conf);
|
||||
struct xran_prb_map dlPm = get_xran_prb_map_dl(fh_config);
|
||||
struct xran_prb_map dlPmMixed = dlPm;
|
||||
dlPmMixed.prbMap[0].nStartSymb = 0;
|
||||
dlPmMixed.prbMap[0].numSymb = info.num_dlsym;
|
||||
oran_cplane_prb_config dlConf = {
|
||||
.nTddPeriod = fh_config->frame_conf.nTddPeriod,
|
||||
.mixed_slot_index = info.idx,
|
||||
.slotMap = dlPm,
|
||||
.mixedSlotMap = dlPmMixed,
|
||||
};
|
||||
oran_allocate_cplane_buffers(pi->instanceHandle,
|
||||
bl->srccp,
|
||||
bl->bufs.tx_prbmap,
|
||||
xran_max_antenna_nr,
|
||||
xran_max_sections_per_slot,
|
||||
size_of_prb_map,
|
||||
&dlConf);
|
||||
|
||||
const uint32_t rxBufSize = get_nFpgaToSW_FTH_RxBufferLen(fh_config->frame_conf.nNumerology);
|
||||
oran_allocate_uplane_buffers(pi->instanceHandle, bl->dst, bl->bufs.rx, xran_max_antenna_nr, rxBufSize);
|
||||
|
||||
struct xran_prb_map ulPm = get_xran_prb_map_ul(fh_config);
|
||||
struct xran_prb_map ulPmMixed = ulPm;
|
||||
ulPmMixed.prbMap[0].nStartSymb = info.start_ulsym;
|
||||
ulPmMixed.prbMap[0].numSymb = info.num_ulsym;
|
||||
oran_cplane_prb_config ulConf = {
|
||||
.nTddPeriod = fh_config->frame_conf.nTddPeriod,
|
||||
.mixed_slot_index = info.idx,
|
||||
.slotMap = ulPm,
|
||||
.mixedSlotMap = ulPmMixed,
|
||||
};
|
||||
oran_allocate_cplane_buffers(pi->instanceHandle,
|
||||
bl->dstcp,
|
||||
bl->bufs.rx_prbmap,
|
||||
xran_max_antenna_nr,
|
||||
xran_max_sections_per_slot,
|
||||
size_of_prb_map,
|
||||
&ulConf);
|
||||
|
||||
// PRACH
|
||||
const uint32_t prachBufSize = PRACH_PLAYBACK_BUFFER_BYTES;
|
||||
oran_allocate_uplane_buffers(pi->instanceHandle, bl->prachdst, bl->bufs.prach, xran_max_antenna_nr, prachBufSize);
|
||||
// PRACH decomp buffer does not have separate DPDK-allocated memory pool
|
||||
// bufs, it points to the same pool as the prach buffer. Unclear to me why
|
||||
for (uint32_t a = 0; a < xran_max_antenna_nr; ++a) {
|
||||
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
|
||||
bl->prachdstdecomp[a][j].pBuffers = &bl->bufs.prachdecomp[a][j][0];
|
||||
for (uint32_t k = 0; k < XRAN_NUM_OF_SYMBOL_PER_SLOT; ++k) {
|
||||
struct xran_flat_buffer *fb = &bl->prachdstdecomp[a][j].pBuffers[k];
|
||||
fb->pData = bl->prachdst[a][j].pBuffers[k].pData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct xran_buffer_list *src[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list *srccp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list *dst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list *dstcp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list *prach[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list *prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
for (uint32_t a = 0; a < XRAN_MAX_ANTENNA_NR; ++a) {
|
||||
for (uint32_t j = 0; j < XRAN_N_FE_BUF_LEN; ++j) {
|
||||
src[a][j] = &bl->src[a][j];
|
||||
srccp[a][j] = &bl->srccp[a][j];
|
||||
dst[a][j] = &bl->dst[a][j];
|
||||
dstcp[a][j] = &bl->dstcp[a][j];
|
||||
prach[a][j] = &bl->prachdst[a][j];
|
||||
prachdecomp[a][j] = &bl->prachdstdecomp[a][j];
|
||||
}
|
||||
}
|
||||
|
||||
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->RxCbTag[0][0]);
|
||||
xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->PrachCbTag[0][0]);
|
||||
}
|
||||
|
||||
int *oai_oran_initialize(const openair0_config_t *openair0_cfg)
|
||||
{
|
||||
int32_t xret = 0;
|
||||
|
||||
struct xran_fh_init init = {0};
|
||||
if (!set_fh_init(&init)) {
|
||||
printf("could not read FHI 7.2/ORAN config\n");
|
||||
return NULL;
|
||||
}
|
||||
print_fh_init(&init);
|
||||
|
||||
/* read all configuration before starting anything */
|
||||
struct xran_fh_config xran_fh_config[XRAN_PORTS_NUM] = {0};
|
||||
for (int32_t o_xu_id = 0; o_xu_id < init.xran_ports; o_xu_id++) {
|
||||
if (!set_fh_config(o_xu_id, init.xran_ports, openair0_cfg, &xran_fh_config[o_xu_id])) {
|
||||
printf("could not read FHI 7.2/RU-specific config\n");
|
||||
return NULL;
|
||||
}
|
||||
print_fh_config(&xran_fh_config[o_xu_id]);
|
||||
}
|
||||
|
||||
// if ((xret = set_main_core(init.something)) < 0) {
|
||||
// printf("set_main_core() failed %d\n", xret);
|
||||
// exit(-1);
|
||||
// }
|
||||
|
||||
xret = xran_init(0, NULL, &init, NULL, &gxran_handle);
|
||||
if (xret != XRAN_STATUS_SUCCESS) {
|
||||
printf("xran_init failed %d\n", xret);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/** process all the O-RU|O-DU for use case */
|
||||
for (int32_t o_xu_id = 0; o_xu_id < init.xran_ports; o_xu_id++) {
|
||||
xret = xran_open(gxran_handle, &xran_fh_config[o_xu_id]);
|
||||
if (xret != XRAN_STATUS_SUCCESS) {
|
||||
printf("xran_open failed %d\n", xret);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int sector = 0;
|
||||
oran_port_instance_t *pi = &gPortInst[o_xu_id][sector];
|
||||
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
|
||||
|
||||
if ((xret = xran_reg_physide_cb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) {
|
||||
printf("xran_reg_physide_cb failed %d\n", xret);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (void *)gxran_handle;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef ORAN_INIT_H
|
||||
#define ORAN_INIT_H
|
||||
|
||||
typedef struct oran_bufs {
|
||||
struct xran_flat_buffer tx[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
|
||||
struct xran_flat_buffer tx_prbmap[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_flat_buffer rx[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
|
||||
struct xran_flat_buffer rx_prbmap[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
|
||||
struct xran_flat_buffer prach[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
|
||||
struct xran_flat_buffer prachdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN][XRAN_NUM_OF_SYMBOL_PER_SLOT];
|
||||
} oran_bufs_t;
|
||||
|
||||
typedef struct oran_buf_list {
|
||||
// xran API requires buffer lists as structs of arrays
|
||||
struct xran_buffer_list src[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list srccp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list dst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list dstcp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
|
||||
struct xran_buffer_list prachdst[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
struct xran_buffer_list prachdstdecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
|
||||
|
||||
oran_bufs_t bufs;
|
||||
} oran_buf_list_t;
|
||||
|
||||
typedef struct oran_port_instance_t {
|
||||
oran_buf_list_t *buf_list;
|
||||
void *instanceHandle;
|
||||
//uint32_t dpdkPoolIndex[MAX_SW_XRAN_INTERFACE_NUM];
|
||||
|
||||
struct xran_cb_tag RxCbTag[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR];
|
||||
struct xran_cb_tag PrachCbTag[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR];
|
||||
} oran_port_instance_t;
|
||||
|
||||
extern struct xran_fh_config gxran_fh_config[XRAN_PORTS_NUM];
|
||||
extern void *gxran_handle;
|
||||
|
||||
struct openair0_config;
|
||||
int *oai_oran_initialize(const struct openair0_config *openair0_cfg);
|
||||
|
||||
#endif /* ORAN_INIT_H */
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef ORAN_PARAMS_H
|
||||
#define ORAN_PARAMS_H
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "stdint.h"
|
||||
|
||||
#define CONFIG_STRING_ORAN "fhi_72"
|
||||
|
||||
#define ORAN_CONFIG_DPDK_DEVICES "dpdk_devices"
|
||||
#define ORAN_CONFIG_IO_CORE "io_core"
|
||||
#define ORAN_CONFIG_WORKER_CORES "worker_cores"
|
||||
#define ORAN_CONFIG_DU_ADDR "du_addr"
|
||||
#define ORAN_CONFIG_RU_ADDR "ru_addr"
|
||||
#define ORAN_CONFIG_MTU "mtu"
|
||||
#define ORAN_CONFIG_FILE_PREFIX "file_prefix"
|
||||
#define ORAN_CONFIG_NETHPERPORT "eth_lines"
|
||||
#define ORAN_CONFIG_NETHSPEED "eth_speed"
|
||||
|
||||
// clang-format off
|
||||
// TODO: PCI addr check
|
||||
// TODO: ethernet addr check
|
||||
#define ORAN_GLOBALPARAMS_DESC { \
|
||||
{ORAN_CONFIG_DPDK_DEVICES, "PCI addr of devices for DPDK\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{ORAN_CONFIG_IO_CORE, "DPDK Core used for IO\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintval=4, TYPE_INT, 0}, \
|
||||
{ORAN_CONFIG_WORKER_CORES, "CPU Cores to use for workers\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=NULL,TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
|
||||
{ORAN_CONFIG_MTU, "MTU of Eth interface\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \
|
||||
{ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \
|
||||
{ORAN_CONFIG_NETHPERPORT, "number of links per port\n", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \
|
||||
{ORAN_CONFIG_NETHSPEED, "ethernet speed link\n", 0, .uptr=NULL, .defuintval=10, TYPE_UINT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
#define CONFIG_STRING_ORAN_FH "fh_config"
|
||||
|
||||
#define ORAN_FH_CONFIG_TADV_CP_DL "Tadv_cp_dl"
|
||||
#define ORAN_FH_CONFIG_T2A_CP_DL "T2a_cp_dl"
|
||||
#define ORAN_FH_CONFIG_T2A_CP_UL "T2a_cp_ul"
|
||||
#define ORAN_FH_CONFIG_T2A_UP "T2a_up"
|
||||
#define ORAN_FH_CONFIG_TA3 "Ta3"
|
||||
#define ORAN_FH_CONFIG_T1A_CP_DL "T1a_cp_dl"
|
||||
#define ORAN_FH_CONFIG_T1A_CP_UL "T1a_cp_ul"
|
||||
#define ORAN_FH_CONFIG_T1A_UP "T1a_up"
|
||||
#define ORAN_FH_CONFIG_TA4 "Ta4"
|
||||
#define ORAN_FH_CONFIG_CP_VLAN_TAG "cp_vlan_tag"
|
||||
#define ORAN_FH_CONFIG_UP_VLAN_TAG "up_vlan_tag"
|
||||
|
||||
#define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n"
|
||||
|
||||
// clang-format off
|
||||
#define ORAN_FH_DESC { \
|
||||
{ORAN_FH_CONFIG_TADV_CP_DL, "Tadv parameter of RU\n", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
|
||||
{ORAN_FH_CONFIG_T2A_CP_DL, "T2a_cp_dl" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T2A_CP_UL, "T2a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T2A_UP, "T2a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_TA3, "Ta3" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_CP_DL, "T1a_cp_dl" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_CP_UL, "T1a_cp_ul" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_T1A_UP, "T1a_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_TA4, "Ta4" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
|
||||
{ORAN_FH_CONFIG_CP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
|
||||
{ORAN_FH_CONFIG_UP_VLAN_TAG, "not used by xran", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
#define CONFIG_STRING_ORAN_RU "ru_config"
|
||||
|
||||
#define ORAN_RU_CONFIG_IQWIDTH "iq_width"
|
||||
#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach"
|
||||
#define ORAN_RU_CONFIG_FFT_SIZE "fft_size"
|
||||
|
||||
// clang-format off
|
||||
#define ORAN_RU_DESC {\
|
||||
{ORAN_RU_CONFIG_IQWIDTH, "sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \
|
||||
{ORAN_RU_CONFIG_IQWIDTH_PRACH, "PRACH sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \
|
||||
{ORAN_RU_CONFIG_FFT_SIZE, "Size of FFT at RU\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=12, TYPE_UINT8, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
#define CONFIG_STRING_ORAN_PRACH "prach_config"
|
||||
|
||||
#define ORAN_PRACH_CONFIG_EAXC_OFFSET "eAxC_offset"
|
||||
#define ORAN_PRACH_CONFIG_KBAR "kbar"
|
||||
|
||||
// clang-format off
|
||||
#define ORAN_PRACH_DESC {\
|
||||
{ORAN_PRACH_CONFIG_EAXC_OFFSET, "RU's eAxC offset for PRACH\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=0, TYPE_UINT8, 0}, \
|
||||
{ORAN_PRACH_CONFIG_KBAR, "PRACH guard interval\n", 0, .uptr=NULL, .defuintval=4, TYPE_UINT, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
#endif /* ORAN_PARAMS_H */
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _ORAN_H_
|
||||
#define _ORAN_H_
|
||||
|
||||
#include "shared_buffers.h"
|
||||
#include "common_lib.h"
|
||||
void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp);
|
||||
|
||||
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot);
|
||||
|
||||
int transport_init(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
|
||||
|
||||
typedef struct {
|
||||
eth_state_t e;
|
||||
shared_buffers buffers;
|
||||
rru_config_msg_type_t last_msg;
|
||||
int capabilities_sent;
|
||||
void *oran_priv;
|
||||
} oran_eth_state_t;
|
||||
#endif /* _ORAN_H_ */
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#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 "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "openair1/PHY/defs_gNB.h"
|
||||
#include "common/utils/threadPool/thread-pool.h"
|
||||
#include "oaioran.h"
|
||||
|
||||
typedef struct {
|
||||
eth_state_t e;
|
||||
rru_config_msg_type_t last_msg;
|
||||
int capabilities_sent;
|
||||
void *oran_priv;
|
||||
} oran_eth_state_t;
|
||||
|
||||
notifiedFIFO_t oran_sync_fifo;
|
||||
|
||||
int trx_oran_start(openair0_device *device)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
|
||||
oran_eth_state_t *s = device->priv;
|
||||
|
||||
// Start ORAN
|
||||
if (xran_start(s->oran_priv) != 0) {
|
||||
printf("%s:%d:%s: Start ORAN failed ... Exit\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
} else {
|
||||
printf("Start ORAN. Done\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void trx_oran_end(openair0_device *device)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
oran_eth_state_t *s = device->priv;
|
||||
xran_close(s->oran_priv);
|
||||
}
|
||||
|
||||
int trx_oran_stop(openair0_device *device)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
oran_eth_state_t *s = device->priv;
|
||||
xran_stop(s->oran_priv);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int trx_oran_set_freq(openair0_device *device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int trx_oran_set_gains(openair0_device *device, openair0_config_t *openair0_cfg)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int trx_oran_get_stats(openair0_device *device)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int trx_oran_reset_stats(openair0_device *device)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int ethernet_tune(openair0_device *device, unsigned int option, int value)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trx_oran_write_raw(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
|
||||
{
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int trx_oran_read_raw(openair0_device *device, openair0_timestamp *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 *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 *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)
|
||||
{
|
||||
ru_info_t ru_info;
|
||||
ru_info.nb_rx = ru->nb_rx;
|
||||
ru_info.rxdataF = ru->common.rxdataF;
|
||||
ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id]
|
||||
|
||||
RU_proc_t *proc = &ru->proc;
|
||||
extern uint16_t sl_ahead;
|
||||
int f, sl;
|
||||
LOG_D(PHY, "Read rxdataF %p,%p\n", ru_info.rxdataF[0], ru_info.rxdataF[1]);
|
||||
start_meas(&ru->rx_fhaul);
|
||||
int ret = xran_fh_rx_read_slot(&ru_info, &f, &sl);
|
||||
stop_meas(&ru->rx_fhaul);
|
||||
LOG_D(PHY, "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);
|
||||
}
|
||||
|
||||
proc->tti_rx = sl;
|
||||
proc->frame_rx = f;
|
||||
proc->tti_tx = (sl + sl_ahead) % 20;
|
||||
proc->frame_tx = (sl > (19 - sl_ahead)) ? (f + 1) & 1023 : f;
|
||||
|
||||
if (proc->first_rx == 0) {
|
||||
if (proc->tti_rx != *slot) {
|
||||
LOG_E(PHY,
|
||||
"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(PHY,
|
||||
"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(PHY, "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(PHY, "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;
|
||||
ru_info.nb_tx = ru->nb_tx;
|
||||
ru_info.txdataF_BF = ru->common.txdataF_BF;
|
||||
// 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 *device,
|
||||
openair0_config_t *openair0_cfg,
|
||||
eth_params_t *eth_params)
|
||||
{
|
||||
oran_eth_state_t *eth;
|
||||
|
||||
device->Mod_id = 0;
|
||||
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;
|
||||
|
||||
eth = (oran_eth_state_t *)calloc(1, sizeof(oran_eth_state_t));
|
||||
if (eth == NULL) {
|
||||
AssertFatal(0 == 1, "out of memory\n");
|
||||
}
|
||||
|
||||
eth->e.flags = ETH_RAW_IF4p5_MODE;
|
||||
eth->e.compression = NO_COMPRESS;
|
||||
eth->e.if_name = eth_params->local_if_name;
|
||||
eth->oran_priv = NULL; // define_oran_pointer();
|
||||
device->priv = eth;
|
||||
device->openair0_cfg = &openair0_cfg[0];
|
||||
|
||||
eth->last_msg = (rru_config_msg_type_t)-1;
|
||||
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
|
||||
initNotifiedFIFO(&oran_sync_fifo);
|
||||
eth->oran_priv = oai_oran_initialize(openair0_cfg);
|
||||
AssertFatal(eth->oran_priv != NULL, "can not initialize fronthaul");
|
||||
// create message queues for ORAN sync
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _ORAN_ISOLATE_H_
|
||||
#define _ORAN_ISOLATE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "xran_fh_o_du.h"
|
||||
|
||||
/*
|
||||
* Structure added to bear the information needed from OAI RU
|
||||
*/
|
||||
typedef struct ru_info_s {
|
||||
// Needed for UL
|
||||
int nb_rx;
|
||||
int32_t **rxdataF;
|
||||
|
||||
// Needed for DL
|
||||
int nb_tx;
|
||||
int32_t **txdataF_BF;
|
||||
|
||||
// Needed for Prach
|
||||
int16_t **prach_buf;
|
||||
} ru_info_t;
|
||||
|
||||
int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot);
|
||||
int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp);
|
||||
|
||||
int compute_xran_statistics();
|
||||
|
||||
#endif /* _ORAN_ISOLATE_H_ */
|
||||
Reference in New Issue
Block a user