Merge branch 'integration_2024_w24' into 'develop'
Integration: `2024.w24` See merge request oai/openairinterface5g!2801 * !2789 CI: Increase iperf/iperf3 command timeout * !2762 improve nrUE NAS security: accept NEA1,NEA2,NIA1,NIA2 * !2791 fix regressions for large physical cell id values * !2792 Add support for MIMO 2x2 with USRP B210 at 20 MHz BW and 3/4 sampling rate * !2748 Small UE fixes * !2745 Add google test testcases for nr_get_Pcmax * !2785 Update FHI 7.2 interface, test bandwidths, fix integer overflows
This commit is contained in:
+22
-19
@@ -463,7 +463,7 @@ add_library(f1ap
|
||||
${F1AP_DIR}/f1ap_handlers.c
|
||||
${F1AP_DIR}/f1ap_itti_messaging.c)
|
||||
target_include_directories(f1ap PUBLIC F1AP_DIR)
|
||||
target_link_libraries(f1ap PUBLIC asn1_f1ap)
|
||||
target_link_libraries(f1ap PUBLIC asn1_f1ap L2_NR)
|
||||
target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE)
|
||||
|
||||
# LPP
|
||||
@@ -1181,9 +1181,10 @@ target_include_directories(PHY_UE PRIVATE ${blas_INCLUDE_DIRS} ${lapacke_INCLUDE
|
||||
add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON})
|
||||
|
||||
add_library(PHY_NR ${PHY_NR_SRC})
|
||||
target_link_libraries(PHY_NR nr_phy_common nr_common)
|
||||
|
||||
add_library(PHY_NR_UE ${PHY_NR_UE_SRC})
|
||||
target_link_libraries(PHY_NR_UE PRIVATE asn1_nr_rrc_hdrs)
|
||||
target_link_libraries(PHY_NR_UE PRIVATE asn1_nr_rrc_hdrs nr_phy_common nr_common)
|
||||
|
||||
add_library(PHY_RU ${PHY_SRC_RU})
|
||||
target_link_libraries(PHY_RU PRIVATE asn1_lte_rrc_hdrs)
|
||||
@@ -1413,7 +1414,6 @@ set (MAC_NR_SRC_UE
|
||||
${NR_UE_MAC_DIR}/nr_ue_scheduler.c
|
||||
${NR_UE_MAC_DIR}/nr_ue_dci_configuration.c
|
||||
${NR_UE_MAC_DIR}/nr_ra_procedures.c
|
||||
${NR_UE_MAC_DIR}/nr_ue_power_procedures.c
|
||||
)
|
||||
|
||||
set (ENB_APP_SRC
|
||||
@@ -1462,7 +1462,7 @@ endif()
|
||||
|
||||
|
||||
add_library(MAC_UE_NR ${MAC_NR_SRC_UE})
|
||||
target_link_libraries(MAC_UE_NR PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
target_link_libraries(MAC_UE_NR PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs PUBLIC nr_ue_power_procedures)
|
||||
|
||||
add_library(L2_LTE ${L2_LTE_SRC})
|
||||
target_link_libraries(L2_LTE PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
@@ -1481,7 +1481,7 @@ add_library(e1_if
|
||||
|
||||
target_link_libraries(e1_if PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap SECURITY ${OPENSSL_LIBRARIES} e1ap GTPV1U)
|
||||
|
||||
target_link_libraries(L2_NR PRIVATE f1ap x2ap s1ap ngap nr_rrc e1ap nr_rlc)
|
||||
target_link_libraries(L2_NR PRIVATE f1ap x2ap s1ap ngap nr_rrc e1ap nr_rlc nr_common)
|
||||
if(E2_AGENT)
|
||||
target_link_libraries(L2_NR PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup)
|
||||
target_compile_definitions(L2_NR PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT)
|
||||
@@ -1516,7 +1516,7 @@ target_link_libraries(L2_UE PRIVATE asn1_lte_rrc_hdrs)
|
||||
|
||||
add_library( NR_L2_UE ${NR_L2_SRC_UE} ${MAC_NR_SRC_UE} )
|
||||
target_link_libraries(NR_L2_UE PRIVATE f1ap nr_rlc)
|
||||
target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
target_link_libraries(NR_L2_UE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs nr_common nr_ue_power_procedures)
|
||||
|
||||
add_library(MAC_NR_COMMON
|
||||
${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c
|
||||
@@ -2083,7 +2083,6 @@ add_executable(nr-softmodem
|
||||
${OPENAIR2_DIR}/RRC/NAS/rb_config.c
|
||||
${OPENAIR_DIR}/common/utils/lte/ue_power.c
|
||||
${OPENAIR_DIR}/common/utils/lte/prach_utils.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c
|
||||
)
|
||||
@@ -2152,7 +2151,6 @@ add_executable(nr-uesoftmodem
|
||||
${OPENAIR2_DIR}/LAYER2/NR_MAC_COMMON/nr_mac_common.c
|
||||
${OPENAIR2_DIR}/RRC/NAS/rb_config.c
|
||||
${OPENAIR3_DIR}/NAS/UE/nas_ue_task.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c
|
||||
)
|
||||
|
||||
@@ -2207,7 +2205,6 @@ target_link_libraries(rftest PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
|
||||
add_executable(polartest
|
||||
${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/polartest.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
)
|
||||
target_link_libraries(polartest PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR PHY_NR_COMMON PHY_NR_UE CONFIG_LIB -Wl,--end-group
|
||||
@@ -2216,7 +2213,6 @@ target_link_libraries(polartest PRIVATE
|
||||
|
||||
add_executable(smallblocktest
|
||||
${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/smallblocktest.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
)
|
||||
|
||||
target_link_libraries(smallblocktest PRIVATE
|
||||
@@ -2242,7 +2238,6 @@ target_link_libraries(ldpctest PRIVATE
|
||||
add_executable(nr_dlschsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlschsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
)
|
||||
target_link_libraries(nr_dlschsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group
|
||||
@@ -2253,7 +2248,6 @@ target_link_libraries(nr_dlschsim PRIVATE asn1_nr_rrc_hdrs)
|
||||
add_executable(nr_pbchsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/pbchsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
)
|
||||
target_link_libraries(nr_pbchsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group
|
||||
@@ -2264,7 +2258,6 @@ target_link_libraries(nr_pbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_executable(nr_psbchsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/psbchsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR2_DIR}/RRC/NAS/nas_config.c
|
||||
${NR_UE_RRC_DIR}/rrc_nsa.c
|
||||
@@ -2282,7 +2275,6 @@ target_link_libraries(nr_psbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_executable(nr_pucchsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/pucchsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
)
|
||||
target_link_libraries(nr_pucchsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group
|
||||
@@ -2293,7 +2285,6 @@ target_link_libraries(nr_pucchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_executable(nr_dlsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR2_DIR}/RRC/NAS/nas_config.c
|
||||
${NR_UE_RRC_DIR}/rrc_nsa.c
|
||||
@@ -2310,7 +2301,6 @@ target_link_libraries(nr_dlsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_executable(nr_prachsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/prachsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
)
|
||||
target_link_libraries(nr_prachsim PRIVATE
|
||||
-Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_RU PHY_NR_UE MAC_NR_COMMON SCHED_NR_LIB CONFIG_LIB -lz -Wl,--end-group
|
||||
@@ -2320,7 +2310,6 @@ target_link_libraries(nr_prachsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_executable(nr_ulschsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulschsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
${PHY_INTERFACE_DIR}/queue_t.c
|
||||
)
|
||||
target_link_libraries(nr_ulschsim PRIVATE
|
||||
@@ -2332,7 +2321,6 @@ target_link_libraries(nr_ulschsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
add_executable(nr_ulsim
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulsim.c
|
||||
${OPENAIR1_DIR}/SIMULATION/NR_PHY/nr_dummy_functions.c
|
||||
${OPENAIR_DIR}/common/utils/nr/nr_common.c
|
||||
${OPENAIR_DIR}/executables/softmodem-common.c
|
||||
${OPENAIR2_DIR}/RRC/NAS/nas_config.c
|
||||
${NR_UE_RRC_DIR}/rrc_nsa.c
|
||||
@@ -2410,7 +2398,7 @@ if (${T_TRACER})
|
||||
PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU PHY_MEX
|
||||
L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap
|
||||
CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU SIMU_ETH OPENAIR0_LIB
|
||||
ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc dfts config_internals)
|
||||
ldpc_orig ldpc_optim ldpc_optim8seg ldpc_t2 ldpc_cl ldpc_cuda ldpc dfts config_internals nr_common)
|
||||
if (TARGET ${i})
|
||||
add_dependencies(${i} generate_T)
|
||||
endif()
|
||||
@@ -2507,6 +2495,21 @@ if(ENABLE_TESTS)
|
||||
# meta-target: each test is supposed to add_dependencies(tests ${NEWTEST})
|
||||
# then, it is possible to build and execute all tests using "ninja tests && ctest"
|
||||
add_custom_target(tests)
|
||||
find_package(GTest)
|
||||
if (NOT GTest_FOUND)
|
||||
message(STATUS "GTest package not found, will download googletest automatically. To prevent that install google test on your system (libgtest-dev)")
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG 58d77fa8070e8cec2dc1ed015d66b454c8d78850 # 1.12.1
|
||||
)
|
||||
set(BUILD_GMOCK OFF)
|
||||
set(INSTALL_GTEST OFF)
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
add_library(GTest::gtest ALIAS gtest)
|
||||
add_library(GTest::gtest_main ALIAS gtest_main)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(common)
|
||||
|
||||
@@ -680,6 +680,8 @@ class Containerize():
|
||||
dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu20"
|
||||
ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {lSourcePath}/cmake_targets/log/unittest-build.log')
|
||||
if ret.returncode != 0:
|
||||
build_log_name = f'build_log_{self.testCase_id}'
|
||||
CopyLogsToExecutor(cmd, lSourcePath, build_log_name)
|
||||
logging.error(f'Cannot build unit tests')
|
||||
HTML.CreateHtmlTestRow("Unit test build failed", 'KO', [dockerfile])
|
||||
HTML.CreateHtmlTabFooter(False)
|
||||
|
||||
@@ -810,7 +810,7 @@ class OaiCiTest():
|
||||
with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(EPC.IPAddress) as cmd_svr:
|
||||
port = 5002 + idx
|
||||
cmd_ue.run(f'{ue.getCmdPrefix()} iperf -B {ueIP} -s -u -i1 >> {server_filename} &', timeout=iperf_time*1.5)
|
||||
cmd_svr.run(f'{svr.getCmdPrefix()} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 2>&1 | tee {client_filename}', timeout=iperf_time*1.5)
|
||||
cmd_svr.run(f'{svr.getCmdPrefix()} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 2>&1 | tee {client_filename}', timeout=iperf_time*2.5)
|
||||
cmd_ue.run(f'cp {client_filename} {logPath}/{client_filename}')
|
||||
cmd_ue.run(f'cp {server_filename} {logPath}/{server_filename}')
|
||||
status, msg = Iperf_analyzeV2UDP(server_filename, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate)
|
||||
@@ -818,7 +818,7 @@ class OaiCiTest():
|
||||
with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(EPC.IPAddress) as cmd_svr:
|
||||
port = 5002 + idx
|
||||
# note: some core setups start an iperf3 server automatically, indicated in ci_infra by runIperf3Server: False`
|
||||
t = iperf_time * 1.5
|
||||
t = iperf_time * 2.5
|
||||
if runIperf3Server:
|
||||
cmd_svr.run(f'{svr.getCmdPrefix()} nohup timeout -vk3 {t} iperf3 -s -B {svrIP} -p {port} -1 {jsonReport} &', timeout=t)
|
||||
cmd_ue.run(f'rm /tmp/{client_filename}', reportNonZero=False)
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
|
||||
FROM ran-base:develop as ran-tests
|
||||
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install --yes \
|
||||
libgtest-dev
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
@@ -109,6 +109,8 @@ elseif (xran_VERSION_STRING STREQUAL "oran_e_maintenance_release_v1.1")
|
||||
set(xran_VERSION 5.1.1)
|
||||
elseif (xran_VERSION_STRING STREQUAL "oran_e_maintenance_release_v1.2")
|
||||
set(xran_VERSION 5.1.2)
|
||||
elseif (xran_VERSION_STRING STREQUAL "oran_e_maintenance_release_v1.3")
|
||||
set(xran_VERSION 5.1.3)
|
||||
endif()
|
||||
unset(xran_VERSION_LINE)
|
||||
unset(xran_VERSION_STRING)
|
||||
|
||||
@@ -7,7 +7,7 @@ index 7508117..0dbe0bd 100644
|
||||
#include <rte_mbuf.h>
|
||||
|
||||
-#define VERSIONX "oran_e_maintenance_release_v1.0"
|
||||
+#define VERSIONX "oran_e_maintenance_release_v1.2"
|
||||
+#define VERSIONX "oran_e_maintenance_release_v1.3"
|
||||
|
||||
#define APP_O_DU 0
|
||||
#define APP_O_RU 1
|
||||
@@ -114,7 +114,7 @@ index 7419ae1..a85f973 100644
|
||||
* @ingroup xran
|
||||
*
|
||||
diff --git a/fhi_lib/lib/api/xran_up_api.h b/fhi_lib/lib/api/xran_up_api.h
|
||||
index 7d3afc5..3e00c5a 100644
|
||||
index 7d3afc5..e2f1f21 100644
|
||||
--- a/fhi_lib/lib/api/xran_up_api.h
|
||||
+++ b/fhi_lib/lib/api/xran_up_api.h
|
||||
@@ -80,6 +80,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
@@ -125,6 +125,16 @@ index 7d3afc5..3e00c5a 100644
|
||||
union ecpri_seq_id *seq_id,
|
||||
uint16_t *num_prbu,
|
||||
uint16_t *start_prbu,
|
||||
@@ -89,7 +90,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
int8_t expect_comp,
|
||||
enum xran_comp_hdr_type staticComp,
|
||||
uint8_t *compMeth,
|
||||
- uint8_t *iqWidth);
|
||||
+ uint8_t *iqWidth,
|
||||
+ uint8_t *is_prach);
|
||||
|
||||
inline int xran_prepare_iq_symbol_portion(
|
||||
struct rte_mbuf *mbuf,
|
||||
diff --git a/fhi_lib/lib/ethernet/ethdi.c b/fhi_lib/lib/ethernet/ethdi.c
|
||||
index b6ba257..b53325f 100644
|
||||
--- a/fhi_lib/lib/ethernet/ethdi.c
|
||||
@@ -173,9 +183,18 @@ index e6d3067..8e0abee 100644
|
||||
static int16_t saturateAbs(int16_t inVal)
|
||||
{
|
||||
diff --git a/fhi_lib/lib/src/xran_bfp_uplane.cpp b/fhi_lib/lib/src/xran_bfp_uplane.cpp
|
||||
index a345df4..7831fa0 100644
|
||||
index a345df4..109b05a 100644
|
||||
--- a/fhi_lib/lib/src/xran_bfp_uplane.cpp
|
||||
+++ b/fhi_lib/lib/src/xran_bfp_uplane.cpp
|
||||
@@ -90,7 +90,7 @@ namespace BFP_UPlane
|
||||
{
|
||||
const __m512i* rawData = reinterpret_cast<const __m512i*>(dataIn.dataExpanded);
|
||||
/// Abs
|
||||
- const auto rawDataAbs = _mm512_abs_epi16(rawData[0]);
|
||||
+ const auto rawDataAbs = _mm512_abs_epi16(_mm512_loadu_epi16(rawData));
|
||||
/// No need to do a full horizontal max operation here, just do a max IQ step,
|
||||
/// compute the exponents and then use a reduce max over all exponent values. This
|
||||
/// is the fastest way to handle a single RB.
|
||||
@@ -116,7 +116,7 @@ namespace BFP_UPlane
|
||||
/// Get AVX512 pointer aligned to desired RB
|
||||
const __m512i* rawDataIn = reinterpret_cast<const __m512i*>(dataIn.dataExpanded + numREOffset);
|
||||
@@ -195,10 +214,18 @@ index a345df4..7831fa0 100644
|
||||
dataOut->dataCompressed[thisRBExpAddr] = thisExp;
|
||||
/// Now have 1 RB worth of bytes separated into 3 chunks (1 per lane)
|
||||
diff --git a/fhi_lib/lib/src/xran_common.c b/fhi_lib/lib/src/xran_common.c
|
||||
index baa673f..edd4ecb 100644
|
||||
index baa673f..00bfdf2 100644
|
||||
--- a/fhi_lib/lib/src/xran_common.c
|
||||
+++ b/fhi_lib/lib/src/xran_common.c
|
||||
@@ -656,6 +656,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid)
|
||||
@@ -650,12 +650,15 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid)
|
||||
uint8_t compMeth = 0;
|
||||
uint8_t iqWidth = 0;
|
||||
|
||||
+ uint8_t is_prach = 0;
|
||||
+
|
||||
void *pHandle = NULL;
|
||||
int ret = MBUF_FREE;
|
||||
uint32_t mb_free = 0;
|
||||
int32_t valid_res = 0;
|
||||
int expect_comp = (p_dev_ctx->fh_cfg.ru_conf.compMeth != XRAN_COMPMETHOD_NONE);
|
||||
enum xran_comp_hdr_type staticComp = p_dev_ctx->fh_cfg.ru_conf.xranCompHdrType;
|
||||
@@ -206,7 +233,7 @@ index baa673f..edd4ecb 100644
|
||||
|
||||
if (staticComp == XRAN_COMP_HDR_TYPE_STATIC)
|
||||
{
|
||||
@@ -674,6 +675,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid)
|
||||
@@ -674,6 +677,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid)
|
||||
&subframe_id,
|
||||
&slot_id,
|
||||
&symb_id,
|
||||
@@ -214,7 +241,14 @@ index baa673f..edd4ecb 100644
|
||||
&seq,
|
||||
&num_prbu,
|
||||
&start_prbu,
|
||||
@@ -688,23 +690,9 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid)
|
||||
@@ -683,28 +687,15 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid)
|
||||
expect_comp,
|
||||
staticComp,
|
||||
&compMeth,
|
||||
- &iqWidth);
|
||||
+ &iqWidth,
|
||||
+ &is_prach);
|
||||
if (num_bytes <= 0){
|
||||
print_err("num_bytes is wrong [%d]\n", num_bytes);
|
||||
return MBUF_FREE;
|
||||
}
|
||||
@@ -241,7 +275,16 @@ index baa673f..edd4ecb 100644
|
||||
#ifndef FCN_ADAPT
|
||||
if(valid_res != 0) {
|
||||
print_dbg("valid_res is wrong [%d] ant %u (%u : %u : %u : %u) seq %u num_bytes %d\n", valid_res, Ant_ID, frame_id, subframe_id, slot_id, symb_id, seq.seq_id, num_bytes);
|
||||
@@ -1189,7 +1177,7 @@ int generate_cpmsg_prach(void *pHandle, struct xran_cp_gen_params *params, struc
|
||||
@@ -756,7 +747,7 @@ process_mbuf(struct rte_mbuf *pkt, void* handle, struct xran_eaxc_info *p_cid)
|
||||
print_dbg("Transport layer fragmentation (eCPRI) is not supported\n");
|
||||
}
|
||||
|
||||
- } else if (Ant_ID >= p_dev_ctx->PrachCPConfig.eAxC_offset && p_dev_ctx->fh_cfg.prachEnable) {
|
||||
+ } else if (/*Ant_ID >= p_dev_ctx->PrachCPConfig.eAxC_offset && */p_dev_ctx->fh_cfg.prachEnable && is_prach) {
|
||||
/* PRACH packet has ruportid = num_eAxc + ant_id */
|
||||
Ant_ID -= p_dev_ctx->PrachCPConfig.eAxC_offset;
|
||||
symbol_total_bytes[p_dev_ctx->xran_port_id][CC_ID][Ant_ID] += num_bytes;
|
||||
@@ -1189,7 +1180,7 @@ int generate_cpmsg_prach(void *pHandle, struct xran_cp_gen_params *params, struc
|
||||
timeOffset += startSymId * (2048 + 144);
|
||||
}
|
||||
timeOffset = timeOffset >> nNumerology; //original number is Tc, convert to Ts based on mu
|
||||
@@ -250,7 +293,7 @@ index baa673f..edd4ecb 100644
|
||||
timeOffset += 16;
|
||||
|
||||
params->dir = XRAN_DIR_UL;
|
||||
@@ -1295,8 +1283,7 @@ int32_t ring_processing_func(void* args)
|
||||
@@ -1295,8 +1286,7 @@ int32_t ring_processing_func(void* args)
|
||||
|
||||
for (i = 0; i < ctx->io_cfg.num_vfs && i < XRAN_VF_MAX; i++){
|
||||
for(qi = 0; qi < ctx->rxq_per_port[i]; qi++) {
|
||||
@@ -430,7 +473,7 @@ index 36bd72c..f7f5678 100644
|
||||
int idx = 0;
|
||||
uint16_t *psrc = (uint16_t *)iq_data_start;
|
||||
diff --git a/fhi_lib/lib/src/xran_up_api.c b/fhi_lib/lib/src/xran_up_api.c
|
||||
index 397853a..4a714b5 100644
|
||||
index 397853a..8977e3d 100644
|
||||
--- a/fhi_lib/lib/src/xran_up_api.c
|
||||
+++ b/fhi_lib/lib/src/xran_up_api.c
|
||||
@@ -329,6 +329,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
@@ -441,7 +484,26 @@ index 397853a..4a714b5 100644
|
||||
union ecpri_seq_id *seq_id,
|
||||
uint16_t *num_prbu,
|
||||
uint16_t *start_prbu,
|
||||
@@ -387,6 +388,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
@@ -338,7 +339,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
int8_t expect_comp,
|
||||
enum xran_comp_hdr_type staticComp,
|
||||
uint8_t *compMeth,
|
||||
- uint8_t *iqWidth)
|
||||
+ uint8_t *iqWidth,
|
||||
+ uint8_t *is_prach)
|
||||
{
|
||||
#if XRAN_MLOG_VAR
|
||||
uint32_t mlogVar[10];
|
||||
@@ -374,6 +376,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
return 0; /* packet too short */
|
||||
|
||||
radio_hdr->sf_slot_sym.value = rte_be_to_cpu_16(radio_hdr->sf_slot_sym.value);
|
||||
+ if (radio_hdr->data_feature.filter_id > 0) *is_prach = 1;
|
||||
+ else *is_prach = 0;
|
||||
|
||||
if (frame_id)
|
||||
*frame_id = radio_hdr->frame_id;
|
||||
@@ -387,6 +391,8 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
if (symb_id)
|
||||
*symb_id = radio_hdr->sf_slot_sym.symb_id;
|
||||
|
||||
@@ -450,7 +512,7 @@ index 397853a..4a714b5 100644
|
||||
/* Process data section hdr */
|
||||
struct data_section_hdr *data_hdr =
|
||||
(void *)rte_pktmbuf_adj(mbuf, sizeof(*radio_hdr));
|
||||
@@ -401,6 +404,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
@@ -401,6 +407,7 @@ int32_t xran_extract_iq_samples(struct rte_mbuf *mbuf,
|
||||
*sym_inc = data_hdr->fields.sym_inc;
|
||||
*rb = data_hdr->fields.rb;
|
||||
*sect_id = data_hdr->fields.sect_id;
|
||||
|
||||
@@ -10,3 +10,4 @@ if(ENABLE_WEBSRV)
|
||||
endif()
|
||||
|
||||
add_subdirectory(T)
|
||||
add_subdirectory(nr)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
add_library(nr_common nr_common.c)
|
||||
target_include_directories(nr_common PUBLIC .)
|
||||
if (ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
+12
-42
@@ -1126,21 +1126,23 @@ int get_scan_ssb_first_sc(const double fc, const int nbRB, const int nrBand, con
|
||||
const double startFreq = get_start_freq(fc, nbRB, mu);
|
||||
const double stopFreq = get_stop_freq(fc, nbRB, mu);
|
||||
|
||||
int scanGscnStart = -1;
|
||||
int scanGscnStop = -1;
|
||||
sync_raster_t tmpRaster = {0};
|
||||
for (const sync_raster_t *r = sync_raster; r < r + (sizeof(sync_raster) / sizeof(sync_raster_t)); r++) {
|
||||
if (r->band == nrBand && r->scs_index == mu) {
|
||||
tmpRaster = *r;
|
||||
break;
|
||||
}
|
||||
int scanGscnStart = 0;
|
||||
int scanGscnStop = 0;
|
||||
const sync_raster_t *tmpRaster = sync_raster;
|
||||
const sync_raster_t * end=sync_raster + sizeofArray(sync_raster);
|
||||
while (tmpRaster < end && (tmpRaster->band != nrBand || tmpRaster->scs_index != mu))
|
||||
tmpRaster++;
|
||||
if (tmpRaster >= end) {
|
||||
LOG_E(PHY, "raster not found nrband=%d, mu=%d\n", nrBand, mu);
|
||||
return 0;
|
||||
}
|
||||
find_gscn_to_scan(startFreq, stopFreq, tmpRaster, &scanGscnStart, &scanGscnStop);
|
||||
|
||||
find_gscn_to_scan(startFreq, stopFreq, *tmpRaster, &scanGscnStart, &scanGscnStop);
|
||||
|
||||
const double scs = MU_SCS(mu) * 1e3;
|
||||
const double pointA = fc - (nbRB / 2 * scs * NR_NB_SC_PER_RB);
|
||||
int numGscn = 0;
|
||||
for (int g = scanGscnStart; (g <= scanGscnStop) && (numGscn < MAX_GSCN_BAND); g += tmpRaster.step_gscn) {
|
||||
for (int g = scanGscnStart; (g <= scanGscnStop) && (numGscn < MAX_GSCN_BAND); g += tmpRaster->step_gscn) {
|
||||
ssbInfo[numGscn].ssRef = get_ssref_from_gscn(g);
|
||||
ssbInfo[numGscn].ssbFirstSC = get_ssb_first_sc(pointA, ssbInfo[numGscn].ssRef, mu);
|
||||
ssbInfo[numGscn].gscn = g;
|
||||
@@ -1174,38 +1176,6 @@ void init_delay_table(uint16_t ofdm_symbol_size,
|
||||
}
|
||||
}
|
||||
|
||||
void freq2time(uint16_t ofdm_symbol_size,
|
||||
int16_t *freq_signal,
|
||||
int16_t *time_signal)
|
||||
{
|
||||
const idft_size_idx_t idft_size = get_idft(ofdm_symbol_size);
|
||||
idft(idft_size, freq_signal, time_signal, 1);
|
||||
}
|
||||
|
||||
void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay)
|
||||
{
|
||||
freq2time(ofdm_symbol_size, (int16_t *)ls_est, (int16_t *)ch_estimates_time);
|
||||
|
||||
int max_pos = delay->delay_max_pos;
|
||||
int max_val = delay->delay_max_val;
|
||||
const int sync_pos = 0;
|
||||
|
||||
for (int i = 0; i < ofdm_symbol_size; i++) {
|
||||
int temp = c16amp2(ch_estimates_time[i]) >> 1;
|
||||
if (temp > max_val) {
|
||||
max_pos = i;
|
||||
max_val = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_pos > ofdm_symbol_size / 2)
|
||||
max_pos = max_pos - ofdm_symbol_size;
|
||||
|
||||
delay->delay_max_pos = max_pos;
|
||||
delay->delay_max_val = max_val;
|
||||
delay->est_delay = max_pos - sync_pos;
|
||||
}
|
||||
|
||||
void nr_timer_start(NR_timer_t *timer)
|
||||
{
|
||||
timer->active = true;
|
||||
|
||||
@@ -241,12 +241,6 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB,
|
||||
int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int scs);
|
||||
int get_delay_idx(int delay, int max_delay_comp);
|
||||
|
||||
void freq2time(uint16_t ofdm_symbol_size,
|
||||
int16_t *freq_signal,
|
||||
int16_t *time_signal);
|
||||
|
||||
void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay);
|
||||
|
||||
int get_scan_ssb_first_sc(const double fc,
|
||||
const int nbRB,
|
||||
const int nrBand,
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
add_executable(test_nr_common test_nr_common.cpp)
|
||||
target_link_libraries(test_nr_common PRIVATE nr_common GTest::gtest minimal_lib)
|
||||
add_dependencies(tests test_nr_common)
|
||||
add_test(NAME test_nr_common
|
||||
COMMAND ./test_nr_common)
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 <gtest/gtest.h>
|
||||
extern "C" {
|
||||
#include "nr_common.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
}
|
||||
|
||||
TEST(nr_common, nr_timer) {
|
||||
NR_timer_t timer;
|
||||
nr_timer_setup(&timer, 10, 1);
|
||||
nr_timer_start(&timer);
|
||||
EXPECT_TRUE(is_nr_timer_active(timer));
|
||||
EXPECT_FALSE(nr_timer_expired(timer));
|
||||
for (auto i = 0; i < 10; i++) {
|
||||
nr_timer_tick(&timer);
|
||||
}
|
||||
EXPECT_FALSE(is_nr_timer_active(timer));
|
||||
EXPECT_TRUE(nr_timer_expired(timer));
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
logInit();
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -391,6 +391,8 @@ Compile the fronthaul interface library by calling `make` and the option
|
||||
environment variables `RTE_SDK` for the path to the source tree of DPDK, and
|
||||
`XRAN_DIR` to set the path to the fronthaul library.
|
||||
|
||||
**Note**: you need at least gcc-11 and g++-11.
|
||||
|
||||
```bash
|
||||
cd ~/phy/fhi_lib/lib
|
||||
make clean
|
||||
@@ -790,7 +792,6 @@ Edit the sample OAI gNB configuration file and check following parameters:
|
||||
compression
|
||||
* `iq_width_prach`: Width of PRACH IQ samples: if 16, no compression, if <16, applies
|
||||
compression
|
||||
* `fft_size`: size of FFT performed by RU, set to 12 by default
|
||||
* `prach_config`: PRACH-specific configuration
|
||||
* `eAxC_offset`: PRACH antenna offset
|
||||
* `kbar`: the PRACH guard interval, provided in RU
|
||||
|
||||
+3
-2
@@ -8,8 +8,9 @@ explaining how to test with cmake and ctest; it is a suggested read, and the
|
||||
following just lists the main points of how to compile the tests and how to add
|
||||
new ones.
|
||||
|
||||
At the time of writing, only the NR RLC tests have been integrated. The author
|
||||
hopes that more tests follow suit.
|
||||
GoogleTest is a C++ unit testing framework that has been added as an external dependency. While using GoogleTest is not a requirement it can simplify writing unit tests.
|
||||
See [primer](http://google.github.io/googletest/primer.html) for a quick introduction. To add it to your test executable link against
|
||||
`GTest::gtest` or `GTest::gtest_main`.
|
||||
|
||||
# How to compile tests
|
||||
|
||||
|
||||
+5
-2
@@ -912,7 +912,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, int slots_per_frame)
|
||||
static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, int slots_per_frame, uint16_t ofdm_symbol_size)
|
||||
{
|
||||
const nfapi_nr_prach_config_t *prach_config = &config->prach_config;
|
||||
const nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table;
|
||||
@@ -934,6 +934,8 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
split7->fftSize = log2(ofdm_symbol_size);
|
||||
}
|
||||
|
||||
/* this function maps the RU tx and rx buffers to the available rf chains.
|
||||
@@ -1157,7 +1159,7 @@ void *ru_thread( void *param ) {
|
||||
nr_dump_frame_parms(fp);
|
||||
nr_phy_init_RU(ru);
|
||||
fill_rf_config(ru, ru->rf_config_file);
|
||||
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp->slots_per_frame);
|
||||
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp->slots_per_frame, fp->ofdm_symbol_size);
|
||||
|
||||
if(!emulate_rf) {
|
||||
// Start IF device if any
|
||||
@@ -1342,6 +1344,7 @@ void *ru_thread( void *param ) {
|
||||
rx_tti_busy[info->slot_rx % RU_RX_SLOT_DEPTH] = false;
|
||||
if ((info->slot_rx % RU_RX_SLOT_DEPTH) == (proc->tti_rx % RU_RX_SLOT_DEPTH))
|
||||
not_done = false;
|
||||
delNotifiedFIFO_elt(res);
|
||||
}
|
||||
if (!res)
|
||||
break;
|
||||
|
||||
+2
-4
@@ -735,6 +735,7 @@ void *UE_thread(void *arg)
|
||||
readFrame(UE, &sync_timestamp, false);
|
||||
notifiedFIFO_elt_t *Msg = newNotifiedFIFO_elt(sizeof(syncData_t), 0, &nf, UE_synch);
|
||||
syncData_t *syncMsg = (syncData_t *)NotifiedFifoData(Msg);
|
||||
*syncMsg = (syncData_t){0};
|
||||
NR_DL_FRAME_PARMS *fp = &UE->frame_parms;
|
||||
if (UE->UE_scan_carrier) {
|
||||
// Get list of GSCN in this band for UE's bandwidth and center frequency.
|
||||
@@ -743,10 +744,7 @@ void *UE_thread(void *arg)
|
||||
get_scan_ssb_first_sc(fp->dl_CarrierFreq, fp->N_RB_DL, fp->nr_band, fp->numerology_index, syncMsg->gscnInfo);
|
||||
} else {
|
||||
LOG_W(PHY, "SSB position provided\n");
|
||||
nr_gscn_info_t *g = syncMsg->gscnInfo;
|
||||
g->ssbFirstSC = fp->ssb_start_subcarrier;
|
||||
g->gscn = 0;
|
||||
g->ssRef = 0;
|
||||
syncMsg->gscnInfo[0] = (nr_gscn_info_t){.ssbFirstSC = fp->ssb_start_subcarrier};
|
||||
syncMsg->numGscn = 1;
|
||||
}
|
||||
syncMsg->UE = UE;
|
||||
|
||||
@@ -4,3 +4,4 @@ add_boolean_option(ENABLE_NRSCOPE OFF "Whether to build the 5G scope" OFF)
|
||||
if(ENABLE_UESCOPE OR ENABLE_ENBSCOPE OR ENABLE_NRSCOPE)
|
||||
add_subdirectory(TOOLS)
|
||||
endif()
|
||||
add_subdirectory(nr_phy_common)
|
||||
|
||||
@@ -160,7 +160,7 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy
|
||||
} //rb
|
||||
} // symb
|
||||
int nb_rb=0;
|
||||
int32_t n0_subband_tot=0;
|
||||
int64_t n0_subband_tot=0;
|
||||
int32_t n0_subband_tot_perANT[frame_parms->nb_antennas_rx];
|
||||
|
||||
memset(n0_subband_tot_perANT, 0, sizeof(n0_subband_tot_perANT));
|
||||
@@ -200,7 +200,7 @@ void nr_gnb_measurements(PHY_VARS_gNB *gNB,
|
||||
unsigned char symbol,
|
||||
uint8_t nrOfLayers)
|
||||
{
|
||||
int rx_power_tot = 0;
|
||||
uint32_t rx_power_tot = 0;
|
||||
unsigned short rx_power_avg_dB;
|
||||
unsigned short rx_power_tot_dB;
|
||||
RU_t *ru = gNB->RU_list[0];
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "PHY/NR_REFSIG/ul_ref_seq_nr.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
#include "nr_phy_common.h"
|
||||
|
||||
|
||||
//#define DEBUG_CH
|
||||
|
||||
@@ -316,6 +316,12 @@ void rx_nr_prach_ru(RU_t *ru,
|
||||
dftlen >>= 1;
|
||||
break;
|
||||
|
||||
case 23040:
|
||||
// 20 MHz @ 23.04 Ms/s
|
||||
Ncp = (Ncp * 3) / 4;
|
||||
dftlen = (dftlen * 3) / 4;
|
||||
break;
|
||||
|
||||
case 30720:
|
||||
// 20, 25, 30 MHz @ 30.72 Ms/s
|
||||
break;
|
||||
|
||||
@@ -454,10 +454,9 @@ static void nr_ulsch_channel_level(int **ul_ch_estimates_ext,
|
||||
avg128U = simde_mm_add_epi32(avg128U, simde_mm_srai_epi32(simde_mm_madd_epi16(ul_ch128[i], ul_ch128[i]), x));
|
||||
}
|
||||
|
||||
avg[aatx*frame_parms->nb_antennas_rx+aarx] = (((int32_t*)&avg128U)[0] +
|
||||
((int32_t*)&avg128U)[1] +
|
||||
((int32_t*)&avg128U)[2] +
|
||||
((int32_t*)&avg128U)[3]) / y;
|
||||
int32_t *avg32i = (int32_t *)&avg128U;
|
||||
int64_t avg64 = (int64_t)avg32i[0] + avg32i[1] + avg32i[2] + avg32i[3];
|
||||
avg[aatx * frame_parms->nb_antennas_rx + aarx] = avg64 / y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB,
|
||||
uint8_t index=0;
|
||||
|
||||
int nb_re_pucch = 12*pucch_pdu->prb_size; // prb size is 1
|
||||
int signal_energy = 0, signal_energy_ant0 = 0;
|
||||
int64_t signal_energy = 0, signal_energy_ant0 = 0;
|
||||
|
||||
for (int l=0; l<pucch_pdu->nr_of_symbols; l++) {
|
||||
uint8_t l2 = l + pucch_pdu->start_symbol_index;
|
||||
@@ -1147,7 +1147,11 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB,
|
||||
|
||||
uint32_t x1 = 0, x2 = 0, sGold = 0;
|
||||
uint8_t *sGold8 = (uint8_t *)&sGold;
|
||||
x2 = (((1<<17)*((14*slot) + (pucch_pdu->start_symbol_index+symb) + 1)*((2*pucch_pdu->dmrs_scrambling_id) + 1)) + (2*pucch_pdu->dmrs_scrambling_id))%(1U<<31); // c_init calculation according to TS38.211 subclause
|
||||
const int scramble = pucch_pdu->dmrs_scrambling_id * 2;
|
||||
// fixme: when MR2754 will be merged, use the gold sequence cache instead of regenerate each time
|
||||
x2 = ((1ULL << 17) * ((NR_NUMBER_OF_SYMBOLS_PER_SLOT * slot + pucch_pdu->start_symbol_index + symb + 1) * (scramble + 1))
|
||||
+ scramble)
|
||||
% (1U << 31); // c_init calculation according to TS38.211 subclause
|
||||
#ifdef DEBUG_NR_PUCCH_RX
|
||||
printf("slot %d, start_symbol_index %d, symbol %d, dmrs_scrambling_id %d\n",
|
||||
slot,pucch_pdu->start_symbol_index,symb,pucch_pdu->dmrs_scrambling_id);
|
||||
|
||||
@@ -29,12 +29,13 @@
|
||||
#include "PHY/NR_REFSIG/nr_mod_table.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_sch_dmrs.h"
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "nr_phy_common.h"
|
||||
#include "filt16a_32.h"
|
||||
#include "T.h"
|
||||
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
|
||||
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
|
||||
|
||||
|
||||
extern openair0_config_t openair0_cfg[];
|
||||
|
||||
// #define DEBUG_PDSCH
|
||||
@@ -651,12 +652,12 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
unsigned char symbol,
|
||||
int dmrss,
|
||||
uint8_t ssb_index,
|
||||
uint8_t n_hf,
|
||||
uint ssb_index,
|
||||
uint n_hf,
|
||||
int ssb_start_subcarrier,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
bool sidelink,
|
||||
uint16_t Nid)
|
||||
uint Nid)
|
||||
{
|
||||
int Ns = proc->nr_slot_rx;
|
||||
c16_t pilot[200] __attribute__((aligned(16)));
|
||||
|
||||
@@ -75,12 +75,12 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
unsigned char symbol,
|
||||
int dmrss,
|
||||
uint8_t ssb_index,
|
||||
uint8_t n_hf,
|
||||
uint ssb_index,
|
||||
uint n_hf,
|
||||
int ssb_start_subcarrier,
|
||||
const c16_t rxdataF[][fp->samples_per_slot_wCP],
|
||||
bool sidelink,
|
||||
uint16_t Nid);
|
||||
uint Nid);
|
||||
|
||||
int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
|
||||
@@ -47,9 +47,7 @@
|
||||
#include "PHY/TOOLS/tools_defs.h"
|
||||
#include "nr-uesoftmodem.h"
|
||||
|
||||
//static nfapi_nr_config_request_t config_t;
|
||||
//static nfapi_nr_config_request_t* config =&config_t;
|
||||
// #define DEBUG_INITIAL_SYNCH
|
||||
//#define DEBUG_INITIAL_SYNCH
|
||||
#define DUMP_PBCH_CH_ESTIMATES 0
|
||||
|
||||
// structure used for multiple SSB detection
|
||||
@@ -223,8 +221,7 @@ void nr_scan_ssb(void *arg)
|
||||
ssbInfo->ssbOffset = sync_pos - fp->nb_prefix_samples;
|
||||
|
||||
#ifdef DEBUG_INITIAL_SYNCH
|
||||
LOG_I(PHY, "[UE%d] Initial sync : Estimated PSS position %d, Nid2 %d\n", ue->Mod_id, sync_pos, ue->common_vars.nid2);
|
||||
LOG_I(PHY, "sync_pos %d ssb_offset %d \n", sync_pos, ue->ssb_offset);
|
||||
LOG_I(PHY, "Initial sync : Estimated PSS position %d, Nid2 %d, ssb offset %d\n", sync_pos, nid2, ssbInfo->ssbOffset);
|
||||
#endif
|
||||
/* check that SSS/PBCH block is continuous inside the received buffer */
|
||||
if (ssbInfo->ssbOffset + NR_N_SYMBOLS_SSB * (fp->ofdm_symbol_size + fp->nb_prefix_samples) >= fp->samples_per_frame) {
|
||||
@@ -256,10 +253,6 @@ void nr_scan_ssb(void *arg)
|
||||
rxdataF,
|
||||
link_type_dl);
|
||||
|
||||
#ifdef DEBUG_INITIAL_SYNCH
|
||||
LOG_I(PHY, "Calling sss detection (normal CP)\n");
|
||||
#endif
|
||||
|
||||
int freq_offset_sss = 0;
|
||||
int32_t metric_tdd_ncp = 0;
|
||||
uint8_t phase_tdd_ncp;
|
||||
@@ -273,7 +266,15 @@ void nr_scan_ssb(void *arg)
|
||||
&phase_tdd_ncp,
|
||||
&freq_offset_sss,
|
||||
rxdataF);
|
||||
|
||||
#ifdef DEBUG_INITIAL_SYNCH
|
||||
LOG_I(PHY,
|
||||
"TDD Normal prefix: sss detection result; %d, CellId %d metric %d, phase %d, measured offset %d\n",
|
||||
ssbInfo->syncRes.cell_detected,
|
||||
ssbInfo->nidCell,
|
||||
metric_tdd_ncp,
|
||||
phase_tdd_ncp,
|
||||
ssbInfo->syncRes.rx_offset);
|
||||
#endif
|
||||
ssbInfo->freqOffset = freq_offset_pss + freq_offset_sss;
|
||||
|
||||
uint32_t nr_gold_pbch_ref[2][64][NR_PBCH_DMRS_LENGTH_DWORD];
|
||||
@@ -315,23 +316,24 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
|
||||
for (int s = 0; s < numGscn; s++) {
|
||||
notifiedFIFO_elt_t *req = newNotifiedFIFO_elt(sizeof(nr_ue_ssb_scan_t), gscnInfo[s].gscn, &nf, &nr_scan_ssb);
|
||||
nr_ue_ssb_scan_t *ssbInfo = (nr_ue_ssb_scan_t *)NotifiedFifoData(req);
|
||||
ssbInfo->gscnInfo = gscnInfo[s];
|
||||
*ssbInfo = (nr_ue_ssb_scan_t){.gscnInfo = gscnInfo[s],
|
||||
.fp = &ue->frame_parms,
|
||||
.proc = proc,
|
||||
.syncRes.cell_detected = false,
|
||||
.nFrames = n_frames,
|
||||
.foFlag = ue->UE_fo_compensation,
|
||||
.targetNidCell = ue->target_Nid_cell};
|
||||
ssbInfo->rxdata = malloc16_clear(fp->nb_antennas_rx * sizeof(c16_t *));
|
||||
for (int ant = 0; ant < fp->nb_antennas_rx; ant++) {
|
||||
ssbInfo->rxdata[ant] = malloc16_clear((fp->samples_per_frame * 2 + fp->ofdm_symbol_size) * sizeof(c16_t));
|
||||
ssbInfo->rxdata[ant] = malloc16(sizeof(c16_t) * (fp->samples_per_frame * 2 + fp->ofdm_symbol_size));
|
||||
memcpy(ssbInfo->rxdata[ant], ue->common_vars.rxdata[ant], sizeof(c16_t) * fp->samples_per_frame * 2);
|
||||
memset(ssbInfo->rxdata[ant] + fp->samples_per_frame * 2, 0, fp->ofdm_symbol_size * sizeof(c16_t));
|
||||
}
|
||||
LOG_I(NR_PHY,
|
||||
"Scanning GSCN: %d, with SSB offset: %d, SSB Freq: %lf\n",
|
||||
ssbInfo->gscnInfo.gscn,
|
||||
ssbInfo->gscnInfo.ssbFirstSC,
|
||||
ssbInfo->gscnInfo.ssRef);
|
||||
ssbInfo->fp = &ue->frame_parms;
|
||||
ssbInfo->proc = proc;
|
||||
ssbInfo->syncRes.cell_detected = false;
|
||||
ssbInfo->nFrames = n_frames;
|
||||
ssbInfo->foFlag = ue->UE_fo_compensation;
|
||||
ssbInfo->targetNidCell = ue->target_Nid_cell;
|
||||
pushTpool(&get_nrUE_params()->Tpool, req);
|
||||
}
|
||||
|
||||
@@ -437,16 +439,6 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
|
||||
res.syncRes.rx_offset = res.ssbOffset - sync_pos_frame;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_INITIAL_SYNCH
|
||||
LOG_I(PHY,
|
||||
"TDD Normal prefix: CellId %d metric %d, phase %d, pbch detected %d, measured offset %d\n",
|
||||
fp->Nid_cell,
|
||||
metric_tdd_ncp,
|
||||
phase_tdd_ncp,
|
||||
ret.cell_detected,
|
||||
ret.rx_offset);
|
||||
#endif
|
||||
|
||||
if (res.syncRes.cell_detected) {
|
||||
LOG_I(PHY, "[UE%d] In synch, rx_offset %d samples\n", ue->Mod_id, res.syncRes.rx_offset);
|
||||
LOG_I(PHY, "[UE %d] Measured Carrier Frequency offset %d Hz\n", ue->Mod_id, res.freqOffset);
|
||||
@@ -455,7 +447,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
|
||||
LOG_I(PHY,"[UE%d] Initial sync : PBCH not ok\n",ue->Mod_id);
|
||||
LOG_I(PHY, "[UE%d] Initial sync : Estimated PSS position %d, Nid2 %d\n", ue->Mod_id, sync_pos, ue->common_vars.nid2);
|
||||
LOG_I(PHY,"[UE%d] Initial sync : Estimated Nid_cell %d, Frame_type %d\n",ue->Mod_id,
|
||||
frame_parms->Nid_cell,frame_parms->frame_type);
|
||||
fp->Nid_cell,fp->frame_type);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -481,10 +473,10 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
|
||||
ue->measurements.rx_power_avg_dB[0] = dB_fixed(ue->measurements.rx_power_avg[0]);
|
||||
|
||||
#ifdef DEBUG_INITIAL_SYNCH
|
||||
LOG_I(PHY, "[UE%d] Initial sync : Estimated power: %d dB\n", ue->Mod_id, ue->measurements.rx_power_avg_dB[0]);
|
||||
LOG_I(PHY, "[UE%d] Initial sync failed : Estimated power: %d dB\n", ue->Mod_id, ue->measurements.rx_power_avg_dB[0]);
|
||||
#endif
|
||||
} else {
|
||||
LOG_A(PHY, "Initial sync successful\n");
|
||||
LOG_A(PHY, "Initial sync successful, PCI: %d\n",fp->Nid_cell);
|
||||
}
|
||||
// exit_fun("debug exit");
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INITIAL_UE_SYNC, VCD_FUNCTION_OUT);
|
||||
|
||||
@@ -55,11 +55,12 @@ static uint16_t nr_pbch_extract(uint32_t rxdataF_sz,
|
||||
uint32_t symbol,
|
||||
uint32_t s_offset,
|
||||
int ssb_start_subcarrier,
|
||||
const NR_DL_FRAME_PARMS *frame_parms)
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
int nid)
|
||||
{
|
||||
uint16_t rb;
|
||||
uint8_t i, j, aarx;
|
||||
int nushiftmod4 = frame_parms->Nid_cell % 4;
|
||||
int nushiftmod4 = nid % 4;
|
||||
AssertFatal(symbol>=1 && symbol<5,
|
||||
"symbol %d illegal for PBCH extraction\n",
|
||||
symbol);
|
||||
@@ -418,7 +419,8 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue,
|
||||
symbol,
|
||||
symbol_offset,
|
||||
ssb_start_subcarrier,
|
||||
frame_parms);
|
||||
frame_parms,
|
||||
Nid_cell);
|
||||
#ifdef DEBUG_PBCH
|
||||
LOG_I(PHY,"[PHY] PBCH Symbol %d ofdm size %d\n",symbol, frame_parms->ofdm_symbol_size);
|
||||
LOG_I(PHY,"[PHY] PBCH starting channel_level\n");
|
||||
|
||||
@@ -65,7 +65,7 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
|
||||
c16_t prach[(4688 + 4 * 24576) * 2] __attribute__((aligned(32))) = {0};
|
||||
int16_t prachF_tmp[(4688+4*24576)*4*2] __attribute__((aligned(32))) = {0};
|
||||
|
||||
int16_t Ncp = 0;
|
||||
int Ncp = 0;
|
||||
int prach_start, prach_sequence_length, i, prach_len, dftlen, mu, kbar, K, n_ra_prb, k, prachStartSymbol, sample_offset_slot;
|
||||
|
||||
fd_occasion = 0;
|
||||
@@ -332,6 +332,12 @@ int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, int frame, uint8_t
|
||||
dftlen >>= 1;
|
||||
break;
|
||||
|
||||
case 23040:
|
||||
// 20 MHz @ 23.04 Ms/s
|
||||
Ncp = (Ncp * 3) / 4;
|
||||
dftlen = (dftlen * 3) / 4;
|
||||
break;
|
||||
|
||||
case 30720:
|
||||
// 20, 25, 30 MHz @ 30.72 Ms/s
|
||||
break;
|
||||
|
||||
@@ -343,13 +343,13 @@ typedef struct {
|
||||
/// \f$\log_2(\max|H_i|^2)\f$
|
||||
int16_t log2_maxh;
|
||||
/// measured RX power based on DRS
|
||||
int ulsch_power[8];
|
||||
uint32_t ulsch_power[8];
|
||||
/// total signal over antennas
|
||||
int ulsch_power_tot;
|
||||
uint32_t ulsch_power_tot;
|
||||
/// measured RX noise power
|
||||
int ulsch_noise_power[8];
|
||||
/// total noise over antennas
|
||||
int ulsch_noise_power_tot;
|
||||
uint32_t ulsch_noise_power_tot;
|
||||
/// \brief llr values.
|
||||
/// - first index: ? [0..1179743] (hard coded)
|
||||
int16_t *llr;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
add_library(nr_phy_common src/nr_phy_common.c)
|
||||
target_include_directories(nr_phy_common PUBLIC inc/)
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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_PHY_COMMON__H__
|
||||
#define __NR_PHY_COMMON__H__
|
||||
#include "PHY/impl_defs_top.h"
|
||||
#include "PHY/TOOLS/tools_defs.h"
|
||||
|
||||
void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal);
|
||||
void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay);
|
||||
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb);
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 "nr_phy_common.h"
|
||||
|
||||
void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal)
|
||||
{
|
||||
const idft_size_idx_t idft_size = get_idft(ofdm_symbol_size);
|
||||
idft(idft_size, freq_signal, time_signal, 1);
|
||||
}
|
||||
|
||||
void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay)
|
||||
{
|
||||
freq2time(ofdm_symbol_size, (int16_t *)ls_est, (int16_t *)ch_estimates_time);
|
||||
|
||||
int max_pos = delay->delay_max_pos;
|
||||
int max_val = delay->delay_max_val;
|
||||
const int sync_pos = 0;
|
||||
|
||||
for (int i = 0; i < ofdm_symbol_size; i++) {
|
||||
int temp = c16amp2(ch_estimates_time[i]) >> 1;
|
||||
if (temp > max_val) {
|
||||
max_pos = i;
|
||||
max_val = temp;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_pos > ofdm_symbol_size / 2)
|
||||
max_pos = max_pos - ofdm_symbol_size;
|
||||
|
||||
delay->delay_max_pos = max_pos;
|
||||
delay->delay_max_val = max_val;
|
||||
delay->est_delay = max_pos - sync_pos;
|
||||
}
|
||||
|
||||
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb)
|
||||
{
|
||||
// assume power at AMP is 20dBm
|
||||
// if gain = 20 (power == 40)
|
||||
int gain_dB = power_dBm - power_max_dBm;
|
||||
double gain_lin;
|
||||
|
||||
gain_lin = pow(10, .1 * gain_dB);
|
||||
if ((nb_rb > 0) && (nb_rb <= total_nb_rb)) {
|
||||
return ((int)(AMP * sqrt(gain_lin * total_nb_rb / (double)nb_rb)));
|
||||
} else {
|
||||
LOG_E(PHY, "Illegal nb_rb/N_RB_UL combination (%d/%d)\n", nb_rb, total_nb_rb);
|
||||
// mac_xface->macphy_exit("");
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@@ -111,8 +111,6 @@ int8_t nr_find_ue(uint16_t rnti, PHY_VARS_eNB *phy_vars_eNB);
|
||||
*/
|
||||
void ue_ta_procedures(PHY_VARS_NR_UE *ue, int slot_tx, int frame_tx);
|
||||
|
||||
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb);
|
||||
|
||||
void set_tx_harq_id(NR_UE_ULSCH_t *ulsch, int harq_pid, int slot_tx);
|
||||
int get_tx_harq_id(NR_UE_ULSCH_t *ulsch, int slot_tx);
|
||||
|
||||
|
||||
@@ -407,23 +407,6 @@ static int nr_ue_pbch_procedures(PHY_VARS_NR_UE *ue,
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int N_RB_UL, int nb_rb)
|
||||
{
|
||||
|
||||
int gain_dB = power_dBm - power_max_dBm;
|
||||
double gain_lin;
|
||||
|
||||
gain_lin = pow(10,.1*gain_dB);
|
||||
if ((nb_rb >0) && (nb_rb <= N_RB_UL)) {
|
||||
return((int)(AMP*sqrt(gain_lin*N_RB_UL/(double)nb_rb)));
|
||||
}
|
||||
else {
|
||||
LOG_E(PHY,"Illegal nb_rb/N_RB_UL combination (%d/%d)\n",nb_rb,N_RB_UL);
|
||||
//mac_xface->macphy_exit("");
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue,
|
||||
const UE_nr_rxtx_proc_t *proc,
|
||||
int32_t pdcch_est_size,
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
add_subdirectory(nr_rlc)
|
||||
add_subdirectory(NR_MAC_UE)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
add_library(nr_ue_power_procedures nr_ue_power_procedures.c)
|
||||
target_link_libraries(nr_ue_power_procedures PUBLIC asn1_nr_rrc ${T_LIB} MAC_NR_COMMON nr_common)
|
||||
if (ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
@@ -227,7 +227,16 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
|
||||
PUCCH_sched_t *pucch,
|
||||
fapi_nr_ul_config_pucch_pdu *pucch_pdu);
|
||||
|
||||
int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int N_RB_UL, bool is_transform_precoding, int n_prbs, int start_prb);
|
||||
int nr_get_Pcmax(int p_Max,
|
||||
uint16_t nr_band,
|
||||
frequency_range_t frequency_range,
|
||||
int Qm,
|
||||
bool powerBoostPi2BPSK,
|
||||
int scs,
|
||||
int N_RB_UL,
|
||||
bool is_transform_precoding,
|
||||
int n_prbs,
|
||||
int start_prb);
|
||||
|
||||
int get_sum_delta_pucch(NR_UE_MAC_INST_t *mac, int slot, frame_t frame);
|
||||
|
||||
|
||||
@@ -79,7 +79,16 @@ void init_RA(NR_UE_MAC_INST_t *mac,
|
||||
int n_prbs = get_N_RA_RB(prach_scs, mac->current_UL_BWP->scs);
|
||||
int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + mac->current_UL_BWP->BWPStart;
|
||||
// PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1)
|
||||
prach_resources->RA_PCMAX = nr_get_Pcmax(mac, 2, false, prach_scs, cfg->carrier_config.dl_grid_size[prach_scs], true, n_prbs, start_prb);
|
||||
prach_resources->RA_PCMAX = nr_get_Pcmax(mac->p_Max,
|
||||
mac->nr_band,
|
||||
mac->frequency_range,
|
||||
2,
|
||||
false,
|
||||
prach_scs,
|
||||
cfg->carrier_config.dl_grid_size[prach_scs],
|
||||
true,
|
||||
n_prbs,
|
||||
start_prb);
|
||||
prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
|
||||
prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER = 1;
|
||||
prach_resources->POWER_OFFSET_2STEP_RA = 0;
|
||||
|
||||
@@ -85,16 +85,24 @@ static int get_deltatf(uint16_t nb_of_prbs,
|
||||
// -- Powerclass 3 capable UE (which is default power class unless otherwise stated)
|
||||
// -- Maximum power reduction (MPR_c) for power class 3
|
||||
// -- no additional MPR (A_MPR_c)
|
||||
int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs, int N_RB_UL, bool is_transform_precoding, int n_prbs, int start_prb)
|
||||
int nr_get_Pcmax(int p_Max,
|
||||
uint16_t nr_band,
|
||||
frequency_range_t frequency_range,
|
||||
int Qm,
|
||||
bool powerBoostPi2BPSK,
|
||||
int scs,
|
||||
int N_RB_UL,
|
||||
bool is_transform_precoding,
|
||||
int n_prbs,
|
||||
int start_prb)
|
||||
{
|
||||
int nr_band = mac->nr_band;
|
||||
if(mac->frequency_range == FR1) {
|
||||
|
||||
//TODO configure P-MAX from the upper layers according to 38.331
|
||||
if (frequency_range == FR1) {
|
||||
// TODO configure P-MAX from the upper layers according to 38.331
|
||||
int p_powerclass = 23; // dBm assuming poweclass 3 UE
|
||||
int p_emax = mac->p_Max != INT_MIN ? mac->p_Max : p_powerclass;
|
||||
int p_emax = p_Max != INT_MIN ? p_Max : p_powerclass;
|
||||
int delta_P_powerclass = 0; // for powerclass 2 needs to be changed
|
||||
if(mac->p_Max && Qm == 1 && powerBoostPi2BPSK && (nr_band == 40 || nr_band == 41 || nr_band == 77 || nr_band == 78 || nr_band == 79)) {
|
||||
if (p_Max && Qm == 1 && powerBoostPi2BPSK
|
||||
&& (nr_band == 40 || nr_band == 41 || nr_band == 77 || nr_band == 78 || nr_band == 79)) {
|
||||
p_emax += 3;
|
||||
delta_P_powerclass -= 3;
|
||||
}
|
||||
@@ -103,54 +111,52 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs,
|
||||
int delta_T_IB = 0;
|
||||
|
||||
// TODO in case of band 41 and PRB allocation within 4MHz of the upper or lower limit of the band -> delta_TC = 1.5
|
||||
if(nr_band == 41)
|
||||
if (nr_band == 41)
|
||||
LOG_E(NR_MAC, "Need to implement delta_TC for band 41\n");
|
||||
int delta_TC = 0;
|
||||
|
||||
float MPR = 0;
|
||||
frame_type_t frame_type = get_frame_type(nr_band, scs);
|
||||
if(compare_relative_ul_channel_bw(nr_band, scs, N_RB_UL, frame_type)) {
|
||||
if (compare_relative_ul_channel_bw(nr_band, scs, N_RB_UL, frame_type)) {
|
||||
int rb_low = (n_prbs / 2) > 1 ? (n_prbs / 2) : 1;
|
||||
int rb_high = N_RB_UL - rb_low - n_prbs;
|
||||
bool is_inner_rb = start_prb >= rb_low && start_prb <= rb_high && n_prbs <= ((N_RB_UL / 2) + (N_RB_UL & 1));
|
||||
// Table 6.2.2-1 in 38.101
|
||||
switch (Qm) {
|
||||
case 1 :
|
||||
case 1:
|
||||
AssertFatal(false, "MPR for Pi/2 BPSK not implemented yet\n");
|
||||
break;
|
||||
case 2 :
|
||||
case 2:
|
||||
if (is_transform_precoding) {
|
||||
if(!is_inner_rb)
|
||||
if (!is_inner_rb)
|
||||
MPR = 1;
|
||||
}
|
||||
else {
|
||||
if(is_inner_rb)
|
||||
} else {
|
||||
if (is_inner_rb)
|
||||
MPR = 1.5;
|
||||
else
|
||||
MPR = 3;
|
||||
}
|
||||
break;
|
||||
case 4 :
|
||||
case 4:
|
||||
if (is_transform_precoding) {
|
||||
if(is_inner_rb)
|
||||
if (is_inner_rb)
|
||||
MPR = 1;
|
||||
else
|
||||
MPR = 2;
|
||||
}
|
||||
else {
|
||||
if(is_inner_rb)
|
||||
} else {
|
||||
if (is_inner_rb)
|
||||
MPR = 2;
|
||||
else
|
||||
MPR = 3;
|
||||
}
|
||||
break;
|
||||
case 6 :
|
||||
case 6:
|
||||
if (is_transform_precoding)
|
||||
MPR = 2.5;
|
||||
else
|
||||
MPR = 3.5;
|
||||
break;
|
||||
case 8 :
|
||||
case 8:
|
||||
if (is_transform_precoding)
|
||||
MPR = 4.5;
|
||||
else
|
||||
@@ -170,12 +176,12 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs,
|
||||
if (P_MPR > total_reduction)
|
||||
total_reduction = P_MPR;
|
||||
int pcmax_high, pcmax_low;
|
||||
if(mac->p_Max) {
|
||||
if (p_Max) {
|
||||
pcmax_high = p_emax < (p_powerclass - delta_P_powerclass) ? p_emax : (p_powerclass - delta_P_powerclass);
|
||||
pcmax_low = (p_emax - delta_TC) < (p_powerclass - delta_P_powerclass - total_reduction) ?
|
||||
(p_emax - delta_TC) : (p_powerclass - delta_P_powerclass - total_reduction);
|
||||
}
|
||||
else {
|
||||
pcmax_low = (p_emax - delta_TC) < (p_powerclass - delta_P_powerclass - total_reduction)
|
||||
? (p_emax - delta_TC)
|
||||
: (p_powerclass - delta_P_powerclass - total_reduction);
|
||||
} else {
|
||||
pcmax_high = p_powerclass - delta_P_powerclass;
|
||||
pcmax_low = p_powerclass - delta_P_powerclass - total_reduction;
|
||||
}
|
||||
@@ -183,8 +189,7 @@ int nr_get_Pcmax(NR_UE_MAC_INST_t *mac, int Qm, bool powerBoostPi2BPSK, int scs,
|
||||
int pcmax = (pcmax_low + pcmax_high) / 2;
|
||||
LOG_D(MAC, "Configured maximum output power: %d dBm <= PCMAX %d dBm <= %d dBm \n", pcmax_low, pcmax, pcmax_high);
|
||||
return pcmax;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// FR2 TODO it is even more complex because it is radiated power
|
||||
return 23;
|
||||
}
|
||||
@@ -294,7 +299,16 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
|
||||
|
||||
// PUCCH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1)
|
||||
// TODO: P_CMAX for format 2
|
||||
int P_CMAX = nr_get_Pcmax(mac, 2, false, mac->current_UL_BWP->scs, mac->current_UL_BWP->BWPSize, true, 1, start_prb);
|
||||
int P_CMAX = nr_get_Pcmax(mac->p_Max,
|
||||
mac->nr_band,
|
||||
mac->frequency_range,
|
||||
2,
|
||||
false,
|
||||
mac->current_UL_BWP->scs,
|
||||
mac->current_UL_BWP->BWPSize,
|
||||
true,
|
||||
1,
|
||||
start_prb);
|
||||
int P_CMIN = -40; // TODO: minimum TX power, possibly 38.101-1 6.3.1
|
||||
int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm);
|
||||
|
||||
@@ -358,3 +372,27 @@ static int get_deltatf(uint16_t nb_of_prbs,
|
||||
}
|
||||
return DELTA_TF;
|
||||
}
|
||||
|
||||
// Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission
|
||||
// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16
|
||||
// Assumptions:
|
||||
// - PRACH transmission from a UE is not in response to a detection of a PDCCH order by the UE
|
||||
// Measurement units:
|
||||
// - referenceSignalPower: dBm/RE (average EPRE of the resources elements that carry secondary synchronization signals in dBm)
|
||||
int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm)
|
||||
{
|
||||
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
|
||||
int referenceSignalPower = cfg->ssb_config.ss_pbch_power;
|
||||
//TODO improve PL measurements. Probably not correct as it is.
|
||||
|
||||
int16_t pathloss = (int16_t)(referenceSignalPower - ssb_rsrp_dBm);
|
||||
|
||||
LOG_D(NR_MAC, "pathloss %d dB, referenceSignalPower %d dBm/RE (%f mW), RSRP %d dBm (%f mW)\n",
|
||||
pathloss,
|
||||
referenceSignalPower,
|
||||
pow(10, referenceSignalPower/10),
|
||||
ssb_rsrp_dBm,
|
||||
pow(10, ssb_rsrp_dBm/10));
|
||||
|
||||
return pathloss;
|
||||
}
|
||||
|
||||
@@ -1368,7 +1368,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac,
|
||||
// if temp_dai is less or equal than cumulative highest dai for given slot
|
||||
// it's an indication dai was reset due to modulo 4 operation
|
||||
if (temp_dai <= highest_dai) {
|
||||
int mod4_count = (highest_dai / 4) + 1; // to take into account how many times dai wrapped up (modulo 4)
|
||||
int mod4_count = (highest_dai + 1) / 4; // to take into account how many times dai wrapped up (modulo 4)
|
||||
current_harq->dai_cumul += (mod4_count * 4);
|
||||
}
|
||||
LOG_D(NR_MAC,
|
||||
@@ -3945,26 +3945,3 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission
|
||||
// computation according to clause 7.4 (Physical random access channel) of 3GPP TS 38.213 version 16.3.0 Release 16
|
||||
// Assumptions:
|
||||
// - PRACH transmission from a UE is not in response to a detection of a PDCCH order by the UE
|
||||
// Measurement units:
|
||||
// - referenceSignalPower: dBm/RE (average EPRE of the resources elements that carry secondary synchronization signals in dBm)
|
||||
int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm)
|
||||
{
|
||||
fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
|
||||
int referenceSignalPower = cfg->ssb_config.ss_pbch_power;
|
||||
//TODO improve PL measurements. Probably not correct as it is.
|
||||
|
||||
int16_t pathloss = (int16_t)(referenceSignalPower - ssb_rsrp_dBm);
|
||||
|
||||
LOG_D(NR_MAC, "pathloss %d dB, referenceSignalPower %d dBm/RE (%f mW), RSRP %d dBm (%f mW)\n",
|
||||
pathloss,
|
||||
referenceSignalPower,
|
||||
pow(10, referenceSignalPower/10),
|
||||
ssb_rsrp_dBm,
|
||||
pow(10, ssb_rsrp_dBm/10));
|
||||
|
||||
return pathloss;
|
||||
}
|
||||
|
||||
@@ -1768,13 +1768,25 @@ static void build_ssb_list(NR_UE_MAC_INST_t *mac)
|
||||
uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[ssb_index / 32].ssb_mask;
|
||||
// check if if current SSB is transmitted
|
||||
if ((curr_mask >> (31 - (ssb_index % 32))) & 0x01) {
|
||||
ssb_list->nb_ssb_per_index[ssb_index]=ssb_list->nb_tx_ssb;
|
||||
ssb_list->nb_ssb_per_index[ssb_index] = ssb_list->nb_tx_ssb;
|
||||
ssb_list->nb_tx_ssb++;
|
||||
}
|
||||
else
|
||||
ssb_list->nb_ssb_per_index[ssb_index] = -1;
|
||||
}
|
||||
ssb_list->tx_ssb = calloc(ssb_list->nb_tx_ssb, sizeof(*ssb_list->tx_ssb));
|
||||
}
|
||||
|
||||
static int get_ssb_idx_from_list(ssb_list_info_t *ssb_list, int idx)
|
||||
{
|
||||
for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) {
|
||||
if (ssb_list->nb_ssb_per_index[ssb_index] == idx)
|
||||
return ssb_index;
|
||||
}
|
||||
AssertFatal(false, "Couldn't find SSB index in SSB list\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Map the transmitted SSBs to the ROs and create the association pattern according to the config
|
||||
static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
|
||||
{
|
||||
@@ -1863,7 +1875,7 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
|
||||
// WIP: only one possible association period so the starting PRACH configuration period is automatically 0
|
||||
// WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
|
||||
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
|
||||
int ssb_idx = 0;
|
||||
int idx = 0;
|
||||
bool done = false;
|
||||
for (int i = 0; i < prach_period->nb_of_prach_conf_period && !done; i++, prach_configuration_period_idx++) {
|
||||
prach_period->prach_conf_period_list[i] = &prach_assoc_pattern->prach_conf_period_list[prach_configuration_period_idx];
|
||||
@@ -1880,9 +1892,10 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
|
||||
// Go through the list of transmitted SSBs and map the required amount of SSBs to this RO
|
||||
// WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
|
||||
// this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
|
||||
for (; ssb_idx < ssb_list->nb_tx_ssb; ssb_idx++) {
|
||||
ssb_info_t *tx_ssb = ssb_list->tx_ssb + ssb_idx;
|
||||
for (; idx < ssb_list->nb_tx_ssb; idx++) {
|
||||
ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx;
|
||||
// Map only the transmitted ssb_idx
|
||||
int ssb_idx = get_ssb_idx_from_list(ssb_list, idx);
|
||||
ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx;
|
||||
ro_p->nb_mapped_ssb++;
|
||||
AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1,
|
||||
@@ -1903,11 +1916,11 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
|
||||
tx_ssb->nb_mapped_ro);
|
||||
// If all the required SSBs are mapped to this RO, exit the loop of SSBs
|
||||
if (ro_p->nb_mapped_ssb == ssb_rach_ratio) {
|
||||
ssb_idx++;
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
done = MAX_NB_SSB == ssb_idx;
|
||||
done = MAX_NB_SSB == idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1919,8 +1932,8 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
|
||||
for (prach_association_period_t *prach_period = prach_assoc_pattern->prach_association_period_list; prach_period < end;
|
||||
prach_period++) {
|
||||
// Go through the list of transmitted SSBs
|
||||
for (int ssb_idx = 0; ssb_idx < ssb_list->nb_tx_ssb; ssb_idx++) {
|
||||
ssb_info_t *tx_ssb = ssb_list->tx_ssb + ssb_idx;
|
||||
for (int idx = 0; idx < ssb_list->nb_tx_ssb; idx++) {
|
||||
ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx;
|
||||
uint8_t nb_mapped_ro_in_association_period=0; // Reset the nb of mapped ROs for the new SSB index
|
||||
bool done = false;
|
||||
// Map all the required ROs to this SSB
|
||||
@@ -1936,6 +1949,7 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
|
||||
for (int ro_in_freq = 0; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq && !done; ro_in_freq++) {
|
||||
prach_occasion_info_t *ro_p =
|
||||
slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq;
|
||||
int ssb_idx = get_ssb_idx_from_list(ssb_list, idx);
|
||||
ro_p->mapped_ssb_idx[0] = ssb_idx;
|
||||
ro_p->nb_mapped_ssb = 1;
|
||||
AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1,
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
add_executable(test_nr_ue_power_procedures
|
||||
test_nr_ue_power_procedures.cpp)
|
||||
target_link_libraries(test_nr_ue_power_procedures PRIVATE nr_ue_power_procedures GTest::gtest minimal_lib)
|
||||
add_dependencies(tests test_nr_ue_power_procedures)
|
||||
add_test(NAME test_nr_ue_power_procedures
|
||||
COMMAND ./test_nr_ue_power_procedures)
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 "gtest/gtest.h"
|
||||
extern "C" {
|
||||
#include "openair2/LAYER2/NR_MAC_UE/mac_proto.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
uint64_t get_softmodem_optmask(void) {return 0;}
|
||||
static softmodem_params_t softmodem_params;
|
||||
softmodem_params_t *get_softmodem_params(void) {
|
||||
return &softmodem_params;
|
||||
|
||||
}
|
||||
}
|
||||
#include <cstdio>
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
TEST(power_procedures_fr1, test_prach_max_tx_power_mpr)
|
||||
{
|
||||
// Inner PRB, MPR = 1.5
|
||||
int prb_start = 4;
|
||||
int N_RB_UL = 51; // 10Mhz
|
||||
EXPECT_EQ(22, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start));
|
||||
|
||||
// Outer PRB, MPR = 3
|
||||
prb_start = 0;
|
||||
EXPECT_EQ(21, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start));
|
||||
|
||||
// Channel bandwidth conditon not met, no MPR
|
||||
N_RB_UL = 106;
|
||||
EXPECT_EQ(23, nr_get_Pcmax(23, 20, FR1, 2, false, 1, N_RB_UL, false, 6, prb_start));
|
||||
}
|
||||
|
||||
TEST(power_procedures_fr1, test_not_implemented)
|
||||
{
|
||||
int N_RB_UL = 51;
|
||||
EXPECT_DEATH(nr_get_Pcmax(23, 20, FR1, 1, false, 1, N_RB_UL, false, 6, 0), "MPR for Pi/2 BPSK not implemented yet");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
logInit();
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -65,6 +65,7 @@ static void schedule_ssb(frame_t frame,
|
||||
dl_config_pdu->PDUSize =2 + sizeof(nfapi_nr_dl_tti_ssb_pdu_rel15_t);
|
||||
|
||||
AssertFatal(scc->physCellId!=NULL,"ServingCellConfigCommon->physCellId is null\n");
|
||||
AssertFatal(*scc->physCellId < 1008 && *scc->physCellId >=0, "5G physicall cell id out of range: %ld\n", *scc->physCellId);
|
||||
dl_config_pdu->ssb_pdu.ssb_pdu_rel15.PhysCellId = *scc->physCellId;
|
||||
dl_config_pdu->ssb_pdu.ssb_pdu_rel15.BetaPss = 0;
|
||||
dl_config_pdu->ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = i_ssb;
|
||||
|
||||
@@ -58,6 +58,79 @@ extern uint16_t NB_UE_INST;
|
||||
static nr_ue_nas_t nr_ue_nas = {0};
|
||||
static nr_nas_msg_snssai_t nas_allowed_nssai[8];
|
||||
|
||||
typedef enum {
|
||||
NAS_SECURITY_NO_SECURITY_CONTEXT,
|
||||
NAS_SECURITY_UNPROTECTED,
|
||||
NAS_SECURITY_INTEGRITY_FAILED,
|
||||
NAS_SECURITY_INTEGRITY_PASSED,
|
||||
NAS_SECURITY_BAD_INPUT
|
||||
} security_state_t;
|
||||
|
||||
security_state_t nas_security_rx_process(nr_ue_nas_t *nas, uint8_t *pdu_buffer, int pdu_length)
|
||||
{
|
||||
if (nas->security_container == NULL)
|
||||
return NAS_SECURITY_NO_SECURITY_CONTEXT;
|
||||
if (pdu_buffer[1] == 0)
|
||||
return NAS_SECURITY_UNPROTECTED;
|
||||
/* header is 7 bytes, require at least one byte of payload */
|
||||
if (pdu_length < 8)
|
||||
return NAS_SECURITY_BAD_INPUT;
|
||||
/* only accept "integrity protected and ciphered" messages */
|
||||
if (pdu_buffer[1] != 2) {
|
||||
LOG_E(NAS, "todo: unhandled security type %d\n", pdu_buffer[2]);
|
||||
return NAS_SECURITY_BAD_INPUT;
|
||||
}
|
||||
|
||||
/* synchronize NAS SQN, based on 24.501 4.4.3.1 */
|
||||
int nas_sqn = pdu_buffer[6];
|
||||
int target_sqn = nas->security.nas_count_dl & 0xff;
|
||||
if (nas_sqn != target_sqn) {
|
||||
if (nas_sqn < target_sqn)
|
||||
nas->security.nas_count_dl += 256;
|
||||
nas->security.nas_count_dl &= ~255;
|
||||
nas->security.nas_count_dl |= nas_sqn;
|
||||
}
|
||||
if (nas->security.nas_count_dl > 0x00ffffff) {
|
||||
/* it's doubtful that this will happen, so let's simply exit for the time being */
|
||||
/* to be refined if needed */
|
||||
LOG_E(NAS, "max NAS COUNT DL reached\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* check integrity */
|
||||
uint8_t computed_mac[4];
|
||||
nas_stream_cipher_t stream_cipher;
|
||||
stream_cipher.context = nas->security_container->integrity_context;
|
||||
stream_cipher.count = nas->security.nas_count_dl;
|
||||
stream_cipher.bearer = 1; /* todo: don't hardcode */
|
||||
stream_cipher.direction = 1;
|
||||
stream_cipher.message = pdu_buffer + 6;
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (pdu_length - 6) << 3;
|
||||
stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, computed_mac);
|
||||
|
||||
uint8_t *received_mac = pdu_buffer + 2;
|
||||
|
||||
if (memcmp(received_mac, computed_mac, 4) != 0)
|
||||
return NAS_SECURITY_INTEGRITY_FAILED;
|
||||
|
||||
/* decipher */
|
||||
uint8_t buf[pdu_length - 7];
|
||||
stream_cipher.context = nas->security_container->ciphering_context;
|
||||
stream_cipher.count = nas->security.nas_count_dl;
|
||||
stream_cipher.bearer = 1; /* todo: don't hardcode */
|
||||
stream_cipher.direction = 1;
|
||||
stream_cipher.message = pdu_buffer + 7;
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (pdu_length - 7) << 3;
|
||||
stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf);
|
||||
memcpy(pdu_buffer + 7, buf, pdu_length - 7);
|
||||
|
||||
nas->security.nas_count_dl++;
|
||||
|
||||
return NAS_SECURITY_INTEGRITY_PASSED;
|
||||
}
|
||||
|
||||
static int nas_protected_security_header_encode(
|
||||
char *buffer,
|
||||
const fgs_nas_message_security_header_t *header,
|
||||
@@ -301,7 +374,8 @@ void derive_kamf(uint8_t *kseaf, uint8_t *kamf, uint16_t abba, uicc_t* uicc) {
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t kamf[32], uint8_t *knas_int) {
|
||||
void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t kamf[32], uint8_t *knas)
|
||||
{
|
||||
uint8_t S[20] = {0};
|
||||
uint8_t out[32] = { 0 };
|
||||
S[0] = 0x69; //FC
|
||||
@@ -315,7 +389,7 @@ void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t
|
||||
byte_array_t data = {.buf = S, .len = 7};
|
||||
kdf(kamf, data, 32, out);
|
||||
|
||||
memcpy(knas_int, out+16, 16);
|
||||
memcpy(knas, out+16, 16);
|
||||
}
|
||||
|
||||
void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb){
|
||||
@@ -360,7 +434,6 @@ void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) {
|
||||
uint8_t *kausf = nas->security.kausf;
|
||||
uint8_t *kseaf = nas->security.kseaf;
|
||||
uint8_t *kamf = nas->security.kamf;
|
||||
uint8_t *knas_int = nas->security.knas_int;
|
||||
uint8_t *output = nas->security.res;
|
||||
uint8_t *rand = nas->security.rand;
|
||||
uint8_t *kgnb = nas->security.kgnb;
|
||||
@@ -383,7 +456,6 @@ void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) {
|
||||
derive_kausf(ck, ik, sqn, kausf, nas->uicc);
|
||||
derive_kseaf(kausf, kseaf, nas->uicc);
|
||||
derive_kamf(kseaf, kamf, 0x0000, nas->uicc);
|
||||
derive_knas(0x02, 2, kamf, knas_int);
|
||||
derive_kgnb(kamf,0,kgnb);
|
||||
|
||||
printf("kausf:");
|
||||
@@ -404,12 +476,6 @@ void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) {
|
||||
printf("%x ", kamf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("knas_int:\n");
|
||||
for(int i = 0; i < 16; i++){
|
||||
printf("%x ", knas_int[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
nr_ue_nas_t *get_ue_nas_info(module_id_t module_id)
|
||||
@@ -464,8 +530,8 @@ void generateRegistrationRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas)
|
||||
mm_msg->registration_request.presencemask |= REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_PRESENT;
|
||||
mm_msg->registration_request.nruesecuritycapability.iei = REGISTRATION_REQUEST_UE_SECURITY_CAPABILITY_IEI;
|
||||
mm_msg->registration_request.nruesecuritycapability.length = 8;
|
||||
mm_msg->registration_request.nruesecuritycapability.fg_EA = 0xa0;
|
||||
mm_msg->registration_request.nruesecuritycapability.fg_IA = 0x20;
|
||||
mm_msg->registration_request.nruesecuritycapability.fg_EA = 0xe0;
|
||||
mm_msg->registration_request.nruesecuritycapability.fg_IA = 0x60;
|
||||
mm_msg->registration_request.nruesecuritycapability.EEA = 0;
|
||||
mm_msg->registration_request.nruesecuritycapability.EIA = 0;
|
||||
size += 10;
|
||||
@@ -513,10 +579,6 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype
|
||||
static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *buf)
|
||||
{
|
||||
derive_ue_keys(buf, nas);
|
||||
/* todo: as of now, nia2 is hardcoded in derive_ue_keys(), remove this hardcoding, use NAS signalling for getting proper algorithm */
|
||||
/* todo: deal with ciphering for this stream_security_container_init() (handle ciphering in general) */
|
||||
/* todo: stream_security_container_delete() is not called anywhere, deal with that */
|
||||
nas->security_container = stream_security_container_init(0, 2 /* hardcoded: nia2 */, NULL, nas->security.knas_int);
|
||||
OctetString res;
|
||||
res.length = 16;
|
||||
res.value = calloc(1,16);
|
||||
@@ -570,6 +632,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
// set security protected header
|
||||
nas_msg.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
|
||||
nas_msg.header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX;
|
||||
nas_msg.header.sequence_number = nas->security.nas_count_ul & 0xff;
|
||||
size += 7;
|
||||
|
||||
mm_msg = &nas_msg.security_protected.plain.mm_msg;
|
||||
@@ -600,16 +663,29 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
|
||||
initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len);
|
||||
|
||||
/* ciphering */
|
||||
uint8_t buf[initialNasMsg->length - 7];
|
||||
stream_cipher.context = nas->security_container->ciphering_context;
|
||||
AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n");
|
||||
stream_cipher.count = nas->security.nas_count_ul;
|
||||
stream_cipher.bearer = 1;
|
||||
stream_cipher.direction = 0;
|
||||
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 7);
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (initialNasMsg->length - 7) << 3;
|
||||
stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf);
|
||||
memcpy(stream_cipher.message, buf, initialNasMsg->length - 7);
|
||||
|
||||
/* integrity protection */
|
||||
stream_cipher.context = nas->security_container->integrity_context;
|
||||
stream_cipher.count = nas->security.mm_counter++;
|
||||
stream_cipher.count = nas->security.nas_count_ul++;
|
||||
stream_cipher.bearer = 1;
|
||||
stream_cipher.direction = 0;
|
||||
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6);
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (initialNasMsg->length - 6) << 3;
|
||||
|
||||
// only for Type of integrity protection algorithm: 128-5G-IA2 (2)
|
||||
stream_compute_integrity(EIA2_128_ALG_ID, &stream_cipher, mac);
|
||||
stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac);
|
||||
|
||||
printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]);
|
||||
for(int i = 0; i < 4; i++){
|
||||
@@ -617,6 +693,40 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_security_mode_command(instance_t instance, nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *pdu, int pdu_length)
|
||||
{
|
||||
/* retrieve integrity and ciphering algorithms */
|
||||
AssertFatal(pdu_length > 10, "nas: bad pdu\n");
|
||||
int ciphering_algorithm = (pdu[10] >> 4) & 0x0f;
|
||||
int integrity_algorithm = pdu[10] & 0x0f;
|
||||
|
||||
uint8_t *kamf = nas->security.kamf;
|
||||
uint8_t *knas_enc = nas->security.knas_enc;
|
||||
uint8_t *knas_int = nas->security.knas_int;
|
||||
|
||||
/* derive keys */
|
||||
derive_knas(0x01, ciphering_algorithm, kamf, knas_enc);
|
||||
derive_knas(0x02, integrity_algorithm, kamf, knas_int);
|
||||
|
||||
printf("knas_int: ");
|
||||
for(int i = 0; i < 16; i++){
|
||||
printf("%x ", knas_int[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("knas_enc: ");
|
||||
for(int i = 0; i < 16; i++){
|
||||
printf("%x ", knas_enc[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* todo: stream_security_container_delete() is not called anywhere, deal with that */
|
||||
nas->security_container = stream_security_container_init(ciphering_algorithm, integrity_algorithm, knas_enc, knas_int);
|
||||
|
||||
nas_itti_kgnb_refresh_req(instance, nas->security.kgnb);
|
||||
generateSecurityModeComplete(nas, initialNasMsg);
|
||||
}
|
||||
|
||||
static void decodeRegistrationAccept(const uint8_t *buf, int len, nr_ue_nas_t *nas)
|
||||
{
|
||||
registration_accept_msg reg_acc = {0};
|
||||
@@ -656,7 +766,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
sp_msg->header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
|
||||
sp_msg->header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
|
||||
sp_msg->header.message_authentication_code = 0;
|
||||
sp_msg->header.sequence_number = 1;
|
||||
sp_msg->header.sequence_number = nas->security.nas_count_ul & 0xff;
|
||||
length = 7;
|
||||
sp_msg->plain.mm_msg.registration_complete.protocoldiscriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
|
||||
length += 1;
|
||||
@@ -672,6 +782,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
|
||||
// encode the message
|
||||
initialNasMsg->data = (Byte_t *)malloc(length * sizeof(Byte_t));
|
||||
initialNasMsg->length = length;
|
||||
|
||||
/* Encode the first octet of the header (extended protocol discriminator) */
|
||||
ENCODE_U8(initialNasMsg->data + size, sp_msg->header.protocol_discriminator, size);
|
||||
@@ -698,18 +809,29 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia
|
||||
if(sortransparentcontainer) {
|
||||
encode_registration_complete(&sp_msg->plain.mm_msg.registration_complete, initialNasMsg->data + size, length - size);
|
||||
}
|
||||
|
||||
initialNasMsg->length = length;
|
||||
|
||||
/* ciphering */
|
||||
uint8_t buf[initialNasMsg->length - 7];
|
||||
stream_cipher.context = nas->security_container->ciphering_context;
|
||||
AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n");
|
||||
stream_cipher.count = nas->security.nas_count_ul;
|
||||
stream_cipher.bearer = 1;
|
||||
stream_cipher.direction = 0;
|
||||
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 7);
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (initialNasMsg->length - 7) << 3;
|
||||
stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf);
|
||||
memcpy(stream_cipher.message, buf, initialNasMsg->length - 7);
|
||||
|
||||
/* integrity protection */
|
||||
stream_cipher.context = nas->security_container->integrity_context;
|
||||
stream_cipher.count = nas->security.mm_counter++;
|
||||
stream_cipher.count = nas->security.nas_count_ul++;
|
||||
stream_cipher.bearer = 1;
|
||||
stream_cipher.direction = 0;
|
||||
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6);
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (initialNasMsg->length - 6) << 3;
|
||||
|
||||
// only for Type of integrity protection algorithm: 128-5G-IA2 (2)
|
||||
stream_compute_integrity(EIA2_128_ALG_ID, &stream_cipher, mac);
|
||||
stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac);
|
||||
|
||||
printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]);
|
||||
for(int i = 0; i < 4; i++){
|
||||
@@ -738,7 +860,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi
|
||||
sp_msg->header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
|
||||
sp_msg->header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
|
||||
sp_msg->header.message_authentication_code = 0;
|
||||
sp_msg->header.sequence_number = 3;
|
||||
sp_msg->header.sequence_number = nas->security.nas_count_ul & 0xff;
|
||||
int size = sizeof(fgs_nas_message_security_header_t);
|
||||
|
||||
fgs_deregistration_request_ue_originating_msg *dereg_req = &sp_msg->plain.mm_msg.fgs_deregistration_request_ue_originating;
|
||||
@@ -761,19 +883,36 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi
|
||||
|
||||
initialNasMsg->length = security_header_len + mm_msg_encode(&sp_msg->plain.mm_msg, (uint8_t *)(initialNasMsg->data + security_header_len), size - security_header_len);
|
||||
|
||||
nas_stream_cipher_t stream_cipher = {
|
||||
.context = nas->security_container->integrity_context,
|
||||
.count = nas->security.mm_counter++,
|
||||
.bearer = 1,
|
||||
.direction = 0,
|
||||
.message = (unsigned char *)(initialNasMsg->data + 6),
|
||||
.blength = (initialNasMsg->length - 6) << 3, /* length in bits */
|
||||
};
|
||||
uint8_t mac[4];
|
||||
nas_stream_encrypt_eia2(&stream_cipher, mac);
|
||||
nas_stream_cipher_t stream_cipher;
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
initialNasMsg->data[2 + i] = mac[i];
|
||||
/* ciphering */
|
||||
uint8_t buf[initialNasMsg->length - 7];
|
||||
stream_cipher.context = nas->security_container->ciphering_context;
|
||||
AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n");
|
||||
stream_cipher.count = nas->security.nas_count_ul;
|
||||
stream_cipher.bearer = 1;
|
||||
stream_cipher.direction = 0;
|
||||
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 7);
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (initialNasMsg->length - 7) << 3;
|
||||
stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf);
|
||||
memcpy(stream_cipher.message, buf, initialNasMsg->length - 7);
|
||||
|
||||
/* integrity protection */
|
||||
stream_cipher.context = nas->security_container->integrity_context;
|
||||
stream_cipher.count = nas->security.nas_count_ul++;
|
||||
stream_cipher.bearer = 1;
|
||||
stream_cipher.direction = 0;
|
||||
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6);
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (initialNasMsg->length - 6) << 3;
|
||||
uint8_t mac[4];
|
||||
stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac);
|
||||
|
||||
printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]);
|
||||
for(int i = 0; i < 4; i++){
|
||||
initialNasMsg->data[2+i] = mac[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, nas_pdu_session_req_t *pdu_req)
|
||||
@@ -800,7 +939,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
|
||||
uint8_t mac[4];
|
||||
nas_msg.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE;
|
||||
nas_msg.header.security_header_type = INTEGRITY_PROTECTED_AND_CIPHERED;
|
||||
nas_msg.header.sequence_number = 2;
|
||||
nas_msg.header.sequence_number = nas->security.nas_count_ul & 0xff;
|
||||
|
||||
size += 7;
|
||||
|
||||
@@ -852,16 +991,28 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
|
||||
|
||||
initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len);
|
||||
|
||||
/* ciphering */
|
||||
uint8_t buf[initialNasMsg->length - 7];
|
||||
stream_cipher.context = nas->security_container->ciphering_context;
|
||||
AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n");
|
||||
stream_cipher.count = nas->security.nas_count_ul;
|
||||
stream_cipher.bearer = 1;
|
||||
stream_cipher.direction = 0;
|
||||
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 7);
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (initialNasMsg->length - 7) << 3;
|
||||
stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf);
|
||||
memcpy(stream_cipher.message, buf, initialNasMsg->length - 7);
|
||||
|
||||
/* integrity protection */
|
||||
stream_cipher.context = nas->security_container->integrity_context;
|
||||
stream_cipher.count = nas->security.mm_counter++;
|
||||
stream_cipher.count = nas->security.nas_count_ul++;
|
||||
stream_cipher.bearer = 1;
|
||||
stream_cipher.direction = 0;
|
||||
stream_cipher.message = (unsigned char *)(initialNasMsg->data + 6);
|
||||
/* length in bits */
|
||||
stream_cipher.blength = (initialNasMsg->length - 6) << 3;
|
||||
|
||||
// only for Type of integrity protection algorithm: 128-5G-IA2 (2)
|
||||
stream_compute_integrity(EIA2_128_ALG_ID, &stream_cipher, mac);
|
||||
stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac);
|
||||
|
||||
printf("mac %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]);
|
||||
for(int i = 0; i < 4; i++){
|
||||
@@ -870,30 +1021,41 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t *
|
||||
}
|
||||
|
||||
|
||||
uint8_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) {
|
||||
uint8_t msg_type = 0;
|
||||
uint8_t offset = 0;
|
||||
static uint8_t get_msg_type(uint8_t *pdu_buffer, uint32_t length)
|
||||
{
|
||||
if (pdu_buffer == NULL)
|
||||
goto error;
|
||||
|
||||
if ((pdu_buffer != NULL) && (length > 0)) {
|
||||
if (((nas_msg_header_t *)(pdu_buffer))->choice.security_protected_nas_msg_header_t.security_header_type > 0) {
|
||||
offset += SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH;
|
||||
if (offset < length) {
|
||||
msg_type = ((mm_msg_header_t *)(pdu_buffer + offset))->message_type;
|
||||
/* get security header type */
|
||||
if (length < 2)
|
||||
goto error;
|
||||
|
||||
if (msg_type == FGS_DOWNLINK_NAS_TRANSPORT) {
|
||||
dl_nas_transport_t tmp;
|
||||
memcpy(&tmp, pdu_buffer + offset, sizeof(tmp));
|
||||
msg_type = tmp.sm_nas_msg_header.message_type;
|
||||
}
|
||||
}
|
||||
} else { // plain 5GS NAS message
|
||||
msg_type = ((nas_msg_header_t *)(pdu_buffer))->choice.plain_nas_msg_header.message_type;
|
||||
}
|
||||
} else {
|
||||
LOG_I(NAS, "[UE] Received invalid downlink message\n");
|
||||
int security_header_type = pdu_buffer[1];
|
||||
|
||||
if (security_header_type == 0) {
|
||||
/* plain NAS message */
|
||||
if (length < 3)
|
||||
goto error;
|
||||
return pdu_buffer[2];
|
||||
}
|
||||
|
||||
if (length < 10)
|
||||
goto error;
|
||||
|
||||
int msg_type = pdu_buffer[9];
|
||||
|
||||
if (msg_type == FGS_DOWNLINK_NAS_TRANSPORT) {
|
||||
if (length < 17)
|
||||
goto error;
|
||||
|
||||
msg_type = pdu_buffer[16];
|
||||
}
|
||||
|
||||
return msg_type;
|
||||
|
||||
error:
|
||||
LOG_E(NAS, "[UE] Received invalid downlink message\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_nas_uplink_data_req(instance_t instance, const as_nas_info_t *initial_nas_msg)
|
||||
@@ -998,11 +1160,13 @@ static void get_allowed_nssai(nr_nas_msg_snssai_t nssai[8], const uint8_t *pdu_b
|
||||
case 0x15: // allowed NSSAI
|
||||
length = *pdu_buffer++;
|
||||
parse_allowed_nssai(nssai, pdu_buffer, length);
|
||||
pdu_buffer += length;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_W(NAS, "This NAS IEI is not handled when extracting list of allowed NSSAI\n");
|
||||
pdu_buffer = end;
|
||||
LOG_W(NAS, "This NAS IEI (0x%2.2x) is not handled when extracting list of allowed NSSAI\n", type);
|
||||
length = *pdu_buffer++;
|
||||
pdu_buffer += length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1135,13 +1299,23 @@ void *nas_nrue(void *args_p)
|
||||
NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
|
||||
|
||||
uint8_t *pdu_buffer = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.data;
|
||||
int msg_type = get_msg_type(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
|
||||
int pdu_length = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length;
|
||||
|
||||
nr_ue_nas_t *nas = get_ue_nas_info(0);
|
||||
|
||||
security_state_t security_state = nas_security_rx_process(nas, pdu_buffer, pdu_length);
|
||||
if (security_state != NAS_SECURITY_INTEGRITY_PASSED
|
||||
&& security_state != NAS_SECURITY_NO_SECURITY_CONTEXT) {
|
||||
LOG_E(NAS, "NAS integrity failed, discard incoming message\n");
|
||||
break;
|
||||
}
|
||||
|
||||
int msg_type = get_msg_type(pdu_buffer, pdu_length);
|
||||
|
||||
if (msg_type == REGISTRATION_ACCEPT) {
|
||||
nr_ue_nas_t *nas = get_ue_nas_info(0);
|
||||
handle_registration_accept(instance, nas, pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
|
||||
handle_registration_accept(instance, nas, pdu_buffer, pdu_length);
|
||||
} else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
|
||||
capture_pdu_session_establishment_accept_msg(pdu_buffer, NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length);
|
||||
capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1199,10 +1373,27 @@ void *nas_nrue(void *args_p)
|
||||
NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length,
|
||||
NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data);
|
||||
as_nas_info_t initialNasMsg = {0};
|
||||
nr_ue_nas_t *nas = get_ue_nas_info(0);
|
||||
|
||||
uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data;
|
||||
int msg_type = get_msg_type(pdu_buffer, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length);
|
||||
nr_ue_nas_t *nas = get_ue_nas_info(0);
|
||||
int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length;
|
||||
|
||||
security_state_t security_state = nas_security_rx_process(nas, pdu_buffer, pdu_length);
|
||||
/* special cases accepted without protection */
|
||||
if (security_state == NAS_SECURITY_UNPROTECTED) {
|
||||
int msg_type = get_msg_type(pdu_buffer, pdu_length);
|
||||
/* for the moment, only FGS_DEREGISTRATION_ACCEPT is accepted */
|
||||
if (msg_type == FGS_DEREGISTRATION_ACCEPT)
|
||||
security_state = NAS_SECURITY_INTEGRITY_PASSED;
|
||||
}
|
||||
|
||||
if (security_state != NAS_SECURITY_INTEGRITY_PASSED
|
||||
&& security_state != NAS_SECURITY_NO_SECURITY_CONTEXT) {
|
||||
LOG_E(NAS, "NAS integrity failed, discard incoming message\n");
|
||||
break;
|
||||
}
|
||||
|
||||
int msg_type = get_msg_type(pdu_buffer, pdu_length);
|
||||
|
||||
switch (msg_type) {
|
||||
case FGS_IDENTITY_REQUEST:
|
||||
@@ -1212,14 +1403,13 @@ void *nas_nrue(void *args_p)
|
||||
generateAuthenticationResp(nas, &initialNasMsg, pdu_buffer);
|
||||
break;
|
||||
case FGS_SECURITY_MODE_COMMAND:
|
||||
nas_itti_kgnb_refresh_req(instance, nas->security.kgnb);
|
||||
generateSecurityModeComplete(nas, &initialNasMsg);
|
||||
handle_security_mode_command(instance, nas, &initialNasMsg, pdu_buffer, pdu_length);
|
||||
break;
|
||||
case FGS_DOWNLINK_NAS_TRANSPORT:
|
||||
decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer);
|
||||
break;
|
||||
case REGISTRATION_ACCEPT:
|
||||
handle_registration_accept(instance, nas, pdu_buffer, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length);
|
||||
handle_registration_accept(instance, nas, pdu_buffer, pdu_length);
|
||||
break;
|
||||
case FGS_DEREGISTRATION_ACCEPT:
|
||||
LOG_I(NAS, "received deregistration accept\n");
|
||||
|
||||
@@ -89,11 +89,12 @@ typedef struct {
|
||||
uint8_t kseaf[32];
|
||||
uint8_t kamf[32];
|
||||
uint8_t knas_int[16];
|
||||
uint8_t knas_enc[16];
|
||||
uint8_t res[16];
|
||||
uint8_t rand[16];
|
||||
uint8_t kgnb[32];
|
||||
uint32_t mm_counter;
|
||||
uint32_t sm_counter;
|
||||
uint32_t nas_count_ul;
|
||||
uint32_t nas_count_dl;
|
||||
} ue_sa_security_key_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -88,25 +88,36 @@ static uint64_t MUL64(uint64_t V, uint64_t P, uint64_t c)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* mask32bit.
|
||||
* Input n: an integer in 1-32.
|
||||
* Output : a 32 bit mask.
|
||||
* Prepares a 32 bit mask with required number of 1 bits on the MSB side.
|
||||
*/
|
||||
static uint32_t mask32bit(int n)
|
||||
/* read a big endian uint64_t at given address (potentially not 64-bits aligned)
|
||||
* don't read more than 'available_bytes'
|
||||
* (use 0 if no byte to read)
|
||||
* (note: the compiler will optimize this, no need to do better)
|
||||
*/
|
||||
static inline uint64_t U64(uint8_t *p, int available_bytes)
|
||||
{
|
||||
uint32_t mask=0x0;
|
||||
uint64_t a = 0;
|
||||
uint64_t b = 0;
|
||||
uint64_t c = 0;
|
||||
uint64_t d = 0;
|
||||
uint64_t e = 0;
|
||||
uint64_t f = 0;
|
||||
uint64_t g = 0;
|
||||
uint64_t h = 0;
|
||||
switch (available_bytes) {
|
||||
case 8: h = p[7]; /* falltrough */
|
||||
case 7: g = p[6]; /* falltrough */
|
||||
case 6: f = p[5]; /* falltrough */
|
||||
case 5: e = p[4]; /* falltrough */
|
||||
case 4: d = p[3]; /* falltrough */
|
||||
case 3: c = p[2]; /* falltrough */
|
||||
case 2: b = p[1]; /* falltrough */
|
||||
case 1: a = p[0];
|
||||
}
|
||||
|
||||
if ( n%32 == 0 )
|
||||
return 0xffffffff;
|
||||
|
||||
while (n--)
|
||||
mask = (mask>>1) ^ 0x80000000;
|
||||
|
||||
return mask;
|
||||
return (a << (32+24)) | (b << (32+16)) | (c << (32+8)) | (d << 32)
|
||||
| (e << 24) | (f << 16) | (g << 8) | h;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Create integrity cmac t for a given message.
|
||||
* @param[in] stream_cipher Structure containing various variables to setup encoding
|
||||
@@ -125,11 +136,8 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o
|
||||
uint64_t c;
|
||||
uint64_t M_D_2;
|
||||
int rem_bits;
|
||||
uint32_t mask = 0;
|
||||
uint32_t *message;
|
||||
uint8_t *key = (uint8_t *)stream_cipher->context;
|
||||
|
||||
message = (uint32_t*)stream_cipher->message; /* To operate 32 bit message internally. */
|
||||
/* Load the Integrity Key for SNOW3G initialization as in section 4.4. */
|
||||
memcpy(K+3,key+0,4); /*K[3] = key[0]; we assume
|
||||
K[3]=key[0]||key[1]||...||key[31] , with key[0] the
|
||||
@@ -181,11 +189,14 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o
|
||||
EVAL = 0;
|
||||
c = 0x1b;
|
||||
|
||||
AssertFatal(stream_cipher->blength % 8 == 0, "unsupported buffer length\n");
|
||||
|
||||
uint8_t *message = stream_cipher->message;
|
||||
|
||||
/* for 0 <= i <= D-3 */
|
||||
for (i=0; i<D-2; i++) {
|
||||
V = EVAL ^ ( (uint64_t)hton_int32(message[2*i]) << 32 | (uint64_t)hton_int32(message[2*i+1]) );
|
||||
V = EVAL ^ U64(&message[4 * 2*i], 8);
|
||||
EVAL = MUL64(V,P,c);
|
||||
//printf ("Mi: %16X %16X\tEVAL: %16lX\n",hton_int32(message[2*i]),hton_int32(message[2*i+1]), EVAL);
|
||||
}
|
||||
|
||||
/* for D-2 */
|
||||
@@ -194,14 +205,7 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o
|
||||
if (rem_bits == 0)
|
||||
rem_bits = 64;
|
||||
|
||||
mask = mask32bit(rem_bits%32);
|
||||
|
||||
if (rem_bits > 32) {
|
||||
M_D_2 = ( (uint64_t) hton_int32(message[2*(D-2)]) << 32 ) |
|
||||
(uint64_t) (hton_int32(message[2*(D-2)+1]) & mask);
|
||||
} else {
|
||||
M_D_2 = ( (uint64_t) hton_int32(message[2*(D-2)]) & mask) << 32 ;
|
||||
}
|
||||
M_D_2 = U64(&message[4 * (2*(D-2))], rem_bits/8);
|
||||
|
||||
V = EVAL ^ M_D_2;
|
||||
EVAL = MUL64(V,P,c);
|
||||
|
||||
@@ -195,6 +195,8 @@ typedef struct split7_config {
|
||||
struct {
|
||||
symbol_direction_t sym_dir[14];
|
||||
} slot_dirs[160];
|
||||
/*! this is the exponent in 2^X for the FFT size */
|
||||
uint16_t fftSize;
|
||||
} split7_config_t;
|
||||
|
||||
/*! \brief RF frontend parameters set by application */
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
# we need at least gcc-11 to build xran, so let's enforce it here
|
||||
# (because xran might not check it, and we have control here)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11.0
|
||||
OR CMAKE_C_COMPILER_VERSION VERSION_LESS 11.0)
|
||||
message(FATAL_ERROR "you need to have at least gcc/g++-11 to use 7.2 FHI through xran")
|
||||
endif()
|
||||
|
||||
# use env var PKG_CONFIG_PATH to override paths to libdpdk.pc
|
||||
pkg_check_modules(dpdk REQUIRED libdpdk)
|
||||
pkg_check_modules(numa REQUIRED numa)
|
||||
|
||||
find_package(xran 5.1.2 EXACT REQUIRED) # E release -> 5
|
||||
find_package(xran 5.1.3 EXACT REQUIRED) # E release -> 5
|
||||
|
||||
# Ignore xran-specific warning: we don't care/can't change the following warning, so suppress
|
||||
# alignment 1 of 'struct XYZ' is less than 2
|
||||
|
||||
@@ -729,7 +729,7 @@ static bool set_fh_frame_config(const openair0_config_t *oai0, struct xran_frame
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_fh_ru_config(const paramdef_t *rup, int nru, struct xran_ru_config *ru_config)
|
||||
static bool set_fh_ru_config(const paramdef_t *rup, uint16_t fftSize, int nru, struct xran_ru_config *ru_config)
|
||||
{
|
||||
ru_config->xranTech = XRAN_RAN_5GNR;
|
||||
ru_config->xranCat = XRAN_CATEGORY_A;
|
||||
@@ -740,7 +740,8 @@ static bool set_fh_ru_config(const paramdef_t *rup, int nru, struct xran_ru_conf
|
||||
ru_config->iqWidth_PRACH = *gpd(rup, nru, ORAN_RU_CONFIG_IQWIDTH_PRACH)->uptr;
|
||||
AssertFatal(ru_config->iqWidth_PRACH <= 16, "IQ Width for PRACH cannot be > 16!\n");
|
||||
ru_config->compMeth_PRACH = ru_config->iqWidth_PRACH < 16 ? XRAN_COMPMETHOD_BLKFLOAT : XRAN_COMPMETHOD_NONE;
|
||||
ru_config->fftSize = *gpd(rup, nru, ORAN_RU_CONFIG_FFT_SIZE)->uptr;
|
||||
AssertFatal(fftSize > 0, "FFT size cannot be 0\n");
|
||||
ru_config->fftSize = fftSize;
|
||||
ru_config->byteOrder = XRAN_NE_BE_BYTE_ORDER;
|
||||
ru_config->iqOrder = XRAN_I_Q_ORDER;
|
||||
ru_config->xran_max_frame = 0;
|
||||
@@ -779,6 +780,7 @@ bool set_fh_config(int ru_idx, int num_rus, const openair0_config_t *oai0, struc
|
||||
DevAssert(oai0->rx_freq[0] == oai0->rx_freq[i]);
|
||||
DevAssert(oai0->nr_band > 0);
|
||||
DevAssert(oai0->nr_scs_for_raster > 0);
|
||||
AssertFatal(oai0->threequarter_fs == 0, "cannot use three-quarter sampling with O-RAN 7.2 split\n");
|
||||
|
||||
// we simply assume that the loading process provides function to_nrarfcn()
|
||||
// to calculate the ARFCN numbers from frequency. That is not clean, but the
|
||||
@@ -869,7 +871,7 @@ bool set_fh_config(int ru_idx, int num_rus, const openair0_config_t *oai0, struc
|
||||
return false;
|
||||
if (!set_fh_frame_config(oai0, &fh_config->frame_conf))
|
||||
return false;
|
||||
if (!set_fh_ru_config(rup, nru, &fh_config->ru_conf))
|
||||
if (!set_fh_ru_config(rup, oai0->split7.fftSize, nru, &fh_config->ru_conf))
|
||||
return false;
|
||||
|
||||
fh_config->bbdev_enc = NULL;
|
||||
|
||||
@@ -123,6 +123,14 @@ static struct xran_prb_map get_xran_prb_map_ul(const struct xran_fh_config *f)
|
||||
return prbmap;
|
||||
}
|
||||
|
||||
static uint32_t next_power_2(uint32_t num)
|
||||
{
|
||||
uint32_t power = 2;
|
||||
while (power < num)
|
||||
power <<= 1;
|
||||
return power;
|
||||
}
|
||||
|
||||
static uint32_t oran_allocate_uplane_buffers(
|
||||
void *instHandle,
|
||||
struct xran_buffer_list list[XRAN_MAX_ANTENNA_NR][XRAN_N_FE_BUF_LEN],
|
||||
@@ -132,7 +140,10 @@ static uint32_t oran_allocate_uplane_buffers(
|
||||
{
|
||||
xran_status_t status;
|
||||
uint32_t pool;
|
||||
uint32_t numBufs = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT;
|
||||
// we need at least XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT
|
||||
// buffers, but xran_bm_init() uses rte_pktmbuf_pool_create() which
|
||||
// recommends to use a power of two for the buffers
|
||||
uint32_t numBufs = next_power_2(XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT);
|
||||
status = xran_bm_init(instHandle, &pool, numBufs, bufSize);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
|
||||
printf("xran_bm_init() hInstance %p poolIdx %u elements %u size %u\n", instHandle, pool, numBufs, bufSize);
|
||||
@@ -211,14 +222,14 @@ static void oran_allocate_cplane_buffers(void *instHandle,
|
||||
{
|
||||
xran_status_t status;
|
||||
uint32_t poolSec;
|
||||
uint32_t numBufsSec = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT * sect * XRAN_MAX_FRAGMENT;
|
||||
uint32_t numBufsSec = next_power_2(XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT * sect * XRAN_MAX_FRAGMENT);
|
||||
uint32_t bufSizeSec = sizeof(struct xran_section_desc);
|
||||
status = xran_bm_init(instHandle, &poolSec, numBufsSec, bufSizeSec);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
|
||||
printf("xran_bm_init() hInstance %p poolIdx %u elements %u size %u\n", instHandle, poolSec, numBufsSec, bufSizeSec);
|
||||
|
||||
uint32_t poolPrb;
|
||||
uint32_t numBufsPrb = XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT;
|
||||
uint32_t numBufsPrb = next_power_2(XRAN_N_FE_BUF_LEN * ant * XRAN_NUM_OF_SYMBOL_PER_SLOT);
|
||||
uint32_t bufSizePrb = size_of_prb_map;
|
||||
status = xran_bm_init(instHandle, &poolPrb, numBufsPrb, bufSizePrb);
|
||||
AssertFatal(XRAN_STATUS_SUCCESS == status, "Failed at xran_bm_init(), status %d\n", status);
|
||||
|
||||
@@ -91,13 +91,11 @@
|
||||
|
||||
#define ORAN_RU_CONFIG_IQWIDTH "iq_width"
|
||||
#define ORAN_RU_CONFIG_IQWIDTH_PRACH "iq_width_prach"
|
||||
#define ORAN_RU_CONFIG_FFT_SIZE "fft_size"
|
||||
|
||||
// clang-format off
|
||||
#define ORAN_RU_DESC {\
|
||||
{ORAN_RU_CONFIG_IQWIDTH, "sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \
|
||||
{ORAN_RU_CONFIG_IQWIDTH_PRACH, "PRACH sample IQ width (16=uncompressed)\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=16, TYPE_UINT8, 0}, \
|
||||
{ORAN_RU_CONFIG_FFT_SIZE, "Size of FFT at RU\n", PARAMFLAG_MANDATORY, .u8ptr=NULL, .defuintval=12, TYPE_UINT8, 0}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -34,6 +34,11 @@
|
||||
#include "common/utils/threadPool/thread-pool.h"
|
||||
#include "oaioran.h"
|
||||
|
||||
// include the following file for VERSIONX, version of xran lib, to print it during
|
||||
// startup. Only relevant for printing, if it ever makes problem, remove this
|
||||
// line and the use of VERSIONX further below. It is relative to phy/fhi_lib/lib/api
|
||||
#include "../../app/src/common.h"
|
||||
|
||||
typedef struct {
|
||||
eth_state_t e;
|
||||
rru_config_msg_type_t last_msg;
|
||||
@@ -309,7 +314,7 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
|
||||
|
||||
eth->last_msg = (rru_config_msg_type_t)-1;
|
||||
|
||||
printf("ORAN: %s\n", __FUNCTION__);
|
||||
LOG_I(HW, "Initializing O-RAN 7.2 FH interface through xran library (compiled against headers of %s)\n", VERSIONX);
|
||||
|
||||
initNotifiedFIFO(&oran_sync_fifo);
|
||||
eth->oran_priv = oai_oran_initialize(openair0_cfg);
|
||||
|
||||
@@ -295,7 +295,6 @@ fhi_72 = {
|
||||
ru_config = {
|
||||
iq_width = 9;
|
||||
iq_width_prach = 9;
|
||||
fft_size = 12;
|
||||
};
|
||||
prach_config = {
|
||||
eAxC_offset = 4;
|
||||
|
||||
@@ -288,7 +288,6 @@ fhi_72 = {
|
||||
ru_config = {
|
||||
iq_width = 9;
|
||||
iq_width_prach = 9;
|
||||
fft_size = 12;
|
||||
};
|
||||
prach_config = {
|
||||
eAxC_offset = 4;
|
||||
|
||||
@@ -288,7 +288,6 @@ fhi_72 = {
|
||||
ru_config = {
|
||||
iq_width = 9;
|
||||
iq_width_prach = 9;
|
||||
fft_size = 12;
|
||||
};
|
||||
prach_config = {
|
||||
eAxC_offset = 4;
|
||||
|
||||
@@ -286,7 +286,6 @@ fhi_72 = {
|
||||
ru_config = {
|
||||
iq_width = 9;
|
||||
iq_width_prach = 9;
|
||||
fft_size = 12;
|
||||
};
|
||||
prach_config = {
|
||||
eAxC_offset = 4;
|
||||
|
||||
Reference in New Issue
Block a user