Compare commits

...

50 Commits

Author SHA1 Message Date
Bartosz Podrygajlo
3904d74658 Attempt to fix the ORU hanging issue
In an attempt to make the ORU interrupt more robust, move the timing thread
stop at the very end of vrtism_end function. This will give an extra second to
applications threads to finalize read operations and stop correctly.
2025-12-04 09:13:10 +01:00
Bartosz Podrygajlo
5e0ae8ba05 Correctly reset new thread affinity in case its -1
In case the new thread affinity is -1, instead of reseting affinity
to all cores set the affinity mask to the affinity of the process.
This way if e.g. taskset is used, threads that are assinged -1 affinity
will not move to cores outside configured taskset.
2025-12-04 09:07:01 +01:00
Bartosz Podrygajlo
6c16fce1d0 ORU: Quarter slot parallelization for DL FH processing
Implemented quarter slot parallelization using thread pool for DL FH
processing. The number of threads started is equal to number of antennas
 x 2. However due to O-RU already processing DL in half slot intervals,
the number of threads per antenna per slot is equal to 4. This achieves
quarter-slot parallelization,

To configure, use legacy RU `num_tp_cores` and `tp_cores` config values
in conf files.
2025-12-04 09:00:33 +01:00
Bartosz Podrygajlo
68dc50c491 Add timespec printout to dump_nonzero_symbol 2025-12-04 08:12:11 +01:00
Bartosz Podrygajlo
531a100bdd Add sync thread to O-RU 2025-12-03 11:17:06 +01:00
Bartosz Podrygajlo
c750b9acd0 Hack for PRACH format B4 O-RU
A hacky solution to make PRACH format B4 work on O-RU. This limits the PRACH
symbol accumulation to first four symbols, making PRACH that much faster. This
is not a proper solution - a proper solution would require to write a symbol
based PRACH receiver. A slight complication is that the PRACH symbol does not
conicide with the OFDM symbl boundary.
2025-12-02 19:31:35 +01:00
Bartosz Podrygajlo
954a17ed70 Clear memory in shm_td_iq_channel after RX
Clear memory in shm_td_iq_channel after RX. This prevents the IQ
from being read twice. This can happen if the application crashes
and will keep the other side reading historical IQ samples.
2025-11-28 09:00:28 +01:00
Bartosz Podrygajlo
5ff23f62c2 Add fix patch for oran RX window end callback 2025-11-25 12:29:28 +01:00
Bartosz Podrygajlo
6f286e48fc conf files from my local setup
these conf files are used in my local setup. I use x710 intel NIC to
create 2 paris of inter-connected VFs using separate VLAN tags for
Cplane and Uplane. See setup_ru_ifs.sh for details.
2025-11-25 11:54:02 +01:00
Bartosz Podrygajlo
8f2e2123be PRACH debugging commit 2025-11-25 11:50:07 +01:00
Bartosz Podrygajlo
aabdb6efb1 Add T2a delay profile parameter 2025-11-25 11:49:42 +01:00
Bartosz Podrygajlo
b8b510a185 Fix (?) PRACH TX 2025-11-25 11:49:19 +01:00
Bartosz Podrygajlo
7bc6a11f78 Couple of debugging prints 2025-11-25 11:49:01 +01:00
Bartosz Podrygajlo
b309482118 Fix xran callback installation for O-RU
Install callback using updated xran library.
2025-11-21 15:12:17 +01:00
Bartosz Podrygajlo
450c2d8b95 PUSCH updates for O-RU 2025-11-18 16:46:07 +01:00
Bartosz Podrygajlo
981e3adc19 ORU: Receive PUSCH and send via xran 2025-11-12 09:04:03 +01:00
Bartosz Podrygajlo
623496b2a7 Correct timestamp generation code in symbol_callback 2025-11-11 19:19:22 +01:00
Bartosz Podrygajlo
3f7b5310c1 O-RU PRACH reception 2025-11-07 14:35:15 +01:00
Bartosz Podrygajlo
fea2086560 Enable instrumentation of nr-softmodem 2025-11-07 14:35:15 +01:00
Bartosz Podrygajlo
c7b8e7fd82 Fix tracy package version 2025-11-07 14:35:15 +01:00
Bartosz Podrygajlo
ff0eec582a Update threadCreate
Two modifications for threadCreate:
 - if -1 is passed, the thread no longer inherits its parent affinity.
   instead thread affnity is cleared
 - if the name is too long, the thread name is shorted to maximum
   pthread name (16 characters).
2025-11-07 14:35:15 +01:00
Bartosz Podrygajlo
a34852f24f Add xran patch for PRACH transmission
Add a fix for a segmentation fault at the DU due to incorrect filter_id field
in packets generated by the O-RU for PRACH.
2025-11-06 10:24:19 +01:00
Bartosz Podrygajlo
3735e8a5df O-RU: Synchronize north read to south read threads.
Perform synchronization between input sample from split8
device and split 7.2 timestamp via a fifo queue between threads.
2025-11-06 10:17:33 +01:00
Bartosz Podrygajlo
c60338659f O-RU test reproduction steps 2025-11-06 10:17:25 +01:00
Bartosz Podrygajlo
594d81d3b9 ORU: Fix incorrect pointer to txdataF_BF
Overwrite RU_t common->txdataF_BF with the buffer pointer used by O-RU.
TODO: cleanup the code so this is not needed.
2025-11-06 10:17:18 +01:00
Bartosz Podrygajlo
d01f7e38fb O-RU: Add missing symbol rotation initialization 2025-11-06 10:17:09 +01:00
Bartosz Podrygajlo
9b70ee6374 Fix decompression for O-RU. 2025-11-06 10:16:58 +01:00
Bartosz Podrygajlo
ed44194ff5 Replace tx_rf with tx_rf_symbols in ORU
Fix the O-RU per symbol transmission.
2025-11-06 10:16:51 +01:00
Bartosz Podrygajlo
f93d1ded10 Add a new tx_rf_symbols function to allow per symbol transmission 2025-11-06 10:16:40 +01:00
Bartosz Podrygajlo
12d0ca747c Add symbol timing functions for NR_DL_FRAME_PARMS
Add two new functions for calculation symbol timestamp and symbol
duration for NR_DL_FRAME_PARMS. These functions are not using
the existing indirection mechanism via function pointers as this
prevents the compiler from properly optimizing the code.
2025-11-06 10:16:31 +01:00
Bartosz Podrygajlo
6952a67101 O-RU: Reset nSecDesc on symbol reception
This is required as xran does not manage this value by itself.
Not resetting this will cause nSecDesc to go above the maximum
supported number of sections per symbol and sections to be discarded.
2025-11-06 10:16:24 +01:00
Bartosz Podrygajlo
d922d45599 Fix lte-softmodem and oairu builds 2025-11-06 10:16:17 +01:00
Bartosz Podrygajlo
7bbeec3eb2 Offset timestamp_tx in O-RU by intended symbol
Add sample offset from symbol to timestamp_tx based on symbol
indicated by oran api.
2025-11-06 10:16:10 +01:00
Bartosz Podrygajlo
bcb158cafc Workarond for a bug in callback mechanism in XRAN
Update symbol_callback to detect and correct an issue with the calculated
frame index. This is caused by an issue with the timer functionality
in libxran where if a timer is setup close to the GPS second start
the sfn offset `xran_sfn_at_sec_start` is not setup correctly causing
the frame in xran_sense_of_time struct to be returned with an offset
of 100 frames (1 second).
2025-11-06 10:16:01 +01:00
Bartosz Podrygajlo
6e66b9fc3f Ensure ofdm_offset_divisor is set in O-RU.
Hardcode ofdm_offset_divisor to 8 in O-RU.
2025-11-06 10:15:54 +01:00
Bartosz Podrygajlo
49e652c9c6 Simplify vrtsim timing job thread. 2025-11-06 10:15:47 +01:00
Bartosz Podrygajlo
19a418cd17 Clean exit for the ORU
- Handle SIGINT
 - Print DL FH processing meas
 - Stop & terminate xran and vrtsim
2025-11-06 10:15:38 +01:00
Bartosz Podrygajlo
684dd38dca Use synchronized rfdevice to xran timestamps in ORU
Synchronize the southbound (time domain) interface to XRAN timestamps
in ORU. This currently only works with vrtsim.

Transmit the samples after processing in oru_downlink_processing.
2025-11-06 10:15:30 +01:00
Bartosz Podrygajlo
bd2c9c32c0 Load vrtsim in O-RU and start reading samples
Added oru_south_read_thread that reads samples from vrtsim.
No UL FH processing is done as of this commit.
2025-11-06 10:15:21 +01:00
Bartosz Podrygajlo
801086e401 Print xran counters to stdout in xran_fh_tx_read_slot 2025-11-06 10:15:14 +01:00
Bartosz Podrygajlo
9e95a2ccde Add get_timestamp to openair_device_t and vrtsim
This function can be used to convert a timespec struct to a
openair0_timestamp. It can be used to synchronize the realtime
clock to the device sample number.
2025-11-06 10:13:46 +01:00
Bartosz Podrygajlo
e48661d8cf Add a periodic print out of the O-RU north read thread 2025-11-06 10:13:36 +01:00
Bartosz Podrygajlo
9e94745f65 Add a config file for O-RU from broadbill 2025-11-06 10:12:59 +01:00
Bartosz Podrygajlo
7ba28c1d05 DL FH processing for O-RU
Add DFT and symbol rotation to O-RU
2025-11-06 10:12:48 +01:00
Bartosz Podrygajlo
b0caad9c40 O-RU: Add north_read thread
Added north read thread that can utilize north_in function for timing
and providing IQ data from the XRAN library.
2025-11-06 10:12:24 +01:00
Bartosz Podrygajlo
b2c62c7cd4 Add north_in function to oran_fhlib_5g
The north_in function is supposed to be used by the ORU to read IQ data
sent from O-DU.
2025-11-06 10:12:15 +01:00
Mario Joa-Ng
ed7c1057c5 Use no of fh_config in configuration file to determine the number of peers
Determine number of DU for RU config file or no of RU for DU config file
based on number of fh_config elements.
2025-11-06 10:12:08 +01:00
Raymond Knopp
c3bd911938 Initial implementation of O-RU for 7.2 emulator
Added new executable oainr_ru which acts as a 7.2 O-RU.

Co-authored-by: Bartosz Podrygajlo <bartosz.podrygajlo@openairinterface.org>
Co-authored-by: Mario Joa-Ng <mario.joa-ng@openairinterface.org>
2025-11-06 10:12:01 +01:00
Bartosz Podrygajlo
5bb7a4d274 FD RFSimulator adaptation layer
A new radio library for use with the gNB. It performs the same tasks as an O-RU
and is meant for testing O-DU functionalities. It acts as an RFSim server with
a frequency domain interface.
2025-11-06 10:11:12 +01:00
Bartosz Podrygajlo
decd8ae8ac Add a function which loads the specified radio library 2025-11-06 10:11:03 +01:00
55 changed files with 4440 additions and 87 deletions

View File

@@ -282,7 +282,7 @@ add_boolean_option(TRACY_ENABLE OFF "Enable tracy instrumentation" ON)
if (TRACY_ENABLE)
# the tracy version here should match the tracy server version
# below is latest release as of this commit
CPMAddPackage("gh:wolfpld/tracy#0.12.2")
CPMAddPackage("gh:wolfpld/tracy#v0.12.2")
endif()
set (OCP_ITTI ${OPENAIR_DIR}/common/utils/ocp_itti)
@@ -1788,6 +1788,30 @@ target_link_libraries(lte-uesoftmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIE
target_link_libraries(lte-uesoftmodem PRIVATE
asn1_lte_rrc asn1_s1ap asn1_m2ap asn1_m3ap asn1_x2ap)
# nr RRU
add_executable(oainr_ru
${OPENAIR_DIR}/executables/nr-ru.c
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
${OPENAIR_DIR}/openair1/SCHED_NR/phy_frame_config_nr.c
${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c
${OPENAIR_DIR}/openair1/SCHED_NR/nr_prach_procedures.c
${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c
${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach.c
${OPENAIR_DIR}/common/utils/nr/nr_common.c
${OPENAIR_DIR}/radio/COMMON/common_lib.c
${OPENAIR_DIR}/radio/COMMON/record_player.c
${OPENAIR_DIR}/executables/softmodem-common.c
${OPENAIR_DIR}/executables/main_nr_ru.c
${OPENAIR_DIR}/executables/nr-oru.c
)
target_link_libraries(oainr_ru PRIVATE
-Wl,--start-group
UTIL SCHED_RU_LIB PHY_COMMON PHY_RU shlib_loader
-Wl,--end-group z dl)
target_link_libraries(oainr_ru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils
barrier actor)
target_link_libraries(oainr_ru PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_phy_common time_management PHY_NR MAC_NR_COMMON PHY_NR_COMMON)
# nr-softmodem
###################################################

View File

@@ -82,6 +82,8 @@ Options:
Makes the NR softmodem
--RU
Makes the OAI RRU
--nrRU
Makes the OAI nrRRU
--UE
Makes the UE specific parts (usim, nvram) from the given configuration file
--nrUE
@@ -227,6 +229,11 @@ function main() {
TARGET_LIST="$TARGET_LIST oairu"
echo_info "Will compile RRU"
shift;;
--nrRU)
nrRU=1
TARGET_LIST="$TARGET_LIST oainr_ru"
echo_info "Will compile nrRRU"
shift;;
--UE)
UE=1
TARGET_LIST="$TARGET_LIST lte-uesoftmodem conf2uedata usim nvram"
@@ -452,7 +459,7 @@ function main() {
if [[ $TARGET_LIST != "" ]] && [[ -f $OPENAIR_DIR/CMakeLists.txt ]]; then
# add some default libraries that should always be built
# for eNB, gNB, UEs, simulators
if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 ]]; then
if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 || $nrRU == 1 ]]; then
TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim rf_emulator"
fi

View File

@@ -0,0 +1,52 @@
diff --git a/fhi_lib/lib/src/xran_cb_proc.c b/fhi_lib/lib/src/xran_cb_proc.c
index 2bb5187..8c5b848 100644
--- a/fhi_lib/lib/src/xran_cb_proc.c
+++ b/fhi_lib/lib/src/xran_cb_proc.c
@@ -460,7 +460,7 @@ xran_reg_sym_cb_rx_win_end(struct xran_device_ctx * p_dev_ctx, xran_callback_sym
int32_t ret = XRAN_STATUS_SUCCESS;
struct cb_user_per_sym_ctx *p_loc_sym_cb_ctx = &p_dev_ctx->symCbCtx[symb][XRAN_CB_SYM_RX_WIN_END];
uint32_t time_diff_us = 0;
- uint32_t time_diff_nSymb = 0;
+ int32_t time_diff_nSymb = 0;
uint32_t absolute_ota_sym = 0;
uint32_t interval_us_local = p_dev_ctx->interval_us_local;
@@ -470,17 +470,29 @@ xran_reg_sym_cb_rx_win_end(struct xran_device_ctx * p_dev_ctx, xran_callback_sym
return ret;
}
- time_diff_us = p_dev_ctx->fh_cfg.Ta4_max;
- printf("RX WIN end Ta4_max is %d [us] where TTI is %d [us] \n", time_diff_us, interval_us_local);
- time_diff_nSymb = time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT);
- if ((time_diff_nSymb/1000/(interval_us_local*1000/N_SYM_PER_SLOT)) < time_diff_us) {
- time_diff_nSymb+=1;
- printf("time duration %d rounded up to duration of %d symbols\n", time_diff_us, time_diff_nSymb);
+ if (p_dev_ctx->fh_init.io_cfg.id == O_DU) {
+ time_diff_us = p_dev_ctx->fh_cfg.Ta4_max;
+ printf("RX WIN end Ta4_max is %d [us] where TTI is %d [us] \n", time_diff_us, interval_us_local);
+ time_diff_nSymb = time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT);
+ if ((time_diff_nSymb/1000/(interval_us_local*1000/N_SYM_PER_SLOT)) < time_diff_us) {
+ time_diff_nSymb+=1;
+ printf("time duration %d rounded up to duration of %d symbols\n", time_diff_us, time_diff_nSymb);
+ }
+ printf("U-plane UL delay %d [us] measured against OTA time [offset in symbols is %d]\n", time_diff_us, time_diff_nSymb);
+ } else {
+ time_diff_us = p_dev_ctx->fh_cfg.T2a_min_up;
+ printf("RX WIN end T2a_min_up is %d [us] where TTI is %d [us] \n", time_diff_us, interval_us_local);
+ time_diff_nSymb = time_diff_us*1000/(interval_us_local*1000/N_SYM_PER_SLOT);
+ time_diff_nSymb *= -1;
+ printf("U-plane DL advance %d [us] measured against OTA time [offset in symbols is %d]\n", time_diff_us, time_diff_nSymb);
+ if (time_diff_nSymb == 0) {
+ print_err("T2a_min_up of %d results in 0 symbol offset leaving no time for O-RU processing. Increase T2a_min_up at least above 1 symbol\n", time_diff_us);
+ return -1;
+ }
}
- printf("U-plane UL delay %d [us] measured against OTA time [offset in symbols is %d]\n", time_diff_us, time_diff_nSymb);
- absolute_ota_sym = (symb + time_diff_nSymb) % XRAN_NUM_OF_SYMBOL_PER_SLOT;
+ absolute_ota_sym = (symb + time_diff_nSymb + XRAN_NUM_OF_SYMBOL_PER_SLOT) % XRAN_NUM_OF_SYMBOL_PER_SLOT;
printf("requested symb %d pkt arrival time [deadline] coresponds to symb %d OTA time\n", symb, absolute_ota_sym);
-
+ fflush(stdout);
p_loc_sym_cb_ctx->symb_num_req = symb;
p_loc_sym_cb_ctx->sym_diff = -time_diff_nSymb;
p_loc_sym_cb_ctx->symb_num_ota = absolute_ota_sym;

View File

@@ -0,0 +1,89 @@
diff --git a/fhi_lib/lib/src/xran_common.c b/fhi_lib/lib/src/xran_common.c
index 5968d01..eb9bb9f 100644
--- a/fhi_lib/lib/src/xran_common.c
+++ b/fhi_lib/lib/src/xran_common.c
@@ -908,7 +908,8 @@ inline int32_t prepare_symbol_ex(enum xran_pkt_dir direction,
uint32_t do_copy,
enum xran_comp_hdr_type staticEn,
uint16_t num_sections,
- uint16_t iq_offset)
+ uint16_t iq_offset,
+ bool is_prach)
{
int32_t n_bytes , iq_len_aggr = 0;
int32_t prep_bytes;
@@ -968,7 +969,7 @@ inline int32_t prepare_symbol_ex(enum xran_pkt_dir direction,
xp[idx].app_params.data_feature.value = 0x10;
xp[idx].app_params.data_feature.data_direction = direction;
// xp[idx].app_params.payl_ver = 1;
- // xp[idx].app_params.filter_id = 0;
+ xp[idx].app_params.data_feature.filter_id = is_prach ? 1 : 0;
xp[idx].app_params.frame_id = frame_id;
xp[idx].app_params.sf_slot_sym.subframe_id = subframe_id;
xp[idx].app_params.sf_slot_sym.slot_id = xran_slotid_convert(slot_id, 0);
@@ -1158,7 +1159,8 @@ int send_symbol_mult_section_ex(void *handle,
do_copy,
staticEn,
1,
- 0); /*Send a single section */
+ 0,
+ true); /*Send a single section */
prb_offset += prb_num_sec;
data_offset += n_bytes;
if(sent) {
@@ -1266,7 +1268,8 @@ int send_symbol_ex(void *handle,
do_copy,
staticEn,
1,
- 0); /*Send a single section */
+ 0,
+ true); /*Send a single section */
if(sent){
pCnt->tx_counter++;
diff --git a/fhi_lib/lib/src/xran_common.h b/fhi_lib/lib/src/xran_common.h
index 04076fd..245b1c0 100644
--- a/fhi_lib/lib/src/xran_common.h
+++ b/fhi_lib/lib/src/xran_common.h
@@ -201,7 +201,8 @@ int32_t prepare_symbol_ex(enum xran_pkt_dir direction,
uint32_t do_copy,
enum xran_comp_hdr_type staticEn,
uint16_t num_sections,
- uint16_t iq_buffer_offset);
+ uint16_t iq_buffer_offset,
+ bool is_prach);
int32_t prepare_sf_slot_sym (enum xran_pkt_dir direction,
uint8_t frame_id,
uint8_t subframe_id,
diff --git a/fhi_lib/lib/src/xran_tx_proc.c b/fhi_lib/lib/src/xran_tx_proc.c
index 85ce6fa..b7db317 100644
--- a/fhi_lib/lib/src/xran_tx_proc.c
+++ b/fhi_lib/lib/src/xran_tx_proc.c
@@ -23,6 +23,7 @@
* @author Intel Corporation
**/
+#include <stdbool.h>
#define _GNU_SOURCE
#include <sched.h>
#include <assert.h>
@@ -421,7 +422,8 @@ int32_t xran_process_tx_sym_cp_off(void *pHandle, uint8_t ctx_id, uint32_t tti,
0,
staticEn,
num_sections,
- p_sec_desc->iq_buffer_offset);
+ p_sec_desc->iq_buffer_offset,
+ false);
curr_sect_id += num_sections;
@@ -683,7 +685,8 @@ xran_process_tx_srs_cp_off(void *pHandle, uint8_t ctx_id, uint32_t tti, int32_t
0,
staticEn,
num_sections,
- 0);
+ 0,
+ false);
section_id += num_sections;

View File

@@ -208,8 +208,11 @@ IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel,
size_t num_samples_first_copy = CIRCULAR_BUFFER_SIZE - first_sample;
memcpy(tx_iq_data, base_ptr + first_sample, num_samples_first_copy * sizeof(sample_t));
memcpy(tx_iq_data + num_samples_first_copy, base_ptr, (num_samples - num_samples_first_copy) * sizeof(sample_t));
memset(base_ptr + first_sample, 0, num_samples_first_copy * sizeof(sample_t));
memset(base_ptr, 0, (num_samples - num_samples_first_copy) * sizeof(sample_t));
} else {
memcpy(tx_iq_data, base_ptr + first_sample, num_samples * sizeof(sample_t));
memset(base_ptr + first_sample, 0, num_samples * sizeof(sample_t));
}
return CHANNEL_NO_ERROR;
}

View File

@@ -282,14 +282,25 @@ void threadCreate(pthread_t* t, void * (*func)(void*), void * param, char* name,
ret=pthread_create(t, &attr, func, param);
AssertFatal(ret == 0, "Error in pthread_create(): ret: %d, errno: %d\n", ret, errno);
pthread_setname_np(*t, name);
if (affinity != -1 ) {
char short_name[16];
strncpy(short_name, name, sizeof(short_name) - 1);
short_name[sizeof(short_name) - 1] = '\0';
ret = pthread_setname_np(*t, short_name);
AssertFatal(ret == 0, "Error in pthread_setname_np(): ret: %d, errno: %d\n", ret, errno);
if (affinity != -1) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(affinity, &cpuset);
ret = pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset);
AssertFatal(ret == 0, "Error in pthread_getaffinity_np(): ret: %d, errno: %d", ret, errno);
} else {
cpu_set_t cpuset;
ret = sched_getaffinity(0, sizeof(cpu_set_t), &cpuset);
AssertFatal(ret == 0, "Error in sched_getaffinity(): ret: %d, errno: %d", ret, errno);
ret = pthread_setaffinity_np(*t, sizeof(cpu_set_t), &cpuset);
AssertFatal(ret == 0, "Error in pthread_setaffinity_np(): ret: %d, errno: %d", ret, errno);
}
pthread_attr_destroy(&attr);
}

View File

@@ -0,0 +1,42 @@
# Reproduction steps to run OAI O-RU with NR UE on broadbill with gNB on peafowl
1. Reserve both machines using the `auto_resrve` script
2. Compile the code on both machines. Example configuration:
```
cmake ../../ -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=/home/bpodrygajlo/phy/fhi_lib/lib
cmake --build . --target vrtsim oainr_ru oran_fhlib_5g nr-softmodem ldpc params_libconfig nr-uesoftmodem
```
3. On broadbill, run `setup_ru_ifs_broadbill.sh`
4. On peafowl, run `setup_ifs_peafowl.sh`
5. On broadbill, run the O-RU:
```
sudo ./oainr_ru -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/ru.band77.106prb.fhi72.4x4.conf --vrtsim.role server
```
and UE
```
sudo taskset -c 50-63 ./nr-uesoftmodem -C 4049760000 -r 106 --numerology 1 --band 77 --ssb 516 --device.name vrtsim
```
6. On peafowl, run the gNB:
```
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.106prb.fhi72.4x4-oairu.conf
```
7. Observe UE detecting SSB and decoding SIB1
# New config file used on my MS-A2 PC
Two sets of config files were added that I've been using on my minipc. These need to be adapted to OAI INFRA
`ru.band77.106prb.fhi72.2x2.conf`, `gnb.2x2.conf` - 2x2 106 PRB mu1
`ru.band77.106prb.fhi72.4x4.conf`, `gnb.conf` - 4x4 106 PRB mu1
`setup_ru_ifs.sh` - the way to setup the vfs on the minipc

View File

@@ -0,0 +1,272 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
nr_cellid = 1;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 1;
maxMIMO_layers = 2;
pusch_AntennaPorts = 2;
do_CSIRS = 1;
do_SRS = 0;
sib1_tda = 15;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# n_TimingAdvanceOffset = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 4049.76 MHz
# selected SSB frequency = 4049.76 MHz
absoluteFrequencySSB = 669984;
dl_frequencyBand = 77;
# frequency point A = 4030.68 MHz
dl_absoluteFrequencyPointA = 668712;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
initialDLBWPlocationAndBandwidth = 28875; #38.101-1 Table 5.3.2-1
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 77;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 106;
pMax = 23;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 159;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 0;
preambleReceivedTargetPower = -100;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 7;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 2;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#one (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
msg3_DeltaPreamble = 2;
p0_NominalWithGrant = -100;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 0;
p0_nominal = -96;
ssb_PositionsInBurst_Bitmap = 0x1;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 5;
nrofDownlinkSlots = 3;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 1;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = 0;
}
);
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ({ ipv4 = "172.21.6.5"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200;
# dl_bler_target_upper = .35;
# dl_bler_target_lower = .15;
ul_bler_target_upper = .35;
ul_bler_target_lower = .15;
pusch_FailureThres = 100;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 110;
pucch0_dtx_threshold = 80;
pusch_dtx_threshold = -100;
# thread_pool_size = 8;
tx_amp_backoff_dB = 36;
L1_rx_thread_core = 11;
L1_tx_thread_core = 12;
phase_compensation = 0; # needs to match O-RU configuration
}
);
RUs = (
{
local_rf = "no";
nb_tx = 2;
nb_rx = 2;
att_tx = 0;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = 10;
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms = ( "nia2", "nia0" );
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
};
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:05:02.2", "0000:05:02.3"); # one VF can be used as well
system_core = 7;
io_core = 8;
worker_cores = (9);
ru_addr = ("00:11:22:33:64:66", "00:11:22:33:64:67");
mtu = 9600;
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
Ta3_up = (100, 350);
T1a_up = (200, 400);
Ta4 = (100, 350);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
});
};

View File

@@ -0,0 +1,272 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
nr_cellid = 1;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 2;
maxMIMO_layers = 2;
pusch_AntennaPorts = 4;
do_CSIRS = 1;
do_SRS = 0;
sib1_tda = 15;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# n_TimingAdvanceOffset = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 4049.76 MHz
# selected SSB frequency = 4049.76 MHz
absoluteFrequencySSB = 669984;
dl_frequencyBand = 77;
# frequency point A = 4030.68 MHz
dl_absoluteFrequencyPointA = 668712;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
initialDLBWPlocationAndBandwidth = 28875; #38.101-1 Table 5.3.2-1
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 77;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 106;
pMax = 23;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 159;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 0;
preambleReceivedTargetPower = -100;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 7;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 2;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#one (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
msg3_DeltaPreamble = 2;
p0_NominalWithGrant = -100;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 0;
p0_nominal = -96;
ssb_PositionsInBurst_Bitmap = 0x1;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 5;
nrofDownlinkSlots = 3;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 1;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = 0;
}
);
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ({ ipv4 = "172.21.6.5"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200;
# dl_bler_target_upper = .35;
# dl_bler_target_lower = .15;
ul_bler_target_upper = .35;
ul_bler_target_lower = .15;
pusch_FailureThres = 100;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 110;
pucch0_dtx_threshold = 80;
pusch_dtx_threshold = -100;
# thread_pool_size = 8;
tx_amp_backoff_dB = 36;
L1_rx_thread_core = 11;
L1_tx_thread_core = 12;
phase_compensation = 0; # needs to match O-RU configuration
}
);
RUs = (
{
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = 10;
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms = ( "nia2", "nia0" );
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
};
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:05:02.2", "0000:05:02.3"); # one VF can be used as well
system_core = 7;
io_core = 8;
worker_cores = (9);
ru_addr = ("00:11:22:33:64:66", "00:11:22:33:64:67");
mtu = 9600;
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
Ta3_up = (100, 350);
T1a_up = (400, 450);
Ta4 = (100, 350);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
});
};

View File

@@ -0,0 +1,93 @@
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
RUs = (
{
local_rf = "no";
nb_tx = 2;
nb_rx = 2;
att_tx = 0;
att_rx = 0;
bands = [77];
tx_bw = [106];
rx_bw = [106];
carrier_tx = [4049760];
carrier_rx = [4049760];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
# PRACH configuration
prach_config_index = 159;
prach_msg1_start = 0;
tdd_period = 5;
num_dl_slots = 3;
num_dl_symbols = 6;
num_ul_slots = 1;
num_ul_symbols = 4;
});
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:05:02.0", "0000:05:02.1"); # one VF can be used as well
system_core = 25;
io_core = 26;
worker_cores = (27);
du_addr = ("00:11:22:33:64:68", "00:11:22:33:64:69");
mtu = 9600;
file_prefix = "ru";
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
Ta3_up = (200, 350);
T1a_up = (400, 450);
T2a_up = (300, 450);
Ta4 = (100, 350);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
});
};
channelmod = {
max_chan=10;
modellist="modellist_rfsimu_1";
modellist_rfsimu_1 = (
{
model_name = "server_tx_channel_model"
type = "Rayleigh8";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
},
{
model_name = "rfsimu_channel_ue0"
type = "AWGN";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
}
);
}

View File

@@ -0,0 +1,87 @@
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
RUs = (
{
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_rx = 0;
bands = [77];
tx_bw = [106];
rx_bw = [106];
carrier_tx = [4049760];
carrier_rx = [4049760];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
# PRACH configuration
prach_config_index = 159;
prach_msg1_start = 0;
});
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:05:02.0", "0000:05:02.1"); # one VF can be used as well
system_core = 25;
io_core = 26;
worker_cores = (27);
du_addr = ("00:11:22:33:64:68", "00:11:22:33:64:69");
mtu = 9600;
file_prefix = "ru";
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
Ta3_up = (100, 350);
T1a_up = (400, 450);
Ta4 = (110, 180);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
});
};
channelmod = {
max_chan=10;
modellist="modellist_rfsimu_1";
modellist_rfsimu_1 = (
{
model_name = "server_tx_channel_model"
type = "Rayleigh8";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
},
{
model_name = "rfsimu_channel_ue0"
type = "AWGN";
ploss_dB = 0;
noise_power_dB = 0;
forgetfact = 0;
offset = 0;
ds_tdl = 0;
}
);
}

View File

@@ -0,0 +1,29 @@
#!/bin/sh
#### 100G interface --> enp1s0f0 | VFs pcie-address --> 01:01.0, 01:01.1
#### 25G interface (PTP) --> enp193s0f1 | VFs pcie-address --> c1:11.0,c1:11.1
set -x
IF_NAME=enp193s0f1
NUM_VFs=2
U_PLANE_MAC_ADD=00:11:22:33:54:00
C_PLANE_MAC_ADD=00:11:22:33:54:01
VLAN=3
MTU=9600
U_PLANE_PCI=0000:c1:11.0
C_PLANE_PCI=0000:c1:11.1
## It will be something like this --> $DPDK_INST/bin
DPDK_DEVBIND_PREFIX=
sudo ethtool -G $IF_NAME rx 8160 tx 8160
sudo sh -c "echo 0 > /sys/class/net/$IF_NAME/device/sriov_numvfs"
sudo sh -c "echo $NUM_VFs > /sys/class/net/$IF_NAME/device/sriov_numvfs"
sudo modprobe -r iavf
sudo modprobe iavf
# this next 2 lines is for C/U planes
sudo ip link set $IF_NAME vf 0 mac $U_PLANE_MAC_ADD vlan $VLAN spoofchk off mtu $MTU
sudo ip link set $IF_NAME vf 1 mac $C_PLANE_MAC_ADD vlan $VLAN spoofchk off mtu $MTU
sleep 1
sudo dpdk-devbind.py --unbind $U_PLANE_PCI
sudo dpdk-devbind.py --unbind $C_PLANE_PCI
sudo modprobe vfio-pci
sudo dpdk-devbind.py --bind vfio-pci $U_PLANE_PCI
sudo dpdk-devbind.py --bind vfio-pci $C_PLANE_PCI

View File

@@ -0,0 +1,40 @@
#!/bin/bash
set -x
# Set these in the DU config
RU_U_PLANE_MAC=00:11:22:33:64:66
RU_C_PLANE_MAC=00:11:22:33:64:67
DU_U_PLANE_MAC=00:11:22:33:64:68
DU_C_PLANE_MAC=00:11:22:33:64:69
UPLANE_CAPTURE_MAC=00:11:22:33:64:70
U_VLAN=3
C_VLAN=4
MTU=9216
IF=enp5s0f0np0
echo 0 | sudo tee /sys/bus/pci/devices/0000\:05\:00.0/sriov_numvfs
echo 5 | sudo tee /sys/bus/pci/devices/0000\:05\:00.0/sriov_numvfs
# this next 2 lines is for C/U planes
sudo ip link set $IF vf 0 mac $RU_U_PLANE_MAC vlan $U_VLAN qos 0 spoofchk off mtu $MTU
sudo ip link set $IF vf 1 mac $RU_C_PLANE_MAC vlan $C_VLAN qos 0 spoofchk off mtu $MTU
# this next 2 lines is for DU C/U planes
sudo ip link set $IF vf 2 mac $DU_U_PLANE_MAC vlan $U_VLAN qos 0 spoofchk off mtu $MTU
sudo ip link set $IF vf 3 mac $DU_C_PLANE_MAC vlan $C_VLAN qos 0 spoofchk off mtu $MTU
# Used for capturing U-plane traffic. To capture, configure MAC in gnb/ORU config file
sudo ip link set $IF vf 4 mac $UPLANE_CAPTURE_MAC vlan $U_VLAN qos 0 spoofchk off mtu $MTU
# bind to vfio-pci
sleep 1
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.0
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.1
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.2
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.3
sudo /usr/local/bin/dpdk-devbind.py --unbind 05:02.4
sudo modprobe vfio-pci
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.0
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.1
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.2
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 05:02.3
sudo /usr/local/bin/dpdk-devbind.py --bind iavf 0000:05:02.4
sleep 5

View File

@@ -0,0 +1,20 @@
#!/bin/bash
set -x
# Set these in the DU config
RU_U_PLANE_MAC=00:11:22:33:64:66
RU_C_PLANE_MAC=00:11:22:33:64:67
UNRELATED_MAC=00:11:22:33:64:70
UNRELATED_MAC2=00:11:22:33:64:71
VLAN=3
MTU=9600
IF=ens2f1np1
# this next 2 lines is for C/U planes
sudo ip link set $IF vf 8 mac $RU_U_PLANE_MAC vlan $VLAN qos 0 spoofchk off mtu $MTU
sudo ip link set $IF vf 9 mac $RU_C_PLANE_MAC vlan $VLAN qos 0 spoofchk off mtu $MTU
sleep 1
sudo /usr/local/bin/dpdk-devbind.py --unbind 41:12.0
sudo /usr/local/bin/dpdk-devbind.py --unbind 41:12.1
sudo modprobe vfio-pci
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 41:12.0
sudo /usr/local/bin/dpdk-devbind.py --bind vfio-pci 41:12.1
sleep 5

View File

@@ -65,7 +65,8 @@ static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFRUTPCORES[] = {2,4,6,8};
static int DEFBW[] = {273};
static int DEFCARRIER[] = {3430560};
#include "ENB_APP/enb_paramdef.h"
#include "common/config/config_userapi.h"

304
executables/main_nr_ru.c Normal file
View File

@@ -0,0 +1,304 @@
/*
* 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
*/
/*! \file oairu.c
* \brief Top-level threads for radio-unit
* \author R. Knopp
* \date 2020
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#include "nfapi_nr_interface_scf.h"
#include "notified_fifo.h"
#include "time_meas.h"
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <sched.h>
#include "assertions.h"
#include "PHY/types.h"
#include "PHY/defs_RU.h"
#include "common/oai_version.h"
#include "common/config/config_userapi.h"
#include "common/utils/load_module_shlib.h"
#include "common/ran_context.h"
#include "radio/COMMON/common_lib.h"
#include "radio/ETHERNET/if_defs.h"
#include "PHY/phy_vars.h"
#include "PHY/phy_extern.h"
#include "PHY/TOOLS/phy_scope_interface.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
// #include "PHY/INIT/phy_init.h"
#include "openair2/ENB_APP/enb_paramdef.h"
#include "system.h"
#include "nfapi/oai_integration/vendor_ext.h"
#include <executables/softmodem-common.h>
#include <executables/thread-common.h>
#include "nr-oru.h"
#include "openair1/PHY/INIT/nr_phy_init.h"
#include "openair1/SCHED_NR/sched_nr.h"
#include "openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h"
#include "actor.h"
#include "instrumentation.h"
pthread_cond_t sync_cond;
pthread_mutex_t sync_mutex;
int sync_var = -1; //!< protected by mutex \ref sync_mutex.
int config_sync_var = -1;
int oai_exit = 0;
int sf_ahead = 4;
int emulate_rf = 0;
RAN_CONTEXT_t RC;
extern void kill_NR_RU_proc(int inst);
extern void set_function_spec_param(RU_t *ru);
extern void start_NR_RU(RU_t *ru);
extern void init_NR_RU(configmodule_interface_t *cfg, char *);
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
void nfapi_setmode(nfapi_mode_t nfapi_mode)
{
return;
}
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
{
if (s != NULL) {
printf("%s:%d %s() Exiting OAI softmodem: %s\n", file, line, function, s);
}
close_log_mem();
oai_exit = 1;
if (assert)
abort();
}
static void get_options(configmodule_interface_t *cfg)
{
CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP);
get_common_options(cfg);
CONFIG_CLEARRTFLAG(CONFIG_NOEXITONHELP);
// NRCConfig();
}
nfapi_mode_t nfapi_getmode(void)
{
return (NFAPI_MODE_PNF);
}
void oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind)
{
AssertFatal(1 == 0, "This is bad ... please check why we get here\n");
}
void wait_eNBs(void)
{
return;
}
void wait_gNBs(void)
{
return;
}
struct timespec timespec_add(struct timespec, struct timespec)
{
struct timespec t = {0};
return t;
};
struct timespec timespec_sub(struct timespec, struct timespec)
{
struct timespec t = {0};
return t;
};
int beam_index_allocation(bool das,
int fapi_beam_index,
nfapi_nr_analog_beamforming_ve_t *analog_bf,
NR_gNB_COMMON *common_vars,
int slot,
int symbols_per_slot,
int bitmap_symbols)
{
return 0;
}
uint16_t nr_du[838];
uint64_t downlink_frequency[MAX_NUM_CCs][4];
configmodule_interface_t *uniqCfg = NULL;
THREAD_STRUCT thread_struct;
extern void fill_rf_config(RU_t *ru, char *rf_config_file);
extern void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp);
void stop_ru(int sig)
{
exit_function(__FILE__, __FUNCTION__, __LINE__, "interrupted", false);
}
int main(int argc, char **argv)
{
memset(&RC, 0, sizeof(RC));
if ((uniqCfg = load_configmodule(argc, argv, 0)) == NULL) {
exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
}
logInit();
printf("Reading in command-line options\n");
get_options(uniqCfg);
if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
fprintf(stderr, "Getting configuration failed\n");
exit(-1);
}
#if T_TRACER
T_Config_Init();
#endif
printf("configuring for RRU\n");
// strdup to put the sring in the core file for post mortem identification
LOG_I(HW, "Version: %s\n", strdup(OAI_PACKAGE_VERSION));
/* Read configuration */
printf("About to Init RU threads\n");
lock_memory_to_ram();
load_dftslib();
RC.nb_RU = 1;
RC.ru = malloc(sizeof(RC.ru));
init_NR_RU(config_get_if(), NULL);
RU_t *ru = RC.ru[0];
ORU_t oru = {0};
for (int i = 0; i < NUM_PUSCH_ACTORS; i++) {
char actor_name[20];
sprintf(actor_name, "PUSCH%d", i);
init_actor(&oru.pusch_actors[i], actor_name, -1);
}
init_actor(&oru.prach_actor, "PRACH", -1);
initNotifiedFIFO(&oru.sync_fifo);
oru.ru = ru;
cpumeas(CPUMEAS_ENABLE);
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nr_dump_frame_parms(fp);
init_symbol_rotation(fp);
fp->ofdm_offset_divisor = 8;
init_timeshift_rotation(fp);
ru->if_south = LOCAL_RF;
nr_phy_init_RU(ru);
fill_rf_config(ru, ru->rf_config_file);
char tpool_config[10 * 16] = "";
for (int i = 0; i < ru->num_tpcores; i++) {
char core_str[16];
sprintf(core_str, "%d", ru->tpcores[i]);
strcat(tpool_config, core_str);
if (i < ru->num_tpcores - 1)
strcat(tpool_config, ",");
}
LOG_A(PHY, "RU thread-pool core string %s (size %d)\n", tpool_config, ru->num_tpcores);
ru->threadPool = malloc(sizeof(tpool_t));
initTpool(tpool_config, &oru.tpool, false);
/* set PRACH configuration */
nfapi_nr_prach_config_t *prach_config = &ru->config.prach_config;
prach_config->prach_ConfigurationIndex.value = ru->prach_config_index;
prach_config->num_prach_fd_occasions_list[0].k1.value = ru->prach_msg1_freq;
prach_config->prach_sequence_length.value = 1;
prach_config->prach_sub_c_spacing.value = 1;
prach_config->num_prach_fd_occasions.value = 1;
prach_config->num_prach_fd_occasions_list[0].num_root_sequences.value = ru->num_root_sequences;
prach_config->num_prach_fd_occasions_list[0].prach_root_sequence_index.value = ru->prach_root_sequence_index;
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp);
ru->N_TA_offset = set_default_nta_offset(fp->freq_range, fp->samples_per_subframe);
reset_meas(&oru.rx_prach);
oru.prach_info = get_nr_prach_occasion_info_from_index(ru->prach_config_index, FR1, fp->frame_type);
LOG_A(PHY, "PRACH configuration index %d\n", ru->prach_config_index);
LOG_A(PHY, "PRACH format %d start_symbol %d duration %d\n", oru.prach_info.format, oru.prach_info.start_symbol,
oru.prach_info.N_dur);
int ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params);
AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport protocol\n", ru->idx, ret);
ret = ru->nr_start_if(ru, NULL);
AssertFatal(ret == 0, "Could not start xran\n");
LOG_I(PHY, "starting vrtsim\n");
ret = openair0_load(&ru->rfdevice, "vrtsim", &ru->openair0_cfg, NULL);
AssertFatal(ret == 0, "RU %u: openair0_load() ret %d: cannot initialize vrtsim\n", ru->idx, ret);
ret = ru->rfdevice.trx_start_func(&ru->rfdevice);
AssertFatal(ret == 0, "RU %u: trx_start_func() ret %d: cannot start vrtsim\n", ru->idx, ret);
signal(SIGINT, stop_ru);
threadCreate(&oru.sync_thread, oru_sync_thread, (void *)&oru, "sync_thread", -1, OAI_PRIORITY_RT_MAX);
threadCreate(&oru.north_read_thread, oru_north_read_thread, (void *)&oru, "north_read_thread", -1, OAI_PRIORITY_RT_MAX);
threadCreate(&oru.south_read_thread, oru_south_read_thread, (void *)&oru, "south_read_thread", -1, OAI_PRIORITY_RT_MAX);
oru.num_sync_messages_needed = 2; // Number of threads requiring initial sync
while (oai_exit == 0) {
sleep(1);
}
ret = pthread_join(oru.sync_thread, NULL);
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
ret = pthread_join(oru.north_read_thread, NULL);
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
ret = pthread_join(oru.south_read_thread, NULL);
AssertFatal(ret == 0, "pthread_join failed %d\n", ret);
LOG_I(PHY, "Threads joined\n");
end_configmodule(uniqCfg);
if (ru->rfdevice.trx_stop_func) {
ru->rfdevice.trx_stop_func(&ru->rfdevice);
}
if (ru->rfdevice.trx_end_func) {
ru->rfdevice.trx_end_func(&ru->rfdevice);
}
if (ru->ifdevice.trx_stop_func) {
ru->ifdevice.trx_stop_func(&ru->ifdevice);
}
if (ru->ifdevice.trx_end_func) {
ru->ifdevice.trx_end_func(&ru->ifdevice);
}
print_meas(&ru->tx_fhaul, "TX FH processing", NULL, NULL);
print_meas(&oru.rx, "RX processing", NULL, NULL);
logClean();
printf("Bye.\n");
return 0;
}

View File

@@ -65,6 +65,8 @@
static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFBW[] = {273};
static int DEFCARRIER[] = {3430560};
static int DEFRUTPCORES[] = {2,4,6,8};
THREAD_STRUCT thread_struct;

568
executables/nr-oru.c Normal file
View File

@@ -0,0 +1,568 @@
/*
* 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 "PHY/TOOLS/tools_defs.h"
#include "PHY/defs_RU.h"
#include "PHY/impl_defs_nr.h"
#include "log.h"
#include "nfapi_nr_interface_scf.h"
#include "platform_types.h"
#include "task_ans.h"
#include "thread-pool.h"
#include "time_meas.h"
#include <bits/pthreadtypes.h>
#include <time.h>
#include <unistd.h>
#define _GNU_SOURCE
#include "nr-oru.h"
#include "openair1/PHY/defs_nr_common.h"
#include "openair1/PHY/INIT/nr_phy_init.h"
#include "openair1/SCHED_NR/sched_nr.h"
#include "notified_fifo.h"
#include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h"
#include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h"
#include <sched.h>
typedef struct {
int x;
int y;
int size_x;
int size_y;
} thread_grid2d_t;
typedef struct {
int frame_unwrap;
int last_frame;
int64_t sync_offset;
} sync_params_t;
typedef struct {
ORU_t *oru;
int frame;
int slot;
} prach_task_args_t;
typedef struct {
ORU_t *oru;
int frame;
int slot;
int num_symbols;
int start_symbol;
thread_grid2d_t thread_grid;
} pusch_task_args_t;
extern void tx_rf_symbols(RU_t *ru, int frame, int slot, uint64_t timestamp, int start_symbol, int num_symbols);
void perform_initial_sync(ORU_t *oru, sense_of_time_t *sense_of_time, initial_sync_t *initial_sync)
{
initial_sync->frame = sense_of_time->frame;
initial_sync->slot = sense_of_time->slot;
initial_sync->symbol = sense_of_time->symbol;
initial_sync->sample = oru->ru->rfdevice.get_timestamp(&oru->ru->rfdevice, &sense_of_time->ts);
LOG_I(PHY,
"RU synchronized: frame, slot %d.%d, symbol %d, sample: %ld\n",
initial_sync->frame,
initial_sync->slot,
initial_sync->symbol,
initial_sync->sample);
}
void initialize_sync_params(NR_DL_FRAME_PARMS *fp, sync_params_t *sync_params, initial_sync_t *initial_sync)
{
sync_params->frame_unwrap = 0;
sync_params->last_frame = initial_sync->frame;
sync_params->sync_offset = initial_sync->sample;
sync_params->sync_offset -=
(uint64_t)(initial_sync->frame) * fp->samples_per_subframe * 10 + fp->get_samples_slot_timestamp(initial_sync->slot, fp, 0);
}
openair0_timestamp get_timestamp(ORU_t *oru, sense_of_time_t *sense_of_time, sync_params_t *sync_params)
{
if (sync_params->last_frame > sense_of_time->frame) {
sync_params->frame_unwrap++;
}
sync_params->last_frame = sense_of_time->frame;
NR_DL_FRAME_PARMS *fp = oru->ru->nr_frame_parms;
int num_frames = sense_of_time->frame + sync_params->frame_unwrap * 1024;
uint64_t timestamp = (uint64_t)(num_frames)*fp->samples_per_subframe * 10
+ fp->get_samples_slot_timestamp(sense_of_time->slot, fp, 0)
+ get_samples_symbol_timestamp(fp, sense_of_time->slot, sense_of_time->symbol);
timestamp += sync_params->sync_offset;
return timestamp;
}
typedef struct {
RU_t *ru;
NR_DL_FRAME_PARMS *fp;
int slot;
int start_symbol;
int num_symbols;
int aatx;
c16_t *txdataF;
task_ans_t *task_ans;
} dl_symbol_process_t;
void dl_symbol_process(void *arg)
{
dl_symbol_process_t *args = (dl_symbol_process_t *)arg;
apply_nr_rotation_TX(args->fp,
args->txdataF,
args->fp->symbol_rotation[0],
args->slot,
args->fp->N_RB_DL,
args->start_symbol,
args->num_symbols);
nr_feptx0(args->ru, args->slot, args->start_symbol, args->num_symbols, args->aatx);
completed_task_ans(args->task_ans);
}
void oru_downlink_processing(ORU_t *oru,
c16_t *txDataF_ptr[oru->ru->nb_tx],
int frame,
int slot,
int start_symbol,
int num_symbols,
openair0_timestamp timestamp_tx)
{
RU_t *ru = oru->ru;
start_meas(&ru->tx_fhaul);
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int num_paralell_workers_per_antenna = num_symbols > 4 ? 2 : 1; // Ensure at least quarter slot parallelization
task_t tasks[ru->nb_tx][num_paralell_workers_per_antenna];
dl_symbol_process_t dl_process_args[ru->nb_tx][num_paralell_workers_per_antenna];
task_ans_t task_ans;
init_task_ans(&task_ans, num_paralell_workers_per_antenna * ru->nb_tx);
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
for (int i = 0; i < num_paralell_workers_per_antenna; i++) {
tasks[aatx][i].func = dl_symbol_process;
tasks[aatx][i].args = (void *)&dl_process_args[aatx][i];
dl_process_args[aatx][i].ru = ru;
dl_process_args[aatx][i].fp = fp;
dl_process_args[aatx][i].slot = slot;
dl_process_args[aatx][i].start_symbol = start_symbol + num_symbols / num_paralell_workers_per_antenna * i;
dl_process_args[aatx][i].num_symbols =
min(num_symbols / num_paralell_workers_per_antenna, num_symbols - (num_symbols / num_paralell_workers_per_antenna) * i);
dl_process_args[aatx][i].aatx = aatx;
dl_process_args[aatx][i].txdataF = txDataF_ptr[aatx];
dl_process_args[aatx][i].task_ans = &task_ans;
pushTpool(&oru->tpool, tasks[aatx][i]);
}
}
LOG_D(PHY,
"[RU_thread] transmit data: frame %d, slot %d, start_symbol %d, num_symbols %d, timestamp %ld\n",
frame,
slot,
start_symbol,
num_symbols,
timestamp_tx);
join_task_ans(&task_ans);
tx_rf_symbols(ru, frame, slot, timestamp_tx, start_symbol, num_symbols);
stop_meas(&ru->tx_fhaul);
}
void *oru_sync_thread(void *arg)
{
ORU_t *oru = (ORU_t *)arg;
RU_t *ru = (RU_t *)oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
AssertFatal(ru->ifdevice.xran_api.north_in_func != NULL, "No fronthaul interface at north port");
__attribute__((aligned(32))) c16_t txDataF[ru->nb_tx][ceil_mod(fp->ofdm_symbol_size * 14, 32)];
c16_t *txDataF_ptr[ru->nb_tx];
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
txDataF_ptr[aatx] = txDataF[aatx];
}
initial_sync_t initial_sync;
while (!oai_exit) {
int num_symbols = 0;
sense_of_time_t sense_of_time;
ru->ifdevice.xran_api.north_in_func((uint32_t **)txDataF_ptr, ru->nb_tx, &sense_of_time, &num_symbols);
if (sense_of_time.symbol == 0) {
perform_initial_sync(oru, &sense_of_time, &initial_sync);
break;
}
}
for (int i = 0; i < oru->num_sync_messages_needed; i++) {
notifiedFIFO_elt_t *sync_msg = newNotifiedFIFO_elt(sizeof(initial_sync_t), 0, NULL, NULL);
initial_sync_t *initial_sync_p = NotifiedFifoData(sync_msg);
*initial_sync_p = initial_sync;
pushNotifiedFIFO(&oru->sync_fifo, sync_msg);
}
return NULL;
}
void *oru_north_read_thread(void *arg)
{
ORU_t *oru = (ORU_t *)arg;
RU_t *ru = (RU_t *)oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
AssertFatal(ru->ifdevice.xran_api.north_in_func != NULL, "No fronthaul interface at north port");
__attribute__((aligned(32))) c16_t txDataF[ru->nb_tx][ceil_mod(fp->ofdm_symbol_size * 14, 32)];
c16_t *txDataF_ptr[ru->nb_tx];
for (int aatx = 0; aatx < ru->nb_tx; aatx++) {
txDataF_ptr[aatx] = txDataF[aatx];
}
ru->common.txdataF_BF = (int32_t **)txDataF_ptr;
notifiedFIFO_elt_t * elt = pullNotifiedFIFO(&oru->sync_fifo);
initial_sync_t *initial_sync = NotifiedFifoData(elt);
delNotifiedFIFO_elt(elt);
sync_params_t sync_params;
initialize_sync_params(fp, &sync_params, initial_sync);
LOG_A(PHY,
"ORU North read thread started at frame %d, slot %d, symbol %d\n",
initial_sync->frame,
initial_sync->slot,
initial_sync->symbol);
while (!oai_exit) {
int num_symbols = 0;
sense_of_time_t sense_of_time;
ru->ifdevice.xran_api.north_in_func((uint32_t **)txDataF_ptr, ru->nb_tx, &sense_of_time, &num_symbols);
openair0_timestamp timestamp_tx = get_timestamp(oru, &sense_of_time, &sync_params);
if ((sense_of_time.frame & 0xff) == 0 && sense_of_time.slot == 0) {
LOG_I(PHY,
"[RU_thread] read data: frame %d, slot %d, start_symbol %d, num_symbols %d\n",
sense_of_time.frame,
sense_of_time.slot,
sense_of_time.symbol,
num_symbols);
}
nfapi_nr_config_request_scf_t *cfg = &ru->config;
int slot_type = nr_slot_select(cfg, sense_of_time.frame, sense_of_time.slot % fp->slots_per_frame);
if (slot_type != NR_UPLINK_SLOT)
oru_downlink_processing(oru,
txDataF_ptr,
sense_of_time.frame,
sense_of_time.slot,
sense_of_time.symbol,
num_symbols,
timestamp_tx);
}
return NULL;
}
void rx_initial_sync(ORU_t *oru, int *slot, int *frame)
{
RU_t *ru = oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
const int num_samples = 3000;
c16_t throwaway_samples[ru->nb_rx][num_samples];
void *rxp[ru->nb_rx];
for (int i = 0; i < ru->nb_rx; i++)
rxp[i] = throwaway_samples[i];
openair0_timestamp timestamp;
initial_sync_t initial_sync;
while (!oai_exit) {
int samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, &timestamp, rxp, num_samples, ru->nb_rx);
AssertFatal(samples_read == num_samples, "Unexpected number of samples received\n");
notifiedFIFO_elt_t *elt = pollNotifiedFIFO(&oru->sync_fifo);
if (elt) {
memcpy(&initial_sync, NotifiedFifoData(elt), sizeof(initial_sync));
break;
}
}
// Synchornize to ORAN timing
int next_slot = initial_sync.slot;
int next_frame = initial_sync.frame;
openair0_timestamp next_sample = timestamp + num_samples;
int64_t diff = next_sample - initial_sync.sample;
LOG_I(PHY,
"Sychronizing to frame slot %d.%d, sample %ld next_sample %ld diff %ld\n",
next_frame,
next_slot,
initial_sync.sample,
next_sample,
diff);
uint64_t samples_to_sync_by = 0;
if (diff < 0) {
samples_to_sync_by = -diff;
} else {
while (diff > 0) {
uint32_t samples_per_slot = fp->get_samples_per_slot(next_slot, fp);
samples_to_sync_by += samples_per_slot;
diff -= samples_per_slot;
next_slot++;
if (next_slot == fp->slots_per_frame) {
next_slot = 0;
next_frame++;
if (next_frame == 1024) {
next_frame = 0;
}
}
}
samples_to_sync_by += diff;
}
LOG_I(PHY, "Thrashing %lu samples to sync to slot %d, frame %d\n", samples_to_sync_by, next_slot, next_frame);
while (!oai_exit && samples_to_sync_by > 0) {
int samples_to_read = min(num_samples, samples_to_sync_by);
int samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, &timestamp, rxp, samples_to_read, ru->nb_rx);
AssertFatal(samples_to_read == samples_read, "Unexpected number of samples received\n");
samples_to_sync_by -= samples_to_read;
}
*slot = next_slot;
*frame = next_frame;
}
void receive_prach(ORU_t *oru, int frame, int slot)
{
RU_t *ru = oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
uint16_t RA_sfn_index = -1;
if (get_nr_prach_sched_from_info(oru->prach_info, ru->prach_config_index, frame, slot, ru->numerology, FR1, &RA_sfn_index, TDD)) {
// Fill PRACH item
prach_item_t prach_id;
prach_id.frame = frame;
prach_id.slot = slot;
prach_id.num_slots = oru->prach_info.format < 4 ? get_long_prach_dur(oru->prach_info.format, fp->numerology_index) : 1;
prach_id.msg1_frequencystart = ru->prach_msg1_freq;
prach_id.mu = 1;
nfapi_nr_config_request_scf_t *cfg = &ru->config;
prach_id.prach_sequence_length = cfg->prach_config.prach_sequence_length.value;
prach_id.restricted_set = 0;
prach_id.numerology_index = fp->numerology_index;
prach_id.nb_rx = ru->nb_rx;
prach_id.rx_prach = &oru->rx_prach;
prach_id.beams[0] = 0; // TODO: Beamforming not supported yet
// Fill PRACH PDU
nfapi_nr_prach_pdu_t *prach_pdu = &prach_id.pdu;
prach_pdu->prach_start_symbol = oru->prach_info.start_symbol;
prach_pdu->num_prach_ocas = 1; // TODO: Hardcoded.
uint16_t format0 = oru->prach_info.format & 0xff;
uint16_t format1 = (oru->prach_info.format >> 8) & 0xff;
if (format1 != 0xff) {
switch (format0) {
case 0xa1:
prach_pdu->prach_format = 11;
break;
case 0xa2:
prach_pdu->prach_format = 12;
break;
case 0xa3:
prach_pdu->prach_format = 13;
break;
default:
AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
}
} else {
switch (format0) {
case 0:
prach_pdu->prach_format = 0;
break;
case 1:
prach_pdu->prach_format = 1;
break;
case 2:
prach_pdu->prach_format = 2;
break;
case 3:
prach_pdu->prach_format = 3;
break;
case 0xa1:
prach_pdu->prach_format = 4;
break;
case 0xa2:
prach_pdu->prach_format = 5;
break;
case 0xa3:
prach_pdu->prach_format = 6;
break;
case 0xb1:
prach_pdu->prach_format = 7;
break;
case 0xb4:
prach_pdu->prach_format = 8;
break;
case 0xc0:
prach_pdu->prach_format = 9;
break;
case 0xc2:
prach_pdu->prach_format = 10;
break;
default:
AssertFatal(1 == 0, "Invalid PRACH format");
}
}
rx_nr_prach_ru(&prach_id, ru->common.rxdata, fp, ru->N_TA_offset);
uint32_t *prach_sig[fp->nb_antennas_rx];
for (int i = 0; i < fp->nb_antennas_rx; i++) {
prach_sig[i] = (uint32_t *)prach_id.rxsigF[0][i];
}
ru->ifdevice.xran_api.north_write_prach_func(prach_sig, prach_id.slot, prach_id.frame);
}
}
void receive_pusch(ORU_t *oru, int frame, int slot, int start_symbol, int num_symbols, thread_grid2d_t *thread_grid)
{
int aarx_start = thread_grid->y;
int aarx_stride = thread_grid->size_y;
int symbol_start = start_symbol + thread_grid->x;
int symbol_stride = thread_grid->size_x;
RU_t *ru = oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_nr_config_request_scf_t *config = &ru->config;
nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table;
AssertFatal(tdd_table->tdd_period.tl.tag == NFAPI_NR_CONFIG_TDD_PERIOD_TAG, "");
int nb_periods_per_frame = get_nb_periods_per_frame(tdd_table->tdd_period.value);
int n_tdd_period = fp->slots_per_frame / nb_periods_per_frame;
AssertFatal(n_tdd_period > 0, "n_tdd_period is zero\n");
nfapi_nr_max_num_of_symbol_per_slot_t *max_num_of_symbol_per_slot_list =
config->tdd_table.max_tdd_periodicity_list[slot % n_tdd_period].max_num_of_symbol_per_slot_list;
c16_t rxdataF[fp->symbols_per_slot * fp->ofdm_symbol_size] __attribute__((aligned(32)));
for (int aarx = aarx_start; aarx < fp->nb_antennas_rx; aarx += aarx_stride) {
for (int symbol = symbol_start; symbol < start_symbol + num_symbols; symbol += symbol_stride) {
if (max_num_of_symbol_per_slot_list[symbol].slot_config.value != 1)
continue;
nr_slot_fep_ul(fp,
ru->common.rxdata[aarx],
(int32_t *)rxdataF,
symbol,
slot,
ru->N_TA_offset);
apply_nr_rotation_symbol_RX(fp,
&rxdataF[symbol * fp->ofdm_symbol_size],
fp->symbol_rotation[link_type_ul],
fp->N_RB_UL,
slot,
symbol);
ru->ifdevice.xran_api.north_write_pusch_func((uint32_t *)&rxdataF[symbol * fp->ofdm_symbol_size],
frame,
slot,
symbol,
aarx);
}
}
}
void pusch_job(void *args) {
pusch_task_args_t *job = (pusch_task_args_t *)args;
receive_pusch(job->oru, job->frame, job->slot, job->start_symbol, job->num_symbols, &job->thread_grid);
}
void prach_job(void *args) {
prach_task_args_t *job = (prach_task_args_t *)args;
receive_prach(job->oru, job->frame, job->slot);
}
void *oru_south_read_thread(void *arg)
{
ORU_t *oru = arg;
RU_t *ru = oru->ru;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
int current_slot = 0;
int current_frame = 0;
rx_initial_sync(oru, &current_slot, &current_frame);
const int symbols_per_iteration = 4;
notifiedFIFO_t response_fifo;
initNotifiedFIFO(&response_fifo);
while (!oai_exit) {
int rx_slot_type = nr_slot_select(&ru->config, current_frame, current_slot);
for (int symbol = 0; symbol < 14; symbol += symbols_per_iteration) {
int num_symbols = min(symbols_per_iteration, 14 - symbol);
int samples_to_read = get_samples_symbol_duration(fp, current_slot, symbol, num_symbols);
size_t offset = fp->get_samples_slot_timestamp(current_slot, fp, 0) + get_samples_symbol_timestamp(fp, current_slot, symbol);
c16_t *rxp[fp->nb_antennas_rx];
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
rxp[aarx] = (c16_t *)&ru->common.rxdata[aarx][offset];
}
openair0_timestamp timestamp;
int num_samples_read = ru->rfdevice.trx_read_func(&ru->rfdevice, &timestamp, (void **)rxp, samples_to_read, ru->nb_rx);
AssertFatal(num_samples_read == samples_to_read, "Unexpected number of samples received\n");
LOG_D(PHY,
"[ORU south] read data: frame %d, slot %d, symbol %d, timestamp %ld num_symbols %d, samples %d\n",
current_frame,
current_slot,
symbol,
timestamp,
num_symbols,
num_samples_read);
if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
int num_jobs = 0;
start_meas(&oru->rx);
if (symbol == 0) {
num_jobs++;
notifiedFIFO_elt_t *prach_task = newNotifiedFIFO_elt(sizeof(prach_task_args_t), 0, &response_fifo, prach_job);
prach_task_args_t *job = NotifiedFifoData(prach_task);
job->oru = oru;
job->frame = current_frame;
job->slot = current_slot;
pushNotifiedFIFO(&oru->prach_actor.fifo, prach_task);
}
for (int i = 0; i < NUM_PUSCH_ACTORS; i++) {
num_jobs++;
notifiedFIFO_elt_t *pusch_task = newNotifiedFIFO_elt(sizeof(pusch_task_args_t), 0, &response_fifo, pusch_job);
pusch_task_args_t *job = NotifiedFifoData(pusch_task);
job->oru = oru;
job->frame = current_frame;
job->slot = current_slot;
job->start_symbol = symbol;
job->num_symbols = num_symbols;
job->thread_grid.x = 0;
job->thread_grid.size_x = 1;
job->thread_grid.y = i;
job->thread_grid.size_y = NUM_PUSCH_ACTORS;
pushNotifiedFIFO(&oru->pusch_actors[i].fifo, pusch_task);
}
while (num_jobs > 0) {
notifiedFIFO_elt_t *elt = pullNotifiedFIFO(&response_fifo);
delNotifiedFIFO_elt(elt);
num_jobs--;
}
ru->ifdevice.xran_api.north_out_func(current_slot, 0, ru->nb_rx, ((1 << num_symbols) - 1) << symbol);
stop_meas(&oru->rx);
}
}
current_slot++;
if (current_slot == fp->slots_per_frame) {
current_slot = 0;
current_frame++;
if (current_frame == 1024) {
current_frame = 0;
}
}
}
return NULL;
}

58
executables/nr-oru.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* 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 NR_ORU_H
#define NR_ORU_H
#include "thread-pool.h"
#include <executables/softmodem-common.h>
#include "openair1/PHY/defs_RU.h"
#include "openair1/PHY/defs_nr_common.h"
#include "openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h"
#include "actor.h"
#define NUM_PUSCH_ACTORS 2
typedef struct {
openair0_timestamp sample;
int slot;
int frame;
int symbol;
} initial_sync_t;
typedef struct {
pthread_t north_read_thread;
pthread_t south_read_thread;
pthread_t sync_thread;
RU_t *ru;
notifiedFIFO_t sync_fifo;
nr_prach_info_t prach_info;
time_stats_t rx_prach;
time_stats_t rx;
Actor_t prach_actor;
Actor_t pusch_actors[NUM_PUSCH_ACTORS];
int num_sync_messages_needed;
tpool_t tpool;
} ORU_t;
void *oru_north_read_thread(void *arg);
void *oru_south_read_thread(void *arg);
void *oru_sync_thread(void *arg);
#endif

View File

@@ -56,6 +56,8 @@ static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFRUTPCORES[] = {-1,-1,-1,-1};
static int DEFBW[] = {273};
static int DEFCARRIER[] = {3430560};
#include "ENB_APP/enb_paramdef.h"
#include "GNB_APP/gnb_paramdef.h"
@@ -561,7 +563,7 @@ void fh_if4p5_north_out(RU_t *ru) {
stop_meas(&ru->tx_fhaul);
}
static void rx_rf(RU_t *ru, int *frame, int *slot)
void rx_rf(RU_t *ru, int *frame, int *slot)
{
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
@@ -714,7 +716,7 @@ static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot)
return flags_gpio;
}
void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
void tx_rf_symbols(RU_t *ru, int frame, int slot, uint64_t timestamp, int start_symbol, int num_symbols)
{
RU_proc_t *proc = &ru->proc;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
@@ -727,7 +729,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
T_INT(0),
T_BUFFER(&ru->common.txdata[0][fp->get_samples_slot_timestamp(slot, fp, 0)], fp->get_samples_per_slot(slot, fp) * 4));
int sf_extension = 0;
int siglen=fp->get_samples_per_slot(slot,fp);
uint32_t siglen = 0;
radio_tx_burst_flag_t flags_burst = TX_BURST_INVALID;
radio_tx_gpio_flag_t flags_gpio = 0;
@@ -741,22 +743,23 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
txsymb++;
}
AssertFatal(txsymb>0,"illegal txsymb %d\n",txsymb);
AssertFatal(txsymb > 0, "illegal txsymb %d\n", txsymb);
if (fp->slots_per_subframe == 1) {
if (txsymb <= 7)
siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
else
siglen = 2 * (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 2) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
} else {
if(slot%(fp->slots_per_subframe/2))
siglen = txsymb * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
else
siglen = (fp->ofdm_symbol_size + fp->nb_prefix_samples0) + (txsymb - 1) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
if (txsymb < start_symbol) {
// No DL symbols in this transmission
return;
}
//+ ru->end_of_burst_delay;
flags_burst = TX_BURST_END;
int end_symbol = start_symbol + num_symbols - 1;
if (end_symbol >= txsymb) {
flags_burst = TX_BURST_END;
} else {
flags_burst = TX_BURST_MIDDLE;
}
int num_symbols_this_transmission = min(txsymb, end_symbol) - start_symbol + 1;
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols_this_transmission);
} else if (slot_type == NR_DOWNLINK_SLOT) {
int prevslot_type = nr_slot_select(cfg,frame,(slot+(fp->slots_per_frame-1))%fp->slots_per_frame);
int nextslot_type = nr_slot_select(cfg,frame,(slot+1)%fp->slots_per_frame);
@@ -768,9 +771,11 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
} else {
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
}
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols);
}
} else { // FDD
flags_burst = proc->first_tx == 1 ? TX_BURST_START : TX_BURST_MIDDLE;
siglen = get_samples_symbol_duration(fp, slot, start_symbol, num_symbols);
}
if (ru->openair0_cfg.gpio_controller != RU_GPIO_CONTROL_NONE)
@@ -785,8 +790,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
int nt = ru->nb_tx * ru->num_beams_period;
void *txp[nt];
uint32_t time_offset = fp->get_samples_slot_timestamp(slot, fp, 0) + get_samples_symbol_timestamp(fp, slot, start_symbol);
for (int i = 0; i < nt; i++)
txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t);
txp[i] = (void *)&ru->common.txdata[i][time_offset] - sf_extension * sizeof(int32_t);
VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff);
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 1);
@@ -813,7 +819,12 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp)
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0);
}
static void fill_rf_config(RU_t *ru, char *rf_config_file)
void tx_rf(RU_t *ru, int frame, int slot, uint64_t timestamp)
{
tx_rf_symbols(ru, frame, slot, timestamp, 0, 14);
}
void fill_rf_config(RU_t *ru, char *rf_config_file)
{
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
nfapi_nr_config_request_scf_t *config = &ru->config; //tmp index
@@ -878,7 +889,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file)
}
}
static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp)
void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp)
{
const nfapi_nr_prach_config_t *prach_config = &config->prach_config;
const nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table;
@@ -1469,6 +1480,7 @@ void set_function_spec_param(RU_t *ru)
reset_meas(&ru->tx_fhaul);
reset_meas(&ru->compression);
reset_meas(&ru->transport);
LOG_I(NR_PHY,"Setting IF4p5 (7.2 split)\n");
} else if (ru->function == gNodeB_3GPP) {
ru->do_prach = 0; // no prach processing in RU
ru->feprx = nr_fep_tp; // this is frequency-shift + DFTs
@@ -1560,8 +1572,13 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
}
}
PHY_VARS_gNB *gNB_RC = RC.gNB[0];
PHY_VARS_gNB *gNB0 = ru->gNB_list[0];
PHY_VARS_gNB *gNB_RC = NULL;
PHY_VARS_gNB *gNB0 = NULL;
if (RC.nb_nr_L1_inst > 0) {
gNB_RC = RC.gNB[0];
gNB0 = ru->gNB_list[0];
}
LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
if (gNB0) {
@@ -1577,6 +1594,9 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
}
}
}
else {
nr_ru_init_frame_parms(ru);
}
set_function_spec_param(ru);
init_RU_proc(ru);
if (ru->if_south != REMOTE_IF4p5) {
@@ -1603,9 +1623,8 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file)
LOG_D(HW,"[nr-softmodem.c] RU threads created\n");
}
void start_NR_RU()
void start_NR_RU(RU_t *ru)
{
RU_t *ru = RC.ru[0];
start_RU_proc(ru);
}
@@ -1796,8 +1815,23 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg)
ru->if_freq_offset = *param[RU_IF_FREQ_OFFSET].iptr;
ru->sl_ahead = *param[RU_SL_AHEAD].iptr;
ru->num_bands = param[RU_BAND_LIST_IDX].numelt;
for (int i = 0; i < ru->num_bands; i++)
for (int i = 0; i < ru->num_bands; i++) {
ru->band[i] = param[RU_BAND_LIST_IDX].iptr[i];
ru->bw_tx[i] = param[RU_TX_BW_LIST_IDX].iptr[i];
ru->bw_rx[i] = param[RU_RX_BW_LIST_IDX].iptr[i];
ru->carrier_freq_tx[i] = param[RU_TX_CARRIER_LIST_IDX].iptr[i];
ru->carrier_freq_rx[i] = param[RU_RX_CARRIER_LIST_IDX].iptr[i];
}
ru->frame_type = *param[RU_FRAME_TYPE_IDX].iptr;
ru->prach_config_index = *param[RU_PRACH_CONFIGID_IDX].iptr;
ru->prach_msg1_freq = *param[RU_PRACH_MSG1FREQ_IDX].iptr;
ru->numerology = *param[RU_NUMEROLOGY_IDX].iptr;
ru->tdd_period = *param[RU_TDD_PERIOD_IDX].iptr;
ru->num_DL_slots = *param[RU_NUM_DL_SLOTS_IDX].iptr;
ru->num_UL_slots = *param[RU_NUM_UL_SLOTS_IDX].iptr;
ru->num_DL_symbols = *param[RU_NUM_DL_SYMBOLS_IDX].iptr;
ru->num_UL_symbols = *param[RU_NUM_UL_SYMBOLS_IDX].iptr;
ru->openair0_cfg.nr_flag = *param[RU_NR_FLAG].iptr;
ru->openair0_cfg.nr_band = ru->band[0];
ru->openair0_cfg.nr_scs_for_raster = *param[RU_NR_SCS_FOR_RASTER].iptr;

View File

@@ -87,6 +87,7 @@ unsigned short config_frames[4] = {2,9,11,13};
#include "x2ap_eNB.h"
#include "openair1/SCHED_NR/sched_nr.h"
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
#include "instrumentation.h"
pthread_cond_t nfapi_sync_cond;
pthread_mutex_t nfapi_sync_mutex;
@@ -444,7 +445,7 @@ int start_L1L2(module_id_t gnb_id)
init_NR_RU(config_get_if(), NULL);
start_NR_RU();
start_NR_RU(RC.ru[0]);
wait_RUs();
init_eNB_afterRU();
LOG_I(GNB_APP, "Sending sync to all threads\n");
@@ -662,7 +663,7 @@ int main( int argc, char **argv ) {
wait_f1_setup_response();
if (RC.nb_RU > 0)
start_NR_RU();
start_NR_RU(RC.ru[0]);
#ifdef ENABLE_AERIAL
gNB_MAC_INST *nrmac = RC.nrmac[0];

View File

@@ -47,7 +47,7 @@ extern void stop_gNB(int);
// In nr-ru.c
extern void init_NR_RU(configmodule_interface_t *cfg, char *);
extern void init_RU_proc(RU_t *ru);
extern void start_NR_RU(void);
extern void start_NR_RU(RU_t *ru);
extern void stop_RU(int nb_ru);
extern void kill_NR_RU_proc(int inst);
extern void set_function_spec_param(RU_t *ru);

View File

@@ -33,20 +33,23 @@ void nr_phy_init_RU(RU_t *ru)
LOG_D(PHY, "Initializing RU signal buffers (if_south %s) nb_tx %d, nb_rx %d\n", ru_if_types[ru->if_south], ru->nb_tx, ru->nb_rx);
nfapi_nr_config_request_scf_t *cfg = &ru->config;
ru->nb_log_antennas = 0;
for (int n = 0; n < ru->num_gNB; n++) {
if (cfg->carrier_config.num_tx_ant.value > ru->nb_log_antennas)
ru->nb_log_antennas = cfg->carrier_config.num_tx_ant.value;
ru->num_beams_period = 1;
if (ru->num_gNB > 0) {
nfapi_nr_config_request_scf_t *cfg = &ru->config;
ru->nb_log_antennas = 0;
for (int n = 0; n < ru->num_gNB; n++) {
if (cfg->carrier_config.num_tx_ant.value > ru->nb_log_antennas)
ru->nb_log_antennas = cfg->carrier_config.num_tx_ant.value;
}
nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve;
ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1;
}
else ru->nb_log_antennas = ru->nb_tx;
// copy configuration from gNB[0] in to RU, assume that all gNB instances sharing RU use the same configuration
// (at least the parts that are needed by the RU, numerology and PRACH)
AssertFatal(ru->nb_log_antennas > 0 && ru->nb_log_antennas < 13, "ru->nb_log_antennas %d ! \n",ru->nb_log_antennas);
nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve;
ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1;
int nb_tx_streams = ru->nb_tx * ru->num_beams_period;
int nb_rx_streams = ru->nb_rx * ru->num_beams_period;
LOG_I(NR_PHY, "nb_tx_streams %d, nb_rx_streams %d, num_Beams_period %d\n", nb_tx_streams, nb_rx_streams, ru->num_beams_period);

View File

@@ -259,6 +259,55 @@ uint32_t get_samples_per_slot(int slot, const NR_DL_FRAME_PARMS *fp)
return samp_count;
}
uint32_t get_samples_symbol_duration(const NR_DL_FRAME_PARMS *fp, int slot, int start_symbol, int num_symbols)
{
int end_symbol = start_symbol + num_symbols - 1;
AssertFatal(start_symbol <= end_symbol && start_symbol >= 0 && end_symbol < fp->symbols_per_slot,
"Symbol range is invalid start_symbol %d, num_symbols %d symbols_per_slot %d\n",
start_symbol,
num_symbols,
fp->symbols_per_slot);
if (num_symbols == fp->symbols_per_slot) {
return get_samples_per_slot(slot, fp);
}
uint32_t num_samples = 0;
int num_symbols_added = 0;
// Handle symbols with different nb_prefix_samples0
if (fp->numerology_index == 0) {
// Add symbol 0
if (start_symbol == 0) {
num_samples += fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
num_symbols_added++;
}
// Add symbol 7
if (start_symbol <= 7 && end_symbol >= 7) {
num_samples += fp->nb_prefix_samples0 + fp->ofdm_symbol_size;
num_symbols_added++;
}
} else {
// Add first symbol
if (start_symbol == 0) {
num_samples += (slot % (fp->slots_per_subframe / 2)) ? fp->nb_prefix_samples : fp->nb_prefix_samples0;
num_samples += fp->ofdm_symbol_size;
num_symbols_added++;
}
}
int num_symbols_left = max(0, num_symbols - num_symbols_added);
num_samples += num_symbols_left * (fp->nb_prefix_samples + fp->ofdm_symbol_size);
return num_samples;
}
uint32_t get_samples_symbol_timestamp(const NR_DL_FRAME_PARMS *fp, int slot, int symbol)
{
if (symbol == 0) {
return 0;
}
return get_samples_symbol_duration(fp, slot, 0, symbol);
}
uint32_t get_slot_from_timestamp(openair0_timestamp timestamp_rx, const NR_DL_FRAME_PARMS *fp)
{
uint32_t slot_idx = 0;
@@ -286,6 +335,93 @@ uint32_t get_samples_slot_timestamp(int slot, const NR_DL_FRAME_PARMS *fp, unsig
return samp_count;
}
void nr_ru_init_frame_parms(RU_t *ru)
{
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
fp->frame_type = ru->frame_type;
ru->config.cell_config.frame_duplex_type.value = ru->frame_type;
ru->config.cell_config.frame_duplex_type.tl.tag = 0x100D;
fp->N_RB_DL = ru->bw_tx[0];
ru->config.ssb_config.scs_common.value = ru->numerology;
ru->config.carrier_config.dl_grid_size[ru->config.ssb_config.scs_common.value].value = ru->bw_tx[0];
fp->N_RB_UL = ru->bw_rx[0];
ru->config.carrier_config.ul_grid_size[ru->config.ssb_config.scs_common.value].value = ru->bw_rx[0];
fp->numerology_index = ru->numerology;
fp->nr_band = ru->band[0];
LOG_I(NR_PHY,
"Set RU frame type to %s, N_RB_DL %d, N_RB_UL %d, mu %d\n",
ru->frame_type == TDD ? "TDD" : "FDD",
ru->bw_tx[0],
ru->bw_rx[0],
ru->numerology);
set_scs_parameters(fp, fp->numerology_index, ru->bw_tx[0]);
fp->slots_per_frame = 10 * fp->slots_per_subframe;
fp->nb_antennas_rx = ru->nb_rx;
fp->nb_antennas_tx = ru->nb_tx;
fp->symbols_per_slot = 14;
fp->samples_per_subframe_wCP = fp->ofdm_symbol_size * fp->symbols_per_slot * fp->slots_per_subframe;
fp->samples_per_frame_wCP = 10 * fp->samples_per_subframe_wCP;
fp->samples_per_slot_wCP = fp->symbols_per_slot * fp->ofdm_symbol_size;
fp->samples_per_slotN0 = (fp->nb_prefix_samples + fp->ofdm_symbol_size) * fp->symbols_per_slot;
fp->samples_per_slot0 =
fp->nb_prefix_samples0 + ((fp->symbols_per_slot - 1) * fp->nb_prefix_samples) + (fp->symbols_per_slot * fp->ofdm_symbol_size);
fp->samples_per_subframe = (fp->nb_prefix_samples0 + fp->ofdm_symbol_size) * 2
+ (fp->nb_prefix_samples + fp->ofdm_symbol_size) * (fp->symbols_per_slot * fp->slots_per_subframe - 2);
fp->get_samples_per_slot = &get_samples_per_slot;
fp->get_samples_slot_timestamp = &get_samples_slot_timestamp;
fp->get_slot_from_timestamp = &get_slot_from_timestamp;
fp->samples_per_frame = 10 * fp->samples_per_subframe;
fp->freq_range = (ru->carrier_freq_tx[0] < 6e6) ? FR1 : FR2;
fp->dl_CarrierFreq = (double)ru->carrier_freq_tx[0] * 1000;
fp->ul_CarrierFreq = (double)ru->carrier_freq_rx[0] * 1000;
fp->Ncp = NORMAL;
// Split 7.2 parameters
ru->config.prach_config.num_prach_fd_occasions.value = 1;
ru->config.prach_config.prach_ConfigurationIndex.value = ru->prach_config_index;
ru->config.prach_config.prach_ConfigurationIndex.tl.tag = 0x1029;
ru->config.prach_config.num_prach_fd_occasions_list = malloc(sizeof(*ru->config.prach_config.num_prach_fd_occasions_list));
ru->config.prach_config.num_prach_fd_occasions_list[0].k1.value = ru->prach_msg1_freq;
if (ru->config.cell_config.frame_duplex_type.value == 1 /* TDD */) {
ru->config.tdd_table.tdd_period.value = ru->tdd_period;
ru->config.tdd_table.tdd_period.tl.tag = 0x1026;
int numb_slots_frame = (1 << ru->numerology) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
int numb_period_frame = get_nb_periods_per_frame(ru->tdd_period);
int numb_slots_period = numb_slots_frame / numb_period_frame;
ru->config.tdd_table.max_tdd_periodicity_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list) * (numb_slots_frame));
for (int n = 0; n < numb_slots_frame; n++) {
int s = 0;
int p = n % numb_slots_period;
if (p < ru->num_DL_slots) {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < 14; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 0;
} else if (p == ru->num_DL_slots) {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < ru->num_DL_symbols; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 0;
for (; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT - ru->num_UL_symbols; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 2;
for (; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 1;
} else {
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list =
malloc(sizeof(*ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list)
* NR_NUMBER_OF_SYMBOLS_PER_SLOT);
for (s = 0; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT; s++)
ru->config.tdd_table.max_tdd_periodicity_list[n].max_num_of_symbol_per_slot_list[s].slot_config.value = 1;
}
}
}
}
void nr_init_frame_parms(nfapi_nr_config_request_scf_t* cfg, NR_DL_FRAME_PARMS *fp)
{

View File

@@ -27,6 +27,7 @@
int nr_get_ssb_start_symbol(const NR_DL_FRAME_PARMS *fp, uint8_t i_ssb);
void nr_init_frame_parms(nfapi_nr_config_request_scf_t *config, NR_DL_FRAME_PARMS *frame_parms);
void nr_ru_init_frame_parms(RU_t *ru);
int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *frame_parms, fapi_nr_config_request_t *config, uint16_t nr_band);
void nr_init_frame_parms_ue_sa(NR_DL_FRAME_PARMS *frame_parms, uint64_t downlink_frequency, int32_t uplink_frequency_offset, uint8_t mu, uint16_t nr_band);
int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp,

View File

@@ -647,6 +647,7 @@ void init_symbol_rotation(NR_DL_FRAME_PARMS *fp)
void init_timeshift_rotation(NR_DL_FRAME_PARMS *fp)
{
AssertFatal(fp->ofdm_offset_divisor != 0, "OFDM offset divisor is zero\n");
const int sample_offset = fp->nb_prefix_samples / fp->ofdm_offset_divisor;
for (int i = 0; i < fp->ofdm_symbol_size; i++) {
double poff = -i * 2.0 * M_PI * sample_offset / fp->ofdm_symbol_size;

View File

@@ -19,6 +19,7 @@
* contact@openairinterface.org
*/
#include "PHY/TOOLS/tools_defs.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/defs_gNB.h"
#include "modulation_UE.h"

View File

@@ -30,6 +30,7 @@
* \warning
*/
#include "PHY/TOOLS/tools_defs.h"
#include "PHY/defs_gNB.h"
#include "SCHED_NR/sched_nr.h"
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
@@ -368,7 +369,7 @@ static void rx_nr_prach_ru_internal(prach_item_t *p,
c16_t *prach2 = prach + Ncp;
c16_t rxsigF_tmp[N_ZC];
memset(rxsigF_tmp, 0, sizeof(rxsigF_tmp));
for (int i = 0; i < reps; i++, prach2 += dftlen) {
for (int i = 0; i < 4; i++, prach2 += dftlen) {
c16_t tmp[dftlen] __attribute__((aligned(32)));
dft(dftsize, (int16_t *)prach2, (int16_t *)tmp, 1);
// Coherent combining of PRACH repetitions (assumes channel does not change, to be revisted for "long" PRACH)

View File

@@ -461,6 +461,32 @@ typedef struct RU_t_s {
int num_bands;
/// band list
int band[MAX_BANDS_PER_RRU];
/// tx carrier
uint64_t carrier_freq_tx[MAX_BANDS_PER_RRU];
/// rx carrier
uint64_t carrier_freq_rx[MAX_BANDS_PER_RRU];
/// tx BW in PRBs
int bw_tx[MAX_BANDS_PER_RRU];
/// rx BW in PRBs
int bw_rx[MAX_BANDS_PER_RRU];
/// 3GPP FRAME Type FDD/TDD
int frame_type;
/// 3GPP PRACH configuration index
int prach_config_index;
/// 3GPP MSG1 Start frequency
int prach_msg1_freq;
int num_root_sequences;
int prach_root_sequence_index;
/// 3GPP TDD periodicity (0.5 ms, 1 0.625ms, 2 1ms, 3 1.25ms, 4 2ms,5 2.5ms, 6 5ms, 7 10ms, 8 3ms, 9 4ms
int tdd_period;
/// number of DL slots
int num_DL_slots;
/// number of UL slots
int num_UL_slots;
/// number of DL symbols
int num_DL_symbols;
/// number of UL symbols
int num_UL_symbols;
/// number of RX paths on device
int nb_rx;
/// number of TX paths on device

View File

@@ -331,4 +331,9 @@ typedef struct {
#define KHz (1000UL)
#define MHz (1000*KHz)
// Get symbol duration within slot in samples
uint32_t get_samples_symbol_duration(const NR_DL_FRAME_PARMS *fp, int slot, int start_symbol, int num_symbols);
// Get timestamp of of symbol within slot in samples
uint32_t get_samples_symbol_timestamp(const NR_DL_FRAME_PARMS *fp, int slot, int symbol);
#endif

View File

@@ -113,6 +113,21 @@ typedef enum {
#define CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION "half_slot_parallelization"
#define CONFIG_STRING_RU_RU_THREAD_CORE "ru_thread_core"
#define CONFIG_STRING_RU_GPIO_CONTROL "gpio_controller"
#define CONFIG_STRING_RU_TX_BW_LIST "tx_bw"
#define CONFIG_STRING_RU_RX_BW_LIST "rx_bw"
#define CONFIG_STRING_RU_CARRIER_TX_LIST "carrier_tx"
#define CONFIG_STRING_RU_CARRIER_RX_LIST "carrier_rx"
#define CONFIG_STRING_RU_FRAME_TYPE "frame_type"
#define CONFIG_STRING_RU_PRACH_CONFIGID "prach_config_index"
#define CONFIG_STRING_RU_PRACH_MSG1FREQ "prach_msg1_start"
#define CONFIG_STRING_RU_PRACH_ROOTSEQ "prach_root_sequence_index"
#define CONFIG_STRING_RU_NUM_ROOTSEQ "num_root_sequences"
#define CONFIG_STRING_RU_NUMEROLOGY "mu"
#define CONFIG_STRING_RU_TDD_PERIOD "tdd_period"
#define CONFIG_STRING_RU_NUM_DL_SLOTS "num_dl_slots"
#define CONFIG_STRING_RU_NUM_UL_SLOTS "num_ul_slots"
#define CONFIG_STRING_RU_NUM_DL_SYMBOLS "num_dl_symbols"
#define CONFIG_STRING_RU_NUM_UL_SYMBOLS "num_ul_symbols"
#define HLP_RU_SF_AHEAD "LTE TX processing advance"
#define HLP_RU_SL_AHEAD "NR TX processing advance"
@@ -126,6 +141,20 @@ typedef enum {
#define HLP_RU_HALF_SLOT_PARALLELIZATION "run half slots in parallel in RU FEP"
#define HLP_RU_RU_THREAD_CORE "id of core to pin ru_thread, -1 is default"
#define HLP_RU_GPIO_CONTROL "set the GPIO control type for the RU"
#define HLP_RU_TX_BW "set the TX bandwidth list per component carrier"
#define HLP_RU_RX_BW "set the RX bandwidth list per component carrier"
#define HLP_RU_CARRIER_TX "set the TX carrier frequencies per component carrier"
#define HLP_RU_CARRIER_RX "set the RX carrier frequencies per component carrier"
#define HLP_RU_FRAMETYPE "set the Frame type TDD/FDD of all component carriers"
#define HLP_RU_PRACH_CONFIGID "set the PRACH configuration id of all component carriers"
#define HLP_RU_PRACH_MSG1FREQ "set the PRACH MSG1 frequency of all component carriers"
#define HLP_RU_NUMEROLOGY "set the numerology of the RU"
#define HLP_RU_TDD_PERIOD "set the 3GPP TDD periodificty 0-9"
#define HLP_RU_NUM_DL_SLOTS "set the number of DL Slots in TDD"
#define HLP_RU_NUM_UL_SLOTS "set the number of UL Slots in TDD"
#define HLP_RU_NUM_DL_SYMBOLS "set the number of DL symbols in the mixed slot"
#define HLP_RU_NUM_UL_SYMBOLS "set the number of UL symbols in the mixed slot"
#define RU_LOCAL_IF_NAME_IDX 0
#define RU_LOCAL_ADDRESS_IDX 1
@@ -170,6 +199,19 @@ typedef enum {
#define RU_HALF_SLOT_PARALLELIZATION 40
#define RU_RU_THREAD_CORE 41
#define RU_GPIO_CONTROL 42
#define RU_TX_BW_LIST_IDX 43
#define RU_RX_BW_LIST_IDX 44
#define RU_TX_CARRIER_LIST_IDX 45
#define RU_RX_CARRIER_LIST_IDX 46
#define RU_FRAME_TYPE_IDX 47
#define RU_PRACH_CONFIGID_IDX 48
#define RU_PRACH_MSG1FREQ_IDX 49
#define RU_NUMEROLOGY_IDX 50
#define RU_TDD_PERIOD_IDX 51
#define RU_NUM_DL_SLOTS_IDX 52
#define RU_NUM_UL_SLOTS_IDX 53
#define RU_NUM_DL_SYMBOLS_IDX 54
#define RU_NUM_UL_SYMBOLS_IDX 55
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
/* RU configuration parameters */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
@@ -219,6 +261,19 @@ typedef enum {
{CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION, HLP_RU_HALF_SLOT_PARALLELIZATION, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_RU_THREAD_CORE, HLP_RU_RU_THREAD_CORE, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_GPIO_CONTROL, HLP_RU_GPIO_CONTROL, 0, .strptr=NULL, .defstrval="generic", TYPE_STRING, 0}, \
{CONFIG_STRING_RU_TX_BW_LIST, HLP_RU_TX_BW, 0, .iptr=NULL, .defintarrayval=DEFBW, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_RU_RX_BW_LIST, HLP_RU_RX_BW, 0, .iptr=NULL, .defintarrayval=DEFBW, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_RU_CARRIER_TX_LIST, HLP_RU_CARRIER_TX, 0, .iptr=NULL, .defintarrayval=DEFCARRIER, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_RU_CARRIER_RX_LIST, HLP_RU_CARRIER_RX, 0, .iptr=NULL, .defintarrayval=DEFCARRIER, TYPE_INTARRAY, 0}, \
{CONFIG_STRING_RU_FRAME_TYPE, HLP_RU_FRAMETYPE, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_PRACH_CONFIGID, HLP_RU_PRACH_CONFIGID, 0, .uptr=NULL, .defintval=152, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_PRACH_MSG1FREQ, HLP_RU_PRACH_MSG1FREQ, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUMEROLOGY, HLP_RU_NUMEROLOGY, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_TDD_PERIOD, HLP_RU_TDD_PERIOD, 0, .uptr=NULL, .defintval=5, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_DL_SLOTS, HLP_RU_NUM_DL_SLOTS, 0, .uptr=NULL, .defintval=3, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_UL_SLOTS, HLP_RU_NUM_UL_SLOTS, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_DL_SYMBOLS, HLP_RU_NUM_DL_SYMBOLS, 0, .uptr=NULL, .defintval=7, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_UL_SYMBOLS, HLP_RU_NUM_UL_SYMBOLS, 0, .uptr=NULL, .defintval=3, TYPE_UINT, 0}, \
}
// clang-format on

View File

@@ -84,7 +84,8 @@ static int DEFBANDS[] = {7};
static int DEFENBS[] = {0};
static int DEFBFW[] = {0x00007fff};
static int DEFRUTPCORES[] = {-1,-1,-1,-1};
static int DEFBW[] = {273};
static int DEFCARRIER[] = {3430560};
/**
* @brief Helper define to allocate and initialize SetupRelease structures
*/

View File

@@ -29,6 +29,8 @@
* \note The PRACH configuration tables are used in the MAC layer for scheduling and beyond.
* For example the PRACH duration is requested in the O-RAN 7.2 FrontHaul Interface
*/
#ifndef NR_PRACH_CONFIG_H_
#define NR_PRACH_CONFIG_H_
/**
* @brief Fetch PRACH format (format only) from PRACH configuration tables
@@ -73,3 +75,5 @@ nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_r
* @return PRACH format (format concatenated with format2)
*/
uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired);
#endif

View File

@@ -275,6 +275,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, NR_UE_MAC_reset_cause_t ca
memset(&mac->sc_info, 0, sizeof(mac->sc_info));
mac->current_DL_BWP = NULL;
LOG_W(NR_MAC, "Releasing MAC configuration for UE %d cause %d\n", mac->ue_id, cause);
mac->current_UL_BWP = NULL;
// in case of re-establishment we don't need to release initial BWP config common

View File

@@ -47,3 +47,8 @@ add_boolean_option(OAI_RF_EMULATOR ON "Activate OAI's RF emulator" OFF)
if(OAI_RF_EMULATOR)
add_subdirectory(emulator)
endif()
add_boolean_option(OAI_FD_RFSIM ON "Activate OAI's FD RFsim adapter driver" OFF)
if(OAI_FD_RFSIM)
add_subdirectory(fd_rfsim)
endif()

View File

@@ -175,6 +175,19 @@ int openair0_transport_load(openair0_device *device,
return rc;
}
int openair0_load(openair0_device *device, char *name, openair0_config_t *openair0_cfg, eth_params_t *eth_params)
{
loader_shlibfunc_t shlib_fdesc[1];
int ret = 0;
shlib_fdesc[0].fname = eth_params == NULL ? "device_init" : "transport_init";
ret = load_module_shlib(name, shlib_fdesc, 1, NULL);
AssertFatal((ret >= 0), "Library %s couldn't be loaded\n", name);
return ((devfunc_t)shlib_fdesc[0].fptr)(device, openair0_cfg, eth_params);
}
static void writerEnqueue(re_order_t *ctx, openair0_timestamp timestamp, void **txp, int nsamps, int nbAnt, int flags)
{
pthread_mutex_lock(&ctx->mutex_store);

View File

@@ -408,6 +408,14 @@ typedef struct {
} queue[WRITE_QUEUE_SZ];
} re_order_t;
/*! \brief Provides a way to map between a symbol and a timespec */
typedef struct {
int frame;
int slot;
int symbol;
struct timespec ts;
} sense_of_time_t;
/*!\brief structure holds the parameters to configure USRP devices */
struct openair0_device_t {
/*!tx write thread*/
@@ -555,6 +563,10 @@ struct openair0_device_t {
*/
int (*trx_stop_func)(openair0_device *device);
/*! \brief Get timestamp from timespec
*/
openair0_timestamp (*get_timestamp)(openair0_device *device, struct timespec *ts);
/* Functions API related to UE*/
/*! \brief Set RX feaquencies
@@ -610,6 +622,40 @@ struct openair0_device_t {
*/
time_stats_t tx_fhaul;
re_order_t reOrder;
// Function pointers used for oran
struct {
/*! \brief O-RU only: reads DL FD IQ. Data is put into the beginning of txdataF buffer regardless
* of the returned start_symbol. maximum number of symbols returned is 7
* \param txdataF An array of nb_tx buffers to write the samples to
* \param nb_tx number of TX antennas and number of buffer in txDataF_BF
* \param sense_of_time frame, slot and symbol with mapping to clock_gettime result
* \param num_symbols number of symbols
*/
void (*north_in_func)(uint32_t **txdataF, int nb_tx, sense_of_time_t* sense_of_time, int *num_symbols);
/*! \brief O-RU only: writes PRACH FD IQ.
* \param prachF buffer containing PRACH samples
* \param slot
*/
void (*north_write_prach_func)(uint32_t **prachF, int slot, int frame);
/*! \brief O-RU only: writes PUSCH FD IQ.
* \param puschF buffer containing PUSCH samples
* \param slot
* \param frame
* \param antenna_id antenna index to write to
* \param symbol_mask bit mask indicating which symbols to read from puschF
*/
void (*north_write_pusch_func)(uint32_t *puschF, int frame, int slot, int symbol, int aarx);
/*! \brief O-RU only: sends UL FD IQ.
* \param slot
* \param start_antenna_index first antenna index to send
* \param num_antennas number of antennas to send
* \param symbol_mask bit mask indicating which symbols to send
*/
void (*north_out_func)(int slot, int start_antenna_index, int num_antennas, uint32_t symbol_mask);
} xran_api;
};
/* type of device init function, implemented in shared lib */
@@ -659,7 +705,7 @@ const char *get_devname(int devtype);
int openair0_device_load(openair0_device *device, openair0_config_t *openair0_cfg);
/*! \brief Initialize transport protocol . It returns 0 if OK */
int openair0_transport_load(openair0_device *device, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
int openair0_load(openair0_device *device, char *name, openair0_config_t *openair0_cfg, eth_params_t *eth_params);
/*! \brief Get current timestamp of USRP
* \param device the hardware to use

View File

@@ -0,0 +1,8 @@
add_library(fd_rfsim MODULE fd_rfsim.c)
target_link_libraries(fd_rfsim PRIVATE atomic UTIL)
set_target_properties(fd_rfsim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
if(NOT OAI_FHI72)
add_custom_command(TARGET fd_rfsim POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink libfd_rfsim.so liboai_transpro.so
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
endif()

29
radio/fd_rfsim/README.md Normal file
View File

@@ -0,0 +1,29 @@
# FD RFsimulator Adapter
## Overview
This library provides a frequency domain adaptation layer for the OAI RFsimulator,
enabling integration with OAI O-DU configuration files. It facilitates testing and
development of 5G NR O-DU and UE components in a simulated radio environment without
real time requirements.
## Usage
### Build
```
cmake --build . --target fd_rfsim
```
Example config provided in `gnb.sa.band77.106prb.fhi72.4x4-fd-rfsim.conf`
### Run
Run gNB
```
sudo ./nr-softmodem -O ../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.106prb.fhi72.4x4-fd-rfsim.conf --rfsimulator.serveraddr server
```
Run UE
```
sudo ./nr-uesoftmodem -C 4049760000 -r 106 --numerology 1 --ssb 516 --band 77 --rfsim
```

521
radio/fd_rfsim/fd_rfsim.c Normal file
View File

@@ -0,0 +1,521 @@
/*
* 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 "platform_types.h"
#include <stdio.h>
#include <string.h>
#include "common_lib.h"
#include "radio/ETHERNET/ethernet_lib.h"
#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
#include "openair1/PHY/defs_gNB.h"
#include "../fhi_72/oran-params.h"
#include <stdatomic.h>
#include "common/utils/threadPool/notified_fifo.h"
#include "PHY/MODULATION/modulation_common.h"
#include "openair1/PHY/TOOLS/phy_scope_interface.h"
#include "openair1/PHY/MODULATION/nr_modulation.h"
#include "PHY/INIT/nr_phy_init.h"
#include "SCHED_NR/sched_nr.h"
#include "common/utils/threadPool/pthread_utils.h"
#include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h"
typedef struct {
openair0_timestamp timestamp;
int slot;
int frame;
} fd_rfsim_timestamp;
typedef struct {
bool is_started;
rru_config_msg_type_t last_msg;
bool capabilities_sent;
openair0_config_t openair0_cfg;
notifiedFIFO_t sync_fifo;
RU_t ru;
pthread_mutex_t mutex;
} fd_rfsim_state_t;
extern void nr_feptx(void *arg);
static int trx_start(openair0_device *device)
{
printf("Starting fd_rfsim\n");
fd_rfsim_state_t *s = (fd_rfsim_state_t *)device->priv;
if (s->ru.rfdevice.trx_start_func) {
if (s->ru.rfdevice.trx_start_func(&s->ru.rfdevice) < 0) {
LOG_E(HW, "Failed to start subdevice\n");
return -1;
}
}
s->is_started = true;
return 0;
}
static void trx_end(openair0_device *device)
{
fd_rfsim_state_t *s = (fd_rfsim_state_t *)device->priv;
if (s->ru.rfdevice.trx_end_func) {
s->ru.rfdevice.trx_end_func(&s->ru.rfdevice);
}
s->is_started = false;
}
static int trx_stop(openair0_device *device)
{
fd_rfsim_state_t *s = (fd_rfsim_state_t *)device->priv;
if (s->ru.rfdevice.trx_stop_func) {
if (s->ru.rfdevice.trx_stop_func(&s->ru.rfdevice) < 0) {
LOG_E(HW, "Failed to stop subdevice\n");
return -1;
}
}
s->is_started = false;
return 0;
}
static int trx_set_freq(openair0_device *device, openair0_config_t *openair0_cfg)
{
fd_rfsim_state_t *s = (fd_rfsim_state_t *)device->priv;
if (!s->is_started) {
LOG_E(HW, "Device not started, cannot set frequency\n");
return -1;
}
if (s->ru.rfdevice.trx_set_freq_func) {
if (s->ru.rfdevice.trx_set_freq_func(&s->ru.rfdevice, openair0_cfg) < 0) {
LOG_E(HW, "Failed to set frequency on subdevice\n");
return -1;
}
}
return 0;
}
static int trx_set_gains(openair0_device *device, openair0_config_t *openair0_cfg)
{
fd_rfsim_state_t *s = (fd_rfsim_state_t *)device->priv;
if (!s->is_started) {
LOG_E(HW, "Device not started, cannot set gains\n");
return -1;
}
if (s->ru.rfdevice.trx_set_gains_func) {
if (s->ru.rfdevice.trx_set_gains_func(&s->ru.rfdevice, openair0_cfg) < 0) {
LOG_E(HW, "Failed to set gains on subdevice\n");
return -1;
}
}
return 0;
}
static int trx_reset_stats(openair0_device *device)
{
fd_rfsim_state_t *s = (fd_rfsim_state_t *)device->priv;
if (!s->is_started) {
LOG_E(HW, "Device not started, cannot reset stats\n");
return -1;
}
if (s->ru.rfdevice.trx_reset_stats_func) {
return s->ru.rfdevice.trx_reset_stats_func(&s->ru.rfdevice);
}
return 0;
}
int ethernet_tune(openair0_device *device, unsigned int option, int value)
{
return 0;
}
static int trx_write_raw(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int cc, int flags)
{
return 0;
}
static int trx_read_raw(openair0_device *device, openair0_timestamp *timestamp, void **buff, int nsamps, int cc)
{
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];
}
static int trx_ctlsend(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
printf("rru_config_msg->type %d [%s]\n", rru_config_msg->type, msg_type(rru_config_msg->type));
return msg_len;
}
static int trx_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
{
RRU_CONFIG_msg_t *rru_config_msg = msg;
fd_rfsim_state_t *s = (fd_rfsim_state_t *)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;
}
extern void rx_rf(RU_t *ru, int *frame, int *slot);
void nr_fep_tp(RU_t *ru, int slot);
static void fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
{
fd_rfsim_state_t *s = (fd_rfsim_state_t *)ru->ifdevice.priv;
LOG_D(HW, "fd_rfsim: fh_if4p5_south_in: frame %d, slot %d\n", *frame, *slot);
// O-DU expects
// rxDataF here: ru_info.rxdataF = ru->common.rxdataF;
/// PRACH data here: ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id]
s->ru.common.rxdataF = ru->common.rxdataF;
NR_DL_FRAME_PARMS *fp = s->ru.nr_frame_parms;
start_meas(&s->ru.rx_fhaul);
rx_rf(&s->ru, frame, slot);
int rx_slot_type = nr_slot_select(&s->ru.config, *frame, *slot);
if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) {
prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, SEARCH_EXIST);
if (prach_id) {
rx_nr_prach_ru(prach_id, s->ru.common.rxdata, fp, s->ru.N_TA_offset);
}
nr_fep_tp(&s->ru, *slot);
if (!ru->gNB_list[0]->phase_comp) {
int soffset = (*slot & 3) * fp->symbols_per_slot * fp->ofdm_symbol_size;
for (int aa = 0; aa < fp->nb_antennas_rx; aa++) {
const uint max_symb = fp->Ncp == EXTENDED ? 12 : 14;
for (int sym = 0; sym < max_symb; sym++)
apply_nr_rotation_symbol_RX(fp,
(c16_t *)s->ru.common.rxdataF[aa] + soffset + sym * fp->ofdm_symbol_size,
fp->symbol_rotation[1],
fp->N_RB_UL,
*slot,
sym);
}
}
}
RU_proc_t *proc = &ru->proc;
int slots_per_frame = fp->slots_per_frame;
proc->tti_rx = *slot;
proc->frame_rx = *frame;
proc->tti_tx = (*slot + ru->sl_ahead) % slots_per_frame;
proc->frame_tx = (*slot > (slots_per_frame - 1 - ru->sl_ahead)) ? (*frame + 1) & 1023 : *frame;
proc->first_rx = 0;
stop_meas(&s->ru.rx_fhaul);
}
extern void tx_rf(RU_t *ru, int frame, int slot, uint64_t timestamp);
extern void nr_feptx0(RU_t *ru, int tti_tx, int first_symbol, int num_symbols, int aa);
static void fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
{
fd_rfsim_state_t *state = (fd_rfsim_state_t *)ru->ifdevice.priv;
RU_t *ru_lower = &state->ru;
ru_lower->common.txdataF_BF = ru->common.txdataF_BF;
start_meas(&ru_lower->tx_fhaul);
// FD data is available in ru->common.txdataF_BF.
NR_DL_FRAME_PARMS *fp = ru_lower->nr_frame_parms;
for (int i = 0; i < ru->nb_tx; i++) {
if (!ru->gNB_list[0]->phase_comp) {
apply_nr_rotation_TX(fp,
(c16_t *)ru->common.txdataF_BF[i],
fp->symbol_rotation[0],
slot,
fp->N_RB_DL,
0,
fp->Ncp == EXTENDED ? 12 : 14);
}
nr_feptx0(ru_lower, slot, 0, fp->Ncp == EXTENDED ? 12 : 14, i);
}
LOG_D(HW, "fd_rfsim: fh_if4p5_south_out: frame %d, slot %d, timestamp %lu\n", frame, slot, timestamp);
// Assume this function called in order
static int frame_tx_unwrap = 0;
static int last_frame = 0;
if (frame < last_frame) {
frame_tx_unwrap += 1024;
}
last_frame = frame;
uint64_t timestamp_tx = (frame + frame_tx_unwrap) * fp->samples_per_subframe * 10 + fp->get_samples_slot_timestamp(slot, fp, 0);
tx_rf(ru_lower, frame, slot, timestamp_tx);
// ru->proc = ru_lower->proc; // Copy the RU proc structure back
stop_meas(&ru_lower->tx_fhaul);
}
static void *get_internal_parameter(char *name)
{
printf("ORAN: %s\n", __FUNCTION__);
if (!strcmp(name, "fh_if4p5_south_in"))
return (void *)fh_if4p5_south_in;
if (!strcmp(name, "fh_if4p5_south_out"))
return (void *)fh_if4p5_south_out;
return NULL;
}
int get_tdd_period(uint8_t nb_periods_per_frame)
{
int tdd_period = 0;
switch (nb_periods_per_frame) {
case 20:
tdd_period = 0; // 10ms/0p5ms
break;
case 16:
tdd_period = 1; // 10ms/0p625ms
break;
case 10:
tdd_period = 2; // 10ms/1ms
break;
case 8:
tdd_period = 3; // 10ms/1p25ms
break;
case 5:
tdd_period = 4; // 10ms/2ms
break;
case 4:
tdd_period = 5; // 10ms/2p5ms
break;
case 2:
tdd_period = 6; // 10ms/5ms
break;
case 1:
tdd_period = 7; // 10ms/10ms
break;
default:
AssertFatal(1 == 0, "Undefined nb_periods_per_frame %d\n", nb_periods_per_frame);
}
return tdd_period;
}
typedef struct {
int scs;
int freq_range;
int nr_band;
int ofdm_offset_divisor;
uint64_t dl_CarrierFreq;
uint64_t ul_CarrierFreq;
int num_rb_dl;
int num_rb_ul;
int num_rx_ant;
int num_tx_ant;
} oru_config;
static void configure_ru_t_for_oru(RU_t *ru, oru_config *oru_cfg)
{
memset(ru, 0, sizeof(*ru));
ru->num_gNB = 1;
ru->nr_frame_parms = calloc_or_fail(1, sizeof(*ru->nr_frame_parms));
ru->proc.first_rx = 1;
NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms;
fp->freq_range = oru_cfg->freq_range;
fp->nr_band = oru_cfg->nr_band;
fp->ofdm_offset_divisor = oru_cfg->ofdm_offset_divisor;
fp->dl_CarrierFreq = oru_cfg->dl_CarrierFreq;
fp->ul_CarrierFreq = oru_cfg->ul_CarrierFreq;
nfapi_nr_config_request_scf_t *cfg = &ru->config;
memset(cfg, 0, sizeof(*cfg));
cfg->cell_config.frame_duplex_type.value = TDD;
cfg->ssb_config.scs_common.value = oru_cfg->scs;
cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value = oru_cfg->num_rb_dl;
cfg->carrier_config.ul_grid_size[cfg->ssb_config.scs_common.value].value = oru_cfg->num_rb_ul;
cfg->carrier_config.num_rx_ant.value = oru_cfg->num_rx_ant;
cfg->carrier_config.num_tx_ant.value = oru_cfg->num_tx_ant;
cfg->prach_config.prach_sub_c_spacing.value = oru_cfg->scs;
nr_init_frame_parms(&ru->config, fp);
init_symbol_rotation(fp);
init_timeshift_rotation(fp);
nr_dump_frame_parms(fp);
ru->if_south = LOCAL_RF;
ru->function = NGFI_RRU_IF5;
ru->nb_tx = oru_cfg->num_tx_ant;
ru->nb_rx = oru_cfg->num_rx_ant;
nr_phy_init_RU(ru);
ru->N_TA_offset = set_default_nta_offset(fp->freq_range, fp->samples_per_subframe);
}
static bool configure_fd_rfsim(openair0_device *device, openair0_config_t *openair0_config)
{
fd_rfsim_state_t *state = calloc_or_fail(1, sizeof(*state));
mutexinit(state->mutex);
state->is_started = false;
state->last_msg = (rru_config_msg_type_t)-1;
state->capabilities_sent = false;
device->priv = state;
RU_t *ru_lower = &state->ru;
oru_config oru_cfg = {
.scs = 1,
.freq_range = FR1,
.nr_band = openair0_config->nr_band,
.ofdm_offset_divisor = 8, // Default value
.dl_CarrierFreq = openair0_config->tx_freq[0],
.ul_CarrierFreq = openair0_config->rx_freq[0],
.num_rb_dl = openair0_config->num_rb_dl,
.num_rb_ul = openair0_config->num_rb_dl,
.num_rx_ant = openair0_config->rx_num_channels,
.num_tx_ant = openair0_config->tx_num_channels,
};
configure_ru_t_for_oru(ru_lower, &oru_cfg);
// Setup TDD table
ru_lower->config.tdd_table.tdd_period.value = get_tdd_period(openair0_config->split7.n_tdd_period);
NR_DL_FRAME_PARMS *fp = ru_lower->nr_frame_parms;
ru_lower->config.tdd_table.max_tdd_periodicity_list = calloc_or_fail(fp->slots_per_frame, sizeof(nfapi_nr_max_tdd_periodicity_t));
for (int i = 0; i < fp->slots_per_frame; i++) {
ru_lower->config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list =
calloc_or_fail(14, sizeof(nfapi_nr_max_num_of_symbol_per_slot_t));
for (int j = 0; j < 14; j++) {
ru_lower->config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list[j].slot_config.value =
openair0_config->split7.slot_dirs[i % openair0_config->split7.n_tdd_period].sym_dir[j];
}
}
// Allocate some threads to the threadpool
ru_lower->threadPool = calloc_or_fail(1, sizeof(*ru_lower->threadPool));
initFloatingCoresTpool(10, ru_lower->threadPool, false, "RU_lower");
// Force load RFSimulator as the RF device
memcpy(&ru_lower->openair0_cfg, openair0_config, sizeof(*openair0_config));
int ret = openair0_load(&ru_lower->rfdevice, "rfsimulator", &ru_lower->openair0_cfg, NULL);
AssertFatal(ret == 0, "Failed to load openair0 device\n");
// These are fhi_72 specific parameters, currently unused.
// 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 fd_rfsim!\n", CONFIG_STRING_ORAN);
return false;
}
paramdef_t fhip[] = ORAN_GLOBALPARAMS_DESC;
checkedparam_t fhip_CheckParams[] = ORAN_GLOBALPARAMS_CHECK_DESC;
static_assert(sizeofArray(fhip) == sizeofArray(fhip_CheckParams), "fhip and fhip_CheckParams should have the same size");
int nump = sizeofArray(fhip);
config_set_checkfunctions(fhip, fhip_CheckParams, nump);
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);
return true;
}
__attribute__((__visibility__("default"))) int transport_init(openair0_device *device,
openair0_config_t *openair0_cfg,
eth_params_t *eth_params)
{
bool ret = configure_fd_rfsim(device, openair0_cfg);
AssertFatal(ret, "Failed to configure fd_rfsim");
device->Mod_id = 0;
device->transp_type = ETHERNET_TP;
device->trx_start_func = trx_start;
device->trx_reset_stats_func = trx_reset_stats;
device->trx_end_func = trx_end;
device->trx_stop_func = trx_stop;
device->trx_set_freq_func = trx_set_freq;
device->trx_set_gains_func = trx_set_gains;
device->trx_write_func = trx_write_raw;
device->trx_read_func = trx_read_raw;
device->trx_ctlsend_func = trx_ctlsend;
device->trx_ctlrecv_func = trx_ctlrecv;
device->get_internal_parameter = get_internal_parameter;
device->openair0_cfg = openair0_cfg;
return 0;
}

View File

@@ -33,7 +33,7 @@ endif()
add_compile_options(-Wno-packed-not-aligned)
set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native")
target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} pthread dl rt m numa)
target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} pthread dl rt m numa MAC_NR_COMMON)
target_link_libraries(oran_fhlib_5g PRIVATE log_headers)
target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS})
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")

View File

@@ -19,12 +19,16 @@
* contact@openairinterface.org
*/
#include "assertions.h"
#include <bits/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "xran_fh_o_du.h"
#include "xran_compression.h"
#include "xran_pkt_up.h"
#include "armral_bfp_compression.h"
#include <time.h>
#if defined(__arm__) || defined(__aarch64__)
#else
@@ -52,6 +56,7 @@
volatile bool first_call_set = false;
int xran_is_prach_slot(uint8_t PortId, uint32_t subframe_id, uint32_t slot_id);
static bool is_tdd_ul_symbol(const struct xran_frame_config *frame_conf, int slot, int sym_idx);
#include "common/utils/LOG/log.h"
#ifndef USE_POLLING
@@ -60,6 +65,76 @@ extern notifiedFIFO_t oran_sync_fifo;
volatile oran_sync_info_t oran_sync_info = {0};
#endif
extern notifiedFIFO_t ru_dl_sync_fifo;
int32_t symbol_callback(void *args, struct xran_sense_of_time *p_sense_of_time)
{
uint32_t frame = p_sense_of_time->nFrameIdx;
uint32_t slot = p_sense_of_time->nSlotIdx;
uint32_t subframe = p_sense_of_time->nSubframeIdx;
oran_symbol_callback_args_t *callback_args = args;
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
const int slots_in_sf = 1 << fh_cfg->frame_conf.nNumerology;
uint32_t slot_in_frame = slot + subframe * slots_in_sf;
if (!first_call_set)
return 0;
static int last_frame = 0;
// Workaround for a bug in XRAN
// In XRAN, time is kept by GPS second and slot within GPS second (tti_counter).
// This is translated to 5G time within xran via xran_sfn_at_sec_start. Due to the
// way timers are setup in xran, the value of xran_sfn_at_sec_start might be incorrect
// at the beginning of the frame, causing the nFrameIdx value returned from xran to be incorrect.
// This was observed only when tti_counter == 0
int frames_per_second = 100;
bool is_xran_bug_triggered = p_sense_of_time->tti_counter == 0 && (last_frame - frames_per_second + 1 + 1024) % 1024 == frame;
if (is_xran_bug_triggered) {
frame = (frame + frames_per_second) % 1024;
}
if (last_frame != frame) {
if (((last_frame + 1024 + 1) % 1024) != frame) {
LOG_W(HW, "Frames are not in order. XRAN core might be too slow frame %d last_frame %d\n", frame, last_frame);
}
last_frame = frame;
}
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(ru_dl_sync_info_t), 0, NULL, NULL);
ru_dl_sync_info_t *info = NotifiedFifoData(req);
info->frame = frame;
info->slot = slot_in_frame;
info->symbol = callback_args->start_symbol;
int slot_duration_uS[] = {1000, 500, 250, 125};
uint64_t slot_in_second_offset_nS = ((uint64_t)p_sense_of_time->tti_counter * slot_duration_uS[fh_cfg->frame_conf.nNumerology]) * 1000UL;
float symbol_duration_nS = ((float)slot_duration_uS[fh_cfg->frame_conf.nNumerology] * 1000) / 14.0f;
uint64_t symbol_in_slot_offset_nS = (uint64_t)(callback_args->start_symbol * symbol_duration_nS);
info->ts.tv_sec = p_sense_of_time->nSecond;
info->ts.tv_nsec = slot_in_second_offset_nS + symbol_in_slot_offset_nS;
uint64_t symbol_in_slot_callback_offset_nS = (uint64_t)(p_sense_of_time->nSymIdx * symbol_duration_nS);
int64_t tv_nsec = slot_in_second_offset_nS + symbol_in_slot_callback_offset_nS;
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
AssertFatal(info->ts.tv_nsec < 1000000000UL, "ORAN: Invalid tv_nsec %ld\n", info->ts.tv_nsec);
LOG_D(HW,
"symbol time %ld.%ld current_time %ld.%ld, diff %ld diff cb %ld expected %.1f\n",
info->ts.tv_sec,
info->ts.tv_nsec,
ts.tv_sec,
ts.tv_nsec,
info->ts.tv_nsec - ts.tv_nsec,
tv_nsec - ts.tv_nsec,
7 * symbol_duration_nS);
pushNotifiedFIFO(&ru_dl_sync_fifo, req);
return 0;
}
/** @details xran-specific callback, called when all packets for given CC and
* 1/4, 1/2, 3/4, all symbols of a slot arrived. Currently, only used to get
* timing information and unblock another thread in xran_fh_rx_read_slot()
@@ -244,6 +319,122 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot)
return (0);
}
int write_prach_data(uint32_t **prachDataF, int nb_rx, int frame, int slot)
{
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
int prach_sym = 1; // TODO: Use get_prach_conf_duration(0);
struct xran_ru_config *ru_conf = &fh_cfg->ru_conf;
AssertFatal(ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE, "Only COMPMETHOD_NONE is supported in write_prach_data\n");
int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology;
int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology;
int tti = slots_per_frame * frame + slot;
uint32_t subframe = slot / slots_per_subframe;
uint32_t is_prach_slot = xran_is_prach_slot(0, subframe, (slot % slots_per_subframe));
AssertFatal(is_prach_slot, "Trying to write PRACH data in non PRACH slot %d.%d\n", frame, slot);
for (int sym_idx = 0; sym_idx < prach_sym; sym_idx++) {
for (int aa = 0; aa < nb_rx; aa++) {
oran_buf_list_t *bufs = get_xran_buffers(0);
int16_t *dst = (int16_t *)bufs->prachdst[aa][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx].pData;
int16_t *src = (int16_t *)prachDataF[aa];
if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) {
for (int idx = 0; idx < 139 * 2; idx++) {
dst[idx + g_kbar] = ((int16_t)htons(src[idx]));
}
}
}
}
return 0;
}
int write_pusch(uint32_t* txdataF_symb, int frame, int slot, int symbol, int aarx)
{
AssertFatal(txdataF_symb != NULL, "txdataF_symb is NULL\n");
int tti = 20 * frame + slot;
void *ptr = NULL;
int32_t *pos = NULL;
int idx = 0;
const struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
int nPRBs = fh_cfg->nDLRBs;
int fftsize = 1 << fh_cfg->ru_conf.fftSize;
oran_buf_list_t *bufs = get_xran_buffers(0);
const struct xran_frame_config *frame_conf = &get_xran_fh_config(0)->frame_conf;
if(!is_tdd_ul_symbol(frame_conf, slot, symbol)){
LOG_W(HW, "Trying to write PUSCH data in non UL symbol %d.%d.%d\n", frame, slot, symbol);
}
uint8_t *pData = bufs->src[aarx][tti % XRAN_N_FE_BUF_LEN].pBuffers[symbol % XRAN_NUM_OF_SYMBOL_PER_SLOT].pData;
AssertFatal(pData != NULL, "pData is NULL\n");
uint8_t *pPrbMapData = bufs->srccp[aarx][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData;
ptr = pData;
pos = (int32_t*)txdataF_symb;
uint8_t *u8dptr;
struct xran_prb_map *pRbMap = pPrbMap;
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 = &p_prbMapElm->sec_desc[symbol][0];
dst = xran_add_hdr_offset(dst, p_prbMapElm->compMethod);
AssertFatal(p_sec_desc != NULL, "p_sec_desc == NULL\n");
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 {
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;
return (0);
}
/** @brief Check if symbol in slot is UL.
*
* @param frame_conf xran frame configuration
@@ -479,6 +670,142 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot)
return (0);
}
/** @details Read DL IQ data from xran buffers on the O-RU. If I/Q compression
* (bitwidth < 16 bits) is configured, deccompresses the data before writing.
* Prints ON TIME counters every 128 frames.
*
* Function is blocking and waits for next frame/slot combination. It is unblocked
* by oai_xran_fh_rx_callback().
*/
int xran_fh_tx_read_slot(uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol, struct timespec *ts)
{
// pull next even from oran_sync_fifo
notifiedFIFO_elt_t *res = pullNotifiedFIFO(&ru_dl_sync_fifo);
ru_dl_sync_info_t *info = NotifiedFifoData(res);
*slot = info->slot;
*frame = info->frame;
*symbol = info->symbol;
*ts = info->ts;
delNotifiedFIFO_elt(res);
struct xran_fh_config *fh_cfg = get_xran_fh_config(0);
int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology;
int tti = slots_per_frame * (*frame) + (*slot);
const struct xran_fh_init *fh_init = get_xran_fh_init();
int fftsize = 1 << fh_cfg->ru_conf.fftSize;
int nPRBs = fh_cfg->nDLRBs;
oran_buf_list_t *bufs = get_xran_buffers(0);
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 < nb_tx; ant_id++) {
AssertFatal(txdataF[ant_id] != NULL, "Buffer for ant_idx %d, nb_tx %d is NULL\n", ant_id, nb_tx);
const struct xran_frame_config *frame_conf = &get_xran_fh_config(0)->frame_conf;
static struct xran_prb_map *pPrbMap;
pPrbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
AssertFatal(pPrbMap != NULL, "Invalid prbMap pointer\n");
AssertFatal(pPrbMap->cc_id == cc_id && pPrbMap->ru_port_id == 0,
"Invalid PRB map cc_id %u ru_port_id %u\n",
pPrbMap->cc_id,
pPrbMap->ru_port_id);
int32_t symbol_buffer[nPRBs * N_SC_PER_PRB] __attribute__((aligned(64)));
for (int32_t sym_idx = *symbol; sym_idx < *symbol + RU_SYMBOLS_PER_CALLBACK; sym_idx++) {
memset(symbol_buffer, 0, sizeof(symbol_buffer));
for (int prb_elem_index = 0; prb_elem_index < pPrbMap->nPrbElm; prb_elem_index++) {
struct xran_prb_elm *prb_elm = &pPrbMap->prbMap[prb_elem_index];
if (is_tdd_ul_symbol(frame_conf, *slot, sym_idx))
continue;
if (sym_idx < prb_elm->nStartSymb || sym_idx > (prb_elm->nStartSymb + prb_elm->numSymb - 1)) {
continue;
}
for (int cplane_sec_idx = 0; cplane_sec_idx < prb_elm->nSecDesc[sym_idx]; cplane_sec_idx++) {
struct xran_section_desc *sec_desc = &prb_elm->sec_desc[sym_idx][cplane_sec_idx];
if (prb_elm->compMethod == XRAN_COMPMETHOD_NONE) {
int start_prb = sec_desc->start_prbu;
int num_prb = sec_desc->num_prbu;
uint16_t *src = (uint16_t *)sec_desc->pData;
uint16_t *dst = (uint16_t *)symbol_buffer;
for (int idx = start_prb * N_SC_PER_PRB * 2; idx < (start_prb + num_prb) * N_SC_PER_PRB * 2; idx++) {
dst[idx] = (int16_t)ntohs(src[idx]);
}
} else if (prb_elm->compMethod == XRAN_COMPMETHOD_BLKFLOAT) {
struct xranlib_decompress_request bfp_decom_req = {};
struct xranlib_decompress_response bfp_decom_rsp = {};
bfp_decom_req.data_in = (int8_t *)sec_desc->pData;
bfp_decom_req.numRBs = sec_desc->num_prbu;
bfp_decom_req.len = (3 * prb_elm->iqWidth + 1) * sec_desc->num_prbu;
bfp_decom_req.compMethod = prb_elm->compMethod;
bfp_decom_req.iqWidth = prb_elm->iqWidth;
bfp_decom_rsp.data_out = (int16_t *)&symbol_buffer[sec_desc->start_prbu * N_SC_PER_PRB];
bfp_decom_rsp.len = 0;
xranlib_decompress_avx512(&bfp_decom_req, &bfp_decom_rsp);
}
}
}
int first_carrier_offset = fftsize - (nPRBs * N_SC_PER_PRB / 2);
size_t first_copy_size = fftsize - first_carrier_offset;
uint32_t *txdataF_symb = &txdataF[ant_id][sym_idx * fftsize];
memcpy(&txdataF_symb[first_carrier_offset], &symbol_buffer[0], first_copy_size * sizeof(uint32_t));
memcpy(&txdataF_symb[0], &symbol_buffer[first_copy_size], ((nPRBs * N_SC_PER_PRB) - first_copy_size) * sizeof(uint32_t));
}
}
}
if (*symbol + RU_SYMBOLS_PER_CALLBACK - 1 == 13) {
for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet.
for(uint32_t ant_id = 0; ant_id < fh_cfg->neAxc; ant_id++) {
struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData;
AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMap == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id);
for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) {
for (uint32_t idxElm = 0; idxElm < pRbMap->nPrbElm; idxElm++ ) {
struct xran_prb_elm *pRbElm = &pRbMap->prbMap[idxElm];
pRbElm->nSecDesc[sym_id] = 0; // number of section descriptors per symbol;
}
}
}
}
}
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];
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(HW,
"[o-ru %d][rx %7ld pps %7ld kbps %7ld][tx %7ld pps %7ld kbps %7ld] [on_time %ld early %ld late %ld corrupt %ld "
"pkt_dupl %ld Invalid_Ext1_packets %ld Total %ld]\n",
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].Rx_on_time,
x_counters[o_xu_id].Rx_early,
x_counters[o_xu_id].Rx_late,
x_counters[o_xu_id].Rx_corrupt,
x_counters[o_xu_id].Rx_pkt_dupl,
x_counters[o_xu_id].rx_invalid_ext1_packets,
x_counters[o_xu_id].Total_msgs_rcvd);
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;
}
/** @details Write PDSCH IQ-data from OAI txdataF_BF buffer to xran buffers. If
* I/Q compression (bitwidth < 16 bits) is configured, compresses the data
* before writing. */

View File

@@ -31,9 +31,18 @@ typedef struct {
uint32_t f;
} oran_sync_info_t;
typedef struct {
int frame;
int slot;
int symbol;
struct timespec ts;
} ru_dl_sync_info_t;
/** @brief xran callback for fronthaul RX, see xran_5g_fronthault_config(). */
void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status);
/** @brief xran callback for time alignment, see xran_reg_physide_cb(). */
int oai_physide_dl_tti_call_back(void *param);
int write_prach_data(uint32_t **prachDataF, int nb_rx, int frame, int slot);
int write_pusch(uint32_t* txdataF_symb, int frame, int slot, int symbol, int aarx);
#endif /* OAIORAN_H */

View File

@@ -184,7 +184,8 @@ void print_fh_init(const struct xran_fh_init *fh_init)
fh_init->filePrefix,
fh_init->mtu,
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);
if (fh_init->p_o_ru_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);
else if (fh_init->p_o_du_addr) 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);
printf("\
totalBfWeights %d\n",
fh_init->totalBfWeights);
@@ -466,14 +467,14 @@ char bbdev_dev[32] = "";
char bbdev_vfio_vf_token[64] = "";
#endif
static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump, const int num_rus)
static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump, const int num_peer, const int is_du)
{
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 -> xran as O-DU; 1 -> xran as O-RU
io_cfg->id = 1 - is_du; // 0 -> xran as O-DU; 1 -> xran as O-RU
io_cfg->num_vfs = num_dev; // number of VFs for C-plane and U-plane (should be even); max = XRAN_VF_MAX
io_cfg->num_rxq = 1; // number of RX queues per VF
for (int i = 0; i < num_dev; ++i) {
@@ -535,7 +536,7 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
io_cfg->io_sleep = 0; // enable sleep on PMD cores; 0 -> no sleep
io_cfg->nEthLinePerPort = *gpd(fhip, nump, ORAN_CONFIG_NETHPERPORT)->uptr; // 1, 2, 3 total number of links per O-RU (Fronthaul Ethernet link)
io_cfg->nEthLineSpeed = *gpd(fhip, nump, ORAN_CONFIG_NETHSPEED)->uptr; // 10G,25G,40G,100G speed of Physical connection on O-RU
io_cfg->one_vf_cu_plane = (io_cfg->num_vfs == num_rus); // C-plane and U-plane use one VF
io_cfg->one_vf_cu_plane = (io_cfg->num_vfs == num_peer); // C-plane and U-plane use one VF
/* eCPRI One-Way Delay Measurements common settings for O-DU and O-RU;
use owdm to calculate T12 and T34 -> CUS specification, section 2.3.3.3;
@@ -546,7 +547,7 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in
/* if RU does support, io_cfg->eowd_cmn[0] should only be filled as id = O_DU; io_cfg->eowd_cmn[1] only used if id = O_RU */
const uint16_t owdm_enable = *gpd(fhip, nump, ORAN_CONFIG_ECPRI_OWDM)->uptr;
if (owdm_enable) {
io_cfg->eowd_cmn[0].initiator_en = 1; // 1 -> initiator (always O-DU), 0 -> recipient (always O-RU)
io_cfg->eowd_cmn[0].initiator_en = is_du ? 1 : 0; // 1 -> initiator (always O-DU), 0 -> recipient (always O-RU)
io_cfg->eowd_cmn[0].numberOfSamples = 8; // total number of samples to be collected and averaged per port
io_cfg->eowd_cmn[0].filterType = 0; // 0 -> simple average based on number of measurements; not used in xran in both E and F releases
io_cfg->eowd_cmn[0].responseTo = 10000000; // response timeout in [ns]
@@ -684,6 +685,16 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
const int nfh = sizeofArray(FHconfigs);
config_getlist(config_get_if(), &FH_ConfigList, FHconfigs, nfh, aprefix);
int num_peer = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs
int is_du=0;
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
int num_du_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt;
if (num_ru_addr > 0 && num_du_addr == 0) is_du = 1;
else if (num_du_addr > 0 && num_ru_addr == 0) is_du = 0;
else AssertFatal(1==0,"Illegal node configuration, num_du_addr %d, num_ru_addr %d\n",num_du_addr,num_ru_addr);
fh_init->xran_ports = num_peer;
#ifdef OAI_MPLANE
ru_session_list_t *ru_session_list = (ru_session_list_t *)mplane_api;
int num_rus = ru_session_list->num_rus;
@@ -710,9 +721,8 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
}
}
#else
int num_rus = FH_ConfigList.numelt; // based on the number of fh_config sections -> number of RUs
fh_init->xran_ports = num_rus; // since we use xran as O-DU, xran_ports is set to the number of RUs
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_rus))
if (!set_fh_io_cfg(&fh_init->io_cfg, fhip, nump, num_peer, is_du))
return false;
if (!set_fh_eaxcid_conf(&fh_init->eAxCId_conf, xran_cat))
return false;
@@ -720,16 +730,36 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
communicated in a single xRAN network layer transaction. Supported 1500 bytes and 9600 bytes (Jumbo Frame);
xran only checks if (MTU <= 1500), therefore setting any value > 1500, xran assumes 9600 value is used */
fh_init->mtu = *gpd(fhip, nump, ORAN_CONFIG_MTU)->uptr;
int num_ru_addr = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->numelt;
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
AssertFatal(fh_init->p_o_ru_addr != NULL, "out of memory\n");
char **ru_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_ADDR)->strlistptr;
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->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
char **ru_addrs,**du_addrs;
if (is_du > 0) {
fh_init->p_o_ru_addr = calloc(num_ru_addr, sizeof(struct rte_ether_addr));
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->p_o_du_addr = NULL;
}
else {
fh_init->p_o_du_addr = calloc(num_du_addr, sizeof(struct rte_ether_addr));
du_addrs = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr;
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 = NULL;
}
#endif
@@ -738,7 +768,6 @@ static bool set_fh_init(void *mplane_api, struct xran_fh_init *fh_init, enum xra
/* used to specify a unique prefix for shared memory, and files created by multiple DPDK processes;
it is necessary */
fh_init->filePrefix = strdup(*gpd(fhip, nump, ORAN_CONFIG_FILE_PREFIX)->strptr);
fh_init->p_o_du_addr = NULL; // DPDK retreives DU MAC address within the xran library with rte_eth_macaddr_get() function
fh_init->totalBfWeights = 0; // only used if id = O_RU (for emulation); C-plane extension types; section 5.4.6 of CUS spec
#ifdef F_RELEASE
@@ -941,6 +970,9 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA4, &fh_config->Ta4_min, &fh_config->Ta4_max)) // both E and F - min not used in xran, max yes
return false;
if (!set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_TA3_UP, &fh_config->Ta3_min, &fh_config->Ta3_max)) // both E and F - min not used in xran, max yes
return false;
set_maxmin_pd(fhp, nfh, ORAN_FH_CONFIG_T2A_UP, &fh_config->T2a_min_up, &fh_config->T2a_max_up);
fh_config->enableCP = 1; // enable C-plane
fh_config->prachEnable = 1; // enable PRACH

View File

@@ -52,6 +52,8 @@ static struct xran_fh_init g_fh_init = {0};
static struct xran_fh_config g_fh_config[XRAN_PORTS_NUM] = {0};
static uint32_t g_prach_conf_duration[XRAN_PORTS_NUM] = {0};
int32_t symbol_callback(void *args, struct xran_sense_of_time* p_sense_of_time);
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);
@@ -298,6 +300,7 @@ static void oai_xran_fh_rx_prach_callback(void *pCallbackTag, xran_status_t stat
}
static void oran_allocate_buffers(void *handle,
bool is_du,
int xran_inst,
int num_sectors,
oran_port_instance_t *portInstances,
@@ -425,8 +428,36 @@ static void oran_allocate_buffers(void *handle,
}
}
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag);
xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag);
if (is_du) {
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, oai_xran_fh_rx_callback, &portInstances->pusch_tag);
xran_5g_prach_req(pi->instanceHandle, prach, prachdecomp, oai_xran_fh_rx_prach_callback, &portInstances->prach_tag);
}
else {
static struct xran_sense_of_time sym_cb_time_half_slot;
static struct xran_sense_of_time sym_cb_time_full_slot;
static oran_symbol_callback_args_t args_half_slot;
static oran_symbol_callback_args_t args_full_slot;
args_half_slot = (oran_symbol_callback_args_t){
.start_symbol = 0,
.num_symbols = RU_SYMBOLS_PER_CALLBACK,
};
args_full_slot = (oran_symbol_callback_args_t){
.start_symbol = 7,
.num_symbols = RU_SYMBOLS_PER_CALLBACK,
};
LOG_I(HW, "Installing oran RX window end callbacks\n");
int ret = xran_reg_sym_cb(handle, symbol_callback, &args_half_slot, &sym_cb_time_half_slot, 6, XRAN_CB_SYM_RX_WIN_END);
AssertFatal(ret == 0, "Callback not installed\n");
ret = xran_reg_sym_cb(handle, symbol_callback, &args_full_slot, &sym_cb_time_full_slot, 13, XRAN_CB_SYM_RX_WIN_END);
AssertFatal(ret == 0, "Callback not installed\n");
// Only setup UPlane/CPlane buffers for O-RU. O-RU does not need callback for PUSCH and PRACH as the timing will be reliant on
// the underlying RF device
xran_5g_fronthault_config(pi->instanceHandle, src, srccp, dst, dstcp, NULL, NULL);
struct xran_buffer_list *pDstBufferDecomp[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN];
memset(pDstBufferDecomp, 0, sizeof(pDstBufferDecomp));
xran_5g_prach_req(pi->instanceHandle, prach, pDstBufferDecomp, NULL, NULL);
// TODO: Beamforming weights
}
}
int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_config *xran_fh_config)
@@ -440,6 +471,7 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
exit(-1);
}
bool is_du = xran_fh_init->io_cfg.id == 0;
/** process all the O-RU|O-DU for use case */
for (int32_t o_xu_id = 0; o_xu_id < xran_fh_init->xran_ports; o_xu_id++) {
print_fh_config(&xran_fh_config[o_xu_id]);
@@ -457,9 +489,9 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi
pi->pusch_tag = tag;
#ifdef E_RELEASE
LOG_W(HW, "Please be aware that E release support will be removed in the future. Consider switching to F release.\n");
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
oran_allocate_buffers(gxran_handle, is_du, o_xu_id, 1, pi, &xran_fh_config[o_xu_id]);
#elif defined F_RELEASE
oran_allocate_buffers(gxran_handle, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]);
oran_allocate_buffers(gxran_handle, is_du, o_xu_id, 1, pi, xran_fh_init->mtu, &xran_fh_config[o_xu_id]);
#endif
if ((xret = xran_reg_physide_cb(gxran_handle, oai_physide_dl_tti_call_back, NULL, 10, XRAN_CB_TTI)) != XRAN_STATUS_SUCCESS) {

View File

@@ -22,6 +22,8 @@
#ifndef ORAN_INIT_H
#define ORAN_INIT_H
#define RU_SYMBOLS_PER_CALLBACK 7
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];
@@ -54,6 +56,12 @@ typedef struct oran_port_instance_t {
struct xran_cb_tag pusch_tag;
} oran_port_instance_t;
typedef struct {
int start_symbol;
int num_symbols;
int symbol_diff;
} oran_symbol_callback_args_t;
extern struct xran_fh_config gxran_fh_config[XRAN_PORTS_NUM];
extern void *gxran_handle;

View File

@@ -99,6 +99,8 @@
#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_TA3_UP "Ta3_up"
#define ORAN_FH_CONFIG_T2A_UP "T2a_up"
#define ORAN_FH_HLP_CPLT " parameter of RU in list form (Min&Max, length 2!)\n"
@@ -108,6 +110,8 @@
{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_TA3_UP, "Ta3_up" ORAN_FH_HLP_CPLT, PARAMFLAG_MANDATORY, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
{ORAN_FH_CONFIG_T2A_UP, "T2a_up" ORAN_FH_HLP_CPLT, 0, .uptr=NULL, .defintarrayval=0, TYPE_UINTARRAY, 0}, \
}
// clang-format on

View File

@@ -19,6 +19,7 @@
* contact@openairinterface.org
*/
#include "assertions.h"
#include <stdio.h>
#include <string.h>
#include "common_lib.h"
@@ -39,6 +40,7 @@
// startup. Only relevant for printing, if it ever makes problem, remove this
// line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api
#include "../../app/src/common.h"
#include <time.h>
#ifdef OAI_MPLANE
#include "mplane/init-mplane.h"
@@ -54,6 +56,7 @@ typedef struct {
} oran_eth_state_t;
notifiedFIFO_t oran_sync_fifo;
notifiedFIFO_t ru_dl_sync_fifo;
int trx_oran_start(openair0_device *device)
{
@@ -211,6 +214,50 @@ int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len)
return 0;
}
void dump_nonzero_symbol(c16_t *txdataF, uint32_t ofdm_symbol_size, int frame, int slot, int symbol, const char* loc)
{
return;
float signal_energy = signal_energy_nodc(txdataF, ofdm_symbol_size);
if (signal_energy > 1) {
// Prepare a buffer to hold the formatted string for the symbol
const int num_chars_per_sample = 4 + 6 * 2;
char symbol_buf[ofdm_symbol_size * num_chars_per_sample]; // Enough for "(r,i) " per sample
int offset = 0;
bool is_zero_block = true;
for (int i = 0; i < ofdm_symbol_size; i++) {
bool is_zero = txdataF[i].r == 0 && txdataF[i].i == 0;
if (is_zero_block && !is_zero) {
offset += snprintf(symbol_buf + offset, sizeof(symbol_buf) - offset, "[sc %d]: ", i);
is_zero_block = false;
}
if (!is_zero_block && is_zero) {
is_zero_block = true;
}
if (!is_zero) {
offset += snprintf(symbol_buf + offset, sizeof(symbol_buf) - offset, "(%d,%d) ", txdataF[i].r, txdataF[i].i);
}
}
symbol_buf[offset] = '\0';
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
LOG_I(HW, "Antenna 0 Frame.Slot.Symbol %d.%d.%d (%s) signal_energy %.3f time %ld.%09ld samples: %s\n", frame, slot, symbol, loc, 10 * log10(signal_energy), ts.tv_sec, ts.tv_nsec, symbol_buf);
}
}
void oran_fh_if4p5_north_in(uint32_t **txdataF, int nb_tx, sense_of_time_t* sense_of_time, int *num_symbols) {
*num_symbols = RU_SYMBOLS_PER_CALLBACK;
int ret = xran_fh_tx_read_slot(txdataF, nb_tx, &sense_of_time->frame, &sense_of_time->slot, &sense_of_time->symbol, &sense_of_time->ts);
AssertFatal(ret == 0, "ORAN: Error reading slot");
int fftsize = 1 << get_xran_fh_config(0)->ru_conf.fftSize;
if (sense_of_time->frame == 0 && sense_of_time->slot == 0) {
for (int symbol = sense_of_time->symbol; symbol < sense_of_time->symbol + *num_symbols; symbol++) {
dump_nonzero_symbol((c16_t *)&txdataF[0][fftsize * symbol], fftsize, sense_of_time->frame, sense_of_time->slot, symbol, "north_in");
}
}
}
void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
{
prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, SEARCH_EXIST);
@@ -234,6 +281,20 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot)
printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl);
}
int slot_offset_rxdata = 3 & sl;
uint32_t slot_size = 14 * ru->nr_frame_parms->ofdm_symbol_size;
for (int symbol = 0; symbol < 14; symbol++) {
dump_nonzero_symbol((c16_t *)&ru->common.rxdataF[0][slot_offset_rxdata * slot_size + ru->nr_frame_parms->ofdm_symbol_size * symbol],
ru->nr_frame_parms->ofdm_symbol_size,
f,
sl,
symbol,
"south_in");
}
if (prach_id) {
dump_nonzero_symbol((c16_t *)prach_id->rxsigF[0][0], 139, f, sl, 0, "prach_south_in");
}
int slots_per_frame = 10 << (ru->openair0_cfg.nr_scs_for_raster);
proc->tti_rx = sl;
proc->frame_rx = f;
@@ -282,6 +343,13 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
// printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp);
int fftsize = 1 << get_xran_fh_config(0)->ru_conf.fftSize;
if (frame == 0 && slot == 0) {
for (int symbol = 0; symbol < 14; symbol++) {
dump_nonzero_symbol((c16_t *)&ru_info.txdataF_BF[0][fftsize * symbol], fftsize, frame, slot, symbol, "south_out");
}
}
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");
@@ -289,6 +357,62 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp)
stop_meas(&ru->tx_fhaul);
}
void oran_write_prach(uint32_t** prach_dataF,
int slot,
int frame)
{
// TODO: Why is this hardcoded array transferred correctly, but not the one from PRACH RX?
// uint16_t* prach = (uint16_t*)prach_dataF[0];
// for (int i = 0; i < 139; i++) {
// prach[2 * i] = i;
// prach[2 * i + 1] = -i;
// }
dump_nonzero_symbol((c16_t *)prach_dataF[0], 139, frame, slot, 0, "write_prach");
write_prach_data(prach_dataF, 1, frame, slot);
}
void oran_write_pusch(uint32_t *pusch_dataF, int frame, int slot, int symbol, int aarx)
{
if (aarx == 0) {
int fftsize = 1 << get_xran_fh_config(0)->ru_conf.fftSize;
dump_nonzero_symbol((c16_t *)pusch_dataF, fftsize, frame, slot, symbol, "write_pusch");
}
write_pusch(pusch_dataF, frame, slot, symbol, aarx);
}
void oran_prepare_packets(int slot, int start_antenna_index, int num_antennas, uint32_t symbol_mask)
{
int xran_port_id = 0; // TODO: support multiple ports
int first_cc = 0;
int num_cc = 1; // TODO: support multiple CCs
int first_symbol = 0;
for (int i = 0; i < 32; ++i) {
if (symbol_mask & (1u << i)) {
first_symbol = i;
break;
}
}
int last_symbol = 31;
for (int i = 31; i >= 0; --i) {
if (symbol_mask & (1u << i)) {
last_symbol = i;
break;
}
}
int num_symbols = last_symbol - first_symbol + 1;
AssertFatal(num_symbols > 0, "ORAN: no symbols to prepare in %s\n", __FUNCTION__);
xran_prepare_up_dl_sym(xran_port_id,
slot,
first_cc,
num_cc,
symbol_mask,
start_antenna_index,
num_antennas,
first_symbol,
num_symbols);
}
void *get_internal_parameter(char *name)
{
printf("ORAN: %s\n", __FUNCTION__);
@@ -401,6 +525,10 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
device->get_internal_parameter = get_internal_parameter;
device->priv = eth;
device->openair0_cfg = &openair0_cfg[0];
device->xran_api.north_in_func = oran_fh_if4p5_north_in;
device->xran_api.north_write_prach_func = oran_write_prach;
device->xran_api.north_write_pusch_func = oran_write_pusch;
device->xran_api.north_out_func = oran_prepare_packets;
return 0;
}

View File

@@ -63,4 +63,8 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot);
/** @brief Writes TX data (PDSCH) of given slot. */
int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp);
/** @brief Read DL IQ data from xran buffers on the O-RU
*/
int xran_fh_tx_read_slot(uint32_t **txdataF, int nb_tx, int *frame, int *slot, int *symbol, struct timespec *ts);
#endif /* _ORAN_ISOLATE_H_ */

View File

@@ -123,6 +123,7 @@ typedef struct {
Actor_t *channel_modelling_actors;
char *taps_socket;
int client_num_rx_antennas;
struct timespec start_ts;
} vrtsim_state_t;
// Sample history for channel impulse response
@@ -206,30 +207,24 @@ static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state)
static void *vrtsim_timing_job(void *arg)
{
vrtsim_state_t *vrtsim_state = arg;
struct timespec timestamp;
if (clock_gettime(CLOCK_REALTIME, &timestamp)) {
struct timespec start_ts;
if (clock_gettime(CLOCK_REALTIME, &start_ts)) {
LOG_E(UTIL, "clock_gettime failed\n");
exit(1);
}
double leftover_samples = 0;
int64_t last_sample_index = 0;
vrtsim_state->start_ts = start_ts;
while (vrtsim_state->run_timing_thread) {
struct timespec current_time;
if (clock_gettime(CLOCK_REALTIME, &current_time)) {
LOG_E(UTIL, "clock_gettime failed\n");
exit(1);
}
uint64_t diff = (current_time.tv_sec - timestamp.tv_sec) * 1000000000 + (current_time.tv_nsec - timestamp.tv_nsec);
timestamp = current_time;
double samples_to_produce = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9;
// Attempt to correct compounding rounding error
leftover_samples += samples_to_produce - (uint64_t)samples_to_produce;
if (leftover_samples > 1.0f) {
samples_to_produce += 1;
leftover_samples -= 1;
}
AssertFatal(samples_to_produce >= 0, "Negative samples to produce: %f\n", samples_to_produce);
uint64_t diff = (current_time.tv_sec - start_ts.tv_sec) * 1000000000 + (current_time.tv_nsec - start_ts.tv_nsec);
double sample_index = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9;
int64_t samples_to_produce = sample_index - last_sample_index;
shm_td_iq_channel_produce_samples(vrtsim_state->channel, samples_to_produce);
last_sample_index = sample_index;
usleep(1);
}
return 0;
@@ -561,11 +556,6 @@ static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp,
static void vrtsim_end(openair0_device *device)
{
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
if (vrtsim_state->role == ROLE_SERVER && vrtsim_state->run_timing_thread) {
vrtsim_state->run_timing_thread = false;
int ret = pthread_join(vrtsim_state->timing_thread, NULL);
AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno));
}
tx_timing_t *tx_timing = vrtsim_state->tx_timing;
if (vrtsim_state->chanmod || vrtsim_state->taps_socket) {
@@ -588,6 +578,11 @@ static void vrtsim_end(openair0_device *device)
}
shm_td_iq_channel_abort(vrtsim_state->channel);
sleep(1);
if (vrtsim_state->role == ROLE_SERVER && vrtsim_state->run_timing_thread) {
vrtsim_state->run_timing_thread = false;
int ret = pthread_join(vrtsim_state->timing_thread, NULL);
AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno));
}
shm_td_iq_channel_destroy(vrtsim_state->channel);
LOG_I(HW,
@@ -628,6 +623,14 @@ static int vrtsim_set_freq(openair0_device *device, openair0_config_t *openair0_
return 0;
}
openair0_timestamp vrtsim_get_timestamp(openair0_device *device, struct timespec *ts)
{
vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv;
uint64_t diff = (ts->tv_sec - vrtsim_state->start_ts.tv_sec) * 1000000000 + (ts->tv_nsec - vrtsim_state->start_ts.tv_nsec);
double diff_samples = vrtsim_state->sample_rate * vrtsim_state->timescale * diff / 1e9;
return diff_samples > 0 ? diff_samples : 0;
}
__attribute__((__visibility__("default"))) int device_init(openair0_device *device, openair0_config_t *openair0_cfg)
{
vrtsim_state_t *vrtsim_state = calloc_or_fail(1, sizeof(vrtsim_state_t));
@@ -643,6 +646,9 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device *devi
device->trx_set_gains_func = vrtsim_stub2;
device->trx_write_func = vrtsim_write;
device->trx_read_func = vrtsim_read;
if (vrtsim_state->role == ROLE_SERVER) {
device->get_timestamp = vrtsim_get_timestamp;
}
device->type = RFSIMULATOR;
device->openair0_cfg = &openair0_cfg[0];

View File

@@ -0,0 +1,275 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) });
nr_cellid = 1;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 1;
maxMIMO_layers = 1;
pusch_AntennaPorts = 2;
do_CSIRS = 0;
do_SRS = 0;
sib1_tda = 15;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# n_TimingAdvanceOffset = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 4049.76 MHz
# selected SSB frequency = 4049.76 MHz
absoluteFrequencySSB = 669984;
dl_frequencyBand = 77;
# frequency point A = 4030.68 MHz
dl_absoluteFrequencyPointA = 668712;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
initialDLBWPlocationAndBandwidth = 28875; #38.101-1 Table 5.3.2-1
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 77;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 106;
pMax = 23;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 159;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 0;
preambleReceivedTargetPower = -100;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 7;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 2;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#one (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
msg3_DeltaPreamble = 2;
p0_NominalWithGrant = -100;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 0;
p0_nominal = -96;
ssb_PositionsInBurst_Bitmap = 0x1;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 5;
nrofDownlinkSlots = 3;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 1;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = 0;
}
);
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ({ ipv4 = "192.168.70.132"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24";
GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200;
# dl_bler_target_upper = .35;
# dl_bler_target_lower = .15;
ul_bler_target_upper = .35;
ul_bler_target_lower = .15;
pusch_FailureThres = 10;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 110;
pucch0_dtx_threshold = 80;
pusch_dtx_threshold = 50;
# thread_pool_size = 8;
tx_amp_backoff_dB = 36;
L1_rx_thread_core = 8;
L1_tx_thread_core = 10;
phase_compensation = 0; # needs to match O-RU configuration
}
);
RUs = (
{
local_rf = "no";
nb_tx = 2;
nb_rx = 2;
att_tx = 0;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = 9;
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms = ( "nia2", "nia0" );
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
};
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); # one VF can be used as well
system_core = 0;
io_core = 1;
worker_cores = (2);
ru_addr = ("98:ae:71:04:83:e3", "98:ae:71:04:83:e3");
mtu = 9600;
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
T1a_up = (125, 350);
Ta4 = (110, 180);
ru_config = {
iq_width = 9;
iq_width_prach = 9;
};
});
};

View File

@@ -0,0 +1,274 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) });
nr_cellid = 1;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 2;
maxMIMO_layers = 2;
pusch_AntennaPorts = 4;
do_CSIRS = 1;
do_SRS = 0;
sib1_tda = 15;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# n_TimingAdvanceOffset = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 4049.76 MHz
# selected SSB frequency = 4049.76 MHz
absoluteFrequencySSB = 669984;
dl_frequencyBand = 77;
# frequency point A = 4030.68 MHz
dl_absoluteFrequencyPointA = 668712;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
initialDLBWPlocationAndBandwidth = 28875; #38.101-1 Table 5.3.2-1
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 77;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 106;
pMax = 23;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 159;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 0;
preambleReceivedTargetPower = -100;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 7;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 2;
#ra_ReponseWindow
#1,2,4,8,10,20,40,80
ra_ResponseWindow = 5;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#one (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
msg3_DeltaPreamble = 2;
p0_NominalWithGrant = -100;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 0;
p0_nominal = -96;
ssb_PositionsInBurst_Bitmap = 0x1;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 5;
nrofDownlinkSlots = 3;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 1;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = 0;
}
);
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ({ ipv4 = "192.168.70.132"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24";
GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200;
# dl_bler_target_upper = .35;
# dl_bler_target_lower = .15;
ul_bler_target_upper = .35;
ul_bler_target_lower = .15;
pusch_FailureThres = 100;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 110;
pucch0_dtx_threshold = 80;
pusch_dtx_threshold = -100;
# thread_pool_size = 8;
tx_amp_backoff_dB = 36;
L1_rx_thread_core = 8;
L1_tx_thread_core = 10;
phase_compensation = 0; # needs to match O-RU configuration
}
);
RUs = (
{
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = 9;
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms = ( "nia2", "nia0" );
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
};
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); # one VF can be used as well
system_core = 0;
io_core = 1;
worker_cores = (2);
ru_addr = ("98:ae:71:04:83:e3", "98:ae:71:04:83:e3");
mtu = 9600;
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
T1a_up = (125, 350);
Ta4 = (110, 180);
ru_config = {
iq_width = 9;
iq_width_prach = 9;
};
});
};

View File

@@ -0,0 +1,271 @@
Active_gNBs = ( "gNB-OAI");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
gNBs =
(
{
////////// Identification parameters:
gNB_ID = 0xe00;
gNB_name = "gNB-OAI";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ( { sst = 1; }); });
nr_cellid = 1;
////////// Physical parameters:
pdsch_AntennaPorts_XP = 2;
pdsch_AntennaPorts_N1 = 2;
maxMIMO_layers = 2;
pusch_AntennaPorts = 4;
do_CSIRS = 1;
do_SRS = 0;
sib1_tda = 15;
servingCellConfigCommon = (
{
#spCellConfigCommon
physCellId = 0;
# n_TimingAdvanceOffset = 0;
# downlinkConfigCommon
#frequencyInfoDL
# center frequency = 4049.76 MHz
# selected SSB frequency = 4049.76 MHz
absoluteFrequencySSB = 669984;
dl_frequencyBand = 77;
# frequency point A = 4030.68 MHz
dl_absoluteFrequencyPointA = 668712;
#scs-SpecificCarrierList
dl_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
dl_subcarrierSpacing = 1;
dl_carrierBandwidth = 106;
#initialDownlinkBWP
#genericParameters
initialDLBWPlocationAndBandwidth = 28875; #38.101-1 Table 5.3.2-1
#
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialDLBWPsubcarrierSpacing = 1;
#pdcch-ConfigCommon
initialDLBWPcontrolResourceSetZero = 11;
initialDLBWPsearchSpaceZero = 0;
#uplinkConfigCommon
#frequencyInfoUL
ul_frequencyBand = 77;
#scs-SpecificCarrierList
ul_offstToCarrier = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
ul_subcarrierSpacing = 1;
ul_carrierBandwidth = 106;
pMax = 23;
#initialUplinkBWP
#genericParameters
initialULBWPlocationAndBandwidth = 28875;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
initialULBWPsubcarrierSpacing = 1;
#rach-ConfigCommon
#rach-ConfigGeneric
prach_ConfigurationIndex = 159;
#prach_msg1_FDM
#0 = one, 1=two, 2=four, 3=eight
prach_msg1_FDM = 0;
prach_msg1_FrequencyStart = 0;
zeroCorrelationZoneConfig = 0;
preambleReceivedTargetPower = -100;
#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200)
preambleTransMax = 7;
#powerRampingStep
# 0=dB0,1=dB2,2=dB4,3=dB6
powerRampingStep = 2;
#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR
#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen
ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4;
#one (0..15) 4,8,12,16,...60,64
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15;
#ra_ContentionResolutionTimer
#(0..7) 8,16,24,32,40,48,56,64
ra_ContentionResolutionTimer = 7;
rsrp_ThresholdSSB = 19;
#prach-RootSequenceIndex_PR
#1 = 839, 2 = 139
prach_RootSequenceIndex_PR = 2;
prach_RootSequenceIndex = 1;
# SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex
#
msg1_SubcarrierSpacing = 1,
# restrictedSetConfig
# 0=unrestricted, 1=restricted type A, 2=restricted type B
restrictedSetConfig = 0,
# this is the offset between the last PRACH preamble power and the Msg3 PUSCH, 2 times the field value in dB
msg3_DeltaPreamble = 2;
p0_NominalWithGrant = -100;
# pucch-ConfigCommon setup :
# pucchGroupHopping
# 0 = neither, 1= group hopping, 2=sequence hopping
pucchGroupHopping = 0;
hoppingId = 0;
p0_nominal = -96;
ssb_PositionsInBurst_Bitmap = 0x1;
# ssb_periodicityServingCell
# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1
ssb_periodicityServingCell = 2;
# dmrs_TypeA_position
# 0 = pos2, 1 = pos3
dmrs_TypeA_Position = 0;
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
subcarrierSpacing = 1;
#tdd-UL-DL-ConfigurationCommon
# subcarrierSpacing
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
referenceSubcarrierSpacing = 1;
# pattern1
# dl_UL_TransmissionPeriodicity
# 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10
dl_UL_TransmissionPeriodicity = 5;
nrofDownlinkSlots = 3;
nrofDownlinkSymbols = 6;
nrofUplinkSlots = 1;
nrofUplinkSymbols = 4;
ssPBCH_BlockPower = 0;
}
);
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// AMF parameters:
amf_ip_address = ({ ipv4 = "172.21.6.5"; });
NETWORK_INTERFACES :
{
GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.51";
GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.51";
GNB_PORT_FOR_S1U = 2152; # Spec 2152
};
}
);
MACRLCs = (
{
num_cc = 1;
tr_s_preference = "local_L1";
tr_n_preference = "local_RRC";
pusch_TargetSNRx10 = 200;
pucch_TargetSNRx10 = 200;
# dl_bler_target_upper = .35;
# dl_bler_target_lower = .15;
ul_bler_target_upper = .35;
ul_bler_target_lower = .15;
pusch_FailureThres = 100;
}
);
L1s = (
{
num_cc = 1;
tr_n_preference = "local_mac";
prach_dtx_threshold = 110;
pucch0_dtx_threshold = 80;
pusch_dtx_threshold = -100;
# thread_pool_size = 8;
tx_amp_backoff_dB = 36;
L1_rx_thread_core = 10;
L1_tx_thread_core = 11;
phase_compensation = 0; # needs to match O-RU configuration
}
);
RUs = (
{
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = 9;
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
security = {
# preferred ciphering algorithms
# the first one of the list that an UE supports in chosen
# valid values: nea0, nea1, nea2, nea3
ciphering_algorithms = ( "nea0" );
# preferred integrity algorithms
# the first one of the list that an UE supports in chosen
# valid values: nia0, nia1, nia2, nia3
integrity_algorithms = ( "nia2", "nia0" );
# setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter
# what 'ciphering_algorithms' configures; same thing for 'drb_integrity'
drb_ciphering = "yes";
drb_integrity = "no";
};
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:c1:11.0", "0000:c1:11.1"); # one VF can be used as well
system_core = 6;
io_core = 7;
worker_cores = (8);
ru_addr = ("00:11:22:33:64:66", "00:11:22:33:64:67");
mtu = 9600;
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
T1a_up = (300, 350);
Ta4 = (110, 180);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
});
};

View File

@@ -0,0 +1,56 @@
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
RUs = (
{
local_rf = "no";
nb_tx = 2;
nb_rx = 2;
att_tx = 0;
att_rx = 0;
bands = [77];
tx_bw = [106];
rx_bw = [106];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = -1;
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
}
);
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:41:12.0", "0000:41:12.1"); # one VF can be used as well
system_core = 25;
io_core = 26;
worker_cores = (27);
du_addr = ("00:11:22:33:54:00", "00:11:22:33:54:01");
mtu = 9216;
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
T1a_up = (200, 350);
Ta4 = (110, 180);
ru_config = {
iq_width = 9;
iq_width_prach = 9;
};
});
};

View File

@@ -0,0 +1,61 @@
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
RUs = (
{
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_rx = 0;
bands = [77];
tx_bw = [106];
rx_bw = [106];
carrier_tx = [4049760];
carrier_rx = [4049760];
max_pdschReferenceSignalPower = -27;
max_rxgain = 75;
sf_extension = 0;
eNB_instances = [0];
ru_thread_core = -1;
sl_ahead = 5;
tr_preference = "raw_if4p5"; # important: activate FHI7.2
do_precoding = 0; # needs to match O-RU configuration
# PRACH configuration
prach_config_index = 159;
prach_msg1_start = 0;
});
log_config :
{
global_log_level = "info";
hw_log_level = "info";
phy_log_level = "info";
mac_log_level = "info";
rlc_log_level = "info";
pdcp_log_level = "info";
rrc_log_level = "info";
ngap_log_level = "info";
f1ap_log_level = "info";
};
fhi_72 = {
dpdk_devices = ("0000:41:12.0", "0000:41:12.1"); # one VF can be used as well
system_core = 25;
io_core = 26;
worker_cores = (27);
du_addr = ("00:11:22:33:54:00", "00:11:22:33:54:01");
mtu = 9600;
fh_config = ({
T1a_cp_dl = (285, 470);
T1a_cp_ul = (285, 429);
Ta3_up = (100, 350);
T1a_up = (300, 350);
Ta4 = (110, 180);
ru_config = {
iq_width = 16;
iq_width_prach = 16;
};
});
};