mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 12:40:28 +00:00
Compare commits
50 Commits
testing_40
...
oru-debug-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3904d74658 | ||
|
|
5e0ae8ba05 | ||
|
|
6c16fce1d0 | ||
|
|
68dc50c491 | ||
|
|
531a100bdd | ||
|
|
c750b9acd0 | ||
|
|
954a17ed70 | ||
|
|
5ff23f62c2 | ||
|
|
6f286e48fc | ||
|
|
8f2e2123be | ||
|
|
aabdb6efb1 | ||
|
|
b8b510a185 | ||
|
|
7bc6a11f78 | ||
|
|
b309482118 | ||
|
|
450c2d8b95 | ||
|
|
981e3adc19 | ||
|
|
623496b2a7 | ||
|
|
3f7b5310c1 | ||
|
|
fea2086560 | ||
|
|
c7b8e7fd82 | ||
|
|
ff0eec582a | ||
|
|
a34852f24f | ||
|
|
3735e8a5df | ||
|
|
c60338659f | ||
|
|
594d81d3b9 | ||
|
|
d01f7e38fb | ||
|
|
9b70ee6374 | ||
|
|
ed44194ff5 | ||
|
|
f93d1ded10 | ||
|
|
12d0ca747c | ||
|
|
6952a67101 | ||
|
|
d922d45599 | ||
|
|
7bbeec3eb2 | ||
|
|
bcb158cafc | ||
|
|
6e66b9fc3f | ||
|
|
49e652c9c6 | ||
|
|
19a418cd17 | ||
|
|
684dd38dca | ||
|
|
bd2c9c32c0 | ||
|
|
801086e401 | ||
|
|
9e95a2ccde | ||
|
|
e48661d8cf | ||
|
|
9e94745f65 | ||
|
|
7ba28c1d05 | ||
|
|
b0caad9c40 | ||
|
|
b2c62c7cd4 | ||
|
|
ed7c1057c5 | ||
|
|
c3bd911938 | ||
|
|
5bb7a4d274 | ||
|
|
decd8ae8ac |
@@ -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
|
||||
###################################################
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
42
doc/tutorial_resources/oru/README.md
Normal file
42
doc/tutorial_resources/oru/README.md
Normal 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
|
||||
272
doc/tutorial_resources/oru/gnb.2x2.conf
Normal file
272
doc/tutorial_resources/oru/gnb.2x2.conf
Normal 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;
|
||||
};
|
||||
});
|
||||
};
|
||||
272
doc/tutorial_resources/oru/gnb.conf
Normal file
272
doc/tutorial_resources/oru/gnb.conf
Normal 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;
|
||||
};
|
||||
});
|
||||
};
|
||||
93
doc/tutorial_resources/oru/ru.band77.106prb.fhi72.2x2.conf
Normal file
93
doc/tutorial_resources/oru/ru.band77.106prb.fhi72.2x2.conf
Normal 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;
|
||||
}
|
||||
);
|
||||
}
|
||||
87
doc/tutorial_resources/oru/ru.band77.106prb.fhi72.4x4.conf
Normal file
87
doc/tutorial_resources/oru/ru.band77.106prb.fhi72.4x4.conf
Normal 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;
|
||||
}
|
||||
);
|
||||
}
|
||||
29
doc/tutorial_resources/oru/setup_ifs_peafowl.sh
Executable file
29
doc/tutorial_resources/oru/setup_ifs_peafowl.sh
Executable 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
|
||||
40
doc/tutorial_resources/oru/setup_ru_ifs.sh
Executable file
40
doc/tutorial_resources/oru/setup_ru_ifs.sh
Executable 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
|
||||
20
doc/tutorial_resources/oru/setup_ru_ifs_broadbill.sh
Executable file
20
doc/tutorial_resources/oru/setup_ru_ifs_broadbill.sh
Executable 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
|
||||
@@ -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
304
executables/main_nr_ru.c
Normal 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;
|
||||
}
|
||||
@@ -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
568
executables/nr-oru.c
Normal 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, ×tamp, 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, ×tamp, 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, ¤t_slot, ¤t_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, ×tamp, (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
58
executables/nr-oru.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
8
radio/fd_rfsim/CMakeLists.txt
Normal file
8
radio/fd_rfsim/CMakeLists.txt
Normal 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
29
radio/fd_rfsim/README.md
Normal 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
521
radio/fd_rfsim/fd_rfsim.c
Normal 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;
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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, ×tamp)) {
|
||||
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, ¤t_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];
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user