diff --git a/.gitignore b/.gitignore index c4a4022fba..d1c6979e76 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ cmake_targets/log/ cmake_targets/*/build/ cmake_targets/ran_build/ -cmake_targets/nas_sim_tools/build/ log/ lte_build_oai/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 38168ae460..57d165ea05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,8 +19,6 @@ # * contact@openairinterface.org # */ -# Author: laurent THOMAS, Lionel GAUTHIER - cmake_minimum_required (VERSION 3.16) project (OpenAirInterface LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 17) @@ -36,6 +34,8 @@ if(NOT DEFINED ENV{CPM_SOURCE_CACHE}) endif() include("cmake_targets/CPM.cmake") +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_targets/tools/MODULES" "${CMAKE_MODULE_PATH}") + ############################## ### CCache: reduce compilation time ############################## @@ -168,12 +168,9 @@ endif() if (NOT CROSS_COMPILE) set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=native") else () - set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8-a") + set(C_FLAGS_PROCESSOR "${C_FLAGS_PROCESSOR} -march=armv8.2-a") endif() -# add autotools definitions that were maybe used! -add_definitions("-DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_FCNTL_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_STRERROR=1 -DHAVE_SOCKET=1 -DHAVE_MEMSET=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_STDLIB_H=1 -DHAVE_MALLOC=1 -DHAVE_LIBSCTP") - # we need -rdynamic to incorporate all symbols in shared objects, see man page set(commonOpts "-pipe -fPIC -Wall -fno-strict-aliasing -rdynamic") # GNU C/C++ Compiler might throw many warnings without packed-bitfield-compat, see man page @@ -192,26 +189,26 @@ set(CMAKE_CXX_FLAGS "${C_FLAGS_PROCESSOR} ${commonOpts} -std=c++11 ${CMAKE_CXX_FLAGS}") -add_boolean_option(SANITIZE_ADDRESS False "enable the address sanitizer (ASan)" ON) +add_boolean_option(SANITIZE_ADDRESS OFF "enable the address sanitizer (ASan)" ON) if (SANITIZE_ADDRESS) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-common") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fno-common") endif () -add_boolean_option(SANITIZE_THREAD False "enable the address sanitizer (TSan)" ON) +add_boolean_option(SANITIZE_THREAD OFF "enable the address sanitizer (TSan)" ON) if (SANITIZE_THREAD) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -fno-omit-frame-pointer -fno-common") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer -fno-common") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread") endif() -add_boolean_option(SANITIZE_UNDEFINED False "enable the undefined behavior sanitizer (UBSan)" ON) +add_boolean_option(SANITIZE_UNDEFINED OFF "enable the undefined behavior sanitizer (UBSan)" ON) if (SANITIZE_UNDEFINED) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") endif () -add_boolean_option(SANITIZE_MEMORY False "enable the memory sanitizer (MSan, requires clang, incompatible with ASan/UBSan)" ON) +add_boolean_option(SANITIZE_MEMORY OFF "enable the memory sanitizer (MSan, requires clang, incompatible with ASan/UBSan)" ON) if(SANITIZE_MEMORY) if (SANITIZE_UNDEFINED OR SANITIZE_ADDRESS) message(FATAL_ERROR "memory sanitizer cannot coexist with address sanitizer or undefined behavior sanitizer, please disable either MSan or ASan and UBSan") @@ -276,15 +273,16 @@ endif() # OAI uses this feature to re-use OAI LOG_I(ASN1, ...) # see common/utils/config.h add_boolean_option(TRACE_ASN1C_ENC_DEC OFF "Enable ASN1 encoder/decoder debug traces via OAI logging system" ON) -add_boolean_option(T_TRACER True "Activate the T tracer, a debugging/monitoring framework" ON) -add_boolean_option(ENABLE_LTTNG False "Activate the LTTNG tracer, a debugging/monitoring framework" ON) -add_boolean_option(UE_AUTOTEST_TRACE False "Activate UE autotest specific logs" ON) -add_boolean_option(UE_DEBUG_TRACE False "Activate UE debug trace" ON) -add_boolean_option(UE_TIMING_TRACE False "Activate UE timing trace" ON) +add_boolean_option(T_TRACER ON "Activate the T tracer, a debugging/monitoring framework" ON) +add_boolean_option(ENABLE_LTTNG OFF "Activate the LTTNG tracer, a debugging/monitoring framework" ON) +add_boolean_option(UE_DEBUG_TRACE OFF "Activate UE debug trace" ON) +add_boolean_option(UE_TIMING_TRACE OFF "Activate UE timing trace" ON) add_boolean_option(TRACY_ENABLE OFF "Enable tracy instrumentation" ON) if (TRACY_ENABLE) - CPMAddPackage("gh:wolfpld/tracy#v0.11.1") + # the tracy version here should match the tracy server version + # below is latest release as of this commit + CPMAddPackage("gh:wolfpld/tracy#0.12.2") endif() set (OCP_ITTI ${OPENAIR_DIR}/common/utils/ocp_itti) @@ -336,7 +334,6 @@ target_link_libraries(nr_rrc PUBLIC asn1_nr_rrc asn1_lte_rrc) set(S1AP_DIR ${OPENAIR3_DIR}/S1AP) include_directories ("${S1AP_DIR}") add_library(s1ap - ${S1AP_DIR}/s1ap_common.c ${S1AP_DIR}/s1ap_eNB.c ${S1AP_DIR}/s1ap_eNB_context_management_procedures.c ${S1AP_DIR}/s1ap_eNB_decoder.c @@ -361,6 +358,7 @@ add_library(ngap ${NGAP_DIR}/ngap_gNB.c ${NGAP_DIR}/ngap_common.c ${NGAP_DIR}/ngap_gNB_context_management_procedures.c + ${NGAP_DIR}/ngap_gNB_mobility_management.c ${NGAP_DIR}/ngap_gNB_decoder.c ${NGAP_DIR}/ngap_gNB_encoder.c ${NGAP_DIR}/ngap_gNB_handlers.c @@ -466,9 +464,6 @@ target_include_directories(f1ap PUBLIC F1AP_DIR) target_link_libraries(f1ap PUBLIC asn1_f1ap GTPV1U) target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE f1ap_lib) target_include_directories(f1ap PRIVATE ${F1AP_DIR}/lib) -if(E2_AGENT) - target_compile_definitions(f1ap PRIVATE E2_AGENT) -endif() # LPP ############## @@ -508,34 +503,34 @@ include_directories ("${OPENAIR_DIR}/radio/COMMON") # ???!!! TO BE DOCUMENTED OPTIONS !!!??? ############################################################## -add_boolean_option(UE_EXPANSION False "enable UE_EXPANSION with max 256 UE" ON) -add_boolean_option(PHY_TX_THREAD False "enable UE_EXPANSION with max 256 UE" ON) -add_boolean_option(PRE_SCD_THREAD False "enable UE_EXPANSION with max 256 UE" ON) +add_boolean_option(UE_EXPANSION OFF "enable UE_EXPANSION with max 256 UE" ON) +add_boolean_option(PHY_TX_THREAD OFF "enable UE_EXPANSION with max 256 UE" ON) +add_boolean_option(PRE_SCD_THREAD OFF "enable UE_EXPANSION with max 256 UE" ON) ########################## # SCHEDULING/REAL-TIME/PERF options ########################## -add_boolean_option(ENABLE_USE_CPU_EXECUTION_TIME False "Add data in vcd traces: disable it if perf issues" ON) -add_boolean_option(ENABLE_VCD False "always true now, time measurements of proc calls and var displays" ON) -add_boolean_option(ENABLE_VCD_FIFO False "time measurements of proc calls and var displays sent to FIFO (one more thread)" ON) +add_boolean_option(ENABLE_USE_CPU_EXECUTION_TIME OFF "Add data in vcd traces: disable it if perf issues" ON) +add_boolean_option(ENABLE_VCD OFF "always true now, time measurements of proc calls and var displays" ON) +add_boolean_option(ENABLE_VCD_FIFO OFF "time measurements of proc calls and var displays sent to FIFO (one more thread)" ON) ########################## # PHY options ########################## -add_integer_option(MAX_NUM_CCs 1 "Carrier component data arrays size (oai doesn't support carrier aggreagtion for now)" ON) -add_boolean_option(SMBV False "Rohde&Schwarz SMBV100A vector signal generator" ON) -add_boolean_option(DEBUG_PHY False "Enable PHY layer debugging options" ON) -add_boolean_option(DEBUG_PHY_PROC False "Enable debugging of PHY layer procedures" ON) +add_integer_option(MAX_NUM_CCs 1 "Carrier component data arrays size (oai doesn't support carrier aggregation for now)" ON) +add_boolean_option(SMBV OFF "Rohde&Schwarz SMBV100A vector signal generator" ON) +add_boolean_option(DEBUG_PHY OFF "Enable PHY layer debugging options" ON) +add_boolean_option(DEBUG_PHY_PROC OFF "Enable debugging of PHY layer procedures" ON) ########################## # NAS LAYER OPTIONS ########################## -add_boolean_option(NAS_BUILT_IN_UE True "UE NAS layer present in this executable" ON) +add_boolean_option(NAS_BUILT_IN_UE ON "UE NAS layer present in this executable" ON) ########################## # RRC LAYER OPTIONS ########################## -add_boolean_option(RRC_DEFAULT_RAB_IS_AM True "set the LTE RLC mode to AM for the default bearer, otherwise it is UM." ON) +add_boolean_option(RRC_DEFAULT_RAB_IS_AM ON "set the LTE RLC mode to AM for the default bearer, otherwise it is UM." ON) # add the binary tree to the search path for include files # We will find common/oai_version.h after generation in target directory @@ -546,7 +541,6 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories("${OPENAIR_DIR}/executables") include_directories("${OPENAIR2_DIR}/COMMON") include_directories("${OPENAIR2_DIR}/UTIL") -include_directories("${OPENAIR2_DIR}/UTIL/LOG") include_directories("${OPENAIR3_DIR}/COMMON") include_directories("${OPENAIR3_DIR}/UTILS") include_directories("${NFAPI_DIR}/nfapi/public_inc") @@ -587,12 +581,7 @@ include_directories("${OPENAIR3_DIR}/ocp-gtpu") include_directories("${OPENAIR3_DIR}/M3AP") include_directories("${OPENAIR3_DIR}/MME_APP") include_directories("${OPENAIR_DIR}/radio/COMMON") -include_directories("${OPENAIR2_DIR}/UTIL/OSA") -include_directories("${OPENAIR2_DIR}/UTIL/MEM") -include_directories("${OPENAIR2_DIR}/UTIL/LISTS") -include_directories("${OPENAIR2_DIR}/UTIL/FIFO") include_directories("${OPENAIR2_DIR}/UTIL/MATH") -include_directories("${OPENAIR2_DIR}/UTIL/TIMER") include_directories("${OPENAIR2_DIR}/UTIL/OTG") include_directories("${OPENAIR2_DIR}/UTIL/OPT") include_directories("${OPENAIR_DIR}") @@ -602,7 +591,7 @@ include_directories("${OPENAIR_DIR}") ############### # include T directory even if the T is off because T macros are in the code -# no matter what. Note: sone files are generated, so we have both source and +# no matter what. Note: some files are generated, so we have both source and # binary directories include_directories(${CMAKE_CURRENT_SOURCE_DIR}/common/utils/T ${CMAKE_CURRENT_BINARY_DIR}/common/utils/T) @@ -620,11 +609,6 @@ add_library(UTIL ${OPENAIR_DIR}/common/utils/LOG/vcd_signal_dumper.c ${OPENAIR2_DIR}/UTIL/OPT/probe.c ) -if (ENABLE_LTTNG) - find_package(LTTngUST 2.3.8 EXACT REQUIRED) -else() - message(STATUS "LTTNG support disabled") -endif() pkg_check_modules(cap libcap) if (cap_FOUND) @@ -715,6 +699,11 @@ add_library(NFAPI_LIB ${NFAPI_SRC}) target_link_libraries(NFAPI_LIB PUBLIC nfapi_common) target_link_libraries(NFAPI_LIB PUBLIC nr_fapi_p5 nr_fapi_p7) +if(OAI_WLS) + target_compile_definitions(NFAPI_LIB PRIVATE ENABLE_WLS) +else() + target_compile_definitions(NFAPI_LIB PRIVATE ENABLE_SOCKET) +endif() include_directories(${NFAPI_DIR}/nfapi/public_inc) include_directories(${NFAPI_DIR}/nfapi/inc) @@ -728,6 +717,9 @@ add_library(NFAPI_PNF_LIB ${NFAPI_PNF_SRC}) target_link_libraries(NFAPI_PNF_LIB PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) target_link_libraries(NFAPI_PNF_LIB PUBLIC nr_fapi_p7) +if(OAI_WLS) + target_compile_definitions(NFAPI_PNF_LIB PRIVATE ENABLE_WLS) +endif() include_directories(${NFAPI_DIR}/pnf/public_inc) include_directories(${NFAPI_DIR}/pnf/inc) @@ -746,6 +738,9 @@ endif() include_directories(${NFAPI_DIR}/vnf/public_inc) include_directories(${NFAPI_DIR}/vnf/inc) +if(OAI_WLS) + target_compile_definitions(NFAPI_VNF_LIB PRIVATE ENABLE_WLS) +endif() # nFAPI user defined code ############################# set(NFAPI_USER_SRC @@ -755,11 +750,15 @@ set(NFAPI_USER_SRC ${NFAPI_USER_DIR}/gnb_ind_vars.c ) add_library(NFAPI_USER_LIB ${NFAPI_USER_SRC}) +if(OAI_WLS) + target_compile_definitions(NFAPI_USER_LIB PRIVATE ENABLE_WLS) +elseif (OAI_AERIAL) + target_compile_definitions(NFAPI_USER_LIB PRIVATE ENABLE_AERIAL) +else() + target_compile_definitions(NFAPI_USER_LIB PRIVATE ENABLE_SOCKET) +endif() target_link_libraries(NFAPI_USER_LIB PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs UTIL) target_link_libraries(NFAPI_USER_LIB PRIVATE nr_fapi_p7) -if(OAI_AERIAL) - target_compile_definitions(NFAPI_USER_LIB PRIVATE ENABLE_AERIAL) -endif() include_directories(${NFAPI_USER_DIR}) # Layer 1 @@ -833,6 +832,7 @@ set(PHY_SRC_COMMON ${OPENAIR1_DIR}/PHY/TOOLS/sqrt.c ${OPENAIR1_DIR}/PHY/TOOLS/get_sin_cos.c ${OPENAIR1_DIR}/PHY/TOOLS/oai_arith_operations.c + ${OPENAIR1_DIR}/PHY/log_tools.c ) set(PHY_SRC @@ -923,9 +923,9 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_tbs_tools.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach_common.c ${OPENAIR1_DIR}/PHY/nr_phy_common/src/nr_phy_common_csirs.c + ${OPENAIR1_DIR}/PHY/nr_phy_common/src/nr_phy_common_srs.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_scrambling.c ${OPENAIR1_DIR}/PHY/NR_REFSIG/refsig.c - ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c ) set(PHY_NR_SRC @@ -1047,7 +1047,7 @@ add_library(PHY_NR_COMMON ${PHY_NR_SRC_COMMON}) target_link_libraries(PHY_NR_COMMON PUBLIC UTIL) add_library(PHY_NR ${PHY_NR_SRC}) -target_link_libraries(PHY_NR nr_phy_common nr_common) +target_link_libraries(PHY_NR nr_phy_common nr_common nr_fapi_p5) add_library(PHY_NR_NO_AVX_256 ${PHY_NR_SRC}) target_link_libraries(PHY_NR_NO_AVX_256 nr_phy_common nr_common) @@ -1148,6 +1148,7 @@ set(L2_NR_SRC ${NR_RRC_DIR}/rrc_gNB.c ${NR_RRC_DIR}/mac_rrc_dl_direct.c ${NR_RRC_DIR}/mac_rrc_dl_f1ap.c + ${NR_RRC_DIR}/rrc_gNB_asn1.c ${NR_RRC_DIR}/rrc_gNB_nsa.c ${NR_RRC_DIR}/rrc_gNB_UE_context.c ${NR_RRC_DIR}/rrc_gNB_NGAP.c @@ -1183,7 +1184,6 @@ set(NR_L2_SRC_UE ${NR_UE_RRC_DIR}/L2_interface_ue.c ${NR_UE_RRC_DIR}/main_ue.c ${NR_UE_RRC_DIR}/rrc_UE.c - ${NR_UE_RRC_DIR}/rrc_nsa.c ${NR_UE_RRC_DIR}/rrc_timers_and_constants.c ${NR_UE_RRC_DIR}/rrc_sl_preconfig.c ) @@ -1298,12 +1298,6 @@ add_library(L2 target_link_libraries(L2 PRIVATE x2ap s1ap lte_rrc m2ap) target_link_libraries(L2 PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) -if(E2_AGENT) - target_link_libraries(L2 PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup) - target_compile_definitions(L2 PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT) -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 PUBLIC nr_ue_power_procedures nr_ue_ra_procedures) @@ -1330,10 +1324,6 @@ target_link_libraries(L2_NR PRIVATE f1ap x2ap s1ap ngap nr_rrc e1ap nr_rlc nr_co if(OAI_AERIAL) target_compile_definitions(L2_NR PRIVATE ENABLE_AERIAL) endif() -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) -endif() add_library(L2_LTE_NR # temporary solution until 4G/5G code completely untangled (as evidenced by deletion of the following file) @@ -1378,9 +1368,10 @@ include_directories("${OPENAIR1_DIR}/SCHED_NR_UE") add_library (GTPV1U ${RRC_DIR}/rrc_eNB_GTPV1U.c ${OPENAIR3_DIR}/ocp-gtpu/gtp_itf.cpp + ${OPENAIR3_DIR}/ocp-gtpu/gtpu_extensions.c ) target_link_libraries(GTPV1U PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) -target_link_libraries(GTPV1U PRIVATE SIMU) +target_link_libraries(GTPV1U PRIVATE SIMU ds) include_directories(${OPENAIR3_DIR}/ocp-gtp) set (MME_APP_SRC @@ -1391,12 +1382,14 @@ add_library(MME_APP ${MME_APP_SRC}) target_link_libraries(MME_APP PRIVATE m2ap m3ap) target_link_libraries(MME_APP PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +find_package(sctp REQUIRED) set(SCTP_SRC ${OPENAIR3_DIR}/SCTP/sctp_common.c ${OPENAIR3_DIR}/SCTP/sctp_eNB_task.c ${OPENAIR3_DIR}/SCTP/sctp_eNB_itti_messaging.c ) add_library(SCTP_CLIENT ${SCTP_SRC}) +target_link_libraries(SCTP_CLIENT PRIVATE sctp::sctp) target_link_libraries(SCTP_CLIENT PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) set(NAS_SRC ${OPENAIR3_DIR}/NAS/) @@ -1660,13 +1653,6 @@ include_directories(${NAS_SRC}UE/EMM/SAP) include_directories(${NAS_SRC}UE/ESM) include_directories(${NAS_SRC}UE/ESM/SAP) -# nbiot -add_definitions("-DNUMBER_OF_UE_MAX_NB_IoT=16") -set (NBIOT_SOURCES - ${OPENAIR2_DIR}/ENB_APP/NB_IoT_config.c - ) -add_library(NB_IoT MODULE ${NBIOT_SOURCES} ) - # Simulation library ########################## set (SIMUSRC @@ -1692,10 +1678,8 @@ include_directories("${NFAPI_DIR}/nfapi/inc") include_directories("${NFAPI_DIR}/sim_common/inc") include_directories("${NFAPI_DIR}/pnf_sim/inc") -add_library(oai_iqplayer MODULE - ${OPENAIR_DIR}/radio/iqplayer/iqplayer_lib.c - ) -set(CMAKE_MODULE_PATH "${OPENAIR_DIR}/cmake_targets/tools/MODULES" "${CMAKE_MODULE_PATH}") +add_library(oai_iqplayer MODULE ${OPENAIR_DIR}/radio/iqplayer/iqplayer_lib.c) +target_link_libraries(oai_iqplayer PRIVATE log_headers) ################################# # add executables for operation @@ -1705,10 +1689,6 @@ add_library(minimal_lib ) target_link_libraries(minimal_lib PUBLIC pthread dl ${T_LIB} LOG) -add_executable(nfapi_test - ${OPENAIR_DIR}/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c - ) - add_executable(measurement_display ${OPENAIR_DIR}/common/utils/threadPool/measurement_display.c) target_link_libraries (measurement_display minimal_lib) @@ -1742,12 +1722,13 @@ target_link_libraries(lte-softmodem PRIVATE ${NAS_UE_LIB} ITTI SIMU shlib_loader -Wl,--end-group z dl) -target_link_libraries(lte-softmodem PRIVATE pthread m CONFIG_LIB rt sctp) +target_link_libraries(lte-softmodem PRIVATE pthread m CONFIG_LIB rt) target_link_libraries(lte-softmodem PRIVATE ${T_LIB}) target_link_libraries(lte-softmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) target_link_libraries(lte-softmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES} ${lapack_LIBRARIES}) if(E2_AGENT) + target_link_libraries(lte-softmodem PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup) target_compile_definitions(lte-softmodem PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT) endif() @@ -1798,7 +1779,7 @@ target_link_libraries(lte-uesoftmodem PRIVATE ${NAS_UE_LIB} ITTI shlib_loader -Wl,--end-group z dl) -target_link_libraries(lte-uesoftmodem PRIVATE pthread m CONFIG_LIB rt sctp) +target_link_libraries(lte-uesoftmodem PRIVATE pthread m CONFIG_LIB rt) target_link_libraries(lte-uesoftmodem PRIVATE ${T_LIB}) target_link_libraries(lte-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) target_link_libraries(lte-uesoftmodem PRIVATE ${blas_LIBRARIES} ${cblas_LIBRARIES} ${lapacke_LIBRARIES} ${lapack_LIBRARIES}) @@ -1835,16 +1816,23 @@ target_link_libraries(nr-softmodem PRIVATE time_management -Wl,--end-group z dl) -target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt sctp) +target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt) target_link_libraries(nr-softmodem PRIVATE ${T_LIB}) target_link_libraries(nr-softmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) target_link_libraries(nr-softmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +add_boolean_option(OAI_WLS OFF "Activate OAI's WLS driver" OFF) +if (OAI_WLS) + target_link_libraries(nr-softmodem PUBLIC wls_integration_lib) +else() + target_link_libraries(nr-softmodem PUBLIC nfapi_socket_lib) +endif() add_boolean_option(OAI_AERIAL OFF "Activate OAI's AERIAL driver" OFF) if (OAI_AERIAL) target_compile_definitions(nr-softmodem PUBLIC ENABLE_AERIAL) target_link_libraries(nr-softmodem PUBLIC aerial_lib) endif() if(E2_AGENT) + target_link_libraries(nr-softmodem PUBLIC e2_agent e2_agent_arg e2_ran_func_du_cucp_cuup) target_compile_definitions(nr-softmodem PRIVATE ${E2AP_VERSION} ${KPM_VERSION} E2_AGENT) endif() @@ -1866,7 +1854,8 @@ target_link_libraries(nr-cuup PRIVATE CONFIG_LIB ITTI SCTP_CLIENT GTPV1U e1ap f1ap time_management - z sctp dl pthread shlib_loader ${T_LIB}) + alg + z dl pthread shlib_loader ${T_LIB}) target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) if(E2_AGENT) target_link_libraries(nr-cuup PRIVATE e2_agent e2_agent_arg e2_ran_func_cuup) @@ -1918,14 +1907,14 @@ target_link_libraries(nr-uesoftmodem PRIVATE ##################################### #special case for dlim TM4, which uses its own version of phy_scope code -add_executable(dlsim_tm4 - ${OPENAIR1_DIR}/SIMULATION/LTE_PHY/dlsim_tm4.c - ${OPENAIR1_DIR}/PHY/TOOLS/lte_phy_scope_tm4.c - ) -target_link_libraries (dlsim_tm4 - -Wl,--start-group SIMU UTIL SCHED_LIB SCHED_RU_LIB PHY ITTI -Wl,--end-group - pthread m rt CONFIG_LIB ${T_LIB} - ) +#add_executable(dlsim_tm4 +# ${OPENAIR1_DIR}/SIMULATION/LTE_PHY/dlsim_tm4.c +# ${OPENAIR1_DIR}/PHY/TOOLS/lte_phy_scope_tm4.c +# ) +#target_link_libraries (dlsim_tm4 +# -Wl,--start-group SIMU UTIL SCHED_LIB SCHED_RU_LIB PHY ITTI -Wl,--end-group +# pthread m rt CONFIG_LIB ${T_LIB} +# ) add_executable(rftest ${OPENAIR_DIR}/openair1/PHY/TOOLS/calibration_test.c @@ -1987,7 +1976,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 ${OPENAIR_DIR}/executables/softmodem-common.c - ${NR_UE_RRC_DIR}/rrc_nsa.c ${NFAPI_USER_DIR}/nfapi.c ${NFAPI_USER_DIR}/gnb_ind_vars.c ${PHY_INTERFACE_DIR}/queue_t.c @@ -2008,7 +1996,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 ${OPENAIR_DIR}/executables/softmodem-common.c - ${NR_UE_RRC_DIR}/rrc_nsa.c ${NFAPI_USER_DIR}/nfapi.c ${NFAPI_USER_DIR}/gnb_ind_vars.c ${PHY_INTERFACE_DIR}/queue_t.c @@ -2038,7 +2025,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 ${OPENAIR_DIR}/executables/softmodem-common.c - ${NR_UE_RRC_DIR}/rrc_nsa.c ${NFAPI_USER_DIR}/nfapi.c ${NFAPI_USER_DIR}/gnb_ind_vars.c ${PHY_INTERFACE_DIR}/queue_t.c @@ -2050,7 +2036,9 @@ target_link_libraries(nr_ulsim PRIVATE ) target_link_libraries(nr_ulsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) -foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim) +# these simulators do not compile: +# dlsim_tm7 pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim +foreach(myExe dlsim ulsim) add_executable(${myExe} ${OPENAIR1_DIR}/SIMULATION/LTE_PHY/${myExe}.c @@ -2070,22 +2058,23 @@ endforeach(myExe) #unitary tests for Core NEtwork pieces ################################# -foreach(myExe s1ap - secu_knas_encrypt_eia1 - secu_kenb - aes128_ctr - secu_knas_encrypt_eea2 - secu_knas secu_knas_encrypt_eea1 - kdf - aes128_cmac_encrypt - secu_knas_encrypt_eia2) - add_executable(test_${myExe} - ${OPENAIR3_DIR}/TEST/test_${myExe}.c - ) - target_link_libraries (test_${myExe} - -Wl,--start-group SECURITY UTIL -Wl,--end-group m rt CONFIG_LIB - ) -endforeach(myExe) +#foreach(myExe +# s1ap +# secu_knas_encrypt_eia1 +# secu_kenb +# aes128_ctr +# secu_knas_encrypt_eea2 +# secu_knas secu_knas_encrypt_eea1 +# kdf +# aes128_cmac_encrypt +# secu_knas_encrypt_eia2) +# add_executable(test_${myExe} +# ${OPENAIR3_DIR}/TEST/test_${myExe}.c +# ) +# target_link_libraries (test_${myExe} +# -Wl,--start-group SECURITY UTIL -Wl,--end-group m rt CONFIG_LIB +# ) +#endforeach(myExe) #ensure that the T header files are generated before targets depending on them if (${T_TRACER}) @@ -2095,17 +2084,17 @@ if (${T_TRACER}) nr-uesoftmodem dlsim dlsim_tm4 dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim prachsim syncsim nr_ulsim nr_dlsim nr_dlschsim nr_pbchsim nr_pucchsim - nr_ulschsim ldpctest polartest smallblocktest cu_test du_test + nr_ulschsim ldpctest polartest smallblocktest #all "add_library" definitions ITTI lte_rrc nr_rrc s1ap x2ap m2ap m3ap f1ap - params_libconfig oai_usrpdevif oai_bladerfdevif oai_lmssdrdevif oai_iqplayer - oai_eth_transpro oai_mobipass HASHTABLE UTIL OMG_SUMO - SECURITY SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB default_sched remote_sched RAL + params_libconfig + oai_eth_transpro HASHTABLE UTIL + SECURITY SCHED_LIB SCHED_NR_LIB SCHED_RU_LIB SCHED_UE_LIB SCHED_NR_UE_LIB NFAPI_LIB NFAPI_PNF_LIB NFAPI_VNF_LIB NFAPI_USER_LIB MISC_NFAPI_LTE_LIB MISC_NFAPI_NR_LIB PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE MAC_NR_COMMON MAC_UE_NR ngap - CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB + GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE SIMU dfts config_internals nr_common crc_byte) if (TARGET ${i}) add_dependencies(${i} generate_T) @@ -2113,8 +2102,6 @@ if (${T_TRACER}) endforeach(i) endif (${T_TRACER}) -include(${OPENAIR1_DIR}/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt) - set(ENABLE_TESTS OFF CACHE STRING "Activate build of tests") set_property(CACHE ENABLE_TESTS PROPERTY TYPE BOOL) set(ENABLE_PHYSIM_TESTS OFF CACHE STRING "Activate build of physim tests") @@ -2160,3 +2147,4 @@ add_subdirectory(openair1) add_subdirectory(openair2) add_subdirectory(openair3) add_subdirectory(radio) +add_subdirectory(tests) diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container index 62ab0266b1..3301c133ec 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Container +++ b/ci-scripts/Jenkinsfile-GitLab-Container @@ -35,6 +35,8 @@ def gitCommitAuthorEmailAddr // list of failing stages def failingStages = "" +OAI_Registry = "gracehopper3-oai.sboai.cs.eurecom.fr" + pipeline { agent { label nodeExecutor @@ -175,6 +177,28 @@ pipeline { } } } + stage ("Ubuntu-Jetson-Image-Builder") { + steps { + script { + triggerSlaveJob ('RAN-Ubuntu-Jetson-Image-Builder', 'Ubuntu-Jetson-Image-Builder') + } + } + post { + always { + script { + // Using a unique variable name for each test stage to avoid overwriting on a global variable + // due to parallel-time concurrency + ubuntuJetsonBuildStatus = finalizeSlaveJob('RAN-Ubuntu-Jetson-Image-Builder') + } + } + failure { + script { + currentBuild.result = 'FAILURE' + failingStages += ubuntuJetsonBuildStatus + } + } + } + } stage ("RHEL-Cluster-Image-Builder") { steps { script { @@ -243,6 +267,23 @@ pipeline { } } } + stage ("DockerHub-Push") { + when { expression {doBuild && "PUSH".equals(env.gitlabActionType)} } + steps { + script { + triggerSlaveJob ('RAN-DockerHub-Push', 'DockerHub-Push') + } + } + post { + failure { + script { + echo "Push to Docker-Hub KO" + currentBuild.result = 'FAILURE' + failingStages += '\n * RAN-DockerHub-Push' + } + } + } + } stage ("Image Test Processes") { when { expression {doBuild} } parallel { @@ -269,6 +310,29 @@ pipeline { } } } + stage ("PhySim-GraceHopper-5G") { + when { expression {do5Gtest || do5GUeTest} } + steps { + script { + triggerSlaveJob ('RAN-PhySim-GraceHopper-5G', 'PhySim-GraceHopper-5G') + } + } + post { + always { + script { + // Using a unique variable name for each test stage to avoid overwriting on a global variable + // due to parallel-time concurrency + physimGH5GStatus = finalizeSlaveJob('RAN-PhySim-GraceHopper-5G') + } + } + failure { + script { + currentBuild.result = 'FAILURE' + failingStages += physimGH5GStatus + } + } + } + } stage ("PhySim-Cluster-4G") { when { expression {do4Gtest} } steps { @@ -661,6 +725,29 @@ pipeline { } } } + stage ("SA-Handover-CN5G") { + when { expression {do5Gtest} } + steps { + script { + triggerSlaveJob ('RAN-SA-Handover-CN5G', 'SA-Handover-CN5G') + } + } + post { + always { + script { + // Using a unique variable name for each test stage to avoid overwriting on a global variable + // due to parallel-time concurrency + saHandoverStatus = finalizeSlaveJob('RAN-SA-Handover-CN5G') + } + } + failure { + script { + currentBuild.result = 'FAILURE' + failingStages += saHandoverStatus + } + } + } + } stage ("SA-OAIUE-CN5G") { when { expression {do5Gtest || do5GUeTest} } steps { @@ -686,23 +773,6 @@ pipeline { } } } - stage ("DockerHub-Push") { - when { expression {doBuild && "PUSH".equals(env.gitlabActionType)} } - steps { - script { - triggerSlaveJob ('RAN-DockerHub-Push', 'DockerHub-Push') - } - } - post { - failure { - script { - echo "Push to Docker-Hub KO" - currentBuild.result = 'FAILURE' - failingStages += '\n * RAN-DockerHub-Push' - } - } - } - } } post { success { @@ -766,11 +836,11 @@ def triggerCN5GSlaveJob (jobName, gitlabStatusName) { shortenShaOne = sh returnStdout: true, script: 'git log -1 --pretty=format:"%h" --abbrev=8 ' + env.gitlabMergeRequestLastCommit shortenShaOne = shortenShaOne.trim() branchName = env.gitlabSourceBranch.replaceAll("/", "-").trim() - fullRanTag = 'porcepix.sboai.cs.eurecom.fr/oai-gnb:' + env.gitlabSourceBranch + '-' + shortenShaOne + fullRanTag = OAI_Registry + '/oai-gnb:' + env.gitlabSourceBranch + '-' + shortenShaOne } else { shortenShaOne = sh returnStdout: true, script: 'git log -1 --pretty=format:"%h" --abbrev=8 ' + env.GIT_COMMIT shortenShaOne = shortenShaOne.trim() - fullRanTag = 'porcepix.sboai.cs.eurecom.fr/oai-gnb:develop-' + shortenShaOne + fullRanTag = OAI_Registry + '/oai-gnb:develop-' + shortenShaOne } // Workaround for the "cancelled" GitLab pipeline notification // The slave job is triggered with the propagate false so the following commands are executed @@ -835,11 +905,13 @@ def finalizeSlaveJob(jobName) { selector: lastCompleted()) if (fileExists(fileName)) { sh "sed -i -e 's#TEMPLATE_BUILD_TIME#${JOB_TIMESTAMP}#' ${fileName}" - archiveArtifacts artifacts: fileName - // BUILD_URL is like http://server:port/jenkins/job/foo/15/ - // no need to add a prefixed '/' - artifactUrl += 'artifact/' + fileName + } else { + sh "echo \"could not copy results from ${jobName}, please check pipeline ${BUILD_URL}\" > ${fileName}" } + archiveArtifacts artifacts: fileName + // BUILD_URL is like http://server:port/jenkins/job/foo/15/ + // no need to add a prefixed '/' + artifactUrl += 'artifact/' + fileName } artifactUrl = "\n * [${jobName}](${artifactUrl})" return artifactUrl diff --git a/ci-scripts/Jenkinsfile-cluster b/ci-scripts/Jenkinsfile-cluster index e91b27426e..174ccab62f 100644 --- a/ci-scripts/Jenkinsfile-cluster +++ b/ci-scripts/Jenkinsfile-cluster @@ -98,18 +98,10 @@ pipeline { echo "no LockResources given" allParametersPresent = false } - if (params.eNB_IPAddress == null) { - echo "no eNB_IPAddress given" - allParametersPresent = false - } if (params.eNB_SourceCodePath == null) { echo "no eNB_SourceCodePath given" allParametersPresent = false } - if (params.eNB_Credentials == null) { - echo "no eNB_Credentials given" - allParametersPresent = false - } // the following 4 parameters should be pushed by the master trigger // if not present, take the job GIT variables (used for developing) if (params.eNB_Repository == null) { @@ -188,7 +180,6 @@ pipeline { } } withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'], [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password'] ]) { sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" @@ -196,7 +187,7 @@ pipeline { if (fileExists(xmlFile)) { try { timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --eNBIPAddress=${params.eNB_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}" + sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}" } } catch (Exception e) { currentBuild.result = 'FAILURE' @@ -204,7 +195,7 @@ pipeline { } } } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" + sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" } } } diff --git a/ci-scripts/Jenkinsfile-nrue b/ci-scripts/Jenkinsfile-nrue index aed99b3568..3f7ef9b9ed 100644 --- a/ci-scripts/Jenkinsfile-nrue +++ b/ci-scripts/Jenkinsfile-nrue @@ -91,24 +91,9 @@ pipeline { echo "no LockResources given" allParametersPresent = false } - if (params.eNB_IPAddress == null) { - allParametersPresent = false - } if (params.eNB_SourceCodePath == null) { allParametersPresent = false } - if (params.eNB_Credentials == null) { - allParametersPresent = false - } - if (params.eNB1_IPAddress == null) { - allParametersPresent = false - } - if (params.eNB1_SourceCodePath == null) { - allParametersPresent = false - } - if (params.eNB1_Credentials == null) { - allParametersPresent = false - } // the following 4 parameters should be pushed by the master trigger // if not present, take the job GIT variables (used for developing) if (params.eNB_Repository == null) { @@ -187,8 +172,6 @@ pipeline { } } withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'], - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB1_Credentials}", usernameVariable: 'eNB1_Username', passwordVariable: 'eNB1_Password'], [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password'] ]) { sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" @@ -197,7 +180,7 @@ pipeline { if (fileExists(xmlFile)) { try { timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --eNBIPAddress=${params.eNB_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName} --eNB1IPAddress=${params.eNB1_IPAddress} --eNB1UserName=${eNB1_Username} --eNB1Password=${eNB1_Password} --eNB1SourceCodePath=${params.eNB1_SourceCodePath}" + sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}" } } catch (Exception e) { currentBuild.result = 'FAILURE' @@ -205,7 +188,7 @@ pipeline { } } } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" + sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" } } } diff --git a/ci-scripts/Jenkinsfile-physim-deploy b/ci-scripts/Jenkinsfile-physim-deploy index ffeff8685b..e3d243d07b 100644 --- a/ci-scripts/Jenkinsfile-physim-deploy +++ b/ci-scripts/Jenkinsfile-physim-deploy @@ -92,15 +92,9 @@ pipeline { echo "no LockResources given" allParametersPresent = false } - if (params.eNB_IPAddress == null) { - allParametersPresent = false - } if (params.eNB_SourceCodePath == null) { allParametersPresent = false } - if (params.eNB_Credentials == null) { - allParametersPresent = false - } // the following 4 parameters should be pushed by the master trigger // if not present, take the job GIT variables (used for developing) if (params.eNB_Repository == null) { @@ -179,7 +173,6 @@ pipeline { } } withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'], [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.OC_Credentials}", usernameVariable: 'OC_Username', passwordVariable: 'OC_Password'] ]) { sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" @@ -188,7 +181,7 @@ pipeline { if (fileExists(xmlFile)) { try { timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --eNBIPAddress=${params.eNB_IPAddress} --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}" + sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile} --OCUserName=${OC_Username} --OCPassword=${OC_Password} --OCProjectName=${OC_ProjectName}" } } catch (Exception e) { currentBuild.result = 'FAILURE' @@ -196,7 +189,7 @@ pipeline { } } } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" + sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" } } } diff --git a/ci-scripts/Jenkinsfile-push-registry b/ci-scripts/Jenkinsfile-push-registry index d3bd5e6e64..ccd91e28ff 100644 --- a/ci-scripts/Jenkinsfile-push-registry +++ b/ci-scripts/Jenkinsfile-push-registry @@ -31,6 +31,9 @@ if (params.LockResources != null && params.LockResources.trim().length() > 0) // Docker Hub account to push to def DH_Account = "oaisoftwarealliance" +// internal registry to use +def OAI_Registry = "gracehopper3-oai.sboai.cs.eurecom.fr" + pipeline { agent { label nodeExecutor @@ -79,14 +82,11 @@ pipeline { def listOfImages = ["oai-enb", "oai-gnb", "oai-lte-ue", "oai-nr-ue", "oai-nr-cuup", "oai-gnb-fhi72"] // Logging in on both registries sh "docker login -u ${DH_Username} -p ${DH_Password} > /dev/null 2>&1" - sh "docker login -u oaicicd -p oaicicd porcepix.sboai.cs.eurecom.fr > /dev/null 2>&1" + sh "docker login -u oaicicd -p oaicicd ${OAI_Registry} > /dev/null 2>&1" listOfImages.eachWithIndex { item, iindex -> - sh "docker pull --quiet porcepix.sboai.cs.eurecom.fr/${item}:develop-${WEEK_SHA}" - sh "docker image tag porcepix.sboai.cs.eurecom.fr/${item}:develop-${WEEK_SHA} ${DH_Account}/${item}:develop" - sh "docker image tag porcepix.sboai.cs.eurecom.fr/${item}:develop-${WEEK_SHA} ${DH_Account}/${item}:${WEEK_TAG}" - sh "docker push --quiet ${DH_Account}/${item}:${WEEK_TAG}" - sh "docker push --quiet ${DH_Account}/${item}:develop" - sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop porcepix.sboai.cs.eurecom.fr/${item}:develop-${WEEK_SHA}" + sh "docker rmi ${DH_Account}/${item}:${WEEK_TAG} ${DH_Account}/${item}:develop || true" + sh "docker buildx imagetools create --tag ${DH_Account}/${item}:${WEEK_TAG} ${OAI_Registry}/${item}:armv8_develop-${WEEK_SHA} ${OAI_Registry}/${item}:develop-${WEEK_SHA}" + sh "docker buildx imagetools create --tag ${DH_Account}/${item}:develop ${OAI_Registry}/${item}:armv8_develop-${WEEK_SHA} ${OAI_Registry}/${item}:develop-${WEEK_SHA}" } // Proxy is not following the same pattern. sh "docker image tag proxy:develop ${DH_Account}/proxy:develop" @@ -95,7 +95,7 @@ pipeline { sh "docker push --quiet ${DH_Account}/proxy:${WEEK_TAG}" sh "docker rmi ${DH_Account}/proxy:develop ${DH_Account}/proxy:${WEEK_TAG}" // Logging out on both registries - sh "docker logout porcepix.sboai.cs.eurecom.fr > /dev/null 2>&1" + sh "docker logout ${OAI_Registry} > /dev/null 2>&1" sh "docker logout > /dev/null 2>&1" } } @@ -105,7 +105,7 @@ pipeline { post { always { script { - sh "docker logout porcepix.sboai.cs.eurecom.fr > /dev/null 2>&1" + sh "docker logout ${OAI_Registry} > /dev/null 2>&1" sh "docker logout > /dev/null 2>&1" echo "End of Registry Push" } diff --git a/ci-scripts/Jenkinsfile-tmp-full-ran b/ci-scripts/Jenkinsfile-tmp-full-ran index f1baa5b04d..07b10ab980 100644 --- a/ci-scripts/Jenkinsfile-tmp-full-ran +++ b/ci-scripts/Jenkinsfile-tmp-full-ran @@ -91,15 +91,9 @@ pipeline { echo "no LockResources given" allParametersPresent = false } - if (params.eNB_IPAddress == null) { - allParametersPresent = false - } if (params.eNB_SourceCodePath == null) { allParametersPresent = false } - if (params.eNB_Credentials == null) { - allParametersPresent = false - } // the following 4 parameters should be pushed by the master trigger // if not present, take the job GIT variables (used for developing) if (params.eNB_Repository == null) { @@ -170,25 +164,21 @@ pipeline { } } } - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'], - ]) { - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { + sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" + String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") + for (xmlFile in myXmlTestSuite) { if (fileExists(xmlFile)) { try { timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" + sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" } } catch (Exception e) { currentBuild.result = 'FAILURE' buildStageStatus = false } } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" } + sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" } } } @@ -198,11 +188,7 @@ pipeline { stage('Terminate eNB') { steps { echo '\u2705 \u001B[32mTerminate eNB\u001B[0m' - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" - } + sh "python3 ci-scripts/main.py --mode=TerminateeNB" } post { success { @@ -216,35 +202,11 @@ pipeline { } stage('Log Collection') { parallel { - stage('Log Collection (eNB - Build)') { - steps { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}" - - echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m' - sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true" - } - script { - if(fileExists("build.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "build.log.${env.BUILD_ID}.zip" - } - } - } - } stage('Log Collection (eNB - Run)') { steps { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" + echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" - echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m' - sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true" - } script { if(fileExists("enb.log.${env.BUILD_ID}.zip")) { archiveArtifacts "enb.log.${env.BUILD_ID}.zip" @@ -280,11 +242,7 @@ pipeline { failure { script { if (!termStatusArray[termENB]) { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" - } + sh "python3 ci-scripts/main.py --mode=TerminateeNB" } } } diff --git a/ci-scripts/Jenkinsfile-tmp-multi-enb b/ci-scripts/Jenkinsfile-tmp-multi-enb index 2680fbe863..c01c8daf7e 100644 --- a/ci-scripts/Jenkinsfile-tmp-multi-enb +++ b/ci-scripts/Jenkinsfile-tmp-multi-enb @@ -81,36 +81,9 @@ pipeline { echo "no LockResources given" allParametersPresent = false } - // 1st eNB parameters - if (params.eNB_IPAddress == null) { - allParametersPresent = false - } if (params.eNB_SourceCodePath == null) { allParametersPresent = false } - if (params.eNB_Credentials == null) { - allParametersPresent = false - } - // 2nd eNB parameters - if (params.eNB1_IPAddress == null) { - allParametersPresent = false - } - if (params.eNB1_SourceCodePath == null) { - allParametersPresent = false - } - if (params.eNB1_Credentials == null) { - allParametersPresent = false - } - // 3rd eNB parameters - if (params.eNB2_IPAddress == null) { - allParametersPresent = false - } - if (params.eNB2_SourceCodePath == null) { - allParametersPresent = false - } - if (params.eNB2_Credentials == null) { - allParametersPresent = false - } // the following 4 parameters should be pushed by the master trigger // if not present, take the job GIT variables (used for developing) if (params.eNB_Repository == null) { @@ -181,27 +154,21 @@ pipeline { } } } - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'], - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB1_Credentials}", usernameVariable: 'eNB1_Username', passwordVariable: 'eNB1_Password'], - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB2_Credentials}", usernameVariable: 'eNB2_Username', passwordVariable: 'eNB2_Password'], - ]) { - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --eNB1IPAddress=${params.eNB1_IPAddress} --eNB1UserName=${eNB1_Username} --eNB1Password=${eNB1_Password} --eNB1SourceCodePath=${params.eNB1_SourceCodePath} --eNB2IPAddress=${params.eNB2_IPAddress} --eNB2UserName=${eNB2_Username} --eNB2Password=${eNB2_Password} --eNB2SourceCodePath=${params.eNB2_SourceCodePath} --XMLTestFile=${xmlFile}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } + sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" + String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") + for (xmlFile in myXmlTestSuite) { + if (fileExists(xmlFile)) { + try { + timeout (time: 60, unit: 'MINUTES') { + sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" + } + } catch (Exception e) { + currentBuild.result = 'FAILURE' + buildStageStatus = false } } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" } + sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" } } } @@ -211,46 +178,18 @@ pipeline { stage('Terminate eNB') { steps { echo '\u2705 \u001B[32mTerminate eNB\u001B[0m' - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" - } + sh "python3 ci-scripts/main.py --mode=TerminateeNB" } } } } stage('Log Collection') { parallel { - stage('Log Collection (eNB - Build)') { - steps { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}" - - echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m' - sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true" - } - script { - if(fileExists("build.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "build.log.${env.BUILD_ID}.zip" - } - } - } - } stage('Log Collection (eNB - Run)') { steps { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" + echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" - echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m' - sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true" - } script { if(fileExists("enb.log.${env.BUILD_ID}.zip")) { archiveArtifacts "enb.log.${env.BUILD_ID}.zip" diff --git a/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa b/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa index 5e60b199b4..67aa6b4511 100644 --- a/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa +++ b/ci-scripts/Jenkinsfile-tmp-multi-enb-nsa @@ -83,36 +83,9 @@ pipeline { echo "no LockResources given" allParametersPresent = false } - // 1st eNB parameters - if (params.eNB_IPAddress == null) { - allParametersPresent = false - } if (params.eNB_SourceCodePath == null) { allParametersPresent = false } - if (params.eNB_Credentials == null) { - allParametersPresent = false - } - // 2nd eNB parameters - if (params.eNB1_IPAddress == null) { - allParametersPresent = false - } - if (params.eNB1_SourceCodePath == null) { - allParametersPresent = false - } - if (params.eNB1_Credentials == null) { - allParametersPresent = false - } - // 3rd eNB parameters - if (params.eNB2_IPAddress == null) { - allParametersPresent = false - } - if (params.eNB2_SourceCodePath == null) { - allParametersPresent = false - } - if (params.eNB2_Credentials == null) { - allParametersPresent = false - } // the following 4 parameters should be pushed by the master trigger // if not present, take the job GIT variables (used for developing) if (params.eNB_Repository == null) { @@ -183,62 +156,31 @@ pipeline { } } } - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'], - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB1_Credentials}", usernameVariable: 'eNB1_Username', passwordVariable: 'eNB1_Password'], - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB2_Credentials}", usernameVariable: 'eNB2_Username', passwordVariable: 'eNB2_Password'], - ]) { - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { - if (fileExists(xmlFile)) { - try { - timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --eNB1IPAddress=${params.eNB1_IPAddress} --eNB1UserName=${eNB1_Username} --eNB1Password=${eNB1_Password} --eNB1SourceCodePath=${params.eNB1_SourceCodePath} --eNB2IPAddress=${params.eNB2_IPAddress} --eNB2UserName=${eNB2_Username} --eNB2Password=${eNB2_Password} --eNB2SourceCodePath=${params.eNB2_SourceCodePath} --XMLTestFile=${xmlFile}" - } - } catch (Exception e) { - currentBuild.result = 'FAILURE' - buildStageStatus = false - } + sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${mainPythonAllXmlFiles}" + String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") + for (xmlFile in myXmlTestSuite) { + if (fileExists(xmlFile)) { + try { + timeout (time: 60, unit: 'MINUTES') { + sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" + } + } catch (Exception e) { + currentBuild.result = 'FAILURE' + buildStageStatus = false } } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" } + sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" } } } } stage('Log Collection') { parallel { - stage('Log Collection (eNB - Build)') { - steps { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}" - - echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m' - sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true" - } - script { - if(fileExists("build.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "build.log.${env.BUILD_ID}.zip" - } - } - } - } stage('Log Collection (eNB - Run)') { steps { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" - - echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m' - sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true" - } + echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" script { if(fileExists("enb.log.${env.BUILD_ID}.zip")) { archiveArtifacts "enb.log.${env.BUILD_ID}.zip" diff --git a/ci-scripts/Jenkinsfile-tmp-ran b/ci-scripts/Jenkinsfile-tmp-ran index 03c0f9a0cb..526899a5a2 100644 --- a/ci-scripts/Jenkinsfile-tmp-ran +++ b/ci-scripts/Jenkinsfile-tmp-ran @@ -96,15 +96,9 @@ pipeline { echo "no LockResources given" allParametersPresent = false } - if (params.eNB_IPAddress == null) { - allParametersPresent = false - } if (params.eNB_SourceCodePath == null) { allParametersPresent = false } - if (params.eNB_Credentials == null) { - allParametersPresent = false - } // the following 4 parameters should be pushed by the master trigger // if not present, take the job GIT variables (used for developing) if (params.eNB_Repository == null) { @@ -181,25 +175,21 @@ pipeline { } } } - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'], - ]) { - sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} ${mainPythonAllXmlFiles}" - String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") - for (xmlFile in myXmlTestSuite) { + sh "python3 main.py --mode=InitiateHtml --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} ${mainPythonAllXmlFiles}" + String[] myXmlTestSuite = testXMLFile.split("\\r?\\n") + for (xmlFile in myXmlTestSuite) { if (fileExists(xmlFile)) { try { timeout (time: 60, unit: 'MINUTES') { - sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" + sh "python3 main.py --mode=TesteNB --ranRepository=${eNB_Repository} --ranBranch=${eNB_Branch} --ranCommitID=${eNB_CommitID} --ranAllowMerge=${eNB_AllowMergeRequestProcess} --ranTargetBranch=${eNB_TargetBranch} ${flexricOption} --eNBSourceCodePath=${params.eNB_SourceCodePath} --XMLTestFile=${xmlFile}" } } catch (Exception e) { currentBuild.result = 'FAILURE' buildStageStatus = false } } - } - sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus} --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" } + sh "python3 main.py --mode=FinalizeHtml --finalStatus=${buildStageStatus}" } } } @@ -209,11 +199,7 @@ pipeline { stage('Terminate eNB') { steps { echo '\u2705 \u001B[32mTerminate eNB\u001B[0m' - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" - } + sh "python3 ci-scripts/main.py --mode=TerminateeNB" } post { success { @@ -227,35 +213,10 @@ pipeline { } stage('Log Collection') { parallel { - stage('Log Collection (eNB - Build)') { - steps { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - echo '\u2705 \u001B[32mLog Collection (eNB - Build)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollectBuild --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath}" - - echo '\u2705 \u001B[32mLog Transfer (eNB - Build)\u001B[0m' - sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/build.log.zip ./build.log.${env.BUILD_ID}.zip || true" - } - script { - if(fileExists("build.log.${env.BUILD_ID}.zip")) { - archiveArtifacts "build.log.${env.BUILD_ID}.zip" - } - } - } - } stage('Log Collection (eNB - Run)') { steps { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' - sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password} --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" - - echo '\u2705 \u001B[32mLog Transfer (eNB - Run)\u001B[0m' - sh "sshpass -p \'${eNB_Password}\' scp -o 'StrictHostKeyChecking no' -o 'ConnectTimeout 10' ${eNB_Username}@${params.eNB_IPAddress}:${eNB_SourceCodePath}/cmake_targets/enb.log.zip ./enb.log.${env.BUILD_ID}.zip || true" - } + echo '\u2705 \u001B[32mLog Collection (eNB - Run)\u001B[0m' + sh "python3 ci-scripts/main.py --mode=LogCollecteNB --eNBSourceCodePath=${params.eNB_SourceCodePath} --BuildId=${env.BUILD_ID}" script { if(fileExists("enb.log.${env.BUILD_ID}.zip")) { archiveArtifacts "enb.log.${env.BUILD_ID}.zip" @@ -291,11 +252,7 @@ pipeline { failure { script { if (!termStatusArray[termENB]) { - withCredentials([ - [$class: 'UsernamePasswordMultiBinding', credentialsId: "${params.eNB_Credentials}", usernameVariable: 'eNB_Username', passwordVariable: 'eNB_Password'] - ]) { - sh "python3 ci-scripts/main.py --mode=TerminateeNB --eNBIPAddress=${params.eNB_IPAddress} --eNBUserName=${eNB_Username} --eNBPassword=${eNB_Password}" - } + sh "python3 ci-scripts/main.py --mode=TerminateeNB" } } } diff --git a/ci-scripts/README.md b/ci-scripts/README.md new file mode 100644 index 0000000000..becd518e4c --- /dev/null +++ b/ci-scripts/README.md @@ -0,0 +1,60 @@ +This document outlines how to use the OAI CI framework and gives a quickstart. + +[[_TOC_]] + +# Quickstart + +There is a script `main.py` that + +- reads scenario files from XML +- executes the steps (e.g., deployment of CN/gNB/UE, attach, ping, ...) + +To simplify, a script `run_locally.sh` can be used to run a single scenario +locally. First, download images for gNB&UE (we assume you already downloaded +the CN) and tag them "latest", which is expected by `run_locally.sh`: + + docker pull oaisoftwarealliance/oai-gnb:develop + docker tag oaisoftwarealliance/oai-gnb:develop oai-gnb + docker pull oaisoftwarealliance/oai-nr-ue:develop + docker tag oaisoftwarealliance/oai-nr-ue:develop oai-nr-ue + +Now, run the scenario: + + cd ~/openairinterface5g/ci-scripts/ + ./run_locally.sh xml_files/container_5g_rfsim_simple.xml + +Output should look like + +``` +[2025-08-07 18:07:49,631] INFO: ---------------------------------------- +[2025-08-07 18:07:49,631] INFO: Creating HTML header +[2025-08-07 18:07:49,631] INFO: ---------------------------------------- +[2025-08-07 18:07:49,766] INFO: ---------------------------------------- +[2025-08-07 18:07:49,767] INFO: Starting Scenario: xml_files/container_5g_rfsim_simple.xml +[2025-08-07 18:07:49,767] INFO: ---------------------------------------- +[2025-08-07 18:07:49,767] INFO: placing all artifacts for this run in /home/richie/oai/cmake_targets/log/container_5g_rfsim_simple.xml.d/ + +[...] + +[2025-08-07 18:07:49,771] INFO: ---------------------------------------- +[2025-08-07 18:07:49,771] INFO: Test ID: 1 (#1) +[2025-08-07 18:07:49,771] INFO: Deploy OAI 5G CoreNetwork +[2025-08-07 18:07:49,771] INFO: ---------------------------------------- +``` + +it will run an end-to-end test, connecting one UE to the gNB, and ping, before +undeploying. As shown, logs will be under +`/home/richie/oai/cmake_targets/log/container_5g_rfsim_simple.xml.d/`. The +python code also produces an HTML report in `ci-scripts/test_results.html`. + +# Running with local changes + +In order to run the tests as above, with local changes, please [build images +locally](../docker/README.md). + +It is not yet possible to override an existing image with changes made locally +to a source file and run it directly through the CI framework. However, it is +possible to override an existing image with local changes, and run the scenario +manually following the console logs steps provided above. This is described in +the [5G RFsimulator +README](yaml_files/5g_rfsimulator/README.md#6-running-with-local-changes). diff --git a/ci-scripts/args_parse.py b/ci-scripts/args_parse.py index 92cb0d163f..4953f049fb 100644 --- a/ci-scripts/args_parse.py +++ b/ci-scripts/args_parse.py @@ -59,17 +59,6 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): force_local = True - #--apply= as parameters file, to replace inline parameters - elif re.match(r'^\-\-Apply=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-Apply=(.+)$', myArgv, re.IGNORECASE) - py_params_file = matchReg.group(1) - with open(py_params_file,'r') as file: - # The FullLoader parameter handles the conversion from YAML - # scalar values to Python dictionary format - py_params = yaml.load(file,Loader=yaml.FullLoader) - py_param_file_present = True #to be removed once validated - #AssignParams(py_params) #to be uncommented once validated - #consider inline parameters elif re.match(r'^\-\-mode=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match(r'^\-\-mode=(.+)$', myArgv, re.IGNORECASE) @@ -132,50 +121,11 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): SCA.ranTargetBranch=matchReg.group(1) CLUSTER.ranTargetBranch=matchReg.group(1) elif re.match(r'^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): - if re.match(r'^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNBIPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.eNBIPAddress=matchReg.group(1) - CONTAINERS.eNBIPAddress=matchReg.group(1) - SCA.eNBIPAddress=matchReg.group(1) - CLUSTER.eNBIPAddress=matchReg.group(1) - elif re.match(r'^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNB1IPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.eNB1IPAddress=matchReg.group(1) - CONTAINERS.eNB1IPAddress=matchReg.group(1) - elif re.match(r'^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNB2IPAddress=(.+)$', myArgv, re.IGNORECASE) - RAN.eNB2IPAddress=matchReg.group(1) - CONTAINERS.eNB2IPAddress=matchReg.group(1) + print("parameters --eNB*IPAddress ignored") elif re.match(r'^\-\-eNBUserName=(.+)$|^\-\-eNB[1-2]UserName=(.+)$', myArgv, re.IGNORECASE): - if re.match(r'^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNBUserName=(.+)$', myArgv, re.IGNORECASE) - RAN.eNBUserName=matchReg.group(1) - CONTAINERS.eNBUserName=matchReg.group(1) - SCA.eNBUserName=matchReg.group(1) - CLUSTER.eNBUserName=matchReg.group(1) - elif re.match(r'^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNB1UserName=(.+)$', myArgv, re.IGNORECASE) - RAN.eNB1UserName=matchReg.group(1) - CONTAINERS.eNB1UserName=matchReg.group(1) - elif re.match(r'^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNB2UserName=(.+)$', myArgv, re.IGNORECASE) - RAN.eNB2UserName=matchReg.group(1) - CONTAINERS.eNB2UserName=matchReg.group(1) + print("parameters --eNB*UserName ignored") elif re.match(r'^\-\-eNBPassword=(.+)$|^\-\-eNB[1-2]Password=(.+)$', myArgv, re.IGNORECASE): - if re.match(r'^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNBPassword=(.+)$', myArgv, re.IGNORECASE) - RAN.eNBPassword=matchReg.group(1) - CONTAINERS.eNBPassword=matchReg.group(1) - SCA.eNBPassword=matchReg.group(1) - CLUSTER.eNBPassword=matchReg.group(1) - elif re.match(r'^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNB1Password=(.+)$', myArgv, re.IGNORECASE) - RAN.eNB1Password=matchReg.group(1) - CONTAINERS.eNB1Password=matchReg.group(1) - elif re.match(r'^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNB2Password=(.+)$', myArgv, re.IGNORECASE) - RAN.eNB2Password=matchReg.group(1) - CONTAINERS.eNB2Password=matchReg.group(1) + print("parameter --eNB*Password ignored") elif re.match(r'^\-\-eNBSourceCodePath=(.+)$|^\-\-eNB[1-2]SourceCodePath=(.+)$', myArgv, re.IGNORECASE): if re.match(r'^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match(r'^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) @@ -184,26 +134,14 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): SCA.eNBSourceCodePath=matchReg.group(1) CLUSTER.eNBSourceCodePath=matchReg.group(1) elif re.match(r'^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - RAN.eNB1SourceCodePath=matchReg.group(1) - CONTAINERS.eNB1SourceCodePath=matchReg.group(1) + print("parameter --eNB1SourceCodePath ignored") elif re.match(r'^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match(r'^\-\-eNB2SourceCodePath=(.+)$', myArgv, re.IGNORECASE) - RAN.eNB2SourceCodePath=matchReg.group(1) - CONTAINERS.eNB2SourceCodePath=matchReg.group(1) + print("parameter --eNB2SourceCodePath ignored") elif re.match(r'^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match(r'^\-\-XMLTestFile=(.+)$', myArgv, re.IGNORECASE) CiTestObj.testXMLfiles.append(matchReg.group(1)) HTML.testXMLfiles.append(matchReg.group(1)) HTML.nbTestXMLfiles=HTML.nbTestXMLfiles+1 - elif re.match(r'^\-\-UEIPAddress=(.+)$', myArgv, re.IGNORECASE): # cleanup - print("parameter --UEIPAddress ignored") - elif re.match(r'^\-\-UEUserName=(.+)$', myArgv, re.IGNORECASE): - print("parameter --UEUserName ignored") - elif re.match(r'^\-\-UEPassword=(.+)$', myArgv, re.IGNORECASE): - print("parameter --UEPassword ignored") - elif re.match(r'^\-\-UESourceCodePath=(.+)$', myArgv, re.IGNORECASE): - print("parameter --UESourceCodePath ignored") elif re.match(r'^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE): matchReg = re.match(r'^\-\-finalStatus=(.+)$', myArgv, re.IGNORECASE) finalStatus = matchReg.group(1) diff --git a/ci-scripts/as_ue/aw2s-multi-00102-20.cfg b/ci-scripts/as_ue/aw2s-multi-00102-20.cfg index 5fc05d6301..5c8872d9ae 100644 --- a/ci-scripts/as_ue/aw2s-multi-00102-20.cfg +++ b/ci-scripts/as_ue/aw2s-multi-00102-20.cfg @@ -5,7 +5,7 @@ { #define N_ANTENNA_DL 1 #define N_ANTENNA_UL 1 -#define DL_ARFCN 631296 +#define DL_ARFCN 627360 #define TDD 1 log_options: "all.level=debug,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1", @@ -46,7 +46,7 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", apn:"oai", attach_pdn_type:"ipv4", @@ -61,8 +61,9 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", + redcap: "redcap", apn:"oai", attach_pdn_type:"ipv4", default_nssai: [ { sst: 1, }, ], @@ -76,7 +77,7 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", apn:"oai", attach_pdn_type:"ipv4", @@ -91,7 +92,7 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", apn:"oai", attach_pdn_type:"ipv4", @@ -106,8 +107,9 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", + redcap: "redcap", apn:"oai", attach_pdn_type:"ipv4", default_nssai: [ { sst: 1, }, ], @@ -121,8 +123,9 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", + redcap: "redcap", apn:"oai", attach_pdn_type:"ipv4", default_nssai: [ { sst: 1, }, ], @@ -136,7 +139,7 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", apn:"oai", attach_pdn_type:"ipv4", @@ -151,7 +154,7 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", apn:"oai", attach_pdn_type:"ipv4", @@ -166,7 +169,7 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", apn:"oai", attach_pdn_type:"ipv4", @@ -181,8 +184,9 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", + redcap: "redcap", apn:"oai", attach_pdn_type:"ipv4", default_nssai: [ { sst: 1, }, ], @@ -196,8 +200,9 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", + redcap: "redcap", apn:"oai", attach_pdn_type:"ipv4", default_nssai: [ { sst: 1, }, ], @@ -211,8 +216,9 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", + redcap: "redcap", apn:"oai", attach_pdn_type:"ipv4", default_nssai: [ { sst: 1, }, ], @@ -226,7 +232,7 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", apn:"oai", attach_pdn_type:"ipv4", @@ -241,7 +247,7 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", apn:"oai", attach_pdn_type:"ipv4", @@ -256,8 +262,9 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", + redcap: "redcap", apn:"oai", attach_pdn_type:"ipv4", default_nssai: [ { sst: 1, }, ], @@ -271,8 +278,9 @@ allow dynamic UE creation from remote API */ "sim_algo":"milenage", "op": "1006020f0a478bf6b699f15c062e42b3", - as_release: 15, + as_release: 17, ue_category: "nr", + redcap: "redcap", apn:"oai", attach_pdn_type:"ipv4", default_nssai: [ { sst: 1, }, ], diff --git a/ci-scripts/as_ue/config.cfg b/ci-scripts/as_ue/config.cfg index 1c71b752c1..42d8eba369 100644 --- a/ci-scripts/as_ue/config.cfg +++ b/ci-scripts/as_ue/config.cfg @@ -44,4 +44,4 @@ rf_driver: { #endif tx_gain: 75.0, /* TX gain (in dB) */ -rx_gain: 55.0, /* RX gain (in dB) */ +rx_gain: 52.0, /* RX gain (in dB) */ diff --git a/ci-scripts/attenuatorctl.py b/ci-scripts/attenuatorctl.py new file mode 100644 index 0000000000..e6f8c01837 --- /dev/null +++ b/ci-scripts/attenuatorctl.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 + +import argparse +import logging +import itertools +import usb.core +import usb.util +import sys +import time + +logging.basicConfig( + level=logging.DEBUG, + stream=sys.stdout, + format="%(message)s" +) + +# helper class parsing command line options for channels and attenuators +class ValidateChAtt(argparse.Action): + def _parse_channels(s): + if len(s.split("-")) == 2: + s, e = [int(x) for x in s.split("-")] + chs = [x for x in range(s, e+1)] + if len(chs) == 0: + raise Exception(f"empty range") + elif len(s.split(",")) > 1: + chs = [int(x) for x in s.split(",")] + elif s.isdigit(): + chs = [int(s)] + else: + raise Exception(f"could not parse channel expression") + for c in chs: + if not 1 <= c <= 4: + raise Exception(f"channel number must be within [1,4], but have {c}") + return chs + + def __call__(self, parse, args, values, option_string=None): + ch, att = values + try: + chs = ValidateChAtt._parse_channels(ch) + except Exception as e: + parse.exit(1, f"while parsing channel expression {ch}: {e}\n") + if not att.isdigit(): + parse.exit(1, f'expected number for attenuation, but got {att}\n') + if not 0 <= int(att) <= 63: + parse.exit(1, f'attenuation must be within [0,63], but is {att}\n') + opts = getattr(args, self.dest) or {} + for c in chs: + opts[c] = int(att) + setattr(args, self.dest, opts) + +def _parse_args() -> argparse.Namespace: + epilog = ''' +[CHs] can have the following forms: + (1) single channel number w (within [1-4]) + (2) a range of channels in the form x-y (x <= y) + (3) a list of channels in the form a,b,c +[ATT] must be within [0,63] (dB) + +--set and --reach are mutually exclusive + +Examples: +- reset all channels to 0: -s 1-4 0 +- set channels 3 and 4 to attenuation 60: -s 3,4 60 +- perform attenuation sweep during 10s, reaching ch. 1+2 to 60: -r 1,2 60 -d 10 +''' + parser = argparse.ArgumentParser(description='Mini-Circuit RC*DAT attenuator controller', + epilog=epilog, + formatter_class=argparse.RawDescriptionHelpFormatter) + + parser.add_argument('--info', '-i', action='store_true', default=False, + help='Get Infos for all connected Mini-Circuits RC*DAT',) + parser.add_argument('--set', '-s', nargs=2, metavar=("[CHs]","[ATT]"), + action=ValidateChAtt, help="Set a fixed attenuation ATT on channels CHs") + parser.add_argument('--reach', '-r', nargs=2, metavar=("[CHs]","[ATT]"), + action=ValidateChAtt, help="Perform an \"attenuation sweep\": reach attenuation ATT on channels CHs") + parser.add_argument('--duration', '-d', action='store', type=float, default=5.0, + help='DURATION for attenuation sweep to --reach given attenuation (Default: 5)',) + parser.add_argument('--progress', '-p', action='store_true', default=False, + help='If provided, will show progress during attenuation sweep',) + return parser.parse_args() + +def _exec(dev, cmd): + dev.write(1, cmd) + ans = dev.read(0x81,64) + # take from ans(wer) while valid bytes + sn = itertools.takewhile(lambda x: x < 255 and x > 0, ans) + # turn bytes into characters and accumulate into string + return "".join(map(chr, sn)) + +def devId(dev): + return f"{dev.idVendor:04x}:{dev.idProduct:04x}" + +def _info(dev): + ident = devId(dev) + SerialN = _exec(dev, "*:SN?") + ModelN = _exec(dev, "*:MN?") + Fw = _exec(dev, "*:FIRMWARE?") + + logging.info(f'{ident}: model is {ModelN}') + logging.info(f'{ident}: serial number is {SerialN}') + logging.info(f'{ident}: FW version is {Fw}') + +def _get_attenuation(dev): + ident = devId(dev) + att = _exec(dev, "*:ATT?") + # remove leading "*" and split by channels + return [float(n) for n in att[1:].split(" ")] + +def _set_attenuation(dev, ch_att): + ident = devId(dev) + for ch, att in ch_att: + #logging.debug(f"{ident}: Set attenuation channel {ch}: {att} dB") + att = round(4 * att) / 4 # round to closest 0.25dB + resp = _exec(dev, f"*:CHAN:{ch}:SETATT:{att};" ) + +def _continuous_set_attenuation(dev, ch_att_end, duration, show_progress=False, step_duration=0.25): + ident = devId(dev) + + current = _get_attenuation(dev) + steps = duration / step_duration + ch_att_step = [(ch, (att_end - current[ch - 1]) / steps) for ch, att_end in ch_att_end] + logging.info(f"{ident}: sweep attenuation during {duration} s in {steps} steps: increments {ch_att_step}") + for i in range(1, int(steps)+1): + next_att = [(ch, current[ch - 1] + i * att_step) for ch, att_step in ch_att_step] + _set_attenuation(dev, next_att) + if show_progress: + logging.debug(f"{ident}: attenuation for channel(s): {next_att}") + time.sleep(step_duration) + _set_attenuation(dev, ch_att_end) + +def _get_usb_devs(idVendor, idProduct): + devs = [] + for dev in usb.core.find(idVendor=idVendor, idProduct=idProduct, find_all=True): + for configuration in dev: + for interface in configuration: + ifnum = interface.bInterfaceNumber + if not dev.is_kernel_driver_active(ifnum): + continue + try: + dev.detach_kernel_driver(ifnum) + except e: + pass + devs.append(dev) + return devs + +if __name__ == '__main__': + # Parse the arguments + args = _parse_args() + if args.set and args.reach: + logging.error("--set and --reach are mutually exclusive") + sys.exit(1) + + # 20ce:0023 is Mini-Circuit RC*DAT device + devs = _get_usb_devs(idVendor=0x20ce, idProduct=0x0023) + if len(devs) == 0: + logging.error('no Mini-Circuits RC*DAT device detected') + sys.exit(-1) + if len(devs) > 1: + logging.error('more than one Mini-Circuits RC*DAT device detected') + sys.exit(-1) + dev = devs[0] + + if args.info: + _info(dev) + + if args.set: + _set_attenuation(dev, [(k,v) for k,v in args.set.items()]) + + if args.reach: + _continuous_set_attenuation(dev, [(k,v) for k,v in args.reach.items()], args.duration, args.progress) + + ident = devId(dev) + for i, a in enumerate(_get_attenuation(dev)): + logging.info(f"{ident}: Attenuation channel {i+1}: {a} dB") + sys.exit(0) diff --git a/ci-scripts/ci_infra.yaml b/ci-scripts/ci_infra.yaml index 1f040c33ff..837f1edb82 100644 --- a/ci-scripts/ci_infra.yaml +++ b/ci-scripts/ci_infra.yaml @@ -5,10 +5,20 @@ idefix: AttachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 wup DetachScript: sudo python3 ci_ctl_qtel.py /dev/ttyUSB2 detach NetworkScript: ip a show dev wwan0 + #Tracing: + # Start: 'sudo rm -f ci_qlog/*; nohup sudo -b QLog/QLog -s ci_qlog -f NR5G.cfg &' + # Stop: 'sudo killall QLog' + # Collect: 'sudo mv ci_qlog/* %%log_dir%%/' + IF: wwan0 + MTU: 1500 + +raspix: + Host: raspix + AttachScript: sudo /opt/mbim_scripts/start_quectel_mbim.sh + DetachScript: sudo /opt/mbim_scripts/stop_quectel_mbim.sh + NetworkScript: ip a show dev wwan0 IF: wwan0 MTU: 1500 - Trace: True - LogStore: /media/usb-drive/ci_qlogs up2: Host: up2 @@ -46,7 +56,6 @@ adb_ue_1: NetworkScript: adb -s R3CM40LZPHT shell "ip address show | grep rmnet_data0" CmdPrefix: adb -s R3CM40LZPHT shell MTU: 1500 - LogStore: /media/usb-drive/ci_adb_1-logs adb_ue_2: Host: nano InitScript: /home/oaicicd/ci_ctl_adb.sh initialize 5200c00db4413517 @@ -59,15 +68,14 @@ adb_ue_2: NetworkScript: adb -s 5200c00db4413517 shell "ip address show | grep rmnet" CmdPrefix: adb -s 5200c00db4413517 shell MTU: 1500 - LogStore: /media/usb-drive/ci_adb_2-logs oc-cn5g: Host: avra NetworkScript: echo "inet 172.21.6.102" RunIperf3Server: False - Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran" - Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran" - LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ci-ran %%log_dir%%" + Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran" + Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran" + LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jun oaicicd-core-for-ci-ran %%log_dir%%" oc-cn5g-20897: Host: cacofonix @@ -77,6 +85,14 @@ oc-cn5g-20897: Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72" LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72 %%log_dir%%" +oc-cn5g-00103-ho: + Host: groot + NetworkScript: echo "inet 172.21.6.111" + RunIperf3Server: False + Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ho" + Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ho" + LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-ho %%log_dir%%" + oc-cn5g-20897-aerial: Host: gracehopper1-oai NetworkScript: echo "inet 172.21.6.105" @@ -89,8 +105,8 @@ matix-cn5g: Host: matix NetworkScript: docker exec prod-trf-gen ip a show dev eth0 RunIperf3Server: False - Deploy: "cd /opt/oai-cn5g-fed-v2/docker-compose && python3 ./core-network.py --type start-basic" - Undeploy: "cd /opt/oai-cn5g-fed-v2/docker-compose && python3 ./core-network.py --type stop-basic" + Deploy: "cd /opt/oai-cn5g-fed-v2-jun-2025/docker-compose && python3 ./core-network.py --type start-basic" + Undeploy: "cd /opt/oai-cn5g-fed-v2-jun-2025/docker-compose && python3 ./core-network.py --type stop-basic" LogCollect: - "docker logs oai-smf > %%log_dir%%/oai-smf.log" - "docker logs oai-amf > %%log_dir%%/oai-amf.log" @@ -147,12 +163,16 @@ ltebox-nepes: amarisoft_ue: Host: amariue - InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue/aw2s-multi-00102-20.cfg & + InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_20MHz_redcap/aw2s-multi-00102-20.cfg & TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 NetworkScript: ip netns exec ue1 ip a show dev pdn0 + #Tracing: + # Start: '' # nothing to be done + # Stop: '' # nothing to be done + # Collect: 'cp /tmp/ue.log %%log_dir%%' amarisoft_ue_2x2: Host: amariue - InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_2x2/aw2s-multi-00102-2x2-v2.cfg & + InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_20MHz_2x2/aw2s-multi-00102-2x2-v2.cfg & TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 NetworkScript: ip netns exec ue1 ip a show dev pdn0 amarisoft_ue_fhi72: @@ -301,6 +321,15 @@ rfsim5g_ue: AttachScript: docker start rfsim5g-oai-nr-ue DetachScript: docker stop rfsim5g-oai-nr-ue MTU: 1500 +# for tests with second PDU session ID 2, needs to match requested PDU session name +rfsim5g_ue_pdu_2: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue1p2 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue1p2 + AttachScript: docker start rfsim5g-oai-nr-ue + DetachScript: docker stop rfsim5g-oai-nr-ue + MTU: 1500 rfsim5g_ue2: Host: "%%current_host%%" @@ -442,3 +471,93 @@ l2sim4g_ext_dn: Host: "%%current_host%%" NetworkScript: docker exec l2sim4g-trf-gen ip a show dev eth0 CmdPrefix: docker exec l2sim4g-trf-gen + +rfsim5g_multiue1: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue1 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue1 + AttachScript: docker start rfsim5g-oai-nr-ue + DetachScript: docker stop rfsim5g-oai-nr-ue + MTU: 1500 + +rfsim5g_multiue2: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue2 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue2 + AttachScript: true + DetachScript: true + MTU: 1500 + +rfsim5g_multiue3: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue3 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue3 + AttachScript: "true" + DetachScript: "true" + MTU: 1500 + +rfsim5g_multiue4: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue4 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue4 + AttachScript: "true" + DetachScript: "true" + MTU: 1500 + +rfsim5g_multiue5: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue5 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue5 + AttachScript: "true" + DetachScript: "true" + MTU: 1500 + +rfsim5g_multiue6: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue6 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue6 + AttachScript: "true" + DetachScript: "true" + MTU: 1500 + +rfsim5g_multiue7: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue7 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue7 + AttachScript: "true" + DetachScript: "true" + MTU: 1500 + +rfsim5g_multiue8: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue8 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue8 + AttachScript: "true" + DetachScript: "true" + MTU: 1500 + +rfsim5g_multiue9: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue9 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue9 + AttachScript: "true" + DetachScript: "true" + MTU: 1500 + +rfsim5g_multiue10: + Host: "%%current_host%%" + NetworkScript: docker exec rfsim5g-oai-nr-ue ip a show dev oaitun_ue10 + CmdPrefix: docker exec rfsim5g-oai-nr-ue + IF: oaitun_ue10 + AttachScript: "true" + DetachScript: "true" + MTU: 1500 diff --git a/ci-scripts/cls_analysis.py b/ci-scripts/cls_analysis.py index ac591b52fb..588490da62 100644 --- a/ci-scripts/cls_analysis.py +++ b/ci-scripts/cls_analysis.py @@ -26,65 +26,26 @@ import os import xml.etree.ElementTree as ET import json -# Define the mapping of physim_test values to search patterns -PHYSIM_PATTERN_MAPPING = { - 'nr_ulsim': [ - r'(Total PHY proc rx)\s+(\d+\.\d+)\s+us', # Pattern for RX PHY processing time - r'(ULSCH total decoding time)\s+(\d+\.\d+)\s+us', # Pattern for ULSCH decoding time - ], - 'nr_dlsim': [ - r'(PHY proc tx)\s+(\d+\.\d+)\s+us', # Pattern for TX PHY processing time - r'(DLSCH encoding time)\s+(\d+\.\d+)\s+us', # Pattern for DLSCH encoding time - ], - 'ldpctest': [ - r'(Encoding time mean):\s+(\d+\.\d+)\s+us', # Pattern for encoding time mean - r'(Decoding time mean):\s+(\d+\.\d+)\s+us', # Pattern for decoding time mean - ], -} -# Define test conditions based on the simulation type -PHYSIM_TEST_CONDITION = { - 'nr_ulsim': 'test OK', # For nr_ulsim, check if 'test OK' is present - 'nr_dlsim': 'test OK', # For nr_dlsim, check if 'test OK' is present - 'ldpctest': None, # No condition for ldpctest, just process the patterns -} - class Analysis(): - def analyze_physim(log, physim_test, options, threshold): - search_patterns = PHYSIM_PATTERN_MAPPING.get(physim_test) - test_condition = PHYSIM_TEST_CONDITION.get(physim_test) - success = False - msg = '' + def _get_test_description(properties): + env_vars = None + for p in properties: + if p["name"] == "ENVIRONMENT": + env_vars = p["value"] # save for later if no custom property + if p["name"] == "TEST_DESCRIPTION": + return p["value"] + # if we came till here, it means there is no custom test property + # saved in JSON. See if we have a description in environment variables + if not env_vars: + return "" + for ev in env_vars: + name, value = ev.split("=", 1) + if name == "TEST_DESCRIPTION": + return value + return "" - try: - with open(log, 'r') as f: - log_content = f.read() - except FileNotFoundError as e: - msg = f'{log} file not found, exception: {e}' - return False, msg - except Exception as e: - msg = f'Error while parsing log file {log}: exception: {e}' - return False, msg - - if test_condition and test_condition not in log_content: - msg = f"Test did not succeed, '{test_condition}' not found in log file {log}." - return False, msg - - time1_match = re.search(search_patterns[0], log_content) - time2_match = re.search(search_patterns[1], log_content) - if not(time1_match and time2_match): - msg = f"Processing time not found in log file {log}." - return False, msg - - success = float(time2_match.group(2)) < float(threshold) - if success: - msg = f'{time1_match.group(1)}: {time1_match.group(2)} us\n{time2_match.group(1)}: {time2_match.group(2)} us' - else: - msg = f'{time1_match.group(1)}: {time1_match.group(2)} us\n{time2_match.group(1)}: {time2_match.group(2)} us exceeds a limit of {threshold} us' - - return success,msg - - def analyze_oc_physim(result_junit, details_json): + def analyze_physim(result_junit, details_json, logPath): try: tree = ET.parse(result_junit) root = tree.getroot() @@ -116,7 +77,7 @@ class Analysis(): for test in root: # for each test test_name = test.attrib["name"] test_exec = json_test_desc[test_name]["properties"][1]["value"][0] - desc = json_test_desc[test_name]["properties"][1]["value"][1] + desc = Analysis._get_test_description(json_test_desc[test_name]["properties"]) # get runtime and checks test_check = test.attrib["status"] == "run" time = round(float(test.attrib["time"]), 1) @@ -124,18 +85,21 @@ class Analysis(): output = test.findtext("system-out") output_check = "exceeds the threshold" not in output # collect logs - log_dir = f'../cmake_targets/log/{test_exec}' + log_dir = f'{logPath}/{test_exec}' os.makedirs(log_dir, exist_ok=True) with open(f'{log_dir}/{test_name}.log', 'w') as f: f.write(output) # prepare result and info - info = f"Runtime: {f'{time:.3f}'[:5]} s" resultstr = 'PASS' if (test_check and time_check and output_check) else 'FAIL' + info = f"{test_name}.log: test {resultstr}" + for l in output.splitlines(): + if l.startswith("CHECK "): + info += f"\n{l}" if test_check: if not output_check: - info += " Test log exceeds maximal allowed length 100 kB" + info += "\nTest log exceeds maximal allowed length 100 kB" if not time_check: - info += " Test exceeds 150s" + info += "\nTest exceeds 150s" if not (time_check and output_check): nb_failed += 1 # time threshold/output length error, not counted for by ctest as of now test_result[test_name] = [desc, info, resultstr] diff --git a/ci-scripts/cls_ci_helper.py b/ci-scripts/cls_ci_helper.py new file mode 100644 index 0000000000..eb47a32892 --- /dev/null +++ b/ci-scripts/cls_ci_helper.py @@ -0,0 +1,44 @@ +#/* +# * 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 +# */ + +import os +from typing import NamedTuple +import logging + +class TestCaseCtx(NamedTuple): + count: int + test_id: int + logPath: str + + def Default(logPath): + return TestCaseCtx(123, 112233, logPath) + def baseFilename(self): + # typically, the test ID is of form 001234 (6 digits) + return f"{self.logPath}/{self.count}-{self.test_id:06d}" + +def archiveArtifact(cmd, ctx, remote_path): + base = os.path.basename(remote_path) + local = f"{ctx.baseFilename()}-{base}" + logging.info(f"Archive artifact '{local}'") + success = cmd.copyin(remote_path, local) + if success: + cmd.run(f'rm {remote_path}', silent=True) + return local if success else None diff --git a/ci-scripts/cls_cluster.py b/ci-scripts/cls_cluster.py index 7e88c6b07b..4e13cdf7b3 100644 --- a/ci-scripts/cls_cluster.py +++ b/ci-scripts/cls_cluster.py @@ -34,11 +34,11 @@ import time import os import cls_oai_html -import cls_analysis import constants as CONST import helpreadme as HELP import cls_containerize import cls_cmd +from cls_ci_helper import archiveArtifact IMAGE_REGISTRY_SERVICE_NAME = "image-registry.openshift-image-registry.svc" NAMESPACE = "oaicicd-ran" @@ -68,9 +68,7 @@ def OC_logout(cmd): class Cluster: def __init__(self): - self.eNBIPAddress = "" self.eNBSourceCodePath = "" - self.forcedWorkspaceCleanup = False self.OCUserName = "" self.OCPassword = "" self.OCProjectName = "" @@ -164,24 +162,6 @@ class Cluster: return -1 return int(result.group("size")) - def _deploy_pod(self, filename, timeout = 120): - ret = self.cmd.run(f'oc create -f {filename}') - result = re.search(r'pod/(?P[a-zA-Z0-9_\-]+) created', ret.stdout) - if result is None: - logging.error(f'could not deploy pod: {ret.stdout}') - return None - pod = result.group("pod") - logging.debug(f'checking if pod {pod} is in Running state') - ret = self.cmd.run(f'oc wait --for=condition=ready pod {pod} --timeout={timeout}s', silent=True) - if ret.returncode == 0: - return pod - logging.error(f'pod {pod} did not reach Running state') - self._undeploy_pod(filename) - return None - - def _undeploy_pod(self, filename): - self.cmd.run(f'oc delete -f {filename}') - def PullClusterImage(self, HTML, node, images, tag_prefix): logging.debug(f'Pull OC image {images} to server {node}') self.testCase_id = HTML.testCase_id @@ -207,13 +187,17 @@ class Cluster: HTML.CreateHtmlTestRowQueue(param, 'KO', [msg]) return success - def BuildClusterImage(self, HTML): + def _retrieveOCLog(self, ctx, job, lSourcePath, image): + fn = f'{lSourcePath}/cmake_targets/log/{image}.log' + self.cmd.run(f'oc logs {job} &> {fn}') + return (image, archiveArtifact(self.cmd, ctx, fn)) + + def BuildClusterImage(self, ctx, node, HTML): if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': HELP.GenericHelp(CONST.Version) raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {ranBranch} ranCommitID {self.ranCommitID}') - lIpAddr = self.eNBIPAddress lSourcePath = self.eNBSourceCodePath - if lIpAddr == '' or lSourcePath == '': + if node == '' or lSourcePath == '': raise ValueError('Insufficient Parameter: eNBSourceCodePath missing') ocUserName = self.OCUserName ocPassword = self.OCPassword @@ -224,8 +208,8 @@ class Cluster: if self.OCRegistry.startswith("http") or self.OCRegistry.endswith("/"): raise ValueError(f'ocRegistry {self.OCRegistry} should not start with http:// or https:// and not end on a slash /') - logging.debug(f'Building on cluster triggered from server: {lIpAddr}') - self.cmd = cls_cmd.RemoteCmd(lIpAddr) + logging.debug(f'Building on cluster triggered from server: {node}') + self.cmd = cls_cmd.RemoteCmd(node) self.testCase_id = HTML.testCase_id @@ -280,124 +264,45 @@ class Cluster: self._recreate_entitlements() status = True # flag to abandon compiling if any image fails - attemptedImages = [] + log_files = [] + build_metrics = f"{lSourcePath}/cmake_targets/log/build-metrics.log" if forceBaseImageBuild: self._recreate_is_tag('ran-base', baseTag, 'openshift/ran-base-is.yaml') self._recreate_bc('ran-base', baseTag, 'openshift/ran-base-bc.yaml') ranbase_job = self._start_build('ran-base') - attemptedImages += ['ran-base'] status = ranbase_job is not None and self._wait_build_end([ranbase_job], 1000) if not status: logging.error('failure during build of ran-base') - self.cmd.run(f'oc logs {ranbase_job} &> cmake_targets/log/ran-base.log') # cannot use cmd.run because of redirect - # recover logs by mounting image - self._retag_image_statement('ran-base', 'ran-base', baseTag, 'openshift/ran-base-log-retrieval.yaml') - pod = self._deploy_pod('openshift/ran-base-log-retrieval.yaml') - if pod is not None: - self.cmd.run(f'mkdir -p cmake_targets/log/ran-base') - self.cmd.run(f'oc rsync {pod}:/oai-ran/cmake_targets/log/ cmake_targets/log/ran-base') - self._undeploy_pod('openshift/ran-base-log-retrieval.yaml') - else: - status = False - - if status: - self._recreate_is_tag('oai-physim', imageTag, 'openshift/oai-physim-is.yaml') - self._recreate_bc('oai-physim', imageTag, 'openshift/oai-physim-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.phySim.rhel9') - physim_job = self._start_build('oai-physim') - attemptedImages += ['oai-physim'] - - self._recreate_is_tag('ran-build', imageTag, 'openshift/ran-build-is.yaml') - self._recreate_bc('ran-build', imageTag, 'openshift/ran-build-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.rhel9') - ranbuild_job = self._start_build('ran-build') - attemptedImages += ['ran-build'] - - self._recreate_is_tag('oai-clang', imageTag, 'openshift/oai-clang-is.yaml') - self._recreate_bc('oai-clang', imageTag, 'openshift/oai-clang-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.clang.rhel9') - clang_job = self._start_build('oai-clang') - attemptedImages += ['oai-clang'] - - wait = ranbuild_job is not None and physim_job is not None and clang_job is not None and self._wait_build_end([ranbuild_job, physim_job, clang_job], 1200) - if not wait: logging.error('error during build of ranbuild_job or physim_job or clang_job') - status = status and wait - self.cmd.run(f'oc logs {ranbuild_job} &> cmake_targets/log/ran-build.log') - self.cmd.run(f'oc logs {physim_job} &> cmake_targets/log/oai-physim.log') - self.cmd.run(f'oc logs {clang_job} &> cmake_targets/log/oai-clang.log') - self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log') - - if status: - self._recreate_is_tag('oai-enb', imageTag, 'openshift/oai-enb-is.yaml') - self._recreate_bc('oai-enb', imageTag, 'openshift/oai-enb-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.eNB.rhel9') - self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.eNB.rhel9') - enb_job = self._start_build('oai-enb') - attemptedImages += ['oai-enb'] - - self._recreate_is_tag('oai-gnb', imageTag, 'openshift/oai-gnb-is.yaml') - self._recreate_bc('oai-gnb', imageTag, 'openshift/oai-gnb-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.rhel9') - self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.rhel9') - gnb_job = self._start_build('oai-gnb') - attemptedImages += ['oai-gnb'] - - self._recreate_is_tag('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-is.yaml') - self._recreate_bc('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.aw2s.rhel9') - self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.aw2s.rhel9') - gnb_aw2s_job = self._start_build('oai-gnb-aw2s') - attemptedImages += ['oai-gnb-aw2s'] - - wait = enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([enb_job, gnb_job, gnb_aw2s_job], 800) - if not wait: logging.error('error during build of eNB/gNB') - status = status and wait - # recover logs - self.cmd.run(f'oc logs {enb_job} &> cmake_targets/log/oai-enb.log') - self.cmd.run(f'oc logs {gnb_job} &> cmake_targets/log/oai-gnb.log') - self.cmd.run(f'oc logs {gnb_aw2s_job} &> cmake_targets/log/oai-gnb-aw2s.log') - - self._recreate_is_tag('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-is.yaml') - self._recreate_bc('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nr-cuup.rhel9') - self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nr-cuup.rhel9') - nr_cuup_job = self._start_build('oai-nr-cuup') - attemptedImages += ['oai-nr-cuup'] - - self._recreate_is_tag('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-is.yaml') - self._recreate_bc('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.lteUE.rhel9') - self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.lteUE.rhel9') - lteue_job = self._start_build('oai-lte-ue') - attemptedImages += ['oai-lte-ue'] - - self._recreate_is_tag('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-is.yaml') - self._recreate_bc('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-bc.yaml') - self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nrUE.rhel9') - self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nrUE.rhel9') - nrue_job = self._start_build('oai-nr-ue') - attemptedImages += ['oai-nr-ue'] - - wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 800) - if not wait: logging.error('error during build of nr-cuup/lteUE/nrUE') - status = status and wait - # recover logs - self.cmd.run(f'oc logs {nr_cuup_job} &> cmake_targets/log/oai-nr-cuup.log') - self.cmd.run(f'oc logs {lteue_job} &> cmake_targets/log/oai-lte-ue.log') - self.cmd.run(f'oc logs {nrue_job} &> cmake_targets/log/oai-nr-ue.log') - self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log') + log_files.append(self._retrieveOCLog(ctx, ranbase_job, lSourcePath, 'ran-base')) if status: self._recreate_is_tag('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-is.yaml') self._recreate_bc('ran-build-fhi72', imageTag, 'openshift/ran-build-fhi72-bc.yaml') self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.fhi72.rhel9') ranbuildfhi72_job = self._start_build('ran-build-fhi72') - attemptedImages += ['ran-build-fhi72'] - wait = ranbuildfhi72_job is not None and self._wait_build_end([ranbuildfhi72_job], 1200) - if not wait: logging.error('error during build of ranbuildfhi72_job') + self._recreate_is_tag('oai-physim', imageTag, 'openshift/oai-physim-is.yaml') + self._recreate_bc('oai-physim', imageTag, 'openshift/oai-physim-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.phySim.rhel9') + physim_job = self._start_build('oai-physim') + + self._recreate_is_tag('ran-build', imageTag, 'openshift/ran-build-is.yaml') + self._recreate_bc('ran-build', imageTag, 'openshift/ran-build-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.build.rhel9') + ranbuild_job = self._start_build('ran-build') + + self._recreate_is_tag('oai-clang', imageTag, 'openshift/oai-clang-is.yaml') + self._recreate_bc('oai-clang', imageTag, 'openshift/oai-clang-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.clang.rhel9') + clang_job = self._start_build('oai-clang') + + wait = ranbuildfhi72_job is not None and ranbuild_job is not None and physim_job is not None and clang_job is not None and self._wait_build_end([ranbuildfhi72_job, ranbuild_job, physim_job, clang_job], 1200) + if not wait: logging.error('error during build of ranbuildfhi72_job or ranbuild_job or physim_job or clang_job') status = status and wait - self.cmd.run(f'oc logs {ranbuildfhi72_job} &> cmake_targets/log/ran-build-fhi72.log') - self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log') + log_files.append(self._retrieveOCLog(ctx, ranbuildfhi72_job, lSourcePath, 'ran-build-fhi72')) + log_files.append(self._retrieveOCLog(ctx, ranbuild_job, lSourcePath, 'ran-build')) + log_files.append(self._retrieveOCLog(ctx, physim_job, lSourcePath, 'oai-physim')) + log_files.append(self._retrieveOCLog(ctx, clang_job, lSourcePath, 'oai-clang')) + self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}') if status: self._recreate_is_tag('oai-gnb-fhi72', imageTag, 'openshift/oai-gnb-fhi72-is.yaml') @@ -405,19 +310,65 @@ class Cluster: self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.fhi72.rhel9') self._retag_image_statement('ran-build-fhi72', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build-fhi72', imageTag, 'docker/Dockerfile.gNB.fhi72.rhel9') gnb_fhi72_job = self._start_build('oai-gnb-fhi72') - attemptedImages += ['oai-gnb-fhi72'] - wait = gnb_fhi72_job is not None and self._wait_build_end([gnb_fhi72_job], 600) - if not wait: logging.error('error during build of gNB-fhi72') + self._recreate_is_tag('oai-enb', imageTag, 'openshift/oai-enb-is.yaml') + self._recreate_bc('oai-enb', imageTag, 'openshift/oai-enb-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.eNB.rhel9') + self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.eNB.rhel9') + enb_job = self._start_build('oai-enb') + + self._recreate_is_tag('oai-gnb', imageTag, 'openshift/oai-gnb-is.yaml') + self._recreate_bc('oai-gnb', imageTag, 'openshift/oai-gnb-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.rhel9') + self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.rhel9') + gnb_job = self._start_build('oai-gnb') + + self._recreate_is_tag('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-is.yaml') + self._recreate_bc('oai-gnb-aw2s', imageTag, 'openshift/oai-gnb-aw2s-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.gNB.aw2s.rhel9') + self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.gNB.aw2s.rhel9') + gnb_aw2s_job = self._start_build('oai-gnb-aw2s') + + wait = gnb_fhi72_job is not None and enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([gnb_fhi72_job, enb_job, gnb_job, gnb_aw2s_job], 800) + if not wait: logging.error('error during build of eNB/gNB') status = status and wait # recover logs - self.cmd.run(f'oc logs {gnb_fhi72_job} &> cmake_targets/log/oai-gnb-fhi72.log') - self.cmd.run(f'oc get pods.metrics.k8s.io &>> cmake_targets/log/build-metrics.log') + log_files.append(self._retrieveOCLog(ctx, gnb_fhi72_job, lSourcePath, 'oai-gnb-fhi72')) + log_files.append(self._retrieveOCLog(ctx, enb_job, lSourcePath, 'oai-enb')) + log_files.append(self._retrieveOCLog(ctx, gnb_job, lSourcePath, 'oai-gnb')) + log_files.append(self._retrieveOCLog(ctx, gnb_aw2s_job, lSourcePath, 'oai-gnb-aw2s')) + self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}') + + self._recreate_is_tag('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-is.yaml') + self._recreate_bc('oai-nr-cuup', imageTag, 'openshift/oai-nr-cuup-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nr-cuup.rhel9') + self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nr-cuup.rhel9') + nr_cuup_job = self._start_build('oai-nr-cuup') + + self._recreate_is_tag('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-is.yaml') + self._recreate_bc('oai-lte-ue', imageTag, 'openshift/oai-lte-ue-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.lteUE.rhel9') + self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.lteUE.rhel9') + lteue_job = self._start_build('oai-lte-ue') + + self._recreate_is_tag('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-is.yaml') + self._recreate_bc('oai-nr-ue', imageTag, 'openshift/oai-nr-ue-bc.yaml') + self._retag_image_statement('ran-base', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-base', baseTag, 'docker/Dockerfile.nrUE.rhel9') + self._retag_image_statement('ran-build', 'image-registry.openshift-image-registry.svc:5000/oaicicd-ran/ran-build', imageTag, 'docker/Dockerfile.nrUE.rhel9') + nrue_job = self._start_build('oai-nr-ue') + + wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 800) + if not wait: logging.error('error during build of nr-cuup/lteUE/nrUE') + status = status and wait + # recover logs + log_files.append(self._retrieveOCLog(ctx, nr_cuup_job, lSourcePath, 'oai-nr-cuup')) + log_files.append(self._retrieveOCLog(ctx, lteue_job, lSourcePath, 'oai-lte-ue')) + log_files.append(self._retrieveOCLog(ctx, nrue_job, lSourcePath, 'oai-nr-ue')) + self.cmd.run(f'oc get pods.metrics.k8s.io &>> {build_metrics}') # split and analyze logs imageSize = {} - for image in attemptedImages: - self.cmd.run(f'mkdir -p cmake_targets/log/{image}') + for image, _ in log_files: tag = imageTag if image != 'ran-base' else baseTag size = self._get_image_size(image, tag) if size <= 0: @@ -428,12 +379,14 @@ class Cluster: imageSize[image] = f'{sizeMb:.1f} Mbytes (uncompressed: ~{sizeMb*2.5:.1f} Mbytes)' logging.info(f'\u001B[1m{image} size is {imageSize[image]}\u001B[0m') - grep_exp = r"\|".join(attemptedImages) - self.cmd.run(f'oc get images | grep -e \'{grep_exp}\' &> cmake_targets/log/image_registry.log'); - self.cmd.run(f'for pod in $(oc get pods | tail -n +2 | awk \'{{print $1}}\'); do oc get pod $pod -o json &>> cmake_targets/log/build_pod_summary.log; done') - - build_log_name = f'build_log_{self.testCase_id}' - cls_containerize.CopyLogsToExecutor(self.cmd, lSourcePath, build_log_name) + archiveArtifact(self.cmd, ctx, build_metrics) + logfile = f'{lSourcePath}/cmake_targets/log/image_registry.log' + grep_exp = r"\|".join([i for i,f in log_files]) + self.cmd.run(f'oc get images | grep -e \'{grep_exp}\' &> {logfile}'); + archiveArtifact(self.cmd, ctx, logfile) + logfile = f'{lSourcePath}/cmake_targets/log/build_pod_summary.log' + self.cmd.run(f'for pod in $(oc get pods | tail -n +2 | awk \'{{print $1}}\'); do oc get pod $pod -o json &>> {logfile}; done') + archiveArtifact(self.cmd, ctx, logfile) self.cmd.run('for pod in $(oc get pods | tail -n +2 | awk \'{print $1}\'); do oc delete pod ${pod}; done') @@ -442,55 +395,24 @@ class Cluster: self.cmd.close() # Analyze the logs - collectInfo = cls_containerize.AnalyzeBuildLogs(build_log_name, attemptedImages, status) - for img in collectInfo: - for f in collectInfo[img]: - status = status and collectInfo[img][f]['status'] - if not status: - logging.debug(collectInfo) + collectInfo = {} + for image, lf in log_files: + ret = cls_containerize.AnalyzeBuildLogs(image, lf) + imgStatus = ret['status'] + msg = f"size {imageSize[image]}, analysis of {os.path.basename(lf)}: {ret['errors']} errors, {ret['warnings']} warnings" + HTML.CreateHtmlTestRowQueue(image, 'OK' if imgStatus else 'KO', [msg]) + status = status and imgStatus if status: logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m') - HTML.CreateHtmlTestRow('all', 'OK', CONST.ALL_PROCESSES_OK) else: logging.error('\u001B[1m Building OAI Images Failed\u001B[0m') - HTML.CreateHtmlTestRow('all', 'KO', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, imageSize) + # TODO fix groovy script, remove the following. + # the groovy scripts expects all logs in + # //ci-scripts, so copy it there + with cls_cmd.LocalCmd() as c: + c.run(f'mkdir -p {os.getcwd()}/test_log_{ctx.test_id}/') + c.run(f'cp -r {ctx.logPath} {os.getcwd()}/test_log_{ctx.test_id}/') return status - - def deploy_oc_physim(self, HTML, oc_release, svr_id): - if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': - HELP.GenericHelp(CONST.Version) - raise ValueError(f'Insufficient Parameter: ranRepository {self.ranRepository} ranBranch {self.ranBranch} ranCommitID {self.ranCommitID}') - image_tag = cls_containerize.CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge) - logging.debug(f'Running physims from server: {svr_id}') - script = "scripts/oc-deploy-physims.sh" - options = f"oaicicd-core-for-ci-ran {oc_release} {image_tag} {self.eNBSourceCodePath}" - ret = cls_cmd.runScript(svr_id, script, 600, options) - logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}') - log_dir = f'{os.getcwd()}/../cmake_targets/log' - os.makedirs(log_dir, exist_ok=True) - result_junit = f'{oc_release}-run.xml' - details_json = f'{oc_release}-tests.json' - with cls_cmd.getConnection(svr_id) as ssh: - ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/{details_json}', tgt=f'{log_dir}/{details_json}') - ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/{result_junit}', tgt=f'{log_dir}/{result_junit}') - ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/physim_log.txt', tgt=f'{log_dir}/physim_log.txt') - ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/physim_pods_summary.txt', tgt=f'{log_dir}/physim_pods_summary.txt') - ssh.copyin(src=f'{self.eNBSourceCodePath}/ci-scripts/LastTestsFailed.log', tgt=f'{log_dir}/LastTestsFailed.log') - test_status, test_summary, test_result = cls_analysis.Analysis.analyze_oc_physim(f'{log_dir}/{result_junit}', f'{log_dir}/{details_json}') - if test_summary: - if test_status: - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlTestRowPhySimTestResult(test_summary, test_result) - logging.info('\u001B[1m Physical Simulator Pass\u001B[0m') - else: - HTML.CreateHtmlTestRow('Some test(s) failed!', 'KO', CONST.OC_PHYSIM_DEPLOY_FAIL) - HTML.CreateHtmlTestRowPhySimTestResult(test_summary, test_result) - logging.error('\u001B[1m Physical Simulator Fail\u001B[0m') - else: - HTML.CreateHtmlTestRowQueue('Physical simulator failed', 'KO', [test_result]) - logging.error('\u001B[1m Physical Simulator Fail\u001B[0m') - return test_status diff --git a/ci-scripts/cls_cmd.py b/ci-scripts/cls_cmd.py index fb074bdfce..9916049c11 100644 --- a/ci-scripts/cls_cmd.py +++ b/ci-scripts/cls_cmd.py @@ -45,12 +45,6 @@ def getConnection(host, d=None): else: return RemoteCmd(host, d=d) -def runScript(host, path, timeout, parameters=None, redirect=None, silent=False): - if is_local(host): - return LocalCmd.exec_script(path, timeout, parameters, redirect, silent) - else: - return RemoteCmd.exec_script(host, path, timeout, parameters, redirect, silent) - # provides a partial interface for the legacy SSHconnection class (getBefore(), command()) class Cmd(metaclass=abc.ABCMeta): def cd(self, d, silent=False): @@ -111,12 +105,12 @@ class LocalCmd(Cmd): logging.debug(f'Working dir is {self.cwd}') self.cp = sp.CompletedProcess(args='', returncode=0, stdout='') - def exec_script(path, timeout, parameters=None, redirect=None, silent=False): + def exec_script(self, path, timeout, parameters=None, redirect=None, silent=False): if redirect and not redirect.startswith("/"): raise ValueError(f"redirect must be absolute, but is {redirect}") c = f"{path} {parameters}" if parameters else path if not redirect: - ret = sp.run(c, shell=True, timeout=timeout, stdout=sp.PIPE, stderr=sp.STDOUT) + ret = sp.run(c, shell=True, cwd=self.cwd, timeout=timeout, stdout=sp.PIPE, stderr=sp.STDOUT) ret.stdout = ret.stdout.decode('utf-8').strip() else: with open(redirect, "w") as f: @@ -238,18 +232,15 @@ class RemoteCmd(Cmd): cfg['sock'] = paramiko.ProxyCommand(ucfg['proxycommand']) return cfg - def exec_script(host, path, timeout, parameters=None, redirect=None, silent=False): + def exec_script(self, path, timeout, parameters=None, redirect=None, silent=False): if redirect and not redirect.startswith("/"): raise ValueError(f"redirect must be absolute, but is {redirect}") p = parameters if parameters else "" r = f"> {redirect}" if redirect else "" if not silent: - logging.debug(f"local> ssh {host} bash -s {p} < {path} {r} # {path} from localhost") - client = RemoteCmd._ssh_init() - cfg = RemoteCmd._lookup_ssh_config(host) - client.connect(**cfg) + logging.debug(f"local> ssh {self.hostname} bash -s {p} < {path} {r}") bash_opt = 'BASH_XTRACEFD=1' # write bash set -x output to stdout, see bash(1) - stdin, stdout, stderr = client.exec_command(f"{bash_opt} bash -s {p} {r}", timeout=timeout) + stdin, stdout, stderr = self.client.exec_command(f"{bash_opt} bash -s {p} {r}", timeout=timeout) # open() the file f at path, read() it and write() it into the stdin of the bash -s cmd with open(path) as f: stdin.write(f.read()) @@ -259,7 +250,6 @@ class RemoteCmd(Cmd): if redirect: cmd += f" &> {redirect}" ret = sp.CompletedProcess(args=cmd, returncode=stdout.channel.recv_exit_status(), stdout=stdout.read(size=None) + stderr.read(size=None)) ret.stdout = ret.stdout.decode('utf-8').strip() - client.close() return ret def run(self, line, timeout=300, silent=False, reportNonZero=True): diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index f3d30d6170..c97bb8d4d1 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -46,12 +46,14 @@ import cls_cmd import helpreadme as HELP import constants as CONST import cls_oaicitest +from cls_ci_helper import archiveArtifact #----------------------------------------------------------- # Helper functions used here and in other classes # (e.g., cls_cluster.py) #----------------------------------------------------------- IMAGES = ['oai-enb', 'oai-lte-ru', 'oai-lte-ue', 'oai-gnb', 'oai-nr-cuup', 'oai-gnb-aw2s', 'oai-nr-ue', 'oai-enb-asan', 'oai-gnb-asan', 'oai-lte-ue-asan', 'oai-nr-ue-asan', 'oai-nr-cuup-asan', 'oai-gnb-aerial', 'oai-gnb-fhi72'] +DEFAULT_REGISTRY = "gracehopper3-oai.sboai.cs.eurecom.fr" def CreateWorkspace(host, sourcePath, ranRepository, ranCommitID, ranTargetBranch, ranAllowMerge): if ranCommitID == '': @@ -65,7 +67,8 @@ def CreateWorkspace(host, sourcePath, ranRepository, ranCommitID, ranTargetBranc ranTargetBranch = 'develop' options += f" {ranTargetBranch}" logging.info(f'execute "{script}" with options "{options}" on node {host}') - ret = cls_cmd.runScript(host, script, 90, options) + with cls_cmd.getConnection(host) as c: + ret = c.exec_script(script, 90, options) logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}') return ret.returncode == 0 @@ -81,69 +84,23 @@ def CreateTag(ranCommitID, ranBranch, ranAllowMerge): tagToUse = f'develop-{shortCommit}' return tagToUse -def CopyLogsToExecutor(cmd, sourcePath, log_name): - cmd.cd(f'{sourcePath}/cmake_targets') - cmd.run(f'rm -f {log_name}.zip') - cmd.run(f'mkdir -p {log_name}') - cmd.run(f'mv log/* {log_name}') - cmd.run(f'zip -r -qq {log_name}.zip {log_name}') - - # copy zip to executor for analysis - if (os.path.isfile(f'./{log_name}.zip')): - os.remove(f'./{log_name}.zip') - if (os.path.isdir(f'./{log_name}')): - shutil.rmtree(f'./{log_name}') - cmd.copyin(src=f'{sourcePath}/cmake_targets/{log_name}.zip', tgt=f'{os.getcwd()}/{log_name}.zip') - cmd.run(f'rm -f {log_name}.zip') - ZipFile(f'{log_name}.zip').extractall('.') - -def AnalyzeBuildLogs(buildRoot, images, globalStatus): - collectInfo = {} - for image in images: - files = {} - file_list = [f for f in os.listdir(f'{buildRoot}/{image}') if os.path.isfile(os.path.join(f'{buildRoot}/{image}', f)) and f.endswith('.txt')] - # Analyze the "sub-logs" of every target image - for fil in file_list: - errorandwarnings = {} - warningsNo = 0 - errorsNo = 0 - with open(f'{buildRoot}/{image}/{fil}', mode='r') as inputfile: - for line in inputfile: - result = re.search(' ERROR ', str(line)) - if result is not None: - errorsNo += 1 - result = re.search(' error:', str(line)) - if result is not None: - errorsNo += 1 - result = re.search(' WARNING ', str(line)) - if result is not None: - warningsNo += 1 - result = re.search(' warning:', str(line)) - if result is not None: - warningsNo += 1 - errorandwarnings['errors'] = errorsNo - errorandwarnings['warnings'] = warningsNo - errorandwarnings['status'] = globalStatus - files[fil] = errorandwarnings - # Analyze the target image - if os.path.isfile(f'{buildRoot}/{image}.log'): - errorandwarnings = {} - committed = False - tagged = False - with open(f'{buildRoot}/{image}.log', mode='r') as inputfile: - for line in inputfile: - lineHasTag = re.search(f'Successfully tagged {image}:', str(line)) is not None - lineHasTag2 = re.search(f'naming to docker.io/library/{image}:', str(line)) is not None - tagged = tagged or lineHasTag or lineHasTag2 - # the OpenShift Cluster builder prepends image registry URL - lineHasCommit = re.search(f'COMMIT [a-zA-Z0-9\.:/\-]*{image}', str(line)) is not None - committed = committed or lineHasCommit - errorandwarnings['errors'] = 0 if committed or tagged else 1 - errorandwarnings['warnings'] = 0 - errorandwarnings['status'] = committed or tagged - files['Target Image Creation'] = errorandwarnings - collectInfo[image] = files - return collectInfo +def AnalyzeBuildLogs(image, lf): + errorandwarnings = {} + committed = False + tagged = False + with open(lf, mode='r') as inputfile: + for line in inputfile: + lineHasTag = re.search(f'Successfully tagged {image}:', str(line)) is not None + lineHasTag2 = re.search(f'naming to docker.io/library/{image}:', str(line)) is not None + tagged = tagged or lineHasTag or lineHasTag2 + # the OpenShift Cluster builder prepends image registry URL + lineHasCommit = re.search(r'COMMIT [a-zA-Z0-9\.:/\-]*' + image, str(line)) is not None + committed = committed or lineHasCommit + errorandwarnings['errors'] = 0 if committed or tagged else 1 + errorandwarnings['warnings'] = 0 + errorandwarnings['status'] = committed or tagged + logging.info(f"Analyzing {image}, file {lf}: {errorandwarnings}") + return errorandwarnings def GetImageName(ssh, svcName, file): ret = ssh.run(f"docker compose -f {file} config --format json {svcName} | jq -r '.services.\"{svcName}\".image'", silent=True) @@ -152,19 +109,6 @@ def GetImageName(ssh, svcName, file): else: return ret.stdout.strip() -def GetServiceHealth(ssh, svcName, file): - if svcName is None: - return False, f"Service {svcName} not found in {file}" - image = GetImageName(ssh, svcName, file) - if 'db_init' in svcName or 'db-init' in svcName: # exits with 0, there cannot be healthy - return True, f"Service {svcName} healthy, image {image}" - for _ in range(8): - result = ssh.run(f"docker compose -f {file} ps --format json {svcName} | jq -r 'if type==\"array\" then .[0].Health else .Health end'", silent=True) - if result.stdout == 'healthy': - return True, f"Service {svcName} healthy, image {image}" - time.sleep(5) - return False, f"Failed to deploy: service {svcName}" - def ExistEnvFilePrint(ssh, wd, prompt='env vars in existing'): ret = ssh.run(f'cat {wd}/.env', silent=True, reportNonZero=False) if ret.returncode != 0: @@ -215,12 +159,10 @@ def GetServices(ssh, requested, file): else: return requested -def CopyinServiceLog(ssh, lSourcePath, yaml, svcName, wd_yaml, filename): - remote_filename = f"{lSourcePath}/cmake_targets/log/{filename}" +def CopyinServiceLog(ssh, lSourcePath, svcName, wd_yaml, ctx): + remote_filename = f"{lSourcePath}/cmake_targets/log/{svcName}.logs" ssh.run(f'docker compose -f {wd_yaml} logs {svcName} --no-log-prefix &> {remote_filename}') - local_dir = f"{os.getcwd()}/../cmake_targets/log/{yaml}" - local_filename = f"{local_dir}/{filename}" - return ssh.copyin(remote_filename, local_filename) + return archiveArtifact(ssh, ctx, remote_filename) def GetRunningServices(ssh, file): ret = ssh.run(f'docker compose -f {file} config --services') @@ -242,14 +184,13 @@ def GetRunningServices(ssh, file): logging.info(f'stopping services: {running_services}') return running_services -def CheckLogs(self, yaml, service_name, HTML, RAN): - logPath = f'{os.getcwd()}/../cmake_targets/log/{yaml}' - filename = f'{logPath}/{service_name}-{HTML.testCase_id}.log' +def CheckLogs(self, filename, HTML, RAN): success = True - if (any(sub in service_name for sub in ['oai_ue','oai-nr-ue','lte_ue'])): + name = os.path.basename(filename) + if (any(sub in name for sub in ['oai_ue','oai-nr-ue','lte_ue'])): logging.debug(f'\u001B[1m Analyzing UE logfile {filename} \u001B[0m') logStatus = cls_oaicitest.OaiCiTest().AnalyzeLogFile_UE(filename, HTML, RAN) - opt = f"UE log analysis for service {service_name}" + opt = f"UE log analysis ({name})" # usage of htmlUEFailureMsg/htmleNBFailureMsg is because Analyze log files # abuse HTML to store their reports, and we here want to put custom options, # which is not possible with CreateHtmlTestRow @@ -260,13 +201,13 @@ def CheckLogs(self, yaml, service_name, HTML, RAN): else: HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmlUEFailureMsg]) HTML.htmlUEFailureMsg = "" - elif service_name == 'nv-cubb': + elif 'nv-cubb' in name: msg = 'Undeploy PNF/Nvidia CUBB' HTML.CreateHtmlTestRow(msg, 'OK', CONST.ALL_PROCESSES_OK) - elif (any(sub in service_name for sub in ['enb','rru','rcc','cu','du','gnb'])): + elif (any(sub in name for sub in ['enb','rru','rcc','cu','du','gnb'])): logging.debug(f'\u001B[1m Analyzing XnB logfile {filename}\u001B[0m') logStatus = RAN.AnalyzeLogFile_eNB(filename, HTML, self.ran_checkers) - opt = f"xNB log analysis for service {service_name}" + opt = f"xNB log analysis ({name})" if (logStatus < 0): HTML.CreateHtmlTestRowQueue(opt, 'KO', [HTML.htmleNBFailureMsg]) success = False @@ -274,9 +215,8 @@ def CheckLogs(self, yaml, service_name, HTML, RAN): HTML.CreateHtmlTestRowQueue(opt, 'OK', [HTML.htmleNBFailureMsg]) HTML.htmleNBFailureMsg = "" else: - logging.info(f'Skipping to analyze log for service name {service_name}') - HTML.CreateHtmlTestRowQueue(f"service {service_name}", 'OK', ["no analysis function"]) - logging.debug(f"log check: service {service_name} passed analysis {success}") + logging.info(f"Skipping analysis of log '{filename}': no submatch for xNB/UE") + logging.debug(f"log check: file {filename} passed analysis {success}") return success #----------------------------------------------------------- @@ -291,46 +231,18 @@ class Containerize(): self.ranAllowMerge = False self.ranCommitID = '' self.ranTargetBranch = '' - self.eNBIPAddress = '' - self.eNBUserName = '' - self.eNBPassword = '' self.eNBSourceCodePath = '' - self.eNB1IPAddress = '' - self.eNB1UserName = '' - self.eNB1Password = '' - self.eNB1SourceCodePath = '' - self.eNB2IPAddress = '' - self.eNB2UserName = '' - self.eNB2Password = '' - self.eNB2SourceCodePath = '' - self.forcedWorkspaceCleanup = False self.imageKind = '' self.proxyCommit = None - self.eNB_instance = 0 - self.eNB_serverId = ['', '', ''] - self.yamlPath = ['', '', ''] - self.services = ['', '', ''] + self.yamlPath = '' + self.services = '' self.deploymentTag = '' - self.eNB_logFile = ['', '', ''] - - self.testCase_id = '' self.cli = '' self.cliBuildOptions = '' self.dockerfileprefix = '' self.host = '' - self.deployedContainers = [] - self.tsharkStarted = False - self.pingContName = '' - self.pingOptions = '' - self.pingLossThreshold = '' - self.svrContName = '' - self.svrOptions = '' - self.cliContName = '' - self.cliOptions = '' - - self.imageToCopy = '' #checkers from xml self.ran_checkers={} self.num_attempts = 1 @@ -341,25 +253,11 @@ class Containerize(): # Container management functions #----------------------------------------------------------- - def GetCredentials(self, server_id): - if server_id == '0': - ip, path = self.eNBIPAddress, self.eNBSourceCodePath - elif server_id == '1': - ip, path = self.eNB1IPAddress, self.eNB1SourceCodePath - elif server_id == '2': - ip, path = self.eNB2IPAddress, self.eNB2SourceCodePath - else: - raise ValueError(f"unknown server ID '{server_id}'") - if ip == '' or path == '': - HELP.GenericHelp(CONST.Version) - raise ValueError(f'Insufficient Parameter: IP/node {ip}, path {path}') - return (ip, path) - - def BuildImage(self, HTML): - svr = self.eNB_serverId[self.eNB_instance] - lIpAddr, lSourcePath = self.GetCredentials(svr) - logging.debug('Building on server: ' + lIpAddr) - cmd = cls_cmd.getConnection(lIpAddr) + def BuildImage(self, ctx, node, HTML): + lSourcePath = self.eNBSourceCodePath + logging.debug('Building on server: ' + node) + cmd = cls_cmd.getConnection(node) + log_files = [] # Checking the hostname to get adapted on cli and dockerfileprefixes cmd.run('hostnamectl') @@ -367,7 +265,7 @@ class Containerize(): self.host = result.group(0) if self.host == 'Ubuntu': self.cli = 'docker' - self.dockerfileprefix = '.ubuntu22' + self.dockerfileprefix = '.ubuntu' self.cliBuildOptions = '' elif self.host == 'Red Hat': self.cli = 'sudo podman' @@ -406,16 +304,20 @@ class Containerize(): imageNames.append(('oai-gnb', 'gNB.fhi72', 'oai-gnb-fhi72', '')) result = re.search('build_cross_arm64', self.imageKind) if result is not None: - self.dockerfileprefix = '.ubuntu22.cross-arm64' - result = re.search('native_arm', self.imageKind) + self.dockerfileprefix = '.ubuntu.cross-arm64' + result = re.search('native_armv9', self.imageKind) if result is not None: imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', '')) imageNames.append(('ran-build-fhi72', 'build.fhi72.native_arm', 'ran-build-fhi72', '')) imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup', '')) imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', '')) imageNames.append(('oai-gnb-aerial', 'gNB.aerial', 'oai-gnb-aerial', '')) + result = re.search('native_armv8', self.imageKind) + if result is not None: + imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', '')) + imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup', '')) + imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', '')) - self.testCase_id = HTML.testCase_id cmd.cd(lSourcePath) # if asterix, copy the entitlement and subscription manager configurations if self.host == 'Red Hat': @@ -445,13 +347,17 @@ class Containerize(): # Let's remove any previous run artifacts if still there cmd.run(f"{self.cli} image prune --force") for image,pattern,name,option in imageNames: - cmd.run(f"{self.cli} image rm {name}:{imageTag}") + cmd.run(f"{self.cli} image rm {name}:{imageTag}", reportNonZero=False) # Build the base image only on Push Events (not on Merge Requests) # On when the base image docker file is being modified. if forceBaseImageBuild: cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}") - cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} . &> cmake_targets/log/ran-base.log", timeout=1600) + logfile = f'{lSourcePath}/cmake_targets/log/ran-base.docker.log' + cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} . &> {logfile}", timeout=1600) + t = ("ran-base", archiveArtifact(cmd, ctx, logfile)) + log_files.append(t) + # First verify if the base image was properly created. ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}") allImagesSize = {} @@ -463,10 +369,9 @@ class Containerize(): cmd.close() logging.error('\u001B[1m Building OAI Images Failed\u001B[0m') HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlTabFooter(False) return False else: - result = re.search('Size *= *(?P[0-9\-]+) *bytes', cmd.getBefore()) + result = re.search(r'Size *= *(?P[0-9\-]+) *bytes', cmd.getBefore()) if result is not None: size = float(result.group("size")) / 1000000 imageSizeStr = f'{size:.1f}' @@ -475,17 +380,9 @@ class Containerize(): else: logging.debug('ran-base size is unknown') - # Recover build logs, for the moment only possible when build is successful - cmd.run(f"{self.cli} create --name test {baseImage}:{baseTag}") - cmd.run("mkdir -p cmake_targets/log/ran-base") - cmd.run(f"{self.cli} cp test:/oai-ran/cmake_targets/log/. cmake_targets/log/ran-base") - cmd.run(f"{self.cli} rm -f test") - # Build the target image(s) status = True - attemptedImages = ['ran-base'] for image,pattern,name,option in imageNames: - attemptedImages += [name] # the archived Dockerfiles have "ran-base:latest" as base image # we need to update them with proper tag cmd.run(f'git checkout -- docker/Dockerfile.{pattern}{self.dockerfileprefix}') @@ -498,16 +395,13 @@ class Containerize(): elif image != 'ran-build': cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}') if image == 'oai-gnb-aerial': - cmd.run('cp -f /opt/nvidia-ipc/nvipc_src.*.tar.gz .') - ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > cmake_targets/log/{name}.log 2>&1', timeout=1200) + cmd.run('cp -f /opt/nvidia-ipc/nvipc_src.2025.10.09.tar.gz .') + logfile = f'{lSourcePath}/cmake_targets/log/{name}.docker.log' + ret = cmd.run(f'{self.cli} build {self.cliBuildOptions} --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{self.dockerfileprefix} {option} . > {logfile} 2>&1', timeout=1200) + t = (name, archiveArtifact(cmd, ctx, logfile)) + log_files.append(t) if image == 'oai-gnb-aerial': - cmd.run('rm -f nvipc_src.*.tar.gz') - if image == 'ran-build' and ret.returncode == 0: - cmd.run(f"docker run --name test-log -d {name}:{imageTag} /bin/true") - cmd.run(f"docker cp test-log:/oai-ran/cmake_targets/log/ cmake_targets/log/{name}/") - cmd.run(f"docker rm -f test-log") - else: - cmd.run(f"mkdir -p cmake_targets/log/{name}") + cmd.run('rm -f nvipc_src.2025.10.09.tar.gz') # check the status of the build ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}") if ret.returncode != 0: @@ -518,7 +412,7 @@ class Containerize(): allImagesSize[name] = 'N/A -- Build Failed' break else: - result = re.search('Size *= *(?P[0-9\-]+) *bytes', cmd.getBefore()) + result = re.search(r'Size *= *(?P[0-9\-]+) *bytes', cmd.getBefore()) if result is not None: size = float(result.group("size")) / 1000000 # convert to MB imageSizeStr = f'{size:.1f}' @@ -541,33 +435,27 @@ class Containerize(): logging.debug(cmd.run("df -h").stdout) logging.debug(cmd.run("docker system df").stdout) - # create a zip with all logs - build_log_name = f'build_log_{self.testCase_id}' - CopyLogsToExecutor(cmd, lSourcePath, build_log_name) cmd.close() # Analyze the logs - collectInfo = AnalyzeBuildLogs(build_log_name, attemptedImages, status) + for name, lf in log_files: + ret = AnalyzeBuildLogs(name, lf) + imgStatus = ret['status'] + msg = f"size {allImagesSize[name]}, analysis of {os.path.basename(lf)}: {ret['errors']} errors, {ret['warnings']} warnings" + HTML.CreateHtmlTestRowQueue(name, 'OK' if imgStatus else 'KO', [msg]) + status = status and imgStatus if status: logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m') - HTML.CreateHtmlTestRow(self.imageKind, 'OK', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize) - return True else: logging.error('\u001B[1m Building OAI Images Failed\u001B[0m') - HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize) - HTML.CreateHtmlTabFooter(False) - return False + return status - def BuildProxy(self, HTML): - svr = self.eNB_serverId[self.eNB_instance] - lIpAddr, lSourcePath = self.GetCredentials(svr) - logging.debug('Building on server: ' + lIpAddr) - ssh = cls_cmd.getConnection(lIpAddr) + def BuildProxy(self, ctx, node, HTML): + lSourcePath = self.eNBSourceCodePath + logging.debug('Building on server: ' + node) + ssh = cls_cmd.getConnection(node) - self.testCase_id = HTML.testCase_id oldRanCommidID = self.ranCommitID oldRanRepository = self.ranRepository oldRanAllowMerge = self.ranAllowMerge @@ -589,19 +477,14 @@ class Containerize(): buildProxy = ret.returncode != 0 # if no image, build new proxy if buildProxy: ssh.run(f'rm -Rf {lSourcePath}') - success = CreateWorkspace(lIpAddr, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge) + success = CreateWorkspace(node, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge) if not success: raise Exception("could not clone proxy repository") - filename = f'build_log_{self.testCase_id}' - fullpath = f'{lSourcePath}/{filename}' + fullpath = f'{lSourcePath}/proxy_build.log' ssh.run(f'docker build --target oai-lte-multi-ue-proxy --tag proxy:{tag} --file {lSourcePath}/docker/Dockerfile.ubuntu18.04 {lSourcePath} > {fullpath} 2>&1') - ssh.run(f'zip -r -qq {fullpath}.zip {fullpath}') - local_file = f"{os.getcwd()}/../cmake_targets/log/{filename}.zip" - ssh.copyin(f'{fullpath}.zip', local_file) - # don't delete such that we might recover the zips - #ssh.run(f'rm -f {fullpath}.zip') + archiveArtifact(ssh, ctx, fullpath) ssh.run('docker image prune --force') ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}') @@ -609,7 +492,6 @@ class Containerize(): logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m') ssh.close() HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlTabFooter(False) return False else: logging.debug('L2sim proxy image for tag ' + tag + ' already exists, skipping build') @@ -630,18 +512,8 @@ class Containerize(): self.ranAllowMerge = oldRanAllowMerge self.ranTargetBranch = oldRanTargetBranch - # we do not analyze the logs (we assume the proxy builds fine at this stage), - # but need to have the following information to correctly display the HTML - files = {} - errorandwarnings = {} - errorandwarnings['errors'] = 0 - errorandwarnings['warnings'] = 0 - errorandwarnings['status'] = True - files['Target Image Creation'] = errorandwarnings - collectInfo = {} - collectInfo['proxy'] = files ret = ssh.run(f'docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' proxy:{tag}') - result = re.search('Size *= *(?P[0-9\-]+) *bytes', ret.stdout) + result = re.search(r'Size *= *(?P[0-9\-]+) *bytes', ret.stdout) # Cleaning any created tmp volume ssh.run('docker volume prune --force') ssh.close() @@ -653,21 +525,18 @@ class Containerize(): allImagesSize['proxy'] = str(round(imageSize,1)) + ' Mbytes' logging.info('\u001B[1m Building L2sim Proxy Image Pass\u001B[0m') HTML.CreateHtmlTestRow('commit ' + tag, 'OK', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize) return True else: logging.error('proxy size is unknown') allImagesSize['proxy'] = 'unknown' logging.error('\u001B[1m Build of L2sim proxy failed\u001B[0m') HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlTabFooter(False) return False - def BuildRunTests(self, HTML): - svr = self.eNB_serverId[self.eNB_instance] - lIpAddr, lSourcePath = self.GetCredentials(svr) - logging.debug('Building on server: ' + lIpAddr) - cmd = cls_cmd.RemoteCmd(lIpAddr) + def BuildRunTests(self, ctx, node, HTML): + lSourcePath = self.eNBSourceCodePath + logging.debug('Building on server: ' + node) + cmd = cls_cmd.RemoteCmd(node) cmd.cd(lSourcePath) ret = cmd.run('hostnamectl') @@ -678,10 +547,6 @@ class Containerize(): raise Exception("Can build unit tests only on Ubuntu server") logging.debug('running on Ubuntu as expected') - if self.forcedWorkspaceCleanup: - cmd.run(f'sudo -S rm -Rf {lSourcePath}') - self.testCase_id = HTML.testCase_id - # check that ran-base image exists as we expect it baseImage = 'ran-base' baseTag = 'develop' @@ -695,43 +560,44 @@ class Containerize(): if ret.returncode != 0: logging.error(f'No {baseImage} image present, cannot build tests') HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlTabFooter(False) return False # build ran-unittests image - dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu22" - ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {lSourcePath}/cmake_targets/log/unittest-build.log') + dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu" + logfile = f'{lSourcePath}/cmake_targets/log/unittest-build.log' + ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {logfile}') + archiveArtifact(cmd, ctx, logfile) 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) return False HTML.CreateHtmlTestRowQueue("Build unit tests", 'OK', [dockerfile]) # it worked, build and execute tests, and close connection - ret = cmd.run(f'docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --rm ran-unittests:{baseTag} ctest --output-on-failure --no-label-summary -j$(nproc)') - cmd.run(f'docker rmi ran-unittests:{baseTag}') - build_log_name = f'build_log_{self.testCase_id}' - CopyLogsToExecutor(cmd, lSourcePath, build_log_name) + # I would like to run it with --rm and mount the ctest result directory to avoid 'docker cp' + # below, but then permissions are messed up and we can't remove the directory without sudo + # making the next pipeline fail + ret = cmd.run(f'docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --name ran-unittests ran-unittests:{baseTag} ctest --no-label-summary -j$(nproc)') + cmd.run('docker cp ran-unittests:/oai-ran/build/Testing/Temporary/LastTest.log .') + archiveArtifact(cmd, ctx, f'{lSourcePath}/LastTest.log') + cmd.run('docker cp ran-unittests:/oai-ran/build/Testing/Temporary/LastTestsFailed.log .') + archiveArtifact(cmd, ctx, f'{lSourcePath}/LastTestsFailed.log') + cmd.run('docker rm ran-unittests') cmd.close() if ret.returncode == 0: HTML.CreateHtmlTestRowQueue('Unit tests succeeded', 'OK', [ret.stdout]) - HTML.CreateHtmlTabFooter(True) return True else: HTML.CreateHtmlTestRowQueue('Unit tests failed (see also doc/UnitTests.md)', 'KO', [ret.stdout]) - HTML.CreateHtmlTabFooter(False) return False - def Push_Image_to_Local_Registry(self, HTML, svr_id, tag_prefix=""): - lIpAddr, lSourcePath = self.GetCredentials(svr_id) - logging.debug('Pushing images to server: ' + lIpAddr) - ssh = cls_cmd.getConnection(lIpAddr) - imagePrefix = 'porcepix.sboai.cs.eurecom.fr' + def Push_Image_to_Local_Registry(self, node, HTML, tag_prefix=""): + lSourcePath = self.eNBSourceCodePath + logging.debug('Pushing images to server: ' + node) + ssh = cls_cmd.getConnection(node) + imagePrefix = DEFAULT_REGISTRY ret = ssh.run(f'docker login -u oaicicd -p oaicicd {imagePrefix}') if ret.returncode != 0: msg = 'Could not log into local registry' @@ -802,28 +668,26 @@ class Containerize(): msg = "Pulled Images:\n" + '\n'.join(pulled_images) return True, msg - def Pull_Image_from_Registry(self, HTML, svr_id, images, tag=None, tag_prefix="", registry="porcepix.sboai.cs.eurecom.fr", username="oaicicd", password="oaicicd"): - lIpAddr, lSourcePath = self.GetCredentials(svr_id) - logging.debug('\u001B[1m Pulling image(s) on server: ' + lIpAddr + '\u001B[0m') + def Pull_Image_from_Registry(self, HTML, node, images, tag=None, tag_prefix="", registry=DEFAULT_REGISTRY, username="oaicicd", password="oaicicd"): + logging.debug(f'\u001B[1m Pulling image(s) on server: {node}\u001B[0m') if not tag: tag = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge) - with cls_cmd.getConnection(lIpAddr) as cmd: + with cls_cmd.getConnection(node) as cmd: success, msg = Containerize.Pull_Image(cmd, images, tag, tag_prefix, registry, username, password) - param = f"on node {lIpAddr}" + param = f"on node {node}" if success: HTML.CreateHtmlTestRowQueue(param, 'OK', [msg]) else: HTML.CreateHtmlTestRowQueue(param, 'KO', [msg]) return success - def Clean_Test_Server_Images(self, HTML, svr_id, images, tag=None): - lIpAddr, lSourcePath = self.GetCredentials(svr_id) - logging.debug(f'\u001B[1m Cleaning image(s) from server: {lIpAddr}\u001B[0m') + def Clean_Test_Server_Images(self, HTML, node, images, tag=None): + logging.debug(f'\u001B[1m Cleaning image(s) from server: {node}\u001B[0m') if not tag: tag = CreateTag(self.ranCommitID, self.ranBranch, self.ranAllowMerge) status = True - with cls_cmd.getConnection(lIpAddr) as myCmd: + with cls_cmd.getConnection(node) as myCmd: removed_images = [] for image in images: fullImage = f"oai-ci/{image}:{tag}" @@ -834,34 +698,28 @@ class Containerize(): msg = "Removed Images:\n" + '\n'.join(removed_images) s = 'OK' if status else 'KO' - param = f"on node {lIpAddr}" + param = f"on node {node}" HTML.CreateHtmlTestRowQueue(param, s, [msg]) return status - def Create_Workspace(self,HTML): - svr = self.eNB_serverId[self.eNB_instance] - lIpAddr, lSourcePath = self.GetCredentials(svr) - success = CreateWorkspace(lIpAddr, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge) + def Create_Workspace(self, node, HTML): + lSourcePath = self.eNBSourceCodePath + success = CreateWorkspace(node, lSourcePath, self.ranRepository, self.ranCommitID, self.ranTargetBranch, self.ranAllowMerge) if success: HTML.CreateHtmlTestRowQueue('N/A', 'OK', [f"created workspace {lSourcePath}"]) else: HTML.CreateHtmlTestRowQueue('N/A', 'KO', ["cannot create workspace"]) return success - def DeployObject(self, HTML): - svr = self.eNB_serverId[self.eNB_instance] + def DeployObject(self, ctx, node, HTML): num_attempts = self.num_attempts - lIpAddr, lSourcePath = self.GetCredentials(svr) - logging.debug(f'Deploying OAI Object on server: {lIpAddr}') - yaml = self.yamlPath[self.eNB_instance].strip('/') - # creating the log folder by default - local_dir = f"{os.getcwd()}/../cmake_targets/log/{yaml.split('/')[-1]}" - os.system(f'mkdir -p {local_dir}') + lSourcePath = self.eNBSourceCodePath + logging.debug(f'Deploying OAI Object on server: {node}') + yaml = self.yamlPath.strip('/') wd = f'{lSourcePath}/{yaml}' wd_yaml = f'{wd}/docker-compose.y*ml' - yaml_dir = yaml.split('/')[-1] - with cls_cmd.getConnection(lIpAddr) as ssh: - services = GetServices(ssh, self.services[self.eNB_instance], wd_yaml) + with cls_cmd.getConnection(node) as ssh: + services = GetServices(ssh, self.services, wd_yaml) if services == [] or services == ' ' or services == None: msg = 'Cannot determine services to start' logging.error(msg) @@ -872,52 +730,43 @@ class Containerize(): if num_attempts <= 0: raise ValueError(f'Invalid value for num_attempts: {num_attempts}, must be greater than 0') for attempt in range(num_attempts): - imagesInfo = [] - healthInfo = [] logging.info(f'will start services {services}') - status = ssh.run(f'docker compose -f {wd_yaml} up -d -- {services}') - if status.returncode != 0: + status = ssh.run(f'docker compose -f {wd_yaml} up -d --wait --wait-timeout 60 -- {services}') + info = ssh.run(f"docker compose -f {wd_yaml} ps --all --format=\'table {{{{.Service}}}} [{{{{.Image}}}}] {{{{.Status}}}}\' -- {services} | column -t") + deployed = status.returncode == 0 + if not deployed: msg = f'cannot deploy services {services}: {status.stdout}' logging.error(msg) - HTML.CreateHtmlTestRowQueue('N/A', 'NOK', [msg]) - return False - for svc in services.split(): - health, msg = GetServiceHealth(ssh, svc, f'{wd_yaml}') - logging.info(msg) - imagesInfo.append(msg) - healthInfo.append(health) - deployed = all(healthInfo) - if deployed: + else: break - elif (attempt < num_attempts - 1): - warning_msg = f'Restart services {services}' + if (attempt < num_attempts - 1): + warning_msg = (f'Failed to deploy on attempt {attempt}, restart services {services}') logging.warning(warning_msg) - imagesInfo.append(warning_msg) - HTML.CreateHtmlTestRowQueue('N/A', 'NOK', ['\n'.join(imagesInfo)]) + HTML.CreateHtmlTestRowQueue('N/A', 'NOK', [warning_msg]) for svc in services.split(): - CopyinServiceLog(ssh, lSourcePath, yaml_dir, svc, wd_yaml, f'{svc}-{HTML.testCase_id}-attempt{attempt}.log') + CopyinServiceLog(ssh, lSourcePath, svc, wd_yaml, ctx) ssh.run(f'docker compose -f {wd_yaml} down -- {services}') + imagesInfo = info.stdout.splitlines()[1:] + logging.debug(f'{info.stdout.splitlines()[1:]}') if deployed: HTML.CreateHtmlTestRowQueue('N/A', 'OK', ['\n'.join(imagesInfo)]) else: HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['\n'.join(imagesInfo)]) return deployed - def UndeployObject(self, HTML, RAN): - svr = self.eNB_serverId[self.eNB_instance] - lIpAddr, lSourcePath = self.GetCredentials(svr) - logging.debug(f'\u001B[1m Undeploying OAI Object from server: {lIpAddr}\u001B[0m') - yaml = self.yamlPath[self.eNB_instance].strip('/') + def UndeployObject(self, ctx, node, HTML, RAN): + lSourcePath = self.eNBSourceCodePath + logging.debug(f'\u001B[1m Undeploying OAI Object from server: {node}\u001B[0m') + yaml = self.yamlPath.strip('/') wd = f'{lSourcePath}/{yaml}' - yaml_dir = yaml.split('/')[-1] - with cls_cmd.getConnection(lIpAddr) as ssh: + with cls_cmd.getConnection(node) as ssh: ExistEnvFilePrint(ssh, wd) services = GetRunningServices(ssh, f"{wd}/docker-compose.y*ml") copyin_res = None if services is not None: all_serv = " ".join([s for s, _ in services]) ssh.run(f'docker compose -f {wd}/docker-compose.y*ml stop -- {all_serv}') - copyin_res = all(CopyinServiceLog(ssh, lSourcePath, yaml_dir, s, f"{wd}/docker-compose.y*ml", f'{s}-{HTML.testCase_id}.log') for s, c in services) + copyin_res = [CopyinServiceLog(ssh, lSourcePath, s, f"{wd}/docker-compose.y*ml", ctx) for s, _ in services] else: logging.warning('could not identify services to stop => no log file') ssh.run(f'docker compose -f {wd}/docker-compose.y*ml down -v') @@ -926,7 +775,7 @@ class Containerize(): HTML.CreateHtmlTestRowQueue('N/A', 'KO', ['Could not copy logfile(s)']) return False else: - log_results = [CheckLogs(self, yaml_dir, s, HTML, RAN) for s, _ in services] + log_results = [CheckLogs(self, f, HTML, RAN) for f in copyin_res] success = all(log_results) if success: logging.info('\u001B[1m Undeploying OAI Object Pass\u001B[0m') diff --git a/ci-scripts/cls_corenetwork.py b/ci-scripts/cls_corenetwork.py index 579bad585b..bfdaa77481 100644 --- a/ci-scripts/cls_corenetwork.py +++ b/ci-scripts/cls_corenetwork.py @@ -29,6 +29,7 @@ import yaml import re import cls_cmd +from cls_ci_helper import archiveArtifact def listify(s): if s is None: @@ -76,7 +77,8 @@ class CoreNetwork: words = line[1:].strip().split(" ") script_name = words[0] options = " ".join(words[1:]) - ret = cls_cmd.runScript(host, script_name, 300, parameters=options, silent=silent) + with cls_cmd.getConnection(host) as c: + ret = c.exec_script(script_name, 300, parameters=options, silent=silent) return ret def _command(self, cmd_list, must_succeed=False, silent=False): @@ -114,8 +116,7 @@ class CoreNetwork: logging.info(f'deployed core network {self}, pingable IP address {ip}') return True, output - def _collect_logs(self, log_dir): - logging.info(f'collecting logs into (local) {log_dir}') + def _collect_logs(self, ctx): remote_dir = "/tmp/cn-undeploy-logs" with cls_cmd.getConnection(self._host) as c: # create a directory for log collection @@ -134,18 +135,17 @@ class CoreNetwork: logging.error("cannot enumerate log files") return [] log_files = [] - # copy them to the executor one by one, and store in log_dir + # copy them to the executor one by one for f in ret.stdout.split("\n"): - l = f.replace(remote_dir, log_dir) - c.copyin(f, l) - log_files.append(l) + name = archiveArtifact(c, ctx, f) + log_files.append(name) c.run(f'rm -rf {remote_dir}') return log_files - def undeploy(self, log_dir=None): + def undeploy(self, ctx=None): log_files = [] - if log_dir is not None: - log_files = self._collect_logs(log_dir) + if ctx is not None: + log_files = self._collect_logs(ctx) else: logging.warning("no directory for log collection specified, cannot retrieve core network logs") logging.info(f'undeploy core network {self}') diff --git a/ci-scripts/cls_module.py b/ci-scripts/cls_module.py index 3ec6ffc9e5..cfdd96477f 100644 --- a/ci-scripts/cls_module.py +++ b/ci-scripts/cls_module.py @@ -32,6 +32,7 @@ import re import yaml import cls_cmd +from cls_ci_helper import archiveArtifact class Module_UE: @@ -59,26 +60,31 @@ class Module_UE: } self.interface = m.get('IF') self.MTU = m.get('MTU') - self.trace = m.get('trace') == True - self.logStore = m.get('LogStore') self.cmd_prefix = m.get('CmdPrefix') logging.info(f'initialized UE {self} from {filename}') + t = m.get('Tracing') + self.trace = t is not None + if self.trace: + if t.get('Start') is None or t.get('Stop') is None or t.get('Collect')is None : + raise ValueError("need to have Start/Stop/Collect for tracing") + self.cmd_dict["traceStart"] = t.get('Start') + self.cmd_dict["traceStop"] = t.get('Stop') + self._logCollect = t.get('Collect') + if "%%log_dir%%" not in self._logCollect: + raise ValueError(f"(At least one) LogCollect expression for {module_name} must contain \"%%log_dir%%\"") + def __str__(self): - return f"{self.module_name}@{self.host} [IP: {self.getIP()}]" + return f"{self.module_name}@{self.host}" def __repr__(self): return self.__str__() - def _command(self, cmd, silent = False): + def _command(self, cmd, silent=False, reportNonZero=True): if cmd is None: raise Exception("no command provided") - if self.host == "" or self.host == "localhost": - c = cls_cmd.LocalCmd() - else: - c = cls_cmd.RemoteCmd(self.host) - response = c.run(cmd, silent=silent) - c.close() + with cls_cmd.getConnection(self.host) as c: + response = c.run(cmd, silent=silent, reportNonZero=reportNonZero) return response #-----------------$ @@ -86,25 +92,23 @@ class Module_UE: #-----------------$ def initialize(self): - if self.trace: - raise Exception("UE tracing not implemented yet") - self._enableTrace() # we first terminate to make sure the UE has been stopped if self.cmd_dict["detach"]: self._command(self.cmd_dict["detach"], silent=True) self._command(self.cmd_dict["terminate"], silent=True) ret = self._command(self.cmd_dict["initialize"]) logging.info(f'For command: {ret.args} | return output: {ret.stdout} | Code: {ret.returncode}') + if self.trace: + self._enableTrace() # Here each UE returns differently for the successful initialization, requires check based on UE return ret.returncode == 0 - def terminate(self): + def terminate(self, ctx=None): self._command(self.cmd_dict["terminate"]) - if self.trace: - raise Exception("UE tracing not implemented yet") + if self.trace and ctx is not None: self._disableTrace() - return self._logCollect() + return self._collectTrace(ctx) return None def attach(self, attach_tries = 4, attach_timeout = 60): @@ -113,10 +117,11 @@ class Module_UE: self._command(self.cmd_dict["attach"]) timeout = attach_timeout logging.debug("Waiting for IP address to be assigned") + ip = self.getIP(silent=False, reportNonZero=True) while timeout > 0 and not ip: - time.sleep(5) - timeout -= 5 - ip = self.getIP() + time.sleep(1) + timeout -= 1 + ip = self.getIP(silent=True, reportNonZero=False) if ip: break logging.warning(f"UE did not receive IP address after {attach_timeout} s, detaching") @@ -160,8 +165,8 @@ class Module_UE: logging.error(message) return False - def getIP(self): - output = self._command(self.cmd_dict["getNetwork"], silent=True) + def getIP(self, silent=True, reportNonZero=True): + output = self._command(self.cmd_dict["getNetwork"], silent=silent, reportNonZero=reportNonZero) result = re.search(r'inet (?P[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)', output.stdout) if result and result.group('ip'): ip = result.group('ip') @@ -191,10 +196,33 @@ class Module_UE: return self.cmd_prefix if self.cmd_prefix else "" def _enableTrace(self): - raise Exception("not implemented") + logging.info(f'UE {self}: start UE tracing') + self._command(self.cmd_dict["traceStart"]) def _disableTrace(self): - raise Exception("not implemented") + logging.info(f'UE {self}: stop UE tracing') + self._command(self.cmd_dict["traceStop"]) - def _logCollect(self): - raise Exception("not implemented") + def _collectTrace(self, ctx): + remote_dir = "/tmp/ue-trace-logs" + with cls_cmd.getConnection(self.host) as c: + # create a directory for log collection + c.run(f'rm -rf {remote_dir}') + ret = c.run(f'mkdir {remote_dir}') + if ret.returncode != 0: + logging.error("cannot create directory for log collection") + return [] + log_cmd = self._logCollect.replace('%%log_dir%%', remote_dir) + self._command(log_cmd) + # enumerate collected files + ret = c.run(f'ls {remote_dir}/*') + if ret.returncode != 0: + logging.error("cannot enumerate log files") + return [] + log_files = [] + # copy them to the executor one by one, and store in log_dir + for f in ret.stdout.split("\n"): + name = archiveArtifact(c, ctx, f) + log_files.append(name) + c.run(f'rm -rf {remote_dir}') + return log_files diff --git a/ci-scripts/cls_native.py b/ci-scripts/cls_native.py index 8f4d90ea84..d96f60bdca 100644 --- a/ci-scripts/cls_native.py +++ b/ci-scripts/cls_native.py @@ -28,26 +28,24 @@ import cls_cmd import cls_oai_html import cls_analysis import constants as CONST +from cls_ci_helper import archiveArtifact -LOG_PATH_PHYSIM = 'phy_sim_logs' +DPDK_PATH = '/opt/dpdk-t2-22.11.0' class Native(): - def Build(test_case, HTML, host, directory, options): - logging.debug(f'Building on server: {host}') + def Build(ctx, node, test_case, HTML, directory, options): + logging.debug(f'Building on server: {node}') HTML.testCase_id = test_case - with cls_cmd.getConnection(host) as ssh: + with cls_cmd.getConnection(node) as ssh: base = f"{directory}/cmake_targets" - ret = ssh.run(f"{base}/build_oai {options} > {base}/log/build_oai.log", timeout=900) + ret = ssh.run(f"C_INCLUDE_PATH={DPDK_PATH}/include/ PKG_CONFIG_PATH={DPDK_PATH}/lib64/pkgconfig/ {base}/build_oai {options} > {base}/build_oai.log", timeout=900) success = ret.returncode == 0 - logs = ssh.run(f"cat {base}/log/build_oai.log", silent=True) - logging.debug(f"build finished with code {ret.returncode}, output:\n{logs.stdout}") + logs = ssh.run(f"cat {base}/build_oai.log", silent=True) + logging.debug(f"build finished with code {ret.returncode}") - # create log directory, and copy build logs - target = f"{base}/build_log_{test_case}/" - ssh.run(f"mkdir -p {target}") - ssh.run(f"mv {base}/log/* {target}") + archiveArtifact(ssh, ctx, f'{base}/build_oai.log') # check if build artifacts are there # NOTE: build_oai should fail with exit code if it could not build, but it does not @@ -66,19 +64,3 @@ class Native(): logging.error('\u001B[1m Building OAI Failed\u001B[0m') HTML.CreateHtmlTestRow(options, 'KO', CONST.ALL_PROCESSES_OK) return success - - def Run_Physim(HTML, host, directory, options, physim_test, threshold): - logging.debug(f'Runnin {physim_test} on server: {host}') - workSpacePath = f'{directory}/cmake_targets' - os.system(f'mkdir -p ./{LOG_PATH_PHYSIM}') - runLogFile=f'physim_{HTML.testCase_id}.log' - with cls_cmd.getConnection(host) as cmd: - cmd.run(f'sudo {workSpacePath}/ran_build/build/{physim_test} {options} >> {workSpacePath}/{runLogFile}') - cmd.copyin(src=f'{workSpacePath}/{runLogFile}', tgt=f'{LOG_PATH_PHYSIM}/{runLogFile}') - success, msg = cls_analysis.Analysis.analyze_physim(f'{LOG_PATH_PHYSIM}/{runLogFile}', physim_test, options, threshold) - if success: - HTML.CreateHtmlTestRowQueue(options, 'OK', [msg]) - else: - logging.error(msg) - HTML.CreateHtmlTestRowQueue(options, 'KO', [msg]) - return success diff --git a/ci-scripts/cls_oai_html.py b/ci-scripts/cls_oai_html.py index 478cbd1860..cb1ca56542 100644 --- a/ci-scripts/cls_oai_html.py +++ b/ci-scripts/cls_oai_html.py @@ -70,16 +70,6 @@ class HTMLManagement(): self.testCase_id = '' self.desc = '' - self.OsVersion = ['', ''] - self.KernelVersion = ['', ''] - self.UhdVersion = ['', ''] - self.UsrpBoard = ['', ''] - self.CpuNb = ['', ''] - self.CpuModel = ['', ''] - self.CpuMHz = ['', ''] - - - #----------------------------------------------------------- # HTML structure creation functions #----------------------------------------------------------- @@ -224,7 +214,6 @@ class HTMLManagement(): self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.close() - time.sleep(1) if passStatus: cmd = "sed -i -e 's/__STATE_" + self.htmlTabNames[0] + "__//' test_results.html" subprocess.run(cmd, shell=True) @@ -258,7 +247,7 @@ class HTMLManagement(): self.htmlFile.write(' \n') self.htmlFile.write(' \n') self.htmlFile.write('

\n') - self.htmlFile.write('
End of Test Report -- Copyright 2018 OpenAirInterface. All Rights Reserved.
\n') + self.htmlFile.write('
End of Test Report -- Copyright 2025 OpenAirInterface. All Rights Reserved.
\n') self.htmlFile.write('\n') self.htmlFile.write('\n') self.htmlFile.close() @@ -343,58 +332,6 @@ class HTMLManagement(): self.htmlFile.write(' \n') self.htmlFile.close() - - def CreateHtmlNextTabHeaderTestRow(self, collectInfo, allImagesSize, machine='eNB'): - if (self.htmlFooterCreated or (not self.htmlHeaderCreated)): - return - self.htmlFile = open('test_results.html', 'a') - if bool(collectInfo) == False: - self.htmlFile.write(' \n') - self.htmlFile.write(' ----IMAGES BUILDING FAILED - Unable to recover the image logs ---- \n') - self.htmlFile.write(' \n') - else: - for image in collectInfo: - files = collectInfo[image] - # TabHeader for image logs on built shared and target images - if allImagesSize[image].count('unknown') > 0: - self.htmlFile.write(' \n') - elif allImagesSize[image].count('Build Failed') > 0: - self.htmlFile.write(' \n') - else: - self.htmlFile.write(' \n') - self.htmlFile.write(' ---- ' + image + ' IMAGE STATUS ----> Size ' + allImagesSize[image] + ' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Element\n') - self.htmlFile.write(' Nb Errors\n') - self.htmlFile.write(' Nb Warnings\n') - self.htmlFile.write(' Status\n') - self.htmlFile.write(' \n') - - for fil in files: - parameters = files[fil] - # TestRow for image logs on built shared and target images - self.htmlFile.write(' \n') - self.htmlFile.write(' ' + fil + ' \n') - if (parameters['errors'] == 0): - self.htmlFile.write(' ' + str(parameters['errors']) + '\n') - else: - self.htmlFile.write(' ' + str(parameters['errors']) + '\n') - if (parameters['errors'] > 0): - self.htmlFile.write(' ' + str(parameters['warnings']) + '\n') - elif (parameters['warnings'] == 0): - self.htmlFile.write(' ' + str(parameters['warnings']) + '\n') - else: - self.htmlFile.write(' ' + str(parameters['warnings']) + '\n') - if (parameters['errors'] == 0) and (parameters['warnings'] == 0): - self.htmlFile.write(' OK \n') - elif (parameters['errors'] == 0): - self.htmlFile.write(' OK \n') - else: - self.htmlFile.write(' NOT OK \n') - self.htmlFile.write(' \n') - self.htmlFile.close() - #for the moment it is limited to 4 columns, to be made generic later def CreateHtmlDataLogTable(self, DataLog): if (self.htmlFooterCreated or (not self.htmlHeaderCreated)): @@ -596,6 +533,6 @@ class HTMLManagement(): self.htmlFile.write(' ' + value[2] + '\n') else: self.htmlFile.write(' ' + value[2] + '\n') - self.htmlFile.write(' ' + value[1] + '\n') + self.htmlFile.write(f'
{value[1]}
\n') self.htmlFile.close() diff --git a/ci-scripts/cls_oaicitest.py b/ci-scripts/cls_oaicitest.py index 4d7cf0a6fd..2b31f41064 100644 --- a/ci-scripts/cls_oaicitest.py +++ b/ci-scripts/cls_oaicitest.py @@ -46,7 +46,9 @@ import constants as CONST import cls_module import cls_corenetwork +import cls_analysis import cls_cmd +from cls_ci_helper import archiveArtifact #----------------------------------------------------------- # Helper functions used here and in other classes @@ -83,6 +85,29 @@ def Iperf_ComputeTime(args): raise Exception('Iperf time not found!') return int(result.group('iperf_time')) +def convert_to_mbps(value, magnitude): + value = float(value) + if magnitude == 'K' or magnitude == 'k': + return value / 1000 + elif magnitude == 'M': + return value + elif magnitude == 'G': + return value * 1000 + else: + return value + +def extract_iperf_data(res): + if not res: + return None + bitrate_val = res.group('bitrate') + magnitude = res.group('magnitude') + return { + 'bitrate_mbps': convert_to_mbps(bitrate_val, magnitude), + 'jitter': res.group('jitter'), + 'packetloss': res.group('packetloss'), + 'bitrate_disp': f'{float(bitrate_val):.2f} {magnitude}bps' + } + def Iperf_analyzeV3TCPJson(filename, iperf_tcp_rate_target): try: with open(filename) as f: @@ -130,54 +155,37 @@ def Iperf_analyzeV3BIDIRJson(filename): return (True, msg) def Iperf_analyzeV3UDP(filename, iperf_bitrate_threshold, iperf_packetloss_threshold, target_bitrate): - if (not os.path.isfile(filename)): + if not os.path.isfile(filename): return (False, 'Iperf3 UDP: Log file not present') - if (os.path.getsize(filename)==0): + if os.path.getsize(filename) == 0: return (False, 'Iperf3 UDP: Log file is empty') - sender_bitrate = None - receiver_bitrate = None - with open(filename, 'r') as server_file: - for line in server_file.readlines(): - res_sender = re.search(r'(?P[0-9\.]+)\s+(?P[KMG]?bits\/sec)\s+(?P[0-9\.]+\s+ms)\s+(?P-?\d+)/(?P-?\d+) \((?P[0-9\.]+).*?\s+(sender)', line) - res_receiver = re.search(r'(?P[0-9\.]+)\s+(?P[KMG]?bits\/sec)\s+(?P[0-9\.]+\s+ms)\s+(?P-?\d+)/(?P-?\d+)\s+\((?P[0-9\.]+)%\).*?(receiver)', line) - if res_sender is not None: - sender_bitrate = res_sender.group('bitrate') - sender_unit = res_sender.group('unit') - sender_jitter = res_sender.group('jitter') - sender_lostPack = res_sender.group('lostPack') - sender_sentPack = res_sender.group('sentPack') - sender_packetloss = res_sender.group('lost') - if res_receiver is not None: - receiver_bitrate = res_receiver.group('bitrate') - receiver_unit = res_receiver.group('unit') - receiver_jitter = res_receiver.group('jitter') - receiver_lostPack = res_receiver.group('lostPack') - receiver_receivedPack = res_receiver.group('receivedPack') - receiver_packetloss = res_receiver.group('lost') - if receiver_bitrate is not None and sender_bitrate is not None: - if sender_unit == 'Kbits/sec': - sender_bitrate = float(sender_bitrate) / 1000 - if receiver_unit == 'Kbits/sec': - receiver_bitrate = float(receiver_bitrate) / 1000 - br_perf = 100 * float(receiver_bitrate) / float(target_bitrate) - br_perf = '%.2f ' % br_perf - sender_bitrate = '%.2f ' % float(sender_bitrate) - receiver_bitrate = '%.2f ' % float(receiver_bitrate) - req_msg = f'Sender Bitrate : {sender_bitrate} Mbps' - bir_msg = f'Receiver Bitrate: {receiver_bitrate} Mbps' - brl_msg = f'{br_perf}%' - jit_msg = f'Jitter : {receiver_jitter}' - pal_msg = f'Packet Loss : {receiver_packetloss} %' - if float(br_perf) < float(iperf_bitrate_threshold): - brl_msg = f'too low! < {iperf_bitrate_threshold}%' - if float(receiver_packetloss) > float(iperf_packetloss_threshold): - pal_msg += f' (too high! > {iperf_packetloss_threshold}%)' - result = float(br_perf) >= float(iperf_bitrate_threshold) and float(receiver_packetloss) <= float(iperf_packetloss_threshold) - return (result, f'{req_msg}\n{bir_msg} ({brl_msg})\n{jit_msg}\n{pal_msg}') - else: + sender_data = None + receiver_data = None + with open(filename, 'r') as server_file: + for line in server_file: + res_sender = re.search(r'(?P[0-9\.]+)\s+(?P[kKMG]?)bits\/sec\s+(?P[0-9\.]+\s+ms)\s+(?P-?\d+)/(?P-?\d+)\s+\((?P[0-9\.eE\-\+]+).*?\s+(sender)', line) + res_receiver = re.search(r'(?P[0-9\.]+)\s+(?P[kKMG]?)bits\/sec\s+(?P[0-9\.]+\s+ms)\s+(?P-?\d+)/(?P-?\d+)\s+\((?P[0-9\.eE\-\+]+)%\).*?(receiver)', line) + if res_sender: + sender_data = extract_iperf_data(res_sender) + if res_receiver: + receiver_data = extract_iperf_data(res_receiver) + if not sender_data or not receiver_data: return (False, 'Could not analyze iperf report') + br_perf = 100 * receiver_data['bitrate_mbps'] / float(target_bitrate) + br_perf_str = f'{br_perf:.2f}%' + req_msg = f"Sender Bitrate : {sender_data['bitrate_disp']}" + bir_msg = f"Receiver Bitrate: {receiver_data['bitrate_disp']} ({br_perf_str})" + jit_msg = f"Jitter : {receiver_data['jitter']}" + pal_msg = f"Packet Loss : {receiver_data['packetloss']}%" + if br_perf < float(iperf_bitrate_threshold): + bir_msg += f' (too low! < {iperf_bitrate_threshold}%)' + if float(receiver_data['packetloss']) > float(iperf_packetloss_threshold): + pal_msg += f' (too high! > {iperf_packetloss_threshold}%)' + result = br_perf >= float(iperf_bitrate_threshold) and float(receiver_data['packetloss']) <= float(iperf_packetloss_threshold) + return (result, f'{req_msg}\n{bir_msg}\n{jit_msg}\n{pal_msg}') + def Iperf_analyzeV2UDP(server_filename, iperf_bitrate_threshold, iperf_packetloss_threshold, target_bitrate): result = None if (not os.path.isfile(server_filename)): @@ -190,12 +198,9 @@ def Iperf_analyzeV2UDP(server_filename, iperf_bitrate_threshold, iperf_packetlos result = re.search(statusTemplate, str(line)) or result if result is None: return (False, 'Could not parse server report!') - bitrate = float(result.group('bitrate')) - magn = result.group('magnitude') - if magn == "k" or magn == "K": - bitrate /= 1000 - elif magn == "G": # we assume bitrate in Mbps, therefore it must be G now - bitrate *= 1000 + bitrate_val = float(result.group('bitrate')) + magnitude = result.group('magnitude') + bitrate = convert_to_mbps(bitrate_val, magnitude) jitter = float(result.group('jitter')) packetloss = float(result.group('packetloss')) br_perf = float(bitrate)/float(target_bitrate) * 100 @@ -213,7 +218,7 @@ def Iperf_analyzeV2UDP(server_filename, iperf_bitrate_threshold, iperf_packetlos pal_msg += f' (too high! >{iperf_packetloss_threshold}%)' return (result, f'{req_msg}\n{bir_msg}\n{brl_msg}\n{jit_msg}\n{pal_msg}') -def Custom_Command(HTML, node, command, command_fail): +def Custom_Command(HTML, node, command): logging.info(f"Executing custom command on {node}") cmd = cls_cmd.getConnection(node) ret = cmd.run(command) @@ -221,35 +226,59 @@ def Custom_Command(HTML, node, command, command_fail): logging.debug(f"Custom_Command: {command} on node: {node} - {'OK, command succeeded' if ret.returncode == 0 else f'Error, return code: {ret.returncode}'}") status = 'OK' message = [] - if ret.returncode != 0 and not command_fail: - message = [ret.stdout] - logging.warning(f'Custom_Command output: {message}') - status = 'Warning' - if ret.returncode != 0 and command_fail: + if ret.returncode != 0: message = [ret.stdout] logging.error(f'Custom_Command failed: output: {message}') status = 'KO' HTML.CreateHtmlTestRowQueue(command, status, message) return status == 'OK' or status == 'Warning' -def Custom_Script(HTML, node, script, command_fail): +def Custom_Script(HTML, node, script): logging.info(f"Executing custom script on {node}") - ret = cls_cmd.runScript(node, script, 90) + with cls_cmd.getConnection(node) as c: + ret = c.exec_script(script, 90) logging.debug(f"Custom_Script: {script} on node: {node} - return code {ret.returncode}, output:\n{ret.stdout}") status = 'OK' message = [ret.stdout] - if ret.returncode != 0 and not command_fail: - status = 'Warning' - if ret.returncode != 0 and command_fail: + if ret.returncode != 0: status = 'KO' HTML.CreateHtmlTestRowQueue(script, status, message) return status == 'OK' or status == 'Warning' def IdleSleep(HTML, idle_sleep_time): + logging.debug(f"sleep for {idle_sleep_time} seconds") time.sleep(idle_sleep_time) HTML.CreateHtmlTestRow(f"{idle_sleep_time} sec", 'OK', CONST.ALL_PROCESSES_OK) return True +def Deploy_Physim(ctx, HTML, node, workdir, script, options): + logging.debug(f'Running physims on server {node} workdir {workdir}') + with cls_cmd.getConnection(node) as c: + sys_info = c.exec_script("scripts/sys-info.sh", 5) + ret = c.exec_script(script, 1000, options) + logging.debug(f'"{script}" finished with code {ret.returncode}, output:\n{ret.stdout}') + HTML.CreateHtmlTestRowQueue('Query system info', 'OK', [sys_info.stdout]) + with cls_cmd.getConnection(node) as ssh: + details_json = archiveArtifact(ssh, ctx, f'{workdir}/desc-tests.json') + result_junit = archiveArtifact(ssh, ctx, f'{workdir}/results-run.xml') + archiveArtifact(ssh, ctx, f'{workdir}/physim_log.txt') + archiveArtifact(ssh, ctx, f'{workdir}/LastTestsFailed.log') + archiveArtifact(ssh, ctx, f'{workdir}/LastTest.log') + test_status, test_summary, test_result = cls_analysis.Analysis.analyze_physim(result_junit, details_json, ctx.logPath) + if test_summary: + if test_status: + HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) + HTML.CreateHtmlTestRowPhySimTestResult(test_summary, test_result) + logging.info('\u001B[1m Physical Simulator Pass\u001B[0m') + else: + HTML.CreateHtmlTestRowQueue('At least one physical simulator test failed!', 'KO', ["See below for details"]) + HTML.CreateHtmlTestRowPhySimTestResult(test_summary, test_result) + logging.error('\u001B[1m Physical Simulator Fail\u001B[0m') + else: + HTML.CreateHtmlTestRowQueue('Physical simulator failed', 'KO', [test_result]) + logging.error('\u001B[1m Physical Simulator Fail\u001B[0m') + return test_status + #----------------------------------------------------------- # OaiCiTest Class Definition #----------------------------------------------------------- @@ -262,9 +291,7 @@ class OaiCiTest(): self.ranAllowMerge = False self.ranTargetBranch = '' - self.testCase_id = '' self.testXMLfiles = [] - self.desc = '' self.ping_args = '' self.ping_packetloss_threshold = '' self.ping_rttavg_threshold ='' @@ -358,7 +385,7 @@ class OaiCiTest(): HTML.CreateHtmlTestRowQueue('NA', 'OK', messages) return True - def Ping_common(self, cn, ue, logPath): + def Ping_common(self, ctx, cn, ue): ping_status = 0 ueIP = ue.getIP() if not ueIP: @@ -366,13 +393,12 @@ class OaiCiTest(): svrIP = cn.getIP() if not svrIP: return (False, f"CN {cn.getName()} has no IP address") - ping_log_file = f'ping_{self.testCase_id}_{ue.getName()}.log' + ping_log_file = f'/tmp/ping_{ue.getName()}.log' ping_time = re.findall(r"-c *(\d+)",str(self.ping_args)) - local_ping_log_file = f'{logPath}/{ping_log_file}' if re.search('%cn_ip%', self.ping_args) or re.search(r'[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+', self.ping_args): raise Exception(f"ping_args should not have IP address: {self.ping_args}") interface = f'-I {ue.getIFName()}' if ue.getIFName() else '' - ping_cmd = f'{ue.getCmdPrefix()} ping {interface} {self.ping_args} {svrIP} 2>&1 | tee /tmp/{ping_log_file}' + ping_cmd = f'{ue.getCmdPrefix()} ping {interface} {self.ping_args} {svrIP} 2>&1 | tee {ping_log_file}' cmd = cls_cmd.getConnection(ue.getHost()) response = cmd.run(ping_cmd, timeout=int(ping_time[0])*1.5) ue_header = f'UE {ue.getName()} ({ueIP})' @@ -380,8 +406,7 @@ class OaiCiTest(): message = ue_header + ': ping crashed: TIMEOUT?' return (False, message) - #copy the ping log file to have it locally for analysis (ping stats) - cmd.copyin(src=f'/tmp/{ping_log_file}', tgt=local_ping_log_file) + local_ping_log_file = archiveArtifact(cmd, ctx, ping_log_file) cmd.close() with open(local_ping_log_file, 'r') as f: @@ -421,18 +446,13 @@ class OaiCiTest(): return (True, message) - def Ping(self, HTML, CONTAINERS, infra_file="ci_infra.yaml"): + def Ping(self, ctx, HTML, infra_file="ci_infra.yaml"): if self.ue_ids == [] or self.svr_id == None: raise Exception("no module names in self.ue_ids or/and self.svr_id provided") - # Creating destination log folder if needed on the python executor workspace - with cls_cmd.getConnection('localhost') as local: - ymlPath = CONTAINERS.yamlPath[0].split('/') - logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}' - local.run(f'mkdir -p {logPath}', silent=True) ues = [cls_module.Module_UE(ue_id, server_name, infra_file) for ue_id, server_name in zip(self.ue_ids, self.nodes)] cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file) with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: - futures = [executor.submit(self.Ping_common, cn, ue, logPath) for ue in ues] + futures = [executor.submit(self.Ping_common, ctx, cn, ue) for ue in ues] results = [f.result() for f in futures] # each result in results is a tuple, first member goes to successes, second to messages successes, messages = map(list, zip(*results)) @@ -453,7 +473,7 @@ class OaiCiTest(): HTML.CreateHtmlTestRowQueue(self.ping_args, 'KO', messages) return success - def Iperf_Module(self, cn, ue, idx, ue_num, logPath): + def Iperf_Module(self, ctx, cn, ue, idx, ue_num): ueIP = ue.getIP() if not ueIP: return (False, f"UE {ue.getName()} has no IP address") @@ -466,7 +486,7 @@ class OaiCiTest(): serverReport = "" udpIperf = re.search('-u', iperf_opt) is not None bidirIperf = re.search('--bidir', iperf_opt) is not None - client_filename = f'iperf_client_{self.testCase_id}_{ue.getName()}.log' + client_filename = f'/tmp/iperf_client_{ue.getName()}.log' if udpIperf: target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(idx, ue_num, self.iperf_profile, self.iperf_args) # note: for UDP testing we don't want to use json report - reports 0 Mbps received bitrate @@ -481,14 +501,11 @@ class OaiCiTest(): port = 5002 + idx # note: some core setups start an iperf3 server automatically, indicated in ci_infra by runIperf3Server: False` t = iperf_time * 2.5 - cmd_ue.run(f'rm /tmp/{client_filename}', reportNonZero=False, silent=True) + cmd_ue.run(f'rm {client_filename}', reportNonZero=False, silent=True) if cn.runIperf3Server(): cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf3 -s -B {svrIP} -p {port} -1 {jsonReport} >> /dev/null &', timeout=t) - cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} {iperf_ue} -B {ueIP} -c {svrIP} -p {port} {iperf_opt} {jsonReport} {serverReport} -O 5 >> /tmp/{client_filename}', timeout=t) - # note: copy iperf3 log to the current directory for log analysis and log collection - dest_filename = f'{logPath}/{client_filename}' - cmd_ue.copyin(f'/tmp/{client_filename}', dest_filename) - cmd_ue.run(f'rm /tmp/{client_filename}', reportNonZero=False, silent=True) + cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} {iperf_ue} -B {ueIP} -c {svrIP} -p {port} {iperf_opt} {jsonReport} {serverReport} -O 5 >> {client_filename}', timeout=t) + dest_filename = archiveArtifact(cmd_ue, ctx, client_filename) if udpIperf: status, msg = Iperf_analyzeV3UDP(dest_filename, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate) elif bidirIperf: @@ -498,20 +515,15 @@ class OaiCiTest(): return (status, f'{ue_header}\n{msg}') - def Iperf(self, HTML, CONTAINERS, infra_file="ci_infra.yaml"): + def Iperf(self, ctx, HTML, infra_file="ci_infra.yaml"): logging.debug(f'Iperf: iperf_args "{self.iperf_args}" iperf_packetloss_threshold "{self.iperf_packetloss_threshold}" iperf_bitrate_threshold "{self.iperf_bitrate_threshold}" iperf_profile "{self.iperf_profile}" iperf_options "{self.iperf_options}"') if self.ue_ids == [] or self.svr_id == None: raise Exception("no module names in self.ue_ids or/and self.svr_id provided") - # create log directory on executor node - with cls_cmd.getConnection('localhost') as local: - ymlPath = CONTAINERS.yamlPath[0].split('/') - logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}' - local.run(f'mkdir -p {logPath}', silent=True) ues = [cls_module.Module_UE(ue_id, server_name, infra_file) for ue_id, server_name in zip(self.ue_ids, self.nodes)] cn = cls_corenetwork.CoreNetwork(self.svr_id, self.svr_node, filename=infra_file) with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: - futures = [executor.submit(self.Iperf_Module, cn, ue, i, len(ues), logPath) for i, ue in enumerate(ues)] + futures = [executor.submit(self.Iperf_Module, ctx, cn, ue, i, len(ues)) for i, ue in enumerate(ues)] results = [f.result() for f in futures] # each result in results is a tuple, first member goes to successes, second to messages successes, messages = map(list, zip(*results)) @@ -532,7 +544,7 @@ class OaiCiTest(): HTML.CreateHtmlTestRowQueue(self.iperf_args, 'KO', messages) return success - def Iperf2_Unidir(self, HTML, CONTAINERS, infra_file="ci_infra.yaml"): + def Iperf2_Unidir(self, ctx, HTML, infra_file="ci_infra.yaml"): if self.ue_ids == [] or self.svr_id == None or len(self.ue_ids) != 1: raise Exception("no module names in self.ue_ids or/and self.svr_id provided, multi UE scenario not supported") ue = cls_module.Module_UE(self.ue_ids[0].strip(),self.nodes[0].strip(), infra_file) @@ -543,23 +555,17 @@ class OaiCiTest(): svrIP = cn.getIP() if not svrIP: return False - server_filename = f'iperf_server_{self.testCase_id}_{ue.getName()}.log' - ymlPath = CONTAINERS.yamlPath[0].split('/') - logPath = f'{os.getcwd()}/../cmake_targets/log/{ymlPath[-1]}' + server_filename = f'/tmp/iperf_server_{ue.getName()}.log' iperf_time = Iperf_ComputeTime(self.iperf_args) target_bitrate, iperf_opt = Iperf_ComputeModifiedBW(0, 1, self.iperf_profile, self.iperf_args) t = iperf_time*2.5 - with cls_cmd.getConnection('localhost') as local: - local.run(f'mkdir -p {logPath}') with cls_cmd.getConnection(ue.getHost()) as cmd_ue, cls_cmd.getConnection(cn.getHost()) as cmd_svr: - cmd_ue.run(f'rm /tmp/{server_filename}', reportNonZero=False) - cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} iperf -B {ueIP} -s -u -i1 >> /tmp/{server_filename} &', timeout=t) + cmd_ue.run(f'rm {server_filename}', reportNonZero=False) + cmd_ue.run(f'{ue.getCmdPrefix()} timeout -vk3 {t} iperf -B {ueIP} -s -u -i1 >> {server_filename} &', timeout=t) cmd_svr.run(f'{cn.getCmdPrefix()} timeout -vk3 {t} iperf -c {ueIP} -B {svrIP} {iperf_opt} -i1 >> /dev/null', timeout=t) localPath = f'{os.getcwd()}' - # note: copy iperf2 log to the directory for log collection - cmd_ue.copyin(f'/tmp/{server_filename}', f'{logPath}/{server_filename}') - cmd_ue.run(f'rm /tmp/{server_filename}', reportNonZero=False) - success, msg = Iperf_analyzeV2UDP(f'{logPath}/{server_filename}', self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate) + local = archiveArtifact(cmd_ue, ctx, server_filename) + success, msg = Iperf_analyzeV2UDP(local, self.iperf_bitrate_threshold, self.iperf_packetloss_threshold, target_bitrate) ue_header = f'UE {ue.getName()} ({ueIP})' logging.info(f'\u001B[1;37;45m iperf result for {ue_header}\u001B[0m') for l in msg.split('\n'): @@ -841,17 +847,17 @@ class OaiCiTest(): global_status = CONST.OAI_UE_PROCESS_COULD_NOT_SYNC return global_status - def TerminateUE(self, HTML): + def TerminateUE(self, ctx, HTML): ues = [cls_module.Module_UE(n.strip()) for n in self.ue_ids] with concurrent.futures.ThreadPoolExecutor(max_workers=64) as executor: - futures = [executor.submit(ue.terminate) for ue in ues] + futures = [executor.submit(ue.terminate, ctx) for ue in ues] archives = [f.result() for f in futures] archive_info = [f'Log at: {a}' if a else 'No log available' for a in archives] messages = [f"UE {ue.getName()}: {log}" for (ue, log) in zip(ues, archive_info)] HTML.CreateHtmlTestRowQueue(f'N/A', 'OK', messages) return True - def DeployCoreNetwork(cn_id, HTML): + def DeployCoreNetwork(cn_id, ctx, HTML): core_name = cn_id.strip() cn = cls_corenetwork.CoreNetwork(core_name) success, output = cn.deploy() @@ -865,41 +871,11 @@ class OaiCiTest(): HTML.CreateHtmlTestRowQueue(core_name, 'KO', [msg]) return success - def UndeployCoreNetwork(cn_id, HTML): - # Ping, Iperf, DeployObject put logs into a path based on YAML. We - # can't do this here (because there is no yaml), so hardcode a path for - # "cn_logs" for the moment - logPath = f'{os.getcwd()}/../cmake_targets/log/cn_logs' - with cls_cmd.getConnection('localhost') as local: - local.run(f'mkdir -p {logPath}', silent=True) + def UndeployCoreNetwork(cn_id, ctx, HTML): core_name = cn_id.strip() cn = cls_corenetwork.CoreNetwork(core_name) - logs, output = cn.undeploy(log_dir=logPath) + logs, output = cn.undeploy(ctx=ctx) logging.info(f"undeployed core network {core_name}, logs {logs}, output:\n{output}") - message = "Log files: " + ", ".join([os.path.basename(l) for l in logs]) + message = "Log files:\n" + "\n".join([os.path.basename(l) for l in logs]) HTML.CreateHtmlTestRowQueue(core_name, 'OK', [message]) return True - - def LogCollectBuild(self,RAN): - # Some pipelines are using "none" IP / Credentials - # In that case, just forget about it - if RAN.eNBIPAddress == 'none': - sys.exit(0) - - if (RAN.eNBIPAddress != '' and RAN.eNBUserName != '' and RAN.eNBPassword != ''): - IPAddress = RAN.eNBIPAddress - UserName = RAN.eNBUserName - Password = RAN.eNBPassword - SourceCodePath = RAN.eNBSourceCodePath - else: - sys.exit('Insufficient Parameter') - with cls_cmd.getConnection(IPAddress) as cmd: - d = f'{SourceCodePath}/cmake_targets' - cmd.run(f'rm -f {d}/build.log.zip') - cmd.run(f'cd {d} && zip -r build.log.zip build_log_*/*') - - def ShowTestID(self): - logging.info(f'\u001B[1m----------------------------------------\u001B[0m') - logging.info(f'\u001B[1m Test ID: {self.testCase_id} \u001B[0m') - logging.info(f'\u001B[1m {self.desc} \u001B[0m') - logging.info(f'\u001B[1m----------------------------------------\u001B[0m') diff --git a/ci-scripts/cls_static_code_analysis.py b/ci-scripts/cls_static_code_analysis.py index f2951b0528..63b5b5b6dd 100644 --- a/ci-scripts/cls_static_code_analysis.py +++ b/ci-scripts/cls_static_code_analysis.py @@ -43,6 +43,7 @@ from pathlib import Path import helpreadme as HELP import constants as CONST import cls_cmd +from cls_ci_helper import archiveArtifact #----------------------------------------------------------- # Class Declaration @@ -75,25 +76,18 @@ class StaticCodeAnalysis(): self.ranAllowMerge = False self.ranCommitID = '' self.ranTargetBranch = '' - self.eNBIPAddress = '' - self.eNBUserName = '' - self.eNBPassword = '' self.eNBSourceCodePath = '' - def CppCheckAnalysis(self, HTML): + def CppCheckAnalysis(self, ctx, node, HTML): if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword lSourcePath = self.eNBSourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - logging.debug('Building on server: ' + lIpAddr) - cmd = cls_cmd.getConnection(lIpAddr) + if not lSourcePath or not node: + raise ValueError(f"{lSourcePath=} {node=}") + logging.debug('Building on server: ' + node) + cmd = cls_cmd.getConnection(node) self.testCase_id = HTML.testCase_id # on RedHat/CentOS .git extension is mandatory result = re.search('([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) @@ -103,7 +97,7 @@ class StaticCodeAnalysis(): full_ran_repo_name = self.ranRepository + '.git' cmd.cd(lSourcePath) - logDir = f'{lSourcePath}/cmake_targets/build_log_{self.testCase_id}' + logDir = f'{lSourcePath}/cmake_targets/log' cmd.run(f'mkdir -p {logDir}') cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal') cmd.run(f'sed -e "s@xenial@bionic@" {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.xenial > {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.bionic') @@ -112,31 +106,21 @@ class StaticCodeAnalysis(): cmd.run(f'docker build --tag oai-cppcheck:focal --file {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.focal . > {logDir}/cppcheck-focal.txt 2>&1') cmd.run('docker image rm oai-cppcheck:bionic oai-cppcheck:focal') - # Analyzing the logs - cmd.copyin(f'{logDir}/cppcheck-bionic.txt', 'cppcheck-bionic.txt') - cmd.copyin(f'{logDir}/cppcheck-focal.txt', 'cppcheck-focal.txt') + bionic = archiveArtifact(cmd, ctx, f'{logDir}/cppcheck-bionic.txt') + focal = archiveArtifact(cmd, ctx, f'{logDir}/cppcheck-focal.txt') cmd.close() CCR = CppCheckResults() CCR_ref = CppCheckResults() vId = 0 for variant in CCR.variants: - refAvailable = False - if self.ranAllowMerge: - refFolder = str(Path.home()) + '/cppcheck-references' - if (os.path.isfile(refFolder + '/cppcheck-'+ variant + '.txt')): - refAvailable = True - with open(refFolder + '/cppcheck-'+ variant + '.txt', 'r') as refFile: - for line in refFile: - ret = re.search(' (?P[0-9\.]+) errors', str(line)) - if ret is not None: - CCR_ref.nbErrors[vId] = int(ret.group('nb_errors')) - ret = re.search(' (?P[0-9\.]+) warnings', str(line)) - if ret is not None: - CCR_ref.nbWarnings[vId] = int(ret.group('nb_warnings')) - if (os.path.isfile('./cppcheck-'+ variant + '.txt')): + filename = ctx.baseFilename() + '-cppcheck-'+ variant + '.txt' + logging.info(f"will check file '{filename}'") + if not os.path.isfile(filename): + raise FileNotFoundError(f"{filename} is not a file") + else: xmlStart = False - with open('./cppcheck-'+ variant + '.txt', 'r') as logfile: + with open(filename, 'r') as logfile: for line in logfile: ret = re.search('cppcheck version="(?P[0-9\.]+)"', str(line)) if ret is not None: @@ -185,26 +169,6 @@ class StaticCodeAnalysis(): vMsg += ' Wrong Scanf Nb Args: ' + str(CCR.nbWrongScanfArg[vId]) + '\n' for vLine in vMsg.split('\n'): logging.debug(vLine) - if self.ranAllowMerge and refAvailable: - if CCR_ref.nbErrors[vId] == CCR.nbErrors[vId]: - logging.debug(' No change in number of errors') - elif CCR_ref.nbErrors[vId] > CCR.nbErrors[vId]: - logging.debug(' Good! Decrease in number of errors') - else: - logging.debug(' Bad! increase in number of errors') - if CCR_ref.nbWarnings[vId] == CCR.nbWarnings[vId]: - logging.debug(' No change in number of warnings') - elif CCR_ref.nbWarnings[vId] > CCR.nbWarnings[vId]: - logging.debug(' Good! Decrease in number of warnings') - else: - logging.debug(' Bad! increase in number of warnings') - # Create new reference file - if not self.ranAllowMerge: - refFolder = str(Path.home()) + '/cppcheck-references' - if not os.path.isdir(refFolder): - os.mkdir(refFolder) - with open(refFolder + '/cppcheck-'+ variant + '.txt', 'w') as refFile: - refFile.write(vMsg) vId += 1 HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) @@ -213,20 +177,16 @@ class StaticCodeAnalysis(): return True - def LicenceAndFormattingCheck(self, HTML): + def LicenceAndFormattingCheck(self, ctx, node, HTML): # Workspace is no longer recreated from scratch. # It implies that this method shall be called last within a build pipeline # where workspace is already created - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword lSourcePath = self.eNBSourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - logging.debug('Building on server: ' + lIpAddr) - cmd = cls_cmd.getConnection(lIpAddr) + if not node or not lSourcePath: + raise ValueError(f"{lSourcePath=} {node=}") + logging.debug('Building on server: ' + node) + cmd = cls_cmd.getConnection(node) self.testCase_id = HTML.testCase_id check_options = '' @@ -238,21 +198,20 @@ class StaticCodeAnalysis(): else: check_options += f' --build-arg TARGET_BRANCH={self.ranTargetBranch}' - logDir = f'{lSourcePath}/cmake_targets/build_log_{self.testCase_id}' + logDir = f'{lSourcePath}/cmake_targets/log/' cmd.run(f'mkdir -p {logDir}') cmd.run('docker image rm oai-formatting-check:latest') - cmd.run(f'docker build --target oai-formatting-check --tag oai-formatting-check:latest {check_options} --file {lSourcePath}/ci-scripts/docker/Dockerfile.formatting.bionic {lSourcePath} > {logDir}/oai-formatting-check.txt 2>&1') + cmd.run(f'docker build --target oai-formatting-check --tag oai-formatting-check:latest {check_options} --file {lSourcePath}/ci-scripts/docker/Dockerfile.formatting.ubuntu {lSourcePath} > {logDir}/oai-formatting-check.txt 2>&1') cmd.run('docker image rm oai-formatting-check:latest') cmd.run('docker image prune --force') cmd.run('docker volume prune --force') - # Analyzing the logs - cmd.copyin(f'{logDir}/oai-formatting-check.txt', 'oai-formatting-check.txt') + file = archiveArtifact(cmd, ctx, f'{logDir}/oai-formatting-check.txt') cmd.close() finalStatus = 0 - if (os.path.isfile('./oai-formatting-check.txt')): + if (os.path.isfile(file)): analyzed = False nbFilesNotFormatted = 0 listFiles = False @@ -263,7 +222,7 @@ class StaticCodeAnalysis(): gnuGplLicenceFiles = [] suspectLicence = False suspectLicenceFiles = [] - with open('./oai-formatting-check.txt', 'r') as logfile: + with open(file, 'r') as logfile: for line in logfile: ret = re.search('./ci-scripts/checkCodingFormattingRules.sh', str(line)) if ret is not None: diff --git a/ci-scripts/conf_files/gnb-cu.sa.band78.106prb.conf b/ci-scripts/conf_files/gnb-cu.sa.band78.106prb.conf index 311c8551fd..4294f920ad 100644 --- a/ci-scripts/conf_files/gnb-cu.sa.band78.106prb.conf +++ b/ci-scripts/conf_files/gnb-cu.sa.band78.106prb.conf @@ -15,7 +15,7 @@ gNBs = // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = 1; plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) }); - + @include "neighbour-config.conf" nr_cellid = 12345678L; @@ -23,9 +23,7 @@ gNBs = local_s_address = "192.168.71.150"; remote_s_address = "192.168.71.171"; - local_s_portc = 501; local_s_portd = 2153; - remote_s_portc = 500; remote_s_portd = 2153; # ------- SCTP definitions diff --git a/ci-scripts/conf_files/gnb-cu.sa.f1.conf b/ci-scripts/conf_files/gnb-cu.sa.f1.conf index 84e5dbadb0..280281997e 100644 --- a/ci-scripts/conf_files/gnb-cu.sa.f1.conf +++ b/ci-scripts/conf_files/gnb-cu.sa.f1.conf @@ -23,9 +23,7 @@ gNBs = local_s_address = "127.0.0.4"; remote_s_address = "127.0.0.5"; - local_s_portc = 501; local_s_portd = 2153; - remote_s_portc = 500; remote_s_portd = 2153; # ------- SCTP definitions diff --git a/ci-scripts/conf_files/gnb-cu.sa.f1.ho.conf b/ci-scripts/conf_files/gnb-cu.sa.f1.ho.conf new file mode 100644 index 0000000000..f16a94b472 --- /dev/null +++ b/ci-scripts/conf_files/gnb-cu.sa.f1.ho.conf @@ -0,0 +1,76 @@ +Active_gNBs = ( "CU-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe88; + +# cell_type = "CELL_MACRO_GNB"; + + gNB_name = "CU-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 001; mnc = 03; mnc_length = 2; snssaiList = ({ sst = 1 }) }); + + @include "neighbour-config-ho.conf" + + nr_cellid = 12345678L; + + tr_s_preference = "f1"; + + local_s_address = "172.21.19.98"; + remote_s_address = "0.0.0.0"; + local_s_portd = 2153; + remote_s_portd = 2154; + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "172.21.6.109"; }); + + NETWORK_INTERFACES : + { + + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.19.98/22"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.19.98/22"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + f1ap_log_level ="info"; + ngap_log_level ="info"; +}; diff --git a/ci-scripts/conf_files/gnb-cucp.sa.e1-ho-n2.conf b/ci-scripts/conf_files/gnb-cucp.sa.e1-ho-n2.conf new file mode 100644 index 0000000000..ad4cca969e --- /dev/null +++ b/ci-scripts/conf_files/gnb-cucp.sa.e1-ho-n2.conf @@ -0,0 +1,82 @@ +Active_gNBs = ( "cu-cp-0"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + +# cell_type = "CELL_MACRO_GNB"; + + gNB_name = "cu-cp-0"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) }); + @include "neighbour-config.conf" + + nr_cellid = 12345678L; + + tr_s_preference = "f1"; + + local_s_address = "192.168.71.150"; + remote_s_address = "192.168.71.171"; + local_s_portd = 2153; + remote_s_portd = 2153; + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "192.168.71.132"; }); + + E1_INTERFACE = + ( + { + type = "cp"; + ipv4_cucp = "192.168.71.150"; + port_cucp = 38462; + ipv4_cuup = "0.0.0.0"; # multiple CU-UPs + port_cuup = 38462; + } + ) + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.71.150"; + }; + } +); + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : { + global_log_level = "info"; + pdcp_log_level = "info"; + rrc_log_level = "info"; + f1ap_log_level = "info"; + ngap_log_level = "info"; +}; diff --git a/ci-scripts/conf_files/gnb-cucp.sa.f1.conf b/ci-scripts/conf_files/gnb-cucp.sa.f1.conf index 28bb7cfc33..214b5dd519 100644 --- a/ci-scripts/conf_files/gnb-cucp.sa.f1.conf +++ b/ci-scripts/conf_files/gnb-cucp.sa.f1.conf @@ -23,9 +23,7 @@ gNBs = local_s_address = "192.168.71.150"; remote_s_address = "0.0.0.0"; # multiple DUs - local_s_portc = 501; local_s_portd = 2152; - remote_s_portc = 500; remote_s_portd = 2152; # ------- SCTP definitions diff --git a/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf b/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf index 8cebc8640a..6a76eb7689 100644 --- a/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf +++ b/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf @@ -23,9 +23,7 @@ gNBs = local_s_address = "127.0.0.4"; remote_s_address = "127.0.0.5"; - local_s_portc = 501; local_s_portd = 2153; - remote_s_portc = 500; remote_s_portd = 2153; # ------- SCTP definitions diff --git a/ci-scripts/conf_files/gnb-cuup.sa.f1.conf b/ci-scripts/conf_files/gnb-cuup.sa.f1.conf index 5dd6c77a9c..e87ac862b1 100644 --- a/ci-scripts/conf_files/gnb-cuup.sa.f1.conf +++ b/ci-scripts/conf_files/gnb-cuup.sa.f1.conf @@ -22,9 +22,7 @@ gNBs = local_s_address = "192.168.72.161"; remote_s_address = "192.168.72.171"; - local_s_portc = 501; local_s_portd = 2153; - remote_s_portc = 500; remote_s_portd = 2153; # ------- SCTP definitions diff --git a/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf b/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf index b9f65cdf53..dbe510ea3f 100644 --- a/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf +++ b/ci-scripts/conf_files/gnb-cuup.sa.f1.quectel.conf @@ -22,9 +22,7 @@ gNBs = local_s_address = "127.0.0.6"; remote_s_address = "127.0.0.5"; - local_s_portc = 501; local_s_portd = 2153; - remote_s_portc = 500; remote_s_portd = 2153; # ------- SCTP definitions diff --git a/ci-scripts/conf_files/gnb-du.sa.band1.52prb.usrpb210.conf b/ci-scripts/conf_files/gnb-du.sa.band1.52prb.usrpb210.conf index 2af3185ffc..35d130f78c 100644 --- a/ci-scripts/conf_files/gnb-du.sa.band1.52prb.usrpb210.conf +++ b/ci-scripts/conf_files/gnb-du.sa.band1.52prb.usrpb210.conf @@ -86,9 +86,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -163,9 +160,7 @@ MACRLCs = ( tr_n_preference = "f1"; local_n_address = "127.0.0.5"; remote_n_address = "127.0.0.4"; - local_n_portc = 500; local_n_portd = 2153; - remote_n_portc = 501; remote_n_portd = 2153; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf index fce5e6dc6e..fbc6de9b5e 100644 --- a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.rfsim.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -168,9 +165,7 @@ MACRLCs = ( tr_n_preference = "f1"; local_n_address = "192.168.71.171"; remote_n_address = "192.168.71.150"; - local_n_portc = 500; local_n_portd = 2153; - remote_n_portc = 501; remote_n_portd = 2153; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf index 45482642b9..e4d9127284 100644 --- a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf @@ -34,11 +34,9 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL - # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) - absoluteFrequencySSB = 641280; + absoluteFrequencySSB = 641280; # GSCN: 7929, Freq: 3619.200 MHz dl_frequencyBand = 78; - # this is 3600 MHz - dl_absoluteFrequencyPointA = 640008; + dl_absoluteFrequencyPointA = 640752; # 3611.280 MHz #scs-SpecificCarrierList dl_offstToCarrier = 0; # subcarrierSpacing @@ -47,13 +45,12 @@ gNBs = dl_carrierBandwidth = 106; #initialDownlinkBWP #genericParameters - # this is RBstart=27,L=48 (275*(L-1))+RBstart - initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 + initialDLBWPlocationAndBandwidth = 13750; # RBstart=0, L=51 (275*(L-1))+RBstart # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialDLBWPsubcarrierSpacing = 1; #pdcch-ConfigCommon - initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPcontrolResourceSetZero = 10; initialDLBWPsearchSpaceZero = 0; #uplinkConfigCommon @@ -68,7 +65,7 @@ gNBs = pMax = 20; #initialUplinkBWP #genericParameters - initialULBWPlocationAndBandwidth = 28875; + initialULBWPlocationAndBandwidth = 13750; # RBstart=0, L=51 (275*(L-1))+RBstart # subcarrierSpacing # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 initialULBWPsubcarrierSpacing = 1; @@ -86,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -152,6 +146,8 @@ gNBs = ); + first_active_bwp = 1; + bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;}); # ------- SCTP definitions SCTP : @@ -195,9 +191,7 @@ MACRLCs = ( tr_n_preference = "f1"; local_n_address = "127.0.0.5"; remote_n_address = "127.0.0.4"; - local_n_portc = 500; local_n_portd = 2153; - remote_n_portc = 501; remote_n_portd = 2153; pusch_TargetSNRx10 = 200; pucch_TargetSNRx10 = 200; diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.51prb.usrpb210.ho-pci0.conf b/ci-scripts/conf_files/gnb-du.sa.band78.51prb.usrpb210.ho-pci0.conf new file mode 100644 index 0000000000..df225e84c2 --- /dev/null +++ b/ci-scripts/conf_files/gnb-du.sa.band78.51prb.usrpb210.ho-pci0.conf @@ -0,0 +1,210 @@ +Active_gNBs = ( "DU0-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe88; + gNB_DU_ID = 0xe00; + gNB_name = "DU0-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1 ; + plmn_list = ({ mcc = 001; mnc = 03; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # 4186.56 MHz + absoluteFrequencySSB = 679104; + dl_frequencyBand = 77; + # 4175.82 MHz + dl_absoluteFrequencyPointA = 678388; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 51; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 13750; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 77; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 51; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 13750; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "f1"; + local_n_address = "172.21.19.98"; + remote_n_address = "172.21.19.98"; + local_n_portd = 2154; + remote_n_portd = 2153; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 230; +# ul_prbblack_SNR_threshold = 10; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 100; + pucch0_dtx_threshold = 10; + max_ldpc_iterations = 20; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +} +); + +RUs = ( +{ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0; + att_rx = 0; + sl_ahead = 3; + bands = [77]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; +# USRP is connected to an Octoclock in order to establish synchroniation with other USRPs + clock_src = "external"; + time_src = "external"; +} +); + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="debug"; + f1ap_log_level ="info"; +}; diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.51prb.usrpb210.ho-pci1.conf b/ci-scripts/conf_files/gnb-du.sa.band78.51prb.usrpb210.ho-pci1.conf new file mode 100644 index 0000000000..14ec8b1e82 --- /dev/null +++ b/ci-scripts/conf_files/gnb-du.sa.band78.51prb.usrpb210.ho-pci1.conf @@ -0,0 +1,210 @@ +Active_gNBs = ( "DU1-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe88; + gNB_DU_ID = 0xe01; + gNB_name = "DU1-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1 ; + plmn_list = ({ mcc = 001; mnc = 03; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + + nr_cellid = 11111111L; + + ////////// Physical parameters: + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 1; + +# downlinkConfigCommon + #frequencyInfoDL + # 4186.56 MHz + absoluteFrequencySSB = 679104; + dl_frequencyBand = 77; + # 4175.82 MHz + dl_absoluteFrequencyPointA = 678388; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 51; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 13750; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 77; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 51; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 13750; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 2; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "f1"; + local_n_address = "172.21.19.99"; + remote_n_address = "172.21.19.98"; + local_n_portd = 2154; + remote_n_portd = 2153; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 230; +# ul_prbblack_SNR_threshold = 10; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 100; + pucch0_dtx_threshold = 10; + max_ldpc_iterations = 20; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +} +); + +RUs = ( +{ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0; + att_rx = 0; + sl_ahead = 3; + bands = [77]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; +# USRP is connected to an Octoclock in order to establish synchroniation with other USRPs + clock_src = "external"; + time_src = "external"; +} +); + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="debug"; + f1ap_log_level ="info"; +}; diff --git a/ci-scripts/conf_files/gnb-vnf.sa.band77.162prb.nfapi.4x4.conf b/ci-scripts/conf_files/gnb-vnf.sa.band77.162prb.nfapi.4x4.conf index ba156df849..814518f3b1 100644 --- a/ci-scripts/conf_files/gnb-vnf.sa.band77.162prb.nfapi.4x4.conf +++ b/ci-scripts/conf_files/gnb-vnf.sa.band77.162prb.nfapi.4x4.conf @@ -85,9 +85,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf b/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf index be2e0404e3..f26891d8f2 100644 --- a/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf +++ b/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.conf @@ -43,19 +43,12 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL - # this is 3300.24 + 134*12*30e3 = 3348.48 MHz (5G NR GSCN: 7741) - absoluteFrequencySSB = 649920; - #652860; #should be 649920 -#647520; -#647540; -#649920; -#650208; -#647540; + # center frequency = 3350.01 MHz + # selected SSB frequency = 3349.92 MHz + absoluteFrequencySSB = 623328; dl_frequencyBand = 78; - # this is 3300.24 MHz - dl_absoluteFrequencyPointA = 646724; -#649104; -#646724; + # frequency point A = 3300.87 MHz + dl_absoluteFrequencyPointA = 620058; #scs-SpecificCarrierList dl_offstToCarrier = 0; # subcarrierSpacing @@ -104,9 +97,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -207,7 +197,6 @@ MACRLCs = ( tr_n_preference = "local_RRC"; pusch_TargetSNRx10 = 200; # 150; pucch_TargetSNRx10 = 200; #200; - ulsch_max_frame_inactivity = 10; dl_max_mcs = 28; ul_max_mcs = 28; } diff --git a/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf b/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf new file mode 100644 index 0000000000..90662226ed --- /dev/null +++ b/ci-scripts/conf_files/gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf @@ -0,0 +1,227 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +nfapi = "AERIAL"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 208; mnc = 97; mnc_length = 2; snssaiList = ({ sst = 1; }); }); + + nr_cellid = 12345678L; + uess_agg_levels = [0,6,0,0,0]; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pdsch_AntennaPorts_N1 = 2; + pusch_AntennaPorts = 2; + do_CSIRS = 1; + do_SRS = 0; + min_rxtxtime = 2; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # center frequency = 3350.01 MHz + # selected SSB frequency = 3349.92 MHz + absoluteFrequencySSB = 623328; + dl_frequencyBand = 78; + # frequency point A = 3300.87 MHz + dl_absoluteFrequencyPointA = 620058; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=162 (275*(275-L+1))+(274-RBstart)) + initialDLBWPlocationAndBandwidth = 1099; + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 159;# testMAC 158; OAI gNB 98 +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant = -90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 5; + nrofDownlinkSlots = 1; + nrofDownlinkSymbols = 10; + nrofUplinkSlots = 3; + nrofUplinkSymbols = 0; + + ssPBCH_BlockPower = -10; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "172.21.6.103"; }); + + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.202"; + GNB_IPV4_ADDRESS_FOR_NGU = "172.21.16.202"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + remote_s_address = "127.0.0.1"; // pnf addr [!] + local_s_address = "127.0.0.2"; // vnf addr + local_s_portc = 50001; // vnf p5 port + remote_s_portc = 50000; // pnf p5 port [!] + local_s_portd = 50011; // vnf p7 port [!] + remote_s_portd = 50010; // pnf p7 port [!] + tr_s_preference = "aerial"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 220; # 150; + pucch_TargetSNRx10 = 200; #200; + dl_max_mcs = 28; + ul_max_mcs = 28; + ul_min_mcs = 16; +} +); + + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="debug"; + f1ap_log_level ="debug"; +}; diff --git a/ci-scripts/conf_files/gnb.band66.106prb.rfsim.phytest-dora.conf b/ci-scripts/conf_files/gnb.band66.106prb.rfsim.phytest-dora.conf index b1d2d6d724..e69fee4722 100644 --- a/ci-scripts/conf_files/gnb.band66.106prb.rfsim.phytest-dora.conf +++ b/ci-scripts/conf_files/gnb.band66.106prb.rfsim.phytest-dora.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.band78.106prb.rfsim.phytest-dora.conf b/ci-scripts/conf_files/gnb.band78.106prb.rfsim.phytest-dora.conf index e49f8c422a..eb7c1e01e2 100644 --- a/ci-scripts/conf_files/gnb.band78.106prb.rfsim.phytest-dora.conf +++ b/ci-scripts/conf_files/gnb.band78.106prb.rfsim.phytest-dora.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.band78.106prb.usrpn300.phytest-dora.conf b/ci-scripts/conf_files/gnb.band79.106prb.usrpn300.phytest-dora.conf similarity index 97% rename from ci-scripts/conf_files/gnb.band78.106prb.usrpn300.phytest-dora.conf rename to ci-scripts/conf_files/gnb.band79.106prb.usrpn300.phytest-dora.conf index bcb3b8e8d8..f36619e58a 100644 --- a/ci-scripts/conf_files/gnb.band78.106prb.usrpn300.phytest-dora.conf +++ b/ci-scripts/conf_files/gnb.band79.106prb.usrpn300.phytest-dora.conf @@ -31,11 +31,11 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL - # this is 3319.68 MHz - absoluteFrequencySSB = 621312; - dl_frequencyBand = 78; - # this is 3300.6 MHz - dl_absoluteFrequencyPointA = 620040; + # this is 4412.64 MHz + absoluteFrequencySSB = 694176; + dl_frequencyBand = 79; + # this is 4400.94 MHz + dl_absoluteFrequencyPointA = 693396; #scs-SpecificCarrierList dl_offstToCarrier = 0; # subcarrierSpacing @@ -55,7 +55,7 @@ gNBs = #uplinkConfigCommon #frequencyInfoUL - ul_frequencyBand = 78; + ul_frequencyBand = 79; #scs-SpecificCarrierList ul_offstToCarrier = 0; # subcarrierSpacing @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf b/ci-scripts/conf_files/gnb.band79.162prb.usrpn300.phytest-dora.conf similarity index 96% rename from ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf rename to ci-scripts/conf_files/gnb.band79.162prb.usrpn300.phytest-dora.conf index 79e9fb5402..caa3381365 100644 --- a/ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf +++ b/ci-scripts/conf_files/gnb.band79.162prb.usrpn300.phytest-dora.conf @@ -31,11 +31,11 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL - # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) - absoluteFrequencySSB = 621312; - dl_frequencyBand = 78; - # this is 3600 MHz - dl_absoluteFrequencyPointA = 620040; + # this is 4435.68 MHz + absoluteFrequencySSB = 695712; + dl_frequencyBand = 79; + # this is 4400.94 MHz + dl_absoluteFrequencyPointA = 693396; #scs-SpecificCarrierList dl_offstToCarrier = 0; # subcarrierSpacing @@ -55,7 +55,7 @@ gNBs = #uplinkConfigCommon #frequencyInfoUL - ul_frequencyBand = 78; + ul_frequencyBand = 79; #scs-SpecificCarrierList ul_offstToCarrier = 0; # subcarrierSpacing @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.band78.273prb.usrpn300.phytest-dora.conf b/ci-scripts/conf_files/gnb.band79.273prb.usrpn300.phytest-dora.conf similarity index 96% rename from ci-scripts/conf_files/gnb.band78.273prb.usrpn300.phytest-dora.conf rename to ci-scripts/conf_files/gnb.band79.273prb.usrpn300.phytest-dora.conf index e0c7b78247..586492e93f 100644 --- a/ci-scripts/conf_files/gnb.band78.273prb.usrpn300.phytest-dora.conf +++ b/ci-scripts/conf_files/gnb.band79.273prb.usrpn300.phytest-dora.conf @@ -33,11 +33,11 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL - # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) - absoluteFrequencySSB = 621312; - dl_frequencyBand = 78; - # this is 3600 MHz - dl_absoluteFrequencyPointA = 620040; + # this is 4458.72 MHz + absoluteFrequencySSB = 697248; + dl_frequencyBand = 79; + # this is 4400.94 MHz + dl_absoluteFrequencyPointA = 693396; #scs-SpecificCarrierList dl_offstToCarrier = 0; # subcarrierSpacing @@ -57,7 +57,7 @@ gNBs = #uplinkConfigCommon #frequencyInfoUL - ul_frequencyBand = 78; + ul_frequencyBand = 79; #scs-SpecificCarrierList ul_offstToCarrier = 0; # subcarrierSpacing @@ -85,9 +85,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf index bbe3168aa2..d71be72f17 100644 --- a/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpb200.conf @@ -78,9 +78,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpn310.2x2.conf b/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpn310.2x2.conf index a7900e5e41..1637e89521 100644 --- a/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpn310.2x2.conf +++ b/ci-scripts/conf_files/gnb.nsa.band78.106prb.usrpn310.2x2.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf index d08d900098..8d71434f66 100644 --- a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf +++ b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf @@ -16,7 +16,6 @@ gNBs = ////////// Physical parameters: - sib1_tda = 5; min_rxtxtime = 6; num_dlharq = 32; num_ulharq = 32; @@ -85,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -150,6 +146,8 @@ gNBs = #ext2 #ntn_Config_r17 + # This can be of values {s5, s10, s15, s20, s25, s30, s35, s40, s45, s50, s55, s60, s120, s180, s240, s900} + ntn-UlSyncValidityDuration-r17 = 5; cellSpecificKoffset_r17 = 40; ta-Common-r17 = 4627000; # 18.84 ms ta-CommonDrift-r17 = -230000; # -46 µs/s @@ -200,7 +198,6 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; -# ulsch_max_frame_inactivity = 0; pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; dl_max_mcs = 9; diff --git a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf index 3e7dd08474..a7663ae811 100644 --- a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf +++ b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf @@ -16,7 +16,7 @@ gNBs = ////////// Physical parameters: - sib1_tda = 5; + do_SINR = 1; min_rxtxtime = 6; disable_harq = 1; cu_sibs = [2]; @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -149,6 +146,8 @@ gNBs = #ext2 #ntn_Config_r17 + # This can be of values {s5, s10, s15, s20, s25, s30, s35, s40, s45, s50, s55, s60, s120, s180, s240, s900} + ntn-UlSyncValidityDuration-r17 = 240; cellSpecificKoffset_r17 = 478; ta-Common-r17 = 58629666; # 238.74 ms positionX-r17 = 0; @@ -193,12 +192,20 @@ gNBs = } ); +rlc = { + srb = { + t_poll_retransmit = "ms2000" + } + drb_am = { + t_poll_retransmit = "ms2000" + } +} + MACRLCs = ( { num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; -# ulsch_max_frame_inactivity = 0; pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; dl_max_mcs = 9; diff --git a/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf index d5b1695d5c..6471c7bd02 100644 --- a/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band66.106prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band66.106prb.rfsim.conf index 6c8ee24c1b..95384a0ae1 100644 --- a/ci-scripts/conf_files/gnb.sa.band66.106prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band66.106prb.rfsim.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band77.162prb.usrpn310.2x2.conf b/ci-scripts/conf_files/gnb.sa.band77.162prb.usrpn310.2x2.conf index b0647e8e5f..932699a83f 100644 --- a/ci-scripts/conf_files/gnb.sa.band77.162prb.usrpn310.2x2.conf +++ b/ci-scripts/conf_files/gnb.sa.band77.162prb.usrpn310.2x2.conf @@ -24,6 +24,7 @@ gNBs = pusch_AntennaPorts = 2; do_CSIRS = 1; do_SRS = 1; + uess_agg_levels = [4,2,0,0,0]; servingCellConfigCommon = ( { @@ -86,9 +87,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -142,9 +140,9 @@ gNBs = # dl_UL_TransmissionPeriodicity # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 dl_UL_TransmissionPeriodicity = 5; - nrofDownlinkSlots = 2; + nrofDownlinkSlots = 1; nrofDownlinkSymbols = 6; - nrofUplinkSlots = 2; + nrofUplinkSlots = 3; nrofUplinkSymbols = 4; ssPBCH_BlockPower = -20; @@ -181,11 +179,12 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - pusch_TargetSNRx10 = 300; - pucch_TargetSNRx10 = 300; - ulsch_max_frame_inactivity = 0; + pusch_TargetSNRx10 = 320; + pucch_TargetSNRx10 = 320; pusch_FailureThres = 100; - ul_max_mcs = 28; + ul_max_mcs = 28; + ul_bler_target_upper = 0.20; + ul_bler_target_lower = 0.10; } ); diff --git a/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf b/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf index 74ab33a28d..b066c27810 100644 --- a/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf +++ b/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 2; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf b/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf index 4e7042c2e4..4be45f6e19 100644 --- a/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf +++ b/ci-scripts/conf_files/gnb.sa.band77.273prb.fhi72.4x4.2L-metanoia.conf @@ -79,9 +79,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -196,8 +193,6 @@ RUs = ( eNB_instances = [0]; ru_thread_core = 6; sl_ahead = 10; #5; - ##beamforming 1x2 matrix: 1 layer x 2 antennas - bf_weights = [0x00007fff, 0x0000,0x00007fff, 0x0000]; tr_preference = "raw_if4p5"; # important: activate FHI7.2 do_precoding = 0; # needs to match O-RU configuration } diff --git a/ci-scripts/conf_files/gnb.sa.band77.273prb.usrpn310.2x2.conf b/ci-scripts/conf_files/gnb.sa.band77.273prb.usrpn310.2x2.conf index d14493376f..5928ea4452 100644 --- a/ci-scripts/conf_files/gnb.sa.band77.273prb.usrpn310.2x2.conf +++ b/ci-scripts/conf_files/gnb.sa.band77.273prb.usrpn310.2x2.conf @@ -86,9 +86,6 @@ gNBs = ( # powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; - # ra_ReponseWindow - # 1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; # ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR # 1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -178,7 +175,6 @@ MACRLCs = ( pusch_TargetSNRx10 = 270; pucch_TargetSNRx10 = 270; pusch_FailureThres = 1000; - ulsch_max_frame_inactivity = 0; ul_max_mcs = 25; } ); @@ -213,7 +209,7 @@ security = { # preferred ciphering algorithms # the first one of the list that an UE supports in chosen # valid values: nea0, nea1, nea2, nea3 - ciphering_algorithms = ( "nea0" ); + ciphering_algorithms = ( "nea2", "nea0" ); # preferred integrity algorithms # the first one of the list that an UE supports in chosen @@ -223,7 +219,7 @@ security = { # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' drb_ciphering = "yes"; - drb_integrity = "no"; + drb_integrity = "yes"; }; log_config : diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf index d92f096f24..ed1c79911e 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf @@ -35,8 +35,8 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL dl_frequencyBand = 78; - absoluteFrequencySSB = 634080; - dl_absoluteFrequencyPointA = 632808; + absoluteFrequencySSB = 628320; + dl_absoluteFrequencyPointA = 627062; #scs-SpecificCarrierList dl_offstToCarrier = 0; # subcarrierSpacing @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -115,7 +112,7 @@ gNBs = # 0 = neither, 1= group hopping, 2=sequence hopping pucchGroupHopping = 0; hoppingId = 40; - p0_nominal = -70; + p0_nominal = -80; ssb_PositionsInBurst_Bitmap = 1; @@ -178,7 +175,7 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "local_RRC"; - pusch_TargetSNRx10 = 180; + pusch_TargetSNRx10 = 150; pucch_TargetSNRx10 = 200; } ); @@ -187,7 +184,7 @@ L1s = ( { num_cc = 1; tr_n_preference = "local_mac"; - prach_dtx_threshold = 120; + prach_dtx_threshold = 150; #pucch0_dtx_threshold = 150; } ); @@ -197,11 +194,11 @@ RUs = ( local_rf = "yes"; nb_tx = 1; nb_rx = 1; - att_tx = 0; + att_tx = 10; att_rx = 0; bands = [78]; max_pdschReferenceSignalPower = -27; - max_rxgain = 65; + max_rxgain = 70; eNB_instances = [0]; sf_extension = 0 sdr_addrs = "addr=192.168.80.52,clock_source=internal,time_source=internal" @@ -212,7 +209,7 @@ security = { # preferred ciphering algorithms # the first one of the list that an UE supports in chosen # valid values: nea0, nea1, nea2, nea3 - ciphering_algorithms = ( "nea0" ); + ciphering_algorithms = ( "nea2", "nea0" ); # preferred integrity algorithms # the first one of the list that an UE supports in chosen @@ -222,7 +219,7 @@ security = { # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' drb_ciphering = "yes"; - drb_integrity = "no"; + drb_integrity = "yes"; }; log_config : diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf index 9627a48d87..c297e40311 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.conf @@ -86,9 +86,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.flexric.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.flexric.conf index 8be3135296..66f8fa2ea1 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.flexric.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.flexric.conf @@ -80,9 +80,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; - #ra_ReponseWindow - #1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf index e4f7d91900..6322d1463c 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -148,64 +145,10 @@ gNBs = ); - # Dedicated Serving Cell Configuration - servingCellConfigDedicated = ({ - # BWP-Downlink - # BWP 1 Configuration - dl_bwp-Id_1 = 1; - dl_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_bwp1_subcarrierSpacing = 1; - - # BWP 2 Configuration - dl_bwp-Id_2 = 2; - dl_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_bwp2_subcarrierSpacing = 1; - - # BWP 3 Configuration - dl_bwp-Id_3 = 3; - dl_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_bwp3_subcarrierSpacing = 1; - - firstActiveDownlinkBWP-Id = 1; #BWP-Id - defaultDownlinkBWP-Id = 1; #BWP-Id - - # bwp-InactivityTimer ENUMERATED {ms2, ms3, ms4, ms5, ms6, ms8, ms10, ms20, ms30, - # ms40,ms50, ms60, ms80,ms100, ms200,ms300, ms500, - # ms750, ms1280, ms1920, ms2560, spare10, spare9, spare8, - # spare7, spare6, spare5, spare4, spare3, spare2, spare1 } - - # UplinkConfig - # BWP-Uplink - # BWP 1 Configuration - ul_bwp-Id_1 = 1; - ul_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - ul_bwp1_subcarrierSpacing = 1; - - # BWP 2 Configuration - ul_bwp-Id_2 = 2; - ul_bwp2_locationAndBandwidth = 13750; // RBstart=0, L=51 (20 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - ul_bwp2_subcarrierSpacing = 1; - - # BWP 3 Configuration - ul_bwp-Id_3 = 3; - ul_bwp3_locationAndBandwidth = 6325; // RBstart=0, L=24 (10 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - ul_bwp3_subcarrierSpacing = 1; - - firstActiveUplinkBWP-Id = 1; #BWP-Id - } - ); + first_active_bwp = 1; + bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;}, + { scs = 1; bwpStart = 0; bwpSize = 51;}, + { scs = 1; bwpStart = 0; bwpSize = 24;}); # ------- SCTP definitions @@ -236,7 +179,6 @@ MACRLCs = ( tr_n_preference = "local_RRC"; pusch_TargetSNRx10 = 250; pucch_TargetSNRx10 = 200; - ulsch_max_frame_inactivity = 0; } ); diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.yaml b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.yaml index a9257ff2c4..e7019b1833 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.yaml +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.yaml @@ -79,9 +79,6 @@ gNBs: #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep: 1 - #ra_ReponseWindow - #1,2,4,8,10,20,40,80 - ra_ResponseWindow: 5 #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4 diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrp310.2x2.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrp310.2x2.conf index 4f546e7f30..263a8444ba 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrp310.2x2.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrp310.2x2.conf @@ -85,9 +85,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf index ba06b69dd2..ee59af2d80 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf @@ -78,9 +78,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpn310.ddsuu-2x2.conf b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpn310.ddsuu-2x2.conf index 05e6c5c67d..59142efec8 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpn310.ddsuu-2x2.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.106prb.usrpn310.ddsuu-2x2.conf @@ -98,9 +98,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.162prb.usrpn310.2x2.conf b/ci-scripts/conf_files/gnb.sa.band78.162prb.usrpn310.2x2.conf index aa7e011ef2..74e3f6e45f 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.162prb.usrpn310.2x2.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.162prb.usrpn310.2x2.conf @@ -99,9 +99,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf index e6baa257bc..4a3d2852c4 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.24prb.rfsim.conf @@ -80,9 +80,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf b/ci-scripts/conf_files/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf index 6a3c31e71a..8d6a0e90cd 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf @@ -87,9 +87,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.273prb.rfsim.2x2.conf b/ci-scripts/conf_files/gnb.sa.band78.273prb.rfsim.2x2.conf index f158cb42bb..cd949fe8d0 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.273prb.rfsim.2x2.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.273prb.rfsim.2x2.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -185,6 +182,7 @@ L1s = ( num_cc = 1; tr_n_preference = "local_mac"; prach_dtx_threshold = 120; + tx_amp_backoff_dB = 30; } ); diff --git a/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.2x2.conf b/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.2x2.conf index fc90aa6a88..4a0fa03c60 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.2x2.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.2x2.conf @@ -87,9 +87,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf b/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf index 143a1455e3..e9f3089019 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.51prb.aw2s.ddsuu.conf @@ -25,6 +25,7 @@ gNBs = pusch_AntennaPorts = 1; do_CSIRS = 1; do_SRS = 0; + uess_agg_levels = [2, 2, 2, 0, 0]; servingCellConfigCommon = ( { @@ -34,11 +35,11 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL - # this is 3469.44 MHz => 301 REs from PointA 25 PRBs + 1 RE - absoluteFrequencySSB = 631296; + # this is 3410.400 MHz + absoluteFrequencySSB = 627360; dl_frequencyBand = 78; - # this is 3469.44 - (51*12*30e-3/2) = 3460.26 MHz - dl_absoluteFrequencyPointA = 630684; + # this is 3401.220 MHz + dl_absoluteFrequencyPointA = 626748; #scs-SpecificCarrierList dl_offstToCarrier = 0; # subcarrierSpacing @@ -87,9 +88,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -153,6 +151,11 @@ gNBs = ); + RedCap: { + cellBarredRedCap1Rx_r17 = 1; + cellBarredRedCap2Rx_r17 = 1; + intraFreqReselectionRedCap_r17 = 0; + } # ------- SCTP definitions SCTP : diff --git a/ci-scripts/conf_files/gnb.sa.band78.51prb.usrpb200.conf b/ci-scripts/conf_files/gnb.sa.band78.51prb.usrpb200.conf index 83495e1c5d..0057d9b75f 100644 --- a/ci-scripts/conf_files/gnb.sa.band78.51prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb.sa.band78.51prb.usrpb200.conf @@ -78,9 +78,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/neighbour-config-ho.conf b/ci-scripts/conf_files/neighbour-config-ho.conf new file mode 100644 index 0000000000..2490ce1883 --- /dev/null +++ b/ci-scripts/conf_files/neighbour-config-ho.conf @@ -0,0 +1,54 @@ +neighbour_list = ( + { + nr_cellid = 12345678; + neighbour_cell_configuration = ( + { + gNB_ID = 0xe01; + nr_cellid = 11111111; + physical_cellId = 1; + absoluteFrequencySSB = 679104; + subcarrierSpacing = 1; #30 KHz + band = 77; + plmn = { mcc = 001; mnc = 03; mnc_length = 2}; + tracking_area_code = 1; + } + ) + }, + { + nr_cellid = 11111111; + neighbour_cell_configuration = ( + { + gNB_ID = 0xe00; + nr_cellid = 12345678; + physical_cellId = 0; + absoluteFrequencySSB = 679104; + subcarrierSpacing = 1; #30 KHz + band = 77; + plmn = { mcc = 001; mnc = 03; mnc_length = 2}; + tracking_area_code = 1; + } + ) + } + ); + + +nr_measurement_configuration = { + Periodical = { + enable = 1; + includeBeamMeasurements = 1; + maxNrofRS_IndexesToReport = 4; + }; + + A2 = { + enable = 1; + threshold = 110; + timeToTrigger = 1; + }; + + A3 = ({ + cell_id = -1; #Default + offset = 10; + hysteresis = 0; + timeToTrigger = 1 + }) +}; diff --git a/ci-scripts/conf_files/neighbour-config.conf b/ci-scripts/conf_files/neighbour-config.conf index 875129365e..a498dbf157 100644 --- a/ci-scripts/conf_files/neighbour-config.conf +++ b/ci-scripts/conf_files/neighbour-config.conf @@ -1,52 +1,51 @@ -neighbour_list = ( - { - nr_cellid = 1; - neighbour_cell_configuration = ( - { - gNB_ID = 0xb00; - nr_cellid = 2; - physical_cellId = 0x002; - absoluteFrequencySSB = 641280 ; - subcarrierSpacing = 1; #30 KHz - plmn = { mcc = 216; mnc = 03; mnc_length = 2}; - tracking_area_code = 2; - }, - { - gNB_ID = 0xa00; - nr_cellid = 3; - physical_cellId = 0x003; - absoluteFrequencySSB = 641280 ; - subcarrierSpacing = 1; #30 KHz - plmn = { mcc = 999; mnc = 99; mnc_length = 2}; - tracking_area_code = 3; - }, - { - gNB_ID = 0xc00; - nr_cellid = 4; - physical_cellId = 0x004; - absoluteFrequencySSB = 641280 ; - subcarrierSpacing = 1; #30 KHz - plmn = { mcc = 999; mnc = 99; mnc_length = 2}; - tracking_area_code = 4; - } - ) - }, - { - nr_cellid = 2; - neighbour_cell_configuration = ( - { - gNB_ID = 0xe00; - nr_cellid = 1; - physical_cellId = 0x000; - absoluteFrequencySSB = 641280 ; - subcarrierSpacing = 1; #30 KHz - plmn = { mcc = 001; mnc = 01; mnc_length = 2}; - tracking_area_code = 1; - } - ) - } - ); +############################################################ +# gNB-to-gNB neighbour list + measurement configuration # +# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) # +############################################################ +neighbour_list = ( + ########################################################## + # Entry USED BY gNB_ID = 0xe00 (nr_cellid = 1) # + ########################################################## + { + nr_cellid = 0; # Serving cell of gNB 0xe00 + neighbour_cell_configuration = ( + { + gNB_ID = 0xb00; + nr_cellid = 1; # Cell served by gNB 0xb00 + physical_cellId = 1; + absoluteFrequencySSB= 621312; + subcarrierSpacing = 1; # 30 kHz + band = 78; + plmn = { mcc = 208; mnc = 99; mnc_length = 2 }; + tracking_area_code = 1; + } + ); + }, + + ########################################################## + # Entry USED BY gNB_ID = 0xb00 (nr_cellid = 2) # + ########################################################## + { + nr_cellid = 1; # Serving cell of gNB 0xb00 + neighbour_cell_configuration = ( + { + gNB_ID = 0xe00; + nr_cellid = 0; # Cell served by gNB 0xe00 + physical_cellId = 0; + absoluteFrequencySSB= 641280; + subcarrierSpacing = 1; # 30 kHz + band = 78; + plmn = { mcc = 208; mnc = 99; mnc_length = 2 }; + tracking_area_code = 1; + } + ); + } +); + +############################################################ +# Common NR measurement-event configuration # +############################################################ nr_measurement_configuration = { Periodical = { diff --git a/ci-scripts/conf_files/untested/benetel-5g.conf b/ci-scripts/conf_files/untested/benetel-5g.conf index 9bd8ed126e..80eef61908 100644 --- a/ci-scripts/conf_files/untested/benetel-5g.conf +++ b/ci-scripts/conf_files/untested/benetel-5g.conf @@ -83,13 +83,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 2; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; -#oneHalf (0..15) 4,8,12,16,...60,64 +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; //15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/conf_files/untested/episci/episci_rcc.band78.tm1.106PRB.nfapi.conf b/ci-scripts/conf_files/untested/episci/episci_rcc.band78.tm1.106PRB.nfapi.conf index ae1b335a27..73e7ad0151 100644 --- a/ci-scripts/conf_files/untested/episci/episci_rcc.band78.tm1.106PRB.nfapi.conf +++ b/ci-scripts/conf_files/untested/episci/episci_rcc.band78.tm1.106PRB.nfapi.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/untested/episci/gnb_band78.sa.fr1.106PRB.2x2.l2sim.conf b/ci-scripts/conf_files/untested/episci/gnb_band78.sa.fr1.106PRB.2x2.l2sim.conf index 27358d99af..dda8cc11c4 100644 --- a/ci-scripts/conf_files/untested/episci/gnb_band78.sa.fr1.106PRB.2x2.l2sim.conf +++ b/ci-scripts/conf_files/untested/episci/gnb_band78.sa.fr1.106PRB.2x2.l2sim.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/untested/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf b/ci-scripts/conf_files/untested/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf index 978b8e22ec..9ca5210ec6 100644 --- a/ci-scripts/conf_files/untested/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf +++ b/ci-scripts/conf_files/untested/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/ci-scripts/conf_files/untested/gNB_SA_n78_106PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/untested/gNB_SA_n78_106PRB.2x2_usrpn310.conf index 43e11c6c40..c15e6d50c0 100644 --- a/ci-scripts/conf_files/untested/gNB_SA_n78_106PRB.2x2_usrpn310.conf +++ b/ci-scripts/conf_files/untested/gNB_SA_n78_106PRB.2x2_usrpn310.conf @@ -98,13 +98,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen - ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; -#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/conf_files/untested/gNB_SA_n78_133PRB.2x2_usrpn310.conf b/ci-scripts/conf_files/untested/gNB_SA_n78_133PRB.2x2_usrpn310.conf index 4e8c55851e..0fc59f4aff 100644 --- a/ci-scripts/conf_files/untested/gNB_SA_n78_133PRB.2x2_usrpn310.conf +++ b/ci-scripts/conf_files/untested/gNB_SA_n78_133PRB.2x2_usrpn310.conf @@ -94,13 +94,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen - ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; -#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/conf_files/untested/gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/untested/gnb.band78.sa.fr1.106PRB.usrpn310.conf index 4ffcf8fa3a..fac93fa30b 100644 --- a/ci-scripts/conf_files/untested/gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/untested/gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -103,13 +103,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen - ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; -#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/conf_files/untested/gnb.band78.tm1.fr1.106PRB.usrpb210.conf b/ci-scripts/conf_files/untested/gnb.band78.tm1.fr1.106PRB.usrpb210.conf index dfd0996a05..85d8b99ed1 100644 --- a/ci-scripts/conf_files/untested/gnb.band78.tm1.fr1.106PRB.usrpb210.conf +++ b/ci-scripts/conf_files/untested/gnb.band78.tm1.fr1.106PRB.usrpb210.conf @@ -77,13 +77,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; -#oneHalf (0..15) 4,8,12,16,...60,64 +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; //15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/conf_files/untested/gnb.band78.tm1.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/untested/gnb.band78.tm1.fr1.106PRB.usrpn310.conf index a8a45e8a68..b6852fa417 100644 --- a/ci-scripts/conf_files/untested/gnb.band78.tm1.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/untested/gnb.band78.tm1.fr1.106PRB.usrpn310.conf @@ -82,13 +82,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; -#oneHalf (0..15) 4,8,12,16,...60,64 +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; //15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/conf_files/untested/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/ci-scripts/conf_files/untested/gnb.sa.band66.fr1.106PRB.usrpn300.conf index 29cc65e17b..36a79087ae 100644 --- a/ci-scripts/conf_files/untested/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/ci-scripts/conf_files/untested/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -81,13 +81,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; -#oneHalf (0..15) 4,8,12,16,...60,64 +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/conf_files/untested/gnb.sa.band78.fr1.51PRB.usrpb210.conf b/ci-scripts/conf_files/untested/gnb.sa.band78.fr1.51PRB.usrpb210.conf index 85bc18fa17..7242b91190 100644 --- a/ci-scripts/conf_files/untested/gnb.sa.band78.fr1.51PRB.usrpb210.conf +++ b/ci-scripts/conf_files/untested/gnb.sa.band78.fr1.51PRB.usrpb210.conf @@ -80,13 +80,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; -#oneHalf (0..15) 4,8,12,16,...60,64 +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/conf_files/untested/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf b/ci-scripts/conf_files/untested/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf index 0ff2cfa2e2..7018e6704e 100644 --- a/ci-scripts/conf_files/untested/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf +++ b/ci-scripts/conf_files/untested/proxy_gnb.band78.sa.fr1.106PRB.usrpn310.conf @@ -79,13 +79,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; -#oneHalf (0..15) 4,8,12,16,...60,64 +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/ci-scripts/datalog_rt_stats.100.2x2.yaml b/ci-scripts/datalog_rt_stats.100.2x2.yaml index 024dfa8e9e..7c5cb48add 100644 --- a/ci-scripts/datalog_rt_stats.100.2x2.yaml +++ b/ci-scripts/datalog_rt_stats.100.2x2.yaml @@ -19,6 +19,9 @@ Ref : DL & UL scheduling timing : 17.0 UL Indication : 1.0 Slot Indication : 13.0 + feprx : 151.0 + feptx_ofdm (per port, half_slot) : 57 + feptx_total : 148 DeviationThreshold : feprx : 0.25 feptx_prec : 0.25 @@ -32,3 +35,6 @@ DeviationThreshold : DL & UL scheduling timing : 0.25 UL Indication : 1.00 Slot Indication : 0.50 + feprx : 0.25 + feptx_ofdm (per port, half_slot) : 0.25 + feptx_total : 0.25 diff --git a/ci-scripts/datalog_rt_stats.1x1.60.yaml b/ci-scripts/datalog_rt_stats.1x1.60.yaml index 85075bac97..5e0564977b 100644 --- a/ci-scripts/datalog_rt_stats.1x1.60.yaml +++ b/ci-scripts/datalog_rt_stats.1x1.60.yaml @@ -19,6 +19,9 @@ Ref : DL & UL scheduling timing : 5.0 UL Indication : 1.0 Slot Indication : 6.0 + feprx : 44.0 + feptx_ofdm (per port, half_slot) : 31 + feptx_total : 58 DeviationThreshold : feprx : 0.25 feptx_prec : 0.25 @@ -32,3 +35,6 @@ DeviationThreshold : DL & UL scheduling timing : 0.50 UL Indication : 1.00 Slot Indication : 0.50 + feprx : 0.25 + feptx_ofdm (per port, half_slot) : 0.25 + feptx_total : 0.25 diff --git a/ci-scripts/datalog_rt_stats.60.2x2.yaml b/ci-scripts/datalog_rt_stats.60.2x2.yaml index b371356971..7352136764 100644 --- a/ci-scripts/datalog_rt_stats.60.2x2.yaml +++ b/ci-scripts/datalog_rt_stats.60.2x2.yaml @@ -19,6 +19,9 @@ Ref : DL & UL scheduling timing : 8.0 UL Indication : 3.0 Slot Indication : 9.0 + feprx : 85.0 + feptx_ofdm (per port, half_slot) : 31 + feptx_total : 92 DeviationThreshold : feprx : 0.25 feptx_prec : 0.25 @@ -32,3 +35,6 @@ DeviationThreshold : DL & UL scheduling timing : 0.35 UL Indication : 1.00 Slot Indication : 0.35 + feprx : 0.25 + feptx_ofdm (per port, half_slot) : 0.25 + feptx_total : 0.25 diff --git a/ci-scripts/datalog_rt_stats.default.yaml b/ci-scripts/datalog_rt_stats.default.yaml index 32977944a0..be3f8b277e 100644 --- a/ci-scripts/datalog_rt_stats.default.yaml +++ b/ci-scripts/datalog_rt_stats.default.yaml @@ -19,6 +19,9 @@ Ref : DL & UL scheduling timing : 4.0 UL Indication : 2.0 Slot Indication : 5.0 + feprx : 43.0 + feptx_ofdm (per port, half_slot) : 30 + feptx_total : 57 DeviationThreshold : feprx : 0.25 feptx_prec : 0.25 @@ -32,3 +35,6 @@ DeviationThreshold : DL & UL scheduling timing : 0.50 UL Indication : 1.00 Slot Indication : 0.50 + feprx : 0.25 + feptx_ofdm (per port, half_slot) : 0.25 + feptx_total : 0.25 diff --git a/ci-scripts/docker/Dockerfile.cppcheck.xenial b/ci-scripts/docker/Dockerfile.cppcheck.xenial index 5a61532346..f2c5856358 100644 --- a/ci-scripts/docker/Dockerfile.cppcheck.xenial +++ b/ci-scripts/docker/Dockerfile.cppcheck.xenial @@ -30,8 +30,8 @@ FROM ubuntu:xenial AS oai-cppcheck ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ build-essential \ vim \ cppcheck diff --git a/ci-scripts/docker/Dockerfile.formatting.bionic b/ci-scripts/docker/Dockerfile.formatting.ubuntu similarity index 92% rename from ci-scripts/docker/Dockerfile.formatting.bionic rename to ci-scripts/docker/Dockerfile.formatting.ubuntu index a8d58f511c..382dcb3514 100644 --- a/ci-scripts/docker/Dockerfile.formatting.bionic +++ b/ci-scripts/docker/Dockerfile.formatting.ubuntu @@ -21,11 +21,11 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 +# Valid for Ubuntu 24.04 # #--------------------------------------------------------------------- -FROM ubuntu:bionic AS oai-formatting-check +FROM ubuntu:noble AS oai-formatting-check ARG MERGE_REQUEST ARG SRC_BRANCH @@ -33,8 +33,8 @@ ARG TARGET_BRANCH ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ gawk \ git diff --git a/ci-scripts/docker/Dockerfile.physim.ubuntu b/ci-scripts/docker/Dockerfile.physim.ubuntu new file mode 100644 index 0000000000..8fe6d91c4a --- /dev/null +++ b/ci-scripts/docker/Dockerfile.physim.ubuntu @@ -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 +# */ +#--------------------------------------------------------------------- +# +# Dockerfile for the Open-Air-Interface BUILD service +# Valid for Ubuntu 24.04 +# +#--------------------------------------------------------------------- + +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 \ +# libyaml-cpp-dev + +RUN rm -Rf /oai-ran +WORKDIR /oai-ran +COPY . . + +WORKDIR /oai-ran/build +# TODO should SANITIZE be ON? it makes it compile much longer +RUN cmake -GNinja -DENABLE_PHYSIM_TESTS=ON \ + -DSANITIZE_UNDEFINED=OFF -DSANITIZE_ADDRESS=OFF \ + -DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror \ + -DPHYSIM_CHECK_FILES="ThresholdsGracehopper.cmake" \ + .. && \ + ninja ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim diff --git a/ci-scripts/docker/Dockerfile.unittest.ubuntu22 b/ci-scripts/docker/Dockerfile.unittest.ubuntu similarity index 98% rename from ci-scripts/docker/Dockerfile.unittest.ubuntu22 rename to ci-scripts/docker/Dockerfile.unittest.ubuntu index 627b0d07f7..eb18bc24c4 100644 --- a/ci-scripts/docker/Dockerfile.unittest.ubuntu22 +++ b/ci-scripts/docker/Dockerfile.unittest.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 +# Valid for Ubuntu 24.04 # #--------------------------------------------------------------------- diff --git a/ci-scripts/helpreadme.py b/ci-scripts/helpreadme.py index ce4c594f58..a9783bd1f0 100644 --- a/ci-scripts/helpreadme.py +++ b/ci-scripts/helpreadme.py @@ -52,10 +52,7 @@ def GitSrvHelp(repository,branch,commit,mergeallow,targetbranch): print(' --ranAllowMerge=[Allow Merge Request (with target branch) (true or false)] -- ' + mergeallow) print(' --ranTargetBranch=[Target Branch in case of a Merge Request] -- ' + targetbranch) -def eNBSrvHelp(ipaddr, username, password, sourcepath): - print(' --eNBIPAddress=[eNB\'s IP Address] -- ' + ipaddr) - print(' --eNBUserName=[eNB\'s Login User Name] -- ' + username) - print(' --eNBPassword=[eNB\'s Login Password] -- ' + password) +def eNBSrvHelp(sourcepath): print(' --eNBSourceCodePath=[eNB\'s Source Code Path] -- ' + sourcepath) def XmlHelp(filename): diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 333d515858..ac4ac2c3be 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -43,8 +43,10 @@ import cls_containerize #class Containerize for all container-based operations import cls_static_code_analysis #class for static code analysis import cls_cluster # class for building/deploying on cluster import cls_native # class for all native/source-based operations +from cls_ci_helper import TestCaseCtx import ran +import cls_cmd import cls_oai_html @@ -91,7 +93,7 @@ def AssignParams(params_dict): setattr(RAN, key, value) setattr(HTML, key, value) -def ExecuteActionWithParam(action): +def ExecuteActionWithParam(action, ctx): global RAN global HTML global CONTAINERS @@ -100,98 +102,46 @@ def ExecuteActionWithParam(action): if action == 'Build_eNB' or action == 'Build_Image' or action == 'Build_Proxy' or action == "Build_Cluster_Image" or action == "Build_Run_Tests": RAN.Build_eNB_args=test.findtext('Build_eNB_args') CONTAINERS.imageKind=test.findtext('kind') - forced_workspace_cleanup = test.findtext('forced_workspace_cleanup') - RAN.Build_eNB_forced_workspace_cleanup=False - CONTAINERS.forcedWorkspaceCleanup=False - CLUSTER.forcedWorkspaceCleanup = False - if forced_workspace_cleanup is not None and re.match('true', forced_workspace_cleanup, re.IGNORECASE): - RAN.Build_eNB_forced_workspace_cleanup = True - CONTAINERS.forcedWorkspaceCleanup = True - CLUSTER.forcedWorkspaceCleanup = True - eNB_instance=test.findtext('eNB_instance') - if (eNB_instance is None): - RAN.eNB_instance=0 - CONTAINERS.eNB_instance=0 - else: - RAN.eNB_instance=int(eNB_instance) - CONTAINERS.eNB_instance=int(eNB_instance) - eNB_serverId=test.findtext('eNB_serverId') - if (eNB_serverId is None): - RAN.eNB_serverId[RAN.eNB_instance]='0' - CONTAINERS.eNB_serverId[RAN.eNB_instance]='0' - else: - RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId - CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]=eNB_serverId - xmlBgBuildField = test.findtext('backgroundBuild') - if (xmlBgBuildField is None): - RAN.backgroundBuild=False - else: - if re.match('true', xmlBgBuildField, re.IGNORECASE): - RAN.backgroundBuild=True - else: - RAN.backgroundBuild=False + node = test.findtext('node') proxy_commit = test.findtext('proxy_commit') if proxy_commit is not None: CONTAINERS.proxyCommit = proxy_commit if action == 'Build_eNB': - success = cls_native.Native.Build(HTML.testCase_id, HTML, RAN.eNBIPAddress, RAN.eNBSourceCodePath, RAN.Build_eNB_args) + success = cls_native.Native.Build(ctx, node, HTML.testCase_id, HTML, RAN.eNBSourceCodePath, RAN.Build_eNB_args) elif action == 'Build_Image': - success = CONTAINERS.BuildImage(HTML) + success = CONTAINERS.BuildImage(ctx, node, HTML) elif action == 'Build_Proxy': - success = CONTAINERS.BuildProxy(HTML) + success = CONTAINERS.BuildProxy(ctx, node, HTML) elif action == 'Build_Cluster_Image': - success = CLUSTER.BuildClusterImage(HTML) + success = CLUSTER.BuildClusterImage(ctx, node, HTML) elif action == 'Build_Run_Tests': - success = CONTAINERS.BuildRunTests(HTML) + success = CONTAINERS.BuildRunTests(ctx, node, HTML) elif action == 'Initialize_eNB': + node = test.findtext('node') datalog_rt_stats_file=test.findtext('rt_stats_cfg') if datalog_rt_stats_file is None: RAN.datalog_rt_stats_file='datalog_rt_stats.default.yaml' else: RAN.datalog_rt_stats_file=datalog_rt_stats_file RAN.Initialize_eNB_args=test.findtext('Initialize_eNB_args') - eNB_instance=test.findtext('eNB_instance') - USRPIPAddress=test.findtext('USRP_IPAddress') - if USRPIPAddress is None: - RAN.USRPIPAddress='' - else: - RAN.USRPIPAddress=USRPIPAddress - if (eNB_instance is None): - RAN.eNB_instance=0 - else: - RAN.eNB_instance=int(eNB_instance) - eNB_serverId=test.findtext('eNB_serverId') - if (eNB_serverId is None): - RAN.eNB_serverId[RAN.eNB_instance]='0' - else: - RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId - + USRPIPAddress = test.findtext('USRP_IPAddress') or '' + #local variable air_interface air_interface = test.findtext('air_interface') if (air_interface is None) or (air_interface.lower() not in ['nr','lte']): - RAN.air_interface[RAN.eNB_instance] = 'lte-softmodem' + RAN.air_interface = 'lte-softmodem' else: - RAN.air_interface[RAN.eNB_instance] = air_interface.lower() +'-softmodem' + RAN.air_interface = air_interface.lower() +'-softmodem' cmd_prefix = test.findtext('cmd_prefix') if cmd_prefix is not None: RAN.cmd_prefix = cmd_prefix - success = RAN.InitializeeNB(HTML) + success = RAN.InitializeeNB(ctx, node, HTML) elif action == 'Terminate_eNB': - eNB_instance=test.findtext('eNB_instance') - if (eNB_instance is None): - RAN.eNB_instance=0 - else: - RAN.eNB_instance=int(eNB_instance) - eNB_serverId=test.findtext('eNB_serverId') - if (eNB_serverId is None): - RAN.eNB_serverId[RAN.eNB_instance]='0' - else: - RAN.eNB_serverId[RAN.eNB_instance]=eNB_serverId - + node = test.findtext('node') #retx checkers - string_field=test.findtext('d_retx_th') + string_field = test.findtext('d_retx_th') if (string_field is not None): RAN.ran_checkers['d_retx_th'] = [float(x) for x in string_field.split(',')] string_field=test.findtext('u_retx_th') @@ -201,10 +151,10 @@ def ExecuteActionWithParam(action): #local variable air_interface air_interface = test.findtext('air_interface') if (air_interface is None) or (air_interface.lower() not in ['nr','lte']): - RAN.air_interface[RAN.eNB_instance] = 'lte-softmodem' + RAN.air_interface = 'lte-softmodem' else: - RAN.air_interface[RAN.eNB_instance] = air_interface.lower() +'-softmodem' - success = RAN.TerminateeNB(HTML) + RAN.air_interface = air_interface.lower() +'-softmodem' + success = RAN.TerminateeNB(ctx, node, HTML) elif action == 'Initialize_UE' or action == 'Attach_UE' or action == 'Detach_UE' or action == 'Terminate_UE' or action == 'CheckStatusUE' or action == 'DataEnable_UE' or action == 'DataDisable_UE': CiTestObj.ue_ids = test.findtext('id').split(' ') @@ -226,7 +176,7 @@ def ExecuteActionWithParam(action): elif action == 'Detach_UE': success = CiTestObj.DetachUE(HTML) elif action == 'Terminate_UE': - success = CiTestObj.TerminateUE(HTML) + success = CiTestObj.TerminateUE(ctx, HTML) elif action == 'CheckStatusUE': success = CiTestObj.CheckStatusUE(HTML) elif action == 'DataEnable_UE': @@ -253,7 +203,7 @@ def ExecuteActionWithParam(action): else: CiTestObj.nodes = [None] * len(CiTestObj.ue_ids) ping_rttavg_threshold = test.findtext('ping_rttavg_threshold') or '' - success = CiTestObj.Ping(HTML, CONTAINERS) + success = CiTestObj.Ping(ctx, HTML) elif action == 'Iperf' or action == 'Iperf2_Unidir': CiTestObj.iperf_args = test.findtext('iperf_args') @@ -284,81 +234,76 @@ def ExecuteActionWithParam(action): logging.error('test-case has wrong option ' + CiTestObj.iperf_options) CiTestObj.iperf_options = 'check' if action == 'Iperf': - success = CiTestObj.Iperf(HTML, CONTAINERS) + success = CiTestObj.Iperf(ctx, HTML) elif action == 'Iperf2_Unidir': - success = CiTestObj.Iperf2_Unidir(HTML, CONTAINERS) + success = CiTestObj.Iperf2_Unidir(ctx, HTML) elif action == 'IdleSleep': st = test.findtext('idle_sleep_time_in_sec') or "5" success = cls_oaicitest.IdleSleep(HTML, int(st)) - elif action == 'Deploy_Run_PhySim': + elif action == 'Deploy_Run_OC_PhySim': oc_release = test.findtext('oc_release') - svr_id = test.findtext('svr_id') or None - success = CLUSTER.deploy_oc_physim(HTML, oc_release, svr_id) + node = test.findtext('node') or None + script = "scripts/oc-deploy-physims.sh" + image_tag = cls_containerize.CreateTag(CLUSTER.ranCommitID, CLUSTER.ranBranch, CLUSTER.ranAllowMerge) + options = f"oaicicd-core-for-ci-ran {oc_release} {image_tag} {CLUSTER.eNBSourceCodePath}" + workdir = CLUSTER.eNBSourceCodePath + success = cls_oaicitest.Deploy_Physim(ctx, HTML, node, workdir, script, options) + + elif action == 'Build_Deploy_Docker_PhySim' or action == 'Build_Deploy_Source_PhySim': + node = test.findtext('node') or None + ctest_opt = test.findtext('ctest-opt') or '' + script = "scripts/docker-build-and-deploy-physims.sh" if action == 'Build_Deploy_Docker_PhySim' else 'scripts/source-deploy-physims.sh' + options = f"{CONTAINERS.eNBSourceCodePath} {ctest_opt}" + workdir = CONTAINERS.eNBSourceCodePath + success = cls_oaicitest.Deploy_Physim(ctx, HTML, node, workdir, script, options) elif action == 'DeployCoreNetwork' or action == 'UndeployCoreNetwork': cn_id = test.findtext('cn_id') core_op = getattr(cls_oaicitest.OaiCiTest, action) - success = core_op(cn_id, HTML) + success = core_op(cn_id, ctx, HTML) elif action == 'Deploy_Object' or action == 'Undeploy_Object' or action == "Create_Workspace": - eNB_instance=test.findtext('eNB_instance') - if (eNB_instance is None): - CONTAINERS.eNB_instance=0 - else: - CONTAINERS.eNB_instance=int(eNB_instance) - eNB_serverId=test.findtext('eNB_serverId') - if (eNB_serverId is None): - CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]='0' - else: - CONTAINERS.eNB_serverId[CONTAINERS.eNB_instance]=eNB_serverId - string_field = test.findtext('yaml_path') - if (string_field is not None): - CONTAINERS.yamlPath[CONTAINERS.eNB_instance] = string_field + node = test.findtext('node') + CONTAINERS.yamlPath = test.findtext('yaml_path') string_field=test.findtext('d_retx_th') if (string_field is not None): CONTAINERS.ran_checkers['d_retx_th'] = [float(x) for x in string_field.split(',')] string_field=test.findtext('u_retx_th') if (string_field is not None): CONTAINERS.ran_checkers['u_retx_th'] = [float(x) for x in string_field.split(',')] - string_field = test.findtext('services') - if string_field is not None: - CONTAINERS.services[CONTAINERS.eNB_instance] = string_field + CONTAINERS.services = test.findtext('services') CONTAINERS.num_attempts = int(test.findtext('num_attempts') or 1) CONTAINERS.deploymentTag = cls_containerize.CreateTag(CONTAINERS.ranCommitID, CONTAINERS.ranBranch, CONTAINERS.ranAllowMerge) if action == 'Deploy_Object': - success = CONTAINERS.DeployObject(HTML) + success = CONTAINERS.DeployObject(ctx, node, HTML) elif action == 'Undeploy_Object': - success = CONTAINERS.UndeployObject(HTML, RAN) + success = CONTAINERS.UndeployObject(ctx, node, HTML, RAN) elif action == 'Create_Workspace': if force_local: # Do not create a working directory when running locally. Current repo directory will be used return True - success = CONTAINERS.Create_Workspace(HTML) - - elif action == 'Run_Physim': - physim_options = test.findtext('physim_run_args') - physim_test = test.findtext('physim_test') - physim_threshold = test.findtext('physim_time_threshold') or 'inf' - success = cls_native.Native.Run_Physim(HTML, RAN.eNBIPAddress, RAN.eNBSourceCodePath, physim_options, physim_test, physim_threshold) + success = CONTAINERS.Create_Workspace(node, HTML) elif action == 'LicenceAndFormattingCheck': - success = SCA.LicenceAndFormattingCheck(HTML) + node = test.findtext('node') + success = SCA.LicenceAndFormattingCheck(ctx, node, HTML) elif action == 'Cppcheck_Analysis': - success = SCA.CppCheckAnalysis(HTML) + node = test.findtext('node') + success = SCA.CppCheckAnalysis(ctx, node, HTML) elif action == 'Push_Local_Registry': - svr_id = test.findtext('svr_id') + node = test.findtext('node') tag_prefix = test.findtext('tag_prefix') or "" - success = CONTAINERS.Push_Image_to_Local_Registry(HTML, svr_id, tag_prefix) + success = CONTAINERS.Push_Image_to_Local_Registry(node, HTML, tag_prefix) elif action == 'Pull_Local_Registry' or action == 'Clean_Test_Server_Images': if force_local: # Do not pull or remove images when running locally. User is supposed to handle image creation & cleanup return True - svr_id = test.findtext('svr_id') + node = test.findtext('node') tag_prefix = test.findtext('tag_prefix') or "" images = test.findtext('images').split() # hack: for FlexRIC, we need to overwrite the tag to use @@ -366,9 +311,9 @@ def ExecuteActionWithParam(action): if len(images) == 1 and images[0] == "oai-flexric": tag = CONTAINERS.flexricTag if action == "Pull_Local_Registry": - success = CONTAINERS.Pull_Image_from_Registry(HTML, svr_id, images, tag=tag, tag_prefix=tag_prefix) + success = CONTAINERS.Pull_Image_from_Registry(HTML, node, images, tag=tag, tag_prefix=tag_prefix) if action == "Clean_Test_Server_Images": - success = CONTAINERS.Clean_Test_Server_Images(HTML, svr_id, images, tag=tag) + success = CONTAINERS.Clean_Test_Server_Images(HTML, node, images, tag=tag) elif action == 'Custom_Command': node = test.findtext('node') @@ -376,14 +321,16 @@ def ExecuteActionWithParam(action): # Change all execution targets to localhost node = 'localhost' command = test.findtext('command') - command_fail = test.findtext('command_fail') in ['True', 'true', 'Yes', 'yes'] - success = cls_oaicitest.Custom_Command(HTML, node, command, command_fail) + # Allow referencing repository workspace path in XML via %%workspace%% + command = command.replace("%%workspace%%", CONTAINERS.eNBSourceCodePath) + success = cls_oaicitest.Custom_Command(HTML, node, command) elif action == 'Custom_Script': node = test.findtext('node') script = test.findtext('script') - command_fail = test.findtext('command_fail') in ['True', 'true', 'Yes', 'yes'] - success = cls_oaicitest.Custom_Script(HTML, node, script, command_fail) + # Allow referencing repository workspace path in XML via %%workspace%% + script = script.replace("%%workspace%%", CONTAINERS.eNBSourceCodePath) + success = cls_oaicitest.Custom_Script(HTML, node, script) elif action == 'Pull_Cluster_Image': tag_prefix = test.findtext('tag_prefix') or "" @@ -409,10 +356,11 @@ def test_in_list(test, list): def receive_signal(signum, frame): sys.exit(1) - - - - +def ShowTestID(ctx, desc): + logging.info(f'\u001B[1m----------------------------------------\u001B[0m') + logging.info(f'\u001B[1m Test ID: {ctx.test_id} (#{ctx.count}) \u001B[0m') + logging.info(f'\u001B[1m {desc} \u001B[0m') + logging.info(f'\u001B[1m----------------------------------------\u001B[0m') #----------------------------------------------------------- # MAIN PART @@ -468,15 +416,7 @@ if py_param_file_present == True: cwd = os.getcwd() if re.match('^TerminateeNB$', mode, re.IGNORECASE): - if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - if RAN.eNBIPAddress == 'none': - sys.exit(0) - RAN.eNB_instance=0 - RAN.eNB_serverId[0]='0' - RAN.eNBSourceCodePath='/tmp/' - RAN.TerminateeNB(HTML) + logging.warning("Option TerminateeNB ignored") elif re.match('^TerminateHSS$', mode, re.IGNORECASE): logging.warning("Option TerminateHSS ignored") elif re.match('^TerminateMME$', mode, re.IGNORECASE): @@ -484,14 +424,9 @@ elif re.match('^TerminateMME$', mode, re.IGNORECASE): elif re.match('^TerminateSPGW$', mode, re.IGNORECASE): logging.warning("Option TerminateSPGW ignored") elif re.match('^LogCollectBuild$', mode, re.IGNORECASE): - if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '': - logging.warning("nothing to collect (eNBIPAddress/eNBUserName/eNBPassword/eNBSourceCodePath is '')") - sys.exit(0) - if RAN.eNBIPAddress == 'none': - sys.exit(0) - CiTestObj.LogCollectBuild(RAN) + logging.warning("Option LogCollectBuild ignored") elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): - if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '': + if RAN.eNBSourceCodePath == '': HELP.GenericHelp(CONST.Version) sys.exit('Insufficient Parameter') if os.path.isdir('cmake_targets/log'): @@ -503,7 +438,6 @@ elif re.match('^LogCollecteNB$', mode, re.IGNORECASE): logging.error("Command '{}' returned non-zero exit status {}.".format(e.cmd, e.returncode)) logging.error("Error output:\n{}".format(e.output)) sys.exit(0) - RAN.LogCollecteNB() elif re.match('^LogCollectHSS$', mode, re.IGNORECASE): logging.warning("Option LogCollectHSS ignored") elif re.match('^LogCollectMME$', mode, re.IGNORECASE): @@ -548,12 +482,12 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re logging.info('\u001B[1m Starting Scenario: ' + CiTestObj.testXMLfiles[0] + '\u001B[0m') logging.info('\u001B[1m----------------------------------------\u001B[0m') if re.match('^TesteNB$', mode, re.IGNORECASE): - if RAN.eNBIPAddress == '' or RAN.ranRepository == '' or RAN.ranBranch == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '': + if RAN.ranRepository == '' or RAN.ranBranch == '' or RAN.eNBSourceCodePath == '': HELP.GenericHelp(CONST.Version) if RAN.ranRepository == '': HELP.GitSrvHelp(RAN.ranRepository, RAN.ranBranch, RAN.ranCommitID, RAN.ranAllowMerge, RAN.ranTargetBranch) - if RAN.eNBIPAddress == '' or RAN.eNBUserName == '' or RAN.eNBPassword == '' or RAN.eNBSourceCodePath == '': - HELP.eNBSrvHelp(RAN.eNBIPAddress, RAN.eNBUserName, RAN.eNBPassword, RAN.eNBSourceCodePath) + if RAN.eNBSourceCodePath == '': + HELP.eNBSrvHelp(RAN.eNBSourceCodePath) sys.exit('Insufficient Parameter') else: if CiTestObj.ranRepository == '' or CiTestObj.ranBranch == '': @@ -567,6 +501,16 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re else: xml_test_file = cwd + "/" + CiTestObj.testXMLfiles[0] + # directory where all log artifacts will be placed + logPath = f"{cwd}/../cmake_targets/log/{CiTestObj.testXMLfiles[0].split('/')[-1]}.d" + # we run from within ci-scripts, but the logPath is absolute, so replace + # the ci-scripts/..; if it does not exist, nothing will happen + logPath = logPath.replace(r'/ci-scripts/..', '') + logging.info(f"placing all artifacts for this run in {logPath}/") + with cls_cmd.LocalCmd() as c: + c.run(f"rm -rf {logPath}") + c.run(f"mkdir -p {logPath}") + xmlTree = ET.parse(xml_test_file) xmlRoot = xmlTree.getroot() @@ -617,29 +561,35 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re task_set_succeeded = True HTML.startTime=int(round(time.time() * 1000)) + i = 0 for test_case_id in todo_tests: for test in all_tests: id = test.get('id') if test_case_id != id: continue + i += 1 CiTestObj.testCase_id = id + ctx = TestCaseCtx(i, int(id), logPath) HTML.testCase_id=CiTestObj.testCase_id - CiTestObj.desc = test.findtext('desc') + desc = test.findtext('desc') always_exec = test.findtext('always_exec') in ['True', 'true', 'Yes', 'yes'] - HTML.desc=CiTestObj.desc + may_fail = test.findtext('may_fail') in ['True', 'true', 'Yes', 'yes'] + HTML.desc = desc action = test.findtext('class') if (CheckClassValidity(xml_class_list, action, id) == False): task_set_succeeded = False continue - CiTestObj.ShowTestID() + ShowTestID(ctx, desc) if not task_set_succeeded and not always_exec: msg = f"skipping test due to prior error" logging.warning(msg) HTML.CreateHtmlTestRowQueue(msg, "SKIP", []) break try: - test_succeeded = ExecuteActionWithParam(action) - if not test_succeeded: + test_succeeded = ExecuteActionWithParam(action, ctx) + if not test_succeeded and may_fail: + logging.warning(f"test ID {test_case_id} action {action} may or may not fail, proceeding despite error") + elif not test_succeeded: logging.error(f"test ID {test_case_id} action {action} failed ({test_succeeded}), skipping next tests") task_set_succeeded = False except Exception as e: diff --git a/ci-scripts/mbim_scripts/stop_quectel_mbim.sh b/ci-scripts/mbim_scripts/stop_quectel_mbim.sh index e7dbbaa43d..5115646b0d 100644 --- a/ci-scripts/mbim_scripts/stop_quectel_mbim.sh +++ b/ci-scripts/mbim_scripts/stop_quectel_mbim.sh @@ -1,3 +1,7 @@ set -x sudo mbimcli -p -d /dev/cdc-wdm0 --set-radio-state=off + +IF=wwan0 +sudo ip link set ${IF} down +sudo ip addr flush dev ${IF} diff --git a/ci-scripts/ran.py b/ci-scripts/ran.py index 6f58478476..e440fc3a62 100644 --- a/ci-scripts/ran.py +++ b/ci-scripts/ran.py @@ -43,9 +43,10 @@ import cls_cmd #----------------------------------------------------------- # OAI Testing modules #----------------------------------------------------------- -import sshconnection as SSH +import cls_cmd import helpreadme as HELP import constants as CONST +from cls_ci_helper import archiveArtifact #----------------------------------------------------------- # Class Declaration @@ -59,33 +60,14 @@ class RANManagement(): self.ranAllowMerge = False self.ranCommitID = '' self.ranTargetBranch = '' - self.eNBIPAddress = '' - self.eNBUserName = '' - self.eNBPassword = '' self.eNBSourceCodePath = '' - self.eNB1IPAddress = '' - self.eNB1UserName = '' - self.eNB1Password = '' - self.eNB1SourceCodePath = '' - self.eNB2IPAddress = '' - self.eNB2UserName = '' - self.eNB2Password = '' - self.eNB2SourceCodePath = '' - self.Build_eNB_args = '' - self.backgroundBuild = False - self.backgroundBuildTestId = ['', '', ''] - self.Build_eNB_forced_workspace_cleanup = False self.Initialize_eNB_args = '' self.imageKind = '' - self.air_interface = ['', '', ''] #changed from 'lte' to '' may lead to side effects in main - self.eNB_instance = 0 - self.eNB_serverId = ['', '', ''] - self.eNBLogFiles = ['', '', ''] + self.air_interface = '' self.eNBOptions = ['', '', ''] self.eNBmbmsEnables = [False, False, False] self.eNBstatuses = [-1, -1, -1] self.testCase_id = '' - self.epcPcapFile = '' self.runtime_stats= '' self.datalog_rt_stats={} self.datalog_rt_stats_file='datalog_rt_stats.default.yaml' @@ -95,331 +77,104 @@ class RANManagement(): self.cmd_prefix = '' # prefix before {lte,nr}-softmodem self.node = '' self.command = '' - self.command_fail = False #----------------------------------------------------------- # RAN management functions #----------------------------------------------------------- - def InitializeeNB(self, HTML): - if self.eNB_serverId[self.eNB_instance] == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId[self.eNB_instance] == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId[self.eNB_instance] == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - logging.debug('Starting eNB/gNB on server: ' + lIpAddr) + def InitializeeNB(self, ctx, node, HTML): + if not node: + raise ValueError(f"{node=}") + logging.debug('Starting eNB/gNB on server: ' + node) self.testCase_id = HTML.testCase_id - mySSH = SSH.SSHConnection() - cwd = os.getcwd() + lSourcePath = self.eNBSourceCodePath + cmd = cls_cmd.getConnection(node) - mySSH.open(lIpAddr, lUserName, lPassWord) - mySSH.command('cd ' + lSourcePath, '\$', 5) # Initialize_eNB_args usually start with -O and followed by the location in repository full_config_file = self.Initialize_eNB_args.replace('-O ','') extra_options = '' extIdx = full_config_file.find('.conf') - if (extIdx > 0): - extra_options = full_config_file[extIdx + 5:] - # if tracer options is on, compiling and running T Tracer - result = re.search('T_stdout', str(extra_options)) - if result is not None: - logging.debug('\u001B[1m Compiling and launching T Tracer\u001B[0m') - mySSH.command('cd common/utils/T/tracer', '\$', 5) - mySSH.command('make', '\$', 10) - mySSH.command('echo $USER; nohup ./record -d ../T_messages.txt -o ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.raw -ON -off VCD -off HEAVY -off LEGACY_GROUP_TRACE -off LEGACY_GROUP_DEBUG > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '_record.log 2>&1 &', lUserName, 5) - mySSH.command('cd ' + lSourcePath, '\$', 5) - full_config_file = full_config_file[:extIdx + 5] - config_path, config_file = os.path.split(full_config_file) - else: - sys.exit('Insufficient Parameter') - ci_full_config_file = config_path + '/ci-' + config_file - rruCheck = False - result = re.search('^rru|^rcc|^du.band', str(config_file)) - if result is not None: - rruCheck = True - mySSH.command('cp ' + full_config_file + ' ' + ci_full_config_file, '\$', 5) - mySSH.command('sed -i -e \'s/CI_ENB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); - mySSH.command('sed -i -e \'s/CI_GNB_IP_ADDR/' + lIpAddr + '/\' ' + ci_full_config_file, '\$', 2); - mySSH.command('sed -i -e \'s/CI_RCC_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - mySSH.command('sed -i -e \'s/CI_RRU1_IP_ADDR/' + self.eNB1IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - mySSH.command('sed -i -e \'s/CI_RRU2_IP_ADDR/' + self.eNB2IPAddress + '/\' ' + ci_full_config_file, '\$', 2); - mySSH.command('sed -i -e \'s/CI_FR1_CTL_ENB_IP_ADDR/' + self.eNBIPAddress + '/\' ' + ci_full_config_file, '\$', 2); - self.eNBmbmsEnables[int(self.eNB_instance)] = False - mySSH.command('grep --colour=never enable_enb_m2 ' + ci_full_config_file, '\$', 2); - result = re.search('yes', mySSH.getBefore()) - if result is not None: - self.eNBmbmsEnables[int(self.eNB_instance)] = True - logging.debug('\u001B[1m MBMS is enabled on this eNB\u001B[0m') - result = re.search('noS1', str(self.Initialize_eNB_args)) - eNBinNoS1 = False - if result is not None: - eNBinNoS1 = True - logging.debug('\u001B[1m eNB is in noS1 configuration \u001B[0m') - # Launch eNB with the modified config file - mySSH.command('source oaienv', '\$', 5) - mySSH.command('cd cmake_targets', '\$', 5) - if self.air_interface[self.eNB_instance] == 'nr-softmodem': - mySSH.command('if [ -e rbconfig.raw ]; then echo ' + lPassWord + ' | sudo -S rm rbconfig.raw; fi', '\$', 5) - mySSH.command('if [ -e reconfig.raw ]; then echo ' + lPassWord + ' | sudo -S rm reconfig.raw; fi', '\$', 5) - # NOTE: WE SHALL do a check if the executable is present (in case build went wrong) + if (extIdx <= 0): + raise ValueError(f"no config file in {self.Initialize_eNB_args}") + extra_options = full_config_file[extIdx + 5:] + full_config_file = full_config_file[:extIdx + 5] + config_path, config_file = os.path.split(full_config_file) - #hack UHD_RFNOC_DIR variable for gNB / N310 on RHEL8 server: - #if the USRP address is in the xml then we are using an eth USRP (N3xx) - if self.air_interface[self.eNB_instance] == 'lte-softmodem': - gNB = False - else: - gNB = True - mySSH.command(f'echo "ulimit -c unlimited && {self.cmd_prefix} ./ran_build/build/{self.air_interface[self.eNB_instance]} -O {lSourcePath}/{ci_full_config_file} {extra_options}" > ./my-lte-softmodem-run{self.eNB_instance}.sh', '\$', 5) + logfile = f'{lSourcePath}/cmake_targets/enb.log' + cmd.cd(f"{lSourcePath}/cmake_targets/") # important: set wd so nrL1_stats.log etc are logged here + cmd.run(f'sudo -E stdbuf -o0 {self.cmd_prefix} {lSourcePath}/cmake_targets/ran_build/build/{self.air_interface} -O {lSourcePath}/{full_config_file} {extra_options} > {logfile} 2>&1 &') - mySSH.command('chmod 775 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - mySSH.command('echo ' + lPassWord + ' | sudo -S rm -Rf enb_' + self.testCase_id + '.log', '\$', 5) - mySSH.command('echo $USER; nohup sudo -E stdbuf -o0 ./my-lte-softmodem-run' + str(self.eNB_instance) + '.sh > ' + lSourcePath + '/cmake_targets/enb_' + self.testCase_id + '.log 2>&1 &', lUserName, 10) - - self.eNBLogFiles[int(self.eNB_instance)] = 'enb_' + self.testCase_id + '.log' if extra_options != '': - self.eNBOptions[int(self.eNB_instance)] = extra_options - time.sleep(6) - doLoop = True - loopCounter = 20 + self.eNBOptions = extra_options + enbDidSync = False - while (doLoop): - loopCounter = loopCounter - 1 - if (loopCounter == 0): - # In case of T tracer recording, we may need to kill it - result = re.search('T_stdout', str(self.Initialize_eNB_args)) - if result is not None: - mySSH.command('killall --signal SIGKILL record', '\$', 5) - mySSH.close() - doLoop = False - logging.error('\u001B[1;37;41m eNB/gNB logging system did not show got sync! \u001B[0m') - HTML.CreateHtmlTestRow(self.air_interface[self.eNB_instance] + ' -O ' + config_file + extra_options, 'KO', CONST.ALL_PROCESSES_OK) - return False - else: - mySSH.command('stdbuf -o0 cat enb_' + self.testCase_id + '.log | grep -E --text --color=never -i "wait|sync|Starting|Started"', '\$', 4) - if rruCheck: - result = re.search('wait RUs', mySSH.getBefore()) - else: - result = re.search('got sync|Starting F1AP at CU', mySSH.getBefore()) - if result is None: - time.sleep(6) - else: - doLoop = False - enbDidSync = True - time.sleep(10) - - rruCheck = False - result = re.search('^rru|^du.band', str(config_file)) - if result is not None: - rruCheck = True - if enbDidSync and eNBinNoS1 and not rruCheck: - mySSH.command('ifconfig oaitun_enb1', '\$', 4) - mySSH.command('ifconfig oaitun_enb1', '\$', 4) - result = re.search('inet addr:1|inet 1', mySSH.getBefore()) + for _ in range(10): + time.sleep(5) + ret = cmd.run(f'grep --text -E --color=never -i "wait|sync|Starting|Started" {logfile}', reportNonZero=False) + result = re.search('got sync|Starting F1AP at CU', ret.stdout) if result is not None: - logging.debug('\u001B[1m oaitun_enb1 interface is mounted and configured\u001B[0m') - else: - logging.error('\u001B[1m oaitun_enb1 interface is either NOT mounted or NOT configured\u001B[0m') - if self.eNBmbmsEnables[int(self.eNB_instance)]: - mySSH.command('ifconfig oaitun_enm1', '\$', 4) - result = re.search('inet addr', mySSH.getBefore()) - if result is not None: - logging.debug('\u001B[1m oaitun_enm1 interface is mounted and configured\u001B[0m') - else: - logging.error('\u001B[1m oaitun_enm1 interface is either NOT mounted or NOT configured\u001B[0m') + enbDidSync = True + break + if not enbDidSync: + cmd.run(f'sudo killall -9 {self.air_interface}') # in case it did not stop automatically + archiveArtifact(cmd, ctx, logfile) + + cmd.close() + + msg = f'{self.cmd_prefix} {self.air_interface} -O {config_file} {extra_options}' if enbDidSync: - self.eNBstatuses[int(self.eNB_instance)] = int(self.eNB_serverId[self.eNB_instance]) + logging.debug('\u001B[1m Initialize eNB/gNB Completed\u001B[0m') + HTML.CreateHtmlTestRowQueue(msg, 'OK', []) + else: + logging.error('\u001B[1;37;41m eNB/gNB logging system did not show got sync! \u001B[0m') + HTML.CreateHtmlTestRowQueue(msg, 'KO', []) - mySSH.close() - - HTML.CreateHtmlTestRow(f'{self.cmd_prefix} {self.air_interface[self.eNB_instance]} -O {config_file} {extra_options}', 'OK', CONST.ALL_PROCESSES_OK) - logging.debug('\u001B[1m Initialize eNB/gNB Completed\u001B[0m') return enbDidSync - def CheckeNBProcess(self, status_queue): - # At least the instance 0 SHALL be on! - if self.eNBstatuses[0] == 0: - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - elif self.eNBstatuses[0] == 1: - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - elif self.eNBstatuses[0] == 2: - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - else: - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - mySSH = SSH.SSHConnection() - mySSH.open(lIpAddr, lUserName, lPassWord) - if self.air_interface[self.eNB_instance] == '': - pattern = 'softmodem' - else: - pattern = self.air_interface[self.eNB_instance] - mySSH.command('stdbuf -o0 ps -aux | grep --color=never ' + pattern + ' | grep -v grep', '\$', 5) - result = re.search(pattern, mySSH.getBefore()) - success = result is not None - if not success: - logging.debug('\u001B[1;37;41m eNB Process Not Found! \u001B[0m') - status_queue.put(CONST.ENB_PROCESS_FAILED) - else: - status_queue.put(CONST.ENB_PROCESS_OK) - mySSH.close() - return success - - def TerminateeNB(self, HTML): - if self.eNB_serverId[self.eNB_instance] == '0': - lIpAddr = self.eNBIPAddress - lUserName = self.eNBUserName - lPassWord = self.eNBPassword - lSourcePath = self.eNBSourceCodePath - elif self.eNB_serverId[self.eNB_instance] == '1': - lIpAddr = self.eNB1IPAddress - lUserName = self.eNB1UserName - lPassWord = self.eNB1Password - lSourcePath = self.eNB1SourceCodePath - elif self.eNB_serverId[self.eNB_instance] == '2': - lIpAddr = self.eNB2IPAddress - lUserName = self.eNB2UserName - lPassWord = self.eNB2Password - lSourcePath = self.eNB2SourceCodePath - if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - logging.debug('Stopping eNB/gNB on server: ' + lIpAddr) - mySSH = SSH.SSHConnection() - mySSH.open(lIpAddr, lUserName, lPassWord) - mySSH.command('cd ' + lSourcePath + '/cmake_targets', '\$', 5) - if self.air_interface[self.eNB_instance] == 'lte-softmodem': - nodeB_prefix = 'e' - else: - nodeB_prefix = 'g' - mySSH.command('stdbuf -o0 ps -aux | grep --color=never -e softmodem | grep -v grep', '\$', 5) - result = re.search('-softmodem', mySSH.getBefore()) + def TerminateeNB(self, ctx, node, HTML): + logging.debug('Stopping eNB/gNB on server: ' + node) + lSourcePath = self.eNBSourceCodePath + cmd = cls_cmd.getConnection(node) + ret = cmd.run('ps -aux | grep --color=never -e softmodem | grep -v grep') + result = re.search('-softmodem', ret.stdout) if result is not None: - mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGINT -r .*-softmodem || true', '\$', 5) - time.sleep(10) - mySSH.command('stdbuf -o0 ps -aux | grep --color=never -e softmodem | grep -v grep', '\$', 5) - result = re.search('-softmodem', mySSH.getBefore()) - if result is not None: - mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL -r .*-softmodem || true', '\$', 5) - time.sleep(5) - mySSH.command('rm -f my-lte-softmodem-run' + str(self.eNB_instance) + '.sh', '\$', 5) - #stopping tshark (valid if eNB and enabled in xml, will not harm otherwise) - logging.debug('\u001B[1m Stopping tshark on xNB \u001B[0m') - mySSH.command('echo ' + lPassWord + ' | sudo -S killall --signal SIGKILL tshark', '\$', 5) - time.sleep(1) - mySSH.close() - # if T tracer was run with option 0 (no logs), analyze logs - # from textlog, otherwise do normal analysis (e.g., option 2) - result = re.search('T_stdout 0', str(self.Initialize_eNB_args)) - if (result is not None): - logging.debug('\u001B[1m Replaying RAW record file\u001B[0m') - mySSH.open(lIpAddr, lUserName, lPassWord) - mySSH.command('cd ' + lSourcePath + '/common/utils/T/tracer/', '\$', 5) - enbLogFile = self.eNBLogFiles[int(self.eNB_instance)] - raw_record_file = enbLogFile.replace('.log', '_record.raw') - replay_log_file = enbLogFile.replace('.log', '_replay.log') - extracted_txt_file = enbLogFile.replace('.log', '_extracted_messages.txt') - extracted_log_file = enbLogFile.replace('.log', '_extracted_messages.log') - mySSH.command('./extract_config -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + extracted_txt_file, '\$', 5) - mySSH.command('echo $USER; nohup ./replay -i ' + lSourcePath + '/cmake_targets/' + raw_record_file + ' > ' + lSourcePath + '/cmake_targets/' + replay_log_file + ' 2>&1 &', lUserName, 5) - mySSH.command('./textlog -d ' + lSourcePath + '/cmake_targets/' + extracted_txt_file + ' -no-gui -ON -full > ' + lSourcePath + '/cmake_targets/' + extracted_log_file, '\$', 5) - mySSH.close() - mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + extracted_log_file, '.') - logging.debug('\u001B[1m Analyzing eNB replay logfile \u001B[0m') - logStatus = self.AnalyzeLogFile_eNB(extracted_log_file, HTML, self.ran_checkers) + cmd.run('sudo -S killall --signal SIGINT -r .*-softmodem') + time.sleep(6) + + ret = cmd.run('ps -aux | grep --color=never -e softmodem | grep -v grep') + result = re.search('-softmodem', ret.stdout) + if result is not None: + cmd.run('sudo -S killall --signal SIGKILL -r .*-softmodem') + time.sleep(5) + + # see InitializeeNB() + logfile = f'{lSourcePath}/cmake_targets/enb.log' + logdir = os.path.dirname(logfile) + + file = archiveArtifact(cmd, ctx, logfile) + archiveArtifact(cmd, ctx, f"{logdir}/nrL1_stats.log") + archiveArtifact(cmd, ctx, f"{logdir}/nrMAC_stats.log") + cmd.close() + if file is None: + logging.debug('\u001B[1;37;41m Could not copy xNB logfile to analyze it! \u001B[0m') + msg = 'Could not copy xNB logfile to analyze it!' + HTML.CreateHtmlTestRowQueue('N/A', 'KO', [msg]) + return False + + logging.debug('\u001B[1m Analyzing xNB logfile \u001B[0m ' + file) + logStatus = self.AnalyzeLogFile_eNB(file, HTML, self.ran_checkers) + if logStatus < 0: + HTML.CreateHtmlTestRow('N/A', 'KO', logStatus) + else: HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK) - self.eNBLogFiles[int(self.eNB_instance)] = '' - return True - else: - analyzeFile = False - if self.eNBLogFiles[int(self.eNB_instance)] != '': - analyzeFile = True - fileToAnalyze = self.eNBLogFiles[int(self.eNB_instance)] - self.eNBLogFiles[int(self.eNB_instance)] = '' - if analyzeFile: - #*stats.log files + pickle + png - mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*stats.log', '.') - mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*.pickle', '.') - mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/*.png', '.') - # - copyin_res = mySSH.copyin(lIpAddr, lUserName, lPassWord, lSourcePath + '/cmake_targets/' + fileToAnalyze, '.') - if (copyin_res == -1): - logging.debug('\u001B[1;37;41m Could not copy ' + nodeB_prefix + 'NB logfile to analyze it! \u001B[0m') - HTML.htmleNBFailureMsg='Could not copy ' + nodeB_prefix + 'NB logfile to analyze it!' - HTML.CreateHtmlTestRow('N/A', 'KO', CONST.ENB_PROCESS_NOLOGFILE_TO_ANALYZE) - self.eNBmbmsEnables[int(self.eNB_instance)] = False - return False - if self.eNB_serverId[self.eNB_instance] != '0': - #*stats.log files + pickle + png - #debug / tentative - mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './nrL1_stats.log', self.eNBSourceCodePath + '/cmake_targets/') - mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './nrMAC_stats.log', self.eNBSourceCodePath + '/cmake_targets/') - mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, './' + fileToAnalyze, self.eNBSourceCodePath + '/cmake_targets/') - logging.debug('\u001B[1m Analyzing ' + nodeB_prefix + 'NB logfile \u001B[0m ' + fileToAnalyze) - logStatus = self.AnalyzeLogFile_eNB(fileToAnalyze, HTML, self.ran_checkers) - if (logStatus < 0): - HTML.CreateHtmlTestRow('N/A', 'KO', logStatus) - #display rt stats for gNB only - if len(self.datalog_rt_stats)!=0 and nodeB_prefix == 'g': - HTML.CreateHtmlDataLogTable(self.datalog_rt_stats) - self.eNBmbmsEnables[int(self.eNB_instance)] = False - return False - else: - HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK) - else: - HTML.CreateHtmlTestRow(self.runtime_stats, 'OK', CONST.ALL_PROCESSES_OK) #display rt stats for gNB only - if len(self.datalog_rt_stats)!=0 and nodeB_prefix == 'g': + if len(self.datalog_rt_stats) != 0: HTML.CreateHtmlDataLogTable(self.datalog_rt_stats) - self.eNBmbmsEnables[int(self.eNB_instance)] = False - self.eNBstatuses[int(self.eNB_instance)] = -1 - return True - def LogCollecteNB(self): - mySSH = SSH.SSHConnection() - # Copying back to xNB server any log from all the runs. - # Should also contains ping and iperf logs - absPath = os.path.abspath('.') - if absPath.count('ci-scripts') == 0: - os.chdir('./ci-scripts') - - for x in os.listdir(): - if x.endswith('.log') or x.endswith('.log.png'): - mySSH.copyout(self.eNBIPAddress, self.eNBUserName, self.eNBPassword, x, self.eNBSourceCodePath + '/cmake_targets/', silent=True, ignorePermDenied=True) - # Back to normal - mySSH.open(self.eNBIPAddress, self.eNBUserName, self.eNBPassword) - mySSH.command('cd ' + self.eNBSourceCodePath, '\$', 5) - mySSH.command('cd cmake_targets', '\$', 5) - mySSH.command('echo ' + self.eNBPassword + ' | sudo -S mv /tmp/enb_*.pcap .','\$',20) - mySSH.command('echo ' + self.eNBPassword + ' | sudo -S mv /tmp/gnb_*.pcap .','\$',20) - mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm -f enb.log.zip', '\$', 5) - mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip *.log enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor*.png ping*.log* iperf*.log log/*/*.log log/*/*.pcap', '\$', 60) - result = re.search('core.\d+', mySSH.getBefore()) - if result is not None: - mySSH.command('echo ' + self.eNBPassword + ' | sudo -S zip enb.log.zip core* ran_build/build/{lte,nr}-softmodem', '\$', 60) # add core and executable to zip - mySSH.command('echo ' + self.eNBPassword + ' | sudo -S rm enb*.log core* enb_*record.raw enb_*.pcap gnb_*.pcap enb_*txt physim_*.log *stats.log *monitor.pickle *monitor*.png ping*.log* iperf*.log log/*/*.log log/*/*.pcap', '\$', 15) - mySSH.close() + return logStatus >= 0 def _analyzeUeRetx(self, rounds, checkers, regex): if len(rounds) == 0 or len(checkers) == 0: @@ -566,16 +321,16 @@ class RANManagement(): X2HO_state = CONST.X2_HO_REQ_STATE__IDLE X2HO_outNbProcedures += 1 - if self.eNBOptions[int(self.eNB_instance)] != '': - res1 = re.search('max_rxgain (?P[0-9]+)', self.eNBOptions[int(self.eNB_instance)]) + if self.eNBOptions[0] != '': + res1 = re.search('max_rxgain (?P[0-9]+)', self.eNBOptions[0]) res2 = re.search('max_rxgain (?P[0-9]+)', str(line)) if res1 is not None and res2 is not None: requested_option = int(res1.group('requested_option')) applied_option = int(res2.group('applied_option')) if requested_option == applied_option: - htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + htmleNBFailureMsg += ' Command line option(s) correctly applied ' + self.eNBOptions[0] + '\n\n' else: - htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[int(self.eNB_instance)] + '\n\n' + htmleNBFailureMsg += ' Command line option(s) NOT applied ' + self.eNBOptions[0] + '\n\n' result = re.search('Exiting OAI softmodem|Caught SIGTERM, shutting down', str(line)) if result is not None: exitSignalReceived = True @@ -662,7 +417,7 @@ class RANManagement(): result = re.search('dropping, not enough RBs', str(line)) if result is not None: dropNotEnoughRBs += 1 - if self.eNBmbmsEnables[int(self.eNB_instance)]: + if self.eNBmbmsEnables[0]: result = re.search('MBMS USER-PLANE.*Requesting.*bytes from RLC', str(line)) if result is not None: mbmsRequestMsg += 1 @@ -735,11 +490,16 @@ class RANManagement(): datalog_rt_stats = yaml.load(f,Loader=yaml.FullLoader) rt_keys = datalog_rt_stats['Ref'] #we use the keys from the Ref field - if os.path.isfile('./nrL1_stats.log') and os.path.isfile('./nrMAC_stats.log'): + # nrL1_stats.log/nrMAC_stats.log should be in the same directory as main log file + # currently the link is only implicit as below based on pattern matching + # I will rework this to give the file explicitly + l1_stats_fn = re.sub(r'-enb.log$', '-nrL1_stats.log', eNBlogFile) + mac_stats_fn = re.sub(r'-enb.log$', '-nrMAC_stats.log', eNBlogFile) + if os.path.isfile(l1_stats_fn) and os.path.isfile(mac_stats_fn): # don't use CI-nrL1_stats.log, as this will increase the processing time for # no reason, we just need the last occurence - nrL1_stats = open('./nrL1_stats.log', 'r') - nrMAC_stats = open('./nrMAC_stats.log', 'r') + nrL1_stats = open(l1_stats_fn, 'r') + nrMAC_stats = open(mac_stats_fn, 'r') for line in nrL1_stats.readlines(): for k in rt_keys: result = re.search(k, line) @@ -759,14 +519,14 @@ class RANManagement(): nrL1_stats.close() nrMAC_stats.close() else: - logging.debug("NR Stats files for RT analysis not found") + logging.debug(f"NR Stats files for RT analysis not found: {l1_stats_fn}, {mac_stats_fn}") #stdout log file and stat log files analysis completed logging.debug(' File analysis (stdout, stats) completed') #post processing depending on the node type if not nodeB_prefix_found: - if self.air_interface[self.eNB_instance] == 'lte-softmodem': + if self.air_interface == 'lte-softmodem': nodeB_prefix = 'e' else: nodeB_prefix = 'g' @@ -970,7 +730,7 @@ class RANManagement(): rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') htmleNBFailureMsg += rrcMsg + '\n' - if self.eNBmbmsEnables[int(self.eNB_instance)]: + if self.eNBmbmsEnables[0]: if mbmsRequestMsg > 0: rrcMsg = 'eNB requested ' + str(mbmsRequestMsg) + ' times the RLC for MBMS USER-PLANE' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') @@ -983,8 +743,8 @@ class RANManagement(): rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)' logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m') htmleNBFailureMsg += rrcMsg + '\n' - if self.eNBOptions[int(self.eNB_instance)] != '': - res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)]) + if self.eNBOptions[0] != '': + res1 = re.search('drx_Config_present prSetup', self.eNBOptions[0]) if res1 is not None: if cdrxActivationMessageCount > 0: rrcMsg = 'eNB activated the CDRX Configuration for ' + str(cdrxActivationMessageCount) + ' time(s)' diff --git a/ci-scripts/run_locally.sh b/ci-scripts/run_locally.sh index 60010ea30a..6423378e9c 100755 --- a/ci-scripts/run_locally.sh +++ b/ci-scripts/run_locally.sh @@ -15,19 +15,31 @@ fi # The script assumes you've build the following images: # -# docker build . -f docker/Dockerfile.gNB.ubuntu22 -t oai-gnb -# docker build . -f docker/Dockerfile.nrUE.ubuntu22 -t oai-nr-ue +# docker build . -f docker/Dockerfile.gNB.ubuntu -t oai-gnb +# docker build . -f docker/Dockerfile.nr-cuup.ubuntu -t oai-nr-cuup +# docker build . -f docker/Dockerfile.nrUE.ubuntu -t oai-nr-ue # # The images above depend on the following images: # -# docker build . -f docker/Dockerfile.build.ubuntu22 -t ran-build -# dokcer build . -f docker/Dockerfile.base.ubuntu22 -t ran-base +# docker build . -f docker/Dockerfile.build.ubuntu -t ran-build +# docker build . -f docker/Dockerfile.base.ubuntu -t ran-base docker tag oai-nr-ue oai-ci/oai-nr-ue:develop-${SHORT_COMMIT_SHA} docker tag oai-gnb oai-ci/oai-gnb:develop-${SHORT_COMMIT_SHA} +docker tag oai-nr-cuup oai-ci/oai-nr-cuup:develop-${SHORT_COMMIT_SHA} + +python3 main.py --mode=InitiateHtml --ranRepository=NONE --ranBranch=${CURRENT_BRANCH} \ + --ranCommitID=${COMMIT_SHA} --ranAllowMerge=false \ + --ranTargetBranch=NONE \ + --XMLTestFile=xml_files/${TESTCASE} --local python3 main.py --mode=TesteNB --ranRepository=NONE --ranBranch=${CURRENT_BRANCH} \ --ranCommitID=${COMMIT_SHA} --ranAllowMerge=false \ - --ranTargetBranch=NONE --eNBIPAddress=NONE --eNBUserName=NONE --eNBPassword=NONE \ + --ranTargetBranch=NONE \ --eNBSourceCodePath=${REPO_PATH} \ - --XMLTestFile=xml_files/${TESTCASE} --local + --XMLTestFile=${TESTCASE} --local +RET=$? + +python3 main.py --mode=FinalizeHtml --local + +exit ${RET} diff --git a/ci-scripts/scripts/create_workspace.sh b/ci-scripts/scripts/create_workspace.sh index c8410802db..a8359a9ae4 100755 --- a/ci-scripts/scripts/create_workspace.sh +++ b/ci-scripts/scripts/create_workspace.sh @@ -22,5 +22,5 @@ git config user.name "OAI Jenkins" git config advice.detachedHead false mkdir -p cmake_targets/log git checkout -f ${ref} -[ -n "${merge}" ] && git merge --ff ${merge} -m "Temporary merge for CI" +[ -n "${merge}" ] && git fetch origin ${merge} && git merge --ff FETCH_HEAD -m "Temporary merge for CI" exit 0 diff --git a/ci-scripts/scripts/docker-build-and-deploy-physims.sh b/ci-scripts/scripts/docker-build-and-deploy-physims.sh new file mode 100755 index 0000000000..c49ebefc1d --- /dev/null +++ b/ci-scripts/scripts/docker-build-and-deploy-physims.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +function die() { echo $@; exit 1; } +[ $# -ge 1 ] || die "usage: $0 [ctest-options]" + +IMAGE=ran-physimtests:ci-temp +CONTAINER=ran-physimtests +function cleanup-docker() { + docker stop ${CONTAINER} + docker rm ${CONTAINER} + docker rmi ${IMAGE} + docker volume prune --force +} +trap cleanup-docker EXIT + +set -x +DIR=$1 +RESULT_DIR=${DIR}/ +shift +CTEST_OPT=$@ + +# build physims +docker build --progress=plain --tag ${IMAGE} --file ${DIR}/ci-scripts/docker/Dockerfile.physim.ubuntu ${DIR} &>> ${RESULT_DIR}/physim_log.txt +if [ $? -ne 0 ]; then + echo "build of physims failed" + exit 1 +fi + +# get a JSON description of all tests to run +docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --rm --name ${CONTAINER} ${IMAGE} ctest ${CTEST_OPT} --show-only=json-v1 &> ${RESULT_DIR}/desc-tests.json +JSON_RES=$? + +# run the actual tests: we don't suppy --rm as we have to copy the files +# similar to unit tests, we can't mount the file where we write physims-5g-run.xml to +# as it would write a file as root, but this script is run as a normal user +docker run -a STDOUT --workdir /oai-ran/build/ --env LD_LIBRARY_PATH=/oai-ran/build/ --name ${CONTAINER} ${IMAGE} ctest ${CTEST_OPT} --output-junit results-run.xml --test-output-size-passed 100000 --test-output-size-failed 100000 &>> ${RESULT_DIR}/physim_log.txt +RUN_RES=$? +docker cp ${CONTAINER}:/oai-ran/build/results-run.xml ${RESULT_DIR}/ +docker cp ${CONTAINER}:/oai-ran/build/Testing/Temporary/LastTestsFailed.log ${RESULT_DIR}/ +docker cp ${CONTAINER}:/oai-ran/build/Testing/Temporary/LastTest.log ${RESULT_DIR}/ + +# if both were successful, return 0 +# TODO not sure +#[[ $JSON_RES -eq 0 && $RUN_RES -eq 0 ]] && exit 0 + +exit 0 diff --git a/ci-scripts/scripts/oc-deploy-physims.sh b/ci-scripts/scripts/oc-deploy-physims.sh index ddb2e964ef..29812a8980 100755 --- a/ci-scripts/scripts/oc-deploy-physims.sh +++ b/ci-scripts/scripts/oc-deploy-physims.sh @@ -1,7 +1,5 @@ #!/bin/bash -set -e - function die() { echo $@; exit 1; } [ $# -eq 4 ] || die "usage: $0 " @@ -11,23 +9,31 @@ IMG_TAG=${3} OAI_DIR=${4} cat /opt/oc-password | oc login -u oaicicd --server https://api.oai.cs.eurecom.fr:6443 > /dev/null +set -x oc project ${OC_NS} > /dev/null oc tag oaicicd-ran/oai-physim:${IMG_TAG} ${OC_NS}/oai-physim:${IMG_TAG} -helm install ${OC_RELEASE} ${OAI_DIR}/charts/${OC_RELEASE} --set global.image.version=${IMG_TAG} --wait +helm install ${OC_RELEASE} ${OAI_DIR}/charts/${OC_RELEASE} --set global.image.version=${IMG_TAG} --wait --timeout 120s +set +x POD_ID=$(oc get pods | grep oai-${OC_RELEASE} | awk '{print $1}') -sleep 10 +wait_creating=30 +while [[ $(oc describe pod "$POD_ID" | grep "ContainerCreating") && ${wait_creating} > 0 ]]; do + sleep 1; + let wait_creating=$wait_creating-1 +done echo "Monitoring logs for 'FINISHED' in pod '$POD_ID'" oc logs -f -n ${OC_NS} "$POD_ID" | while read -r line; do if [[ "$line" == *"FINISHED"* ]]; then echo "'FINISHED' detected in logs. Copying logs..." - oc logs -n ${OC_NS} "$POD_ID" >> ${OAI_DIR}/ci-scripts/physim_log.txt - oc describe pod $POD_ID >> ${OAI_DIR}/ci-scripts/physim_pods_summary.txt - oc cp "$POD_ID":/opt/oai-physim/Testing/Temporary/LastTestsFailed.log ${OAI_DIR}/ci-scripts/LastTestsFailed.log - oc cp "$POD_ID":/opt/oai-physim/${OC_RELEASE}-tests.json ${OAI_DIR}/ci-scripts/${OC_RELEASE}-tests.json - oc cp "$POD_ID":/opt/oai-physim/${OC_RELEASE}-run.xml ${OAI_DIR}/ci-scripts/${OC_RELEASE}-run.xml + oc cp "$POD_ID":/opt/oai-physim/Testing/Temporary/LastTestsFailed.log ${OAI_DIR}/LastTestsFailed.log + oc cp "$POD_ID":/opt/oai-physim/Testing/Temporary/LastTest.log ${OAI_DIR}/LastTest.log + oc cp "$POD_ID":/opt/oai-physim/${OC_RELEASE}-tests.json ${OAI_DIR}/desc-tests.json + oc cp "$POD_ID":/opt/oai-physim/${OC_RELEASE}-run.xml ${OAI_DIR}/results-run.xml break fi done +set -x +oc logs -n ${OC_NS} "$POD_ID" >> ${OAI_DIR}/physim_log.txt +oc describe pod $POD_ID >> ${OAI_DIR}/physim_log.txt helm uninstall ${OC_RELEASE} --wait oc delete istag oai-physim:${IMG_TAG} -n ${OC_NS} oc logout > /dev/null diff --git a/ci-scripts/scripts/source-deploy-physims.sh b/ci-scripts/scripts/source-deploy-physims.sh new file mode 100644 index 0000000000..6054453301 --- /dev/null +++ b/ci-scripts/scripts/source-deploy-physims.sh @@ -0,0 +1,30 @@ + +function die() { echo $@; exit 1; } +[ $# -ge 1 ] || die "usage: $0 [ctest-options]" + +set -x +DIR=$1 +shift +CTEST_OPT=$@ + +cd ${DIR}/cmake_targets/ran_build/build +ninja ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim + +# get a JSON description of all tests to run +ctest ${CTEST_OPT} --show-only=json-v1 &> ${DIR}/desc-tests.json +JSON_RES=$? + +# we run the T2 offload tests, so provide some additional permissions +# to be able to initialize DPDK +sudo setcap cap_dac_override,cap_sys_admin+ep nr_ulsim +sudo setcap cap_dac_override,cap_sys_admin+ep nr_dlsim +ctest ${CTEST_OPT} --output-junit ${DIR}/results-run.xml --test-output-size-passed 100000 --test-output-size-failed 100000 &>> ${DIR}/physim_log.txt +RUN_RES=$? +cp Testing/Temporary/LastTestsFailed.log ${DIR}/ +cp Testing/Temporary/LastTest.log ${DIR}/ + +# if both were successful, return 0 +# TODO not sure +#[[ $JSON_RES -eq 0 && $RUN_RES -eq 0 ]] && exit 0 + +exit 0 diff --git a/ci-scripts/scripts/sys-info.sh b/ci-scripts/scripts/sys-info.sh new file mode 100755 index 0000000000..01dd4b0d6c --- /dev/null +++ b/ci-scripts/scripts/sys-info.sh @@ -0,0 +1,17 @@ +CORES=$(nproc) +MODEL=$(lscpu | awk -F: '/Model name/ {print $2; exit}' | xargs) +MAX_FREQ=$(lscpu | awk -F: '/CPU max MHz/ {printf "%.2f MHz", $2; exit}') +CURRENT_FREQ=$(awk -F: '/cpu MHz/ {printf " %.2f MHz", $2; exit}' /proc/cpuinfo) +RAM=$(free -h --si | awk '/Mem:/ {print $2}') +# sudo -n: non-interactive, will silently fail in case we don't have privileges +DMID=$(sudo -n dmidecode -t memory 2>/dev/null) +if [ $? -eq 0 ]; then + RAM_TYPE=$(echo "$DMID" | awk -F: '/Type:/ {print $2}' | grep -Ev 'Unknown|Other|None' | head -1 | xargs) +else + RAM_TYPE="can't query" +fi + + +echo "CPU: model ${MODEL}" +echo "${CORES} cores, max CPU freq ${MAX_FREQ}, current ${CURRENT_FREQ}" +echo "RAM ${RAM} type ${RAM_TYPE}" diff --git a/ci-scripts/sshconnection.py b/ci-scripts/sshconnection.py deleted file mode 100644 index a41b8bf7f1..0000000000 --- a/ci-scripts/sshconnection.py +++ /dev/null @@ -1,281 +0,0 @@ -#/* -# * 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 -# */ -#--------------------------------------------------------------------- -# Python for CI of OAI-eNB + COTS-UE -# -# Required Python Version -# Python 3.x -# -# Required Python Package -# pexpect -#--------------------------------------------------------------------- - -#----------------------------------------------------------- -# Import -#----------------------------------------------------------- -import pexpect # pexpect -import logging -import time # sleep -import re -import subprocess -import sys - -#----------------------------------------------------------- -# Class Declaration -#----------------------------------------------------------- -class SSHConnection(): - def __init__(self): - self.ssh = '' - self.picocom_closure = False - self.ipaddress = '' - self.username = '' - self.cmd2Results = '' - - def disablePicocomClosure(self): - self.picocom_closure = False - - def enablePicocomClosure(self): - self.picocom_closure = True - - def open(self, ipaddress, username, password): - prompt = "\$" - count = 0 - connect_status = False - while count < 4: - self.ssh = pexpect.spawn('ssh -o PubkeyAuthentication=yes {}@{}'.format(username,ipaddress)) - # Longer timeout at connection due to asterix slowness - self.ssh.timeout = 25 - self.sshresponse = self.ssh.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', 'Last login', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - self.ssh.sendline('yes') - self.sshresponse = self.ssh.expect(['password:', username + '@']) - if self.sshresponse == 0: - self.ssh.sendline(password) - self.sshresponse = self.ssh.expect([prompt, 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - else: - logging.warning('self.sshresponse = ' + str(self.sshresponse)) - elif self.sshresponse == 1: - self.ssh.sendline(password) - self.sshresponse = self.ssh.expect([prompt, 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - count = 10 - connect_status = True - else: - logging.warning('self.sshresponse = ' + str(self.sshresponse)) - elif self.sshresponse == 2: - # We directly ended up on the remote server because of pubkey auth - count = 10 - connect_status = True - # this expect() seems to be necessary to advance the read buffer until the prompt, or getBefore() will not return the last command - self.sshresponse = self.ssh.expect([prompt]) - else: - # debug output - logging.warning(str(self.ssh.before)) - logging.warning('self.sshresponse = ' + str(self.sshresponse)) - # adding a tempo when failure - if not connect_status: - time.sleep(1) - count += 1 - if connect_status: - self.command('unset HISTFILE', prompt, 5, silent=True) - else: - raise ConnectionError('SSH Connection Failed') - self.ipaddress = ipaddress - self.username = username - - - - - def cde_check_value(self, commandline, expected, timeout): - logging.info(commandline) - self.ssh.timeout = timeout - self.ssh.sendline(commandline) - expected.append(pexpect.EOF) - expected.append(pexpect.TIMEOUT) - self.sshresponse = self.ssh.expect(expected) - return self.sshresponse - - def command(self, commandline, expectedline, timeout, silent=False, resync=False): - if not silent: - logging.info(commandline) - self.ssh.timeout = timeout - # Nasty patch when pexpect output is out of sync. - # Much pronounced when running back-to-back-back oc commands - if resync: - self.ssh.send(commandline) - self.ssh.expect([commandline, pexpect.TIMEOUT]) - self.ssh.send('\r\n') - self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT]) - else: - self.ssh.sendline(commandline) - self.sshresponse = self.ssh.expect([expectedline, pexpect.EOF, pexpect.TIMEOUT]) - if self.sshresponse == 0: - return 0 - elif self.sshresponse == 1: - logging.error('\u001B[1;37;41m Unexpected EOF \u001B[0m') - logging.error('Expected Line : ' + expectedline) - logging.error(str(self.ssh.before)) - raise ConnectionError(self.sshresponse) - elif self.sshresponse == 2: - logging.error('\u001B[1;37;41m Unexpected TIMEOUT \u001B[0m') - logging.error('Expected Line : ' + expectedline) - result = re.search('ping |iperf |picocom', str(commandline)) - if result is None: - logging.warning(str(self.ssh.before)) - raise ConnectionError(self.sshresponse) - else: - return -1 - else: - logging.error('\u001B[1;37;41m Unexpected Others \u001B[0m') - logging.error('Expected Line : ' + expectedline) - raise ConnectionError(self.sshresponse) - - def command2(self, commandline, timeout, silent=False): - if not silent: - logging.info(commandline) - self.cmd2Results = '' - noHistoryCmd = 'unset HISTFILE; ' + commandline - myHost = self.username + '@' + self.ipaddress - # CAUTION: THIS METHOD IMPLIES THAT THERE ARE VALID SSH KEYS - # BETWEEN THE PYTHON EXECUTOR NODE AND THE REMOTE HOST - # OTHERWISE IT WON'T WORK - lSsh = subprocess.Popen(["ssh", "%s" % myHost, noHistoryCmd],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - self.cmd2Results = str(lSsh.stdout.readlines()) - - def command3(self, commandline, timeout, silent=False): - if not silent: - logging.info(commandline) - self.cmd2Results = '' - noHistoryCmd = 'unset HISTFILE; ' + commandline - myHost = self.username + '@' + self.ipaddress - # CAUTION: THIS METHOD IMPLIES THAT THERE ARE VALID SSH KEYS - # BETWEEN THE PYTHON EXECUTOR NODE AND THE REMOTE HOST - # OTHERWISE IT WON'T WORK - lSsh = subprocess.Popen(["ssh", "%s" % myHost, noHistoryCmd],shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - return lSsh.stdout.readlines() - - - def close(self): - self.ssh.timeout = 5 - self.ssh.sendline('exit') - self.sshresponse = self.ssh.expect([pexpect.EOF, pexpect.TIMEOUT]) - self.ipaddress = '' - self.username = '' - if self.sshresponse == 0: - pass - elif self.sshresponse == 1: - if not self.picocom_closure: - logging.warning('\u001B[1;37;41m Unexpected TIMEOUT during closing\u001B[0m') - else: - logging.warning('\u001B[1;37;41m Unexpected Others during closing\u001B[0m') - - def copyin(self, ipaddress, username, password, source, destination): - count = 0 - copy_status = False - logging.info('scp -r '+ username + '@' + ipaddress + ':' + source + ' ' + destination) - while count < 10: - scp_spawn = pexpect.spawn('scp -r '+ username + '@' + ipaddress + ':' + source + ' ' + destination, timeout = 100) - scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - scp_spawn.sendline('yes') - scp_spawn.expect('password:') - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - count = 10 - copy_status = True - else: - logging.warning('1 - scp_response = ' + str(scp_response)) - elif scp_response == 1: - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0 or scp_response == 3: - count = 10 - copy_status = True - else: - logging.warning('2 - scp_response = ' + str(scp_response)) - elif scp_response == 2: - count = 10 - copy_status = True - else: - logging.warning('3 - scp_response = ' + str(scp_response)) - # adding a tempo when failure - if not copy_status: - time.sleep(1) - count += 1 - if copy_status: - return 0 - else: - return -1 - - def copyout(self, ipaddress, username, password, source, destination, silent=False, ignorePermDenied=False): - count = 0 - copy_status = False - if not silent: - logging.info('scp -r ' + source + ' ' + username + '@' + ipaddress + ':' + destination) - while count < 4: - scp_spawn = pexpect.spawn('scp -r ' + source + ' ' + username + '@' + ipaddress + ':' + destination, timeout = 100) - scp_response = scp_spawn.expect(['Are you sure you want to continue connecting (yes/no)?', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - scp_spawn.sendline('yes') - scp_spawn.expect('password:') - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0: - count = 10 - copy_status = True - elif scp_response == 1 and ignorePermDenied: - logging.warning(f'copyout(): permission denied, not copying file ({source})') - count = 10 - copy_status = True - else: - logging.warning('1 - scp_response = ' + str(scp_response)) - elif scp_response == 1: - scp_spawn.sendline(password) - scp_response = scp_spawn.expect(['\$', 'Permission denied', 'password:', pexpect.EOF, pexpect.TIMEOUT]) - if scp_response == 0 or scp_response == 3: - count = 10 - copy_status = True - elif scp_response == 1 and ignorePermDenied: - logging.warning(f'copyout(): permission denied, not copying file ({source})') - count = 10 - copy_status = True - else: - logging.warning('2 - scp_response = ' + str(scp_response)) - elif scp_response == 2: - count = 10 - copy_status = True - else: - logging.warning('3 - scp_response = ' + str(scp_response)) - # adding a tempo when failure - if not copy_status: - time.sleep(1) - count += 1 - if copy_status: - pass - else: - raise ConnectionError('SCP failed') - - def getBefore(self): - return self.ssh.before.decode('utf-8') diff --git a/ci-scripts/tests/build.py b/ci-scripts/tests/build.py index 669e6711b4..013486a560 100644 --- a/ci-scripts/tests/build.py +++ b/ci-scripts/tests/build.py @@ -11,6 +11,7 @@ import tempfile sys.path.append('./') # to find OAI imports below import cls_oai_html import cls_containerize +from cls_ci_helper import TestCaseCtx import cls_cmd class TestBuild(unittest.TestCase): @@ -18,22 +19,21 @@ class TestBuild(unittest.TestCase): self.html = cls_oai_html.HTMLManagement() self.html.testCase_id = "000000" self.cont = cls_containerize.Containerize() - self.cont.eNB_serverId[0] = '0' - self.cont.eNBIPAddress = 'localhost' - self.cont.eNBUserName = None - self.cont.eNBPassword = None self._d = tempfile.mkdtemp() logging.warning(f"temporary directory: {self._d}") + self.node = 'localhost' self.cont.eNBSourceCodePath = self._d + self.ctx = TestCaseCtx.Default(tempfile.mkdtemp()) def tearDown(self): logging.warning(f"removing directory contents") with cls_cmd.getConnection(None) as cmd: cmd.run(f"rm -rf {self._d}") + cmd.run(f'rm -rf {self.ctx.logPath}') def test_build_proxy(self): self.cont.proxyCommit = "b64d9bce986b38ca59e8582864ade3fcdd05c0dc" - success = self.cont.BuildProxy(self.html) + success = self.cont.BuildProxy(self.ctx, self.node, self.html) self.assertTrue(success) if __name__ == '__main__': diff --git a/ci-scripts/tests/cmd.py b/ci-scripts/tests/cmd.py index 4d7aedfa0e..b9cbb6f51e 100644 --- a/ci-scripts/tests/cmd.py +++ b/ci-scripts/tests/cmd.py @@ -36,17 +36,20 @@ class TestCmd(unittest.TestCase): self.assertEqual(ret.stdout, "test") def test_local_script(self): - ret = cls_cmd.runScript("localhost", "tests/scripts/hello-world.sh", 1) + with cls_cmd.getConnection("localhost") as ssh: + ret = ssh.exec_script("tests/scripts/hello-world.sh", 1) self.assertEqual(ret.args, "tests/scripts/hello-world.sh") self.assertEqual(ret.returncode, 0) self.assertEqual(ret.stdout, "+ echo hello, world\nhello, world") - ret = cls_cmd.runScript("localhost", "tests/scripts/hello-fail.sh", 1, "TESTFAIL") + with cls_cmd.getConnection("localhost") as ssh: + ret = ssh.exec_script("tests/scripts/hello-fail.sh", 1, "TESTFAIL") self.assertEqual(ret.args, "tests/scripts/hello-fail.sh TESTFAIL") self.assertEqual(ret.returncode, 1) self.assertEqual(ret.stdout, "TESTFAIL") - ret = cls_cmd.runScript("localhost", "tests/scripts/hello-fail.sh", 1, "TESTFAIL2", "/tmp/result") + with cls_cmd.getConnection("localhost") as ssh: + ret = ssh.exec_script("tests/scripts/hello-fail.sh", 1, "TESTFAIL2", "/tmp/result") self.assertEqual(ret.args, "tests/scripts/hello-fail.sh TESTFAIL2 &> /tmp/result") self.assertEqual(ret.returncode, 1) self.assertEqual(ret.stdout, "") @@ -75,17 +78,20 @@ class TestCmd(unittest.TestCase): @unittest.skip("need to be able to passwordlessly SSH to localhost, also disable stty -ixon") def test_remote_script(self): - ret = cls_cmd.runScript("127.0.0.1", "tests/scripts/hello-world.sh", 1) + with cls_cmd.getConnection("127.0.0.1") as ssh: + ret = ssh.exec_script("tests/scripts/hello-world.sh", 1) self.assertEqual(ret.args, "tests/scripts/hello-world.sh") self.assertEqual(ret.returncode, 0) self.assertEqual(ret.stdout, "+ echo hello, world\nhello, world") - ret = cls_cmd.runScript("127.0.0.1", "tests/scripts/hello-fail.sh", 1, "TESTFAIL") + with cls_cmd.getConnection("127.0.0.1") as ssh: + ret = ssh.exec_script("tests/scripts/hello-fail.sh", 1, "TESTFAIL") self.assertEqual(ret.args, "tests/scripts/hello-fail.sh TESTFAIL") self.assertEqual(ret.returncode, 1) self.assertEqual(ret.stdout, "TESTFAIL") - ret = cls_cmd.runScript("127.0.0.1", "tests/scripts/hello-fail.sh", 1, "TESTFAIL2", "/tmp/result") + with cls_cmd.getConnection("127.0.0.1") as ssh: + ret = ssh.exec_script("tests/scripts/hello-fail.sh", 1, "TESTFAIL2", "/tmp/result") self.assertEqual(ret.args, "tests/scripts/hello-fail.sh TESTFAIL2 &> /tmp/result") self.assertEqual(ret.returncode, 1) self.assertEqual(ret.stdout, "") diff --git a/ci-scripts/tests/config/test_module_infra.yaml b/ci-scripts/tests/config/test_module_infra.yaml new file mode 100644 index 0000000000..7bfdfc1d9d --- /dev/null +++ b/ci-scripts/tests/config/test_module_infra.yaml @@ -0,0 +1,34 @@ +test: + Host: localhost + InitScript: "" + TermScript: "" + AttachScript: "true" + DetachScript: "true" + NetworkScript: ip a show dev lo + IF: lo + MTU: 65536 + +test-fail: + Host: localhost + InitScript: "" + TermScript: "" + AttachScript: "false" + DetachScript: "true" + NetworkScript: ip a show dev TESTDEVICEDOESNOTEXIST + IF: TESTDEVICEDOESNOTEXIST + MTU: 123 + +test-trace: + Host: localhost + InitScript: "" + TermScript: "" + AttachScript: "true" + DetachScript: "true" + Tracing: + # tttf: temp-trace-test-file + Start: "rm -f /tmp/tttf; for i in {1..8}; do echo $i >> /tmp/tttf; sleep 1; done &" + Stop: "while [[ $(wc -l /tmp/tttf) < 4 ]]; do sleep 1; done" + Collect: "cp /tmp/tttf %%log_dir%%" + NetworkScript: ip a show dev lo + IF: lo + MTU: 65536 diff --git a/ci-scripts/tests/corenetwork.py b/ci-scripts/tests/corenetwork.py index 77e5c7629e..7bc1603305 100644 --- a/ci-scripts/tests/corenetwork.py +++ b/ci-scripts/tests/corenetwork.py @@ -6,14 +6,22 @@ logging.basicConfig( format="[%(asctime)s] %(levelname)8s: %(message)s" ) import os +import tempfile import unittest sys.path.append('./') # to find OAI imports below import cls_corenetwork +from cls_ci_helper import TestCaseCtx import cls_cmd class TestCoreNetwork(unittest.TestCase): + def setUp(self): + self.ctx = TestCaseCtx.Default(tempfile.mkdtemp()) + def tearDown(self): + with cls_cmd.LocalCmd() as c: + c.run(f'rm -rf {self.ctx.logPath}') + def test_simple_core(self): c = cls_corenetwork.CoreNetwork("test", filename="tests/config/test_core_infra.yaml") success, output = c.deploy() @@ -22,14 +30,14 @@ class TestCoreNetwork(unittest.TestCase): # should not have it set in config self.assertTrue(c.runIperf3Server()) self.assertEqual(c.getIP(), "127.0.0.1") - log_files, output = c.undeploy(log_dir="/tmp") + log_files, output = c.undeploy(self.ctx) self.assertEqual(output, "undeploy") with cls_cmd.LocalCmd() as cmd: # there must be one log file for this (test) core self.assertEqual(len(log_files), 1) - # test core writes to %%log_dir%%/logs, which expands to /tmp/logs + # undeploy uses archiveArtifact(), which writes to {prefix}-logs l = log_files[0] - self.assertEqual(l, "/tmp/logs") + self.assertEqual(l, f"{self.ctx.baseFilename()}-logs") ret = cmd.run(f"cat {l}") self.assertEqual(ret.returncode, 0) # command must succeed self.assertEqual(ret.stdout, "logs") # output should be "logs" @@ -39,14 +47,14 @@ class TestCoreNetwork(unittest.TestCase): success, _ = c.deploy() self.assertTrue(success) self.assertFalse(c.runIperf3Server()) - c.undeploy(log_dir="/tmp") + c.undeploy(None) def test_core_fail(self): c = cls_corenetwork.CoreNetwork("test_fail", filename="tests/config/test_core_infra.yaml") success, _ = c.deploy() self.assertFalse(success) # undeployment should still work - c.undeploy(log_dir="/tmp") + c.undeploy(None) def test_core_script(self): c = cls_corenetwork.CoreNetwork("test_script", filename="tests/config/test_core_infra.yaml") diff --git a/ci-scripts/tests/deployment.py b/ci-scripts/tests/deployment.py index a7337f6e52..e7efc707bf 100644 --- a/ci-scripts/tests/deployment.py +++ b/ci-scripts/tests/deployment.py @@ -6,6 +6,7 @@ logging.basicConfig( format="[%(asctime)s] %(levelname)8s: %(message)s" ) import os +import tempfile os.system(f'rm -rf cmake_targets') os.system(f'mkdir -p cmake_targets/log') import unittest @@ -14,6 +15,7 @@ sys.path.append('./') # to find OAI imports below import cls_oai_html import cls_oaicitest import cls_containerize +from cls_ci_helper import TestCaseCtx import ran import cls_cmd @@ -38,72 +40,83 @@ class TestDeploymentMethods(unittest.TestCase): self.ci = cls_oaicitest.OaiCiTest() self.cont = cls_containerize.Containerize() self.ran = ran.RANManagement() - self.cont.yamlPath[0] = '' + self.cont.yamlPath = '' self.cont.ranAllowMerge = True self.cont.ranBranch = '' self.cont.ranCommitID = '' - self.cont.eNB_serverId[0] = '0' - self.cont.eNBIPAddress = 'localhost' - self.cont.eNBUserName = None - self.cont.eNBPassword = None self.cont.eNBSourceCodePath = os.getcwd() self.cont.num_attempts = 3 + self.node = 'localhost' + self.ctx = TestCaseCtx.Default(tempfile.mkdtemp()) + def tearDown(self): + with cls_cmd.LocalCmd() as c: + c.run(f'rm -rf {self.ctx.logPath}') def test_deploy(self): - self.cont.yamlPath[0] = 'tests/simple-dep/' + self.cont.yamlPath = 'tests/simple-dep/' self.cont.deploymentTag = "noble" - deploy = self.cont.DeployObject(self.html) - undeploy = self.cont.UndeployObject(self.html, self.ran) + deploy = self.cont.DeployObject(self.ctx, self.node, self.html) + undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran) self.assertTrue(deploy) self.assertTrue(undeploy) def test_deployfails(self): # fails reliably old = self.cont.yamlPath - self.cont.yamlPath[0] = 'tests/simple-fail/' - deploy = self.cont.DeployObject(self.html) - self.cont.UndeployObject(self.html, self.ran) + self.cont.yamlPath = 'tests/simple-fail/' + deploy = self.cont.DeployObject(self.ctx, self.node, self.html) + self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran) self.assertFalse(deploy) self.cont.yamlPath = old def test_deployfails_2svc(self): # fails reliably old = self.cont.yamlPath - self.cont.yamlPath[0] = 'tests/simple-fail-2svc/' - deploy = self.cont.DeployObject(self.html) - self.cont.UndeployObject(self.html, self.ran) + self.cont.yamlPath = 'tests/simple-fail-2svc/' + deploy = self.cont.DeployObject(self.ctx, self.node, self.html) + self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran) self.assertFalse(deploy) self.cont.yamlPath = old def test_deploy_ran(self): - self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora' - self.cont.services[0] = "oai-gnb" + self.cont.yamlPath = 'yaml_files/5g_rfsimulator_tdd_dora' + self.cont.services = "oai-gnb" self.cont.deploymentTag = 'develop-12345678' - deploy = self.cont.DeployObject(self.html) - undeploy = self.cont.UndeployObject(self.html, self.ran) + deploy = self.cont.DeployObject(self.ctx, self.node, self.html) + undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran) self.assertTrue(deploy) self.assertTrue(undeploy) def test_deploy_multiran(self): - self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora' - self.cont.services[0] = "oai-gnb oai-nr-ue" + self.cont.yamlPath = 'yaml_files/5g_rfsimulator_tdd_dora' + self.cont.services = "oai-gnb oai-nr-ue" self.cont.deploymentTag = 'develop-12345678' - deploy = self.cont.DeployObject(self.html) - undeploy = self.cont.UndeployObject(self.html, self.ran) + deploy = self.cont.DeployObject(self.ctx, self.node, self.html) + undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran) self.assertTrue(deploy) self.assertTrue(undeploy) def test_deploy_staged(self): - self.cont.yamlPath[0] = 'yaml_files/5g_rfsimulator_tdd_dora' - self.cont.services[0] = "oai-gnb" + self.cont.yamlPath = 'yaml_files/5g_rfsimulator_tdd_dora' + self.cont.services = "oai-gnb" self.cont.deploymentTag = 'develop-12345678' - deploy1 = self.cont.DeployObject(self.html) - self.cont.services[0] = "oai-nr-ue" - deploy2 = self.cont.DeployObject(self.html) - undeploy = self.cont.UndeployObject(self.html, self.ran) + deploy1 = self.cont.DeployObject(self.ctx, self.node, self.html) + self.cont.services = "oai-nr-ue" + deploy2 = self.cont.DeployObject(self.ctx, self.node, self.html) + undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran) self.assertTrue(deploy1) self.assertTrue(deploy2) self.assertTrue(undeploy) + def test_create_workspace(self): + self.cont.eNBSourceCodePath = tempfile.mkdtemp() + self.cont.ranRepository = "https://gitlab.eurecom.fr/oai/openairinterface5g.git" + self.cont.ranCommitID = "05f9c975eeecbca1bdff5940affad44465f1301f" + self.cont.ranBranch = "develop" + ws = self.cont.Create_Workspace(self.node, self.html) + with cls_cmd.LocalCmd() as cmd: + cmd.run(f"rm -rf {self.cont.eNBSourceCodePath}") + self.assertTrue(ws) + if __name__ == '__main__': unittest.main() diff --git a/ci-scripts/tests/log/iperf_udp_msg_nok.txt b/ci-scripts/tests/log/iperf_udp_msg_nok.txt index 0e03a2dc76..a2ec0e22d6 100644 --- a/ci-scripts/tests/log/iperf_udp_msg_nok.txt +++ b/ci-scripts/tests/log/iperf_udp_msg_nok.txt @@ -1,4 +1,4 @@ -Sender Bitrate : 0.52 Mbps -Receiver Bitrate: 0.52 Mbps (too low! < 99%) +Sender Bitrate : 524.00 Kbps +Receiver Bitrate: 524.00 Kbps (52.40%) (too low! < 99%) Jitter : 0.026 ms -Packet Loss : 10 % (too high! > 0%) +Packet Loss : 10% (too high! > 0%) diff --git a/ci-scripts/tests/log/iperf_udp_msg_nok2.txt b/ci-scripts/tests/log/iperf_udp_msg_nok2.txt index c0c34193f2..e24cc1402a 100644 --- a/ci-scripts/tests/log/iperf_udp_msg_nok2.txt +++ b/ci-scripts/tests/log/iperf_udp_msg_nok2.txt @@ -1,4 +1,4 @@ -Sender Bitrate : 0.00 Mbps -Receiver Bitrate: 3.98 Mbps (too low! < 99%) +Sender Bitrate : 0.00 bps +Receiver Bitrate: 3.98 Mbps (4.97%) (too low! < 99%) Jitter : 3.847 ms -Packet Loss : 0.038 % (too high! > 0%) +Packet Loss : 0.038% (too high! > 0%) diff --git a/ci-scripts/tests/log/iperf_udp_msg_nok3.txt b/ci-scripts/tests/log/iperf_udp_msg_nok3.txt index c302493e85..b027491913 100644 --- a/ci-scripts/tests/log/iperf_udp_msg_nok3.txt +++ b/ci-scripts/tests/log/iperf_udp_msg_nok3.txt @@ -1,4 +1,4 @@ -Sender Bitrate : 1.03 Mbps -Receiver Bitrate: 0.00 Mbps (too low! < 99%) +Sender Bitrate : 1.03 Mbps +Receiver Bitrate: 0.00 bps (0.00%) (too low! < 99%) Jitter : 0.000 ms -Packet Loss : 0 % +Packet Loss : 0% diff --git a/ci-scripts/tests/log/iperf_udp_msg_ok.txt b/ci-scripts/tests/log/iperf_udp_msg_ok.txt index defea05c79..a771c6fdb1 100644 --- a/ci-scripts/tests/log/iperf_udp_msg_ok.txt +++ b/ci-scripts/tests/log/iperf_udp_msg_ok.txt @@ -1,4 +1,4 @@ -Sender Bitrate : 1.00 Mbps -Receiver Bitrate: 1.00 Mbps (99.60 %) +Sender Bitrate : 996.00 Kbps +Receiver Bitrate: 996.00 Kbps (99.60%) Jitter : 0.029 ms -Packet Loss : 0 % +Packet Loss : 0% diff --git a/ci-scripts/tests/log/iperf_udp_msg_ok2.txt b/ci-scripts/tests/log/iperf_udp_msg_ok2.txt index 31a5ec14cd..856b851112 100644 --- a/ci-scripts/tests/log/iperf_udp_msg_ok2.txt +++ b/ci-scripts/tests/log/iperf_udp_msg_ok2.txt @@ -1,4 +1,4 @@ -Sender Bitrate : 4.67 Mbps -Receiver Bitrate: 4.67 Mbps (100.00 %) +Sender Bitrate : 4.67 Mbps +Receiver Bitrate: 4.67 Mbps (100.00%) Jitter : 3.413 ms -Packet Loss : 0 % +Packet Loss : 0% diff --git a/ci-scripts/tests/module.py b/ci-scripts/tests/module.py new file mode 100644 index 0000000000..47760cfa27 --- /dev/null +++ b/ci-scripts/tests/module.py @@ -0,0 +1,64 @@ +import sys +import logging +import tempfile +logging.basicConfig( + level=logging.DEBUG, + stream=sys.stdout, + format="[%(asctime)s] %(levelname)8s: %(message)s" +) +import os + +import unittest + +sys.path.append('./') # to find OAI imports below +import cls_module +from cls_ci_helper import TestCaseCtx +import cls_cmd + +class TestModule(unittest.TestCase): + def setUp(self): + self.ctx = TestCaseCtx.Default(tempfile.mkdtemp()) + def tearDown(self): + with cls_cmd.LocalCmd() as c: + c.run(f'rm -rf {self.ctx.logPath}') + + def test_simple_module(self): + c = cls_module.Module_UE("test", filename="tests/config/test_module_infra.yaml") + self.assertFalse(c.trace) + success = c.initialize() + self.assertTrue(success) + ip = c.attach() + self.assertEqual(ip, "127.0.0.1") + self.assertTrue(c.checkMTU()) + c.detach() + logs = c.terminate() + self.assertEqual(logs, None) # no tracing + + @unittest.skip("this test takes long: it verifies the UE cannot attach") + def test_simple_fail(self): + c = cls_module.Module_UE("test-fail", filename="tests/config/test_module_infra.yaml") + success = c.initialize() + self.assertTrue(success) + ip = c.attach() + self.assertEqual(ip, None) + self.assertFalse(c.checkMTU()) + c.detach() + logs = c.terminate() + self.assertEqual(logs, None) # no tracing + + def test_simple_trace(self): + c = cls_module.Module_UE("test-trace", filename="tests/config/test_module_infra.yaml") + self.assertTrue(c.trace) + success = c.initialize() + self.assertTrue(success) + ip = c.attach() + self.assertEqual(ip, "127.0.0.1") + self.assertTrue(c.checkMTU()) + c.detach() + tmp = tempfile.mkdtemp() + log_file = c.terminate(self.ctx) + # undeploy uses archiveArtifact(), which writes to {prefix}-logs + self.assertEqual(log_file, [f"{self.ctx.baseFilename()}-tttf"]) # matches test-trace UE collection file + +if __name__ == '__main__': + unittest.main() diff --git a/ci-scripts/tests/ping-iperf.py b/ci-scripts/tests/ping-iperf.py index 225fe4e868..bd30768a9f 100644 --- a/ci-scripts/tests/ping-iperf.py +++ b/ci-scripts/tests/ping-iperf.py @@ -9,11 +9,13 @@ import os os.system(f'rm -rf cmake_targets') os.system(f'mkdir -p cmake_targets/log') import unittest +import tempfile sys.path.append('./') # to find OAI imports below import cls_oai_html +from cls_ci_helper import TestCaseCtx import cls_oaicitest -import cls_containerize +import cls_cmd class TestPingIperf(unittest.TestCase): def setUp(self): @@ -22,7 +24,10 @@ class TestPingIperf(unittest.TestCase): self.ci = cls_oaicitest.OaiCiTest() self.ci.ue_ids = ["test"] self.ci.nodes = ["localhost"] - self.cont = cls_containerize.Containerize() + self.ctx = TestCaseCtx.Default(tempfile.mkdtemp()) + def tearDown(self): + with cls_cmd.LocalCmd() as c: + c.run(f'rm -rf {self.ctx.logPath}') def test_ping(self): self.ci.ping_args = "-c3" @@ -30,7 +35,7 @@ class TestPingIperf(unittest.TestCase): self.ci.svr_id = "test" infra_file = "tests/config/infra_ping_iperf.yaml" # TODO Should need nothing but options and UE(s) to use - success = self.ci.Ping(self.html, self.cont, infra_file=infra_file) + success = self.ci.Ping(self.ctx, self.html, infra_file=infra_file) self.assertTrue(success) def test_iperf(self): @@ -45,7 +50,7 @@ class TestPingIperf(unittest.TestCase): self.ci.iperf_profile = "balanced" infra_file = "tests/config/infra_ping_iperf.yaml" # TODO Should need nothing but options and UE(s) to use - success = self.ci.Iperf(self.html, self.cont, infra_file=infra_file) + success = self.ci.Iperf(self.ctx, self.html, infra_file=infra_file) self.assertTrue(success) def test_iperf2_unidir(self): @@ -57,7 +62,22 @@ class TestPingIperf(unittest.TestCase): self.ci.iperf_profile = "balanced" infra_file = "tests/config/infra_ping_iperf.yaml" # TODO Should need nothing but options and UE(s) to use - success = self.ci.Iperf2_Unidir(self.html, self.cont, infra_file=infra_file) + success = self.ci.Iperf2_Unidir(self.ctx, self.html, infra_file=infra_file) + self.assertTrue(success) + + def test_iperf_highrate(self): + # note: needs to be five seconds because Iperf() adds -O 3, so if it is + # too short, the server is terminated before the client loaded + # everything + self.ci.iperf_args = "-u -t 5 -b 1000M -R -O 0" + self.ci.svr_id = "test" + self.ci.svr_node = "localhost" + self.ci.iperf_packetloss_threshold = "0" + self.ci.iperf_bitrate_threshold = "0" + self.ci.iperf_profile = "balanced" + infra_file = "tests/config/infra_ping_iperf.yaml" + # TODO Should need nothing but options and UE(s) to use + success = self.ci.Iperf(self.ctx, self.html, infra_file=infra_file) self.assertTrue(success) if __name__ == '__main__': diff --git a/ci-scripts/tests/pull-clean-int-registry.py b/ci-scripts/tests/pull-clean-int-registry.py index d4d5b4fc0a..3bf4b9e67e 100644 --- a/ci-scripts/tests/pull-clean-int-registry.py +++ b/ci-scripts/tests/pull-clean-int-registry.py @@ -20,33 +20,32 @@ class TestDeploymentMethods(unittest.TestCase): self.html = cls_oai_html.HTMLManagement() self.html.testCaseId = "000000" self.cont = cls_containerize.Containerize() - self.cont.eNBIPAddress = 'localhost' self.cont.eNBSourceCodePath = os.getcwd() def test_pull_clean_local_reg(self): # the pull function has the authentication at the internal cluster hardcoded # this is a refactoring opportunity: we should do it in a separate step # and allow to have pull work with any registry - registry = "porcepix.sboai.cs.eurecom.fr" + registry = cls_containerize.DEFAULT_REGISTRY with cls_cmd.getConnection("localhost") as cmd: ret = cmd.run(f"ping -c1 -w1 {registry}") if ret.returncode != 0: # could not ping once -> skip test self.skipTest(f"test_pull_clean_local_reg: could not reach {registry} (run inside sboai)") - svr_id = '0' + node = 'localhost' images = ["oai-gnb"] tag = "develop" - pull = self.cont.Pull_Image_from_Registry(self.html, svr_id, images, tag=tag) - clean = self.cont.Clean_Test_Server_Images(self.html, svr_id, images, tag=tag) + pull = self.cont.Pull_Image_from_Registry(self.html, node, images, tag=tag) + clean = self.cont.Clean_Test_Server_Images(self.html, node, images, tag=tag) self.assertTrue(pull) self.assertTrue(clean) def test_pull_clean_docker_hub(self): - svr_id = '0' + node = 'localhost' r = "docker.io" images = ["hello-world"] tag = "latest" - pull = self.cont.Pull_Image_from_Registry(self.html, svr_id, images, tag=tag, registry=r, username=None, password=None) - clean = self.cont.Clean_Test_Server_Images(self.html, svr_id, images, tag=tag) + pull = self.cont.Pull_Image_from_Registry(self.html, node, images, tag=tag, registry=r, username=None, password=None) + clean = self.cont.Clean_Test_Server_Images(self.html, node, images, tag=tag) self.assertTrue(pull) self.assertTrue(clean) diff --git a/ci-scripts/tests/test-runner/run.sh b/ci-scripts/tests/test-runner/run.sh index 9c02186a5f..55d421cdb0 100755 --- a/ci-scripts/tests/test-runner/run.sh +++ b/ci-scripts/tests/test-runner/run.sh @@ -22,9 +22,6 @@ python3 main.py \ --ranCommitID=${commit} \ --ranAllowMerge=true \ --ranTargetBranch=develop \ - --eNBIPAddress=localhost \ - --eNBUserName=NONE \ - --eNBPassword=NONE \ --eNBSourceCodePath=NONE \ --XMLTestFile=tests/test-runner/test.xml diff --git a/ci-scripts/tests/test-runner/test.xml b/ci-scripts/tests/test-runner/test.xml index d5efacfdae..cb54989301 100644 --- a/ci-scripts/tests/test-runner/test.xml +++ b/ci-scripts/tests/test-runner/test.xml @@ -27,6 +27,8 @@ wrench 000001 + 000011 + 000012 000002 000003 000004 @@ -38,7 +40,21 @@ This should succeed localhost true - yes + + + + Custom_Command + This may fail + true + localhost + false + + + + Custom_Command + This is still executed + localhost + true @@ -46,7 +62,6 @@ This should fail localhost false - yes @@ -54,7 +69,6 @@ This should be skipped localhost true - yes @@ -63,6 +77,5 @@ true localhost true - yes diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml index 211e02d4c1..615454bbea 100755 --- a/ci-scripts/xml_class_list.yml +++ b/ci-scripts/xml_class_list.yml @@ -1,7 +1,6 @@ - Build_Proxy - Build_Cluster_Image - Pull_Cluster_Image - - Run_Physim - Build_eNB - Initialize_eNB - Terminate_eNB @@ -23,7 +22,9 @@ - Deploy_Object - Undeploy_Object - Cppcheck_Analysis - - Deploy_Run_PhySim + - Deploy_Run_OC_PhySim + - Build_Deploy_Docker_PhySim + - Build_Deploy_Source_PhySim - LicenceAndFormattingCheck - Push_Local_Registry - Pull_Local_Registry diff --git a/ci-scripts/xml_files/cluster_image_build.xml b/ci-scripts/xml_files/cluster_image_build.xml index 6810873b1c..a80d1cd7d4 100644 --- a/ci-scripts/xml_files/cluster_image_build.xml +++ b/ci-scripts/xml_files/cluster_image_build.xml @@ -32,10 +32,12 @@ Create_Workspace Create new Workspace + poseidon Build_Cluster_Image Build Images on OpenShift Cluster + poseidon diff --git a/ci-scripts/xml_files/container_4g_l2sim_tdd.xml b/ci-scripts/xml_files/container_4g_l2sim_tdd.xml index 98e0ec7d08..eabece50cd 100644 --- a/ci-scripts/xml_files/container_4g_l2sim_tdd.xml +++ b/ci-scripts/xml_files/container_4g_l2sim_tdd.xml @@ -44,49 +44,44 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + obelix oai-enb oai-lte-ue Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy Cassandra Database + localhost ci-scripts/yaml_files/4g_l2sim_fdd cassandra db_init - 0 - 0 Deploy_Object Deploy OAI 4G CoreNetwork + localhost ci-scripts/yaml_files/4g_l2sim_fdd oai_hss redis magma_mme oai_spgwc oai_spgwu trf_gen - 0 - 0 Deploy_Object Deploy OAI 4G eNB L2 sim + localhost ci-scripts/yaml_files/4g_l2sim_fdd oai_enb - 0 - 0 Deploy_Object Deploy OAI L2 sim 4G LTE-UE 1 and Proxy + localhost ci-scripts/yaml_files/4g_l2sim_fdd proxy oai_ue1 - 0 - 0 @@ -145,6 +140,7 @@ Undeploy_Object true + localhost Undeploy all OAI 4G stack ci-scripts/yaml_files/4g_l2sim_fdd @@ -153,7 +149,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + obelix oai-enb oai-lte-ue diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml index aa80d4b5dc..4b93c10fcd 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz.xml @@ -46,23 +46,21 @@ Create_Workspace Create new Workspace - 0 - 0 + localhost Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-enb-asan oai-lte-ue-asan Deploy_Object Deploy Cassandra Database + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz cassandra db_init - 0 - 0 @@ -80,44 +78,41 @@ Deploy_Object Deploy OAI 4G CoreNetwork + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz oai_hss redis magma_mme oai_spgwc oai_spgwu trf_gen - 0 - 0 Deploy_Object Deploy OAI 4G eNB RF sim (FDD 05MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz oai_enb0 - 0 - 0 Deploy_Object Deploy OAI 4G LTE-UE RF sim (FDD 05MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz oai_ue0 - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - cacofonix + acamas Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -c 20 5 @@ -126,9 +121,9 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - cacofonix + acamas rfsim4g_ue - cacofonix + acamas -c 20 5 @@ -141,8 +136,8 @@ -u -t 30 -b 2M -R 25 80 - cacofonix - cacofonix + acamas + acamas @@ -153,24 +148,23 @@ -u -t 30 -b 1M 25 80 - cacofonix - cacofonix + acamas + acamas Undeploy_Object true Undeploy all OAI 4G stack + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-enb-asan oai-lte-ue-asan diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml index bfcade47ab..968e30071a 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_05MHz_noS1.xml @@ -43,14 +43,13 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-enb-asan oai-lte-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost IdleSleep @@ -67,28 +66,26 @@ Deploy_Object Deploy OAI 4G eNB RF sim (FDD 05MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz_noS1 oai_enb0 - 0 - 0 Deploy_Object Deploy OAI 4G LTE-UE RF sim (FDD 05MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz_noS1 oai_ue0 - 0 - 0 Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - cacofonix + acamas rfsim4g_enb_nos1 - cacofonix + acamas -c 20 5 @@ -97,9 +94,9 @@ Ping Ping LTE-UE from eNB rfsim4g_enb_nos1 - cacofonix + acamas rfsim4g_ue - cacofonix + acamas -c 20 5 @@ -108,9 +105,9 @@ Iperf Iperf UDP DL rfsim4g_ue - cacofonix + acamas rfsim4g_enb_nos1 - cacofonix + acamas -u -t 30 -b 2M -R 25 80 @@ -120,9 +117,9 @@ Iperf Iperf UDP UL rfsim4g_ue - cacofonix + acamas rfsim4g_enb_nos1 - cacofonix + acamas -u -t 30 -b 1M 25 80 @@ -132,16 +129,15 @@ Undeploy_Object true Undeploy all OAI 4G stack + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz_noS1 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-enb-asan oai-lte-ue-asan diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml index 0cf4944a6c..076ee6995b 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_10MHz.xml @@ -47,22 +47,20 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-enb-asan oai-lte-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy Cassandra Database + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz cassandra db_init - 0 - 0 @@ -80,44 +78,41 @@ Deploy_Object Deploy OAI 4G CoreNetwork + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz oai_hss redis magma_mme oai_spgwc oai_spgwu trf_gen - 0 - 0 Deploy_Object Deploy OAI 4G eNB RF sim (FDD 10MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz oai_enb0 - 0 - 0 Deploy_Object Deploy OAI 4G LTE-UE RF sim (FDD 10MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz oai_ue0 - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - cacofonix + acamas Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -c 20 5 @@ -126,9 +121,9 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - cacofonix + acamas rfsim4g_ue - cacofonix + acamas -c 20 5 @@ -137,9 +132,9 @@ Iperf Iperf UDP DL rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -u -t 30 -b 2M -R 25 80 @@ -149,9 +144,9 @@ Iperf Iperf UDP UL rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -u -t 30 -b 1M 25 80 @@ -161,16 +156,15 @@ Undeploy_Object true Undeploy all OAI 4G stack + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-enb-asan oai-lte-ue-asan diff --git a/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml index 069db0c585..2e049e4efe 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fdd_20MHz.xml @@ -47,22 +47,20 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-enb-asan oai-lte-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy Cassandra Database + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz cassandra db_init - 0 - 0 @@ -80,44 +78,41 @@ Deploy_Object Deploy OAI 4G CoreNetwork + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz oai_hss redis magma_mme oai_spgwc oai_spgwu trf_gen - 0 - 0 Deploy_Object Deploy OAI 4G eNB RF sim (FDD 20MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz oai_enb0 - 0 - 0 Deploy_Object Deploy OAI 4G LTE-UE RF sim (FDD 20MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz oai_ue0 - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim4g_ue - cacofonix + acamas Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -c 20 5 @@ -126,9 +121,9 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - cacofonix + acamas rfsim4g_ue - cacofonix + acamas -c 20 5 @@ -137,9 +132,9 @@ Iperf Iperf UDP DL rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -u -t 30 -b 2M -R 25 80 @@ -149,9 +144,9 @@ Iperf Iperf UDP UL rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -u -t 30 -b 1M 25 80 @@ -161,16 +156,15 @@ Undeploy_Object true Undeploy all OAI 4G stack + localhost ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-enb-asan oai-lte-ue-asan diff --git a/ci-scripts/xml_files/container_4g_rfsim_fembms.xml b/ci-scripts/xml_files/container_4g_rfsim_fembms.xml index c030fbb4a4..7ab434c804 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_fembms.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_fembms.xml @@ -40,14 +40,13 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-enb-asan oai-lte-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost IdleSleep @@ -64,28 +63,26 @@ Deploy_Object Deploy OAI 4G eNB RF sim (FeMBMS) + localhost ci-scripts/yaml_files/4g_rfsimulator_fembms oai_enb0 - 0 - 0 Deploy_Object Deploy OAI 4G LTE-UE RF sim (FeMBMS) + localhost ci-scripts/yaml_files/4g_rfsimulator_fembms oai_ue0 - 0 - 0 Iperf2_Unidir Iperf2 UDP DL rfsim4g_ue_fembms - cacofonix + acamas rfsim4g_enb_fembms - cacofonix + acamas -u -t 30 -b 2M 25 80 @@ -95,16 +92,15 @@ Undeploy_Object true Undeploy all OAI 4G stack + localhost ci-scripts/yaml_files/4g_rfsimulator_fembms - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-enb-asan oai-lte-ue-asan diff --git a/ci-scripts/xml_files/container_4g_rfsim_mbms.xml b/ci-scripts/xml_files/container_4g_rfsim_mbms.xml index 34c2fc6c89..e6a4cde19a 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_mbms.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_mbms.xml @@ -40,14 +40,13 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-enb-asan oai-lte-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost IdleSleep @@ -64,28 +63,26 @@ Deploy_Object Deploy OAI 4G eNB RF sim (MBMS) + localhost ci-scripts/yaml_files/4g_rfsimulator_mbms oai_enb0 - 0 - 0 Deploy_Object Deploy OAI 4G LTE-UE RF sim (MBMS) + localhost ci-scripts/yaml_files/4g_rfsimulator_mbms oai_ue0 - 0 - 0 Iperf Iperf UDP DL rfsim4g_ue - cacofonix + acamas rfsim4g_enb_nos1 - cacofonix + acamas -u -t 30 -b 2M -R 25 80 @@ -95,16 +92,15 @@ Undeploy_Object true Undeploy all OAI 4G stack + localhost ci-scripts/yaml_files/4g_rfsimulator_mbms - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-enb-asan oai-lte-ue-asan diff --git a/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml b/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml index df44214af9..2e22577879 100644 --- a/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml +++ b/ci-scripts/xml_files/container_4g_rfsim_tdd_05MHz.xml @@ -47,22 +47,20 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-enb oai-lte-ue Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy Cassandra Database + localhost ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz cassandra db_init - 0 - 0 @@ -80,37 +78,34 @@ Deploy_Object Deploy OAI 4G CoreNetwork + localhost ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz oai_hss oai_mme oai_spgwc oai_spgwu trf_gen - 0 - 0 Deploy_Object Deploy OAI 4G eNB RF sim (TDD 05MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz oai_enb0 - 0 - 0 Deploy_Object Deploy OAI 4G LTE-UE RF sim (TDD 05MHz) + localhost ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz oai_ue0 - 0 - 0 Ping Ping Traffic-Gen from LTE-UE rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -c 20 5 @@ -119,9 +114,9 @@ Ping Ping LTE-UE from Traffic-Gen rfsim4g_ext_dn - cacofonix + acamas rfsim4g_ue - cacofonix + acamas -c 20 5 @@ -130,9 +125,9 @@ Iperf Iperf UDP DL rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -u -t 30 -b 2M -R 25 80 @@ -142,9 +137,9 @@ Iperf Iperf UDP UL rfsim4g_ue - cacofonix + acamas rfsim4g_ext_dn - cacofonix + acamas -u -t 30 -b 1M 25 80 @@ -154,16 +149,15 @@ Undeploy_Object true Undeploy all OAI 4G stack + localhost ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-enb oai-lte-ue diff --git a/ci-scripts/xml_files/container_5g_e1_rfsim.xml b/ci-scripts/xml_files/container_5g_e1_rfsim.xml index 95ae2f7b0a..d27091ac63 100644 --- a/ci-scripts/xml_files/container_5g_e1_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_e1_rfsim.xml @@ -40,56 +40,52 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb oai-nr-cuup oai-nr-ue Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator_e1 mysql oai-amf oai-smf oai-upf - 0 - 0 Deploy_Object Deploy OAI 5G RAN RF sim SA (1 CU-CP, 3 CU-UPs, 3 DUs) + localhost ci-scripts/yaml_files/5g_rfsimulator_e1 oai-cucp oai-cuup oai-cuup2 oai-cuup3 oai-du oai-du2 oai-du3 - 0 - 0 Deploy_Object Deploy OAI 5G NR-UE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_e1 oai-nr-ue oai-nr-ue2 oai-nr-ue3 - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue rfsim5g_ue2 rfsim5g_ue3 - cacofonix cacofonix cacofonix + acamas acamas acamas Ping Ping ext-dn from all NR-UEs rfsim5g_ue rfsim5g_ue2 rfsim5g_ue3 - cacofonix cacofonix cacofonix + acamas acamas acamas rfsim5g_5gc_fixed_ip - cacofonix + acamas -c 20 -i0.25 5 @@ -97,19 +93,18 @@ Undeploy_Object true + localhost Undeploy all OAI 5G stack ci-scripts/yaml_files/5g_rfsimulator_e1 1,0,0,0 1,0,0,0 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb oai-nr-cuup oai-nr-ue diff --git a/ci-scripts/xml_files/container_5g_f1_rfsim.xml b/ci-scripts/xml_files/container_5g_f1_rfsim.xml index b27b0b5701..50e794e4cb 100644 --- a/ci-scripts/xml_files/container_5g_f1_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_f1_rfsim.xml @@ -55,6 +55,10 @@ 000031 020022 040026 + 040025 + 000031 + 020022 + 040027 100021 222222 @@ -63,37 +67,34 @@ Pull_Local_Registry Pull Images from Local Registry - 0 - oai-gnb-asan oai-nr-cuup-asan oai-nr-ue-asan + localhost + oai-gnb-asan oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_f1_rfsimulator mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G CU + DU-PCI0 + UE RF sim SA + localhost ci-scripts/yaml_files/5g_f1_rfsimulator oai-cu oai-du-pci0 oai-nr-ue - 0 - 0 IdleSleep Sleep - 5 + 15 @@ -106,25 +107,24 @@ Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - cacofonix + acamas Deploy_Object Deploy OAI 5G (target) DU-PCI1 RF sim SA + localhost ci-scripts/yaml_files/5g_f1_rfsimulator oai-du-pci1 - 0 - 0 Ping Ping ext-dn from all NR-UEs rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i0.25 5 @@ -132,19 +132,18 @@ Custom_Command Simulate a DL radio channel with noise (3 dB) - cacofonix - echo channelmod modify 0 noise_power_dB 3 | nc --send-only 192.168.71.181 8091 - yes + acamas + echo channelmod modify 0 noise_power_dB 3 | ncat --send-only 192.168.71.181 8091 Iperf - Iperf (DL/5Mbps/UDP)(30 sec) - -u -b 5M -t 20 -R + Iperf (DL/3Mbps/UDP)(30 sec) + -u -b 3M -t 20 -R rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -154,9 +153,9 @@ Iperf (UL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -164,18 +163,17 @@ Custom_Command Trigger Reestablishment - cacofonix - echo ci force_reestab | nc 192.168.71.171 9090 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' - yes + acamas + echo ci force_reestab | ncat 192.168.71.171 9090 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i0.5 -w25 80 @@ -183,84 +181,75 @@ Custom_Command Verify Reestablishment - cacofonix - echo ci get_reestab_count | nc 192.168.71.150 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' - yes + acamas + echo ci get_reestab_count | ncat 192.168.71.150 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' Custom_Command Simulate a disruption of DL radio channel (ploss 55) - cacofonix - echo channelmod modify 0 ploss 55 | nc 192.168.71.181 8091 - yes + acamas + echo channelmod modify 0 ploss 55 | ncat 192.168.71.181 8091 Custom_Command Get UE sync state (UE ID 0) - cacofonix - echo ciUE sync_state 0 | nc 192.168.71.181 8091 | grep -E UE_NOT_SYNC - yes + acamas + echo ciUE sync_state 0 | ncat 192.168.71.181 8091 | grep -E UE_NOT_SYNC Custom_Command Restoration of the original DL channel conditions (ploss 20) - cacofonix - echo channelmod modify 0 ploss 20 | nc 192.168.71.181 8091 - yes + acamas + echo channelmod modify 0 ploss 20 | ncat 192.168.71.181 8091 Custom_Command Get UE sync state (UE ID 0) - cacofonix - echo ciUE sync_state 0 | nc 192.168.71.181 8091 | grep -E UE_CONNECTED - yes + acamas + echo ciUE sync_state 0 | ncat 192.168.71.181 8091 | grep -E UE_CONNECTED Custom_Command Trigger Handover - cacofonix - echo ci trigger_f1_ho | nc 192.168.71.150 9090 - yes + acamas + echo ci trigger_f1_ho | ncat 192.168.71.150 9090 Custom_Command UE (1) connected to DU-PCI 0? - cacofonix - echo ci fetch_du_by_ue_id 1 | nc 192.168.71.150 9090 | grep "3584" - yes + acamas + echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.150 9090 | grep "3584" Custom_Command UE (1) connected to DU-PCI 1? - cacofonix - echo ci fetch_du_by_ue_id 1 | nc 192.168.71.150 9090 | grep "3585" - yes + acamas + echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.150 9090 | grep "3585" Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_f1_rfsimulator 30,100,100,100 30,100,100,100 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 - oai-gnb-asan oai-nr-cuup-asan oai-nr-ue-asan + localhost + oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml index 2c9fd04544..6ce1e37b90 100644 --- a/ci-scripts/xml_files/container_5g_fdd_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_fdd_rfsim.xml @@ -42,47 +42,44 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb oai-nr-ue Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_fdd_rfsimulator mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G gNB+UE RF sim SA + localhost ci-scripts/yaml_files/5g_fdd_rfsimulator oai-gnb oai-nr-ue - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - cacofonix + acamas Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 5 @@ -91,9 +88,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c 20 -i 0.25 5 @@ -103,9 +100,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 30 -R rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -115,9 +112,9 @@ Iperf (UL/3Mbps/UDP)(30 sec) -u -b 3M -t 30 rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -126,18 +123,17 @@ Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_fdd_rfsimulator 1,0,0,0 1,0,0,0 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb oai-nr-ue diff --git a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml index a56248fe0e..8ee9326b5e 100644 --- a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml @@ -51,21 +51,21 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb oai-nr-ue Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-flexric Clean_Test_Server_Images Clean Test Images on Test Server - 0 + localhost oai-gnb oai-nr-ue true @@ -73,7 +73,7 @@ Clean_Test_Server_Images Clean Test Images on Test Server - 0 + localhost oai-flexric true @@ -88,37 +88,33 @@ Deploy_Object Deploy OAI 5G CoreNetwork + localhost doc/tutorial_resources/oai-cn5g mysql oai-nrf oai-udr oai-udm oai-ausf oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI FlexRIC + localhost ci-scripts/yaml_files/5g_rfsimulator_flexric oai-flexric - 0 - 0 Deploy_Object Deploy OAI 5G gNB in RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_flexric oai-gnb - 0 - 0 Deploy_Object Deploy 2 OAI 5G NR-UEs in RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_flexric oai-nr-ue oai-nr-ue2 - 0 - 0 @@ -149,55 +145,49 @@ Undeploy_Object Undeploy Core Network + localhost doc/tutorial_resources/oai-cn5g - 0 - 0 true Undeploy_Object Undeploy RAN and Flexric + localhost ci-scripts/yaml_files/5g_rfsimulator_flexric - 0 - 0 true Deploy_Object RC monitoring + localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-rc-moni - 0 - 0 Deploy_Object KPM monitoring + localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-kpm-moni - 0 - 0 Deploy_Object KPM monitoring and RC control + localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-kpm-rc - 0 - 0 Deploy_Object Custom SMs monitoring + localhost ci-scripts/yaml_files/5g_rfsimulator_flexric xapp-gtp-mac-rlc-pdcp-moni - 0 - 0 diff --git a/ci-scripts/xml_files/container_5g_rfsim.xml b/ci-scripts/xml_files/container_5g_rfsim.xml index f20820629b..d7fb38ef8f 100644 --- a/ci-scripts/xml_files/container_5g_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_rfsim.xml @@ -57,92 +57,84 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G gNB RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator oai-gnb - 0 - 0 Deploy_Object Deploy OAI 5G NR-UE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator oai-nr-ue - 0 - 0 Deploy_Object Deploy Second OAI 5G NR-UE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator oai-nr-ue2 - 0 - 0 Deploy_Object Deploy OAI 5G NR-UEs (#3, #4, #5) RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator oai-nr-ue3 oai-nr-ue4 oai-nr-ue5 - 0 - 0 Deploy_Object Deploy OAI 5G NR-UEs (#6, #7, #8) RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator oai-nr-ue6 oai-nr-ue7 oai-nr-ue8 - 0 - 0 Deploy_Object Deploy OAI 5G NR-UEs (#9, #10) RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator oai-nr-ue9 oai-nr-ue10 - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue rfsim5g_ue2 rfsim5g_ue3 rfsim5g_ue4 rfsim5g_ue5 rfsim5g_ue6 rfsim5g_ue7 rfsim5g_ue8 rfsim5g_ue9 rfsim5g_ue10 - cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix + acamas acamas acamas acamas acamas acamas acamas acamas acamas acamas Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 5 @@ -151,9 +143,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c 20 -i 0.25 5 @@ -162,9 +154,9 @@ Ping Ping ext-dn from Second NR-UE rfsim5g_ue2 - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 5 @@ -173,9 +165,9 @@ Ping Ping Second NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue2 - cacofonix + acamas -c 20 -i 0.25 5 @@ -184,9 +176,9 @@ Ping Ping ext-dn from both UEs rfsim5g_ue rfsim5g_ue2 - cacofonix cacofonix + acamas acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 5 @@ -195,9 +187,9 @@ Ping Ping ext-dn from all UEs rfsim5g_ue rfsim5g_ue2 rfsim5g_ue3 rfsim5g_ue4 rfsim5g_ue5 rfsim5g_ue6 rfsim5g_ue7 rfsim5g_ue8 rfsim5g_ue9 rfsim5g_ue10 - cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix + acamas acamas acamas acamas acamas acamas acamas acamas acamas acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 -s 1016 5 @@ -207,9 +199,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -219,9 +211,9 @@ Iperf (UL/1Mbps/UDP)(30 sec) -u -b 1M -t 20 rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -230,39 +222,38 @@ Attach_UE Attach OAI UE 1 and 2 rfsim5g_ue rfsim5g_ue2 - cacofonix cacofonix + acamas acamas Detach_UE Detach OAI UE 1 and 2 rfsim5g_ue rfsim5g_ue2 - cacofonix cacofonix + acamas acamas Detach_UE - Detach OAI UE 2 to 10 + Detach OAI UE 3 to 10 rfsim5g_ue3 rfsim5g_ue4 rfsim5g_ue5 rfsim5g_ue6 rfsim5g_ue7 rfsim5g_ue8 rfsim5g_ue9 rfsim5g_ue10 - cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix cacofonix + acamas acamas acamas acamas acamas acamas acamas acamas Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator 1,0,0,0 1,0,0,0 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue diff --git a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml index 5a59880b2f..7db37d8e63 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml @@ -60,38 +60,35 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator_24prb mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G gNB+UE RFsim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_24prb oai-gnb oai-nr-ue - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - cacofonix + acamas @@ -104,9 +101,9 @@ Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i0.5 80 @@ -115,9 +112,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c 20 -i0.2 5 @@ -127,9 +124,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -139,9 +136,9 @@ Iperf (UL/1Mbps/UDP)(30 sec) -u -b 1M -t 20 rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -149,33 +146,30 @@ Custom_Command Force Msg3 C-RNTI RA - cacofonix - echo ciUE force_crnti_ra | nc 192.168.71.150 8091 - yes + acamas + echo ciUE force_crnti_ra | ncat 192.168.71.150 8091 Custom_Command Force RRC_IDLE (UE ID 0) - cacofonix - echo ciUE force_RRC_IDLE | nc 192.168.71.150 8091 - yes + acamas + echo ciUE force_RRC_IDLE | ncat 192.168.71.150 8091 Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_24prb - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_rfsim_2x2.xml b/ci-scripts/xml_files/container_5g_rfsim_2x2.xml index 77d39a3c55..75924e1ca2 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_2x2.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_2x2.xml @@ -42,47 +42,44 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator_2x2 mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G gNB+UE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_2x2 oai-gnb oai-nr-ue - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - cacofonix + acamas Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 5 @@ -91,9 +88,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c 20 -i 0.25 5 @@ -103,21 +100,21 @@ Iperf (DL/10Mbps/UDP)(30 sec) -u -b 10M -t 20 -R rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 Iperf - Iperf (UL/4Mbps/UDP)(30 sec) - -u -b 4M -t 20 + Iperf (UL/3Mbps/UDP)(30 sec) + -u -b 3M -t 20 rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -126,9 +123,8 @@ Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_2x2 - 0 - 0 1,0,0,0 1,0,0,0 @@ -137,7 +133,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_rfsim_fdd_phytest.xml b/ci-scripts/xml_files/container_5g_rfsim_fdd_phytest.xml index cd908d0d82..b376df99f4 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_fdd_phytest.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_fdd_phytest.xml @@ -42,47 +42,44 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue-asan Custom_Command Clean-Up any residual volume - cacofonix + acamas docker volume rm 5g_rfsimulator_fdd_phytest_rrc.config -f Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G gNB RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_fdd_phytest oai-gnb - 0 - 0 Deploy_Object Deploy OAI 5G NR-UE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_fdd_phytest oai-nr-ue - 0 - 0 Ping Ping gNB from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_gnb_nos1 - cacofonix + acamas -c20 -i0.2 0 @@ -91,9 +88,9 @@ Ping Ping NR-UE from gNB rfsim5g_gnb_nos1 - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c20 -i0.2 0 @@ -103,9 +100,9 @@ Iperf (DL/30kbps/UDP)(30 sec) -u -b 0.03M -t 20 -R -c 10.0.1.1 rfsim5g_ue - cacofonix + acamas rfsim5g_gnb_nos1 - cacofonix + acamas 5 90 @@ -115,9 +112,9 @@ Iperf (UL/30kbps/UDP)(30 sec) -u -b 0.03M -t 20 -c 10.0.1.1 rfsim5g_ue - cacofonix + acamas rfsim5g_gnb_nos1 - cacofonix + acamas 5 90 @@ -126,18 +123,17 @@ Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_fdd_phytest 10,100,100,100 10,100,100,100 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_rfsim_fr2_32prb.xml b/ci-scripts/xml_files/container_5g_rfsim_fr2_32prb.xml index db10ff6478..6a47da0ff9 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_fr2_32prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_fr2_32prb.xml @@ -29,6 +29,7 @@ 800813 000000 000001 + 000013 020001 020002 100001 @@ -39,42 +40,46 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI gNB + localhost ci-scripts/yaml_files/5g_rfsimulator_fr2_32prb mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI NR-UE + localhost ci-scripts/yaml_files/5g_rfsimulator_fr2_32prb oai-gnb oai-nr-ue - 0 - 0 + + + + Attach_UE + Attach OAI UE (Wait for IP) + rfsim5g_ue + acamas Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i0.2 0 @@ -83,9 +88,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c 20 -i0.2 0 @@ -94,18 +99,17 @@ Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_fr2_32prb 10,0,0,0 10,0,0,0 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_rfsim_multiue.xml b/ci-scripts/xml_files/container_5g_rfsim_multiue.xml new file mode 100644 index 0000000000..79d85e154c --- /dev/null +++ b/ci-scripts/xml_files/container_5g_rfsim_multiue.xml @@ -0,0 +1,210 @@ + + + rfsim-5gnr-tdd-multiue + Monolithic SA TDD gNB multiue + wrench + + 111111 + 800813 + 000001 + 000002 + 000003 + 000008 + 020001 + 020002 + 020003 + 020004 + 020105 + 444445 + 030001 + 030002 + 444444 + 100001 + 222222 + + + + + Pull_Local_Registry + Pull Images from Local Registry + 0 + oai-gnb-asan oai-nr-ue + + + Create_Workspace + Create new Workspace + 0 + 0 + + + Deploy_Object + Deploy OAI 5G CoreNetwork + ci-scripts/yaml_files/5g_rfsimulator_multiue + mysql oai-amf oai-smf oai-upf oai-ext-dn + 0 + 0 + + + + Deploy_Object + Deploy OAI 5G gNB RF sim SA + ci-scripts/yaml_files/5g_rfsimulator_multiue + oai-gnb + 0 + 0 + + + + Deploy_Object + Deploy OAI 5G NR-UE RF sim SA + ci-scripts/yaml_files/5g_rfsimulator_multiue + oai-nr-ue + 0 + 0 + + + + Attach_UE + Attach OAI UE (Wait for IP) + rfsim5g_multiue1 rfsim5g_multiue2 rfsim5g_multiue3 rfsim5g_multiue4 rfsim5g_multiue5 rfsim5g_multiue6 rfsim5g_multiue7 rfsim5g_multiue8 rfsim5g_multiue9 rfsim5g_multiue10 + acamas acamas acamas acamas acamas acamas acamas acamas acamas acamas + + + + Ping + Ping ext-dn from NR-UE + rfsim5g_multiue1 + acamas + rfsim5g_ext_dn + acamas + -c 20 -i 0.25 + 5 + + + + Ping + Ping NR-UE from ext-dn + rfsim5g_ext_dn + acamas + rfsim5g_multiue1 + acamas + -c 20 -i 0.25 + 5 + + + + Ping + Ping ext-dn from Second NR-UE + rfsim5g_multiue2 + acamas + rfsim5g_ext_dn + acamas + -c 20 -i 0.25 + 5 + + + + Ping + Ping Second NR-UE from ext-dn + rfsim5g_ext_dn + acamas + rfsim5g_multiue2 + acamas + -c 20 -i 0.25 + 5 + + + + Ping + Ping ext-dn from both UEs + rfsim5g_multiue1 rfsim5g_multiue2 + acamas acamas + rfsim5g_ext_dn + acamas + -c 20 -i 0.25 + 5 + + + + Ping + Ping ext-dn from all UEs + rfsim5g_multiue1 rfsim5g_multiue2 rfsim5g_multiue3 rfsim5g_multiue4 rfsim5g_multiue5 rfsim5g_multiue6 rfsim5g_multiue7 rfsim5g_multiue8 rfsim5g_multiue9 rfsim5g_multiue10 + acamas acamas acamas acamas acamas acamas acamas acamas acamas acamas + rfsim5g_ext_dn + acamas + -c 20 -i 0.25 -s 1016 + 5 + + + + Iperf + Iperf (DL/3Mbps/UDP)(30 sec) + -u -b 3M -t 20 -R + rfsim5g_multiue1 + acamas + rfsim5g_ext_dn + acamas + 5 + 90 + + + + Iperf + Iperf (UL/1Mbps/UDP)(30 sec) + -u -b 1M -t 20 + rfsim5g_multiue1 + acamas + rfsim5g_ext_dn + acamas + 5 + 90 + + + + Detach_UE + Detach OAI UEs + rfsim5g_multiue1 + acamas + + + + Undeploy_Object + true + Undeploy all OAI 5G stack + ci-scripts/yaml_files/5g_rfsimulator_multiue + 1,0,0,0 + 1,0,0,0 + 0 + 0 + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + 0 + oai-gnb-asan oai-nr-ue + + + diff --git a/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml b/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml new file mode 100644 index 0000000000..feffaedf05 --- /dev/null +++ b/ci-scripts/xml_files/container_5g_rfsim_n2_ho.xml @@ -0,0 +1,204 @@ + + + rfsim-5gnr-f1-n2-ho + F1 SA TDD N2 Handover + wrench + + 111111 + 800813 + 000001 + 000002 + 000003 + 020001 + 000004 + 040001 + 050001 + 020001 + 020002 + 050002 + 030001 + 030002 + 050003 + 020001 + 020002 + 050004 + 050001 + 020001 + 020002 + 050002 + 100001 + 222222 + + + + + Pull_Local_Registry + Pull Images from Local Registry + 0 + oai-gnb-asan oai-nr-cuup-asan oai-nr-ue-asan + + + + Create_Workspace + Create new Workspace + 0 + 0 + + + + Deploy_Object + Deploy OAI 5G CoreNetwork + ci-scripts/yaml_files/5g_rfsimulator_n2_ho + mysql oai-amf oai-smf oai-upf oai-ext-dn + 0 + 0 + + + + Deploy_Object + Deploy OAI 5G CU-CP/CU-UP/DU 0 + UE RFsim SA + ci-scripts/yaml_files/5g_rfsimulator_n2_ho + oai-cucp-0 oai-cuup-0 oai-du-0 oai-nr-ue + 0 + 0 + + + + Attach_UE + Attach OAI UE (Wait for IP) + rfsim5g_ue + acamas + + + + Deploy_Object + Deploy OAI 5G CU-CP/CU-UP/DU 1 RFsim SA + ci-scripts/yaml_files/5g_rfsimulator_n2_ho + oai-cucp-1 oai-cuup-1 oai-du-1 + 0 + 0 + + + + Ping + Ping NR-UE from ext-dn + rfsim5g_ext_dn + acamas + rfsim5g_ue + acamas + -c 50 -i 0.25 + 5 + + + + Ping + Ping ext-dn from NR-UE + rfsim5g_ue + acamas + rfsim5g_ext_dn + acamas + -c 50 -i 0.25 + 10 + + + + Iperf + Iperf (DL/10Mbps/UDP)(30 sec) + -u -b 3M -t 20 -R + rfsim5g_ue + acamas + rfsim5g_ext_dn + acamas + 5 + 90 + + + + Iperf + Iperf (UL/4Mbps/UDP)(30 sec) + -u -b 1M -t 20 + rfsim5g_ue + acamas + rfsim5g_ext_dn + acamas + 5 + 90 + + + + IdleSleep + Sleep + 5 + + + + Custom_Command + Trigger N2 Handover + acamas + echo ci trigger_n2_ho 1,1 | ncat 192.168.71.150 9090 + yes + + + + Custom_Command + UE (1) connected to DU-PCI 1? + acamas + echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.180 9090 | grep "1234" + + + + Custom_Command + Trigger N2 Handover + acamas + echo ci trigger_n2_ho 0,1 | ncat 192.168.71.180 9090 + yes + + + + Custom_Command + UE (1) connected to DU-PCI 0? + acamas + echo ci fetch_du_by_ue_id 1 | ncat 192.168.71.150 9090 | grep "3584" + + + + Undeploy_Object + true + Undeploy all OAI 5G stack + ci-scripts/yaml_files/5g_rfsimulator_n2_ho + 0 + 0 + 10,100,100,100 + 10,100,100,100 + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + 0 + oai-gnb-asan oai-nr-cuup-asan oai-nr-ue-asan + + + diff --git a/ci-scripts/xml_files/container_5g_rfsim_ntn_geo.xml b/ci-scripts/xml_files/container_5g_rfsim_ntn_geo.xml index 72a6836882..7107b7971b 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_ntn_geo.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_ntn_geo.xml @@ -26,13 +26,17 @@ wrench 111111 - 100001 800813 000001 000002 000003 020001 020002 + 040001 + 020022 + 040002 + 020001 + 020002 100001 222222 @@ -41,48 +45,45 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator_ntn_geo mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G gNB+nrUE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_ntn_geo oai-gnb oai-nr-ue - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - cacofonix + acamas Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 5 @@ -91,27 +92,53 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c 20 -i 0.25 5 + + Custom_Command + Trigger Reestablishment + acamas + echo ci force_reestab | ncat 192.168.71.140 9090 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' + yes + + + + Ping + Ping ext-dn from NR-UE + rfsim5g_ue + acamas + rfsim5g_ext_dn + acamas + -c 20 -i0.5 -w25 + 80 + + + + Custom_Command + Verify Reestablishment + acamas + echo ci get_reestab_count | ncat 192.168.71.140 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' + yes + + Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_ntn_geo - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml b/ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml index 2846fc016e..63897cfb8b 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_ntn_leo.xml @@ -26,7 +26,6 @@ wrench 111111 - 100001 800813 000001 000002 @@ -41,48 +40,45 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator_ntn_leo mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G gNB+nrUE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_ntn_leo oai-gnb oai-nr-ue - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - cacofonix + acamas Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 5 @@ -91,9 +87,9 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c 20 -i 0.25 5 @@ -102,16 +98,15 @@ Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_ntn_leo - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_rfsim_sidelink.xml b/ci-scripts/xml_files/container_5g_rfsim_sidelink.xml index 133d960c3a..58bff964d4 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_sidelink.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_sidelink.xml @@ -39,33 +39,30 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G UE 1 + localhost ci-scripts/yaml_files/5g_rfsimulator_sidelink oai-nr-ue-1 - 0 - 0 Deploy_Object Deploy OAI 5G UE 2 + localhost ci-scripts/yaml_files/5g_rfsimulator_sidelink oai-nr-ue-2 - 0 - 0 @@ -77,27 +74,25 @@ Custom_Command Check that UE synched - cacofonix + acamas docker logs rfsim5g-oai-nr-ue-2 | grep -m 1 "PSBCH RX:OK" - yes Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_sidelink 1,0,0,0 1,0,0,0 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_rfsim_simple.xml b/ci-scripts/xml_files/container_5g_rfsim_simple.xml new file mode 100644 index 0000000000..738ce1a077 --- /dev/null +++ b/ci-scripts/xml_files/container_5g_rfsim_simple.xml @@ -0,0 +1,97 @@ + + + rfsim-5gnr-tdd + Monolithic SA TDD gNB + wrench + + 000001 + 000002 + 000003 + 000008 + 020001 + 444444 + 100001 + + + + + Deploy_Object + Deploy OAI 5G CoreNetwork + localhost + ci-scripts/yaml_files/5g_rfsimulator + mysql oai-amf oai-smf oai-upf oai-ext-dn + + + + Deploy_Object + Deploy OAI 5G gNB RF sim SA + localhost + ci-scripts/yaml_files/5g_rfsimulator + oai-gnb + + + + Deploy_Object + Deploy OAI 5G NR-UE RF sim SA + localhost + ci-scripts/yaml_files/5g_rfsimulator + oai-nr-ue + + + + Attach_UE + Attach OAI UE (Wait for IP) + rfsim5g_ue + localhost + + + + Ping + Ping ext-dn from NR-UE + rfsim5g_ue + localhost + rfsim5g_ext_dn + localhost + -c 20 -i 0.25 + 5 + + + + Detach_UE + Detach OAI UE 1 + rfsim5g_ue + localhost + + + + Undeploy_Object + true + Undeploy all OAI 5G stack + localhost + ci-scripts/yaml_files/5g_rfsimulator + 1,0,0,0 + 1,0,0,0 + + + diff --git a/ci-scripts/xml_files/container_5g_rfsim_tdd_dora.xml b/ci-scripts/xml_files/container_5g_rfsim_tdd_dora.xml index bf71fc98ab..97730bd233 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_tdd_dora.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_tdd_dora.xml @@ -30,6 +30,7 @@ 004000 000000 000001 + 000030 020001 020002 100001 @@ -41,47 +42,50 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue-asan Custom_Command Clean-Up any residual volume - cacofonix + acamas docker volume rm 5g_rfsimulator_tdd_dora_rrc.config -f Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI gNB + localhost ci-scripts/yaml_files/5g_rfsimulator_tdd_dora oai-gnb - 0 - 0 Deploy_Object Deploy OAI NR-UE + localhost ci-scripts/yaml_files/5g_rfsimulator_tdd_dora oai-nr-ue - 0 - 0 + + + + IdleSleep + Sleep + 5 Ping Ping gNB from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_gnb_nos1 - cacofonix + acamas -c20 -i0.2 0 @@ -90,9 +94,9 @@ Ping Ping NR-UE from gNB rfsim5g_gnb_nos1 - cacofonix + acamas rfsim5g_ue - cacofonix + acamas -c20 -i0.2 0 @@ -101,26 +105,17 @@ Undeploy_Object true Undeploy all OAI 5G stack + localhost ci-scripts/yaml_files/5g_rfsimulator_tdd_dora 0,0,0,0 0,0,0,0 - 0 - 0 - - - - Custom_Command - true - Clean-Up any residual volume - cacofonix - docker volume rm 5g_rfsimulator_tdd_dora_rrc.config Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml index bedb40799e..c5c76124d3 100644 --- a/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml +++ b/ci-scripts/xml_files/container_5g_rfsim_u0_25prb.xml @@ -32,6 +32,8 @@ 000003 020001 020002 + 000004 + 020003 030001 030002 100001 @@ -42,47 +44,44 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + localhost oai-gnb-asan oai-nr-ue-asan Create_Workspace Create new Workspace - 0 - 0 + localhost Deploy_Object Deploy OAI 5G CoreNetwork + localhost ci-scripts/yaml_files/5g_rfsimulator_u0_25prb mysql oai-amf oai-smf oai-upf oai-ext-dn - 0 - 0 Deploy_Object Deploy OAI 5G VNF+PNF+nrUE RF sim SA + localhost ci-scripts/yaml_files/5g_rfsimulator_u0_25prb oai-vnf oai-pnf oai-nr-ue - 0 - 0 Attach_UE Attach OAI UE (Wait for IP) rfsim5g_ue - cacofonix + acamas Ping Ping ext-dn from NR-UE rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas -c 20 -i 0.25 5 @@ -91,9 +90,27 @@ Ping Ping NR-UE from ext-dn rfsim5g_ext_dn - cacofonix + acamas rfsim5g_ue - cacofonix + acamas + -c 20 -i 0.25 + 5 + + + + Attach_UE + Verify 2nd PDU session is up + rfsim5g_ue_pdu_2 + acamas + + + + Ping + Ping ext-dn from NR-UE on PDU session ID 2 + rfsim5g_ue_pdu_2 + acamas + rfsim5g_ext_dn + acamas -c 20 -i 0.25 5 @@ -103,9 +120,9 @@ Iperf (DL/3Mbps/UDP)(30 sec) -u -b 3M -t 20 -R rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -115,9 +132,9 @@ Iperf (UL/1Mbps/UDP)(30 sec) -u -b 1M -t 20 rfsim5g_ue - cacofonix + acamas rfsim5g_ext_dn - cacofonix + acamas 5 90 @@ -126,19 +143,18 @@ Undeploy_Object true Undeploy all OAI 5G stack + localhost oai-vnf oai-pnf ci-scripts/yaml_files/5g_rfsimulator_u0_25prb 1,0,0,0 1,0,0,0 - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + localhost oai-gnb-asan oai-nr-ue-asan diff --git a/ci-scripts/xml_files/container_build_run_tests.xml b/ci-scripts/xml_files/container_build_run_tests.xml index 479bb20a5d..087c5af598 100644 --- a/ci-scripts/xml_files/container_build_run_tests.xml +++ b/ci-scripts/xml_files/container_build_run_tests.xml @@ -32,9 +32,8 @@ Build_Run_Tests Build and Run UnitTests + obelix all - 0 - 0 diff --git a/ci-scripts/xml_files/container_image_build.xml b/ci-scripts/xml_files/container_image_build.xml index 7db63e4281..afd58d4d6d 100644 --- a/ci-scripts/xml_files/container_image_build.xml +++ b/ci-scripts/xml_files/container_image_build.xml @@ -34,22 +34,19 @@ Create_Workspace Create new Workspace for server 0 - 0 - 0 + obelix Build_Image Build all Images + obelix all - 0 - 0 - True Push_Local_Registry Push Images to Local Registry - 0 + obelix diff --git a/ci-scripts/xml_files/container_image_build_arm.xml b/ci-scripts/xml_files/container_image_build_arm.xml index 722d23ddcf..f5daa348aa 100644 --- a/ci-scripts/xml_files/container_image_build_arm.xml +++ b/ci-scripts/xml_files/container_image_build_arm.xml @@ -34,21 +34,19 @@ Create_Workspace Create new Workspace for server 0 - 0 - 0 + gracehopper3-oai Build_Image Build all Images - native_arm - 0 - 0 + gracehopper3-oai + native_armv9 Push_Local_Registry Push Images to Local Registry - 0 + gracehopper3-oai arm_ diff --git a/ci-scripts/xml_files/container_image_build_cross.xml b/ci-scripts/xml_files/container_image_build_cross.xml index 046ceb5413..ab94d847c8 100644 --- a/ci-scripts/xml_files/container_image_build_cross.xml +++ b/ci-scripts/xml_files/container_image_build_cross.xml @@ -32,16 +32,13 @@ Create_Workspace Create new Workspace - 0 - 0 + alambix Build_Image Cross-Compile for ARM64 build_cross_arm64 - 0 - 0 - True + alambix diff --git a/ci-scripts/xml_files/container_image_build_jetson.xml b/ci-scripts/xml_files/container_image_build_jetson.xml new file mode 100644 index 0000000000..3cdac5efcb --- /dev/null +++ b/ci-scripts/xml_files/container_image_build_jetson.xml @@ -0,0 +1,53 @@ + + + build-tab + Build Container Images for ARM + wrench + + 800813 + 000001 + 000010 + + + + + Create_Workspace + Create new Workspace for server 0 + jetson3-oai + + + Build_Image + Build all Images + jetson3-oai + native_armv8 + + + + Push_Local_Registry + Push Images to Local Registry + jetson3-oai + armv8_ + + + diff --git a/ci-scripts/xml_files/container_l2sim_proxy.xml b/ci-scripts/xml_files/container_l2sim_proxy.xml index 197baf429b..c2f19f9471 100644 --- a/ci-scripts/xml_files/container_l2sim_proxy.xml +++ b/ci-scripts/xml_files/container_l2sim_proxy.xml @@ -32,9 +32,7 @@ Build_Proxy Build L2sim Proxy Image - 1 - 1 - True + localhost b64d9bce986b38ca59e8582864ade3fcdd05c0dc diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1.xml index a6d39d3f98..10ab1fd3b0 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1.xml @@ -43,7 +43,7 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1.xml Pull_Local_Registry Pull Images from Local Registry - 0 + hutch oai-enb @@ -69,15 +69,13 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1.xml Create_Workspace Create new Workspace for server 0 - 0 - 0 + hutch Deploy_Object Deploy eNB (FDD/Band7/5MHz/B200) in a container + hutch ci-scripts/yaml_files/lte_b200_fdd_05Mhz_tm1 - 0 - 0 @@ -90,9 +88,8 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1.xml Undeploy_Object true Undeploy eNB + hutch ci-scripts/yaml_files/lte_b200_fdd_05Mhz_tm1 - 0 - 0 @@ -212,7 +209,7 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1.xml Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + hutch oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_if4_5.xml b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_if4_5.xml index 3e306844de..ebc59e746d 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_if4_5.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_if4_5.xml @@ -42,7 +42,7 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + hutch oai-enb @@ -68,24 +68,21 @@ Create_Workspace Create new Workspace for server 0 - 0 - 0 + hutch Deploy_Object Deploy RRU (FDD/Band7/5MHz/B200) in a container + hutch ci-scripts/yaml_files/lte_b200_fdd_05Mhz_if4.5 rru_fdd - 0 - 0 Deploy_Object Deploy RCC (FDD/Band7/5MHz) in a container + hutch ci-scripts/yaml_files/lte_b200_fdd_05Mhz_if4.5 rcc_fdd - 0 - 0 @@ -98,9 +95,8 @@ Undeploy_Object true Undeploy RCC/RRU + hutch ci-scripts/yaml_files/lte_b200_fdd_05Mhz_if4.5 - 0 - 0 @@ -195,7 +191,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + hutch oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_no_rrc_activity.xml b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_no_rrc_activity.xml index 9d54eceaeb..8936a3928e 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_no_rrc_activity.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_05Mhz_tm1_no_rrc_activity.xml @@ -42,7 +42,7 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_no_flexran.xm Pull_Local_Registry Pull Images from Local Registry - 0 + hutch oai-enb @@ -61,24 +61,21 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_no_flexran.xm Create_Workspace Create new Workspace for server 0 - 0 - 0 + hutch Deploy_Object Deploy eNB (FDD/Band7/5MHz/B200) in a container + hutch ci-scripts/yaml_files/lte_b200_fdd_05Mhz_tm1_no_rrc_activity - 0 - 0 Undeploy_Object true Undeploy eNB + hutch ci-scripts/yaml_files/lte_b200_fdd_05Mhz_tm1_no_rrc_activity - 0 - 0 @@ -178,7 +175,7 @@ Replaces xml_files/enb_usrp210_band7_test_05mhz_tm1_rrc_inactivity_no_flexran.xm Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + hutch oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1.xml index 2889101ee8..1456418475 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1.xml @@ -44,7 +44,7 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Pull_Local_Registry Pull Images from Local Registry - 0 + hutch oai-enb @@ -63,15 +63,13 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Create_Workspace Create new Workspace for server 0 - 0 - 0 + hutch Deploy_Object Deploy eNB (FDD/Band7/10MHz/B200) in a container + hutch ci-scripts/yaml_files/lte_b200_fdd_10Mhz_tm1 - 0 - 0 @@ -84,9 +82,8 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Undeploy_Object true Undeploy eNB + hutch ci-scripts/yaml_files/lte_b200_fdd_10Mhz_tm1 - 0 - 0 @@ -207,7 +204,7 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + hutch oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_cdrx.xml b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_cdrx.xml index fb18ce090f..aafcdff6ea 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_cdrx.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_cdrx.xml @@ -43,7 +43,7 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Pull_Local_Registry Pull Images from Local Registry - 0 + hutch oai-enb @@ -62,24 +62,21 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Create_Workspace Create new Workspace for server 0 - 0 - 0 + hutch Deploy_Object Deploy eNB (FDD/Band7/10MHz/B200) in a container + hutch ci-scripts/yaml_files/lte_b200_fdd_10Mhz_tm1_cdrx - 0 - 0 Undeploy_Object true Undeploy eNB + hutch ci-scripts/yaml_files/lte_b200_fdd_10Mhz_tm1_cdrx - 0 - 0 @@ -139,7 +136,7 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + hutch oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_oaiue.xml b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_oaiue.xml index 5501ad86fb..f50330ab89 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_oaiue.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_10Mhz_tm1_oaiue.xml @@ -49,13 +49,13 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + hutch oai-enb Pull_Local_Registry Pull Images from Local Registry - 1 + carabe oai-lte-ue @@ -87,28 +87,24 @@ Create_Workspace Create new Workspace for server 0 - 0 - 0 + hutch Deploy_Object Deploy eNB (FDD/Band7/10MHz/B200) in a container ci-scripts/yaml_files/lte_b200_fdd_10Mhz_tm1_magma - 0 - 0 + hutch Create_Workspace Create new Workspace for server 1 - 1 - 1 + carabe Deploy_Object Deploy LTE-UE (FDD/Band7/10MHz/B200) in a container + carabe ci-scripts/yaml_files/lte_b200_fdd_10Mhz_oai_ue_magma - 1 - 1 @@ -127,18 +123,16 @@ Undeploy_Object true Undeploy eNB + hutch ci-scripts/yaml_files/lte_b200_fdd_10Mhz_tm1_magma - 0 - 0 Undeploy_Object true Undeploy LTE-UE + carabe ci-scripts/yaml_files/lte_b200_fdd_10Mhz_oai_ue_magma - 1 - 1 @@ -191,7 +185,7 @@ Clean_Test_Server_Images true Clean Test Images on eNB Test Server - 0 + hutch oai-enb @@ -199,7 +193,7 @@ Clean_Test_Server_Images true Clean Test Images on LTE-UE Test Server - 1 + carabe oai-lte-ue diff --git a/ci-scripts/xml_files/container_lte_b200_fdd_20Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_fdd_20Mhz_tm1.xml index 3a64107484..52dbcb8972 100644 --- a/ci-scripts/xml_files/container_lte_b200_fdd_20Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_fdd_20Mhz_tm1.xml @@ -43,7 +43,7 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Pull_Local_Registry Pull Images from Local Registry - 0 + hutch oai-enb @@ -62,15 +62,13 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Create_Workspace Create new Workspace for server 0 - 0 - 0 + hutch Deploy_Object Deploy eNB (FDD/Band7/20MHz/B200) in a container + hutch ci-scripts/yaml_files/lte_b200_fdd_20Mhz_tm1 - 0 - 0 @@ -83,9 +81,8 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Undeploy_Object true Undeploy eNB + hutch ci-scripts/yaml_files/lte_b200_fdd_20Mhz_tm1 - 0 - 0 @@ -207,7 +204,7 @@ Replaces xml_files/enb_usrp210_band7_test_10mhz_tm1.xml Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + hutch oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1.xml index bb6359d636..f46697a106 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1.xml @@ -43,7 +43,7 @@ Replaces xml_files/enb_usrp210_band40_test_05mhz_tm1.xml Pull_Local_Registry Pull Images from Local Registry - 0 + starsky oai-enb @@ -70,15 +70,13 @@ Replaces xml_files/enb_usrp210_band40_test_05mhz_tm1.xml Create_Workspace Create new Workspace for server 0 - 0 - 0 + starsky Deploy_Object Deploy eNB (TDD/Band40/5MHz/B200) in a container + starsky ci-scripts/yaml_files/lte_b200_tdd_05Mhz_tm1 - 0 - 0 @@ -91,9 +89,8 @@ Replaces xml_files/enb_usrp210_band40_test_05mhz_tm1.xml Undeploy_Object true Undeploy eNB + starsky ci-scripts/yaml_files/lte_b200_tdd_05Mhz_tm1 - 0 - 0 @@ -224,7 +221,7 @@ Replaces xml_files/enb_usrp210_band40_test_05mhz_tm1.xml Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + starsky oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1_if4_5.xml b/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1_if4_5.xml index 0d4d1cae81..da187e2120 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1_if4_5.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_05Mhz_tm1_if4_5.xml @@ -41,7 +41,7 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + starsky oai-enb @@ -68,24 +68,21 @@ Create_Workspace Create new Workspace for server 0 - 0 - 0 + starsky Deploy_Object Deploy RRU (TDD/Band40/5MHz/B200) in a container + starsky ci-scripts/yaml_files/lte_b200_tdd_05Mhz_if4.5 rru_tdd - 0 - 0 Deploy_Object Deploy RCC (TDD/Band40/5MHz) in a container + starsky ci-scripts/yaml_files/lte_b200_tdd_05Mhz_if4.5 rcc_tdd - 0 - 0 @@ -98,9 +95,8 @@ Undeploy_Object true Undeploy RRU/RCC + starsky ci-scripts/yaml_files/lte_b200_tdd_05Mhz_if4.5 - 0 - 0 @@ -210,7 +206,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + starsky oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_10Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_tdd_10Mhz_tm1.xml index e261a3a057..88b3330508 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_10Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_10Mhz_tm1.xml @@ -42,7 +42,7 @@ Replaces xml_files/enb_usrp210_band40_test_10mhz_tm1.xml Pull_Local_Registry Pull Images from Local Registry - 0 + starsky oai-enb @@ -61,15 +61,13 @@ Replaces xml_files/enb_usrp210_band40_test_10mhz_tm1.xml Create_Workspace Create new Workspace for server 0 - 0 - 0 + starsky Deploy_Object Deploy eNB (TDD/Band40/10MHz/B200) in a container + starsky ci-scripts/yaml_files/lte_b200_tdd_10Mhz_tm1 - 0 - 0 @@ -82,9 +80,8 @@ Replaces xml_files/enb_usrp210_band40_test_10mhz_tm1.xml Undeploy_Object true Undeploy eNB + starsky ci-scripts/yaml_files/lte_b200_tdd_10Mhz_tm1 - 0 - 0 @@ -215,7 +212,7 @@ Replaces xml_files/enb_usrp210_band40_test_10mhz_tm1.xml Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + starsky oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1.xml b/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1.xml index dd8ef337b8..65f4dfc6b4 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1.xml @@ -42,7 +42,7 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1.xml Pull_Local_Registry Pull Images from Local Registry - 0 + starsky oai-enb @@ -61,15 +61,13 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1.xml Create_Workspace Create new Workspace for server 0 - 0 - 0 + starsky Deploy_Object Deploy eNB (TDD/Band40/20MHz/B200) in a container + starsky ci-scripts/yaml_files/lte_b200_tdd_20Mhz_tm1 - 0 - 0 @@ -82,9 +80,8 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1.xml Undeploy_Object true Undeploy eNB + starsky ci-scripts/yaml_files/lte_b200_tdd_20Mhz_tm1 - 0 - 0 @@ -213,7 +210,7 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1.xml Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + starsky oai-enb diff --git a/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1_default_scheduler.xml b/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1_default_scheduler.xml index 1719ad2691..6a0cb0f892 100644 --- a/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1_default_scheduler.xml +++ b/ci-scripts/xml_files/container_lte_b200_tdd_20Mhz_tm1_default_scheduler.xml @@ -42,7 +42,7 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1_default_scheduler.xml Pull_Local_Registry Pull Images from Local Registry - 0 + starsky oai-enb @@ -62,15 +62,13 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1_default_scheduler.xml Create_Workspace Create new Workspace for server 0 - 0 - 0 + starsky Deploy_Object Deploy eNB (TDD/Band40/20MHz/B200) in a container + starsky ci-scripts/yaml_files/lte_b200_tdd_20Mhz_tm1_default_scheduler - 0 - 0 @@ -83,9 +81,8 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1_default_scheduler.xml Undeploy_Object true Undeploy eNB + starsky ci-scripts/yaml_files/lte_b200_tdd_20Mhz_tm1_default_scheduler - 0 - 0 @@ -218,7 +215,7 @@ Replaces xml_files/enb_usrp210_band40_test_20mhz_tm1_default_scheduler.xml Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + starsky oai-enb diff --git a/ci-scripts/xml_files/container_lte_n3xx_tdd_2x2_tm1.xml b/ci-scripts/xml_files/container_lte_n3xx_tdd_2x2_tm1.xml index f127601e39..3337bba999 100644 --- a/ci-scripts/xml_files/container_lte_n3xx_tdd_2x2_tm1.xml +++ b/ci-scripts/xml_files/container_lte_n3xx_tdd_2x2_tm1.xml @@ -48,7 +48,7 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + obelix oai-enb @@ -68,15 +68,13 @@ Create_Workspace Create new Workspace - 0 - 0 + obelix Deploy_Object Deploy eNB (TDD/Band38/2.6Ghz/N3XX) in a container + obelix ci-scripts/yaml_files/lte_n3xx_tdd_2x2_tm1 - 0 - 0 @@ -142,9 +140,8 @@ Undeploy_Object true Undeploy gNB + obelix ci-scripts/yaml_files/lte_n3xx_tdd_2x2_tm1 - 0 - 0 - epc-start-tab - EPC-Start - log-in - - 000100 - - - - - - DeployCoreNetwork - Start EPC - ltebox-nepes - - + TEST-AERIAL-SA-CN-START + Deploy 5GC + tasks + + 555000 + + + + DeployCoreNetwork + Initialize 5G Core + oc-cn5g-20897-aerial + + diff --git a/ci-scripts/xml_files/sa_oaiue_cn5g_deploy.xml b/ci-scripts/xml_files/container_sa_aerial_cn_stop.xml similarity index 64% rename from ci-scripts/xml_files/sa_oaiue_cn5g_deploy.xml rename to ci-scripts/xml_files/container_sa_aerial_cn_stop.xml index a49a2cda18..bf0bd9fb9c 100644 --- a/ci-scripts/xml_files/sa_oaiue_cn5g_deploy.xml +++ b/ci-scripts/xml_files/container_sa_aerial_cn_stop.xml @@ -21,18 +21,18 @@ --> - cn5g-start-tab - CN5G-Start - log-in - -000100 - - - - - - DeployCoreNetwork - Initialize 5G Core - oc-cn5g - + TEST-AERIAL-SA-CN-STOP + Undeploy 5GC + tasks + + 000555 + + + + UndeployCoreNetwork + true + Terminate 5G Core + oc-cn5g-20897-aerial + + diff --git a/ci-scripts/xml_files/container_sa_aerial_quectel.xml b/ci-scripts/xml_files/container_sa_aerial_quectel.xml index 8f524550da..05d35d0171 100644 --- a/ci-scripts/xml_files/container_sa_aerial_quectel.xml +++ b/ci-scripts/xml_files/container_sa_aerial_quectel.xml @@ -25,7 +25,6 @@ AERIAL 100 MHz TDD SA tasks - 555000 111111 000222 800813 @@ -35,22 +34,17 @@ 000011 000022 000033 + 200022 + 300033 000222 222222 333333 - 000555 - - DeployCoreNetwork - Initialize 5G Core - oc-cn5g-20897-aerial - - Pull_Local_Registry Pull Images from Local Registry - 0 + gracehopper1-oai oai-gnb-aerial arm_ @@ -58,26 +52,23 @@ Create_Workspace Create new Workspace for server 0 - 0 - 0 + gracehopper1-oai Deploy_Object Deploy PNF/Nvidia CUBB in a container + gracehopper1-oai ci-scripts/yaml_files/sa_gnb_aerial nv-cubb - 0 - 0 Deploy_Object Deploy VNF in a container + gracehopper1-oai ci-scripts/yaml_files/sa_gnb_aerial oai-gnb-aerial - 0 - 0 @@ -115,6 +106,28 @@ 80 + + Iperf + Optional iperf (DL/UDP/1000M)(30 sec)(single-ue profile) + true + -u -b 1000M -t 30 -R + oc-cn5g-20897-aerial + up2-aerial + 25 + 80 + + + + Iperf + Optional iperf (UL/UDP/90M)(30 sec)(single-ue profile) + true + -u -b 90M -t 30 -l 1428 + oc-cn5g-20897-aerial + up2-aerial + 25 + 80 + + Detach_UE true @@ -126,9 +139,8 @@ Undeploy_Object true Undeploy gNB + gracehopper1-oai ci-scripts/yaml_files/sa_gnb_aerial - 0 - 0 20,100,100,100 20,100,100,100 @@ -137,15 +149,8 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + gracehopper1-oai oai-gnb-aerial - - - UndeployCoreNetwork - true - Terminate 5G Core - oc-cn5g-20897-aerial - diff --git a/ci-scripts/xml_files/container_sa_aerial_quectel_ul_heavy.xml b/ci-scripts/xml_files/container_sa_aerial_quectel_ul_heavy.xml new file mode 100644 index 0000000000..ab38b72295 --- /dev/null +++ b/ci-scripts/xml_files/container_sa_aerial_quectel_ul_heavy.xml @@ -0,0 +1,144 @@ + + + TEST-AERIAL-SA-UL-Heavy + AERIAL 100 MHz DSUUU SA + tasks + + 111111 + 000222 + 800813 + 002222 + 002223 + 000111 + 000011 + 000032 + 000033 + 000022 + 000222 + 222222 + 333333 + + + + Pull_Local_Registry + Pull Images from Local Registry + gracehopper1-oai + oai-gnb-aerial + arm_ + + + + Create_Workspace + Create new Workspace for server 0 + gracehopper1-oai + + + + Deploy_Object + Deploy PNF/Nvidia CUBB in a container + gracehopper1-oai + ci-scripts/yaml_files/sa_gnb_aerial_ul + nv-cubb + + + + Deploy_Object + Deploy VNF in a container + gracehopper1-oai + ci-scripts/yaml_files/sa_gnb_aerial_ul + oai-gnb-aerial + + + + Attach_UE + Attach Quectel + up2-aerial + + + + Ping + Ping: 100pings in 20sec + up2-aerial + oc-cn5g-20897-aerial + -c 100 -i 0.2 + 5 + + + + Iperf + iperf (DL/UDP/200M)(30 sec)(single-ue profile) + -u -b 200M -t 30 -R + oc-cn5g-20897-aerial + up2-aerial + 25 + 80 + + + + Iperf + iperf (UL/UDP/200M)(30 sec)(single-ue profile) + -u -b 200M -t 30 -l 1428 + oc-cn5g-20897-aerial + up2-aerial + 10 + 90 + + + + Iperf + iperf (UL/UDP/220M)(30 sec)(single-ue profile) + true + -u -b 220M -t 30 -l 1428 + oc-cn5g-20897-aerial + up2-aerial + 10 + 90 + + + + Detach_UE + true + Detach Quectel + up2-aerial + + + + Undeploy_Object + true + Undeploy gNB + gracehopper1-oai + ci-scripts/yaml_files/sa_gnb_aerial_ul + 20,100,100,100 + 20,100,100,100 + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + gracehopper1-oai + oai-gnb-aerial + + + diff --git a/ci-scripts/xml_files/container_sa_aw2s_asue.xml b/ci-scripts/xml_files/container_sa_aw2s_asue.xml index 7eb6411827..e5d32c181f 100644 --- a/ci-scripts/xml_files/container_sa_aw2s_asue.xml +++ b/ci-scripts/xml_files/container_sa_aw2s_asue.xml @@ -32,20 +32,10 @@ 120000 102000 102001 + 302001 102002 + 302002 102003 - 102004 - 102005 - 102006 - 102007 - 102008 - 102009 - 102010 - 102011 - 102012 - 102013 - 102014 - 102015 100100 100010 100020 @@ -78,111 +68,51 @@ Create_Workspace Creating new Workspace - 0 - 0 + avra Deploy_Object Deploy gNB (TDD/Band78/20MHz/aw2s) in a container + avra ci-scripts/yaml_files/sa_aw2s_gnb - 0 - 0 Attach_UE - Attach UE + Attach UE 1 amarisoft_ue_1 + + Custom_Command + Verify UE 1 is normal (no RedCap) + avra + [ $(docker logs oai-gnb-aw2s | grep -E "UE with RNTI [0-9a-f]{4} is RedCap" | wc -l) -eq 0 ] + + Attach_UE - Attach UE + Attach (RedCap) UE 2 amarisoft_ue_2 + + Custom_Command + Verify UE 2 is RedCap + avra + [ $(docker logs oai-gnb-aw2s | grep -m1 -E "UE with RNTI [0-9a-f]{4} is RedCap" | wc -l) -eq 1 ] + + Attach_UE - Attach UE - amarisoft_ue_3 - - - - Attach_UE - Attach UE - amarisoft_ue_4 - - - - Attach_UE - Attach UE - amarisoft_ue_5 - - - - Attach_UE - Attach UE - amarisoft_ue_6 - - - - Attach_UE - Attach UE - amarisoft_ue_7 - - - - Attach_UE - Attach UE - amarisoft_ue_8 - - - - Attach_UE - Attach UE - amarisoft_ue_9 - - - - Attach_UE - Attach UE - amarisoft_ue_10 - - - - Attach_UE - Attach UE - amarisoft_ue_11 - - - - Attach_UE - Attach UE - amarisoft_ue_12 - - - - Attach_UE - Attach UE - amarisoft_ue_13 - - - - Attach_UE - Attach UE - amarisoft_ue_14 - - - - Attach_UE - Attach UE - amarisoft_ue_15 + Attach UE 3 - 15 + amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 Iperf - iperf (DL/3Mbps/UDP)(30 sec)(multi-ue profile) + iperf (DL/3Mbps/UDP)(30 sec) -u -b 45M -t 30 -R amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 25 @@ -193,7 +123,7 @@ Iperf - iperf (DL/TCP)(30 sec)(multi-ue profile) + iperf (DL/TCP)(30 sec) -t 30 -R amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 2 @@ -202,7 +132,7 @@ Iperf - iperf (UL/1Mbps/UDP)(30 sec)(multi-ue profile) + iperf (UL/1Mbps/UDP)(30 sec) -u -b 15M -t 30 amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 25 @@ -213,7 +143,7 @@ Iperf - iperf (UL/TCP)(30 sec)(multi-ue profile) + iperf (UL/TCP)(30 sec) -t 30 oc-cn5g amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 @@ -233,7 +163,7 @@ Attach_UE - Attach UE + Attach (RedCap) UE 16 amarisoft_ue_16 @@ -271,16 +201,15 @@ Undeploy_Object true Undeploy gNB + avra ci-scripts/yaml_files/sa_aw2s_gnb - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + avra oai-gnb-aw2s diff --git a/ci-scripts/xml_files/container_sa_aw2s_asue_2x2.xml b/ci-scripts/xml_files/container_sa_aw2s_asue_2x2.xml index 739534be21..4a2dd6c420 100644 --- a/ci-scripts/xml_files/container_sa_aw2s_asue_2x2.xml +++ b/ci-scripts/xml_files/container_sa_aw2s_asue_2x2.xml @@ -70,15 +70,13 @@ Create_Workspace Create new Workspace - 0 - 0 + avra Deploy_Object Deploy gNB (TDD/Band78/20MHz/aw2s) in a container + avra ci-scripts/yaml_files/sa_aw2s_2x2_gnb - 0 - 0 @@ -179,7 +177,7 @@ Iperf - iperf (DL/4Mbps/UDP)(30 sec)(multi-ue profile) + iperf (DL/4Mbps/UDP)(30 sec) -u -b 60M -t 30 -R amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 25 @@ -190,7 +188,7 @@ Iperf - iperf (DL/TCP)(30 sec)(multi-ue profile) + iperf (DL/TCP)(30 sec) -t 30 -R amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 3.9 @@ -199,7 +197,7 @@ Iperf - iperf (UL/1.5Mbps/UDP)(30 sec)(multi-ue profile) + iperf (UL/1.5Mbps/UDP)(30 sec) -u -b 22.5M -t 30 amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 25 @@ -210,7 +208,7 @@ Iperf - iperf (UL/TCP)(30 sec)(multi-ue profile) + iperf (UL/TCP)(30 sec) -t 30 oc-cn5g amarisoft_ue_1 amarisoft_ue_2 amarisoft_ue_3 amarisoft_ue_4 amarisoft_ue_5 amarisoft_ue_6 amarisoft_ue_7 amarisoft_ue_8 amarisoft_ue_9 amarisoft_ue_10 amarisoft_ue_11 amarisoft_ue_12 amarisoft_ue_13 amarisoft_ue_14 amarisoft_ue_15 @@ -268,16 +266,15 @@ Undeploy_Object true Undeploy gNB + avra ci-scripts/yaml_files/sa_aw2s_2x2_gnb - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + avra oai-gnb-aw2s diff --git a/ci-scripts/xml_files/container_sa_b200_quectel.xml b/ci-scripts/xml_files/container_sa_b200_quectel.xml index 9f3559aff1..7b42e42b0c 100644 --- a/ci-scripts/xml_files/container_sa_b200_quectel.xml +++ b/ci-scripts/xml_files/container_sa_b200_quectel.xml @@ -59,7 +59,7 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + ofqot oai-gnb @@ -102,15 +102,13 @@ Create_Workspace Create new Workspace for server 0 - 0 - 0 + ofqot Deploy_Object Deploy gNB (TDD/Band78/40MHz/B200) in a container + ofqot ci-scripts/yaml_files/sa_b200_gnb - 0 - 0 @@ -200,23 +198,20 @@ Trigger Reestablishment ofqot echo ci force_reestab | nc -N 127.0.0.1 9090 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' - yes Custom_Command Verify Reestablishment ofqot echo ci get_reestab_count | nc -N 127.0.0.1 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' - yes Undeploy_Object true Undeploy gNB + ofqot ci-scripts/yaml_files/sa_b200_gnb - 0 - 0 10,100,100,100 10,100,100,100 @@ -225,7 +220,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + ofqot oai-gnb diff --git a/ci-scripts/xml_files/container_sa_e1_b200_quectel.xml b/ci-scripts/xml_files/container_sa_e1_b200_quectel.xml index dcbcb9a45f..89a5ebfd6c 100644 --- a/ci-scripts/xml_files/container_sa_e1_b200_quectel.xml +++ b/ci-scripts/xml_files/container_sa_e1_b200_quectel.xml @@ -30,11 +30,10 @@ 310000 800813 330101 - 800814 330102 - 800815 330103 310001 + 400001 350000 370001 370000 @@ -56,7 +55,7 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + ofqot oai-gnb oai-nr-cuup @@ -85,31 +84,27 @@ Create_Workspace Create new Workspace - 0 - 0 + ofqot Deploy_Object Deploy gNB-CU-CP in a container + ofqot ci-scripts/yaml_files/sa_e1_b200_gnb - 0 - 0 gnb_cucp Deploy_Object Deploy gNB-CU-UP in a container + ofqot ci-scripts/yaml_files/sa_e1_b200_gnb - 0 - 0 gnb_cuup Deploy_Object Deploy gNB-DU (TDD/Band78/40MHz/B200) in a container + ofqot ci-scripts/yaml_files/sa_e1_b200_gnb - 0 - 0 gnb_du_tdd @@ -147,6 +142,13 @@ 95 + + Custom_Command + Check UE is on dedicated BWP ID 1 + ofqot + echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 1 (dedicated) UL BWP ID 1 (dedicated)' + + Iperf iperf (UL/8Mbps/UDP)(30 sec) @@ -188,14 +190,12 @@ Trigger Reestablishment (on DU) ofqot echo ci force_reestab | nc -N 127.0.0.1 9091 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' - yes Custom_Command Verify Reestablishment (on CU) ofqot echo ci get_reestab_count | nc -N 127.0.0.1 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' - yes @@ -211,9 +211,8 @@ Undeploy_Object true Undeploy CUCP/CU-UP/DU + ofqot ci-scripts/yaml_files/sa_e1_b200_gnb - 0 - 0 10,100,100,100 10,100,100,100 @@ -222,7 +221,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + ofqot oai-gnb oai-nr-cuup diff --git a/ci-scripts/xml_files/container_sa_f1_b200_quectel.xml b/ci-scripts/xml_files/container_sa_f1_b200_quectel.xml index 9622b2cf13..3ae295597f 100644 --- a/ci-scripts/xml_files/container_sa_f1_b200_quectel.xml +++ b/ci-scripts/xml_files/container_sa_f1_b200_quectel.xml @@ -64,7 +64,7 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + ofqot oai-gnb @@ -93,23 +93,20 @@ Create_Workspace Create new Workspace - 0 - 0 + ofqot Deploy_Object Deploy gNB-CU in a container + ofqot ci-scripts/yaml_files/sa_f1_b200_gnb - 0 - 0 gnb_cu Deploy_Object Deploy gNB-DU (FDD/Band1/10MHz/B200) in a container + ofqot ci-scripts/yaml_files/sa_f1_b200_gnb - 0 - 0 gnb_du_fdd @@ -233,23 +230,20 @@ Trigger Reestablishment (on DU) ofqot echo ci force_reestab | nc -N 127.0.0.1 9091 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' - yes Custom_Command Verify Reestablishment (on CU) ofqot echo ci get_reestab_count | nc -N 127.0.0.1 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' - yes Undeploy_Object true Undeploy CU-DU + ofqot ci-scripts/yaml_files/sa_f1_b200_gnb - 0 - 0 10,100,100,100 10,100,100,100 @@ -258,7 +252,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + ofqot oai-gnb diff --git a/ci-scripts/xml_files/container_sa_f1_ho_b210_quectel.xml b/ci-scripts/xml_files/container_sa_f1_ho_b210_quectel.xml new file mode 100644 index 0000000000..77b2312409 --- /dev/null +++ b/ci-scripts/xml_files/container_sa_f1_ho_b210_quectel.xml @@ -0,0 +1,268 @@ + + + TEST-F1-HO-B210 + F1 Handover 20 MHz TDD SA + tasks + + 000001 + 000002 + 000003 + 000004 + 000005 + 000006 + 000007 + 000008 + 000009 + 000010 + 000011 + 000012 + 000013 + 000014 + 000015 + 000016 + 000017 + 000018 + 000019 + 000020 + 000021 + 000022 + 000023 + 000024 + 000025 + 000026 + 000027 + 000028 + + + + + + DeployCoreNetwork + Initialize 5G Core + oc-cn5g-00103-ho + + + + Pull_Local_Registry + Pull Images from Local Registry + oai-gnb + groot + + + + Pull_Local_Registry + Pull Images from Local Registry + oai-gnb + rocket + + + + Create_Workspace + Create new Workspace for groot + groot + + + + Create_Workspace + Create new Workspace on rocket + rocket + + + + Custom_Command + Set attenuator to 0 for DU0 and 17 for DU1 + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -r 1,2 0 -r 3,4 17 -d 5 + + + + Deploy_Object + Deploy gNB-CU in a container + ci-scripts/yaml_files/5g_sa_f1_b210_ho + groot + oai-cu + + + + Deploy_Object + Deploy gNB-DU0 (TDD/Band77/20MHz/B210) in a container + ci-scripts/yaml_files/5g_sa_f1_b210_ho + oai-du0 + groot + + + + Deploy_Object + Deploy gNB-DU1 (TDD/Band77/20MHz/B210) in a container + ci-scripts/yaml_files/5g_sa_f1_b210_ho + rocket + oai-du1 + + + + Attach_UE + Attach Quectel + raspix + + + + Ping + Ping: 100pings in 20sec + raspix + oc-cn5g-00103-ho + -c 100 -i 0.2 + 5 + + + + IdleSleep + Sleep + 5 + + + + Custom_Command + Attenuate DU0 by 15 and remove the attenuation on DU1 to trigger Handover + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -r 1,2 15 -r 3,4 0 -d 5 + + + + Ping + Ping: 50pings in 10sec + raspix + oc-cn5g-00103-ho + -c 50 -i 0.2 + 5 + + + + Custom_Command + UE connected to DU1? + groot + echo ci fetch_du_by_ue_id 1 | ncat 127.0.0.1 9090 | grep "3585" + + + + Custom_Command + Attenuate DU1 by 17dB and remove attenuation on DU0 to trigger Handover + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -r 1,2 0 -r 3,4 17 -d 5 + + + + Ping + Ping: 50pings in 10sec + raspix + oc-cn5g-00103-ho + -c 50 -i 0.2 + 5 + + + + Custom_Command + UE connected to DU0? + groot + echo ci fetch_du_by_ue_id 1 | ncat 127.0.0.1 9090 | grep "3584" + + + + Custom_Command + Attenuate DU0 by 15 and remove the attenuation on DU1 to trigger Handover + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -r 1,2 15 -r 3,4 0 -d 5 + + + + Ping + Ping: 50pings in 10sec + raspix + oc-cn5g-00103-ho + -c 50 -i 0.2 + 5 + + + + Custom_Command + UE connected to DU1? + groot + echo ci fetch_du_by_ue_id 1 | ncat 127.0.0.1 9090 | grep "3585" + + + + Detach_UE + true + Detach Quectel + raspix + + + + Undeploy_Object + true + Undeploy CU-DU0 + groot + ci-scripts/yaml_files/5g_sa_f1_b210_ho + + + + Undeploy_Object + true + Undeploy DU1 + rocket + ci-scripts/yaml_files/5g_sa_f1_b210_ho + + + + Custom_Command + Reset all channels on the attenuator to 0 + rocket + python3 %%workspace%%/ci-scripts/attenuatorctl.py -s 1-4 0 + true + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + groot + oai-gnb + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + rocket + oai-gnb + + + + UndeployCoreNetwork + true + Terminate 5G Core + oc-cn5g-00103-ho + + + + diff --git a/ci-scripts/xml_files/container_sa_fhi72_metanoia_up2_2x2.xml b/ci-scripts/xml_files/container_sa_fhi72_metanoia_up2_2x2.xml index e71ec3e37c..979aabbc5e 100644 --- a/ci-scripts/xml_files/container_sa_fhi72_metanoia_up2_2x2.xml +++ b/ci-scripts/xml_files/container_sa_fhi72_metanoia_up2_2x2.xml @@ -49,29 +49,26 @@ Setup sriov and network interfaces Metanoia cacofonix - yes Pull_Local_Registry Pull Images from Local Registry - 0 + cacofonix oai-gnb-fhi72 Create_Workspace Create new Workspace for server 0 - 0 - 0 + cacofonix Deploy_Object Deploy gNB (TDD/Band78/100MHz/Metanoia) in a container + cacofonix ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb - 0 - 0 @@ -92,7 +89,7 @@ Iperf - iperf (DL/570Mbps/UDP)(30 sec)(multi-ue profile) + iperf (DL/570Mbps/UDP)(30 sec) -u -b 570M -t 30 -R up2-fhi72 20 @@ -103,7 +100,7 @@ Iperf - iperf (DL/TCP)(30 sec)(multi-ue profile) + iperf (DL/TCP)(30 sec) -t 30 -R up2-fhi72 80 @@ -112,7 +109,7 @@ Iperf - iperf (UL/100Mbps/UDP)(30 sec)(multi-ue profile) + iperf (UL/100Mbps/UDP)(30 sec) -u -b 100M -t 30 up2-fhi72 20 @@ -123,7 +120,7 @@ Iperf - iperf (UL/TCP)(30 sec)(multi-ue profile) + iperf (UL/TCP)(30 sec) -t 30 up2-fhi72 80 @@ -147,16 +144,15 @@ Undeploy_Object true Undeploy gNB + cacofonix ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + cacofonix oai-gnb-fhi72 @@ -166,7 +162,6 @@ Set CPU to idle state, set kernel parameters to default values cacofonix - yes diff --git a/ci-scripts/xml_files/container_sa_fhi72_vvdn_up2.xml b/ci-scripts/xml_files/container_sa_fhi72_vvdn_up2.xml index 4afe8f1b12..b8df43ef52 100644 --- a/ci-scripts/xml_files/container_sa_fhi72_vvdn_up2.xml +++ b/ci-scripts/xml_files/container_sa_fhi72_vvdn_up2.xml @@ -36,6 +36,7 @@ 100020 100030 100040 + 100011 103000 100002 130000 @@ -49,27 +50,24 @@ Setup sriov and network interfaces VVDN cacofonix - yes Pull_Local_Registry Pull Images from Local Registry - 0 + cacofonix oai-gnb-fhi72 Create_Workspace Create new Workspace for server 0 - 0 - 0 + cacofonix Deploy_Object Deploy gNB (TDD/Band78/100MHz/VVDN) in a container + cacofonix ci-scripts/yaml_files/sa_fhi_7.2_vvdn_gnb - 0 - 0 @@ -90,7 +88,7 @@ Iperf - iperf (DL/600Mbps/UDP)(30 sec)(multi-ue profile) + iperf (DL/600Mbps/UDP)(30 sec) -u -b 600M -t 30 -R up2-fhi72 20 @@ -99,9 +97,20 @@ oc-cn5g-20897 + + Iperf + Optional iperf (DL/700Mbps/UDP)(30 sec) + true + -u -b 700M -t 30 -R + up2-fhi72 + 10 + 95 + oc-cn5g-20897 + + Iperf - iperf (DL/TCP)(30 sec)(multi-ue profile) + iperf (DL/TCP)(30 sec) -t 30 -R up2-fhi72 40 @@ -110,7 +119,7 @@ Iperf - iperf (UL/80Mbps/UDP)(30 sec)(multi-ue profile) + iperf (UL/80Mbps/UDP)(30 sec) -u -b 80M -t 30 up2-fhi72 20 @@ -121,7 +130,7 @@ Iperf - iperf (UL/TCP)(30 sec)(multi-ue profile) + iperf (UL/TCP)(30 sec) -t 30 up2-fhi72 10 @@ -145,16 +154,15 @@ Undeploy_Object true Undeploy gNB + cacofonix ci-scripts/yaml_files/sa_fhi_7.2_vvdn_gnb - 0 - 0 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + cacofonix oai-gnb-fhi72 @@ -164,7 +172,6 @@ Set CPU to idle state, set kernel parameters to default values cacofonix - yes diff --git a/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml index 94e97176ff..a4d72398e1 100644 --- a/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_2X2_100MHz_quectel.xml @@ -80,15 +80,13 @@ Create_Workspace Create new Workspace - 0 - 0 + matix Deploy_Object Deploy gNB (TDD/Band77/100MHz/N310) in a container + matix ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz - 0 - 0 3 @@ -146,9 +144,8 @@ Undeploy_Object true Undeploy gNB + matix ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz - 0 - 0 oai-gnb 10,100,100,100 10,100,100,100 @@ -158,7 +155,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + matix oai-gnb diff --git a/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml index a701fc5ab9..ab7188c023 100644 --- a/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_2X2_60MHz_quectel.xml @@ -22,7 +22,7 @@ --> TEST-SA-FR1-N310-2x2-60MHz - 60 MHz 2x2 TDD SA + 60 MHz 2x2 TDD SA DSUUU tasks 100000 @@ -80,15 +80,13 @@ Create_Workspace Create new Workspace - 0 - 0 + matix Deploy_Object Deploy gNB (TDD/Band77/60MHz/N310) in a container + matix ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz - 0 - 0 3 @@ -116,8 +114,8 @@ Iperf - iperf (DL/200Mbps/UDP)(30 sec)(single-ue profile) - -u -b 200M -t 30 -R + iperf (DL/150Mbps/UDP)(30 sec)(single-ue profile) + -u -b 150M -t 30 -R matix-cn5g up2 25 @@ -126,8 +124,8 @@ Iperf - iperf (UL/180Mbps/UDP)(30 sec)(single-ue profile) - -u -b 180M -t 30 + iperf (UL/250Mbps/UDP)(30 sec)(single-ue profile) + -u -b 250M -t 30 matix-cn5g up2 10 @@ -146,19 +144,18 @@ Undeploy_Object true Undeploy gNB + matix ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz - 0 - 0 oai-gnb - 10,100,100,100 - 10,100,100,100 + 15,100,100,100 + 20,100,100,100 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + matix oai-gnb diff --git a/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml b/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml index 75087fb4a0..d7cf992aa4 100644 --- a/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml +++ b/ci-scripts/xml_files/container_sa_n310_4X4_60MHz_quectel.xml @@ -80,15 +80,13 @@ Create_Workspace Create new Workspace - 0 - 0 + matix Deploy_Object Deploy VNF-PNF (TDD/Band77/60MHz/N310) in a container + matix ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz - 0 - 0 3 @@ -146,9 +144,8 @@ Undeploy_Object true Undeploy VNF-PNF + matix ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz - 0 - 0 oai-vnf oai-pnf 10,100,100,100 10,100,100,100 @@ -158,7 +155,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + matix oai-gnb diff --git a/ci-scripts/xml_files/container_sa_n310_nrue.xml b/ci-scripts/xml_files/container_sa_n310_nrue.xml index 7d093be3d7..63088afc1c 100644 --- a/ci-scripts/xml_files/container_sa_n310_nrue.xml +++ b/ci-scripts/xml_files/container_sa_n310_nrue.xml @@ -25,6 +25,7 @@ 40 MHz TDD SA tasks + 060000 010000 010001 800813 020000 @@ -38,9 +39,16 @@ 040001 040000 333333 444444 + 060001 + + DeployCoreNetwork + Initialize 5G Core + oc-cn5g + + Pull_Cluster_Image Pull Images from Cluster @@ -71,29 +79,25 @@ Create_Workspace Create new Workspace - 0 - 0 + avra Deploy_Object Deploy gNB (TDD/Band78/40MHz/N310) in a container + avra ci-scripts/yaml_files/5g_sa_n310_gnb - 0 - 0 3 Create_Workspace Create new Workspace - 1 - 1 + caracal Deploy_Object Deploy nrUE (TDD/Band78/40MHz/N310) in a container ci-scripts/yaml_files/5g_sa_n310_nrue - 1 - 1 + caracal 3 @@ -105,8 +109,8 @@ Iperf - iperf (DL/20Mbps/UDP)(30 sec)(single-ue profile) - -u -b 20M -t 30 -i 1 -R + iperf (DL/60Mbps/UDP)(30 sec) + -u -b 60M -t 30 -i 1 -R oai_ue_caracal oc-cn5g 25 @@ -115,8 +119,8 @@ Iperf - iperf (UL/5Mbps/UDP)(30 sec)(single-ue profile) - -u -b 5M -t 30 -i 1 + iperf (UL/20Mbps/UDP)(30 sec) + -u -b 20M -t 30 -i 1 oai_ue_caracal oc-cn5g 25 @@ -147,9 +151,8 @@ Undeploy_Object true Undeploy gNB + avra ci-scripts/yaml_files/5g_sa_n310_gnb - 0 - 0 20,100,100,100 20,100,100,100 @@ -158,16 +161,15 @@ Undeploy_Object true Undeploy nr UE + caracal ci-scripts/yaml_files/5g_sa_n310_nrue - 1 - 1 Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + avra oai-gnb @@ -175,8 +177,15 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 1 + caracal oai-nr-ue + + UndeployCoreNetwork + Terminate 5G Core + true + oc-cn5g + + diff --git a/ci-scripts/xml_files/container_sa_n310_nrue_longrun.xml b/ci-scripts/xml_files/container_sa_n310_nrue_longrun.xml new file mode 100644 index 0000000000..f0d8f4f3b6 --- /dev/null +++ b/ci-scripts/xml_files/container_sa_n310_nrue_longrun.xml @@ -0,0 +1,179 @@ + + + LONGRUN-5G-NRUE + Longrun 40 MHz TDD SA + tasks + + 060000 + 010000 010001 + 800813 + 020000 + 800814 + 020001 + 000001 + 001000 + 000100 + 001000 + 000100 + 001000 + 000100 + 001000 + 000200 + 001000 + 000200 + 001000 + 000200 + 040001 040000 + 333333 + 444444 + 060001 + + + + + DeployCoreNetwork + Initialize 5G Core + oc-cn5g + + + + Pull_Cluster_Image + Pull Images from Cluster + oai-gnb + avra + + + + Pull_Cluster_Image + Pull Images from Cluster + oai-nr-ue + caracal + + + + Create_Workspace + Create new Workspace + avra + + + + Deploy_Object + Deploy gNB (TDD/Band78/40MHz/N310) in a container + avra + ci-scripts/yaml_files/5g_sa_n310_gnb + 3 + + + + Create_Workspace + Create new Workspace + caracal + + + + Deploy_Object + Deploy nrUE (TDD/Band78/40MHz/N310) in a container + ci-scripts/yaml_files/5g_sa_n310_nrue + caracal + 3 + + + + Attach_UE + Attach OAIUE + oai_ue_caracal + + + + Iperf + iperf (DL/10Mbps/UDP)(10 min) + -u -b 10M -t 600 -i 1 -R + oai_ue_caracal + oc-cn5g + 25 + 80 + + + + Iperf + iperf (UL/2Mbps/UDP)(10 min) + -u -b 2M -t 600 -i 1 + oai_ue_caracal + oc-cn5g + 25 + 80 + + + + Ping + Ping: 20pings in 20sec + oai_ue_caracal + oc-cn5g + -c 20 + 1 + 25 + + + + Undeploy_Object + true + Undeploy gNB + avra + ci-scripts/yaml_files/5g_sa_n310_gnb + 20,100,100,100 + 20,100,100,100 + + + + Undeploy_Object + true + Undeploy nr UE + caracal + ci-scripts/yaml_files/5g_sa_n310_nrue + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + avra + oai-gnb + + + + Clean_Test_Server_Images + true + Clean Test Images on Test Server + caracal + oai-nr-ue + + + + UndeployCoreNetwork + Terminate 5G Core + true + oc-cn5g + + + diff --git a/ci-scripts/xml_files/container_sa_sc_b200_quectel.xml b/ci-scripts/xml_files/container_sa_sc_b200_quectel.xml index 69201ebcc8..d687120eb9 100644 --- a/ci-scripts/xml_files/container_sa_sc_b200_quectel.xml +++ b/ci-scripts/xml_files/container_sa_sc_b200_quectel.xml @@ -53,7 +53,7 @@ Pull_Local_Registry Pull Images from Local Registry - 0 + ofqot oai-gnb @@ -96,15 +96,13 @@ Create_Workspace Create new Workspace - 0 - 0 + ofqot Deploy_Object Deploy gNB (TDD/pattern2/Band78/40MHz/B200) with SC-FDMA in a container + ofqot ci-scripts/yaml_files/sa_sc_b200_gnb - 0 - 0 @@ -194,23 +192,20 @@ Trigger Reestablishment ofqot echo ci force_reestab | nc -N 127.0.0.1 9090 | grep -E 'Reset RLC counters of UE RNTI [0-9a-f]{4} to trigger reestablishment' - yes Custom_Command Verify Reestablishment ofqot echo ci get_reestab_count | nc -N 127.0.0.1 9090 | grep -E 'UE RNTI [0-9a-f]{4} reestab 1' - yes Undeploy_Object true Undeploy gNB + ofqot ci-scripts/yaml_files/sa_sc_b200_gnb - 0 - 0 10,100,100,100 10,100,100,100 @@ -219,7 +214,7 @@ Clean_Test_Server_Images true Clean Test Images on Test Server - 0 + ofqot oai-gnb diff --git a/ci-scripts/xml_files/cppcheck.xml b/ci-scripts/xml_files/cppcheck.xml index 18d8760b0d..daab4e01c2 100644 --- a/ci-scripts/xml_files/cppcheck.xml +++ b/ci-scripts/xml_files/cppcheck.xml @@ -32,10 +32,12 @@ Create_Workspace Create new Workspace + carabe Cppcheck_Analysis Static Code Analysis with cppcheck + carabe diff --git a/ci-scripts/xml_files/formatting_check.xml b/ci-scripts/xml_files/formatting_check.xml index bdf47af65d..e54ee1973e 100644 --- a/ci-scripts/xml_files/formatting_check.xml +++ b/ci-scripts/xml_files/formatting_check.xml @@ -32,6 +32,7 @@ LicenceAndFormattingCheck License and Formatting Checks + obelix diff --git a/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml b/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml new file mode 100644 index 0000000000..3d2efb5084 --- /dev/null +++ b/ci-scripts/xml_files/gnb_phytest_rfemulator_run_100_2x2.xml @@ -0,0 +1,70 @@ + + + gNB-PHY-Test-100-2x2-RFemu + Timing phytest 100 MHz 2x2 RFemulator + tasks + +100000 390101 000001 390109 200000 + + + + Custom_Command + Disable Sleep States + caracal + sudo cpupower idle-set -D 0 + + + Custom_Command + true + Enable Sleep States + caracal + sudo cpupower idle-set -E + + + + Initialize_eNB + Initialize gNB USRP + caracal + -O ci-scripts/conf_files/gnb.band79.273prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 273 -t 23 -D 127 -m 23 -M 273 -l 2 --device.name rf_emulator --rf_emulator.noise_level_dBFS -36 --log_config.global_log_options level,nocolor,time + datalog_rt_stats.100.2x2.yaml + NR + numactl --cpunodebind=netdev:enp94s0f0np0 --membind=netdev:enp94s0f0np0 + + + + IdleSleep + Sleep + 60 + + + + + Terminate_eNB + caracal + true + Terminate gNB + NR + + + diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run.xml index 7a66ea6c34..5adeb17966 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run.xml @@ -45,7 +45,8 @@ Initialize_eNB Initialize gNB USRP - -O ci-scripts/conf_files/gnb.band78.106prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 106 -t 23 -D 127 -m 28 -M 106 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time + caracal + -O ci-scripts/conf_files/gnb.band79.106prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 106 -t 23 -D 127 -m 28 -M 106 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time datalog_rt_stats.default.yaml NR 192.168.20.2 @@ -63,6 +64,7 @@ Terminate_eNB true Terminate gNB + caracal NR diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run_100_2x2.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run_100_2x2.xml index 2f94fa986d..7821be863c 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run_100_2x2.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run_100_2x2.xml @@ -45,7 +45,8 @@ Initialize_eNB Initialize gNB USRP - -O ci-scripts/conf_files/gnb.band78.273prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 273 -t 23 -D 127 -m 23 -M 273 -l 2 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time + caracal + -O ci-scripts/conf_files/gnb.band79.273prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 273 -t 23 -D 127 -m 23 -M 273 -l 2 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time datalog_rt_stats.100.2x2.yaml NR 192.168.20.2 @@ -63,6 +64,7 @@ Terminate_eNB true Terminate gNB + caracal NR diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run_60.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run_60.xml index 77e47c66b4..72e4b5244e 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run_60.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run_60.xml @@ -45,7 +45,8 @@ Initialize_eNB Initialize gNB USRP - -O ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 162 -t 23 -D 127 -m 23 -M 162 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time + caracal + -O ci-scripts/conf_files/gnb.band79.162prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 162 -t 23 -D 127 -m 23 -M 162 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time datalog_rt_stats.1x1.60.yaml NR 192.168.20.2 @@ -63,6 +64,7 @@ Terminate_eNB true Terminate gNB + caracal NR diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run_60_2x2.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run_60_2x2.xml index 67e2316ea3..1be4a24477 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run_60_2x2.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run_60_2x2.xml @@ -45,7 +45,8 @@ Initialize_eNB Initialize gNB USRP - -O ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf --phy-test --gNBs.[0].pdsch_AntennaPorts_XP 2 --RUs.[0].nb_tx 2 --RUs.[0].nb_rx 2 -q -U 768 -T 162 -t 23 -D 127 -m 23 -M 162 -l 2 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time + caracal + -O ci-scripts/conf_files/gnb.band79.162prb.usrpn300.phytest-dora.conf --phy-test --gNBs.[0].pdsch_AntennaPorts_XP 2 --RUs.[0].nb_tx 2 --RUs.[0].nb_rx 2 -q -U 768 -T 162 -t 23 -D 127 -m 23 -M 162 -l 2 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time datalog_rt_stats.60.2x2.yaml NR 192.168.20.2 @@ -63,6 +64,7 @@ Terminate_eNB true Terminate gNB + caracal NR diff --git a/ci-scripts/xml_files/gnb_usrp_build.xml b/ci-scripts/xml_files/gnb_usrp_build.xml index f67098116b..32043985f5 100644 --- a/ci-scripts/xml_files/gnb_usrp_build.xml +++ b/ci-scripts/xml_files/gnb_usrp_build.xml @@ -34,19 +34,21 @@ Create_Workspace Create new Workspace + caracal TesteNB Build_eNB Build gNB (USRP) - --gNB -w USRP --ninja -c -P --build-lib ldpc_cuda --build-lib ldpc_t2 --cmake-opt -DASN1C_EXEC=/opt/asn1c/bin/asn1c - True + caracal + --gNB -w USRP --ninja -c -P --build-lib ldpc_cuda --build-lib ldpc_aal --cmake-opt -DASN1C_EXEC=/opt/asn1c/bin/asn1c --cmake-opt -DPHYSIM_CHECK_FILES="ThresholdsOffload.cmake" Custom_Command Reboot USRP + true caracal ssh root@192.168.20.2 reboot diff --git a/ci-scripts/xml_files/ldpc_gpu_test.xml b/ci-scripts/xml_files/ldpc_gpu_test.xml deleted file mode 100644 index bee9035c8b..0000000000 --- a/ci-scripts/xml_files/ldpc_gpu_test.xml +++ /dev/null @@ -1,356 +0,0 @@ - - - test-ldpc-gpu - Test-ldpc-GPU - tasks - - 000002 000003 000004 000005 000006 000007 000008 000009 000010 000011 000012 000013 000014 000015 000016 000017 000018 000019 000020 000021 - 000022 000023 000024 000025 000026 000027 000028 000029 000030 000031 000032 000033 000034 000035 000036 000037 000038 000039 000040 000041 - - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 3872 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 3872 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 4224 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 4224 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 4576 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 4576 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 4928 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 4928 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 5280 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 5280 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 5632 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 5632 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 6336 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 6336 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 7040 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 7040 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 7744 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 7744 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 8448 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 8448 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 1 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 1 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 100 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 100 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 193 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 193 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 500 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 500 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 561 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 561 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 600 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 600 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 641 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 641 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 2000 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 2000 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 3000 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 3000 -s10 -n100 -G 1 - - - - Run_Physim - Run LDPC Test with CPU - true - ldpctest - -l 3840 -s10 -n100 - - - - Run_Physim - Run LDPC Test with GPU - true - ldpctest - -l 3840 -s10 -n100 -G 1 - - - - - diff --git a/ci-scripts/xml_files/nsa_epc_closure.xml b/ci-scripts/xml_files/nsa_epc_closure.xml deleted file mode 100644 index 23181ec674..0000000000 --- a/ci-scripts/xml_files/nsa_epc_closure.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - epc-closure - EPC-Closure - log-out - -060000 - - - - - UndeployCoreNetwork - Terminate EPC - ltebox-nepes - - - diff --git a/ci-scripts/xml_files/physim_4g_deploy_run.xml b/ci-scripts/xml_files/physim_4g_deploy_run.xml index f8fb8781d5..cd34037760 100644 --- a/ci-scripts/xml_files/physim_4g_deploy_run.xml +++ b/ci-scripts/xml_files/physim_4g_deploy_run.xml @@ -33,15 +33,14 @@ Create_Workspace Create new Workspace - 0 - 0 + avra - Deploy_Run_PhySim + Deploy_Run_OC_PhySim Deploy and run physical simulator on openshift physims-4g - avra + avra diff --git a/ci-scripts/xml_files/physim_5g_deploy_run.xml b/ci-scripts/xml_files/physim_5g_deploy_run.xml index bd8bb0a121..1967003124 100644 --- a/ci-scripts/xml_files/physim_5g_deploy_run.xml +++ b/ci-scripts/xml_files/physim_5g_deploy_run.xml @@ -33,15 +33,14 @@ Create_Workspace Create new Workspace - 0 - 0 + avra - Deploy_Run_PhySim + Deploy_Run_OC_PhySim Deploy and run physical simulator on openshift physims-5g - avra + avra diff --git a/ci-scripts/xml_files/container_4g_l2sim_proxy.xml b/ci-scripts/xml_files/physim_gracehopper.xml similarity index 65% rename from ci-scripts/xml_files/container_4g_l2sim_proxy.xml rename to ci-scripts/xml_files/physim_gracehopper.xml index cd57a24b6a..f04ae2541f 100644 --- a/ci-scripts/xml_files/container_4g_l2sim_proxy.xml +++ b/ci-scripts/xml_files/physim_gracehopper.xml @@ -21,27 +21,26 @@ --> - l2sim-4glte-proxy-build - Build L2sim proxy image + physim-tab + PhySim wrench - 100001 - 000001 + 800813 + 010201 - + + Create_Workspace Create new Workspace - 1 - 1 - - - Build_Proxy - Build L2sim Proxy Image - 1 - 1 - True - b64d9bce986b38ca59e8582864ade3fcdd05c0dc + localhost + + Build_Deploy_Docker_PhySim + Build and Deploy PhySim + localhost + -R 5g -E "nr_dlsim|nr_ulsim|ldpctest" -j32 + + diff --git a/ci-scripts/xml_files/sa_cn5g_asue_start.xml b/ci-scripts/xml_files/physim_timed_gracehopper.xml similarity index 55% rename from ci-scripts/xml_files/sa_cn5g_asue_start.xml rename to ci-scripts/xml_files/physim_timed_gracehopper.xml index a9d3a88d5d..7658279088 100644 --- a/ci-scripts/xml_files/sa_cn5g_asue_start.xml +++ b/ci-scripts/xml_files/physim_timed_gracehopper.xml @@ -21,27 +21,26 @@ --> - cn5g-start-tab - CN5G-Start - log-in - -100000 -000100 - - - + physim-timed-tab + PhySim with timing check + wrench + + 800813 + 010202 + + - - Initialize_5GCN - Initialize 5G Core - --type start-mini-as-ue --scenario 1 --capture /tmp/oai-cn5g-v1.5.pcap - + + Create_Workspace + Create new Workspace + localhost + - - Custom_Command - Reboot USRP - asterix - ssh root@172.21.19.14 reboot ; sleep 45 + + Build_Deploy_Docker_PhySim + Build and Deploy PhySim with timing check + localhost + -R 5g -R "nr_dlsim|nr_ulsim|ldpctest" -E physim.5g.nr_dlsim.mcs.mimo.test9 -j1 diff --git a/ci-scripts/xml_files/sa_oaiue_cn5g_undeploy.xml b/ci-scripts/xml_files/sa_oaiue_cn5g_undeploy.xml deleted file mode 100644 index beb490dbed..0000000000 --- a/ci-scripts/xml_files/sa_oaiue_cn5g_undeploy.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - cn5g-closure - CN5G-Closure - log-out - -060000 - - - - - UndeployCoreNetwork - Terminate 5G Core - oc-cn5g - - - diff --git a/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml b/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml deleted file mode 100644 index c959d99e1b..0000000000 --- a/ci-scripts/xml_files/t2_offload_dec_nr_ulsim.xml +++ /dev/null @@ -1,212 +0,0 @@ - - - - test-t2-offload-dec - Test T2 Offload Decoder - tasks - - 010204 - 010111 010112 010121 010122 010131 010132 - 010211 010212 010221 010222 010231 010232 - 010311 010312 010321 010322 010331 010332 - 402010 - - - - - Custom_Command - Disable Sleep States - caracal - sudo cpupower idle-set -D 0 - - - - Custom_Command - true - Enable Sleep States - caracal - sudo cpupower idle-set -E - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer - true - nr_ulsim - 300 - -n1000 -s30 -S30.2 -m5 -r106 -R106 -C10 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 106 PRBs, 1 layer - true - nr_ulsim - 100 - -n1000 -s30 -S30.2 -m5 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer - true - nr_ulsim - 300 - -n1000 -s30 -S30.2 -m15 -r106 -R106 -C10 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 106 PRBs, 1 layer - true - nr_ulsim - 150 - -n1000 -s30 -S30.2 -m15 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer - true - nr_ulsim - 250 - -n1000 -s30 -S30.2 -m25 -r106 -R106 -C10 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 106 PRBs, 1 layer - true - nr_ulsim - 250 - -n1000 -s30 -S30.2 -m25 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 1 layer - true - nr_ulsim - 300 - -n1000 -s30 -S30.2 -m5 -r273 -R273 -C10 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 1 layer - true - nr_ulsim - 150 - -n1000 -s30 -S30.2 -m5 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer - true - nr_ulsim - 400 - -n1000 -s30 -S30.2 -m15 -r273 -R273 -C10 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 1 layer - true - nr_ulsim - 350 - -n1000 -s30 -S30.2 -m15 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer - true - nr_ulsim - 400 - -n1000 -s30 -S30.2 -m25 -r273 -R273 -C10 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 1 layer - true - nr_ulsim - 550 - -n1000 -s30 -S30.2 -m25 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers - true - nr_ulsim - 300 - -n1000 -s30 -S30.2 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers - true - nr_ulsim - 250 - -n1000 -s30 -S30.2 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers - true - nr_ulsim - 600 - -n1000 -s30 -S30.2 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 2 layers - true - nr_ulsim - 650 - -n1000 -s30 -S30.2 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_ulsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers - true - nr_ulsim - 650 - -n1000 -s30 -S30.2 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P - - - - Run_Physim - Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers - true - nr_ulsim - 1100 - -n1000 -s30 -S30.2 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - diff --git a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml b/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml deleted file mode 100644 index 400399d3a1..0000000000 --- a/ci-scripts/xml_files/t2_offload_enc_nr_dlsim.xml +++ /dev/null @@ -1,266 +0,0 @@ - - - - test-t2-offload-enc - Test T2 Offload Encoder - tasks - - 102040 - 000111 000112 000121 000122 000131 000132 - 000211 000212 000221 000222 000231 000232 - 000311 000312 000321 000322 000331 000332 - 000411 000412 000421 000422 000431 000432 - 040201 - - - - - Custom_Command - Disable Sleep States - caracal - sudo cpupower idle-set -D 0 - - - - Custom_Command - true - Enable Sleep States - caracal - sudo cpupower idle-set -E - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer - true - nr_dlsim - 230 - -n1000 -s30 -S30.2 -e5 -b106 -R106 -X 8,9,10,11,12 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 106 PRBs, 1 layer - true - nr_dlsim - 100 - -n1000 -s30 -S30.2 -e5 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer - true - nr_dlsim - 300 - -n1000 -s30 -S30.2 -e15 -b106 -R106 -X 8,9,10,11,12 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 106 PRBs, 1 layer - true - nr_dlsim - 100 - -n1000 -s30 -S30.2 -e15 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer - true - nr_dlsim - 350 - -n1000 -s30 -S30.2 -e25 -b106 -R106 -X 8,9,10,11,12 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 106 PRBs, 1 layer - true - nr_dlsim - 200 - -n1000 -s30 -S30.2 -e25 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 1 layer - true - nr_dlsim - 300 - -n1000 -s30 -S30.2 -e5 -b273 -R273 -X 8,9,10,11,12 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 1 layer - true - nr_dlsim - 150 - -n1000 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer - true - nr_dlsim - 350 - -n1000 -s30 -S30.2 -e15 -b273 -R273 -X 8,9,10,11,12 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 1 layer - true - nr_dlsim - 250 - -n1000 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer - true - nr_dlsim - 400 - -n1000 -s30 -S30.2 -e25 -b273 -R273 -X 8,9,10,11,12 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 1 layer - true - nr_dlsim - 400 - -n1000 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers - true - nr_dlsim - 400 - -n1000 -s30 -S30.2 -e5 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers - true - nr_dlsim - 200 - -n1000 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers - true - nr_dlsim - 450 - -n1000 -s30 -S30.2 -e15 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 2 layers - true - nr_dlsim - 500 - -n1000 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers - true - nr_dlsim - 500 - -n1000 -s30 -S30.2 -e25 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers - true - nr_dlsim - 500 - -n1000 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers, 4 antennas - true - nr_dlsim - 400 - -n1000 -s30 -S30.2 -e5 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers, 4 antennas - true - nr_dlsim - 200 - -n1000 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 20, 273 PRBs, 2 layers, 4 antennas - true - nr_dlsim - 400 - -n1000 -s30 -S30.2 -e15 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 20, 273 PRBs, 2 layers, 4 antennas - true - nr_dlsim - 300 - -n1000 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - - - Run_Physim - Run nr_dlsim with CPU: SNR = 30, MCS = 27, 273 PRBs, 2 layers, 4 antennas - true - nr_dlsim - 450 - -n1000 -s30 -S30.2 -e25 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P - - - - Run_Physim - Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 27, 273 PRBs, 2 layers, 4 antennas - true - nr_dlsim - 450 - -n1000 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev d8:00.0 --nrLDPC_coding_t2.dpdk_core_list 11-12 - - diff --git a/ci-scripts/xml_files/t2_offload_physim_enc_dec.xml b/ci-scripts/xml_files/t2_offload_physim_enc_dec.xml new file mode 100644 index 0000000000..73631a7a3c --- /dev/null +++ b/ci-scripts/xml_files/t2_offload_physim_enc_dec.xml @@ -0,0 +1,54 @@ + + + + test-t2-offload-enc-dec + Test T2 Offload + tasks + + 010204 + 111111 + 402010 + + + + + Custom_Command + Disable Sleep States + caracal + sudo cpupower idle-set -D 0 + + + + Custom_Command + true + Enable Sleep States + caracal + sudo cpupower idle-set -E + + + + Build_Deploy_Source_PhySim + Build and Deploy PhySim T2 Offload tests + caracal + -R 5g-offload -j1 + + diff --git a/ci-scripts/xml_files/test_case_list_template.xml b/ci-scripts/xml_files/test_case_list_template.xml deleted file mode 100644 index bcc8f94c09..0000000000 --- a/ci-scripts/xml_files/test_case_list_template.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - 010101 050101 060101 070101 030101 030201 050201 070201 060201 - 010102 030102 030103 030104 030105 030106 - - - - - Build_eNB - Build eNB (USRP) - -w USRP -c --eNB - - - - Build_eNB - Build eNB (USRP) - -w BLADERF -c --eNB - - - - Initialize_eNB - Initialize eNB (FDD/Band1/5MHz/info) - -O enb.band7.tm1.50prb.usrpb210.conf --log_config.global_log_options level,nocolor,time - - - - Initialize_eNB - Initialize eNB (FDD/Band1/10MHz/info) - -O 10M.band1.FDD.info.conf --log_config.global_log_options level,nocolor,time - - - - Initialize_eNB - Initialize eNB (FDD/Band1/20MHz/info) - -O 20M.band1.FDD.info.conf --log_config.global_log_options level,nocolor,time - - - - Initialize_eNB - Initialize eNB (TDD/Band38/5MHz/info) - -O 5M.band38.TDD.info.conf --log_config.global_log_options level,nocolor,time - - - - Initialize_eNB - Initialize eNB (TDD/Band38/10MHz/info) - -O 10M.band38.TDD.info.conf --log_config.global_log_options level,nocolor,time - - - - Initialize_eNB - Initialize eNB (TDD/Band38/20MHz/info) - -O 20M.band38.TDD.info.conf --log_config.global_log_options level,nocolor,time - - - - Terminate_eNB - Terminate eNB - - - - - - Initialize_UE - Initialize UE - - - - Terminate_UE - Terminate UE - - - - Attach_UE - Attach UE - - - - Detach_UE - Detach UE - - - diff --git a/ci-scripts/yaml_files/4g_l2sim_fdd/docker-compose.yml b/ci-scripts/yaml_files/4g_l2sim_fdd/docker-compose.yml index 9f40fb856d..0d810a1d4b 100644 --- a/ci-scripts/yaml_files/4g_l2sim_fdd/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_l2sim_fdd/docker-compose.yml @@ -10,7 +10,7 @@ services: CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch healthcheck: test: /bin/bash -c "nodetool status" - interval: 10s + interval: 20s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml index fb1d5a95ce..73d2505e92 100644 --- a/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "rfsim5g-mysql" image: mysql:8.0 + init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -13,6 +14,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -21,7 +24,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +36,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +48,8 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true environment: - TZ=Europe/Paris volumes: @@ -61,13 +65,16 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" @@ -78,6 +85,8 @@ services: ipv4_address: 192.168.72.135 healthcheck: test: /bin/bash -c "ping -c 2 192.168.72.134" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -87,9 +96,10 @@ services: container_name: rfsim5g-oai-cu cap_drop: - ALL + cap_add: + - SYS_NICE environment: USE_ADDITIONAL_OPTIONS: --log_config.global_log_options level,nocolor,time - --rfsimulator.options chanmod --gNBs.[0].remote_s_address 0.0.0.0 --telnetsrv --telnetsrv.listenaddr 192.168.71.150 --telnetsrv.shrmod ci @@ -100,9 +110,12 @@ services: public_net: ipv4_address: 192.168.71.150 volumes: + - ../../conf_files/neighbour-config.conf:/opt/oai-gnb/etc/neighbour-config.conf - ../../conf_files/gnb-cu.sa.band78.106prb.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -112,6 +125,8 @@ services: container_name: rfsim5g-oai-du-pci0 cap_drop: - ALL + cap_add: + - SYS_NICE environment: USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time @@ -130,6 +145,8 @@ services: - ../../conf_files/gnb-du.sa.band78.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -139,6 +156,8 @@ services: container_name: rfsim5g-oai-du-pci1 cap_drop: - ALL + cap_add: + - SYS_NICE environment: USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time @@ -161,6 +180,8 @@ services: - ../../conf_files/gnb-du.sa.band78.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -173,13 +194,13 @@ services: cap_add: - NET_ADMIN # for interface bringup - NET_RAW # for ping + - SYS_NICE environment: USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time -r 106 --numerology 1 -C 3619200000 --uicc0.imsi 208990100001100 --rfsimulator.options chanmod --rfsimulator.serveraddr server - --rfsimulator.hanging-workaround 1 --telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.181 --telnetsrv.listenport 8091 --channelmod.modellist_rfsimu_1.[0].model_name rfsimu_channel_ue0 --channelmod.modellist_rfsimu_1.[1].model_name rfsimu_channel_ue1 @@ -193,6 +214,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml index a40033be7f..9eec82a98b 100644 --- a/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "rfsim5g-mysql" image: mysql:8.0 + init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -15,13 +16,15 @@ services: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" interval: 10s timeout: 5s + start_period: 10s + start_interval: 500ms retries: 30 networks: public_net: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +36,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +48,8 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true environment: - TZ=Europe/Paris volumes: @@ -61,12 +65,15 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" @@ -80,6 +87,8 @@ services: interval: 10s timeout: 5s retries: 5 + start_period: 10s + start_interval: 500ms oai-gnb: image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} container_name: rfsim5g-oai-gnb @@ -99,6 +108,8 @@ services: test: /bin/bash -c "pgrep nr-softmodem" interval: 10s timeout: 5s + start_period: 10s + start_interval: 500ms retries: 5 ipc: host oai-nr-ue: @@ -126,6 +137,8 @@ services: interval: 10s timeout: 5s retries: 5 + start_period: 10s + start_interval: 500ms ipc: host networks: diff --git a/ci-scripts/yaml_files/5g_rfsimulator/README.md b/ci-scripts/yaml_files/5g_rfsimulator/README.md index ba3382c86c..629d0860fd 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator/README.md +++ b/ci-scripts/yaml_files/5g_rfsimulator/README.md @@ -37,9 +37,9 @@ Now pull images. ```bash $ docker pull mysql:8.0 -$ docker pull oaisoftwarealliance/oai-amf:v2.1.9 -$ docker pull oaisoftwarealliance/oai-smf:v2.1.9 -$ docker pull oaisoftwarealliance/oai-upf:v2.1.9 +$ docker pull oaisoftwarealliance/oai-amf:v2.1.10 +$ docker pull oaisoftwarealliance/oai-smf:v2.1.10 +$ docker pull oaisoftwarealliance/oai-upf:v2.1.10 $ docker pull oaisoftwarealliance/trf-gen-cn5g:focal $ docker pull oaisoftwarealliance/oai-gnb:develop @@ -52,7 +52,7 @@ $ docker logout **CAUTION: 2023/01/27 with the release `v1.5.0` of the `CN5G`, the previous version was not compatible any-more.** -**This new version is working only with the `v2.1.9` of the `CN5G`.** +**This new version is working only with `v2.1.9` or later of the `CN5G`.** # 2. Deploy containers # @@ -67,6 +67,18 @@ All the following commands **SHALL** be run from the `ci-scripts/yaml_files/5g_r For a deployment with the gNB split in CU and DU components, please refer to the `../5g_f1_rfsimulator` folder. For a deployment with the gNB split in CU-CP, CU-UP, and DU components, please refer to the `../5g_rfsimulator_e1` folder. +Note: **These instructions require `docker compose` v2.36.0 or later** due to the +use of the `interface_name` property, which is necessary for ensuring consistent +IP address assignment to the container interface. + +If you're using an older version of `docker compose`, you may encounter the following +error: +``` +validating docker-compose.yaml: services.oai-upf.networks.public_net Additional property interface_name is not allowed +``` +To update to the required version, you can follow the official Docker documentation: +https://docs.docker.com/compose/install/linux/ + ## 2.1. Deploy OAI 5G Core Network ## ```bash @@ -546,8 +558,7 @@ section in the file for details. This includes an image build service as well as code compilation service. This is necessary as the executable has to be linked against the same libraries that are present in the executing image. This might take a while the first time but other that that is very fast. Here is a list of -commands (wait between each command). Tested with `docker compose` v2.27.0 - +commands (wait between each command). Tested with `docker compose` v2.36.2. This command deploys OAI 5G Core Network ```bash diff --git a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml index 02c3b1ab7b..42f8184532 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "mysql" image: mysql:8.0 + init: true volumes: - ./conf/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ./conf/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -14,6 +15,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -65,13 +68,15 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 - + interface_name: eth1 oai-ext-dn: privileged: true container_name: oai-ext-dn image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" @@ -82,6 +87,8 @@ services: ipv4_address: 192.168.72.135 healthcheck: test: /bin/bash -c "ping -c 2 192.168.72.134" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -101,6 +108,8 @@ services: - ../../conf_files/gnb.sa.band78.106prb.rfsim.yaml:/opt/oai-gnb/etc/gnb.yaml healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -159,6 +168,8 @@ services: - ../../conf_files/nrue.uicc.yaml:/opt/oai-nr-ue/etc/nr-ue.yaml healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -183,6 +194,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -207,6 +220,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -231,6 +246,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -255,6 +272,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -279,6 +298,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -303,6 +324,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -327,6 +350,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -340,6 +365,12 @@ services: cap_add: - NET_ADMIN # for interface bringup - NET_RAW # for ping +<<<<<<< HEAD +======= + - SYS_NICE + environment: + USE_ADDITIONAL_OPTIONS: -E --rfsim -r 106 --numerology 1 --uicc0.imsi 208990100001109 -C 3319680000 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time +>>>>>>> 2025.w42 depends_on: - oai-gnb networks: @@ -351,6 +382,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml index 165d2791e7..9cab11ea9e 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "rfsim5g-mysql" image: mysql:8.0 + init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -13,6 +14,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -21,7 +24,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +36,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +48,8 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true environment: - TZ=Europe/Paris volumes: @@ -61,12 +65,15 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" @@ -77,6 +84,8 @@ services: ipv4_address: 192.168.72.135 healthcheck: test: /bin/bash -c "ping -c 2 192.168.72.134" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -97,6 +106,8 @@ services: - ../../conf_files/gnb.sa.band78.24prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -124,6 +135,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml index b051712a4c..778754fd58 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "rfsim5g-mysql" image: mysql:8.0 + init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -13,6 +14,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -21,7 +24,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +36,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +48,8 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true environment: - TZ=Europe/Paris volumes: @@ -61,12 +65,15 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" @@ -77,6 +84,8 @@ services: ipv4_address: 192.168.72.135 healthcheck: test: /bin/bash -c "ping -c 2 192.168.72.134" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -85,6 +94,8 @@ services: container_name: rfsim5g-oai-gnb cap_drop: - ALL + cap_add: + - SYS_NICE environment: USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time ASAN_OPTIONS: detect_leaks=0 @@ -97,6 +108,8 @@ services: - ../../conf_files/gnb.sa.band78.273prb.rfsim.2x2.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -109,6 +122,7 @@ services: cap_add: - NET_ADMIN # for interface bringup - NET_RAW # for ping + - SYS_NICE environment: USE_ADDITIONAL_OPTIONS: --rfsim -r 273 --numerology 1 --band 78 -C 3450720000 --ssb 1518 --ue-nb-ant-tx 2 --uicc0.imsi 208990100001100 --ue-nb-ant-rx 2 --uecap_file /opt/oai-nr-ue/etc/uecap.xml --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time depends_on: @@ -123,6 +137,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml index 69d27de863..9ccce2a8e1 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "rfsim5g-mysql" image: mysql:8.0 + init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -13,6 +14,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -21,7 +24,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +36,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +48,8 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true environment: - TZ=Europe/Paris volumes: @@ -61,8 +65,10 @@ services: networks: core_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-cucp: image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} @@ -87,6 +93,8 @@ services: - ../../conf_files/gnb-cucp.sa.f1.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -116,6 +124,8 @@ services: - ../../conf_files/gnb-cuup.sa.f1.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-cuup" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -148,6 +158,8 @@ services: - ../../conf_files/gnb-cuup.sa.f1.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-cuup" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -180,6 +192,8 @@ services: - ../../conf_files/gnb-cuup.sa.f1.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-cuup" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -209,6 +223,8 @@ services: - ../../conf_files/gnb-du.sa.band78.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -241,6 +257,8 @@ services: - ../../conf_files/gnb-du.sa.band78.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -273,6 +291,8 @@ services: - ../../conf_files/gnb-du.sa.band78.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -301,6 +321,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -329,6 +351,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -358,6 +382,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_fr2_32prb/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_fr2_32prb/docker-compose.yaml index 627fde5dce..13d91d9090 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_fr2_32prb/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_fr2_32prb/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "rfsim5g-mysql" image: mysql:8.0 + init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -13,6 +14,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -21,7 +24,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +36,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +48,8 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true environment: - TZ=Europe/Paris volumes: @@ -61,12 +65,15 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" @@ -77,6 +84,8 @@ services: ipv4_address: 192.168.72.135 healthcheck: test: /bin/bash -c "ping -c 2 192.168.72.134" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -96,6 +105,8 @@ services: - ../../conf_files/gnb.sa.band261.u3.32prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -124,6 +135,8 @@ services: ipv4_address: 192.168.71.150 healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_multiue/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_multiue/docker-compose.yaml new file mode 100644 index 0000000000..9d660e0c3b --- /dev/null +++ b/ci-scripts/yaml_files/5g_rfsimulator_multiue/docker-compose.yaml @@ -0,0 +1,146 @@ +services: + mysql: + container_name: "rfsim5g-mysql" + image: mysql:8.0 + volumes: + - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql + - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh + environment: + - TZ=Europe/Paris + - MYSQL_DATABASE=oai_db + - MYSQL_USER=test + - MYSQL_PASSWORD=test + - MYSQL_ROOT_PASSWORD=linux + healthcheck: + test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + interval: 10s + timeout: 5s + retries: 30 + networks: + public_net: + ipv4_address: 192.168.71.131 + oai-amf: + container_name: "rfsim5g-oai-amf" + image: oaisoftwarealliance/oai-amf:v2.1.10 + environment: + - TZ=Europe/paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-amf/etc/config.yaml + depends_on: + - mysql + networks: + public_net: + ipv4_address: 192.168.71.132 + oai-smf: + container_name: "rfsim5g-oai-smf" + image: oaisoftwarealliance/oai-smf:v2.1.10 + environment: + - TZ=Europe/Paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-smf/etc/config.yaml + depends_on: + - oai-amf + networks: + public_net: + ipv4_address: 192.168.71.133 + oai-upf: + container_name: "rfsim5g-oai-upf" + image: oaisoftwarealliance/oai-upf:v2.1.10 + environment: + - TZ=Europe/Paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-upf/etc/config.yaml + depends_on: + - oai-smf + cap_add: + - NET_ADMIN + - SYS_ADMIN + cap_drop: + - ALL + privileged: true + networks: + public_net: + ipv4_address: 192.168.71.134 + interface_name: eth0 + traffic_net: + ipv4_address: 192.168.72.134 + interface_name: eth1 + oai-ext-dn: + privileged: true + container_name: rfsim5g-oai-ext-dn + image: oaisoftwarealliance/trf-gen-cn5g:focal + entrypoint: /bin/bash -c \ + "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ + "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" + depends_on: + - oai-upf + networks: + traffic_net: + ipv4_address: 192.168.72.135 + healthcheck: + test: /bin/bash -c "ping -c 2 192.168.72.134" + interval: 10s + timeout: 5s + retries: 5 + oai-gnb: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: rfsim5g-oai-gnb + cap_drop: + - ALL + environment: + USE_ADDITIONAL_OPTIONS: -E --rfsim --log_config.global_log_options level,nocolor,time --gNBs.[0].TIMERS.t300 1000 + ASAN_OPTIONS: detect_leaks=0 + depends_on: + - oai-ext-dn + networks: + public_net: + ipv4_address: 192.168.71.140 + volumes: + - ../../conf_files/gnb.sa.band78.106prb.rfsim.yaml:/opt/oai-gnb/etc/gnb.yaml + healthcheck: + test: /bin/bash -c "pgrep nr-softmodem" + interval: 10s + timeout: 5s + retries: 5 + oai-nr-ue: + image: ${REGISTRY:-oaisoftwarealliance}/${NRUE_IMG:-oai-nr-ue}:${TAG:-develop} + container_name: rfsim5g-oai-nr-ue + cap_drop: + - ALL + cap_add: + - NET_ADMIN # for interface bringup + - NET_RAW # for ping + environment: + USE_ADDITIONAL_OPTIONS: -E --rfsim -r 106 --numerology 1 --uicc0.imsi 208990100001100 -C 3319680000 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time --num-ues 10 + depends_on: + - oai-gnb + networks: + public_net: + ipv4_address: 192.168.71.150 + devices: + - /dev/net/tun:/dev/net/tun + volumes: + - ./nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf + healthcheck: + test: /bin/bash -c "pgrep nr-uesoftmodem" + interval: 10s + timeout: 5s + retries: 5 + +networks: + public_net: + driver: bridge + name: rfsim5g-oai-public-net + ipam: + config: + - subnet: 192.168.71.128/26 + driver_opts: + com.docker.network.bridge.name: "rfsim5g-public" + traffic_net: + driver: bridge + name: rfsim5g-oai-traffic-net + ipam: + config: + - subnet: 192.168.72.128/26 + driver_opts: + com.docker.network.bridge.name: "rfsim5g-traffic" diff --git a/ci-scripts/yaml_files/5g_rfsimulator_multiue/nrue.uicc.conf b/ci-scripts/yaml_files/5g_rfsimulator_multiue/nrue.uicc.conf new file mode 100644 index 0000000000..92ccf9dca2 --- /dev/null +++ b/ci-scripts/yaml_files/5g_rfsimulator_multiue/nrue.uicc.conf @@ -0,0 +1,75 @@ +uicc0 = { + imsi = "208990100001100"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc1 = { + imsi = "208990100001101"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc2 = { + imsi = "208990100001102"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc3 = { + imsi = "208990100001103"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc4 = { + imsi = "208990100001104"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc5 = { + imsi = "208990100001105"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc6 = { + imsi = "208990100001106"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc7 = { + imsi = "208990100001107"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc8 = { + imsi = "208990100001108"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} +uicc9 = { + imsi = "208990100001109"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc= "C42449363BBAD02B66D16BC975D77CC1"; + dnn= "oai"; + nssai_sst=1; +} + + + +thread-pool: "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1" + diff --git a/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml new file mode 100644 index 0000000000..6c03a02443 --- /dev/null +++ b/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml @@ -0,0 +1,306 @@ +services: + mysql: + container_name: "rfsim5g-mysql" + image: mysql:8.0 + volumes: + - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql + - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh + environment: + - TZ=Europe/Paris + - MYSQL_DATABASE=oai_db + - MYSQL_USER=test + - MYSQL_PASSWORD=test + - MYSQL_ROOT_PASSWORD=linux + healthcheck: + test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + interval: 10s + timeout: 5s + retries: 30 + networks: + public_net: + ipv4_address: 192.168.71.131 + oai-amf: + container_name: "rfsim5g-oai-amf" + image: oaisoftwarealliance/oai-amf:ci-tmp-pr-372-26c14bcd + environment: + - TZ=Europe/paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-amf/etc/config.yaml + depends_on: + - mysql + networks: + public_net: + ipv4_address: 192.168.71.132 + oai-smf: + container_name: "rfsim5g-oai-smf" + image: oaisoftwarealliance/oai-smf:v2.1.9 + environment: + - TZ=Europe/Paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-smf/etc/config.yaml + depends_on: + - oai-amf + networks: + public_net: + ipv4_address: 192.168.71.133 + oai-upf: + container_name: "rfsim5g-oai-upf" + image: oaisoftwarealliance/oai-upf:v2.1.9 + environment: + - TZ=Europe/Paris + volumes: + - ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-upf/etc/config.yaml + depends_on: + - oai-smf + cap_add: + - NET_ADMIN + - SYS_ADMIN + cap_drop: + - ALL + privileged: true + networks: + public_net: + ipv4_address: 192.168.71.134 + interface_name: eth0 + traffic_net: + ipv4_address: 192.168.72.134 + interface_name: eth1 + oai-ext-dn: + privileged: true + container_name: rfsim5g-oai-ext-dn + image: oaisoftwarealliance/trf-gen-cn5g:focal + entrypoint: /bin/bash -c \ + "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ + "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" + depends_on: + - oai-upf + networks: + traffic_net: + ipv4_address: 192.168.72.135 + healthcheck: + test: /bin/bash -c "ping -c 2 192.168.72.134" + interval: 10s + timeout: 5s + retries: 5 + + oai-cucp-0: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: rfsim5g-oai-cucp-0 + cap_drop: + - ALL + environment: + USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.shrmod ci + --telnetsrv.listenaddr 192.168.71.150 + --gNBs.[0].nr_cellid 0 + --log_config.global_log_options level,nocolor,time + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 + depends_on: + - oai-amf + networks: + public_net: + ipv4_address: 192.168.71.150 + volumes: + - ../../conf_files/neighbour-config.conf:/opt/oai-gnb/etc/neighbour-config.conf + - ../../conf_files/gnb-cucp.sa.e1-ho-n2.conf:/opt/oai-gnb/etc/gnb.conf + healthcheck: + test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms + interval: 10s + timeout: 5s + retries: 5 + + oai-cuup-0: + image: ${REGISTRY:-oaisoftwarealliance}/${NRCUUP_IMG:-oai-nr-cuup}:${TAG:-develop} + container_name: rfsim5g-oai-cuup-0 + cap_drop: + - ALL + environment: + USE_ADDITIONAL_OPTIONS: --log_config.global_log_options level,nocolor,time + --gNBs.[0].E1_INTERFACE.[0].ipv4_cucp 192.168.71.150 + --gNBs.[0].E1_INTERFACE.[0].ipv4_cuup 192.168.71.151 + --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NGU 192.168.71.151 + --gNBs.[0].local_s_address 192.168.71.151 + ASAN_OPTIONS: detect_leaks=0 + depends_on: + - oai-cucp-0 + networks: + public_net: + ipv4_address: 192.168.71.151 + volumes: + - ../../conf_files/gnb-cuup.sa.f1.conf:/opt/oai-gnb/etc/gnb.conf + healthcheck: + test: /bin/bash -c "pgrep nr-cuup" + start_period: 10s + start_interval: 500ms + interval: 10s + timeout: 5s + retries: 5 + + + oai-du-0: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: rfsim5g-oai-du-0 + cap_drop: + - ALL + environment: + USE_ADDITIONAL_OPTIONS: --rfsim + --log_config.global_log_options level,nocolor,time + --gNBs.[0].nr_cellid 0 + --telnetsrv --telnetsrv.listenaddr 192.168.71.171 + --telnetsrv.shrmod ci + --rfsimulator.serveraddr 192.168.71.190 + --gNBs.[0].servingCellConfigCommon.[0].ra_ResponseWindow 5 + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 + depends_on: + - oai-cucp-0 + networks: + public_net: + ipv4_address: 192.168.71.171 + volumes: + - ../../conf_files/neighbour-config.conf:/opt/oai-gnb/etc/neighbour-config.conf + - ../../conf_files/gnb-du.sa.band78.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf + healthcheck: + test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms + interval: 10s + timeout: 5s + retries: 5 + + oai-nr-ue: + image: ${REGISTRY:-oaisoftwarealliance}/${NRUE_IMG:-oai-nr-ue}:${TAG:-develop} + container_name: rfsim5g-oai-nr-ue + cap_drop: + - ALL + cap_add: + - NET_ADMIN # for interface bringup + - NET_RAW # for ping + environment: + USE_ADDITIONAL_OPTIONS: --rfsim --rfsimulator.serveraddr server + --band 78 -C 3619200000 -r 106 --numerology 1 --ssb 516 + --uicc0.imsi 208990100001100 + --log_config.global_log_options level,nocolor,time + networks: + public_net: + ipv4_address: 192.168.71.190 + devices: + - /dev/net/tun:/dev/net/tun + volumes: + - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf + healthcheck: + test: /bin/bash -c "pgrep nr-uesoftmodem" + interval: 10s + timeout: 5s + retries: 5 + + oai-cucp-1: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: rfsim5g-oai-cucp-1 + cap_drop: + - ALL + environment: + USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.shrmod ci + --telnetsrv.listenaddr 192.168.71.180 + --gNBs.[0].E1_INTERFACE.[0].ipv4_cucp 192.168.71.180 + --gNBs.[0].E1_INTERFACE.[0].ipv4_cuup 192.168.71.181 + --gNBs.[0].local_s_address 192.168.71.180 + --gNBs.[0].remote_s_address 192.168.71.181 + --gNBs.[0].gNB_ID 0xb00 + --gNBs.[0].nr_cellid 1 + --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF 192.168.71.180 + --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NGU 192.168.71.180 + --log_config.global_log_options level,nocolor,time + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 + networks: + public_net: + ipv4_address: 192.168.71.180 + volumes: + - ../../conf_files/neighbour-config.conf:/opt/oai-gnb/etc/neighbour-config.conf + - ../../conf_files/gnb-cucp.sa.e1-ho-n2.conf:/opt/oai-gnb/etc/gnb.conf + healthcheck: + test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms + interval: 10s + timeout: 5s + retries: 5 + + oai-cuup-1: + image: ${REGISTRY:-oaisoftwarealliance}/${NRCUUP_IMG:-oai-nr-cuup}:${TAG:-develop} + container_name: rfsim5g-oai-cuup-1 + cap_drop: + - ALL + environment: + USE_ADDITIONAL_OPTIONS: --log_config.global_log_options level,nocolor,time + --gNBs.[0].E1_INTERFACE.[0].ipv4_cucp 192.168.71.180 + --gNBs.[0].E1_INTERFACE.[0].ipv4_cuup 192.168.71.181 + --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NGU 192.168.71.181 + --gNBs.[0].local_s_address 192.168.71.181 + ASAN_OPTIONS: detect_leaks=0 + depends_on: + - oai-cucp-0 + networks: + public_net: + ipv4_address: 192.168.71.181 + volumes: + - ../../conf_files/gnb-cuup.sa.f1.conf:/opt/oai-gnb/etc/gnb.conf + healthcheck: + test: /bin/bash -c "pgrep nr-cuup" + start_period: 10s + start_interval: 500ms + interval: 10s + timeout: 5s + retries: 5 + + oai-du-1: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: rfsim5g-oai-du-1 + cap_drop: + - ALL + environment: + USE_ADDITIONAL_OPTIONS: --rfsim + --rfsimulator.serveraddr 192.168.71.190 + --log_config.global_log_options level,nocolor,time + --gNBs.[0].gNB_DU_ID 1234 + --gNBs.[0].gNB_ID 0xb00 + --gNBs.[0].nr_cellid 1 + --gNBs.[0].servingCellConfigCommon.[0].physCellId 1 + --gNBs.[0].servingCellConfigCommon.[0].absoluteFrequencySSB 621312 + --gNBs.[0].servingCellConfigCommon.[0].dl_absoluteFrequencyPointA 620040 + --MACRLCs.[0].local_n_address 192.168.71.182 + --MACRLCs.[0].remote_n_address 192.168.71.180 + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 + depends_on: + - oai-cucp-1 + networks: + public_net: + ipv4_address: 192.168.71.182 + volumes: + - ../../conf_files/neighbour-config.conf:/opt/oai-gnb/etc/neighbour-config.conf + - ../../conf_files/gnb-du.sa.band78.106prb.rfsim.conf:/opt/oai-gnb/etc/gnb.conf + healthcheck: + test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms + interval: 10s + timeout: 5s + retries: 5 + +networks: + public_net: + driver: bridge + name: rfsim5g-oai-public-net + ipam: + config: + - subnet: 192.168.71.128/26 + driver_opts: + com.docker.network.bridge.name: "rfsim5g-public" + traffic_net: + driver: bridge + name: rfsim5g-oai-traffic-net + ipam: + config: + - subnet: 192.168.72.128/26 + driver_opts: + com.docker.network.bridge.name: "rfsim5g-traffic" diff --git a/ci-scripts/yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml index 31390cde9c..c83060b713 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_ntn_geo/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "rfsim5g-mysql" image: mysql:8.0 + init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -13,6 +14,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -21,7 +24,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +36,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +48,8 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true environment: - TZ=Europe/Paris volumes: @@ -61,12 +65,15 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" @@ -77,6 +84,8 @@ services: ipv4_address: 192.168.72.135 healthcheck: test: /bin/bash -c "ping -c 2 192.168.72.134" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -87,7 +96,9 @@ services: - ALL environment: USE_ADDITIONAL_OPTIONS: --rfsim --log_config.global_log_options level,nocolor,time - ASAN_OPTIONS: detect_leaks=0 + --telnetsrv --telnetsrv.listenaddr 192.168.71.140 + --telnetsrv.shrmod ci + ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0 depends_on: - oai-ext-dn networks: @@ -97,6 +108,8 @@ services: - ../../conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -122,6 +135,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml index 29be9d6900..5469b0b247 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml @@ -13,6 +13,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -21,7 +23,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +35,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +47,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -61,8 +63,10 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn @@ -77,6 +81,8 @@ services: ipv4_address: 192.168.72.135 healthcheck: test: /bin/bash -c "ping -c 2 192.168.72.134" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -97,6 +103,8 @@ services: - ../../conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -129,6 +137,8 @@ services: - ../../conf_files/nrue.uicc.ntn-leo.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_sidelink/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_sidelink/docker-compose.yaml index 35e6a4eee9..c04e634ca2 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_sidelink/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_sidelink/docker-compose.yaml @@ -18,6 +18,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -43,6 +45,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -56,11 +60,3 @@ networks: - subnet: 192.168.71.128/26 driver_opts: com.docker.network.bridge.name: "rfsim5g-public" - traffic_net: - driver: bridge - name: rfsim5g-oai-traffic-net - ipam: - config: - - subnet: 192.168.72.128/26 - driver_opts: - com.docker.network.bridge.name: "rfsim5g-traffic" diff --git a/ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml index cd0365b4ec..ed1701ef86 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_u0_25prb/docker-compose.yaml @@ -2,6 +2,7 @@ services: mysql: container_name: "rfsim5g-mysql" image: mysql:8.0 + init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -13,6 +14,8 @@ services: - MYSQL_ROOT_PASSWORD=linux healthcheck: test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 30 @@ -21,7 +24,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.9 + image: oaisoftwarealliance/oai-amf:v2.1.10 environment: - TZ=Europe/paris volumes: @@ -33,7 +36,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.9 + image: oaisoftwarealliance/oai-smf:v2.1.10 environment: - TZ=Europe/Paris volumes: @@ -45,7 +48,8 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.9 + image: oaisoftwarealliance/oai-upf:v2.1.10 + init: true environment: - TZ=Europe/Paris volumes: @@ -61,12 +65,15 @@ services: networks: public_net: ipv4_address: 192.168.71.134 + interface_name: eth0 traffic_net: ipv4_address: 192.168.72.134 + interface_name: eth1 oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn image: oaisoftwarealliance/trf-gen-cn5g:focal + init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ "ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity" @@ -77,6 +84,8 @@ services: ipv4_address: 192.168.72.135 healthcheck: test: /bin/bash -c "ping -c 2 192.168.72.134" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -99,6 +108,8 @@ services: - ../../conf_files/gnb-vnf.sa.band66.u0.25prb.nfapi.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -121,6 +132,8 @@ services: - ../../conf_files/gnb-pnf.band66.rfsim.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 @@ -134,7 +147,7 @@ services: - NET_ADMIN # for interface bringup - NET_RAW # for ping environment: - USE_ADDITIONAL_OPTIONS: --rfsim -r 25 --numerology 0 --uicc0.imsi 208990100001100 --band 66 -C 2152680000 --CO -400000000 --ssb 48 --rfsimulator.serveraddr 192.168.71.141 --log_config.global_log_options level,nocolor,time + USE_ADDITIONAL_OPTIONS: --rfsim -r 25 --numerology 0 --uicc0.imsi 208990100001100 --band 66 -C 2152680000 --CO -400000000 --ssb 48 --rfsimulator.serveraddr 192.168.71.141 --extra-pdu-id 2 --log_config.global_log_options level,nocolor,time depends_on: - oai-pnf networks: @@ -146,6 +159,8 @@ services: - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" + start_period: 10s + start_interval: 500ms interval: 10s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_sa_f1_b210_ho/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_f1_b210_ho/docker-compose.yml new file mode 100644 index 0000000000..c1c3db1607 --- /dev/null +++ b/ci-scripts/yaml_files/5g_sa_f1_b210_ho/docker-compose.yml @@ -0,0 +1,90 @@ +services: + oai-cu: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: oai-cu + cap_drop: + - ALL + ulimits: + core: -1 # for core dumps + environment: + USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.listenport 9090 --telnetsrv.shrmod ci + --log_config.global_log_options level,nocolor,utc_time,line_num,function + volumes: + - ../../conf_files/gnb-cu.sa.f1.ho.conf:/opt/oai-gnb/etc/gnb.conf + - ../../conf_files/neighbour-config-ho.conf:/opt/oai-gnb/etc/neighbour-config-ho.conf + # for performance reasons, we use host mode: in bridge mode, we have + # unacceptable DL TCP performance. However, the whole point of + # containerization is to not be in host mode, so update this to macvlan + # later. + network_mode: "host" + #entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + # pgrep does NOT work + test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem" + interval: 10s + timeout: 5s + retries: 5 + + oai-du0: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: oai-du0 + cap_drop: + - ALL + cap_add: + - SYS_NICE + - IPC_LOCK + ulimits: + core: -1 # for core dumps + environment: + USE_B2XX: 'yes' + USE_ADDITIONAL_OPTIONS: --RUs.[0].sdr_addrs serial=30AD30F + --telnetsrv --telnetsrv.listenport 9091 --telnetsrv.shrmod ci + --log_config.global_log_options level,nocolor,utc_time,line_num,function + devices: + - /dev/bus/usb/:/dev/bus/usb/ + volumes: + - ../../conf_files/gnb-du.sa.band78.51prb.usrpb210.ho-pci0.conf:/opt/oai-gnb/etc/gnb.conf + # for performance reasons, we use host mode: in bridge mode, we have + # unacceptable DL TCP performance. However, the whole point of + # containerization is to not be in host mode, so update this to macvlan + # later. + network_mode: "host" + #entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + # pgrep does NOT work + test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem" + interval: 10s + timeout: 5s + retries: 5 + + oai-du1: + image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} + container_name: oai-du1 + cap_drop: + - ALL + cap_add: + - SYS_NICE + - IPC_LOCK + ulimits: + core: -1 # for core dumps + environment: + USE_B2XX: 'yes' + USE_ADDITIONAL_OPTIONS: --RUs.[0].sdr_addrs serial=31F8010 + --telnetsrv --telnetsrv.listenport 9091 --telnetsrv.shrmod ci + --log_config.global_log_options level,nocolor,utc_time,line_num,function + devices: + - /dev/bus/usb/:/dev/bus/usb/ + volumes: + - ../../conf_files/gnb-du.sa.band78.51prb.usrpb210.ho-pci1.conf:/opt/oai-gnb/etc/gnb.conf + # for performance reasons, we use host mode: in bridge mode, we have + # unacceptable DL TCP performance. However, the whole point of + # containerization is to not be in host mode, so update this to macvlan + # later. + network_mode: "host" + #entrypoint: /bin/bash -c "sleep infinity" + healthcheck: + # pgrep does NOT work + test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem" + interval: 10s + timeout: 5s + retries: 5 diff --git a/ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz/docker-compose.yml index 6d597d3a86..11ecb20f08 100644 --- a/ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz/docker-compose.yml @@ -14,7 +14,9 @@ services: volumes: - ../../conf_files/gnb.sa.band77.273prb.usrpn310.2x2.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: - test: /bin/bash -c "pgrep nr-softmodem" - interval: 10s + test: /bin/bash -c "/opt/oai-gnb/bin/check-prach-io.sh" + start_period: 15s + start_interval: 500ms + interval: 5s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz/docker-compose.yml index 43211d7381..332fb23503 100644 --- a/ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz/docker-compose.yml @@ -14,7 +14,9 @@ services: volumes: - ../../conf_files/gnb.sa.band77.162prb.usrpn310.2x2.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: - test: /bin/bash -c "pgrep nr-softmodem" - interval: 10s + test: /bin/bash -c "/opt/oai-gnb/bin/check-prach-io.sh" + start_period: 15s + start_interval: 500ms + interval: 5s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz/docker-compose.yml index 0ecba5f39e..d3d2ddf582 100644 --- a/ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz/docker-compose.yml @@ -16,7 +16,7 @@ services: - ../../conf_files/gnb-vnf.sa.band77.162prb.nfapi.4x4.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: test: /bin/bash -c "pgrep nr-softmodem" - interval: 15s + interval: 5s timeout: 5s retries: 5 oai-pnf: @@ -35,7 +35,9 @@ services: volumes: - ../../conf_files/gnb-pnf.band77.usrpn310.4x4.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: - test: /bin/bash -c "pgrep nr-softmodem" - interval: 15s + test: /bin/bash -c "/opt/oai-gnb/bin/check-prach-io.sh" + start_period: 15s + start_interval: 500ms + interval: 5s timeout: 5s retries: 5 diff --git a/ci-scripts/yaml_files/5g_sa_n310_gnb/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n310_gnb/docker-compose.yml index e93152bd37..562b72561a 100644 --- a/ci-scripts/yaml_files/5g_sa_n310_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_sa_n310_gnb/docker-compose.yml @@ -16,7 +16,9 @@ services: volumes: - ../../conf_files/gnb.sa.band78.106prb.n310.7ds2u.conf:/opt/oai-gnb/etc/gnb.conf healthcheck: - test: /bin/bash -c "pgrep nr-softmodem" - interval: 10s + test: /bin/bash -c "/opt/oai-gnb/bin/check-prach-io.sh" + start_period: 15s + start_interval: 500ms + interval: 5s timeout: 5s - retries: 5 + retries: 10 diff --git a/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml b/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml index a0a15ac11e..aac787a916 100644 --- a/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_sa_n310_nrue/docker-compose.yml @@ -17,7 +17,7 @@ services: #entrypoint: /bin/bash -c "sleep infinity" environment: TZ: Europe/Paris - USE_ADDITIONAL_OPTIONS: --usrp-args type=n3xx,name=ni-n3xx-31641B9,addr=192.168.10.2 -r 106 --numerology 1 --band 78 -C 3511200000 --ue-fo-compensation --ue-rxgain 65 --tune-offset 20000000 -A 90 --log_config.global_log_options level,nocolor,time --uicc0.imsi 001020000000111 --uicc0.nssai_sd 16777215 + USE_ADDITIONAL_OPTIONS: --usrp-args type=n3xx,name=ni-n3xx-31641B9,addr=192.168.10.2 -r 106 --numerology 1 --band 78 -C 3425010000 --ssb 509 --ue-fo-compensation --ue-rxgain 65 --tune-offset 20000000 -A 90 --log_config.global_log_options level,nocolor,time --uicc0.imsi 001020000000111 --uicc0.nssai_sd 16777215 volumes: - ../../conf_files/ue.sa.conf:/opt/oai-nr-ue/etc/nr-ue.conf healthcheck: diff --git a/ci-scripts/yaml_files/local_common_overrides/build_images.yaml b/ci-scripts/yaml_files/local_common_overrides/build_images.yaml index a771289ae4..d738ccb2ff 100644 --- a/ci-scripts/yaml_files/local_common_overrides/build_images.yaml +++ b/ci-scripts/yaml_files/local_common_overrides/build_images.yaml @@ -3,7 +3,7 @@ services: image: ran-base build: context: ../../../ - dockerfile: docker/Dockerfile.base.ubuntu22 + dockerfile: docker/Dockerfile.base.ubuntu tags: - ran-base @@ -11,7 +11,7 @@ services: image: ran-build build: context: ../../../ - dockerfile: docker/Dockerfile.build.ubuntu22 + dockerfile: docker/Dockerfile.build.ubuntu tags: - ran-build depends_on: @@ -22,7 +22,7 @@ services: image: gnb-local build: context: ../../../ - dockerfile: docker/Dockerfile.gNB.ubuntu22 + dockerfile: docker/Dockerfile.gNB.ubuntu tags: - gnb-local depends_on: @@ -35,7 +35,7 @@ services: image: ue-local build: context: ../../../ - dockerfile: docker/Dockerfile.nrUE.ubuntu22 + dockerfile: docker/Dockerfile.nrUE.ubuntu tags: - ue-local depends_on: diff --git a/ci-scripts/yaml_files/sa_fhi_7.2_benetel550_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_fhi_7.2_benetel550_gnb/docker-compose.yml index a0bc415730..b70229ac94 100644 --- a/ci-scripts/yaml_files/sa_fhi_7.2_benetel550_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/sa_fhi_7.2_benetel550_gnb/docker-compose.yml @@ -22,10 +22,12 @@ services: oai-net: ipv4_address: 172.21.18.20 healthcheck: - test: /bin/bash -c "pgrep nr-softmodem" - interval: 10s + test: /bin/bash -c "/opt/oai-gnb/bin/check-prach-io.sh" + start_period: 15s + start_interval: 500ms + interval: 5s timeout: 5s - retries: 5 + retries: 10 networks: oai-net: driver: macvlan diff --git a/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/docker-compose.yml index 0dd0a6c99d..f08859a516 100644 --- a/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/sa_fhi_7.2_metanoia_2x2_gnb/docker-compose.yml @@ -9,7 +9,7 @@ services: container_name: oai-gnb environment: TZ: Europe/Paris - USE_ADDITIONAL_OPTIONS: --sa --thread-pool 7,8,9,10,11,12 + USE_ADDITIONAL_OPTIONS: --thread-pool 7,8,9,10,11,12 devices: - /dev/vfio:/dev/vfio/ volumes: @@ -21,10 +21,12 @@ services: oai-net: ipv4_address: 172.21.18.20 healthcheck: - test: /bin/bash -c "pgrep nr-softmodem" - interval: 10s + test: /bin/bash -c "/opt/oai-gnb/bin/check-prach-io.sh" + start_period: 15s + start_interval: 500ms + interval: 5s timeout: 5s - retries: 5 + retries: 10 networks: oai-net: driver: macvlan diff --git a/ci-scripts/yaml_files/sa_fhi_7.2_vvdn_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_fhi_7.2_vvdn_gnb/docker-compose.yml index a74b583e2b..ff06893fa0 100644 --- a/ci-scripts/yaml_files/sa_fhi_7.2_vvdn_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/sa_fhi_7.2_vvdn_gnb/docker-compose.yml @@ -21,10 +21,13 @@ services: oai-net: ipv4_address: 172.21.18.20 healthcheck: - test: /bin/bash -c "pgrep nr-softmodem" - interval: 10s + test: /bin/bash -c "/opt/oai-gnb/bin/check-prach-io.sh" + start_period: 15s + start_interval: 500ms + interval: 5s timeout: 5s - retries: 5 + retries: 10 + networks: oai-net: driver: macvlan diff --git a/ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml b/ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml index d5677ac239..c9f3d90131 100644 --- a/ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml +++ b/ci-scripts/yaml_files/sa_gnb_aerial/docker-compose.yaml @@ -23,7 +23,7 @@ services: - ../../../cmake_targets/share:/opt/cuBB/share userns_mode: host ipc: "shareable" - image: cubb-build:24-3 + image: cubb-build:25-2.1 environment: - cuBB_SDK=/opt/nvidia/cuBB command: bash -c "sudo rm -rf /tmp/phy.log && sudo chmod +x /opt/nvidia/cuBB/aerial_l1_entrypoint.sh && /opt/nvidia/cuBB/aerial_l1_entrypoint.sh" @@ -33,7 +33,7 @@ services: timeout: 5s retries: 5 oai-gnb-aerial: - cpuset: "13-20" + cpuset: "13-14" image: ${REGISTRY:-oaisoftwarealliance}/oai-gnb-aerial:${TAG:-develop} depends_on: nv-cubb: diff --git a/ci-scripts/yaml_files/sa_gnb_aerial_ul/aerial_l1_entrypoint.sh b/ci-scripts/yaml_files/sa_gnb_aerial_ul/aerial_l1_entrypoint.sh new file mode 100755 index 0000000000..e0fea22190 --- /dev/null +++ b/ci-scripts/yaml_files/sa_gnb_aerial_ul/aerial_l1_entrypoint.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Check if cuBB_SDK is defined, if not, use default path +cuBB_Path="${cuBB_SDK:-/opt/nvidia/cuBB}" + +cd "$cuBB_Path" || exit 1 +# Add gdrcopy to LD_LIBRARY_PATH +export LD_LIBRARY_PATH=/usr/local/nvidia/lib:/usr/local/nvidia/lib64:/opt/mellanox/dpdk/lib/x86_64-linux-gnu:/opt/mellanox/doca/lib/x86_64-linux-gnu:/opt/nvidia/cuBB/cuPHY-CP/external/gdrcopy/build/x86_64/ + +# Restart MPS +# Export variables +export CUDA_DEVICE_MAX_CONNECTIONS=8 +export CUDA_MPS_PIPE_DIRECTORY=/var +export CUDA_MPS_LOG_DIRECTORY=/var + +# Stop existing MPS +sudo -E echo quit | sudo -E nvidia-cuda-mps-control + +# Start MPS +sudo -E nvidia-cuda-mps-control -d +sudo -E echo start_server -uid 0 | sudo -E nvidia-cuda-mps-control + +# Start cuphycontroller_scf +# Check if an argument is provided +if [ $# -eq 0 ]; then + # No argument provided, use default value + argument="P5G_FXN_GH" +else + # Argument provided, use it + argument="$1" +fi + +sudo -E "$cuBB_Path"/build/cuPHY-CP/cuphycontroller/examples/cuphycontroller_scf "$argument" +sudo -E ./build/cuPHY-CP/gt_common_libs/nvIPC/tests/pcap/pcap_collect diff --git a/ci-scripts/yaml_files/sa_gnb_aerial_ul/docker-compose.yaml b/ci-scripts/yaml_files/sa_gnb_aerial_ul/docker-compose.yaml new file mode 100644 index 0000000000..077c58c67c --- /dev/null +++ b/ci-scripts/yaml_files/sa_gnb_aerial_ul/docker-compose.yaml @@ -0,0 +1,66 @@ +services: + nv-cubb: + container_name: nv-cubb + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: + - gpu + network_mode: host + shm_size: 4096m + privileged: true + stdin_open: true + tty: true + volumes: + - /lib/modules:/lib/modules + - /dev/hugepages:/dev/hugepages + - /usr/src:/usr/src + - ./aerial_l1_entrypoint.sh:/opt/nvidia/cuBB/aerial_l1_entrypoint.sh + - /var/log/aerial:/var/log/aerial + - ../../../cmake_targets/share:/opt/cuBB/share + userns_mode: host + ipc: "shareable" + image: cubb-build:25-2.1_srs-ul-heavy + environment: + - cuBB_SDK=/opt/nvidia/cuBB + command: bash -c "sudo rm -rf /tmp/phy.log && sudo chmod +x /opt/nvidia/cuBB/aerial_l1_entrypoint.sh && /opt/nvidia/cuBB/aerial_l1_entrypoint.sh" + healthcheck: + test: ["CMD-SHELL",'grep -q "L1 is ready!" /tmp/phy.log && echo 0 || echo 1'] + interval: 20s + timeout: 5s + retries: 5 + oai-gnb-aerial: + cpuset: "13-16" + image: ${REGISTRY:-oaisoftwarealliance}/oai-gnb-aerial:${TAG:-develop} + depends_on: + nv-cubb: + condition: service_healthy + cap_drop: + - ALL + cap_add: + - SYS_NICE + - IPC_LOCK + ipc: "container:nv-cubb" + environment: + USE_ADDITIONAL_OPTIONS: --log_config.global_log_options level,nocolor,time + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: + - gpu + network_mode: host + shm_size: 4096m + volumes: + - ../../conf_files/gnb-vnf.sa.band78.273prb.aerial.ul-heavy.conf:/opt/oai-gnb/etc/gnb.conf + container_name: oai-gnb-aerial + healthcheck: + test: /bin/bash -c "ps aux | grep -v grep | grep -c softmodem" + interval: 10s + timeout: 5s + retries: 5 diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 5e9bfaf444..658b0b858a 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -34,19 +34,14 @@ source "$THIS_SCRIPT_PATH"/tools/build_helper set_openair_env # Variables for UE data generation -gen_nvram_path=$OPENAIR_DIR/cmake_targets/ran_build/build conf_nvram_path=$OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf HW="" -VERBOSE_COMPILE=0 -RUN_GROUP=0 -TEST_CASE_GROUP="" BUILD_DIR=ran_build -BUILD_DOXYGEN=0 DISABLE_HARDWARE_DEPENDENCY="False" CMAKE_BUILD_TYPE="RelWithDebInfo" CMAKE_CMD="$CMAKE" -OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 ldpc_xdma websrv oai_iqplayer imscope imscope_record" +OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_aal ldpc_xdma websrv oai_iqplayer imscope imscope_record" TARGET_LIST="" BUILD_TOOL_OPT="-j$(nproc)" @@ -93,23 +88,15 @@ Options: Makes the NR UE softmodem --UE-conf-nvram [configuration file] Specify conf_nvram_path (default \"$conf_nvram_path\") ---UE-gen-nvram [output path] - Specify gen_nvram_path (default \"$gen_nvram_path\") -w | --hardware USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default) Adds this RF board support (in external packages installation and in compilation) -t | --transport - Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g, oran_fhlib_5g_mplane + Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g, oran_fhlib_5g_mplane, WLS -P | --phy_simulators Makes the unitary tests Layer 1 simulators --s | --check - runs a set of auto-tests based on simulators and several compilation tests ---run-group - runs only specified test cases specified here. This flag is only valid with -s -V | --vcd Adds a debgging facility to the binary files: GUI with major internal synchronization events ---verbose-compile - Shows detailed compilation instructions in makefile --build-doxygen Builds doxygen based documentation. --trace-asn1c-enc-dec @@ -120,8 +107,6 @@ Options: Disables the T tracer. --disable-hardware-dependency Disable HW dependency during installation ---ue-autotest-trace - Enable specific traces for UE autotest framework --ue-trace Enable traces for UE debugging --ue-timing @@ -244,7 +229,7 @@ function main() { shift;; --UE) UE=1 - TARGET_LIST="$TARGET_LIST lte-uesoftmodem" + TARGET_LIST="$TARGET_LIST lte-uesoftmodem conf2uedata usim nvram" echo_info "Will compile UE" shift;; --nrUE) @@ -259,9 +244,6 @@ function main() { --UE-conf-nvram) conf_nvram_path=$(readlink -f "$2") shift 2;; - --UE-gen-nvram) - gen_nvram_path=$(readlink -f "$2") - shift 2;; -w | --hardware) case "$2" in "USRP" | "BLADERF" | "LMSSDR" | "IRIS") @@ -308,6 +290,9 @@ function main() { TARGET_LIST="$TARGET_LIST $2" CMAKE_CMD="$CMAKE_CMD -DOAI_FHI72=ON -DOAI_FHI72_MPLANE=ON" ;; + "WLS"|"Wls"|"wls") + CMAKE_CMD="$CMAKE_CMD -DOAI_WLS=ON" + ;; "None") ;; *) @@ -322,28 +307,14 @@ function main() { TARGET_LIST="$TARGET_LIST dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim nr_psbchsim" echo_info "Will compile dlsim, ulsim, ..." shift;; - -s | --check) - OAI_TEST=1 - echo_info "Will run auto-tests" - shift;; - --run-group) - RUN_GROUP=1 - TEST_CASE_GROUP=$2 - echo_info "executing test cases only in group: $TEST_CASE_GROUP" - shift 2;; -V | --vcd) echo_info "Setting gtk-wave output" CMAKE_CMD="$CMAKE_CMD -DENABLE_VCD_FIFO=True" shift;; - --verbose-compile) - VERBOSE_COMPILE=1 - echo_info "Will compile with verbose instructions" - shift;; --build-doxygen) CMAKE_CMD="$CMAKE_CMD -DGENERATE_DOXYGEN=ON" - TARGET_LIST="$TARGET_LIST doc" - BUILD_DOXYGEN=1 - echo_info "Will build doxygen support" + TARGET_LIST="$TARGET_LIST doc" + echo_info "Will build Doxygen documentation: $DIR/$BUILD_DIR/build/doc/html/index.html" shift;; --enable-LTTNG) CMAKE_CMD="$CMAKE_CMD -DENABLE_LTTNG=ON -DT_TRACER=OFF" @@ -358,10 +329,6 @@ function main() { echo_info "Disabling hardware dependency for compiling software" DISABLE_HARDWARE_DEPENDENCY="True" shift 1;; - --ue-autotest-trace) - CMAKE_CMD="$CMAKE_CMD -DUE_AUTOTEST_TRACE=True" - echo_info "Enabling autotest specific trace for UE" - shift 1;; --ue-trace) CMAKE_CMD="$CMAKE_CMD -DUE_DEBUG_TRACE=False" echo_info "Enabling UE trace for debug" @@ -490,7 +457,7 @@ function main() { # add some default libraries that should always be built # for eNB, gNB, UEs, simulators if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 ]]; then - TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim" + TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml vrtsim rf_emulator" fi mkdir -p $DIR/$BUILD_DIR/build @@ -501,27 +468,13 @@ function main() { CMAKE_CMD="$CMAKE_CMD ../../.." echo_info "Running \"$CMAKE_CMD\"" eval $CMAKE_CMD - compilations $BUILD_DIR all.txt "$TARGET_LIST" "${BUILD_TOOL_OPT}" - ################### - # Doxygen Support # - ################### - if [ "$BUILD_DOXYGEN" = "1" ] ; then - echo_info "Built Doxygen based documentation. The documentation file is located here: $DIR/$BUILD_DIR/build/doc/html/index.html" - fi + cmd="$CMAKE --build . --target ${TARGET_LIST} -- ${BUILD_TOOL_OPT}" + echo_info "Running \"${cmd}\"" $green + eval $cmd + ret=$? if [ "$UE" = 1 ] ; then - - echo_info "Compiling UE specific part" - - [ "$CLEAN" = "1" ] && rm -rf $DIR/nas_sim_tools/build - mkdir -p $DIR/nas_sim_tools/build - cd $DIR/nas_sim_tools/build - - ${CMAKE_CMD% *} .. - compilations nas_sim_tools usim.txt "usim" "${BUILD_TOOL_OPT}" - compilations nas_sim_tools nvram.txt "nvram" "${BUILD_TOOL_OPT}" - compilations nas_sim_tools conf2uedata.txt "conf2uedata" "${BUILD_TOOL_OPT}" - + echo_info "Generate LTE USIM default sim content UE specific part" # generate USIM data if [ -f conf2uedata ]; then install_nas_tools $conf_nvram_path $DIR/$BUILD_DIR/build "$DIR/$BUILD_DIR/build/conf2uedata.txt" @@ -531,26 +484,7 @@ function main() { fi fi - - ############## - # Auto-tests # - ############## - if [ "$OAI_TEST" = "1" ] ; then - echo_info "The log file for the autotest script for debugging is located here: $OPENAIR_DIR/cmake_targets/autotests/log/autotests.log " - echo_info "The results of autotests results is located here: $OPENAIR_DIR/cmake_targets/autotests/log/results_autotests.xml " - echo_info "You can hit CTRL-C at any time to terminate the autotests..." - rm -fr $OPENAIR_DIR/cmake_targets/autotests/log - mkdir -p $OPENAIR_DIR/cmake_targets/autotests/log - if [ "$RUN_GROUP" -eq "1" ]; then - $OPENAIR_DIR/cmake_targets/autotests/run_exec_autotests.bash -g "$TEST_CASE_GROUP" >& $OPENAIR_DIR/cmake_targets/autotests/log/autotests.log - else - $OPENAIR_DIR/cmake_targets/autotests/run_exec_autotests.bash >& $OPENAIR_DIR/cmake_targets/autotests/log/autotests.log - fi - wait - else - echo_success "BUILD SHOULD BE SUCCESSFUL" - fi - + echo_success "BUILD SHOULD BE SUCCESSFUL" } main "$@" diff --git a/cmake_targets/cross-arm.cmake b/cmake_targets/cross-arm.cmake index 9480fc0fe0..09d6b25e70 100644 --- a/cmake_targets/cross-arm.cmake +++ b/cmake_targets/cross-arm.cmake @@ -1,8 +1,8 @@ set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) -set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc-11) -set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++-11) +set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc) +set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++) set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/aarch64-linux-gnu/pkgconfig") diff --git a/cmake_targets/nas_sim_tools/CMakeLists.txt b/cmake_targets/nas_sim_tools/CMakeLists.txt deleted file mode 100755 index 98b0772582..0000000000 --- a/cmake_targets/nas_sim_tools/CMakeLists.txt +++ /dev/null @@ -1,79 +0,0 @@ -cmake_minimum_required(VERSION 3.5) - -project(NAS_SIM_TOOLS) - -include(FindPkgConfig) -pkg_search_module(CONFIG libconfig REQUIRED) -include_directories(${CONFIG_INCLUDE_DIRS}) -add_definitions(-std=gnu99) -include("../macros.cmake") - -ENABLE_LANGUAGE(C) - -set(CMAKE_C_FLAGS - "${CMAKE_C_FLAGS} ${C_FLAGS_PROCESSOR} -Werror -Wall -Wstrict-prototypes -g") - -set(OPENAIR_DIR $ENV{OPENAIR_DIR}) -set(OPENAIR3_DIR $ENV{OPENAIR_DIR}/openair3) -include_directories (${OPENAIR_DIR}/openair2/COMMON) -include_directories (${OPENAIR_DIR}) - -set(CONF2UEDATA_LIB_SRC - ${OPENAIR_DIR}/openair3/NAS/TOOLS/conf_emm.c - ${OPENAIR_DIR}/openair3/NAS/TOOLS/conf_user_data.c - ${OPENAIR_DIR}/openair3/NAS/TOOLS/conf_usim.c - ${OPENAIR_DIR}/openair3/NAS/TOOLS/conf_network.c - ${OPENAIR_DIR}/openair3/NAS/TOOLS/conf_user_plmn.c - ${OPENAIR_DIR}/openair3/NAS/TOOLS/conf_parser.c - ${OPENAIR_DIR}/openair3/NAS/TOOLS/fs.c - ${OPENAIR_DIR}/openair3/NAS/TOOLS/display.c - ${OPENAIR_DIR}/openair3/NAS/UE/API/USIM/usim_api.c - ${OPENAIR_DIR}/openair3/NAS/UE/API/USIM/aka_functions.c - ${OPENAIR_DIR}/common/utils/mem/memory.c - ${OPENAIR_DIR}/openair3/NAS/COMMON/UTIL/OctetString.c - ${OPENAIR_DIR}/common/utils/utils.c -) - -include_directories( - ${OPENAIR_DIR}/common/utils - ${OPENAIR_DIR}/openair3/NAS/UE - ${OPENAIR_DIR}/openair3/NAS/COMMON - ${OPENAIR_DIR}/openair3/NAS/UE/API/USER - ${OPENAIR_DIR}/openair3/NAS/UE/API/USIM - ${OPENAIR_DIR}/openair3/NAS/UE/EMM/ - ${OPENAIR_DIR}/openair3/NAS/UE/ESM/ - ${OPENAIR_DIR}/openair3/NAS/COMMON/IES/ - ${OPENAIR_DIR}/openair3/NAS/COMMON/UTIL -) - -# conf2uedata binary - -set(conf2uedata_SRC - ${OPENAIR_DIR}/openair3/NAS/TOOLS/conf2uedata.c - ${CONF2UEDATA_LIB_SRC} -) - -add_executable(conf2uedata ${conf2uedata_SRC} ) -target_link_libraries(conf2uedata ${CONFIG_LIBRARIES}) - -# usim binary - -set(usim_SRC - ${OPENAIR_DIR}/openair3/NAS/TOOLS/usim.c - ${CONF2UEDATA_LIB_SRC} -) - - -add_executable(usim ${usim_SRC} ) -target_link_libraries(usim ${CONFIG_LIBRARIES}) - -# nvram binary - -set(nvram_SRC - ${OPENAIR_DIR}/openair3/NAS/TOOLS/nvram.c - ${CONF2UEDATA_LIB_SRC} -) - - -add_executable(nvram ${nvram_SRC}) -target_link_libraries(nvram ${CONFIG_LIBRARIES}) diff --git a/cmake_targets/tools/MODULES/FindSCTP.cmake b/cmake_targets/tools/MODULES/FindSCTP.cmake deleted file mode 100755 index de8e878a99..0000000000 --- a/cmake_targets/tools/MODULES/FindSCTP.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# - Try to find SCTP library and headers -# Once done, this will define -# -# SCTP_FOUND - system has SCTP -# SCTP_INCLUDE_DIR - the SCTP include directories -# SCTP_LIBRARIES - link these to use SCTP - -if (SCTP_INCLUDE_DIR AND SCTP_LIBRARIES) - set(SCTP_FIND_QUIETLY TRUE) -endif (SCTP_INCLUDE_DIR AND SCTP_LIBRARIES) - -# Include dir -find_path(SCTP_INCLUDE_DIR - NAMES netinet/sctp.h -) - -# Library -find_library(SCTP_LIBRARY - NAMES sctp -) - -# Set the include dir variables and the libraries and let libfind_process do the rest. -# NOTE: Singular variables for this library, plural for libraries this this lib depends on. -#set(SCTP_PROCESS_INCLUDES SCTP_INCLUDE_DIR) -#set(SCTP_PROCESS_LIBS SCTP_LIBRARY) -#libfind_process(SCTP) - - -# handle the QUIETLY and REQUIRED arguments and set SCTP_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SCTP DEFAULT_MSG SCTP_LIBRARY SCTP_INCLUDE_DIR) - -# If we successfully found the sctp library then add the library to the -# SCTP_LIBRARIES cmake variable otherwise set SCTP_LIBRARIES to nothing. -IF(SCTP_FOUND) - SET( SCTP_LIBRARIES ${SCTP_LIBRARY} ) -ELSE(SCTP_FOUND) - SET( SCTP_LIBRARIES ) -ENDIF(SCTP_FOUND) - - -# Lastly make it so that the SCTP_LIBRARY and SCTP_INCLUDE_DIR variables -# only show up under the advanced options in the gui cmake applications. -MARK_AS_ADVANCED( SCTP_LIBRARY SCTP_INCLUDE_DIR ) - diff --git a/cmake_targets/tools/MODULES/Findsctp.cmake b/cmake_targets/tools/MODULES/Findsctp.cmake new file mode 100644 index 0000000000..44e3ee6a2b --- /dev/null +++ b/cmake_targets/tools/MODULES/Findsctp.cmake @@ -0,0 +1,64 @@ +# - Try to find SCTP library and headers +# +# Imported Targets +# ^^^^^^^^^^^^^^^^ +# +# This module provides the following imported targets, if found: +# +# ``sctp::sctp`` +# The SCTP library +# +# Result Variables +# ^^^^^^^^^^^^^^^^ +# +# this will define +# +# sctp_FOUND - system has SCTP +# sctp_INCLUDE_DIRS - the SCTP include directories +# sctp_LIBRARIES - link these to use SCTP + +# Include dir +find_path(sctp_INCLUDE_DIR + NAMES netinet/sctp.h +) + +# Library +find_library(sctp_LIBRARY + NAMES sctp +) + +# Set the include dir variables and the libraries and let libfind_process do the rest. +# NOTE: Singular variables for this library, plural for libraries this this lib depends on. +#set(sctp_PROCESS_INCLUDES sctp_INCLUDE_DIR) +#set(sctp_PROCESS_LIBS sctp_LIBRARY) +#libfind_process(sctp) + + +# handle the QUIETLY and REQUIRED arguments and set sctp_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(sctp + FOUND_VAR sctp_FOUND + REQUIRED_VARS + sctp_LIBRARY + sctp_INCLUDE_DIR +) + +# If we successfully found the sctp library then add the library to the +# sctp_LIBRARIES cmake variable otherwise set sctp_LIBRARIES to nothing. +if(sctp_FOUND) + set(sctp_LIBRARIES ${sctp_LIBRARY}) + set(sctp_INCLUDE_DIRS ${sctp_INCLUDE_DIR}) +endif() + +if(sctp_FOUND AND NOT TARGET sctp::sctp) + add_library(sctp::sctp UNKNOWN IMPORTED) + set_target_properties(sctp::sctp PROPERTIES + IMPORTED_LOCATION "${sctp_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${sctp_INCLUDE_DIRS}" + ) +endif() + +# Lastly make it so that the SCTP_LIBRARY and SCTP_INCLUDE_DIR variables +# only show up under the advanced options in the gui cmake applications. +mark_as_advanced(SCTP_LIBRARY SCTP_INCLUDE_DIR) diff --git a/cmake_targets/tools/MODULES/Findxran.cmake b/cmake_targets/tools/MODULES/Findxran.cmake index 1ade3ac522..369f04753f 100644 --- a/cmake_targets/tools/MODULES/Findxran.cmake +++ b/cmake_targets/tools/MODULES/Findxran.cmake @@ -126,12 +126,9 @@ find_package_handle_standard_args(xran VERSION_VAR xran_VERSION ) -# in proper usage of cmake, include directory should only contain "api", but not header files under "src" directory; -# however, we use xran_dev_get_ctx() and xran_dev_get_ctx_by_id() functions which are defined in xran_common.h; -# since xran_common.h is under "src" directory, we have to include it in ${xran_INCLUDE_DIRS} if(xran_FOUND) set(xran_LIBRARIES ${xran_LIBRARY}) - set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR} ${xran_INCLUDE_DIR}/../src) + set(xran_INCLUDE_DIRS ${xran_INCLUDE_DIR}) endif() if(xran_FOUND AND NOT TARGET xran::xran) diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 264e26d890..eeffc9d4f1 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -177,78 +177,16 @@ clean_all_files() { dir=$OPENAIR_DIR/cmake_targets rm -rf $dir/ran_build $dir/ran_build_noLOG rm -rf $dir/lte-simulators/build - rm -rf $dir/nas_sim_tools/build rm -rf $dir/oaisim_build_oai/build $dir/oaisim_build_oai/CMakeLists.txt rm -rf $dir/autotests/bin $dir/autotests/log $dir/autotests/*/build } -################################### -# Compilers -################################### - -#check_warnings: -# print error message if the compilation had warnings -#argument: -# $1: log file -check_warnings() { - #we look for 'warning:' in the compilation log file - #this is how gcc starts a warning - #this is not perfect, we may get false positive - warning_count=`grep "warning:" "$1" | grep -E -v "jobserver unavailable|disabling jobserver mode" | wc -l` - if [ $warning_count -gt 0 ]; then - echo_error "WARNING: $warning_count warnings. See $1" - fi -} - -#check_errors: -# print error message if the compilation had errors -#argument: -# $1: log file -check_errors() { - #we look for 'error:' in the compilation log file - error_count=`grep -c "error:" "$1"` - if [ $error_count -gt 0 ]; then - echo_error "ERROR: $error_count error. See $1" - fi -} - -compilations() { - [[ $# -eq 4 ]] || echo_fatal "compilations " - local dir=$1 - local logfile=$2 - local targets=$3 - local build_tool_opt=$4 - local verbose=$([ "$VERBOSE_COMPILE" == "1" ] && echo "-v" || echo "") - echo cd $OPENAIR_DIR/cmake_targets/$dir/build - cd $OPENAIR_DIR/cmake_targets/$dir/build - cmd="$CMAKE --build . ${verbose} --target ${targets} -- ${build_tool_opt}" - echo_info "Running \"${cmd}\"" $green - echo "Log file for compilation is being written to: $dlog/$logfile" - set +e - { - eval ${cmd} - ret=$? - } > $dlog/$logfile 2>&1 - # Print the errors and warnings for CI purposes - grep -E -A5 -B5 "warning:|error:| Error " $dlog/$logfile || true - check_warnings "$dlog/$logfile" - if [[ $ret -eq 0 ]]; then - echo_success "$targets compiled" - else - check_errors "$dlog/$logfile" - echo_error "compilation of $targets failed" - exit 1 - fi -} - ############################################ # External packages installers ############################################ install_usrp_uhd_driver_from_source(){ - uhd_install_log=$OPENAIR_DIR/cmake_targets/log/uhd_install_log.txt - echo_info "\nInstalling UHD driver from sources. The log file for UHD driver installation is here: $uhd_install_log " - ( + echo_info "\nInstalling UHD driver from sources." pushd /tmp echo "Cloning UHD driver repository" rm -rf /tmp/uhd @@ -264,7 +202,7 @@ install_usrp_uhd_driver_from_source(){ # - 3.15.0.0 git apply $OPENAIR_DIR/cmake_targets/tools/uhd-3.15-tdd-patch.diff ret=$?;[[ $ret -ne 0 ]] && echo_fatal "Could not apply the TDD patch" - elif [[ "$UHD_VERSION" == "4.7.0.0" || "$UHD_VERSION" == "4.6.0.0" || "$UHD_VERSION" == "4.5.0.0" ]]; then + elif [[ "$UHD_VERSION" == "4.8.0.0" || "$UHD_VERSION" == "4.7.0.0" || "$UHD_VERSION" == "4.6.0.0" || "$UHD_VERSION" == "4.5.0.0" ]]; then # Tested that patch for the following versions: # - 4.7.0.0 cp $OPENAIR_DIR/cmake_targets/tools/uhd-4.x-tdd-patch.diff $OPENAIR_DIR/cmake_targets/tools/uhd-4.5plus-tdd-patch.diff @@ -293,7 +231,7 @@ install_usrp_uhd_driver_from_source(){ git diff mkdir -p host/build cd host/build || true - $CMAKE ../ -GNinja -DENABLE_TESTS=OFF -DENABLE_EXAMPLES=OFF + $CMAKE ../ -GNinja -DENABLE_TESTS=OFF -DENABLE_EXAMPLES=OFF -DENABLE_B100=OFF -DENABLE_DOXYGEN=OFF -DENABLE_MANUAL=OFF -DENABLE_MAN_PAGES=OFF -DENABLE_MAN_PAGE_COMPRESSION=OFF -DENABLE_OCTOCLOCK=ON -DENABLE_USRP1=OFF -DENABLE_USRP2=OFF echo "Compiling UHD" ninja $SUDO ninja install @@ -308,25 +246,13 @@ install_usrp_uhd_driver_from_source(){ fi popd rm -rf /tmp/uhd - ) >& $uhd_install_log } check_install_usrp_uhd_driver(){ if [[ "$OS_BASEDISTRO" == "debian" ]]; then boost_libs_ubuntu="libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-program-options-dev libboost-thread-dev libboost-test-dev libboost-regex-dev" #first we remove old installation - $SUDO apt-get remove uhd -y || true - $SUDO apt-get remove uhd-host -y || true - $SUDO apt-get remove libuhd-dev -y || true - $SUDO apt-get remove libuhd003 -y || true - $SUDO apt-get remove libuhd3.13.1 -y || true - $SUDO apt-get remove libuhd3.14.0 -y || true - $SUDO apt-get remove libuhd3.14.1 -y || true - $SUDO apt-get remove libuhd3.15.0 -y || true - local distribution=$(get_distribution_release) - if [[ "$distribution" == "ubuntu20.04" || "$distribution" == "ubuntu22.04" ]]; then - $SUDO apt-get remove libuhd4.?.? -y || true - fi + $SUDO apt-get remove uhd* libuhd* -y || true v=$(lsb_release -cs) $SUDO apt-add-repository --remove "deb http://files.ettus.com/binaries/uhd/repo/uhd/ubuntu/$v $v main" if [[ -v BUILD_UHD_FROM_SOURCE ]] || [[ "$OS_DISTRO" == "debian" ]]; then @@ -405,9 +331,7 @@ install_usrp_uhd_driver() { } install_bladerf_driver_from_source(){ - bladerf_install_log=$OPENAIR_DIR/cmake_targets/log/bladerf_install_log.txt - echo_info "\nInstalling BladeRF driver from sources. The log file for BladeRF driver installation is here: $bladerf_install_log " - ( + echo_info "\nInstalling BladeRF driver from sources." cd /tmp echo "Downloading BladeRF driver" rm -rf /tmp/bladeRF @@ -430,7 +354,6 @@ install_bladerf_driver_from_source(){ sudo mkdir -p /usr/share/Nuand/bladeRF sudo mv bladeRF_fw_latest.img /usr/share/Nuand/bladeRF/bladeRF_fw.img sudo mv hostedx40-latest.rbf /usr/share/Nuand/bladeRF/hostedx40.rbf - ) >& $bladerf_install_log } check_install_bladerf_driver(){ @@ -465,9 +388,7 @@ check_install_lmssdr_driver(){ } install_soapy_from_source(){ - soapy_install_log=$OPENAIR_DIR/cmake_targets/log/soapy_install_log.txt - echo_info "\nInstalling Soapy EcoSystem from source. The log file for Soapy installation is here: $soapy_install_log " - ( + echo_info "\nInstalling Soapy EcoSystem from source." cd /tmp echo "Downloading SoapySDR" rm -rf /tmp/SoapySDR @@ -494,13 +415,10 @@ install_soapy_from_source(){ make -j`nproc` $SUDO make install $SUDO ldconfig - ) >& $soapy_install_log } install_soapy_iris_from_source(){ - iris_install_log=$OPENAIR_DIR/cmake_targets/log/iris_install_log.txt - echo_info "\nInstalling Iris driver from source. The log file for Iris driver installation is here: $iris_install_log " - ( + echo_info "\nInstalling Iris driver from source." cd /tmp echo "Downloading SoapyIris" rm -rf /tmp/sklk-soapyiris @@ -513,7 +431,6 @@ install_soapy_iris_from_source(){ make -j`nproc` $SUDO make install $SUDO ldconfig - ) >& $iris_install_log } check_install_soapy () { @@ -645,10 +562,7 @@ check_install_oai_software() { } install_asn1c_from_source(){ - mkdir -p $OPENAIR_DIR/cmake_targets/log - asn1_install_log=$OPENAIR_DIR/cmake_targets/log/asn1c_install_log.txt - echo_info "\nInstalling ASN1. The log file for ASN1 installation is here: $asn1_install_log " - ( + echo_info "\nInstalling ASN1." $SUDO $INSTALLER -y install bison flex $SUDO rm -rf /tmp/asn1c # GIT_SSL_NO_VERIFY=true git clone https://gitlab.eurecom.fr/oai/asn1c.git /tmp/asn1c @@ -661,7 +575,7 @@ install_asn1c_from_source(){ # Showing which version is used git log -n1 autoreconf -iv - ./configure --prefix /opt/asn1c/ + CFLAGS="-O2 -fno-strict-aliasing" ./configure --prefix /opt/asn1c/ make -j`nproc` $SUDO make install cd - @@ -669,7 +583,6 @@ install_asn1c_from_source(){ if [[ -v CI_ENV ]]; then $SUDO rm -rf /tmp/asn1c fi - ) > $asn1_install_log 2>&1 } install_simde_from_source(){ @@ -809,43 +722,3 @@ set_openair_env(){ export OPENAIR3_DIR=$openair_path/openair3 export OPENAIR_TARGETS=$openair_path/targets } - -################################ -# Function to killall the subprocesses when Ctrl-C Key is hit -############################### -function handle_ctrl_c(){ -CURPID=$$ -ppid=$$ -arraycounter=1 -echo_info "** Trapped CTRL-C. Killing all subprocesses now..." -echo_info "** Calling sync now..." -sync -while true -do - FORLOOP=FALSE - # Get all the child process id - for i in `ps -ef| awk '$3 == '$ppid' { print $2 }'` - do - if [ $i -ne $CURPID ] ; then - procid[$arraycounter]=$i - arraycounter=`expr $arraycounter + 1` - ppid=$i - FORLOOP=TRUE - fi - done - if [ "$FORLOOP" = "FALSE" ] ; then - arraycounter=`expr $arraycounter - 1` - ## We want to kill child process id first and then parent id's - while [ $arraycounter -ne 0 ] - do - echo "first we send ctrl-c to program" - $SUDO kill -INT "${procid[$arraycounter]}" - sleep 5 - echo "Now we force kill if that didn't work" - $SUDO kill -9 "${procid[$arraycounter]}" >/dev/null - arraycounter=`expr $arraycounter - 1` - done - exit - fi -done -} diff --git a/cmake_targets/tools/install_wls_lib.patch b/cmake_targets/tools/install_wls_lib.patch new file mode 100644 index 0000000000..5050b79a4e --- /dev/null +++ b/cmake_targets/tools/install_wls_lib.patch @@ -0,0 +1,209 @@ +diff --git a/wls_lib/Makefile b/wls_lib/Makefile +index 2f8e4b2..e657488 100644 +--- a/wls_lib/Makefile ++++ b/wls_lib/Makefile +@@ -1,20 +1,6 @@ +-############################################################################### +-# +-# Copyright (c) 2021 Intel. +-# +-# Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +-# +-# 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. +-# +-############################################################################### ++################################################################ ++# ++################################################################ + + MYCUSTOMTAB=' ' + MYCUSTOMSPACE='============================================================================================' +@@ -24,11 +10,17 @@ MYCUSTOMSPACE1='------------------------------------------------------------' + # Tools configuration + ############################################################## + ifeq ($(WIRELESS_SDK_TOOLCHAIN),icc) +-CC := icc ++ CC := icc + CPP := icpc +-AS := as +-AR := ar +-LD := icc ++ AS := as ++ AR := ar ++ LD := icc ++else ifeq ($(WIRELESS_SDK_TOOLCHAIN),gcc) ++ CC := gcc ++ CPP := g++ ++ AS := as ++ AR := ar ++ LD := gcc + else ifeq ($(WIRELESS_SDK_TOOLCHAIN),icx) + CC := icx + CPP := icx +@@ -44,9 +36,9 @@ ifeq ($(WIRELESS_SDK_TARGET_ISA),sse) + else ifeq ($(WIRELESS_SDK_TARGET_ISA),avx2) + TARGET_PROCESSOR := -xCORE-AVX2 + else ifeq ($(WIRELESS_SDK_TARGET_ISA),avx512) +- TARGET_PROCESSOR := -xCORE-AVX512 ++ TARGET_PROCESSOR := -march=skylake-avx512 + else ifeq ($(WIRELESS_SDK_TARGET_ISA),snc) +- TARGET_PROCESSOR := -xicelake-server ++ TARGET_PROCESSOR := -march=icelake-server + else ifeq ($(WIRELESS_SDK_TARGET_ISA),spr) + TARGET_PROCESSOR := -march=sapphirerapids + endif +@@ -66,15 +58,38 @@ PROJECT_DIR := ./ + BUILDDIR := make + PROJECT_BINARY := $(PROJECT_NAME).so + ++PKGCONF ?= pkg-config ++LIBDPDK_VERSION=20.11.3 ++ ++ifeq ($(shell $(PKGCONF) --modversion "libdpdk = '$(LIBDPDK_VERSION)'"),$(LIBDPDK_VERSION)) ++ DPDK_INSTALLED=1 ++else ++ DPDK_INSTALLED=0 ++endif ++ + ifeq ($(RTE_SDK),) +-$(error "Please define RTE_SDK environment variable") ++ifeq ($(DPDK_INSTALLED),0) ++$(error "Please define RTE_SDK environment variable OR install DPDK version $(LIBDPDK_VERSION)") ++endif + endif + +-RTE_INC := $(shell PKG_CONFIG_PATH=/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkgconf --cflags-only-I libdpdk) ++# At least one of the options is defined ++ ++ifneq ($(RTE_SDK),) ++ RTE_INC := $(shell PKG_CONFIG_PATH=/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkgconf --cflags-only-I libdpdk) ++else ifeq ($(DPDK_INSTALLED),1) ++ RTE_INC := $(shell PKG_CONFIG_PATH=/usr/lib64/pkgconfig $(PKGCONF) --cflags-only-I libdpdk) ++endif + + CC_SRC = wls_lib_dpdk.c \ + syslib.c + ++CC_HDR = syslib.h \ ++ ttypes.h \ ++ wls.h \ ++ wls_debug.h \ ++ wls_lib.h ++ + CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \ + -fdata-sections \ + -ffunction-sections \ +@@ -84,18 +99,19 @@ CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \ + -Wimplicit-function-declaration \ + -g -O3 -mcmodel=large $(TARGET_PROCESSOR) + +-INC := -I$(RTE_INC) ++INC := -I$(RTE_INC) -I../intel_fapi/ + DEF := + + AS_FLAGS := + AR_FLAGS := rc + + PROJECT_OBJ_DIR := $(BUILDDIR)/obj ++PROJECT_DEP_DIR := $(PROJECT_OBJ_DIR)/$(PROJECT_NAME).dep.d + + CC_OBJS := $(patsubst %.c,%.o,$(CC_SRC)) + AS_OBJS := $(patsubst %.s,%.o,$(AS_SRC)) + OBJS := $(CC_OBJS) $(AS_OBJS) $(LIBS) +-DIRLIST := $(addprefix $(PROJECT_OBJ_DIR)/,$(sort $(dir $(OBJS)))) ++DIRLIST := $(addprefix $(PROJECT_OBJ_DIR)/,$(sort $(dir $(OBJS)))) $(PROJECT_DEP_DIR) + + CC_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(CC_OBJS)) + +@@ -104,9 +120,7 @@ CC_FLAGS_FULL := $(CC_FLAGS) $(INC) $(DEF) + + AS_FLAGS := $(AS_FLAGS) $(INC) + +-PROJECT_DEP_FILE := $(PROJECT_OBJ_DIR)/$(PROJECT_NAME).dep +- +-ifeq ($(wildcard $(PROJECT_DEP_FILE)),$(PROJECT_DEP_FILE)) ++ifeq ($(wildcard $(PROJECT_DEP_DIR)),$(PROJECT_DEP_DIR)) + GENERATE_DEPS := + else + +@@ -119,11 +133,11 @@ all : welcome_line $(PROJECT_BINARY) + + .PHONY : clear_dep + clear_dep: +- @$(RM) $(PROJECT_DEP_FILE) +- @echo [DEP] $(subst $(PROJECT_OBJ_DIR)/,,$(PROJECT_DEP_FILE)) ++ @echo [DEP] rm $(PROJECT_DEP_DIR)/$(@F).dep ++ @$(RM) $(PROJECT_DEP_DIR)/$(@F).dep + +-$(CC_DEPS) : +- @$(CC) -MM $(subst __up__,../,$(subst __dep__,,$@)) -MT $(PROJECT_OBJ_DIR)/$(patsubst %.c,%.o,$(subst __up__,../,$(subst __dep__,,$@))) $(CC_FLAGS_FULL) >> $(PROJECT_DEP_FILE) ++$(CC_DEPS) : $(PROJECT_DEP_DIR) ++ @$(CC) $(CC_FLAGS_FULL) -MM $(subst __up__,../,$(subst __dep__,,$@)) -MT $(PROJECT_OBJ_DIR)/$(patsubst %.c,%.o,$(subst __up__,../,$(subst __dep__,,$@))) >> $(PROJECT_DEP_DIR)/$(@F).dep + + .PHONY : generate_deps + generate_deps : clear_dep $(CC_DEPS) +@@ -136,17 +150,17 @@ echo_start_build : + $(DIRLIST) : + -@$(MD) $@ + +-$(CC_OBJTARGETS) : ++$(CC_OBJTARGETS) : $(GENERATE_DEPS) + @echo [CC] $(subst $(PROJECT_OBJ_DIR)/,,$@) + @$(CC) -c $(CC_FLAGS_FULL) -o"$@" $(patsubst %.o,%.c,$(subst $(PROJECT_OBJ_DIR)/,,$@)) + +-$(AS_OBJTARGETS) : ++$(AS_OBJTARGETS) : $(CC_OBJTARGETS) $(CPP_OBJTARGETS) + @echo [AS] $(subst $(PROJECT_OBJ_DIR)/,,$@) + @$(AS) $(AS_FLAGS) -o"$@" $(patsubst %.o,%.s,$(subst $(PROJECT_OBJ_DIR)/,,$@)) + +-ifeq ($(wildcard $(PROJECT_DEP_FILE)),$(PROJECT_DEP_FILE)) ++ifeq ($(wildcard $(PROJECT_DEP_DIR)),$(PROJECT_DEP_DIR)) + +-include $(PROJECT_DEP_FILE) ++include $(PROJECT_DEP_DIR)/* + + endif + +@@ -156,7 +170,7 @@ clean: + @$(RM) $(CC_OBJTARGETS) $(AS_OBJTARGETS) + ifneq ($(wildcard $(PROJECT_DIR)/$(PROJECT_MAKE)),) + @echo [CLEAN] : $(PROJECT_NAME) +- @$(RM) $(PROJECT_BINARY) $(PROJECT_BINARY_LIB) $(PROJECT_DEP_FILE) ++ @$(RM) -rf $(PROJECT_BINARY) $(PROJECT_BINARY_LIB) $(PROJECT_DEP_DIR) + endif + + xclean: clean +@@ -172,7 +186,24 @@ welcome_line : + debug : all + release : all + +-$(PROJECT_BINARY) : $(DIRLIST) echo_start_build $(GENERATE_DEPS) $(PRE_BUILD) $(CC_OBJTARGETS) $(AS_OBJTARGETS) ++$(PROJECT_BINARY) : $(DIRLIST) echo_start_build $(GENERATE_DEPS) $(CC_OBJTARGETS) $(AS_OBJTARGETS) + @echo [AR] $(subst $(BUILDDIR)/,,$@) + @$(CC) $(CC_OBJTARGETS) $(AS_OBJTARGETS) -shared -fPIC -o $@ + ++############################################################## ++# Install configuration ++############################################################## ++ ++INSTALL_DIR := /usr/local ++INCLUDE_DIR := $(INSTALL_DIR)/include/ ++ ++.PHONY : install ++install: $(PROJECT_BINARY) install_headers ++ @echo [INSTALL] : $(PROJECT_BINARY) ++ @$(CP) $(PROJECT_BINARY) $(INSTALL_DIR)/lib ++ ++.PHONY : install_headers ++install_headers: $(CC_SRC) ++ @echo [INSTALL] : $(PROJECT_NAME) headers ++ @$(MD) $(INCLUDE_DIR) ++ @$(CP) $(CC_HDR) $(INCLUDE_DIR) diff --git a/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch b/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch index baa5378673..8d0610892a 100644 --- a/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch +++ b/cmake_targets/tools/oran_fhi_integration_patches/E/oaioran_E.patch @@ -1,5 +1,5 @@ diff --git a/fhi_lib/app/src/common.h b/fhi_lib/app/src/common.h -index 7508117..ce17ebd 100644 +index 7508117..318508b 100644 --- a/fhi_lib/app/src/common.h +++ b/fhi_lib/app/src/common.h @@ -28,7 +28,7 @@ @@ -7,12 +7,12 @@ index 7508117..ce17ebd 100644 #include -#define VERSIONX "oran_e_maintenance_release_v1.0" -+#define VERSIONX "oran_e_maintenance_release_v1.5" ++#define VERSIONX "oran_e_maintenance_release_v1.6" #define APP_O_DU 0 #define APP_O_RU 1 diff --git a/fhi_lib/lib/Makefile b/fhi_lib/lib/Makefile -index de141bf..fa2923f 100644 +index de141bf..c2a448d 100644 --- a/fhi_lib/lib/Makefile +++ b/fhi_lib/lib/Makefile @@ -23,12 +23,25 @@ MYCUSTOMSPACE1='------------------------------------------------------------' @@ -50,9 +50,9 @@ index de141bf..fa2923f 100644 -RTE_INC := $(shell PKG_CONFIG_PATH=/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkgconf --cflags-only-I libdpdk) +ifeq ($(TARGET), x86) -+RTE_INC := $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH):/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkgconf --cflags-only-I libdpdk) ++RTE_INC := $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH):/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkg-config --cflags-only-I libdpdk) +else ifeq ($(TARGET), armv8) -+RTE_INC := $(pkgconf --cflags-only-I libdpdk) ++RTE_INC := $(shell pkg-config --cflags-only-I libdpdk) +endif API_DIR := $(PROJECT_DIR)/api SRC_DIR := $(PROJECT_DIR)/src @@ -85,7 +85,7 @@ index de141bf..fa2923f 100644 CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \ -fdata-sections \ -@@ -112,12 +132,21 @@ CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \ +@@ -112,14 +132,23 @@ CC_FLAGS += -std=gnu11 -Wall -Wno-deprecated-declarations \ -fPIC \ -Wall \ -Wimplicit-function-declaration \ @@ -110,8 +110,11 @@ index de141bf..fa2923f 100644 + -Werror -Wno-unused-variable -std=c++14 +endif - INC := -I$(API_DIR) -I$(ETH_DIR) -I$(SRC_DIR) -I$(RTE_INC) +-INC := -I$(API_DIR) -I$(ETH_DIR) -I$(SRC_DIR) -I$(RTE_INC) ++INC := -I$(API_DIR) -I$(ETH_DIR) -I$(SRC_DIR) $(RTE_INC) DEF := + ifeq ($(MLOG),1) + INC += -I$(MLOG_DIR)/source @@ -150,8 +179,13 @@ CPP_SNC_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(CPP_OBJS_SNC)) AS_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(AS_OBJS)) diff --git a/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch b/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch index b8d09cf862..bec423b95e 100644 --- a/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch +++ b/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch @@ -1,5 +1,5 @@ diff --git a/fhi_lib/app/src/common.h b/fhi_lib/app/src/common.h -index ac5f471..9ebbcab 100644 +index ac5f471..5efcce3 100644 --- a/fhi_lib/app/src/common.h +++ b/fhi_lib/app/src/common.h @@ -28,7 +28,7 @@ @@ -7,12 +7,12 @@ index ac5f471..9ebbcab 100644 #include -#define VERSIONX "oran_f_release_v1.0" -+#define VERSIONX "oran_f_release_v1.3" ++#define VERSIONX "oran_f_release_v1.4" #define APP_O_DU 0 #define APP_O_RU 1 diff --git a/fhi_lib/lib/Makefile b/fhi_lib/lib/Makefile -index eccc4ae..b1b8f4b 100644 +index eccc4ae..a97fdc6 100644 --- a/fhi_lib/lib/Makefile +++ b/fhi_lib/lib/Makefile @@ -23,24 +23,46 @@ MYCUSTOMSPACE1='------------------------------------------------------------' @@ -83,9 +83,9 @@ index eccc4ae..b1b8f4b 100644 RTE_TARGET ?= x86_64-native-linux-icc -RTE_INC := $(shell PKG_CONFIG_PATH=/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkgconf --cflags-only-I libdpdk) +ifeq ($(TARGET), x86) -+RTE_INC := $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH):/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkgconf --cflags-only-I libdpdk) ++RTE_INC := $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH):/usr/lib64/pkgconfig:$(RTE_SDK)/build/meson-uninstalled pkg-config --cflags-only-I libdpdk) +else ifeq ($(TARGET), armv8) -+RTE_INC := $(pkgconf --cflags-only-I libdpdk) ++RTE_INC := $(shell pkg-config --cflags-only-I libdpdk) +endif API_DIR := $(PROJECT_DIR)/api @@ -147,6 +147,15 @@ index eccc4ae..b1b8f4b 100644 ifeq ($(WIRELESS_SDK_TOOLCHAIN),icc) CPP_FLAGS += -fp-model fast=2 -no-prec-div -no-prec-sqrt -fast-transcendentals -restrict +@@ -150,7 +187,7 @@ CPP_FLAGS += -fp-model fast -march=icelake-server -mintrinsic-promote -Wno-unus + endif + + +-INC := -I$(API_DIR) -I$(ETH_DIR) -I$(SRC_DIR) -I$(RTE_INC) ++INC := -I$(API_DIR) -I$(ETH_DIR) -I$(SRC_DIR) $(RTE_INC) + DEF := + ifeq ($(MLOG),1) + INC += -I$(MLOG_DIR)/source @@ -186,8 +223,13 @@ CPP_SNC_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(CPP_OBJS_SNC)) AS_OBJTARGETS := $(addprefix $(PROJECT_OBJ_DIR)/,$(AS_OBJS)) @@ -164,7 +173,7 @@ index eccc4ae..b1b8f4b 100644 CPP_FLAGS_FULL := $(CPP_FLAGS) $(CPP_COMP) $(INC) $(DEF) CPP_FLAGS_FULL_SNC := $(CPP_FLAGS) $(CPP_COMP_SNC) $(INC) $(DEF) diff --git a/fhi_lib/lib/api/xran_fh_o_du.h b/fhi_lib/lib/api/xran_fh_o_du.h -index bacf597..8bd7c66 100644 +index bacf597..1dd6d66 100644 --- a/fhi_lib/lib/api/xran_fh_o_du.h +++ b/fhi_lib/lib/api/xran_fh_o_du.h @@ -141,7 +141,7 @@ extern "C" { @@ -176,7 +185,15 @@ index bacf597..8bd7c66 100644 #define XRAN_MAX_SET_BFWS (64) /**< Assumed 64Ant, BFP 9bit with 9K jumbo frame */ #define XRAN_MAX_PKT_BURST (448+4) /**< 4x14x8 symbols per ms */ -@@ -1193,6 +1193,31 @@ int32_t xran_reg_physide_cb_by_dev_id(void *pHandle, xran_fh_tti_callback_fn Cb, +@@ -419,6 +419,7 @@ struct xran_io_cfg { + uint16_t num_rxq; /**< number of RX queues per VF */ + char *dpdk_dev[XRAN_VF_MAX]; /**< VFs devices */ + char *bbdev_dev[1]; /**< BBDev dev name */ ++ char *bbdev_vfio_vf_token[1]; /**< BBDev dev token */ + int32_t bbdev_mode; /**< DPDK for BBDev */ + uint32_t dpdkIoVaMode; /**< IOVA Mode */ + uint32_t dpdkMemorySize; /**< DPDK max memory allocation */ +@@ -1193,6 +1194,31 @@ int32_t xran_reg_physide_cb_by_dev_id(void *pHandle, xran_fh_tti_callback_fn Cb, */ int32_t xran_get_slot_idx (uint32_t PortId, uint32_t *nFrameIdx, uint32_t *nSubframeIdx, uint32_t *nSlotIdx, uint64_t *nSecond); @@ -259,7 +276,7 @@ index 46e0e1d..409ef4b 100644 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 f5b2fd6..144a65e 100644 +index f5b2fd6..8fb0ec2 100644 --- a/fhi_lib/lib/ethernet/ethdi.c +++ b/fhi_lib/lib/ethernet/ethdi.c @@ -37,7 +37,10 @@ @@ -273,8 +290,37 @@ index f5b2fd6..144a65e 100644 #include #include #include -@@ -325,8 +328,8 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, +@@ -185,14 +188,24 @@ static void check_port_link_status(uint8_t portid) + printf("Port %d Link Up - speed %u " + "Mbps - %s\n", (uint8_t)portid, + (unsigned)link.link_speed, ++#if (RTE_VER_YEAR >= 21) ++ (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX) ? ++ ("full-duplex") : ("half-duplex\n") ++#else + (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? +- ("full-duplex") : ("half-duplex\n")); ++ ("full-duplex") : ("half-duplex\n") ++#endif ++ ); + else + printf("Port %d Link Down\n", + (uint8_t)portid); + } + /* clear all_ports_up flag if any link down */ ++#if (RTE_VER_YEAR >= 21) ++ if (link.link_status == RTE_ETH_LINK_DOWN) { ++#else + if (link.link_status == ETH_LINK_DOWN) { ++#endif + all_ports_up = 0; + break; + } +@@ -323,10 +336,11 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, + uint64_t nWorkerCore = 1; + uint32_t coreNum = sysconf(_SC_NPROCESSORS_CONF); char bbdev_wdev[32] = ""; ++ char bbdev_vfio_vf_token[64] = ""; char bbdev_vdev[32] = ""; char iova_mode[32] = "--iova-mode=pa"; - char socket_mem[32] = "--socket-mem=8192"; @@ -284,16 +330,36 @@ index f5b2fd6..144a65e 100644 char ring_name[32] = ""; int32_t xran_port = -1; queueid_t qi = 0; -@@ -336,7 +339,7 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, +@@ -336,8 +350,8 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, cpu = sched_getcpu(); node = numa_node_of_cpu(cpu); - char *argv[] = { name, core_mask, "-n2", iova_mode, socket_mem, socket_limit, "--proc-type=auto", +- "--file-prefix", name, "-a0000:00:00.0", bbdev_wdev, bbdev_vdev}; + char *argv[] = { name, core_mask, "-n2", iova_mode, socket_mem, socket_limit, "--proc-type=auto", "--no-telemetry", - "--file-prefix", name, "-a0000:00:00.0", bbdev_wdev, bbdev_vdev}; ++ "--file-prefix", name, "-a0000:00:00.0", bbdev_wdev, bbdev_vdev, bbdev_vfio_vf_token}; if (io_cfg == NULL) -@@ -481,11 +484,13 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, + return 0; +@@ -347,11 +361,17 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, + // hw-accelerated bbdev + printf("hw-accelerated bbdev %s\n", io_cfg->bbdev_dev[0]); + snprintf(bbdev_wdev, RTE_DIM(bbdev_wdev), "-a%s", io_cfg->bbdev_dev[0]); ++ if (io_cfg->bbdev_vfio_vf_token[0] != NULL) { ++ snprintf(bbdev_vfio_vf_token, RTE_DIM(bbdev_vfio_vf_token), "--vfio-vf-token=%s", io_cfg->bbdev_vfio_vf_token[0]); ++ } + } else if (io_cfg->bbdev_mode == XRAN_BBDEV_MODE_HW_OFF){ + snprintf(bbdev_wdev, RTE_DIM(bbdev_wdev), "%s", "--vdev=baseband_turbo_sw"); + } else if (io_cfg->bbdev_mode == XRAN_BBDEV_MODE_HW_SW){ + printf("software and hw-accelerated bbdev %s\n", io_cfg->bbdev_dev[0]); + snprintf(bbdev_wdev, RTE_DIM(bbdev_wdev), "-a%s", io_cfg->bbdev_dev[0]); ++ if (io_cfg->bbdev_vfio_vf_token[0] != NULL) { ++ snprintf(bbdev_vfio_vf_token, RTE_DIM(bbdev_vfio_vf_token), "--vfio-vf-token=%s", io_cfg->bbdev_vfio_vf_token[0]); ++ } + snprintf(bbdev_vdev, RTE_DIM(bbdev_vdev), "%s", "--vdev=baseband_turbo_sw"); + } else { + rte_panic("Cannot init DPDK incorrect [bbdev_mode %d]\n", io_cfg->bbdev_mode); +@@ -481,11 +501,13 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, ctx->tx_ring[i] = rte_ring_create(ring_name, NUM_MBUFS_RING_TRX, rte_lcore_to_socket_id(*lcore_id), RING_F_SC_DEQ); PANIC_ON(ctx->tx_ring[i] == NULL, "failed to allocate rx ring"); @@ -307,7 +373,7 @@ index f5b2fd6..144a65e 100644 } } } else { -@@ -555,7 +560,7 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, +@@ -555,7 +577,7 @@ xran_ethdi_init_dpdk_io(char *name, const struct xran_io_cfg *io_cfg, ctx->up_dl_pkt_gen_ring[i] = rte_ring_create(ring_name, NUM_MBUFS_RING, rte_lcore_to_socket_id(*lcore_id), /*RING_F_SC_DEQ*/0); PANIC_ON(ctx->up_dl_pkt_gen_ring[i] == NULL, "failed to allocate dl gen ring"); @@ -317,7 +383,7 @@ index f5b2fd6..144a65e 100644 return 1; diff --git a/fhi_lib/lib/ethernet/ethernet.c b/fhi_lib/lib/ethernet/ethernet.c -index edda598..791256c 100644 +index edda598..77e5ca7 100644 --- a/fhi_lib/lib/ethernet/ethernet.c +++ b/fhi_lib/lib/ethernet/ethernet.c @@ -37,7 +37,10 @@ @@ -331,6 +397,78 @@ index edda598..791256c 100644 #include #include #include +@@ -149,13 +152,22 @@ void xran_init_port(int p_id, uint16_t num_rxq, uint32_t mtu) + static uint16_t nb_txd = BURST_SIZE; + struct rte_ether_addr addr; + struct rte_eth_rxmode rxmode = { ++#if (RTE_VER_YEAR >= 21) ++ .mtu = MAX_RX_LEN, ++#else + .split_hdr_size = 0, + .max_rx_pkt_len = MAX_RX_LEN, + .offloads = DEV_RX_OFFLOAD_JUMBO_FRAME ++#endif + }; + struct rte_eth_txmode txmode = { ++#if (RTE_VER_YEAR >= 21) ++ .mq_mode = RTE_ETH_MQ_TX_NONE, ++ .offloads = RTE_ETH_TX_OFFLOAD_MULTI_SEGS ++#else + .mq_mode = ETH_MQ_TX_NONE, + .offloads = DEV_TX_OFFLOAD_MULTI_SEGS ++#endif + }; + struct rte_eth_conf port_conf = { + .rxmode = rxmode, +@@ -174,8 +186,13 @@ void xran_init_port(int p_id, uint16_t num_rxq, uint32_t mtu) + uint32_t num_mbufs = 0; + + if (mtu <= 1500) { ++#if (RTE_VER_YEAR >= 21) ++ rxmode.offloads &= ~RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO; ++ rxmode.mtu = RTE_ETHER_MAX_LEN; ++#else + rxmode.offloads &= ~DEV_RX_OFFLOAD_JUMBO_FRAME; + rxmode.max_rx_pkt_len = RTE_ETHER_MAX_LEN; ++#endif + data_room_size = MBUF_POOL_ELM_SMALL; + } + +@@ -184,10 +201,19 @@ void xran_init_port(int p_id, uint16_t num_rxq, uint32_t mtu) + drv_name = dev_info.driver_name; + printf("initializing port %d for TX, drv=%s\n", p_id, drv_name); + +- if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE){ ++#if (RTE_VER_YEAR >= 21) ++ if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) ++#else ++ if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) ++#endif ++ { + printf("set DEV_TX_OFFLOAD_MBUF_FAST_FREE\n"); + port_conf.txmode.offloads |= ++#if (RTE_VER_YEAR >= 21) ++ RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE; ++#else + DEV_TX_OFFLOAD_MBUF_FAST_FREE; ++#endif + } + + rte_eth_macaddr_get(p_id, &addr); +@@ -293,8 +319,13 @@ void xran_add_eth_hdr_vlan(struct rte_ether_addr *dst, uint16_t ethertype, struc + PANIC_ON(h == NULL, "mbuf prepend of ether_hdr failed"); + + /* Fill in the ethernet header. */ ++#if (RTE_VER_YEAR >= 21) ++ rte_eth_macaddr_get(mb->port, &h->src_addr); /* set source addr */ ++ h->dst_addr = *dst; /* set dst addr */ ++#else + rte_eth_macaddr_get(mb->port, &h->s_addr); /* set source addr */ + h->d_addr = *dst; /* set dst addr */ ++#endif + h->ether_type = rte_cpu_to_be_16(ethertype); /* ethertype too */ + #if 0 + struct rte_ether_addr *s = &h->s_addr; diff --git a/fhi_lib/lib/src/xran_bfp_ref.cpp b/fhi_lib/lib/src/xran_bfp_ref.cpp index e6d3067..8e0abee 100644 --- a/fhi_lib/lib/src/xran_bfp_ref.cpp @@ -565,7 +703,7 @@ index 789c6fd..a768efb 100644 #include #include diff --git a/fhi_lib/lib/src/xran_delay_measurement.c b/fhi_lib/lib/src/xran_delay_measurement.c -index 4c943c8..d9e7983 100644 +index 4c943c8..7db51a8 100644 --- a/fhi_lib/lib/src/xran_delay_measurement.c +++ b/fhi_lib/lib/src/xran_delay_measurement.c @@ -23,7 +23,10 @@ @@ -579,6 +717,155 @@ index 4c943c8..d9e7983 100644 #include #include #include +@@ -572,16 +575,28 @@ int xran_generate_delay_meas(uint16_t port_id, void* handle, uint8_t actionType, + PANIC_ON(h == NULL, "mbuf prepend of ether_hdr failed"); + + /* Fill in the ethernet header. */ ++#if (RTE_VER_YEAR >= 21) ++ rte_eth_macaddr_get(port_id, &h->src_addr); /* set source addr */ ++#else + rte_eth_macaddr_get(port_id, &h->s_addr); /* set source addr */ ++#endif + + if (p_xran_dev_ctx->fh_init.io_cfg.id) + { + // rte_ether_addr_copy( (struct rte_ether_addr *)p_xran_dev_ctx->fh_init.p_o_du_addr[port_id],&h->d_addr); ++#if (RTE_VER_YEAR >= 21) ++ h->dst_addr = ctx->entities[port_id][ID_O_DU]; /* set dst addr */ ++#else + h->d_addr = ctx->entities[port_id][ID_O_DU]; /* set dst addr */ ++#endif + } + else + { ++#if (RTE_VER_YEAR >= 21) ++ h->dst_addr = ctx->entities[port_id][ID_O_RU]; /* set dst addr */ ++#else + h->d_addr = ctx->entities[port_id][ID_O_RU]; /* set dst addr */ ++#endif + // rte_ether_addr_copy( (struct rte_ether_addr *)p_xran_dev_ctx->fh_init.p_o_ru_addr[port_id],&h->d_addr); + } + +@@ -752,7 +767,11 @@ int xran_generate_delay_meas(uint16_t port_id, void* handle, uint8_t actionType, + int8_t *pa = &p_xran_dev_ctx->fh_init.p_o_du_addr[0]; + printf("DST_MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]); + #endif ++#if (RTE_VER_YEAR >= 21) ++ rte_ether_addr_copy((struct rte_ether_addr *)&p_xran_dev_ctx->fh_init.p_o_du_addr[0], (struct rte_ether_addr *)&h->dst_addr.addr_bytes[0]); ++#else + rte_ether_addr_copy((struct rte_ether_addr *)&p_xran_dev_ctx->fh_init.p_o_du_addr[0], (struct rte_ether_addr *)&h->d_addr.addr_bytes[0]); ++#endif + + } + else +@@ -761,13 +780,25 @@ int xran_generate_delay_meas(uint16_t port_id, void* handle, uint8_t actionType, + int8_t *pb = &p_xran_dev_ctx->fh_init.p_o_ru_addr[0]; + printf("DST_MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pb[0],pb[1],pb[2],pb[3],pb[4],pb[5]); + #endif ++#if (RTE_VER_YEAR >= 21) ++ rte_ether_addr_copy((struct rte_ether_addr *)&p_xran_dev_ctx->fh_init.p_o_ru_addr[0], (struct rte_ether_addr *)&h->dst_addr.addr_bytes[0]); ++#else + rte_ether_addr_copy((struct rte_ether_addr *)&p_xran_dev_ctx->fh_init.p_o_ru_addr[0], (struct rte_ether_addr *)&h->d_addr.addr_bytes[0]); ++#endif + + } + #ifdef XRAN_OWD_DEBUG_PKTS ++#if (RTE_VER_YEAR >= 21) ++ uint8_t *pc = &h->src_addr.addr_bytes[0]; ++#else + uint8_t *pc = &h->s_addr.addr_bytes[0]; ++#endif + printf(" Src MAC from packet: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pc[0],pc[1],pc[2],pc[3],pc[4],pc[5]); ++#if (RTE_VER_YEAR >= 21) ++ uint8_t *pd = &h->dst_addr.addr_bytes[0]; ++#else + uint8_t *pd = &h->d_addr.addr_bytes[0]; ++#endif + printf(" Dst MAC from packet: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pd[0],pd[1],pd[2],pd[3],pd[4],pd[5]); + #endif + // Copy dest address from above +@@ -862,9 +893,15 @@ int xran_process_delmeas_request(struct rte_mbuf *pkt, void* handle, struct xran + // 11) Fill the ethernet header properly by swapping src and dest addressed from the copied frame + eth_hdr = rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr *); + /* Swap dest and src mac addresses. */ ++#if (RTE_VER_YEAR >= 21) ++ rte_ether_addr_copy(ð_hdr->dst_addr, &addr); ++ rte_ether_addr_copy(ð_hdr->src_addr, ð_hdr->dst_addr); ++ rte_ether_addr_copy(&addr, ð_hdr->src_addr); ++#else + rte_ether_addr_copy(ð_hdr->d_addr, &addr); + rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr); + rte_ether_addr_copy(&addr, ð_hdr->s_addr); ++#endif + // Still need to check ol_flags state and update if necessary + // Compute the delay td12 and save + // Still need to define the DB to save the info and run averages +@@ -872,9 +909,17 @@ int xran_process_delmeas_request(struct rte_mbuf *pkt, void* handle, struct xran + // 12) Send the response right away + #ifdef XRAN_OWD_DEBUG_PKTS + struct rte_ether_hdr *h = (struct rte_ether_hdr *)rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr*); ++#if (RTE_VER_YEAR >= 21) ++ uint8_t *pc = &h->src_addr.addr_bytes[0]; ++#else + uint8_t *pc = &h->s_addr.addr_bytes[0]; ++#endif + printf(" Src MAC from packet: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pc[0],pc[1],pc[2],pc[3],pc[4],pc[5]); ++#if (RTE_VER_YEAR >= 21) ++ uint8_t *pd = &h->dst_addr.addr_bytes[0]; ++#else + uint8_t *pd = &h->d_addr.addr_bytes[0]; ++#endif + printf(" Dst MAC from packet: %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n", pd[0],pd[1],pd[2],pd[3],pd[4],pd[5]); + // printf("EtherType: %04"PRIx16" \n",&h->ether_type); + #endif +@@ -1100,9 +1145,15 @@ int xran_process_delmeas_rem_request(struct rte_mbuf *pkt, void* handle, struct + // 9) Fill the ethernet header properly by swapping src and dest addressed from the copied frame + eth_hdr = rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr *); + /* Swap dest and src mac addresses. */ ++#if (RTE_VER_YEAR >= 21) ++ rte_ether_addr_copy(ð_hdr->dst_addr, &addr); ++ rte_ether_addr_copy(ð_hdr->src_addr, ð_hdr->dst_addr); ++ rte_ether_addr_copy(&addr, ð_hdr->src_addr); ++#else + rte_ether_addr_copy(ð_hdr->d_addr, &addr); + rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr); + rte_ether_addr_copy(&addr, ð_hdr->s_addr); ++#endif + // 10) Send the response right away + pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt *, sizeof(struct rte_ether_hdr) ); + pdm->cmnhdr.bits.ecpri_payl_size = 10 + powdc->owdm_PlLength; // 10 correponds to the xran_ecpri_delay_meas_pl minus the dummy_bytes field which now allows the user to select the length for this field to be sent +@@ -1177,9 +1228,15 @@ int xran_process_delmeas_rem_request_w_fup(struct rte_mbuf* pkt, void* handle, s + // 7) Fill the ethernet header properly by swapping src and dest addressed from the copied frame + eth_hdr = rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr *); + /* Swap dest and src mac addresses. */ ++#if (RTE_VER_YEAR >= 21) ++ rte_ether_addr_copy(ð_hdr->dst_addr, &addr); ++ rte_ether_addr_copy(ð_hdr->src_addr, ð_hdr->dst_addr); ++ rte_ether_addr_copy(&addr, ð_hdr->src_addr); ++#else + rte_ether_addr_copy(ð_hdr->d_addr, &addr); + rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr); + rte_ether_addr_copy(&addr, ð_hdr->s_addr); ++#endif + // 8) Duplicate packet to be used for the follow up packet + pkt2 = rte_pktmbuf_copy(pkt1, _eth_mbuf_pool, 0, UINT32_MAX); + // 9) Record the current timestamp when the request with follow up is being sent +@@ -1283,9 +1340,15 @@ int xran_process_delmeas_follow_up(struct rte_mbuf *pkt, void* handle, struct xr + // 9) Fill the ethernet header properly by swapping src and dest addressed from the copied frame + eth_hdr = rte_pktmbuf_mtod(pkt1, struct rte_ether_hdr *); + /* Swap dest and src mac addresses. */ ++#if (RTE_VER_YEAR >= 21) ++ rte_ether_addr_copy(ð_hdr->dst_addr, &addr); ++ rte_ether_addr_copy(ð_hdr->src_addr, ð_hdr->dst_addr); ++ rte_ether_addr_copy(&addr, ð_hdr->src_addr); ++#else + rte_ether_addr_copy(ð_hdr->d_addr, &addr); + rte_ether_addr_copy(ð_hdr->s_addr, ð_hdr->d_addr); + rte_ether_addr_copy(&addr, ð_hdr->s_addr); ++#endif + pdm = (struct xran_ecpri_del_meas_pkt*)rte_pktmbuf_mtod_offset(pkt1, struct xran_ecpri_del_meas_pkt *, sizeof(struct rte_ether_hdr) ); + pdm->cmnhdr.bits.ecpri_payl_size = 10 + powdc->owdm_PlLength; // 10 correponds to the xran_ecpri_delay_meas_pl minus the dummy_bytes field which now allows the user to select the length for this field to be sent + pdm->cmnhdr.bits.ecpri_payl_size = rte_cpu_to_be_16(pdm->cmnhdr.bits.ecpri_payl_size); diff --git a/fhi_lib/lib/src/xran_dev.c b/fhi_lib/lib/src/xran_dev.c index 4acade1..c939edc 100644 --- a/fhi_lib/lib/src/xran_dev.c @@ -1377,7 +1664,7 @@ index 72249bc..6b30084 100644 #include diff --git a/fhi_lib/lib/src/xran_tx_proc.c b/fhi_lib/lib/src/xran_tx_proc.c -index 45a17a8..28c5568 100644 +index 45a17a8..85ce6fa 100644 --- a/fhi_lib/lib/src/xran_tx_proc.c +++ b/fhi_lib/lib/src/xran_tx_proc.c @@ -35,7 +35,11 @@ @@ -1392,6 +1679,58 @@ index 45a17a8..28c5568 100644 #include #include +@@ -1514,7 +1518,11 @@ xran_process_tx_sym_cp_on_opt(void* pHandle, uint8_t ctx_id, uint32_t tti, int32 + mb_oran_hdr_ext->buf_addr = ext_buff; + mb_oran_hdr_ext->buf_iova = ((struct rte_mempool_objhdr*)RTE_PTR_SUB(mb_base, rte_mempool_objhdr_size))->iova + RTE_PTR_DIFF(ext_buff, mb_base); + mb_oran_hdr_ext->buf_len = ext_buff_len; ++#if (RTE_VER_YEAR >= 21) ++ mb_oran_hdr_ext->ol_flags |= RTE_MBUF_F_EXTERNAL; ++#else + mb_oran_hdr_ext->ol_flags |= EXT_ATTACHED_MBUF; ++#endif + mb_oran_hdr_ext->shinfo = p_share_data; + mb_oran_hdr_ext->data_off = (uint16_t)RTE_MIN((uint16_t)RTE_PKTMBUF_HEADROOM, (uint16_t)mb_oran_hdr_ext->buf_len) - rte_ether_hdr_size; + mb_oran_hdr_ext->data_len = (uint16_t)(mb_oran_hdr_ext->data_len + rte_ether_hdr_size); +@@ -1532,8 +1540,13 @@ xran_process_tx_sym_cp_on_opt(void* pHandle, uint8_t ctx_id, uint32_t tti, int32 + + /* Fill in the ethernet header. */ + #ifndef TRANSMIT_BURST ++#if (RTE_VER_YEAR >= 21) ++ rte_eth_macaddr_get(mb_oran_hdr_ext->port, &((struct rte_ether_hdr*)pStart)->src_addr); /* set source addr */ ++ ((struct rte_ether_hdr*)pStart)->dst_addr = eth_ctx->entities[vf_id][ID_O_RU]; /* set dst addr */ ++#else + rte_eth_macaddr_get(mb_oran_hdr_ext->port, &((struct rte_ether_hdr*)pStart)->s_addr); /* set source addr */ + ((struct rte_ether_hdr*)pStart)->d_addr = eth_ctx->entities[vf_id][ID_O_RU]; /* set dst addr */ ++#endif + ((struct rte_ether_hdr*)pStart)->ether_type = ETHER_TYPE_ECPRI_BE; /* ethertype */ + #endif + nPktSize = sizeof(struct rte_ether_hdr) +@@ -1878,7 +1891,11 @@ xran_process_tx_srs_cp_on(void* pHandle, uint8_t ctx_id, uint32_t tti, int32_t s + mb_oran_hdr_ext->buf_addr = ext_buff; + mb_oran_hdr_ext->buf_iova = ((struct rte_mempool_objhdr*)RTE_PTR_SUB(mb_base, rte_mempool_objhdr_size))->iova + RTE_PTR_DIFF(ext_buff, mb_base); + mb_oran_hdr_ext->buf_len = ext_buff_len; ++#if (RTE_VER_YEAR >= 21) ++ mb_oran_hdr_ext->ol_flags |= RTE_MBUF_F_EXTERNAL; ++#else + mb_oran_hdr_ext->ol_flags |= EXT_ATTACHED_MBUF; ++#endif + mb_oran_hdr_ext->shinfo = p_share_data; + mb_oran_hdr_ext->data_off = (uint16_t)RTE_MIN((uint16_t)RTE_PKTMBUF_HEADROOM, (uint16_t)mb_oran_hdr_ext->buf_len) - rte_ether_hdr_size; + mb_oran_hdr_ext->data_len = (uint16_t)(mb_oran_hdr_ext->data_len + rte_ether_hdr_size); +@@ -1887,8 +1904,13 @@ xran_process_tx_srs_cp_on(void* pHandle, uint8_t ctx_id, uint32_t tti, int32_t s + pStart = (char*)((char*)mb_oran_hdr_ext->buf_addr + mb_oran_hdr_ext->data_off); + + /* Fill in the ethernet header. */ ++#if (RTE_VER_YEAR >= 21) ++ rte_eth_macaddr_get(mb_oran_hdr_ext->port, &((struct rte_ether_hdr*)pStart)->src_addr); /* set source addr */ ++ ((struct rte_ether_hdr*)pStart)->dst_addr = eth_ctx->entities[vf_id][ID_O_RU]; /* set dst addr */ ++#else + rte_eth_macaddr_get(mb_oran_hdr_ext->port, &((struct rte_ether_hdr*)pStart)->s_addr); /* set source addr */ + ((struct rte_ether_hdr*)pStart)->d_addr = eth_ctx->entities[vf_id][ID_O_RU]; /* set dst addr */ ++#endif + ((struct rte_ether_hdr*)pStart)->ether_type = ETHER_TYPE_ECPRI_BE; /* ethertype */ + + nPktSize = sizeof(struct rte_ether_hdr) diff --git a/fhi_lib/lib/src/xran_up_api.c b/fhi_lib/lib/src/xran_up_api.c index fe22a1f..3fd369b 100644 --- a/fhi_lib/lib/src/xran_up_api.c diff --git a/common/5g_platform_types.h b/common/5g_platform_types.h index a5b7b7a1fc..4ed7f33e47 100644 --- a/common/5g_platform_types.h +++ b/common/5g_platform_types.h @@ -45,6 +45,63 @@ typedef struct nr_guami_s { uint8_t amf_pointer; } nr_guami_t; +typedef enum { + PDUSessionType_ipv4 = 0, + PDUSessionType_ipv6 = 1, + PDUSessionType_ipv4v6 = 2, + PDUSessionType_ethernet = 3, + PDUSessionType_unstructured = 4 +} pdu_session_type_t; + typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t; +/* QoS Priority Level */ +typedef enum { + QOS_PRIORITY_SPARE = 0, + QOS_PRIORITY_HIGHEST, + QOS_PRIORITY_2, + QOS_PRIORITY_3, + QOS_PRIORITY_4, + QOS_PRIORITY_5, + QOS_PRIORITY_6, + QOS_PRIORITY_7, + QOS_PRIORITY_8, + QOS_PRIORITY_9, + QOS_PRIORITY_10, + QOS_PRIORITY_11, + QOS_PRIORITY_12, + QOS_PRIORITY_13, + QOS_PRIORITY_LOWEST, + QOS_NO_PRIORITY +} qos_priority_t; + +/* Pre-emption Capability */ +typedef enum { + PEC_SHALL_NOT_TRIGGER_PREEMPTION = 0, + PEC_MAY_TRIGGER_PREEMPTION, + PEC_MAX, +} qos_pec_t; + +/* Pre-emption Vulnerability */ +typedef enum { + PEV_NOT_PREEMPTABLE = 0, + PEV_PREEMPTABLE = 1, + PEV_MAX, +} qos_pev_t; + +/* Allocation Retention Priority */ +typedef struct { + qos_priority_t priority_level; + qos_pec_t pre_emp_capability; + qos_pev_t pre_emp_vulnerability; +} qos_arp_t; + +typedef struct pdusession_level_qos_parameter_s { + uint8_t qfi; + uint64_t fiveQI; + uint64_t qos_priority; + fiveQI_t fiveQI_type; + qos_arp_t arp; +} pdusession_level_qos_parameter_t; + #endif diff --git a/common/config/DOC/config/rtusage.md b/common/config/DOC/config/rtusage.md index 3b51e1afd2..7c42a6edcc 100644 --- a/common/config/DOC/config/rtusage.md +++ b/common/config/DOC/config/rtusage.md @@ -55,7 +55,6 @@ To get help on supported parameters you can use specific options: --ulsch-max-errors: set the eNodeB max ULSCH erros --phy-test: test UE phy layer, mac disabled --usim-test: use XOR autentication algo in case of test usim mode - --emulate-rf: Emulated RF enabled(disable by defult) --clock: tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo) --wait-for-sync: Help string not specified -C: Set the downlink frequency for all component carriers diff --git a/common/config/config_load_configmodule.c b/common/config/config_load_configmodule.c index 9bb1b85f7d..cfe05042ce 100644 --- a/common/config/config_load_configmodule.c +++ b/common/config/config_load_configmodule.c @@ -300,12 +300,16 @@ configmodule_interface_t *load_configmodule(int argc, cfgmode = strdup(CONFIG_LIBCONFIGFILE); } } - static configmodule_interface_t *cfgptr; + static configmodule_interface_t *cfgptr = NULL; if (cfgptr) fprintf(stderr, "ERROR: Call load_configmodule more than one time\n"); // The macros are not thread safe print_params and similar cfgptr = calloc(sizeof(configmodule_interface_t), 1); + if (!cfgptr) { + fprintf(stderr, "ERROR: cannot allocate a memory for configuration\n"); + return NULL; + } /* argv_info is used to memorize command line options which have been recognized */ /* and to detect unrecognized command line options which might have been specified */ cfgptr->argv_info = calloc(sizeof(int32_t), argc+10); diff --git a/common/config/config_load_configmodule.h b/common/config/config_load_configmodule.h index 3ec27d456f..d5f87d0f8b 100644 --- a/common/config/config_load_configmodule.h +++ b/common/config/config_load_configmodule.h @@ -39,7 +39,6 @@ #include #include #include "common/config/config_paramdesc.h" -#include "common/utils/T/T.h" #define CONFIG_MAX_OOPT_PARAMS 10 // maximum number of parameters in the -O option (-O :P1:P2... #define CONFIG_MAX_ALLOCATEDPTRS 32768 // maximum number of parameters that can be dynamicaly allocated in the config module diff --git a/common/config/yaml/CMakeLists.txt b/common/config/yaml/CMakeLists.txt index 635887e37e..cfcc57e2ab 100644 --- a/common/config/yaml/CMakeLists.txt +++ b/common/config/yaml/CMakeLists.txt @@ -8,11 +8,11 @@ else() endif() add_library(params_yaml_static config_yaml.cpp) -target_link_libraries(params_yaml_static PUBLIC UTIL yaml-cpp::yaml-cpp) +target_link_libraries(params_yaml_static PUBLIC yaml-cpp::yaml-cpp) if (ENABLE_TESTS) add_subdirectory(tests) endif() add_library(params_yaml MODULE config_yaml.cpp) -target_link_libraries(params_yaml PUBLIC UTIL yaml-cpp::yaml-cpp) +target_link_libraries(params_yaml PUBLIC yaml-cpp::yaml-cpp) set_target_properties(params_yaml PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/common/config/yaml/tests/CMakeLists.txt b/common/config/yaml/tests/CMakeLists.txt index e3f1002d79..a460ccfdd4 100644 --- a/common/config/yaml/tests/CMakeLists.txt +++ b/common/config/yaml/tests/CMakeLists.txt @@ -1,5 +1,5 @@ add_executable(test_yaml_config test_yaml_config.cpp) -target_link_libraries(test_yaml_config PRIVATE params_yaml_static GTest::gtest) +target_link_libraries(test_yaml_config PRIVATE params_yaml_static GTest::gtest CONFIG_LIB) add_dependencies(tests test_yaml_config) add_test(NAME test_yaml_config COMMAND ./test_yaml_config) diff --git a/common/platform_constants.h b/common/platform_constants.h index 00c68bd5b8..4000ffb001 100644 --- a/common/platform_constants.h +++ b/common/platform_constants.h @@ -97,4 +97,7 @@ #define UNUSED_VARIABLE(vARIABLE) (void)(vARIABLE) #define NUM_PRACH_RX_FOR_NOISE_ESTIMATE 100 +// SDAP +#define MAX_QOS_FLOWS 64 + #endif /* __PLATFORM_CONSTANTS_H__ */ diff --git a/common/platform_types.h b/common/platform_types.h index 8cbd502fda..e2ffb7b304 100644 --- a/common/platform_types.h +++ b/common/platform_types.h @@ -33,6 +33,39 @@ #include #include +#define ALIGNARRAYSIZE(a, b) (((a + b - 1) / b) * b) +#define ALNARS_16_4(a) ALIGNARRAYSIZE(a, 4) + +typedef struct complexd { + double r; + double i; +} cd_t; + +typedef struct complexf { + float r; + float i; +} cf_t; + +typedef struct complex8 { + int8_t r; + int8_t i; +} c8_t; + +typedef struct complex16 { + int16_t r; + int16_t i; +} c16_t; + +typedef struct complex32 { + int32_t r; + int32_t i; +} c32_t; + +typedef struct complex64 { + int64_t r; + int64_t i; +} c64_t; + //----------------------------------------------------------------------------- // GENERIC ACCESS STRATUM TYPES //----------------------------------------------------------------------------- @@ -45,7 +78,6 @@ typedef uint16_t module_id_t; typedef uint8_t slice_id_t; typedef uint8_t eNB_index_t; typedef uint64_t ue_id_t; -typedef int16_t smodule_id_t; typedef long rb_id_t; typedef long srb_id_t; @@ -74,24 +106,7 @@ typedef enum { FDD = 0 } frame_type_t; -typedef enum link_direction_e { UNKNOWN_DIR = 0, DIR_UPLINK = 1, DIR_DOWNLINK = 2 } link_direction_t; - -typedef enum rb_type_e { UNKNOWN_RADIO_BEARER = 0, SIGNALLING_RADIO_BEARER = 1, RADIO_ACCESS_BEARER = 2 } rb_type_t; - -typedef enum { CR_ROUND = 0, CR_SRB12 = 1, CR_HOL = 2, CR_LC = 3, CR_CQI = 4, CR_LCP = 5, CR_NUM = 6 } sorting_criterion_t; - -typedef enum { POL_FAIR = 0, POL_GREEDY = 1, POL_NUM = 2 } accounting_policy_t; -//----------------------------------------------------------------------------- -// PHY TYPES -//----------------------------------------------------------------------------- -typedef uint8_t crc8_t; -typedef uint16_t crc16_t; -typedef uint32_t crc32_t; typedef unsigned int crc_t; - -//----------------------------------------------------------------------------- -// MAC TYPES -//----------------------------------------------------------------------------- typedef sdu_size_t tbs_size_t; typedef sdu_size_t tb_size_t; typedef unsigned int logical_chan_id_t; @@ -103,9 +118,6 @@ typedef uint8_t mac_enb_index_t; //----------------------------------------------------------------------------- typedef unsigned int mui_t; typedef unsigned int confirm_t; -typedef unsigned int rlc_tx_status_t; -typedef int16_t rlc_sn_t; -typedef uint16_t rlc_usn_t; typedef int32_t rlc_buffer_occupancy_t; typedef signed int rlc_op_status_t; @@ -130,7 +142,6 @@ typedef struct { //----------------------------------------------------------------------------- typedef uint16_t pdcp_sn_t; typedef uint32_t pdcp_hfn_t; -typedef int16_t pdcp_hfn_offset_t; typedef enum pdcp_transmission_mode_e { PDCP_TRANSMISSION_MODE_UNKNOWN = 0, @@ -177,7 +188,6 @@ typedef struct net_ip_address_s { typedef uint32_t mbms_session_id_t; typedef uint16_t mbms_service_id_t; typedef uint16_t rnti_t; -typedef uint8_t rrc_enb_index_t; typedef uint8_t mme_code_t; typedef uint32_t m_tmsi_t; @@ -188,7 +198,6 @@ typedef uint32_t m_tmsi_t; #define P_RNTI (rnti_t)0xFFFE #define SI_RNTI (rnti_t)0xFFFF #define CBA_RNTI (rnti_t)0xfff4 -#define OAI_C_RNTI (rnti_t)0x1234 typedef enum config_action_e { CONFIG_ACTION_NULL = 0, CONFIG_ACTION_ADD = 1, @@ -207,26 +216,38 @@ typedef struct nsa_msg_t { uint8_t msg_buffer[MAX_MESSAGE_SIZE]; } nsa_msg_t; +typedef enum nr_lcid_rb_type { NR_LCID_NONE = 0, NR_LCID_SRB = 1, NR_LCID_DRB = 2 } nr_lcid_rb_type; + +typedef struct nr_lcid_rb_t { + nr_lcid_rb_type type; + union { + int srb_id; + int drb_id; + } choice; +} nr_lcid_rb_t; + typedef struct transport_layer_addr_s { - /** - * Transport Layer Address as a bitstring: - * - 32 bits for IPv4 (RFC 791), - * - 128 bits for IPv6 (RFC 2460), - * - 160 bits for both IPv4 and IPv6, with IPv4 in the first 32 bits. - * The S1AP/NGAP layer forwards this address (bitstring<1..160>) - * to S1-U/NG-U without interpreting it. - */ + /** Transport Layer Address in bytes: + * - 4 bytes for IPv4 (RFC 791), 16 bytes for IPv6 (RFC 2460), + * - 20 bytes for both IPv4 and IPv6, with IPv4 in the first 4 bytes. */ uint8_t length; /// Buffer: address in network byte order uint8_t buffer[20]; } transport_layer_addr_t; +/** @brief GTP tunnel configuration */ +typedef struct { + // Tunnel endpoint identifier + uint32_t teid; + // Transport layer address + transport_layer_addr_t addr; +} gtpu_tunnel_t; + //----------------------------------------------------------------------------- // GTPV1U TYPES //----------------------------------------------------------------------------- typedef uint32_t teid_t; // tunnel endpoint identifier typedef uint8_t ebi_t; // eps bearer id -typedef uint8_t pdusessionid_t; //----------------------------------------------------------------------------- // @@ -244,8 +265,6 @@ typedef struct protocol_ctxt_s { eNB_index_t eNB_index; /*!< \brief valid for UE indicating the index of connected eNB(s) */ bool brOption; } protocol_ctxt_t; -// warning time hardcoded -#define PROTOCOL_CTXT_TIME_MILLI_SECONDS(CtXt_h) ((CtXt_h)->frame * 10 + (CtXt_h)->subframe) #define UE_MODULE_ID_TO_INSTANCE(mODULE_iD) mODULE_iD + RC.nb_inst #define ENB_MODULE_ID_TO_INSTANCE(mODULE_iD) mODULE_iD @@ -297,12 +316,6 @@ typedef struct protocol_ctxt_s { #define PROTOCOL_CTXT_ARGS(CTXT_Pp) \ (CTXT_Pp)->frame, ((CTXT_Pp)->enb_flag == ENB_FLAG_YES) ? "eNB" : " UE", (CTXT_Pp)->module_id, (CTXT_Pp)->rntiMaybeUEid -#define PROTOCOL_NR_CTXT_ARGS(CTXT_Pp) \ - (CTXT_Pp)->frame, ((CTXT_Pp)->enb_flag == GNB_FLAG_YES) ? "gNB" : " UE", (CTXT_Pp)->module_id, (CTXT_Pp)->rntiMaybeUEid - -#define CHECK_CTXT_ARGS(CTXT_Pp) - - static inline int ceil_mod(const unsigned int v, const unsigned int mod) { return ((v + mod - 1) / mod) * mod; diff --git a/common/ran_context.h b/common/ran_context.h index e009d0987f..91baa78d84 100644 --- a/common/ran_context.h +++ b/common/ran_context.h @@ -46,7 +46,6 @@ struct gNB_RRC_INST_s; struct eNB_MAC_INST_s; struct eNB_MAC_INST_NB_IoT_s; struct gNB_MAC_INST_s; -struct gtpv1u_data_s; struct RU_t_s; typedef struct { @@ -100,8 +99,6 @@ typedef struct { struct eNB_MAC_INST_NB_IoT_s **nb_iot_mac; /// NR MAC context variables struct gNB_MAC_INST_s **nrmac; - /// GTPu descriptor - struct gtpv1u_data_s *gtpv1u_data_g; /// RU descriptors. These describe what each radio unit is supposed to do and contain the necessary functions for fronthaul interfaces struct RU_t_s **ru; /// Mask to indicate fronthaul setup status of RU (hard-limit to 64 RUs) diff --git a/common/utils/LOG/CMakeLists.txt b/common/utils/LOG/CMakeLists.txt index ff224329de..ade7f76dea 100644 --- a/common/utils/LOG/CMakeLists.txt +++ b/common/utils/LOG/CMakeLists.txt @@ -4,10 +4,12 @@ target_link_libraries(log_headers INTERFACE T_headers) set(log_sources log.c) if (ENABLE_LTTNG) + find_package(LTTngUST 2.3.8 EXACT REQUIRED) set(log_sources ${log_sources} lttng-tp.c) +else() + message(STATUS "LTTNG support disabled") endif() add_library(LOG ${log_sources}) -target_include_directories(LOG PUBLIC .) target_link_libraries(LOG PRIVATE CONFIG_LIB) target_link_libraries(LOG PUBLIC log_headers) if (ENABLE_LTTNG) diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h index 7b9b570a06..1f7474253c 100644 --- a/common/utils/LOG/log.h +++ b/common/utils/LOG/log.h @@ -52,6 +52,7 @@ #endif #include #include +#include "common/utils/T/T.h" #if ENABLE_LTTNG #include "lttng-log.h" #endif diff --git a/common/utils/T/.gitignore b/common/utils/T/.gitignore index 60264a9c4a..7ac6cc75bd 100644 --- a/common/utils/T/.gitignore +++ b/common/utils/T/.gitignore @@ -3,6 +3,7 @@ genids tracer/enb tracer/gnb +tracer/gnb_mac tracer/extract_config tracer/record tracer/replay diff --git a/common/utils/T/CMakeLists.txt b/common/utils/T/CMakeLists.txt index 5425a564b1..8f58871adc 100644 --- a/common/utils/T/CMakeLists.txt +++ b/common/utils/T/CMakeLists.txt @@ -47,7 +47,7 @@ add_custom_target(generate_T DEPENDS T_IDs.h check_vcd) # even if T is off, we need the headers as many targets depend on it # for this, create an INTERFACE (header-only) library T_headers. To ensure the # headers have really been created, we make this headers library explicitly -# depend on the generated headers. +# depend on the generate_T target. add_library(T_headers INTERFACE) add_dependencies(T_headers T_IDs.h generate_T) target_include_directories(T_headers INTERFACE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/common/utils/T/T.h b/common/utils/T/T.h index 746607cc6e..c78b99632a 100644 --- a/common/utils/T/T.h +++ b/common/utils/T/T.h @@ -100,12 +100,14 @@ struct T_header; /* T macro tricks */ extern int T_stdout; -#define TN(...) TN_N(__VA_ARGS__,39,38,37,36,35,34,33,32,31,30,29,28,27,26, \ - 25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7, \ - 6,5,4,3,2,1,0)(__VA_ARGS__) -#define TN_N(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17, \ - n18,n19,n20,n21,n22,n23,n24,n25,n26,n27,n28,n29,n30,n31,n32, \ - n33,n34,n35,n36,n37,n38,n,...) T##n +#define TN(...) TN_N(__VA_ARGS__,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,\ + 56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,\ + 37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,\ + 18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)(__VA_ARGS__) +#define TN_N(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17,n18,n19,n20,\ + n21,n22,n23,n24,n25,n26,n27,n28,n29,n30,n31,n32,n33,n34,n35,n36,n37,n38,\ + n39,n40,n41,n42,n43,n44,n45,n46,n47,n48,n49,n50,n51,n52,n53,n54,n55,n56,\ + n57,n58,n59,n60,n61,n62,n63,n64,n65,n66,n67,n68,n69,n70,n,...) T##n #define T(...) do { if (T_stdout == 0 || T_stdout == 2) TN(__VA_ARGS__); } while (0) /* type used to send arbitrary buffer data */ @@ -620,6 +622,633 @@ extern int *T_active; } \ } while (0) + +#define T41(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T43(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T45(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T47(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T49(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T51(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T53(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T55(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T57(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26,t27,x27) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_PUT_##t27(29, x27); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T59(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26,t27,x27,t28,x28) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_PUT_##t27(29, x27); \ + T_PUT_##t28(30, x28); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T61(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26,t27,x27,t28,x28,t29,x29) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_PUT_##t27(29, x27); \ + T_PUT_##t28(30, x28); \ + T_PUT_##t29(31, x29); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T63(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26,t27,x27,t28,x28,t29,x29,t30,x30) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_PUT_##t27(29, x27); \ + T_PUT_##t28(30, x28); \ + T_PUT_##t29(31, x29); \ + T_PUT_##t30(32, x30); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T65(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26,t27,x27,t28,x28,t29,x29,t30,x30,t31,x31) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_PUT_##t27(29, x27); \ + T_PUT_##t28(30, x28); \ + T_PUT_##t29(31, x29); \ + T_PUT_##t30(32, x30); \ + T_PUT_##t31(33, x31); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T67(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26,t27,x27,t28,x28,t29,x29,t30,x30,t31,x31,t32,x32) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_PUT_##t27(29, x27); \ + T_PUT_##t28(30, x28); \ + T_PUT_##t29(31, x29); \ + T_PUT_##t30(32, x30); \ + T_PUT_##t31(33, x31); \ + T_PUT_##t32(34, x32); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T69(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26,t27,x27,t28,x28,t29,x29,t30,x30,t31,x31,t32,x32,t33,x33) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_PUT_##t27(29, x27); \ + T_PUT_##t28(30, x28); \ + T_PUT_##t29(31, x29); \ + T_PUT_##t30(32, x30); \ + T_PUT_##t31(33, x31); \ + T_PUT_##t32(34, x32); \ + T_PUT_##t33(35, x33); \ + T_COMMIT(); \ + } \ + } while (0) + +#define T71(t,t0,x0,t1,x1,t2,x2,t3,x3,t4,x4,t5,x5,t6,x6,t7,x7,t8,x8,t9,x9,\ + t10,x10,t11,x11,t12,x12,t13,x13,t14,x14,t15,x15,t16,x16,t17,x17,\ + t18,x18,t19,x19,t20,x20,t21,x21,t22,x22,t23,x23,t24,x24,t25,x25,\ + t26,x26,t27,x27,t28,x28,t29,x29,t30,x30,t31,x31,t32,x32,t33,x33,t34,x34) \ + do { \ + if (T_ACTIVE(t)) { \ + T_LOCAL_DATA \ + T_HEADER(t); \ + T_PUT_##t0(2, x0); \ + T_PUT_##t1(3, x1); \ + T_PUT_##t2(4, x2); \ + T_PUT_##t3(5, x3); \ + T_PUT_##t4(6, x4); \ + T_PUT_##t5(7, x5); \ + T_PUT_##t6(8, x6); \ + T_PUT_##t7(9, x7); \ + T_PUT_##t8(10, x8); \ + T_PUT_##t9(11, x9); \ + T_PUT_##t10(12, x10); \ + T_PUT_##t11(13, x11); \ + T_PUT_##t12(14, x12); \ + T_PUT_##t13(15, x13); \ + T_PUT_##t14(16, x14); \ + T_PUT_##t15(17, x15); \ + T_PUT_##t16(18, x16); \ + T_PUT_##t17(19, x17); \ + T_PUT_##t18(20, x18); \ + T_PUT_##t19(21, x19); \ + T_PUT_##t20(22, x20); \ + T_PUT_##t21(23, x21); \ + T_PUT_##t22(24, x22); \ + T_PUT_##t23(25, x23); \ + T_PUT_##t24(26, x24); \ + T_PUT_##t25(27, x25); \ + T_PUT_##t26(28, x26); \ + T_PUT_##t27(29, x27); \ + T_PUT_##t28(30, x28); \ + T_PUT_##t29(31, x29); \ + T_PUT_##t30(32, x30); \ + T_PUT_##t31(33, x31); \ + T_PUT_##t32(34, x32); \ + T_PUT_##t33(35, x33); \ + T_PUT_##t34(36, x34); \ + T_COMMIT(); \ + } \ + } while (0) + + #define T_CALL_ERROR \ do { \ printf("%s:%d:%s: error calling T, you have to use T_INT() or T_XX()\n", \ @@ -645,6 +1274,22 @@ extern int *T_active; #define T34(...) T_CALL_ERROR #define T36(...) T_CALL_ERROR #define T38(...) T_CALL_ERROR +#define T40(...) T_CALL_ERROR +#define T42(...) T_CALL_ERROR +#define T44(...) T_CALL_ERROR +#define T46(...) T_CALL_ERROR +#define T48(...) T_CALL_ERROR +#define T50(...) T_CALL_ERROR +#define T52(...) T_CALL_ERROR +#define T54(...) T_CALL_ERROR +#define T56(...) T_CALL_ERROR +#define T58(...) T_CALL_ERROR +#define T60(...) T_CALL_ERROR +#define T62(...) T_CALL_ERROR +#define T64(...) T_CALL_ERROR +#define T66(...) T_CALL_ERROR +#define T68(...) T_CALL_ERROR +#define T70(...) T_CALL_ERROR /* special cases for VCD logs */ diff --git a/common/utils/T/T_messages.txt b/common/utils/T/T_messages.txt index 0f306501f0..2f17b62ea5 100644 --- a/common/utils/T/T_messages.txt +++ b/common/utils/T/T_messages.txt @@ -92,9 +92,13 @@ ID = UE_PHY_INITIATE_RA_PROCEDURE GROUP = ALL:PHY:UE:WIRESHARK FORMAT = int,frame : int,subframe_or_slot : int,preamble : int,power ID = GNB_PHY_DL_TICK - DESC = gNodeB downlink tick - one tick per ms at start of downlink processing + DESC = gNodeB downlink tick - one tick per slot at start of downlink processing GROUP = ALL:PHY:GRAPHIC:GNB - FORMAT = int,gNB_ID : int,frame : int,subframe + FORMAT = int,gNB_ID : int,frame : int,slot +ID = GNB_PHY_UL_TICK + DESC = gNodeB uplink tick - one tick per slot at start of uplink processing + GROUP = ALL:PHY:GRAPHIC:GNB + FORMAT = int,gNB_ID : int,frame : int,slot ID = ENB_PHY_MIB DESC = MIB data GROUP = ALL:PHY:ENB:WIRESHARK @@ -111,6 +115,26 @@ ID = GNB_PHY_PUCCH_PUSCH_IQ DESC = gNodeB input data in the frequency domain for a slot where some PUCCH or PUSCH detection was done GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB FORMAT = int,frame : int,slot : buffer,rxdataF +ID = GNB_PHY_UL_FD_PUSCH_IQ + DESC = gNodeB UL PUSCH IQ Data in the frequency domain + GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB + FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data +ID = GNB_PHY_UL_FD_DMRS + DESC = gNodeB UL DMRS Signal in the frequency domain + GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB + FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data +ID = GNB_PHY_UL_FD_CHAN_EST_DMRS_POS + DESC = gNodeB channel estimation in the frequency domain based on DMRS and at DMRS pilots location without any further interploation. + GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB + FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data +ID = GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL + DESC = gNodeB channel estimation in the frequency domain based on DMRS and interploation. + GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB + FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,dataI +ID = GNB_PHY_UL_PAYLOAD_RX_BITS + DESC = gNodeB slot payload after decoder + GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB + FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data ID = GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE DESC = gNodeB channel estimation in the frequency domain GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB @@ -119,6 +143,10 @@ ID = GNB_PHY_UL_TIME_CHANNEL_ESTIMATE DESC = gNodeB channel estimation in the time domain GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : buffer,chest_t +ID = GNB_PHY_UL_SNR_ESTIMATE + DESC = gNodeB SNR estimation based on SRS + GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB + FORMAT = int,gNB_ID : int,rnti : int,frame : int,subframe : int,antenna : buffer,snr ID = GNB_PHY_PRACH_INPUT_SIGNAL DESC = gNodeB input data in the time domain for slots with PRACH detection GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB @@ -201,6 +229,22 @@ ID = NRUE_MAC_DL_RAR_PDU_WITH_DATA DESC = NR MAC downlink PDU for RAR GROUP = ALL:MAC:UE:WIRESHARK FORMAT = int,rnti : int,frame : int,slot : buffer,data +ID = GNB_MAC_DL + DESC = NR MAC downlink scheduler decision for an UE + GROUP = ALL:MAC:GNB + FORMAT = int,rnti : int,frame : int,slot : int,mcs : int,tbs +ID = GNB_MAC_LCID_DL + DESC = NR MAC downlink scheduler decision for an UE for a specific LCID + GROUP = ALL:MAC:GNB + FORMAT = int,rnti : int,frame : int,slot : int,lcid : int,data_size : int,tx_list_occupancy +ID = GNB_MAC_UL + DESC = NR MAC uplink scheduler decision for an UE + GROUP = ALL:MAC:GNB + FORMAT = int,rnti : int,frame : int,slot : int,mcs : int,tbs +ID = GNB_MAC_LCID_UL + DESC = NR MAC uplink traffic received for an UE for a specific LCID + GROUP = ALL:MAC:GNB + FORMAT = int,rnti : int,frame : int,slot : int,lcid : int,data_size #RLC logs ID = ENB_RLC_DL @@ -1352,6 +1396,14 @@ ID = UE_PHY_MEAS DESC = UE PHY measurements GROUP = ALL:PHY:GRAPHIC:HEAVY:UE FORMAT = int,eNB_ID : int,frame : int,subframe : int,rsrp : int,rssi : int,snr: int,rx_power: int,noise_power: int,w_cqi: int,freq_offset +ID = UE_PHY_UL_PAYLOAD_TX_BITS + DESC = UE UL Tx bits in one slot before decoder and scrambler + GROUP = ALL:PHY:GRAPHIC:HEAVY:UE + FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_tx : int,number_of_bits : buffer,data +ID = UE_PHY_UL_SCRAMBLED_TX_BITS + DESC = UE UL Tx bits in one slot after scrambler + GROUP = ALL:PHY:GRAPHIC:HEAVY:UE + FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_tx : int,number_of_bits : buffer,data #for debug/test - not used ID = first diff --git a/common/utils/T/tracer/CMakeLists.txt b/common/utils/T/tracer/CMakeLists.txt index e1c79ffdf6..56568c905e 100644 --- a/common/utils/T/tracer/CMakeLists.txt +++ b/common/utils/T/tracer/CMakeLists.txt @@ -62,9 +62,13 @@ if(T_TRACER_GUI) tracer_logger tracer_view tracer_events) target_link_libraries(gnb PRIVATE png) - add_executable(ue ue.c) - target_link_libraries(ue PRIVATE tracer_utils tracer_filter tracer_gui + add_executable(gnb_mac gnb_mac.c) + target_link_libraries(gnb_mac PRIVATE tracer_utils tracer_filter tracer_gui tracer_logger tracer_view tracer_events) + + add_executable(ue ue.c) + target_link_libraries(ue PRIVATE tracer_utils tracer_view tracer_gui + tracer_logger tracer_filter tracer_events) target_link_libraries(ue PRIVATE png) add_executable(vcd vcd.c) @@ -77,5 +81,5 @@ if(T_TRACER_GUI) add_subdirectory(gui) - add_dependencies(T_tools enb gnb ue vcd to_vcd) + add_dependencies(T_tools enb gnb gnb_mac ue vcd to_vcd) endif() diff --git a/common/utils/T/tracer/Makefile b/common/utils/T/tracer/Makefile index 807347f5a4..ce99eabbe8 100644 --- a/common/utils/T/tracer/Makefile +++ b/common/utils/T/tracer/Makefile @@ -8,7 +8,7 @@ XLIBS=-lX11 -lpng -lXft all: record replay extract_config textlog enb ue vcd macpdu2wireshark \ extract_input_subframe extract_output_subframe to_vcd extract multi \ - gnb + gnb t_tracer_app_gnb t_tracer_app_ue gnb_mac record: utils.o record.o database.o configuration.o $(CC) $(CFLAGS) -o record $^ $(LIBS) @@ -65,6 +65,18 @@ gnb: utils.o gnb.o database.o event.o handler.o configuration.o \ filter/filter.a $(CC) $(CFLAGS) -o gnb $^ $(LIBS) $(XLIBS) +t_tracer_app_gnb: utils.o t_tracer_app_gnb.o database.o event.o handler.o \ + configuration.o logger/logger.a filter/filter.a + $(CC) $(CFLAGS) -o t_tracer_app_gnb $^ $(LIBS) $(XLIBS) + +t_tracer_app_ue: utils.o t_tracer_app_ue.o database.o event.o handler.o \ + configuration.o logger/logger.a filter/filter.a + $(CC) $(CFLAGS) -o t_tracer_app_ue $^ $(LIBS) $(XLIBS) + +gnb_mac: gnb_mac.o gui/gui.a view/view.a logger/logger.a filter/filter.a \ + utils.o database.o configuration.o handler.o event.o + $(CC) $(CFLAGS) -o gnb_mac $^ $(LIBS) $(XLIBS) + multi.o: ../incgen/T_IDs.h ../incgen/T_IDs.h: ../T_messages.txt @@ -91,6 +103,7 @@ clean: rm -f *.o core tracer_remote textlog enb ue vcd record replay rm -f extract_config macpdu2wireshark extract_input_subframe rm -f extract_output_subframe to_vcd extract multi gnb + rm -f t_tracer_app_gnb t_tracer_app_ue gnb_mac cd gui && $(MAKE) clean cd view && $(MAKE) clean cd logger && $(MAKE) clean diff --git a/common/utils/T/tracer/enb.c b/common/utils/T/tracer/enb.c index 5bb1cb87e2..f48f8e7dd7 100644 --- a/common/utils/T/tracer/enb.c +++ b/common/utils/T/tracer/enb.c @@ -340,12 +340,12 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, xy_plot_set_range(g, w, 0, 1024*10, -10, 80); l = new_ttilog(h, database, "ENB_PHY_PUCCH_1_ENERGY", "frame", "subframe", "threshold", 0); - v = new_view_tti(10, g, w, new_color(g, "#ff0000")); + v = new_view_tti(10, g, w, new_color(g, "#ff0000"), 10); logger_add_view(l, v); e->pucch1_energy_ue_threshold_logger = l; l = new_ttilog(h, database, "ENB_PHY_PUCCH_1_ENERGY", "frame", "subframe", "energy", 1); - v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10); logger_add_view(l, v); e->pucch1_energy_ue_energy_logger = l; @@ -368,7 +368,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, line, w, -1); l = new_ticked_ttilog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe", "ENB_PHY_DLSCH_UE_DCI", "mcs", 0, -1); - v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10); logger_add_view(l, v); e->dl_mcs_logger = l; @@ -379,7 +379,7 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, line, w, -1); l = new_ticked_ttilog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe", "ENB_PHY_ULSCH_UE_DCI", "mcs", 0, -1); - v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10); logger_add_view(l, v); e->ul_mcs_logger = l; @@ -394,8 +394,8 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, col, w, -1); container_set_child_growable(g, col, w, 1); l = new_throughputlog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe", - "ENB_PHY_DLSCH_UE_DCI", "TBS"); - v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2); + "ENB_PHY_DLSCH_UE_DCI", "TBS", 10); + v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 10); logger_add_view(l, v); /* UE x UL PHY (truly: DCI) throughput */ @@ -409,8 +409,8 @@ static void enb_main_gui(enb_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, col, w, -1); container_set_child_growable(g, col, w, 1); l = new_throughputlog(h, database, "ENB_PHY_DL_TICK", "frame", "subframe", - "ENB_PHY_ULSCH_UE_DCI", "TBS"); - v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2); + "ENB_PHY_ULSCH_UE_DCI", "TBS", 10); + v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 10); logger_add_view(l, v); /* downlink/uplink UE DCIs */ diff --git a/common/utils/T/tracer/event.h b/common/utils/T/tracer/event.h index e3d7637bf4..594cf94d09 100644 --- a/common/utils/T/tracer/event.h +++ b/common/utils/T/tracer/event.h @@ -8,7 +8,7 @@ #endif /* maximum number of arguments for the T macro */ -#define T_MAX_ARGS 32 +#define T_MAX_ARGS 72 enum event_arg_type { EVENT_INT, diff --git a/common/utils/T/tracer/gnb.c b/common/utils/T/tracer/gnb.c index 22567492f8..d47f627341 100644 --- a/common/utils/T/tracer/gnb.c +++ b/common/utils/T/tracer/gnb.c @@ -19,6 +19,7 @@ typedef struct { widget *pucch_pusch_iq_plot; widget *ul_freq_estimate_ue_xy_plot; widget *ul_time_estimate_ue_xy_plot; + widget *ul_snr_estimate_ue_xy_plot; widget *current_ue_label; widget *current_ue_button; widget *prev_ue_button; @@ -26,6 +27,7 @@ typedef struct { logger *pucch_pusch_iq_logger; logger *ul_freq_estimate_ue_logger; logger *ul_time_estimate_ue_logger; + logger *ul_snr_ue_logger; } gnb_gui; typedef struct { @@ -98,6 +100,9 @@ static void set_current_ue(gui *g, gnb_data *e, int ue) sprintf(s, "UL channel estimation in time domain [UE %d]", ue); xy_plot_set_title(g, e->e->ul_time_estimate_ue_xy_plot, s); + + sprintf(s, "UL SNR per RB based on SRS [UE %d]", ue); + xy_plot_set_title(g, e->e->ul_snr_estimate_ue_xy_plot, s); } void reset_ue_ids(void) @@ -146,12 +151,13 @@ static void gnb_main_gui(gnb_gui *e, gui *g, event_handler *h, void *database, g logger *l; view *v; - main_window = new_toplevel_window(g, 1500, 230, "gNB tracer"); + main_window = new_toplevel_window(g, 1500, 460, "gNB tracer"); top_container = new_container(g, VERTICAL); widget_add_child(g, main_window, top_container, -1); line = new_container(g, HORIZONTAL); widget_add_child(g, top_container, line, -1); + logo = new_image(g, openair_logo_png, openair_logo_png_len); /* logo + prev/next UE buttons */ @@ -206,6 +212,21 @@ static void gnb_main_gui(gnb_gui *e, gui *g, event_handler *h, void *database, g logger_add_view(l, v); e->ul_time_estimate_ue_logger = l; + line = new_container(g, HORIZONTAL); + widget_add_child(g, top_container, line, -1); + + /* UL SNR based on SRS */ + w = new_xy_plot(g, 1280, 200, "", 190); + e->ul_snr_estimate_ue_xy_plot = w; + widget_add_child(g, line, w, -1); + xy_plot_set_range(g, w, 0, 273, -10, 65); + l = new_framelog(h, database, "GNB_PHY_UL_SNR_ESTIMATE", "subframe", "snr"); + framelog_set_update_only_at_sf9(l, 0); + framelog_set_type_buffer_db(l); + v = new_view_xy(273, 10, g, w, new_color(g, "#0c0c72"), XY_LOOP_MODE); + logger_add_view(l, v); + e->ul_snr_ue_logger = l; + set_current_ue(g, ed, ed->ue); register_notifier(g, "click", e->current_ue_button, click, ed); register_notifier(g, "click", e->prev_ue_button, click, ed); @@ -251,6 +272,7 @@ int main(int n, char **v) on_off(database, "GNB_PHY_PUCCH_PUSCH_IQ", is_on, 1); on_off(database, "GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE", is_on, 1); on_off(database, "GNB_PHY_UL_TIME_CHANNEL_ESTIMATE", is_on, 1); + on_off(database, "GNB_PHY_UL_SNR_ESTIMATE", is_on, 1); gnb_data.ue = 0; gnb_data.e = ⪚ diff --git a/common/utils/T/tracer/gnb_mac.c b/common/utils/T/tracer/gnb_mac.c new file mode 100644 index 0000000000..84f29b8f82 --- /dev/null +++ b/common/utils/T/tracer/gnb_mac.c @@ -0,0 +1,332 @@ +#include +#include +#include +#include + +#include "utils.h" +#include "gui/gui.h" +#include "view/view.h" +#include "logger/logger.h" +#include "filter/filter.h" +#include "database.h" +#include "configuration.h" +#include "handler.h" + +typedef struct { + int used; +} ue_list_item; + +typedef struct { + widget *container; +} gnb_gui; + +typedef struct { + int socket; + gui *g; + gnb_gui *gg; + event_handler *h; + void *database; + ue_list_item ues[65536]; + int rnti_arg; +} gnb_data; + +void *gui_thread(void *_g) +{ + gui *g = _g; + gui_loop(g); + return 0; +} + +void add_ue(gnb_data *gd, int rnti, int lcid) +{ + event_handler *h = gd->h; + void *database = gd->database; + gnb_gui *gg = gd->gg; + gui *g = gd->g; + widget *line; + widget *w, *w2, *col; + view *v; + logger *l; + + gd->ues[rnti].used = 1; + + line = new_container(g, HORIZONTAL); + widget_add_child(g, gg->container, line, -1); + + /* label */ + char s[512]; + sprintf(s, "UE %d", rnti); + widget *label = new_label(g, s); + widget_add_child(g, line, label, -1); + + /* DL MCS */ + w = new_xy_plot(g, 128, 55, "DL mcs", 20); + xy_plot_set_range(g, w, 0, 1024*20, -2, 30); + widget_add_child(g, line, w, -1); + l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot", + "GNB_MAC_DL", "mcs", 0, -1); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20); + logger_add_view(l, v); + logger_set_filter(l, + filter_eq( + filter_evarg(database, "GNB_MAC_DL", "rnti"), + filter_int(rnti))); + + /* DL TBS */ + col = new_container(g, VERTICAL); + widget_add_child(g, line, col, -1); + w = new_xy_plot(g, 70, 10, "DL tbs", 35); + w2 = new_textarea(g, 70, 11, 64); + xy_plot_set_range(g, w, 0, 1024*20, 0, 1000); + xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK); + widget_add_child(g, col, w2, -1); + widget_add_child(g, col, w, -1); + container_set_child_growable(g, col, w, 1); + l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot", + "GNB_MAC_DL", "tbs", 0, -1); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20); + view_tti_enable_automax(v, w2); + logger_add_view(l, v); + logger_set_filter(l, + filter_eq( + filter_evarg(database, "GNB_MAC_DL", "rnti"), + filter_int(rnti))); + + /* DL lcid throughput */ + col = new_container(g, VERTICAL); + widget_add_child(g, line, col, -1); + sprintf(s, "DL lcid %d", lcid); + w = new_xy_plot(g, 70, 10, s, 35); + w2 = new_textarea(g, 70, 11, 64); + xy_plot_set_range(g, w, 0, 1000, 0, 100000); + xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK); + widget_add_child(g, col, w2, -1); + widget_add_child(g, col, w, -1); + container_set_child_growable(g, col, w, 1); + l = new_throughputlog(h, database, "GNB_PHY_DL_TICK", "frame", "slot", + "GNB_MAC_LCID_DL", "data_size", 20); + v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 20); + logger_add_view(l, v); + logger_set_filter(l, + filter_and( + filter_eq( + filter_evarg(database, "GNB_MAC_LCID_DL", "rnti"), + filter_int(rnti)), + filter_eq( + filter_evarg(database, "GNB_MAC_LCID_DL", "lcid"), + filter_int(lcid)))); + + /* UL MCS */ + w = new_xy_plot(g, 128, 55, "UL mcs", 20); + xy_plot_set_range(g, w, 0, 1024*20, -2, 30); + widget_add_child(g, line, w, -1); + /* GNB_PHY_DL_TICK (and not UL) because GNB_MAC_UL is from DCI */ + l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot", + "GNB_MAC_UL", "mcs", 0, -1); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20); + logger_add_view(l, v); + logger_set_filter(l, + filter_eq( + filter_evarg(database, "GNB_MAC_UL", "rnti"), + filter_int(rnti))); + + /* UL TBS */ + col = new_container(g, VERTICAL); + widget_add_child(g, line, col, -1); + w = new_xy_plot(g, 70, 10, "UL tbs", 35); + w2 = new_textarea(g, 70, 11, 64); + xy_plot_set_range(g, w, 0, 1024*20, 0, 1000); + xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK); + widget_add_child(g, col, w2, -1); + widget_add_child(g, col, w, -1); + container_set_child_growable(g, col, w, 1); + /* GNB_PHY_DL_TICK (and not UL) because GNB_MAC_UL is from DCI */ + l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot", + "GNB_MAC_UL", "tbs", 0, -1); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20); + view_tti_enable_automax(v, w2); + logger_add_view(l, v); + logger_set_filter(l, + filter_eq( + filter_evarg(database, "GNB_MAC_UL", "rnti"), + filter_int(rnti))); + + /* UL lcid throughput */ + col = new_container(g, VERTICAL); + widget_add_child(g, line, col, -1); + sprintf(s, "UL lcid %d", lcid); + w = new_xy_plot(g, 70, 10, s, 35); + w2 = new_textarea(g, 70, 11, 64); + xy_plot_set_range(g, w, 0, 1000, 0, 100000); + xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK); + widget_add_child(g, col, w2, -1); + widget_add_child(g, col, w, -1); + container_set_child_growable(g, col, w, 1); + l = new_throughputlog(h, database, "GNB_PHY_UL_TICK", "frame", "slot", + "GNB_MAC_LCID_UL", "data_size", 20); + v = new_view_scrolltti(10, g, w, new_color(g, "#0c0c72"), w2, 20); + logger_add_view(l, v); + logger_set_filter(l, + filter_and( + filter_eq( + filter_evarg(database, "GNB_MAC_LCID_UL", "rnti"), + filter_int(rnti)), + filter_eq( + filter_evarg(database, "GNB_MAC_LCID_UL", "lcid"), + filter_int(lcid)))); + + /* lcid RLC tx buffer occupancy */ + col = new_container(g, VERTICAL); + widget_add_child(g, line, col, -1); + sprintf(s, "rlc tx %d", lcid); + w = new_xy_plot(g, 70, 10, s, 35); + w2 = new_textarea(g, 70, 11, 64); + xy_plot_set_range(g, w, 0, 1024*20, 0, 1000); + xy_plot_set_tick_type(g, w, XY_PLOT_SCROLL_TICK); + widget_add_child(g, col, w2, -1); + widget_add_child(g, col, w, -1); + container_set_child_growable(g, col, w, 1); + l = new_ticked_ttilog(h, database, "GNB_PHY_DL_TICK", "frame", "slot", + "GNB_MAC_LCID_DL", "tx_list_occupancy", 0, -1); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 20); + view_tti_enable_automax(v, w2); + logger_add_view(l, v); + logger_set_filter(l, + filter_and( + filter_eq( + filter_evarg(database, "GNB_MAC_LCID_DL", "rnti"), + filter_int(rnti)), + filter_eq( + filter_evarg(database, "GNB_MAC_LCID_DL", "lcid"), + filter_int(lcid)))); +} + +void build_gui(gnb_gui *gg, gui *g) +{ + widget *main_window; + + main_window = new_toplevel_window(g, 900, 1000, "gNB MAC tracer"); + gg->container = new_container(g, VERTICAL); + widget_add_child(g, main_window, gg->container, -1); +} + +void usage(void) +{ + printf( +"options:\n" +" -d this option is mandatory\n" +" -ip connect to given IP address (default %s)\n" +" -p connect to given port (default %d)\n", + DEFAULT_REMOTE_IP, + DEFAULT_REMOTE_PORT + ); + exit(1); +} + +void check_new_ue(void *_gd, event e) +{ + gnb_data *gd = _gd; + int rnti = e.e[gd->rnti_arg].i; + if (!gd->ues[rnti].used) + add_ue(gd, rnti, 4); +} + +int main(int n, char **v) +{ + gui *g; + gnb_gui gg; + gnb_data *gd; + char *database_filename = NULL; + void *database; + char *ip = DEFAULT_REMOTE_IP; + int port = DEFAULT_REMOTE_PORT; + event_handler *h; + int *is_on; + int number_of_events; + int i; + + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); + if (!strcmp(v[i], "-d")) { if (i > n-2) usage(); database_filename = v[++i]; continue; } + if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; } + if (!strcmp(v[i], "-p")) { if (i > n-2) usage(); port = atoi(v[++i]); continue; } + usage(); + } + + if (database_filename == NULL) { + printf("ERROR: provide a database file (-d)\n"); + exit(1); + } + + database = parse_database(database_filename); + + load_config_file(database_filename); + + number_of_events = number_of_ids(database); + is_on = calloc(number_of_events, sizeof(int)); + if (is_on == NULL) abort(); + + on_off(database, "GNB_PHY_DL_TICK", is_on, 1); + on_off(database, "GNB_MAC_DL", is_on, 1); + on_off(database, "GNB_MAC_LCID_DL", is_on, 1); + on_off(database, "GNB_PHY_UL_TICK", is_on, 1); + on_off(database, "GNB_MAC_UL", is_on, 1); + on_off(database, "GNB_MAC_LCID_UL", is_on, 1); + + gd = calloc(1, sizeof(*gd)); if (!gd) abort(); + + h = new_handler(database); + + g = gui_init(); + new_thread(gui_thread, g); + + build_gui(&gg, g); + + gd->g = g; + gd->gg = ≫ + gd->h = h; + gd->database = database; + + /* get rnti_arg from event GNB_MAC_DL */ + int event_id = event_id_from_name(database, "GNB_MAC_DL"); + database_event_format f = get_format(database, event_id); + gd->rnti_arg = -1; + for (i = 0; i < f.count; i++) { + if (!strcmp(f.name[i], "rnti")) gd->rnti_arg = i; + } + if (gd->rnti_arg == -1) { + printf("fatal: event 'GNB_MAC_DL' does not have argument 'rnti'\n"); + exit(1); + } + if (strcmp(f.type[gd->rnti_arg], "int") != 0) { + printf("fatal: argument 'rnti' of event 'GNB_MAC_DL' is not 'int'\n"); + exit(1); + } + + register_handler_function(h, event_id, check_new_ue, gd); + + OBUF ebuf = {.osize = 0, .omaxsize = 0, .obuf = NULL}; + + gd->socket = -1; + +restart: + clear_remote_config(); + if (gd->socket != -1) close(gd->socket); + gd->socket = connect_to(ip, port); + + /* send the first message - activate selected traces */ + int t = 1; + if (socket_send(gd->socket, &t, 1) == -1 || + socket_send(gd->socket, &number_of_events, sizeof(int)) == -1 || + socket_send(gd->socket, is_on, number_of_events * sizeof(int)) == -1) + goto restart; + + while (1) { + event e; + e = get_event(gd->socket, &ebuf, database); + if (e.type == -1) goto restart; + handle_event(h, e); + } + + return 0; +} diff --git a/common/utils/T/tracer/gui/gui.h b/common/utils/T/tracer/gui/gui.h index 0fb96db325..b2fce32cff 100644 --- a/common/utils/T/tracer/gui/gui.h +++ b/common/utils/T/tracer/gui/gui.h @@ -54,6 +54,8 @@ void container_set_child_growable(gui *_gui, widget *_this, int xy_plot_new_plot(gui *gui, widget *this, int color); void xy_plot_set_range(gui *gui, widget *this, float xmin, float xmax, float ymin, float ymax); +void xy_plot_get_range(gui *gui, widget *this, + float *xmin, float *xmax, float *ymin, float *ymax); void xy_plot_set_points(gui *gui, widget *this, int plot, int npoints, float *x, float *y); void xy_plot_get_dimensions(gui *gui, widget *this, int *width, int *height); diff --git a/common/utils/T/tracer/gui/xy_plot.c b/common/utils/T/tracer/gui/xy_plot.c index c10b76c6ee..cc198475c2 100644 --- a/common/utils/T/tracer/gui/xy_plot.c +++ b/common/utils/T/tracer/gui/xy_plot.c @@ -280,6 +280,22 @@ void xy_plot_set_range(gui *_gui, widget *_this, gunlock(g); } +void xy_plot_get_range(gui *_gui, widget *_this, + float *xmin, float *xmax, float *ymin, float *ymax) +{ + struct gui *g = _gui; + struct xy_plot_widget *this = _this; + + glock(g); + + *xmin = this->xmin; + *xmax = this->xmax; + *ymin = this->ymin; + *ymax = this->ymax; + + gunlock(g); +} + void xy_plot_set_points(gui *_gui, widget *_this, int plot, int npoints, float *x, float *y) { diff --git a/common/utils/T/tracer/hacks/Makefile b/common/utils/T/tracer/hacks/Makefile index 7157406796..2c96e67823 100644 --- a/common/utils/T/tracer/hacks/Makefile +++ b/common/utils/T/tracer/hacks/Makefile @@ -3,7 +3,7 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I. -I.. LIBS=-lX11 -lm -lpng -lXft -all: dump_nack_signal time_meas timeplot multi-rru-clean +all: dump_nack_signal time_meas timeplot multi-rru-clean ant0 plot-ofdm dump_nack_signal: ../utils.o ../database.o ../configuration.o ../event.o \ dump_nack_signal.o @@ -19,10 +19,25 @@ timplot: timeplot.o multi-rru-clean: ../utils.o ../database.o ../event.o ../configuration.o multi-rru-clean.o $(CC) $(CFLAGS) -o $@ $^ $(LIBS) +ant0: ant0.o ../utils.o ../database.o ../configuration.o ../event.o + $(CC) $(CFLAGS) -o $@ $^ -lm + +#ant0 needs good compilation, conversion to float is heavy +ant0.o: ant0.c + $(CC) $(CFLAGS) -c -o $@ $< -march=native -ffast-math -O3 + +plot-ofdm: plot-ofdm.o ../utils.o + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) -lfftw3f + +#plot-ofdm needs good compilation +plot-ofdm.o: plot-ofdm.c + $(CC) $(CFLAGS) -c -o $@ $< -march=native -ffast-math -O3 + .PHONY: all %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< clean: - rm -f *.o core dump_nack_signal time_meas timeplot multi-rru-clean + rm -f *.o core dump_nack_signal time_meas timeplot multi-rru-clean \ + ant0 plot-ofdm diff --git a/common/utils/T/tracer/hacks/ant0.c b/common/utils/T/tracer/hacks/ant0.c new file mode 100644 index 0000000000..3de4dac325 --- /dev/null +++ b/common/utils/T/tracer/hacks/ant0.c @@ -0,0 +1,259 @@ +#include +#include +#include +#include +#include +#include "database.h" +//#include "utils.h" +#include "configuration.h" +#include "event.h" + +void usage(void) +{ + fprintf(stderr, +"options:\n" +" -d this option is mandatory\n" +" -o this option is mandatory (use - to dump to stdout)\n" +" -ip connect to given IP address (default %s)\n" +" -p connect to given port (default %d)\n" +" -n save maximum 'max' IQ points (may be a bit more)\n" +" -nosig don't intercept ctrl+c, ctrl+z (it may mess up when piping to another tool)\n" +" -e trace given event (default 'USRP_TX_ANT0')\n" +" -b trace given buffer (default 'data')\n" +" -no-timestamp don't use 'timestamp' to fill missing transmission\n" +" -scale divide 16bits input by given value for float output (default 32768.)\n" +" -s16 output short instead of float\n", + DEFAULT_REMOTE_IP, + DEFAULT_REMOTE_PORT + ); + exit(1); +} + +volatile int run = 1; + +static int socket = -1; + +void force_stop(int x) +{ + fprintf(stderr, "\ngently quit...\n"); + close(socket); + socket = -1; + run = 0; +} + +int main(int n, char **v) +{ + char *database_filename = NULL; + char *output_filename = NULL; + FILE *out; + void *database; + char *ip = DEFAULT_REMOTE_IP; + int port = DEFAULT_REMOTE_PORT; + int *is_on; + int number_of_events; + int i; + char mt; + long max = -1; + long dumped = 0; + int nosig = 0; + char *event_name = "USRP_TX_ANT0"; + char *buffer_name = "data"; + int no_timestamp = 0; + float scale = 32768; + int do_float = 1; + + /* write on a socket fails if the other end is closed and we get SIGPIPE */ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) abort(); + + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) usage(); + if (!strcmp(v[i], "-d")) { if (i > n-2) usage(); database_filename = v[++i]; continue; } + if (!strcmp(v[i], "-o")) { if (i > n-2) usage(); output_filename = v[++i]; continue; } + if (!strcmp(v[i], "-ip")) { if (i > n-2) usage(); ip = v[++i]; continue; } + if (!strcmp(v[i], "-p")) { if (i > n-2) usage(); port = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-n")) { if (i > n-2) usage(); max = atol(v[++i]); continue; } + if (!strcmp(v[i], "-nosig")) { nosig = 1; continue; } + if (!strcmp(v[i], "-e")) { if (i > n-2) usage(); event_name = v[++i]; continue; } + if (!strcmp(v[i], "-b")) { if (i > n-2) usage(); buffer_name = v[++i]; continue; } + if (!strcmp(v[i], "-no-timestamp")) { no_timestamp = 1; continue; } + if (!strcmp(v[i], "-scale")) { if (i > n-2) usage(); scale = atof(v[++i]); continue; } + if (!strcmp(v[i], "-s16")) { do_float = 0; continue; } + usage(); + } + + if (database_filename == NULL) { + fprintf(stderr, "ERROR: provide a database file (-d)\n"); + exit(1); + } + if (output_filename == NULL) { + fprintf(stderr, "ERROR: provide an output file (-o)\n"); + exit(1); + } + + database = parse_database(database_filename); + load_config_file(database_filename); + + /* get the event and fields from database */ + int tx_ant0_id = event_id_from_name(database, event_name); + database_event_format f = get_format(database, tx_ant0_id); + +#define G(var_name, var_type, var) \ + if (!strcmp(f.name[i], var_name)) { \ + if (strcmp(f.type[i], var_type)) abort(); \ + var = i; \ + continue; \ + } + + int timestamp_id = -1; + int data_id = -1; + for (i = 0; i < f.count; i++) { + /* there is a typo in T_messages.txt, "timestap" instead of "timestamp" */ + if (!no_timestamp) + G("timestap", "int", timestamp_id); + G(buffer_name, "buffer", data_id); + } + if ((!no_timestamp && timestamp_id == -1) || data_id == -1) { + if (data_id == -1) + fprintf(stderr, "fatal: field '%s' of event '%s' does not exist\n", + buffer_name, event_name); + if (!no_timestamp && timestamp_id == -1) + fprintf(stderr, "fatal: field 'timestamp' of event '%s' does not exist\n", + event_name); + exit(1); + } + + number_of_events = number_of_ids(database); + is_on = calloc(number_of_events, sizeof(int)); + if (is_on == NULL) abort(); + + on_off(database, event_name, is_on, 1); + + /* connect to tracee */ + socket = connect_to(ip, port); + + /* activate trace */ + mt = 1; + if (socket_send(socket, &mt, 1) == -1 || + socket_send(socket, &number_of_events, sizeof(int)) == -1 || + socket_send(socket, is_on, number_of_events * sizeof(int)) == -1) + abort(); + + /* - means to output to stdout */ + if (!strcmp(output_filename, "-")) { + out = stdout; + } else { + out = fopen(output_filename, "w"); + if (out == NULL) { + perror(output_filename); + exit(1); + } + } + + if (!nosig) { + /* exit on ctrl+c and ctrl+z */ + if (signal(SIGQUIT, force_stop) == SIG_ERR) abort(); + if (signal(SIGINT, force_stop) == SIG_ERR) abort(); + if (signal(SIGTSTP, force_stop) == SIG_ERR) abort(); + } + + OBUF ebuf = {.osize = 0, .omaxsize = 0, .obuf = NULL}; + + /* read messages */ + unsigned int last_timestamp = 0; + int last_count = 0; + int first = 1; + + /* stop if max reached */ + while ((max == -1 || dumped < max) && run) { + event e; + e = get_event(socket, &ebuf, database); + + if (e.type == -1) break; + if (e.type != tx_ant0_id) continue; + + unsigned int timestamp = 0; + if (!no_timestamp) + timestamp = e.e[timestamp_id].i; + int count = e.e[data_id].bsize / 4; + +#if 0 + fprintf(stderr, "timestamp %u buffer %p count %d not transmitted %d delta %d\n", + timestamp, + e.e[data_id].b, + count, + timestamp - (last_timestamp + last_count), + timestamp - last_timestamp); +#endif + + /* rfsimulator may send 1 sample with old time when a new client connects + * let's reject this packet + */ + if (!first && timestamp < last_timestamp + last_count) { + /* more than 1 sample is not accepted */ + if (count != 1) { + fprintf(stderr, "fatal: past transmission detected (%d samples)\n", count); + abort(); + } + fprintf(stderr, "past transmission detected (%d samples), ignore\n", count); + continue; + } + + /* insert missing samples */ + if (!no_timestamp && !first) { + int missing = timestamp - (last_timestamp + last_count); + if (missing < 0) abort(); + while (missing) { + /* limit size of array miss[], it's allocated on the stack */ + int count = missing > 65536 ? 65536 : missing; + float miss[count * 2]; + memset(miss, 0, count * 2 * sizeof(float)); + + if (fwrite(miss, count * 2 * sizeof(float), 1, out) != 1) { + fprintf(stderr, "error writing to %s\n", output_filename); + if (strcmp(output_filename, "-")) + fclose(out); + close(socket); + exit(1); + } + dumped += count; + missing -= count; + } + } + + first = 0; + + if (do_float) { + /* transform to float */ + float iq[count * 2]; + short *iq_short = (short *)e.e[data_id].b; + for (int i = 0; i < count * 2; i++) + iq[i] = iq_short[i] / scale; + + /* save */ + if (fwrite(iq, count * 2 * sizeof(float), 1, out) != 1) { + fprintf(stderr, "error writing to %s\n", output_filename); + if (strcmp(output_filename, "-")) + fclose(out); + exit(1); + } + } else { + /* save directly as short */ + if (fwrite(e.e[data_id].b, count * 2 * 2, 1, out) != 1) { + fprintf(stderr, "error writing to %s\n", output_filename); + if (strcmp(output_filename, "-")) + fclose(out); + exit(1); + } + } + dumped += count; + + last_timestamp = timestamp; + last_count = count; + } + + if (strcmp(output_filename, "-")) + fclose(out); + close(socket); + + return 0; +} diff --git a/common/utils/T/tracer/hacks/plot-ofdm.c b/common/utils/T/tracer/hacks/plot-ofdm.c new file mode 100644 index 0000000000..3f6e0b9dce --- /dev/null +++ b/common/utils/T/tracer/hacks/plot-ofdm.c @@ -0,0 +1,351 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +const int width = 14 * 20 * 4; +int height; + +/* when vzoom = 1 each pixel represents 1 RE + * when 2, it is max of 2 vertical REs + * useful if height of plot is to big + * (with 106 RB we already reach 106*12 = 1272 pixels, so with even bigger + * bandwidths...) + */ +int vzoom = 1; +/* when hzoom = 1 each pixel represents 1 RE + * when 2, it is max of 2 horizontal REs + * useful to slow down display + */ +int hzoom = 1; +/* intensity is to scale the input + * normally, as float, cabs(input) is in [0..1] + * to get pixel color we *255 + * but maybe it's too intense, or not enough, + * so let's have a control the user can set at will + */ +float intensity = 255; + +pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + +void lock(void) +{ + pthread_mutex_lock(&m); +} + +void unlock(void) +{ + pthread_mutex_unlock(&m); +} + +typedef struct { + Display *d; + Window w; + XImage *img; + unsigned char *img_data; + int img_pos; +} gui_t; + +/* delay management begin */ + +long double frame_time; + +void time_start(void) +{ + struct timespec l; + if (clock_gettime(CLOCK_REALTIME, &l)) abort(); + frame_time = l.tv_sec * 1000000000. + l.tv_nsec; +} + +void delay(int fps) +{ + struct timespec t; + struct timespec delay; + long double cur_time; + + frame_time += 1000000000. / fps; + + if (clock_gettime(CLOCK_REALTIME, &t)) abort(); + + cur_time = t.tv_sec * 1000000000. + t.tv_nsec; + + if (frame_time < cur_time) { fprintf(stderr, "ERROR: we late\n"); return; } + + delay.tv_nsec = ((uint64_t)(frame_time-cur_time)) % 1000000000; + delay.tv_sec = ((uint64_t)(frame_time-cur_time)) / 1000000000; + + if (pselect(0, NULL, NULL, NULL, &delay, NULL)) { fprintf(stderr, "ERROR: pselect fails\n"); exit(1); } +} + +/* delay management end */ + +static void *gui_thread(void *_g) +{ + time_start(); + + gui_t *g = _g; + while (1) { + XEvent e; while (XPending(g->d)) XNextEvent(g->d, &e); + lock(); + XPutImage(g->d, g->w, DefaultGC(g->d, DefaultScreen(g->d)), g->img, 0, 0, 0, 0, + width, height/vzoom); + unlock(); + delay(10); + } + return 0; +} + +unsigned char re_to_pixel(float re) +{ + float v = fminf(255, re * intensity); + return v; +} + +unsigned char mix(unsigned char a, unsigned char b) +{ + return a > b ? a : b; +} + +void usage(void) +{ + printf("options:\n"); + printf(" -f input is float, not s16\n"); + printf(" -srate set sampling rate (default 61440000)\n"); + printf(" -prb set number of PRBs (default 106)\n"); + printf(" -mu set mu (default 1, 0 is for 15KHz, 1 for 30KHz, etc.)\n"); + printf(" -no-fft don't do fft, input is in frequency domain\n"); + printf(" -vzoom add some sort of vertical zoom, default 1, passing 2 divides height by 2, etc.\n"); + printf(" -hzoom add some sort of speed control, default 1, passing 2 means 2 REs per pixel, etc.\n"); + printf(" -delay delay 'delay' microseconds between processing of each symbol\n"); + printf(" -intensity set intensity of data pixel (default 255.)\n"); + printf(" -skip skip 'count' samples at beginning\n"); + exit(0); +} + +int main(int n, char **v) +{ + int input_is_float = 0; + int no_fft = 0; + int delay = 0; + int skip = 0; + int symbols_per_subframe; + long sampling_rate = 61440000; + int mu = 1; + int prb = 106; + + /* parse command line arguments */ + for (int i = 1; i < n; i++) { + if (!strcmp(v[i], "-f")) { input_is_float = 1; continue; } + if (!strcmp(v[i], "-no-fft")) { no_fft = 1; continue; } + if (!strcmp(v[i], "-vzoom")) { if (i>n-2) usage(); vzoom = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-hzoom")) { if (i>n-2) usage(); hzoom = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-delay")) { if (i>n-2) usage(); delay = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-intensity")) { if (i>n-2) usage(); intensity = atof(v[++i]); continue; } + if (!strcmp(v[i], "-srate")) { if (i>n-2) usage(); sampling_rate = atol(v[++i]); continue; } + if (!strcmp(v[i], "-prb")) { if (i>n-2) usage(); prb = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-mu")) { if (i>n-2) usage(); mu = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-skip")) { if (i>n-2) usage(); skip = atoi(v[++i]); continue; } + usage(); + } + + symbols_per_subframe = 14 * (1 << mu); + + /* compute durations from sampling rate and mu (scs) */ + /* this is 38.211 5.3.1, a bit simplified/reordered */ + int ofdm_duration = sampling_rate / 15000 / (1 << mu); + int l0_cycle_prefix = sampling_rate / 480000 * (144*64 / (1 << mu) + 16*64) / 4096; + int cycle_prefix = sampling_rate / 480000 * (144*64 / (1 << mu)) / 4096; + + /* small sanity check */ + if (prb * 12 > ofdm_duration) { + printf("fatal: too many PRBs for this sampling rate / mu\n"); + exit(1); + } + + height = prb * 12; + + if (height % vzoom) { fprintf(stderr, "bad vzoom for this height, try 1, 2, 4, ...\n"); return 1; } + + gui_t g = { 0 }; + + /* open X11 display */ + g.d = XOpenDisplay(0); + if (!g.d) { + fprintf(stderr, "could not open display\n"); + return 1; + } + + /* create window */ + g.w = XCreateSimpleWindow(g.d, DefaultRootWindow(g.d), 0, 0, + width, height / vzoom, 0, WhitePixel(g.d, DefaultScreen(g.d)), + WhitePixel(g.d, DefaultScreen(g.d))); + XStoreName(g.d, g.w, "IQ"); + /* enable backing store */ + { + XSetWindowAttributes att; + att.backing_store = Always; + XChangeWindowAttributes(g.d, g.w, CWBackingStore, &att); + } + XSelectInput(g.d, g.w, + KeyPressMask | + ButtonPressMask | + ButtonReleaseMask | + PointerMotionMask | + ExposureMask | + StructureNotifyMask); + XMapWindow(g.d, g.w); + + g.img_data = calloc(1, width * height/vzoom * 4); if (!g.img_data) abort(); + g.img = XCreateImage(g.d, DefaultVisual(g.d, DefaultScreen(g.d)), 24 /*depth*/, + ZPixmap, 0 /*offset*/, (char*)g.img_data, width, height/vzoom, 8, 0); + + new_thread(gui_thread, &g); + + /* fft data */ + int fft_size = ofdm_duration; + float complex *in = fftwf_malloc(sizeof(float complex) * fft_size); + float complex *out = fftwf_malloc(sizeof(float complex) * fft_size); + fftwf_plan p_fft = fftwf_plan_dft_1d(fft_size, in, out, + FFTW_FORWARD, FFTW_ESTIMATE); + memset(in, 0, sizeof(float complex) * fft_size); + fftwf_execute(p_fft); + + int symbol = 0; + int back_color = 0; + int hpixel = 0; + + if (skip) { + if (input_is_float) { + float intime[skip * 2]; + if (fread(intime, skip * 8, 1, stdin) != 1) abort(); + } else { + short intime[skip * 2]; + if (fread(intime, skip * 4, 1, stdin) != 1) abort(); + } + } + + while (1) { + int cur_cycle_prefix; + if (symbol == 0 || symbol == 7 * (1 << mu)) + cur_cycle_prefix = l0_cycle_prefix; + else + cur_cycle_prefix = cycle_prefix; + + if (no_fft) goto without_fft; + + /* input signal is in time domain, timing aligned, do FFT */ + + /* read time domain data */ + if (input_is_float) { + float intime[(ofdm_duration + cur_cycle_prefix) * 2]; + if (fread(intime, (ofdm_duration + cur_cycle_prefix) * 8, 1, stdin) != 1) break; + + for (int i = 0; i < fft_size; i++) + /* skip cycle prefix */ + in[i] = intime[(cur_cycle_prefix + i) * 2] + I * intime[(cur_cycle_prefix + i) * 2 + 1]; + } else { + short intime[(ofdm_duration + cur_cycle_prefix) * 2]; + if (fread(intime, (ofdm_duration + cur_cycle_prefix) * 4, 1, stdin) != 1) break; + + for (int i = 0; i < fft_size; i++) + /* skip cycle prefix */ + in[i] = intime[(cur_cycle_prefix + i) * 2] / 2048. + I * intime[(cur_cycle_prefix + i) * 2 + 1] / 2048.; + } + + /* go to freq domain */ + fftwf_execute(p_fft); + + goto after_fft; + +without_fft: + /* input data is symbols, each containing full FFT data */ + if (input_is_float) { + float infreq[fft_size * 2]; + if (fread(infreq, fft_size * 2 * 4, 1, stdin) != 1) break; + + for (int i = 0; i < fft_size; i++) + out[i] = infreq[i * 2] + I * infreq[i * 2 + 1]; + } else { + short infreq[ofdm_duration * 2]; + if (fread(infreq, fft_size * 2 * 2, 1, stdin) != 1) break; + + for (int i = 0; i < fft_size; i++) + out[i] = infreq[i * 2] / 2048. + I * infreq[i * 2 + 1] / 2048.; + } + +after_fft: + lock(); + + /* extract data of this ofdm symbol */ + unsigned char *p = g.img_data + g.img_pos * 4; + int front_pos = (g.img_pos + 8) % width; + unsigned char *pfront = g.img_data + front_pos * 4; + for (int i = prb * 12 - 1; i >= 0; i -= vzoom) { + /* take the max */ + float out_val = 0; + for (int j = 0; j < vzoom; j++) { + int start = - prb * 12 / 2; + int pos = start + i + j; + /* neg freq are at the end of fft data array */ + int pos_in_fft = pos >= 0 + ? pos + : pos + fft_size; + float v = cabs(out[pos_in_fft]); + if (v > out_val) out_val = v; + } + int color = re_to_pixel(out_val); + /* grey level image mixed with some background changing every slot */ + unsigned char back_col[2][3] = { + { 100, 90, 90 }, + { 100, 60, 60, } + }; + if (hpixel == 0) { + p[0] = p[1] = p[2] = color; + } else { + p[0] = mix(p[0], color); + p[1] = mix(p[1], color); + p[2] = mix(p[2], color); + } + if (hpixel == hzoom - 1) { + p[0] = mix(p[0], back_col[back_color][0]); + p[1] = mix(p[1], back_col[back_color][1]); + p[2] = mix(p[2], back_col[back_color][2]); + } + p[3] = 255; + p += width * 4; + pfront[0] = 255; + pfront[1] = 128; + pfront[2] = 128; + pfront[3] = 255; + pfront += width * 4; + } + + unlock(); + + hpixel++; + if (hpixel == hzoom) { + hpixel = 0; + g.img_pos++; + if (g.img_pos == width) g.img_pos = 0; + } + + symbol++; + if (symbol == symbols_per_subframe) symbol = 0; + + /* switch back color every slot */ + if (symbol % 14 == 0) + back_color = 1 - back_color; + + if (delay) usleep(delay); + } + + return 0; +} diff --git a/common/utils/T/tracer/logger/framelog.c b/common/utils/T/tracer/logger/framelog.c index 45ae3e399f..040482278f 100644 --- a/common/utils/T/tracer/logger/framelog.c +++ b/common/utils/T/tracer/logger/framelog.c @@ -8,6 +8,11 @@ #include #include +typedef enum { + FRAMELOG_BUFFER, + FRAMELOG_BUFFER_dB, +} framelog_buffer_type_t; + struct framelog { struct logger common; void *database; @@ -22,6 +27,7 @@ struct framelog { int skip_current; /* internal data for the skip mechanism */ int skip_on; /* internal data for the skip mechanism */ int update_only_at_sf9; + framelog_buffer_type_t type; }; static void _event(void *p, event e) @@ -52,7 +58,10 @@ static void _event(void *p, event e) } if (l->skip_on) return; - nsamples = bsize / (2*sizeof(int16_t)); + if (l->type == FRAMELOG_BUFFER) + nsamples = bsize / (2 * sizeof(int16_t)); + else + nsamples = bsize / sizeof(int16_t); if (l->blength != nsamples * 10) { l->blength = nsamples * 10; @@ -71,10 +80,15 @@ static void _event(void *p, event e) } /* TODO: compute the LOGs in the plotter (too much useless computations) */ - for (i = 0; i < nsamples; i++) { - int I = ((int16_t *)buffer)[i*2]; - int Q = ((int16_t *)buffer)[i*2+1]; - l->buffer[subframe * nsamples + i] = 10*log10(1.0+(float)(I*I+Q*Q)); + if (l->type == FRAMELOG_BUFFER_dB) { + for (i = 0; i < nsamples; i++) + l->buffer[subframe * nsamples + i] = ((int16_t *)buffer)[i]; + } else { + for (i = 0; i < nsamples; i++) { + int I = ((int16_t *)buffer)[i * 2]; + int Q = ((int16_t *)buffer)[i * 2 + 1]; + l->buffer[subframe * nsamples + i] = 10 * log10(1.0 + (float)(I * I + Q * Q)); + } } if (l->update_only_at_sf9 == 0 || subframe == 9) @@ -132,6 +146,8 @@ logger *new_framelog(event_handler *h, void *database, abort(); } + ret->type = FRAMELOG_BUFFER; + return ret; } @@ -153,3 +169,9 @@ void framelog_set_update_only_at_sf9(logger *_this, int update_only_at_sf9) struct framelog *l = _this; l->update_only_at_sf9 = update_only_at_sf9; } + +void framelog_set_type_buffer_db(logger *_this) +{ + struct framelog *l = _this; + l->type = FRAMELOG_BUFFER_dB; +} diff --git a/common/utils/T/tracer/logger/logger.h b/common/utils/T/tracer/logger/logger.h index d746161e70..d8458ef104 100644 --- a/common/utils/T/tracer/logger/logger.h +++ b/common/utils/T/tracer/logger/logger.h @@ -15,8 +15,8 @@ logger *new_ticked_ttilog(void *event_handler, void *database, char *event_name, char *data_varname, int convert_to_dB, float empty_value); logger *new_throughputlog(void *event_handler, void *database, - char *tick_event_name, char *frame_varname, char *subframe_varname, - char *event_name, char *data_varname); + char *tick_event_name, char *frame_varname, char *tick_varname, + char *event_name, char *data_varname, int ticks_per_frame); logger *new_timelog(void *event_handler, void *database, char *event_name); logger *new_ticklog(void *event_handler, void *database, char *event_name, char *frame_name, char *subframe_name); @@ -30,6 +30,7 @@ logger *new_iqdotlog(void *event_handler, void *database, void framelog_set_skip(logger *_this, int skip_delay); void framelog_set_update_only_at_sf9(logger *_this, int update_only_at_sf9); +void framelog_set_type_buffer_db(logger *_this); void textlog_dump_buffer(logger *_this, int dump_buffer); void textlog_raw_time(logger *_this, int raw_time); diff --git a/common/utils/T/tracer/logger/throughputlog.c b/common/utils/T/tracer/logger/throughputlog.c index 8a2d46da91..5f066df343 100644 --- a/common/utils/T/tracer/logger/throughputlog.c +++ b/common/utils/T/tracer/logger/throughputlog.c @@ -13,13 +13,14 @@ struct throughputlog { struct logger common; void *database; int tick_frame_arg; - int tick_subframe_arg; + int tick_tick_arg; int data_frame_arg; - int data_subframe_arg; + int data_tick_arg; int data_arg; int last_tick_frame; - int last_tick_subframe; - unsigned long bits[1000]; + int last_tick_tick; + int ticks_per_frame; + unsigned long *bits; unsigned long total; int insert_point; char *tick_event_name; @@ -32,16 +33,16 @@ static void _event(void *p, event e) { struct throughputlog *l = p; int frame; - int subframe; + int tick; unsigned long value; if (l->common.filter != NULL && filter_eval(l->common.filter, e) == 0) return; frame = e.e[l->data_frame_arg].i; - subframe = e.e[l->data_subframe_arg].i; + tick = e.e[l->data_tick_arg].i; - if (frame != l->last_tick_frame || subframe != l->last_tick_subframe) { + if (frame != l->last_tick_frame || tick != l->last_tick_tick) { printf("WARNING: %s:%d: data comes without previous tick!\n", __FILE__, __LINE__); return; @@ -62,28 +63,34 @@ static void _tick_event(void *p, event e) struct throughputlog *l = p; int i; int frame; - int subframe; + int tick; if (l->tick_filter != NULL && filter_eval(l->tick_filter, e) == 0) return; frame = e.e[l->tick_frame_arg].i; - subframe = e.e[l->tick_subframe_arg].i; + tick = e.e[l->tick_tick_arg].i; for (i = 0; i < l->common.vsize; i++) - l->common.v[i]->append(l->common.v[i], frame, subframe, (double)l->total); + l->common.v[i]->append(l->common.v[i], frame, tick, (double)l->total); - l->insert_point = (l->insert_point + 1) % 1000; - l->total -= l->bits[l->insert_point]; - l->bits[l->insert_point] = 0; + while (l->last_tick_frame != frame || l->last_tick_tick != tick) { + l->insert_point = (l->insert_point + 1) % (100 * l->ticks_per_frame); + l->total -= l->bits[l->insert_point]; + l->bits[l->insert_point] = 0; + l->last_tick_tick++; + if (l->last_tick_tick == l->ticks_per_frame) { + l->last_tick_tick = 0; + l->last_tick_frame++; + l->last_tick_frame %= 1024; + } + } - l->last_tick_frame = frame; - l->last_tick_subframe = subframe; } logger *new_throughputlog(event_handler *h, void *database, - char *tick_event_name, char *frame_varname, char *subframe_varname, - char *event_name, char *data_varname) + char *tick_event_name, char *frame_varname, char *tick_varname, + char *event_name, char *data_varname, int ticks_per_frame) { struct throughputlog *ret; int event_id; @@ -106,21 +113,21 @@ logger *new_throughputlog(event_handler *h, void *database, f = get_format(database, event_id); - /* look for frame and subframe */ + /* look for frame and tick */ ret->tick_frame_arg = -1; - ret->tick_subframe_arg = -1; + ret->tick_tick_arg = -1; for (i = 0; i < f.count; i++) { if (!strcmp(f.name[i], frame_varname)) ret->tick_frame_arg = i; - if (!strcmp(f.name[i], subframe_varname)) ret->tick_subframe_arg = i; + if (!strcmp(f.name[i], tick_varname)) ret->tick_tick_arg = i; } if (ret->tick_frame_arg == -1) { printf("%s:%d: frame argument '%s' not found in event '%s'\n", __FILE__, __LINE__, frame_varname, event_name); abort(); } - if (ret->tick_subframe_arg == -1) { - printf("%s:%d: subframe argument '%s' not found in event '%s'\n", - __FILE__, __LINE__, subframe_varname, event_name); + if (ret->tick_tick_arg == -1) { + printf("%s:%d: tick argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, tick_varname, event_name); abort(); } if (strcmp(f.type[ret->tick_frame_arg], "int") != 0) { @@ -128,9 +135,9 @@ logger *new_throughputlog(event_handler *h, void *database, __FILE__, __LINE__, frame_varname); abort(); } - if (strcmp(f.type[ret->tick_subframe_arg], "int") != 0) { + if (strcmp(f.type[ret->tick_tick_arg], "int") != 0) { printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", - __FILE__, __LINE__, subframe_varname); + __FILE__, __LINE__, tick_varname); abort(); } @@ -141,13 +148,13 @@ logger *new_throughputlog(event_handler *h, void *database, f = get_format(database, event_id); - /* look for frame, subframe and data args */ + /* look for frame, tick and data args */ ret->data_frame_arg = -1; - ret->data_subframe_arg = -1; + ret->data_tick_arg = -1; ret->data_arg = -1; for (i = 0; i < f.count; i++) { if (!strcmp(f.name[i], frame_varname)) ret->data_frame_arg = i; - if (!strcmp(f.name[i], subframe_varname)) ret->data_subframe_arg = i; + if (!strcmp(f.name[i], tick_varname)) ret->data_tick_arg = i; if (!strcmp(f.name[i], data_varname)) ret->data_arg = i; } if (ret->data_frame_arg == -1) { @@ -155,9 +162,9 @@ logger *new_throughputlog(event_handler *h, void *database, __FILE__, __LINE__, frame_varname, event_name); abort(); } - if (ret->data_subframe_arg == -1) { - printf("%s:%d: subframe argument '%s' not found in event '%s'\n", - __FILE__, __LINE__, subframe_varname, event_name); + if (ret->data_tick_arg == -1) { + printf("%s:%d: tick argument '%s' not found in event '%s'\n", + __FILE__, __LINE__, tick_varname, event_name); abort(); } if (ret->data_arg == -1) { @@ -170,9 +177,9 @@ logger *new_throughputlog(event_handler *h, void *database, __FILE__, __LINE__, frame_varname); abort(); } - if (strcmp(f.type[ret->data_subframe_arg], "int") != 0) { + if (strcmp(f.type[ret->data_tick_arg], "int") != 0) { printf("%s:%d: argument '%s' has wrong type (should be 'int')\n", - __FILE__, __LINE__, subframe_varname); + __FILE__, __LINE__, tick_varname); abort(); } if (strcmp(f.type[ret->data_arg], "int") != 0 && @@ -183,6 +190,10 @@ logger *new_throughputlog(event_handler *h, void *database, abort(); } + ret->ticks_per_frame = ticks_per_frame; + ret->bits = calloc(100 * ticks_per_frame, sizeof(unsigned long)); + if (ret->bits == NULL) abort(); + return ret; } diff --git a/common/utils/T/tracer/shared_memory_config.h b/common/utils/T/tracer/shared_memory_config.h new file mode 100644 index 0000000000..c126d85801 --- /dev/null +++ b/common/utils/T/tracer/shared_memory_config.h @@ -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 + */ + +/*! \file common/utils/T/tracer/shared_memory_config.h + * \brief shared memory to store data captured by T-Tracer services to be processed by data recording application + * \author Abdo Gaber + * \date 2024 + * \version 1.0 + * \company Emerson, NI Test and Measurement + * \email: + * \note + * \warning + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef _SHARED_MEMORY_CONFIG_H_ +#define _SHARED_MEMORY_CONFIG_H_ + +#define SHMSIZE ((122.88e6 / (100 * 20)) * 1000 * 8) // Assume capture in 1000, each I+Q represented by 8 byts +// 122.88e6: 10ms at 100 MHz BW of 5G NR +// 20: 20 slots in 10ms +// subcarrier spacing: 30 KHz + +// for gNB T Tracer App +#define GETKEYDIR1_gNB ("/tmp/gnb_app1") +#define GETKEYDIR2_gNB ("/tmp/gnb_app2") +#define PROJECTID_gNB (2335) + +// for UET Tracer App +#define GETKEYDIR1_UE ("/tmp/ue_app1") +#define GETKEYDIR2_UE ("/tmp/ue_app2") +#define PROJECTID_UE (2336) + +void err_exit(char *buf); +int create_shm(char **addrN, const char *pathname, int projectId); +void del_shm(char *addr, int shm_id); + +#endif /* _SHARED_MEMORY_CONFIG_H_ */ diff --git a/common/utils/T/tracer/t_tracer_app_gnb.c b/common/utils/T/tracer/t_tracer_app_gnb.c new file mode 100644 index 0000000000..3cb0325e39 --- /dev/null +++ b/common/utils/T/tracer/t_tracer_app_gnb.c @@ -0,0 +1,973 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file common/utils/T/tracer/t_tracer_app_gnb.c + * \brief T-Tracer gnb service to capture tracee Messages from gNB, it is used by data recording application + * \author Abdo Gaber + * \date 2025 + * \version 1.0 + * \company Emerson, NI Test and Measurement + * \email: + * \note + * \warning + */ + +#include +#include +#include +#include +#include +#include "database.h" +#include "event.h" +#include "handler.h" +#include "logger/logger.h" +#include "utils.h" +#include "event_selector.h" +#include "configuration.h" +#include "shared_memory_config.h" +#include +#include +#include +#include +#include +#include +#include +#define MAX_FRAME_INDEX 1023 +#define MAX_SLOT_INDEX 19 +#define DEBUG_T_Tracer +#define DEBUG_BUFFER +// Duration to discard recording in milliseconds to mitigate reading data from +// the buffer in the stack from the previous record +#define DISCARD_RECORD_DURATION_MS 10 + +// Combine bytes in - little-endian format +int combine_bytes(const uint8_t *bytes, size_t num_bytes) +{ + int result = 0; + for (size_t i = 0; i < num_bytes; ++i) { + result |= (bytes[i] << (i * 8)); + } + return result; +} + +// Convert an integer to an array of bytes - little-endian format +void int_to_bytes(int num, uint8_t *bytes, size_t num_bytes) +{ + for (size_t i = 0; i < num_bytes; ++i) { + bytes[i] = (num >> (i * 8)) & 0xFF; + } +} + +// Check if the message is in the list of bits messages +bool is_bits_messages(int traces_bits_support_data_Collection_format_idx[], int n_bits_msgs, int msg_id) +{ + for (int i = 0; i < n_bits_msgs; i++) { + if (msg_id == traces_bits_support_data_Collection_format_idx[i]) { + return true; + } + } + return false; +} + +// Get the current time +struct timespec get_current_time() +{ + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + return time; +} + +// Function to convert timespec to microseconds +long long timespec_to_microseconds(struct timespec time) +{ + return (time.tv_sec * 1000000LL) + (time.tv_nsec / 1000); +} + +// Calculate the time difference in milliseconds +double calculate_time_difference(struct timespec start, struct timespec end) +{ + double start_ms = start.tv_sec * 1000.0 + start.tv_nsec / 1000000.0; + double end_ms = end.tv_sec * 1000.0 + end.tv_nsec / 1000000.0; + return end_ms - start_ms; +} + +// Get Time Stamp in microseconds in YYYYMMDDHHMMSSmmmuuu format +char *get_time_stamp_usec(char time_stamp_str[]) +{ + // initialization to measure time stamp --This part should be moved to inilization part + time_t my_time; + struct tm *timeinfo; + time(&my_time); + struct timeval tv; + + // get time stamp + timeinfo = localtime(&my_time); + gettimeofday(&tv, NULL); + // Add time stamp: yyyy mm dd hh mm ss usec + uint16_t year = timeinfo->tm_year + 1900; + uint8_t mon = timeinfo->tm_mon + 1; + uint8_t mday = timeinfo->tm_mday; + uint8_t hour = timeinfo->tm_hour; + uint8_t min = timeinfo->tm_min; + uint8_t sec = timeinfo->tm_sec; + uint16_t usec = (tv.tv_usec); + // printf ("Time stamp: %d_%d_%d_%d_%d_%d_%d \n",year,mon,mday,hour,min,sec,usec); + // sprintf(time_stamp_str, "%d_%d_%d_%d_%d_%d_%d",year,mon,mday,hour,min,sec,usec); + sprintf(time_stamp_str, "%04d%02d%02d%02d%02d%02d%06d", year, mon, mday, hour, min, sec, usec); + + return time_stamp_str; +} + +// Convert timestamp string to integer +int convert_time_stamp_to_int(const char *timestamp) +{ + return atoi(timestamp); +} + +// Split timestamp string and convert to integer +int split_time_stamp_and_convert_to_int(char time_stamp_str[], int shift, int length) +{ + char time_part[length + 1]; // Buffer to hold the date part YYYYMMDD or HHMMSSmmm + // Copy the first 8 or 9 characters (YYYYMMDD) to HHMMSSmmm + strncpy(time_part, time_stamp_str + shift, length); + time_part[length] = '\0'; // Null-terminate the string + // Convert timestamp string to integer + return convert_time_stamp_to_int(time_part); +} + +void err_exit(char *buf) +{ + fprintf(stderr, "%s\n", buf); + exit(1); +} + +// create shared memory +int create_shm(char **addrN, const char *shm_path, int projectId) +{ + key_t key; + if (-1 != open(shm_path, O_CREAT, 0777)) { + key = ftok(shm_path, projectId); + } else { + err_exit("Error: open shared memory"); + } + + if (key < 0) { + err_exit("Error: ftok error"); + } + + int shm_id; + shm_id = shmget(key, SHMSIZE, IPC_CREAT | IPC_EXCL | 0664); + if (shm_id == -1) { + if (errno == EEXIST) { + printf("Error: shared memeory already exist\n"); + shm_id = shmget(key, 0, 0); + printf("reference shm_id = %d\n", shm_id); + } else { + perror("errno"); + err_exit("shmget error"); + } + } + char *addr; + // address to attach - attach for read & write + if ((addr = shmat(shm_id, 0, 0)) == (void *)-1) { + if (shmctl(shm_id, IPC_RMID, NULL) == -1) + err_exit("Error: shmctl error"); + else { + printf("Attach shared memory failed\n"); + printf("remove shared memory identifier successful\n"); + } + err_exit("shmat error"); + } + *addrN = addr; + return shm_id; +} + +// delete shared memory +void del_shm(char *addr, int shm_id) +{ + if (shmdt(addr) < 0) + err_exit("shmdt error"); + + if (shmctl(shm_id, IPC_RMID, NULL) == -1) + err_exit("shmctl error"); + else { + printf("Remove shared memory identifier successful\n"); + } +} + +/* this function sends the activated traces to the nr-softmodem */ +void activate_traces(int socket, int number_of_events, int *is_on) +{ + char t = 1; + if (socket_send(socket, &t, 1) == -1 || socket_send(socket, &number_of_events, sizeof(int)) == -1 + || socket_send(socket, is_on, number_of_events * sizeof(int)) == -1) + abort(); +} + +void usage(void) +{ + printf( + "options:\n" + " -d this option is mandatory\n" + " -ip connect to given IP address (default %s)\n" + " -p connect to given port (default %d)\n", + DEFAULT_REMOTE_IP, + DEFAULT_REMOTE_PORT); + exit(1); +} + +// class to store the message and the action to enable capture selected data +// 0: do not record message +// 1: record message +struct trace_struct { + char on_off_name[100]; + int on_off_action; +}; + +// struct for trace message based on Data Collection Trace Messages Structure +// you need to define the vararibles of each message +typedef struct { + /* Data Collection Trace Message Structure */ + int frame; + int slot; + int datetime_yyyymmdd; + int datetime_hhmmssmmm; + int frame_type, freq_range, subcarrier_spacing, cyclic_prefix, symbols_per_slot; + int Nid_cell, rnti; + int rb_size, rb_start, start_symbol_index, nr_of_symbols; + int qam_mod_order, mcs_index, mcs_table, nrOfLayers, transform_precoding; + int dmrs_config_type, ul_dmrs_symb_pos, number_dmrs_symbols; + int dmrs_port, dmrs_nscid, nb_antennas_rx, number_of_bits; + int data_size, data; +} event_trace_msg_data; + +void setup_trace_msg_data(event_trace_msg_data *d, void *database) +{ + database_event_format f; + int i; + + /* Data Collection Trace Message Structure */ + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : + // int,dmrs_port : int,dmrs_nscid : + // int,nb_antennas_rx : int,number_of_bits : buffer,data + + // Initialize the data structure + d->frame = -1; + d->slot = -1; + d->datetime_yyyymmdd = -1; + d->datetime_hhmmssmmm = -1; + d->frame_type = -1; + d->freq_range = -1; + d->subcarrier_spacing = -1; + d->cyclic_prefix = -1; + d->symbols_per_slot = -1; + d->Nid_cell = -1; + d->rnti = -1; + d->rb_size = -1; + d->rb_start = -1; + d->start_symbol_index = -1; + d->nr_of_symbols = -1; + d->qam_mod_order = -1; + d->mcs_index = -1; + d->mcs_table = -1; + d->nrOfLayers = -1; + d->transform_precoding = -1; + d->dmrs_config_type = -1; + d->ul_dmrs_symb_pos = -1; + d->number_dmrs_symbols = -1; + d->dmrs_port = -1; + d->dmrs_nscid = -1; + d->nb_antennas_rx = -1; + d->number_of_bits = -1; + d->data = -1; + +/* this macro looks for a particular element and checks its type */ +#define G(var_name, var_type, var) \ + if (!strcmp(f.name[i], var_name)) { \ + if (strcmp(f.type[i], var_type)) { \ + printf("Error: Trace Message has a bad type for %s\n", var_name); \ + exit(1); \ + } \ + var = i; \ + continue; \ + } + + /* ------------------------------*/ + /* Create Macro for Data Collection Trace Message */ + /* ------------------------------*/ + // Data Collection Trace Message Structure + // Example: GNB_PHY_UL_FD_PUSCH_IQ, GNB_PHY_UL_FD_DMRS_ID, + // GNB_PHY_UL_FD_CHAN_EST_DMRS_POS, GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL + // GNB_PHY_UL_PAYLOAD_RX_BITS + // UE_PHY_UL_SCRAMBLED_TX_BITS + // UE_PHY_UL_PAYLOAD_TX_BITS + // Get a template of any message based on Data Collection Trace Messages Structure + int Trace_MSG_ID = event_id_from_name(database, "GNB_PHY_UL_FD_PUSCH_IQ"); + f = get_format(database, Trace_MSG_ID); + + /* get the elements of the trace + * the value is an index in the event, see below */ + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : + // int,dmrs_port : int,dmrs_nscid : + // int,nb_antennas_rx : int,number_of_bits : buffer,data + + for (i = 0; i < f.count; i++) { + G("frame", "int", d->frame) + G("slot", "int", d->slot) + G("datetime_yyyymmdd", "int", d->datetime_yyyymmdd) + G("datetime_hhmmssmmm", "int", d->datetime_hhmmssmmm) + G("frame_type", "int", d->frame_type) + G("freq_range", "int", d->freq_range) + G("subcarrier_spacing", "int", d->subcarrier_spacing) + G("cyclic_prefix", "int", d->cyclic_prefix) + G("symbols_per_slot", "int", d->symbols_per_slot) + G("Nid_cell", "int", d->Nid_cell) + G("rnti", "int", d->rnti) + G("rb_size", "int", d->rb_size) + G("rb_start", "int", d->rb_start) + G("start_symbol_index", "int", d->start_symbol_index) + G("nr_of_symbols", "int", d->nr_of_symbols) + G("qam_mod_order", "int", d->qam_mod_order) + G("mcs_index", "int", d->mcs_index) + G("mcs_table", "int", d->mcs_table) + G("nrOfLayers", "int", d->nrOfLayers) + G("transform_precoding", "int", d->transform_precoding) + G("dmrs_config_type", "int", d->dmrs_config_type) + G("ul_dmrs_symb_pos", "int", d->ul_dmrs_symb_pos) + G("number_dmrs_symbols", "int", d->number_dmrs_symbols) + G("dmrs_port", "int", d->dmrs_port) + G("dmrs_nscid", "int", d->dmrs_nscid) + G("nb_antennas_rx", "int", d->nb_antennas_rx) + G("number_of_bits", "int", d->number_of_bits) + G("data", "buffer", d->data) + } + // if (d->frame == -1 || d->slot == -1) goto error; +#undef G + return; +} + +// Function to check if a value is in the array +int isValueInArray(int value, int arr[], int size) +{ + for (int i = 0; i < size; i++) { + if (arr[i] == value) { + return 1; // Value found + } + } + return 0; // Value not found +} + +void reestablish_connection(int *socket, char *ip, int port, int number_of_events, int *is_on) +{ + clear_remote_config(); + if (*socket != -1) + close(*socket); + + /* connect to the nr-softmodem */ + *socket = connect_to(ip, port); + if (*socket == -1) { + printf("\n Failed to connect to nr-softmodem. Retrying...\n"); + return; + } + printf("\n Connected"); + + /* activate the traces in the nr-softmodem */ + activate_traces(*socket, number_of_events, is_on); + printf("\n Activated Traces in nr-softmodem"); +} + +int main(int n, char **v) +{ + // Define and initialize an array of strings to list + // trace_msgs_support_data_Collection_format + // it is used to parse the requested messages if it is based + // on Data Collection Trace Messages Structure and supported tracer messages indices + char *traces_iq_support_data_Collection_format[] = {"GNB_PHY_UL_FD_PUSCH_IQ", + "GNB_PHY_UL_FD_DMRS", + "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS", + "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL"}; + char *traces_bits_support_data_Collection_format[] = {"GNB_PHY_UL_PAYLOAD_RX_BITS", + "UE_PHY_UL_SCRAMBLED_TX_BITS", + "UE_PHY_UL_PAYLOAD_TX_BITS"}; + // extra number of records to simlify Sync between base station and UE synchronization records. + // if you have network delay, you can increase the number of records to capture + int max_sync_offset = 6; // 6 frames ~ 60 ms + // all supported messages + // Calculate the size of the combined array + int n_iq_msgs = sizeof(traces_iq_support_data_Collection_format) / sizeof(traces_iq_support_data_Collection_format[0]); + int n_bits_msgs = sizeof(traces_bits_support_data_Collection_format) / sizeof(traces_bits_support_data_Collection_format[0]); + int n_msgs_based_data_Collection_format = n_iq_msgs + n_bits_msgs; + + // Create the combined array + char *traces_support_data_Collection_format[n_msgs_based_data_Collection_format]; + // Copy IQ messages to the combined array + for (int i = 0; i < n_iq_msgs; i++) { + traces_support_data_Collection_format[i] = traces_iq_support_data_Collection_format[i]; + } + + // Copy Bits messages to the combined array + for (int i = 0; i < n_bits_msgs; i++) { + traces_support_data_Collection_format[i + n_iq_msgs] = traces_bits_support_data_Collection_format[i]; + } + + uint16_t msg_id = 0; + uint16_t start_frame_number = 0; + uint32_t number_records = 0; // number of records to capture, it is number of slots + // array to store the requested tracer messages indices + int req_tracer_msgs_indices[100] = {0}; + // define variables --> to do: add all of them to be class of pointers + char *database_filename = NULL; + void *database; + char *ip = DEFAULT_REMOTE_IP; + char ip_address[16]; // max IP address length is 15 + 1 for null terminator + int port = DEFAULT_REMOTE_PORT; + int *is_on; + int number_of_events; + int i; + int socket = -1; + char trace_time_stamp_str[30]; + + // data structure for the trace messages based on Data Collection Trace Messages Structure + event_trace_msg_data trace_msg_data; + + // initlization variables + unsigned int bufIdx_wr = 0; + unsigned int bufIdx_rd = 0; + uint8_t num_req_tracer_msgs = 0; + + // initilaze shared memory + char *addr_wr, *addr_rd; + printf("\n Data Collection Service: Initializing shared memory ..."); + printf("\n Directory 1: %s, Directory 2: %s", GETKEYDIR1_gNB, GETKEYDIR2_gNB); + printf("\n Project ID: %d\n", PROJECTID_gNB); + int shm_id_wr = create_shm(&addr_wr, GETKEYDIR1_gNB, PROJECTID_gNB); + int shm_id_rd = create_shm(&addr_rd, GETKEYDIR2_gNB, PROJECTID_gNB); + del_shm(addr_wr, shm_id_wr); + del_shm(addr_rd, shm_id_rd); + shm_id_wr = create_shm(&addr_wr, GETKEYDIR1_gNB, PROJECTID_gNB); + shm_id_rd = create_shm(&addr_rd, GETKEYDIR2_gNB, PROJECTID_gNB); + + /* write on a socket fails if the other end is closed and we get SIGPIPE */ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + abort(); + + /* parse command line options */ + // Port number and IP address are given via API and not via command line + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) + usage(); + if (!strcmp(v[i], "-d")) { + if (i > n - 2) + usage(); + database_filename = v[++i]; + continue; + } + if (!strcmp(v[i], "-ip")) { + if (i > n - 2) + usage(); + ip = v[++i]; + continue; + } + if (!strcmp(v[i], "-p")) { + if (i > n - 2) + usage(); + port = atoi(v[++i]); + continue; + } + usage(); + } + + if (database_filename == NULL) { + printf("ERROR: Provide a database file (-d)\n"); + exit(1); + } + + /* load the database T_messages.txt */ + database = parse_database(database_filename); + load_config_file(database_filename); + + /* an array of int for all the events defined in the database is needed */ + number_of_events = number_of_ids(database); + is_on = calloc(number_of_events, sizeof(int)); + if (is_on == NULL) + abort(); + + // Set first byte of the shared memory to 0 + addr_rd[0] = 0; // important to check if we have new requested messages + + // read requested tracer msg indices from memory + printf("\n Data Collection Service: Waiting for messages request ...\n"); + // 0: Wait + // 1: config + // 2: record + // 3: stop + // Wait for Action Config + while (1) { + if ((uint8_t)(addr_rd[0]) == 0) { + usleep(50); // sleep for 50 us: 0.5 ms slot duration + } + // config state + else if ((uint8_t)(addr_rd[0]) == 1) { + get_time_stamp_usec(trace_time_stamp_str); + printf("\n Received config message. Time Stamp: %s", trace_time_stamp_str); + + // get the IP address length in bytes + bufIdx_rd = 1; + uint8_t ip_address_length = addr_rd[bufIdx_rd]; + bufIdx_rd += 1; // + 1 byte = IP address length + + // read the IP address + for (int i = 0; i < ip_address_length; i++) { + ip_address[i] = addr_rd[bufIdx_rd]; + bufIdx_rd += 1; + } + + ip = ip_address; + + // get the array bytes of the port number : 2 bytes + uint8_t port_number_bytes[2] = {addr_rd[bufIdx_rd], addr_rd[bufIdx_rd + 1]}; + bufIdx_rd += 2; // + 2 bytes = start frame number + + port = combine_bytes(port_number_bytes, 2); + printf("\n Parameters: IP Address length: %d, IP Address: %s, Port Number: %d \n", ip_address_length, ip_address, port); + addr_rd[0] = 0; // reset memory : to wait for record action + break; + } + } + // Establish connection to the nr-softmodem + clear_remote_config(); + if (socket != -1) + close(socket); + + /* connect to the nr-softmodem */ + socket = connect_to(ip, port); + printf("\n Connected to nr-softmodem"); + + // Read Action record or stop + printf("\n Data Collection Service: Waiting for record message ...\n"); + while (1) { + // wait for Action record + if ((uint8_t)(addr_rd[0]) == 0) { + usleep(50); // sleep for 50 us: 0.5 ms slot duration + } + + // quit state + else if ((uint8_t)(addr_rd[0]) == 3) { + printf("\n Received 'stop' command. Exiting..."); + printf("\n "); + // Clean up and exit + break; + } + // record state + else if ((uint8_t)(addr_rd[0]) == 2) { + // clear remote buffer if there is + clear_remote_config(); + get_time_stamp_usec(trace_time_stamp_str); + printf("\n Received record message. Time Stamp: %s", trace_time_stamp_str); + + // read number of requested messages + bufIdx_rd = 1; + num_req_tracer_msgs = addr_rd[bufIdx_rd]; + bufIdx_rd += 1; + printf("\n Number of requested tracer messages: %d,", num_req_tracer_msgs); + // reset memory : action to wait for next record action + addr_rd[0] = 0; + + // read tracer msg IDs - every message ID has been stored in two bytes + for (uint8_t msg_n = 0; msg_n < num_req_tracer_msgs; msg_n++) { + // get the array bytes of the tracer message ID: 2 bytes + uint8_t msg_id_bytes[2] = {addr_rd[bufIdx_rd], addr_rd[bufIdx_rd + 1]}; + bufIdx_rd += 2; // + 2 bytes = message ID + msg_id = combine_bytes(msg_id_bytes, 2); + + req_tracer_msgs_indices[msg_n] = msg_id; + printf(" msg_id: %d, ", msg_id); + } + // get the array bytes of the number of records: 4 bytes + uint8_t number_records_bytes[4] = {addr_rd[bufIdx_rd], + addr_rd[bufIdx_rd + 1], + addr_rd[bufIdx_rd + 2], + addr_rd[bufIdx_rd + 3]}; + bufIdx_rd += 4; // + 4 bytes = number of records + + number_records = combine_bytes(number_records_bytes, 4); + + printf("num_records: %d, ", number_records); + + // get the array bytes of the start frame number : 2 bytes + uint8_t start_frame_number_bytes[2] = {addr_rd[bufIdx_rd], addr_rd[bufIdx_rd + 1]}; + bufIdx_rd += 2; // + 2 bytes = start frame number + + start_frame_number = combine_bytes(start_frame_number_bytes, 2); + + printf("start_frame: %d\n", start_frame_number); + + /* activate the trace in this array */ + printf("\n Activate Tracer messages in on_off array: "); + for (i = 0; i < num_req_tracer_msgs; i++) { + char *on_off_name = event_name_from_id(database, req_tracer_msgs_indices[i]); + on_off(database, on_off_name, is_on, 1); + printf("%d, %s, ", req_tracer_msgs_indices[i], on_off_name); + // on_off(database, "GNB_PHY_DL_OUTPUT_SIGNAL", is_on, 1); + } + + // get the event IDs for the bit messages + int traces_bits_support_data_Collection_format_idx[n_bits_msgs]; + for (int i = 0; i < n_bits_msgs; i++) { + traces_bits_support_data_Collection_format_idx[i] = + event_id_from_name(database, traces_bits_support_data_Collection_format[i]); + } + + // all supported messages + int traces_support_data_Collection_format_idx[n_msgs_based_data_Collection_format]; + for (int i = 0; i < n_msgs_based_data_Collection_format; i++) { + traces_support_data_Collection_format_idx[i] = event_id_from_name(database, traces_support_data_Collection_format[i]); + } + + // setup data for the trace messages + setup_trace_msg_data(&trace_msg_data, database); + printf("\n Setup Trace Data Done"); + + // Get the start time + struct timespec start_time = get_current_time(); + + /* activate the tracee in the nr-softmodem */ + activate_traces(socket, number_of_events, is_on); + printf("\n Activated Traces in nr-softmodem"); + + /* a buffer needed to receive events from the nr-softmodem */ + OBUF ebuf = {osize : 0, omaxsize : 0, obuf : NULL}; + + /* read events */ + int nrecord_idx = 0; + bufIdx_wr = 0; + // logic to be sure that we have a complete slot record + bool start_recording = false; + bool got_ref_frame_slot = false; + int ref_slot = 0; + int ref_frame = 0; + int slot_difference = 0; + int frame_difference = 0; + int current_frame = 0, prev_frame = 0, current_slot = 0, prev_slot = 0; + // offset to sync between base station and UE synchronization records or power measurements + int sync_offset_index = 0; // increase the index only if the index of frame changes after getting all records + // since we will use the frame differece to do extra records, we should be sure that the last slot is recorded completely + printf("\n\n Data Collection Service: Start reading messages ..."); + struct pollfd event_poll_fd; + event_poll_fd.fd = socket; + event_poll_fd.events = POLLIN; + while (1) { + // stop if number of records is done + if ((nrecord_idx >= number_records) && (sync_offset_index >= max_sync_offset)) { + // We added one to the number of records to capture the last record completely if + // we have several messages enabled per slot + break; + } + int poll_ret = poll(&event_poll_fd, 1, 1); // 1 ms timeout for poll + if (poll_ret > 0 && (event_poll_fd.revents & POLLIN)) { + event e = get_event(socket, &ebuf, database); + + if (e.type == -1) { + printf("\n Link broken or unexpected message received. Re-establishing connection...\n"); + reestablish_connection(&socket, ip, port, number_of_events, is_on); + continue; // Skip further processing and retry + } + //------------------------- + // GNB_PHY_UL_FD_PUSCH_IQ, GNB_PHY_UL_FD_DMRS_ID, GNB_PHY_UL_FD_CHAN_EST_DMRS_POS, + // UE_PHY_UL_SCRAMBLED_TX_BITS, GNB_PHY_UL_PAYLOAD_RX_BITS, UE_PHY_UL_PAYLOAD_TX_BITS + //------------------------- + // is it a requested message + if (isValueInArray(e.type, req_tracer_msgs_indices, num_req_tracer_msgs)) { + // is it based on Data Collection Trace Messages Structure + if (isValueInArray(e.type, traces_support_data_Collection_format_idx, n_msgs_based_data_Collection_format)) { + // Start recording from the next slot to mitigate capturing partial data + // check if the current frame and slot are different from the previous frame and slot + // Then, increase the record index + if (start_recording == false) { + if (got_ref_frame_slot == false) { + ref_frame = e.e[trace_msg_data.frame].i; + ref_slot = e.e[trace_msg_data.slot].i; + printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type); + got_ref_frame_slot = true; + } + + current_frame = e.e[trace_msg_data.frame].i; + current_slot = e.e[trace_msg_data.slot].i; + frame_difference = (current_frame - ref_frame + MAX_FRAME_INDEX + 1) % (MAX_FRAME_INDEX + 1); + slot_difference = (current_slot - ref_slot + MAX_SLOT_INDEX + 1) % (MAX_SLOT_INDEX + 1); + printf("\n First frame.slot: %d.%d, current frame.slot: %d.%d, diff frame.slot: %d.%d", + ref_frame, + ref_slot, + current_frame, + current_slot, + frame_difference, + slot_difference); + + if ((ref_frame != current_frame) || (ref_slot != current_slot)) { + start_recording = true; + printf("\n Start recording from frame: %d, slot: %d ", e.e[trace_msg_data.frame].i, e.e[trace_msg_data.slot].i); + } + } + // start recording from the next frame to mitigate capturing partial data + if (start_recording == true) { + /* this is how to access the elements of the Data Collection trace messages. + * we use e.e[] and then the correct suffix, here + * it's .i for the integer and .b for the buffer and .bsize for the buffer size + * see in event.h the structure event_arg + */ + unsigned char *buf = e.e[trace_msg_data.data].b; + + printf("\n\nRecord number: %d", nrecord_idx); +#ifdef DEBUG_BUFFER + printf("\nBuffer index in bytes: %d", bufIdx_wr); +#endif + + // add general message header: message ID, + // T-Tracer Message format + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : + // int,dmrs_port : int,dmrs_nscid : + // int,nb_antennas_rx : int,number_of_bits : buffer,data + memcpy(&addr_wr[bufIdx_wr], &e.type, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.frame].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.slot].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.datetime_yyyymmdd].i, sizeof(uint32_t)); + bufIdx_wr += sizeof(uint32_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.datetime_hhmmssmmm].i, sizeof(uint32_t)); + bufIdx_wr += sizeof(uint32_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.frame_type].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.freq_range].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.subcarrier_spacing].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.cyclic_prefix].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.symbols_per_slot].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.Nid_cell].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rnti].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rb_size].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rb_start].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.start_symbol_index].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nr_of_symbols].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.qam_mod_order].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.mcs_index].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.mcs_table].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nrOfLayers].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.transform_precoding].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_config_type].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.ul_dmrs_symb_pos].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.number_dmrs_symbols].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_port].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_nscid].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nb_antennas_rx].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.number_of_bits].i, sizeof(uint32_t)); + bufIdx_wr += sizeof(uint32_t); + + printf("\nTime Stamp: %d_%d", e.e[trace_msg_data.datetime_yyyymmdd].i, e.e[trace_msg_data.datetime_hhmmssmmm].i); + + // add message body: length in bytes + recorded data + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.data].bsize, sizeof(uint32_t)); + bufIdx_wr += sizeof(uint32_t); + + // read data from buffer and convert from unsigned char * array to int 16 using the right endianness + // T-tracer: Little Endian + // For BITS Messages, example: UE_PHY_UL_SCRAMBLED_TX_BITS: data in bytes + + if (is_bits_messages(traces_bits_support_data_Collection_format_idx, n_bits_msgs, e.type)) { + for (int byte_idx = 0; byte_idx < e.e[trace_msg_data.data].bsize; byte_idx += 1) { + // printf("%d, ", buf[byte_idx]); + memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx], sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + } + + } else { + for (int byte_idx = 0; byte_idx < e.e[trace_msg_data.data].bsize; byte_idx += 2) { + // For a little-endian system: + memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx], sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx + 1], sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + } + } + /* + for (int byte_idx_i = 0; byte_idx_i < e.e[d.nr_ul_fd_dmrs_data].bsize; byte_idx_i+=4) { + int16_t I = buf[byte_idx_i] | (buf[byte_idx_i+1] << 8); + int16_t Q = buf[byte_idx_i+2] | (buf[byte_idx_i+3] << 8); + printf ("idx %d, ", byte_idx_i); + printf ("\n%d", I); + printf ("\n%d", Q); + } + */ + // check if the current frame and slot are different from the previous frame and slot + // Then, increase the record index + current_frame = e.e[trace_msg_data.frame].i; + current_slot = e.e[trace_msg_data.slot].i; + + // increase sync offset index if the current frame is different from the previous frame + if ((current_frame != prev_frame) && nrecord_idx >= number_records) { + sync_offset_index++; + } + + if (current_frame != prev_frame || current_slot != prev_slot) { + nrecord_idx++; + // Update previous frame and slot numbers + prev_frame = current_frame; + prev_slot = current_slot; + } +#ifdef DEBUG_T_Tracer + printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type); + printf("frame %d, slot %d, datetime %d_%d\n", + e.e[trace_msg_data.frame].i, + e.e[trace_msg_data.slot].i, + e.e[trace_msg_data.datetime_yyyymmdd].i, + e.e[trace_msg_data.datetime_hhmmssmmm].i); + printf("frame_type %d, freq_range %d, subcarrier_spacing %d, cyclic_prefix %d, symbols_per_slot %d\n", + e.e[trace_msg_data.frame_type].i, + e.e[trace_msg_data.freq_range].i, + e.e[trace_msg_data.subcarrier_spacing].i, + e.e[trace_msg_data.cyclic_prefix].i, + e.e[trace_msg_data.symbols_per_slot].i); + printf("Nid_cell %d, rnti %d, rb_size %d, rb_start %d, start_symbol_index %d, nr_of_symbols %d\n", + e.e[trace_msg_data.Nid_cell].i, + e.e[trace_msg_data.rnti].i, + e.e[trace_msg_data.rb_size].i, + e.e[trace_msg_data.rb_start].i, + e.e[trace_msg_data.start_symbol_index].i, + e.e[trace_msg_data.nr_of_symbols].i); + printf("qam_mod_order %d, mcs_index %d, mcs_table %d, nrOfLayers %d, transform_precoding %d\n", + e.e[trace_msg_data.qam_mod_order].i, + e.e[trace_msg_data.mcs_index].i, + e.e[trace_msg_data.mcs_table].i, + e.e[trace_msg_data.nrOfLayers].i, + e.e[trace_msg_data.transform_precoding].i); + printf("dmrs_config_type %d, ul_dmrs_symb_pos %d, number_dmrs_symbols %d, dmrs_port %d, dmrs_nscid %d\n", + e.e[trace_msg_data.dmrs_config_type].i, + e.e[trace_msg_data.ul_dmrs_symb_pos].i, + e.e[trace_msg_data.number_dmrs_symbols].i, + e.e[trace_msg_data.dmrs_port].i, + e.e[trace_msg_data.dmrs_nscid].i); + printf("nb_antennas_rx %d, number_of_bits %d, data size %d\n", + e.e[trace_msg_data.nb_antennas_rx].i, + e.e[trace_msg_data.number_of_bits].i, + e.e[trace_msg_data.data].bsize); +#endif + } // End of start recording flag + } // end of if statement for the supported messages based on Data Collection Trace Messages Structure + else { + printf("ERROR: Requested Message is not based on Data Collection Trace Messages Structure\n"); + printf("ERROR: Requested Message ID: %d\n", e.type); + } + } // end of if statement for the requested messages + } // end while loop of reading events + else { + // No data, just loop and check time + usleep(100); // optional: avoid busy-waiting + } + } // End of while loop to read events + + // de-activate the tracee in the nr-softmodem + printf("\n De-activated Tracer message:\n"); + for (i = 0; i < num_req_tracer_msgs; i++) { + char *on_off_name = event_name_from_id(database, req_tracer_msgs_indices[i]); + on_off(database, on_off_name, is_on, 0); + // printf("\n %d, %s, ", req_tracer_msgs_indices[i], on_off_name); + // on_off(database, "GNB_PHY_DL_OUTPUT_SIGNAL", is_on, 1); + } + // De-activate the tracee in the nr-softmodem + activate_traces(socket, number_of_events, is_on); + printf("\n De-activated Traces"); + // Get the end time + struct timespec end_time = get_current_time(); + // Calculate the time difference + double time_diff = calculate_time_difference(start_time, end_time); + printf("Total Time difference: %.2f ms\n", time_diff); + printf("Time difference per record: %.2f ms\n", time_diff / (number_records + max_sync_offset)); + + // discard stale or previous record data for the first DISCARD_RECORD_DURATION_MS + struct timespec record_start, record_now; + clock_gettime(CLOCK_MONOTONIC, &record_start); + + while (1) { + clock_gettime(CLOCK_MONOTONIC, &record_now); + double elapsed_ms = calculate_time_difference(record_start, record_now); + if (elapsed_ms >= DISCARD_RECORD_DURATION_MS) { + break; // Stop after 10ms + } + int poll_ret = poll(&event_poll_fd, 1, 1); // 1 ms timeout for poll + if (poll_ret > 0 && (event_poll_fd.revents & POLLIN)) { + event e = get_event(socket, &ebuf, database); + printf("%d", e.type); + if (e.type == -1) { + printf("\n Link broken or unexpected message received. Re-establishing connection...\n"); + reestablish_connection(&socket, ip, port, number_of_events, is_on); + continue; + } + } else { + // No data, just loop and check time + usleep(100); // optional: avoid busy-waiting + } + } // End of while loop to discard stale records + } + } // End a while loop to check for the "stop" command + // de-activate the tracee in the nr-softmodem + + free_database(database); + free(is_on); + close(socket); + + return 0; +} diff --git a/common/utils/T/tracer/t_tracer_app_ue.c b/common/utils/T/tracer/t_tracer_app_ue.c new file mode 100644 index 0000000000..141bbd2385 --- /dev/null +++ b/common/utils/T/tracer/t_tracer_app_ue.c @@ -0,0 +1,976 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file common/utils/T/tracer/t_tracer_app_ue.c + * \brief T-Tracer UE service to capture tracee Messages from UE, it is used by data recording application + * \author Abdo Gaber + * \date 2025 + * \version 1.0 + * \company Emerson, NI Test and Measurement + * \email: + * \note + * \warning + */ + +#include +#include +#include +#include +#include +#include "database.h" +#include "event.h" +#include "handler.h" +#include "logger/logger.h" +#include "utils.h" +#include "event_selector.h" +#include "configuration.h" +#include "shared_memory_config.h" +#include +#include +#include +#include +#include +#include +#include +#define MAX_FRAME_INDEX 1023 +#define MAX_SLOT_INDEX 19 +#define DEBUG_T_Tracer +#define DEBUG_BUFFER +// Duration to discard recording in milliseconds to mitigate stale or previous record data +#define DISCARD_RECORD_DURATION_MS 10 +// #include + +// Combine bytes in little-endian format +int combine_bytes(const uint8_t *bytes, size_t num_bytes) +{ + int result = 0; + for (size_t i = 0; i < num_bytes; ++i) { + result |= (bytes[i] << (i * 8)); + } + return result; +} + +// Convert an integer to an array of bytes in little-endian format +void int_to_bytes(int num, uint8_t *bytes, size_t num_bytes) +{ + for (size_t i = 0; i < num_bytes; ++i) { + bytes[i] = (num >> (i * 8)) & 0xFF; + } +} + +// Check if the message is in the list of bits messages +bool is_bits_messages(int traces_bits_support_data_Collection_format_idx[], int n_bits_msgs, int msg_id) +{ + for (int i = 0; i < n_bits_msgs; i++) { + if (msg_id == traces_bits_support_data_Collection_format_idx[i]) { + return true; + } + } + return false; +} + +// Get the current time +struct timespec get_current_time() +{ + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + return time; +} + +// Function to convert timespec to microseconds +long long timespec_to_microseconds(struct timespec time) +{ + return (time.tv_sec * 1000000LL) + (time.tv_nsec / 1000); +} + +// Calculate the time difference in milliseconds +double calculate_time_difference(struct timespec start, struct timespec end) +{ + double start_ms = start.tv_sec * 1000.0 + start.tv_nsec / 1000000.0; + double end_ms = end.tv_sec * 1000.0 + end.tv_nsec / 1000000.0; + return end_ms - start_ms; +} + +// Get Time Stamp in microseconds in YYYYMMDDHHMMSSmmmuuu format +char *get_time_stamp_usec(char time_stamp_str[]) +{ + // initialization to measure time stamp --This part should be moved to inilization part + time_t my_time; + struct tm *timeinfo; + time(&my_time); + struct timeval tv; + + // get time stamp + timeinfo = localtime(&my_time); + gettimeofday(&tv, NULL); + // Add time stamp: yyyy mm dd hh mm ss usec + uint16_t year = timeinfo->tm_year + 1900; + uint8_t mon = timeinfo->tm_mon + 1; + uint8_t mday = timeinfo->tm_mday; + uint8_t hour = timeinfo->tm_hour; + uint8_t min = timeinfo->tm_min; + uint8_t sec = timeinfo->tm_sec; + uint16_t usec = (tv.tv_usec); + // printf ("Time stamp: %d_%d_%d_%d_%d_%d_%d \n",year,mon,mday,hour,min,sec,usec); + // sprintf(time_stamp_str, "%d_%d_%d_%d_%d_%d_%d",year,mon,mday,hour,min,sec,usec); + sprintf(time_stamp_str, "%04d%02d%02d%02d%02d%02d%06d", year, mon, mday, hour, min, sec, usec); + + return time_stamp_str; +} + +// Convert timestamp string to integer +int convert_time_stamp_to_int(const char *timestamp) +{ + return atoi(timestamp); +} + +// Split timestamp string and convert to integer +int split_time_stamp_and_convert_to_int(char time_stamp_str[], int shift, int length) +{ + char time_part[length + 1]; // Buffer to hold the date part YYYYMMDD or HHMMSSmmm + // Copy the first 8 or 9 characters (YYYYMMDD) to HHMMSSmmm + strncpy(time_part, time_stamp_str + shift, length); + time_part[length] = '\0'; // Null-terminate the string + // Convert timestamp string to integer + return convert_time_stamp_to_int(time_part); +} + +void err_exit(char *buf) +{ + fprintf(stderr, "%s\n", buf); + exit(1); +} + +// create shared memory +int create_shm(char **addrN, const char *shm_path, int projectId) +{ + key_t key; + if (-1 != open(shm_path, O_CREAT, 0777)) { + key = ftok(shm_path, projectId); + } else { + err_exit("Error: open shared memory"); + } + + if (key < 0) { + err_exit("Error: ftok error"); + } + + int shm_id; + shm_id = shmget(key, SHMSIZE, IPC_CREAT | IPC_EXCL | 0664); + if (shm_id == -1) { + if (errno == EEXIST) { + printf("Error: shared memeory already exist\n"); + shm_id = shmget(key, 0, 0); + printf("reference shm_id = %d\n", shm_id); + } else { + perror("errno"); + err_exit("shmget error"); + } + } + char *addr; + // address to attach - attach for read & write + if ((addr = shmat(shm_id, 0, 0)) == (void *)-1) { + if (shmctl(shm_id, IPC_RMID, NULL) == -1) + err_exit("Error: shmctl error"); + else { + printf("Attach shared memory failed\n"); + printf("remove shared memory identifier successful\n"); + } + err_exit("shmat error"); + } + *addrN = addr; + return shm_id; +} + +// delete shared memory +void del_shm(char *addr, int shm_id) +{ + if (shmdt(addr) < 0) + err_exit("shmdt error"); + + if (shmctl(shm_id, IPC_RMID, NULL) == -1) + err_exit("shmctl error"); + else { + printf("Remove shared memory identifier successful\n"); + } +} + +/* this function sends the activated traces to the nr-softmodem */ +void activate_traces(int socket, int number_of_events, int *is_on) +{ + char t = 1; + if (socket_send(socket, &t, 1) == -1 || socket_send(socket, &number_of_events, sizeof(int)) == -1 + || socket_send(socket, is_on, number_of_events * sizeof(int)) == -1) + abort(); +} + +void usage(void) +{ + printf( + "options:\n" + " -d this option is mandatory\n" + " -ip connect to given IP address (default %s)\n" + " -p connect to given port (default %d)\n", + DEFAULT_REMOTE_IP, + DEFAULT_REMOTE_PORT); + exit(1); +} + +// class to store the message and the action to enable capture selected data +// 0: do not record message +// 1: record message +struct trace_struct { + char on_off_name[100]; + int on_off_action; +}; + +// struct for trace message based on Data Collection Trace Messages Structure +// you need to define the vararibles of each message +typedef struct { + /* Data Collection Trace Message Structure */ + int frame; + int slot; + int datetime_yyyymmdd; + int datetime_hhmmssmmm; + int frame_type, freq_range, subcarrier_spacing, cyclic_prefix, symbols_per_slot; + int Nid_cell, rnti; + int rb_size, rb_start, start_symbol_index, nr_of_symbols; + int qam_mod_order, mcs_index, mcs_table, nrOfLayers, transform_precoding; + int dmrs_config_type, ul_dmrs_symb_pos, number_dmrs_symbols; + int dmrs_port, dmrs_nscid, nb_antennas_tx, number_of_bits; + int data_size, data; +} event_trace_msg_data; + +void setup_trace_msg_data(event_trace_msg_data *d, void *database) +{ + database_event_format f; + int i; + + /* Data Collection Trace Message Structure */ + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : + // int,dmrs_port : int,dmrs_nscid : + // int,nb_antennas_tx : int,number_of_bits : buffer,data + + // Initialize the data structure + d->frame = -1; + d->slot = -1; + d->datetime_yyyymmdd = -1; + d->datetime_hhmmssmmm = -1; + d->frame_type = -1; + d->freq_range = -1; + d->subcarrier_spacing = -1; + d->cyclic_prefix = -1; + d->symbols_per_slot = -1; + d->Nid_cell = -1; + d->rnti = -1; + d->rb_size = -1; + d->rb_start = -1; + d->start_symbol_index = -1; + d->nr_of_symbols = -1; + d->qam_mod_order = -1; + d->mcs_index = -1; + d->mcs_table = -1; + d->nrOfLayers = -1; + d->transform_precoding = -1; + d->dmrs_config_type = -1; + d->ul_dmrs_symb_pos = -1; + d->number_dmrs_symbols = -1; + d->dmrs_port = -1; + d->dmrs_nscid = -1; + d->nb_antennas_tx = -1; + d->number_of_bits = -1; + d->data = -1; + +/* this macro looks for a particular element and checks its type */ +#define G(var_name, var_type, var) \ + if (!strcmp(f.name[i], var_name)) { \ + if (strcmp(f.type[i], var_type)) { \ + printf("Error: Trace Message has a bad type for %s\n", var_name); \ + exit(1); \ + } \ + var = i; \ + continue; \ + } + + /* ------------------------------*/ + /* Create Macro for Data Collection Trace Message */ + /* ------------------------------*/ + // Data Collection Trace Message Structure + // Example: GNB_PHY_UL_FD_PUSCH_IQ, GNB_PHY_UL_FD_DMRS_ID, + // GNB_PHY_UL_FD_CHAN_EST_DMRS_POS, GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL + // GNB_PHY_UL_PAYLOAD_RX_BITS + // UE_PHY_UL_SCRAMBLED_TX_BITS + // UE_PHY_UL_PAYLOAD_TX_BITS + // Get a template of any message based on Data Collection Trace Messages Structure + int Trace_MSG_ID = event_id_from_name(database, "GNB_PHY_UL_FD_PUSCH_IQ"); + f = get_format(database, Trace_MSG_ID); + + /* get the elements of the trace + * the value is an index in the event, see below */ + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : + // int,dmrs_port : int,dmrs_nscid : + // int,nb_antennas_tx : int,number_of_bits : buffer,data + + for (i = 0; i < f.count; i++) { + G("frame", "int", d->frame) + G("slot", "int", d->slot) + G("datetime_yyyymmdd", "int", d->datetime_yyyymmdd) + G("datetime_hhmmssmmm", "int", d->datetime_hhmmssmmm) + G("frame_type", "int", d->frame_type) + G("freq_range", "int", d->freq_range) + G("subcarrier_spacing", "int", d->subcarrier_spacing) + G("cyclic_prefix", "int", d->cyclic_prefix) + G("symbols_per_slot", "int", d->symbols_per_slot) + G("Nid_cell", "int", d->Nid_cell) + G("rnti", "int", d->rnti) + G("rb_size", "int", d->rb_size) + G("rb_start", "int", d->rb_start) + G("start_symbol_index", "int", d->start_symbol_index) + G("nr_of_symbols", "int", d->nr_of_symbols) + G("qam_mod_order", "int", d->qam_mod_order) + G("mcs_index", "int", d->mcs_index) + G("mcs_table", "int", d->mcs_table) + G("nrOfLayers", "int", d->nrOfLayers) + G("transform_precoding", "int", d->transform_precoding) + G("dmrs_config_type", "int", d->dmrs_config_type) + G("ul_dmrs_symb_pos", "int", d->ul_dmrs_symb_pos) + G("number_dmrs_symbols", "int", d->number_dmrs_symbols) + G("dmrs_port", "int", d->dmrs_port) + G("dmrs_nscid", "int", d->dmrs_nscid) + // bug in T-Tracer Framework, need to be checked that is why we are getting + // the right tx antennas only if we set to rx "nb_antennas_rx" + G("nb_antennas_rx", "int", d->nb_antennas_tx) + G("number_of_bits", "int", d->number_of_bits) + G("data", "buffer", d->data) + } + // if (d->frame == -1 || d->slot == -1) goto error; +#undef G + return; +} + +// Function to check if a value is in the array +int isValueInArray(int value, int arr[], int size) +{ + for (int i = 0; i < size; i++) { + if (arr[i] == value) { + return 1; // Value found + } + } + return 0; // Value not found +} + +void reestablish_connection(int *socket, char *ip, int port, int number_of_events, int *is_on) +{ + clear_remote_config(); + if (*socket != -1) + close(*socket); + + /* connect to the nr-softmodem */ + *socket = connect_to(ip, port); + if (*socket == -1) { + printf("\n Failed to connect to nr-softmodem. Retrying...\n"); + return; + } + printf("\n Connected"); + + /* activate the traces in the nr-softmodem */ + activate_traces(*socket, number_of_events, is_on); + printf("\n Activated Traces in nr-softmodem"); +} + +int main(int n, char **v) +{ + // Define and initialize an array of strings to list + // trace_msgs_support_data_Collection_format + // it is used to parse the requested messages if it is based + // on Data Collection Trace Messages Structure and supported tracer messages indices + char *traces_iq_support_data_Collection_format[] = {"GNB_PHY_UL_FD_PUSCH_IQ", + "GNB_PHY_UL_FD_DMRS", + "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS", + "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL"}; + char *traces_bits_support_data_Collection_format[] = {"GNB_PHY_UL_PAYLOAD_RX_BITS", + "UE_PHY_UL_SCRAMBLED_TX_BITS", + "UE_PHY_UL_PAYLOAD_TX_BITS"}; + // extra number of records to simlify Sync between base station and UE synchronization records. + // if you have network delay, you can increase the number of records to capture + int max_sync_offset = 6; // 6 frames ~ 60 ms + // all supported messages + // Calculate the size of the combined array + int n_iq_msgs = sizeof(traces_iq_support_data_Collection_format) / sizeof(traces_iq_support_data_Collection_format[0]); + int n_bits_msgs = sizeof(traces_bits_support_data_Collection_format) / sizeof(traces_bits_support_data_Collection_format[0]); + int n_msgs_based_data_Collection_format = n_iq_msgs + n_bits_msgs; + + // Create the combined array + char *traces_support_data_Collection_format[n_msgs_based_data_Collection_format]; + // Copy IQ messages to the combined array + for (int i = 0; i < n_iq_msgs; i++) { + traces_support_data_Collection_format[i] = traces_iq_support_data_Collection_format[i]; + } + + // Copy Bits messages to the combined array + for (int i = 0; i < n_bits_msgs; i++) { + traces_support_data_Collection_format[i + n_iq_msgs] = traces_bits_support_data_Collection_format[i]; + } + + uint16_t msg_id = 0; + uint16_t start_frame_number = 0; + uint32_t number_records = 0; // number of records to capture, it is number of slots + // array to store the requested tracer messages indices + int req_tracer_msgs_indices[100] = {0}; + // define variables --> to do: add all of them to be class of pointers + char *database_filename = NULL; + void *database; + char *ip = DEFAULT_REMOTE_IP; + char ip_address[16]; // max IP address length is 15 + 1 for null terminator + int port = DEFAULT_REMOTE_PORT; + int *is_on; + int number_of_events; + int i; + int socket = -1; + char trace_time_stamp_str[30]; + + // data structure for the trace messages based on Data Collection Trace Messages Structure + event_trace_msg_data trace_msg_data; + + // initlization variables + unsigned int bufIdx_wr = 0; + unsigned int bufIdx_rd = 0; + uint8_t num_req_tracer_msgs = 0; + + // initilaze shared memory + char *addr_wr, *addr_rd; + printf("\n Data Collection Service: Initializing shared memory ..."); + printf("\n Directory 1: %s, Directory 2: %s", GETKEYDIR1_UE, GETKEYDIR2_UE); + printf("\n Project ID: %d\n", PROJECTID_UE); + int shm_id_wr = create_shm(&addr_wr, GETKEYDIR1_UE, PROJECTID_UE); + int shm_id_rd = create_shm(&addr_rd, GETKEYDIR2_UE, PROJECTID_UE); + del_shm(addr_wr, shm_id_wr); + del_shm(addr_rd, shm_id_rd); + shm_id_wr = create_shm(&addr_wr, GETKEYDIR1_UE, PROJECTID_UE); + shm_id_rd = create_shm(&addr_rd, GETKEYDIR2_UE, PROJECTID_UE); + + /* write on a socket fails if the other end is closed and we get SIGPIPE */ + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + abort(); + + /* parse command line options */ + // Port number and IP address are given via API and not via command line + for (i = 1; i < n; i++) { + if (!strcmp(v[i], "-h") || !strcmp(v[i], "--help")) + usage(); + if (!strcmp(v[i], "-d")) { + if (i > n - 2) + usage(); + database_filename = v[++i]; + continue; + } + if (!strcmp(v[i], "-ip")) { + if (i > n - 2) + usage(); + ip = v[++i]; + continue; + } + if (!strcmp(v[i], "-p")) { + if (i > n - 2) + usage(); + port = atoi(v[++i]); + continue; + } + usage(); + } + + if (database_filename == NULL) { + printf("ERROR: Provide a database file (-d)\n"); + exit(1); + } + + /* load the database T_messages.txt */ + database = parse_database(database_filename); + load_config_file(database_filename); + + /* an array of int for all the events defined in the database is needed */ + number_of_events = number_of_ids(database); + is_on = calloc(number_of_events, sizeof(int)); + if (is_on == NULL) + abort(); + + // Set first byte of the shared memory to 0 + addr_rd[0] = 0; // important to check if we have new requested messages + + // read requested tracer msg indices from memory + printf("\n Data Collection Service: Waiting for messages request ...\n"); + // 0: Wait + // 1: config + // 2: record + // 3: stop + // Wait for Action Config + while (1) { + if ((uint8_t)(addr_rd[0]) == 0) { + usleep(50); // sleep for 50 us: 0.5 ms slot duration + } + // config state + else if ((uint8_t)(addr_rd[0]) == 1) { + get_time_stamp_usec(trace_time_stamp_str); + printf("\n Received config message. Time Stamp: %s", trace_time_stamp_str); + + // get the IP address length in bytes + bufIdx_rd = 1; + uint8_t ip_address_length = addr_rd[bufIdx_rd]; + bufIdx_rd += 1; // + 1 byte = IP address length + + // read the IP address + for (int i = 0; i < ip_address_length; i++) { + ip_address[i] = addr_rd[bufIdx_rd]; + bufIdx_rd += 1; + } + + ip = ip_address; + + // get the array bytes of the port number : 2 bytes + uint8_t port_number_bytes[2] = {addr_rd[bufIdx_rd], addr_rd[bufIdx_rd + 1]}; + bufIdx_rd += 2; // + 2 bytes = start frame number + + port = combine_bytes(port_number_bytes, 2); + printf("\n Parameters: IP Address length: %d, IP Address: %s, Port Number: %d \n", ip_address_length, ip_address, port); + addr_rd[0] = 0; // reset memory : to wait for record action + break; + } + } + // Establish connection to the nr-softmodem + clear_remote_config(); + if (socket != -1) + close(socket); + + /* connect to the nr-softmodem */ + socket = connect_to(ip, port); + printf("\n Connected to nr-UEsoftmodem"); + + // Read Action record or stop + printf("\n Data Collection Service: Waiting for record message ...\n"); + while (1) { + // wait for Action record + if ((uint8_t)(addr_rd[0]) == 0) { + usleep(50); // sleep for 50 us: 0.5 ms slot duration + } + + // quit state + else if ((uint8_t)(addr_rd[0]) == 3) { + printf("\n Received 'stop' command. Exiting..."); + printf("\n "); + // Clean up and exit + break; + } + // record state + else if ((uint8_t)(addr_rd[0]) == 2) { + // clear remote buffer if there is + clear_remote_config(); + get_time_stamp_usec(trace_time_stamp_str); + printf("\n Received record message. Time Stamp: %s", trace_time_stamp_str); + + // read number of requested messages + bufIdx_rd = 1; + num_req_tracer_msgs = addr_rd[bufIdx_rd]; + bufIdx_rd += 1; + printf("\n Number of requested tracer messages: %d,", num_req_tracer_msgs); + // reset memory : action to wait for next record action + addr_rd[0] = 0; + + // read tracer msg IDs - every message ID has been stored in two bytes + for (uint8_t msg_n = 0; msg_n < num_req_tracer_msgs; msg_n++) { + // get the array bytes of the tracer message ID: 2 bytes + uint8_t msg_id_bytes[2] = {addr_rd[bufIdx_rd], addr_rd[bufIdx_rd + 1]}; + bufIdx_rd += 2; // + 2 bytes = message ID + msg_id = combine_bytes(msg_id_bytes, 2); + + req_tracer_msgs_indices[msg_n] = msg_id; + printf(" msg_id: %d, ", msg_id); + } + // get the array bytes of the number of records: 4 bytes + uint8_t number_records_bytes[4] = {addr_rd[bufIdx_rd], + addr_rd[bufIdx_rd + 1], + addr_rd[bufIdx_rd + 2], + addr_rd[bufIdx_rd + 3]}; + bufIdx_rd += 4; // + 4 bytes = number of records + + number_records = combine_bytes(number_records_bytes, 4); + + printf("num_records: %d, ", number_records); + + // get the array bytes of the start frame number : 2 bytes + uint8_t start_frame_number_bytes[2] = {addr_rd[bufIdx_rd], addr_rd[bufIdx_rd + 1]}; + bufIdx_rd += 2; // + 2 bytes = start frame number + + start_frame_number = combine_bytes(start_frame_number_bytes, 2); + + printf("start_frame: %d\n", start_frame_number); + + /* activate the trace in this array */ + printf("\n Activate Tracer messages in on_off array: \n"); + for (i = 0; i < num_req_tracer_msgs; i++) { + char *on_off_name = event_name_from_id(database, req_tracer_msgs_indices[i]); + on_off(database, on_off_name, is_on, 1); + printf("%d, %s, ", req_tracer_msgs_indices[i], on_off_name); + // on_off(database, "GNB_PHY_DL_OUTPUT_SIGNAL", is_on, 1); + } + + // get the event IDs for the bit messages + int traces_bits_support_data_Collection_format_idx[n_bits_msgs]; + for (int i = 0; i < n_bits_msgs; i++) { + traces_bits_support_data_Collection_format_idx[i] = + event_id_from_name(database, traces_bits_support_data_Collection_format[i]); + } + + // all supported messages + int traces_support_data_Collection_format_idx[n_msgs_based_data_Collection_format]; + for (int i = 0; i < n_msgs_based_data_Collection_format; i++) { + traces_support_data_Collection_format_idx[i] = event_id_from_name(database, traces_support_data_Collection_format[i]); + } + + // setup data for the trace messages + setup_trace_msg_data(&trace_msg_data, database); + printf("\n Setup Trace Data Done"); + + // Get the start time + struct timespec start_time = get_current_time(); + + /* activate the tracee in the nr-softmodem */ + activate_traces(socket, number_of_events, is_on); + printf("\n Activated Traces in nr-UEsoftmodem"); + + /* a buffer needed to receive events from the nr-softmodem */ + OBUF ebuf = {osize : 0, omaxsize : 0, obuf : NULL}; + /* read events */ + int nrecord_idx = 0; + bufIdx_wr = 0; + // logic to be sure that we have a complete slot record + bool start_recording = false; + bool got_ref_frame_slot = false; + int ref_slot = 0; + int ref_frame = 0; + int slot_difference = 0; + int frame_difference = 0; + int current_frame = 0, prev_frame = 0, current_slot = 0, prev_slot = 0; + // offset to sync between base station and UE synchronization records or power measurements + int sync_offset_index = 0; // increase the index only if the index of frame changes after getting all records + // since we will use the frame differece to do extra records, we should be sure that the last slot is recorded completely + printf("\n\n Data Collection Service: Start reading messages ..."); + struct pollfd event_poll_fd; + event_poll_fd.fd = socket; + event_poll_fd.events = POLLIN; + while (1) { + // stop if number of records is done + if ((nrecord_idx >= number_records) && (sync_offset_index >= max_sync_offset)) { + // We added one to the number of records to capture the last record completely + // if we have several messages enabled per slot + break; + } + int poll_ret = poll(&event_poll_fd, 1, 1); // 1 ms timeout for poll + if (poll_ret > 0 && (event_poll_fd.revents & POLLIN)) { + event e = get_event(socket, &ebuf, database); + if (e.type == -1) { + printf("\n Link broken or unexpected message received. Re-establishing connection...\n"); + reestablish_connection(&socket, ip, port, number_of_events, is_on); + continue; // Skip further processing and retry + } + + //------------------------- + // GNB_PHY_UL_FD_PUSCH_IQ, GNB_PHY_UL_FD_DMRS_ID, GNB_PHY_UL_FD_CHAN_EST_DMRS_POS, + // UE_PHY_UL_SCRAMBLED_TX_BITS, GNB_PHY_UL_PAYLOAD_RX_BITS, UE_PHY_UL_PAYLOAD_TX_BITS + //------------------------- + // is it a requested message + if (isValueInArray(e.type, req_tracer_msgs_indices, num_req_tracer_msgs)) { + // is it based on Data Collection Trace Messages Structure + if (isValueInArray(e.type, traces_support_data_Collection_format_idx, n_msgs_based_data_Collection_format)) { + // Start recording from the next slot to mitigate capturing partial data + // check if the current frame and slot are different from the previous frame and slot + // Then, increase the record index + if (start_recording == false) { + if (got_ref_frame_slot == false) { + ref_frame = e.e[trace_msg_data.frame].i; + ref_slot = e.e[trace_msg_data.slot].i; + printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type); + got_ref_frame_slot = true; + } + + current_frame = e.e[trace_msg_data.frame].i; + current_slot = e.e[trace_msg_data.slot].i; + frame_difference = (current_frame - ref_frame + MAX_FRAME_INDEX + 1) % (MAX_FRAME_INDEX + 1); + slot_difference = (current_slot - ref_slot + MAX_SLOT_INDEX + 1) % (MAX_SLOT_INDEX + 1); + printf("\n First frame.slot: %d.%d, current frame.slot: %d.%d, diff frame.slot: %d.%d", + ref_frame, + ref_slot, + current_frame, + current_slot, + frame_difference, + slot_difference); + + if ((ref_frame != current_frame) || (ref_slot != current_slot)) { + start_recording = true; + printf("\n Start recording from frame: %d, slot: %d ", e.e[trace_msg_data.frame].i, e.e[trace_msg_data.slot].i); + } + } + // start recording from the next frame to mitigate capturing partial data + if (start_recording == true) { + /* this is how to access the elements of the Data Collection trace messages. + * we use e.e[] and then the correct suffix, here + * it's .i for the integer and .b for the buffer and .bsize for the buffer size + * see in event.h the structure event_arg + */ + unsigned char *buf = e.e[trace_msg_data.data].b; + + printf("\n\nRecord number: %d", nrecord_idx); +#ifdef DEBUG_BUFFER + printf("\nBuffer index in bytes: %d", bufIdx_wr); +#endif + + // add general message header: message ID, + // T-Tracer Message format + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : + // int,dmrs_port : int,dmrs_nscid : + // int,nb_antennas_tx : int,number_of_bits : buffer,data + // printf("\nTX : %d", e.e[trace_msg_data.nb_antennas_tx].i); + memcpy(&addr_wr[bufIdx_wr], &e.type, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.frame].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.slot].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.datetime_yyyymmdd].i, sizeof(uint32_t)); + bufIdx_wr += sizeof(uint32_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.datetime_hhmmssmmm].i, sizeof(uint32_t)); + bufIdx_wr += sizeof(uint32_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.frame_type].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.freq_range].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.subcarrier_spacing].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.cyclic_prefix].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.symbols_per_slot].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.Nid_cell].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rnti].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rb_size].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rb_start].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.start_symbol_index].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nr_of_symbols].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.qam_mod_order].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.mcs_index].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.mcs_table].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nrOfLayers].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.transform_precoding].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_config_type].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.ul_dmrs_symb_pos].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.number_dmrs_symbols].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_port].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_nscid].i, sizeof(uint16_t)); + bufIdx_wr += sizeof(uint16_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nb_antennas_tx].i, sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.number_of_bits].i, sizeof(uint32_t)); + bufIdx_wr += sizeof(uint32_t); + + printf("\nTime Stamp: %d_%d", e.e[trace_msg_data.datetime_yyyymmdd].i, e.e[trace_msg_data.datetime_hhmmssmmm].i); + + // add message body: length in bytes + recorded data + memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.data].bsize, sizeof(uint32_t)); + bufIdx_wr += sizeof(uint32_t); + + // read data from buffer and convert from unsigned char * array to int 16 using the right endianness + // T-tracer: Little Endian + // For BITS Messages, example: UE_PHY_UL_SCRAMBLED_TX_BITS: data in bytes + + if (is_bits_messages(traces_bits_support_data_Collection_format_idx, n_bits_msgs, e.type)) { + for (int byte_idx = 0; byte_idx < e.e[trace_msg_data.data].bsize; byte_idx += 1) { + // printf("%d, ", buf[byte_idx]); + memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx], sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + } + + } else { + for (int byte_idx = 0; byte_idx < e.e[trace_msg_data.data].bsize; byte_idx += 2) { + // For a little-endian system: + memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx], sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx + 1], sizeof(uint8_t)); + bufIdx_wr += sizeof(uint8_t); + } + } + /* + for (int byte_idx_i = 0; byte_idx_i < e.e[d.nr_ul_fd_dmrs_data].bsize; byte_idx_i+=4) { + int16_t I = buf[byte_idx_i] | (buf[byte_idx_i+1] << 8); + int16_t Q = buf[byte_idx_i+2] | (buf[byte_idx_i+3] << 8); + printf ("idx %d, ", byte_idx_i); + printf ("\n%d", I); + printf ("\n%d", Q); + } + */ + // check if the current frame and slot are different from the previous frame and slot + // Then, increase the record index + current_frame = e.e[trace_msg_data.frame].i; + current_slot = e.e[trace_msg_data.slot].i; + + // increase sync offset index if the current frame is different from the previous frame + if ((current_frame != prev_frame) && nrecord_idx >= number_records) { + sync_offset_index++; + } + + if (current_frame != prev_frame || current_slot != prev_slot) { + nrecord_idx++; + // Update previous frame and slot numbers + prev_frame = current_frame; + prev_slot = current_slot; + } +#ifdef DEBUG_T_Tracer + printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type); + printf("frame %d, slot %d, datetime %d_%d\n", + e.e[trace_msg_data.frame].i, + e.e[trace_msg_data.slot].i, + e.e[trace_msg_data.datetime_yyyymmdd].i, + e.e[trace_msg_data.datetime_hhmmssmmm].i); + printf("frame_type %d, freq_range %d, subcarrier_spacing %d, cyclic_prefix %d, symbols_per_slot %d\n", + e.e[trace_msg_data.frame_type].i, + e.e[trace_msg_data.freq_range].i, + e.e[trace_msg_data.subcarrier_spacing].i, + e.e[trace_msg_data.cyclic_prefix].i, + e.e[trace_msg_data.symbols_per_slot].i); + printf("Nid_cell %d, rnti %d, rb_size %d, rb_start %d, start_symbol_index %d, nr_of_symbols %d\n", + e.e[trace_msg_data.Nid_cell].i, + e.e[trace_msg_data.rnti].i, + e.e[trace_msg_data.rb_size].i, + e.e[trace_msg_data.rb_start].i, + e.e[trace_msg_data.start_symbol_index].i, + e.e[trace_msg_data.nr_of_symbols].i); + printf("qam_mod_order %d, mcs_index %d, mcs_table %d, nrOfLayers %d, transform_precoding %d\n", + e.e[trace_msg_data.qam_mod_order].i, + e.e[trace_msg_data.mcs_index].i, + e.e[trace_msg_data.mcs_table].i, + e.e[trace_msg_data.nrOfLayers].i, + e.e[trace_msg_data.transform_precoding].i); + printf("dmrs_config_type %d, ul_dmrs_symb_pos %d, number_dmrs_symbols %d, dmrs_port %d, dmrs_nscid %d\n", + e.e[trace_msg_data.dmrs_config_type].i, + e.e[trace_msg_data.ul_dmrs_symb_pos].i, + e.e[trace_msg_data.number_dmrs_symbols].i, + e.e[trace_msg_data.dmrs_port].i, + e.e[trace_msg_data.dmrs_nscid].i); + printf("nb_antennas_tx %d, number_of_bits %d, data size %d\n", + e.e[trace_msg_data.nb_antennas_tx].i, + e.e[trace_msg_data.number_of_bits].i, + e.e[trace_msg_data.data].bsize); +#endif + } // End of start recording flag + } // end of if statement for the supported messages based on Data Collection Trace Messages Structure + else { + printf("ERROR: Requested Message is not based on Data Collection Trace Messages Structure\n"); + printf("ERROR: Requested Message ID: %d\n", e.type); + } + } // end of if statement for the requested messages + } // end while loop of reading events + else { + // No data, just loop and check time + usleep(100); // optional: avoid busy-waiting + } + } // End of while loop to read messages + + // de-activate the tracee in the nr-softmodem + printf("\n De-activated Tracer message:\n"); + for (i = 0; i < num_req_tracer_msgs; i++) { + char *on_off_name = event_name_from_id(database, req_tracer_msgs_indices[i]); + on_off(database, on_off_name, is_on, 0); + // printf("\n %d, %s, ", req_tracer_msgs_indices[i], on_off_name); + // on_off(database, "GNB_PHY_DL_OUTPUT_SIGNAL", is_on, 1); + } + // De-activate the tracee in the nr-softmodem + activate_traces(socket, number_of_events, is_on); + printf("\n De-activated Traces"); + + // Get the end time + struct timespec end_time = get_current_time(); + // Calculate the time difference + double time_diff = calculate_time_difference(start_time, end_time); + printf("Total Time difference: %.2f ms\n", time_diff); + printf("Time difference per record: %.2f ms\n", time_diff / (number_records + max_sync_offset)); + + // discard stale or previous record data for the first DISCARD_RECORD_DURATION_MS + struct timespec record_start, record_now; + clock_gettime(CLOCK_MONOTONIC, &record_start); + + while (1) { + clock_gettime(CLOCK_MONOTONIC, &record_now); + double elapsed_ms = calculate_time_difference(record_start, record_now); + if (elapsed_ms >= DISCARD_RECORD_DURATION_MS) { + break; // Stop after 10ms + } + int poll_ret = poll(&event_poll_fd, 1, 1); // 1 ms timeout for poll + if (poll_ret > 0 && (event_poll_fd.revents & POLLIN)) { + event e = get_event(socket, &ebuf, database); + printf("%d", e.type); + if (e.type == -1) { + printf("\n Link broken or unexpected message received. Re-establishing connection...\n"); + reestablish_connection(&socket, ip, port, number_of_events, is_on); + continue; + } + } else { + // No data, just loop and check time + usleep(100); // optional: avoid busy-waiting + } + } // End of while loop to discard stale records + } + } // End a while loop to check for the "stop" command + // de-activate the tracee in the nr-softmodem + + // free_database(database); //Do on one app, for example on gNB App + free(is_on); + close(socket); + + return 0; +} diff --git a/common/utils/T/tracer/ue.c b/common/utils/T/tracer/ue.c index b28f83b0f2..f4ea38f980 100644 --- a/common/utils/T/tracer/ue.c +++ b/common/utils/T/tracer/ue.c @@ -250,15 +250,15 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, line, w, -1); xy_plot_set_range(g, w, 0, 1024*10, -130, 35); /*l = new_ticked_ttilog(h, database,"UE_PHY_DL_TICK", "frame", "subframe","UE_PHY_MEAS", "rssi", 0, -1); - v = new_view_tti(10, g, w, new_color(g, "#720c0c")); + v = new_view_tti(10, g, w, new_color(g, "#720c0c"), 10); logger_add_view(l, v); e->phy_meas_logger = l;*/ l = new_ticked_ttilog(h, database,"UE_PHY_DL_TICK", "frame", "subframe","UE_PHY_MEAS", "rsrp", 0, -1); - v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10); logger_add_view(l, v); e->phy_meas_logger = l; l = new_ticked_ttilog(h, database,"UE_PHY_DL_TICK", "frame", "subframe","UE_PHY_MEAS", "snr", 0, -1); - v = new_view_tti(10, g, w, new_color(g, "#0c720c")); + v = new_view_tti(10, g, w, new_color(g, "#0c720c"), 10); logger_add_view(l, v); e->phy_meas_logger = l; @@ -277,7 +277,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, line, w, -1); l = new_ticked_ttilog(h, database, "UE_PHY_DL_TICK", "frame", "subframe", "UE_PHY_DLSCH_UE_DCI", "mcs", 0, -1); - v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10); logger_add_view(l, v); e->dl_mcs_logger = l; @@ -288,7 +288,7 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, widget_add_child(g, line, w, -1); l = new_ticked_ttilog(h, database, "UE_PHY_DL_TICK", "frame", "subframe", "UE_PHY_ULSCH_UE_DCI", "mcs", 0, -1); - v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10); logger_add_view(l, v); e->ul_mcs_logger = l; @@ -301,12 +301,12 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, xy_plot_set_range(g, w, 0, 1024*10, -30, 50); l = new_ttilog(h, database, "UE_PHY_PUSCH_TX_POWER", "frame", "subframe", "p0_pusch", 0); - v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10); logger_add_view(l, v); e->pusch_power_logger = l; l = new_ttilog(h, database, "UE_PHY_PUSCH_TX_POWER", "frame", "subframe", "ampl", 1); - v = new_view_tti(10, g, w, new_color(g, "#720c0c")); + v = new_view_tti(10, g, w, new_color(g, "#720c0c"), 10); logger_add_view(l, v); e->pusch_ampl_logger = l; @@ -319,12 +319,12 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, xy_plot_set_range(g, w, 0, 1024*10, -30, 50); l = new_ttilog(h, database, "UE_PHY_PUCCH_TX_POWER", "frame", "subframe", "p0_pucch", 0); - v = new_view_tti(10, g, w, new_color(g, "#0c0c72")); + v = new_view_tti(10, g, w, new_color(g, "#0c0c72"), 10); logger_add_view(l, v); e->pucch_power_logger = l; l = new_ttilog(h, database, "UE_PHY_PUCCH_TX_POWER", "frame", "subframe", "ampl", 1); - v = new_view_tti(10, g, w, new_color(g, "#720c0c")); + v = new_view_tti(10, g, w, new_color(g, "#720c0c"), 10); logger_add_view(l, v); e->pucch_ampl_logger = l; @@ -335,22 +335,22 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, xy_plot_set_range(g, w, 0, 1024*10, -10, 80); l = new_ttilog(h, database, "UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level00", 1); - v = new_view_tti(10, g, w, new_color(g, "#ff0000")); + v = new_view_tti(10, g, w, new_color(g, "#ff0000"), 10); logger_add_view(l, v); e->pdsch_energy_logger = l; l = new_ttilog(h, database, "UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level01", 1); - v = new_view_tti(10, g, w, new_color(g, "#00ff00")); + v = new_view_tti(10, g, w, new_color(g, "#00ff00"), 10); logger_add_view(l, v); e->pdsch_energy_logger = l; l = new_ttilog(h, database, "UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level10", 1); - v = new_view_tti(10, g, w, new_color(g, "#0f0f0f")); + v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"), 10); logger_add_view(l, v); e->pdsch_energy_logger = l; l = new_ttilog(h, database, "UE_PHY_PDSCH_ENERGY", "frame", "subframe", "pdsch_ch_level11", 1); - v = new_view_tti(10, g, w, new_color(g, "#0000ff")); + v = new_view_tti(10, g, w, new_color(g, "#0000ff"), 10); logger_add_view(l, v); e->pdsch_energy_logger = l; @@ -361,22 +361,22 @@ static void ue_main_gui(ue_gui *e, gui *g, event_handler *h, void *database, xy_plot_set_range(g, w, 0, 1024*10, -10, 80); l = new_ttilog(h, database, "UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level00", 1); - v = new_view_tti(10, g, w, new_color(g, "#ff0000")); + v = new_view_tti(10, g, w, new_color(g, "#ff0000"), 10); logger_add_view(l, v); e->pdcch_energy_logger = l; l = new_ttilog(h, database, "UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level01", 1); - v = new_view_tti(10, g, w, new_color(g, "#00ff00")); + v = new_view_tti(10, g, w, new_color(g, "#00ff00"), 10); logger_add_view(l, v); e->pdcch_energy_logger = l; l = new_ttilog(h, database, "UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level10", 1); - v = new_view_tti(10, g, w, new_color(g, "#0f0f0f")); + v = new_view_tti(10, g, w, new_color(g, "#0f0f0f"), 10); logger_add_view(l, v); e->pdcch_energy_logger = l; l = new_ttilog(h, database, "UE_PHY_PDCCH_ENERGY", "frame", "subframe", "pdcch_ch_level11", 1); - v = new_view_tti(10, g, w, new_color(g, "#0000ff")); + v = new_view_tti(10, g, w, new_color(g, "#0000ff"), 10); logger_add_view(l, v); e->pdcch_energy_logger = l; diff --git a/common/utils/T/tracer/utils.c b/common/utils/T/tracer/utils.c index 78b01a2516..66dd2a0b48 100644 --- a/common/utils/T/tracer/utils.c +++ b/common/utils/T/tracer/utils.c @@ -159,7 +159,7 @@ int socket_send(int socket, void *buffer, int size) { int get_connection(char *addr, int port) { int s, t; - printf("waiting for connection on %s:%d\n", addr, port); + fprintf(stderr, "waiting for connection on %s:%d\n", addr, port); s = create_listen_socket(addr, port); t = socket_accept(s); @@ -169,7 +169,7 @@ int get_connection(char *addr, int port) { } close(s); - printf("connected\n"); + fprintf(stderr, "connected\n"); return t; } @@ -216,12 +216,12 @@ int try_connect_to(char *addr, int port) { int connect_to(char *addr, int port) { int s; - printf("connecting to %s:%d\n", addr, port); + fprintf(stderr, "connecting to %s:%d\n", addr, port); again: s = try_connect_to(addr, port); if (s == -1) { - printf("trying again in 1s\n"); + fprintf(stderr, "trying again in 1s\n"); sleep(1); goto again; } diff --git a/common/utils/T/tracer/view/scrolltti.c b/common/utils/T/tracer/view/scrolltti.c index ad83cbc756..3bf1c93bd2 100644 --- a/common/utils/T/tracer/view/scrolltti.c +++ b/common/utils/T/tracer/view/scrolltti.c @@ -15,11 +15,14 @@ struct scrolltti { int plot; float refresh_rate; pthread_mutex_t lock; - unsigned long data[1000]; - unsigned long total; /* sum data[0..999] to have smoother value printed */ - float xout[1000]; - float yout[1000]; + int ticks_per_frame; + unsigned long *data; + unsigned long total; /* sum data[0..n] to have smoother value printed */ + float *xout; + float *yout; int insert_point; + int next_tick_frame; + int next_tick_tick; }; /* this array is used to get Y range 1000, 2000, 5000, 10000, ... */ @@ -38,21 +41,21 @@ static void *scrolltti_thread(void *_this) /* TODO: optimize */ p = this->insert_point; max = 0; - for (i = 0; i < 1000; i++) { + for (i = 0; i < this->ticks_per_frame * 100; i++) { this->xout[i] = i; this->yout[i] = this->data[p]; if (this->data[p] > max) max = this->data[p]; - p = (p + 1) % 1000; + p = (p + 1) % (this->ticks_per_frame * 100); } - bps(o, this->total/1000., "b/s"); + bps(o, this->total/(this->ticks_per_frame * 100.), "b/s"); textarea_set_text(this->g, this->throughput_textarea, o); /* for Y range we want 1000, 2000, 5000, 10000, 20000, 50000, etc. */ if (max < 1000) max = 1000; mlog = pow(10, floor(log10(max))); max = tolog[(int)ceil(max/mlog)] * mlog; - xy_plot_set_range(this->g, this->w, 0, 1000, 0, max); + xy_plot_set_range(this->g, this->w, 0, this->ticks_per_frame * 100, 0, max); xy_plot_set_points(this->g, this->w, this->plot, - 1000, this->xout, this->yout); + this->ticks_per_frame * 100, this->xout, this->yout); if (pthread_mutex_unlock(&this->lock)) abort(); sleepms(1000/this->refresh_rate); } @@ -65,20 +68,40 @@ static void clear(view *this) /* TODO */ } -static void append(view *_this, int frame, int subframe, double value) +static void insert(struct scrolltti *this, double value) +{ + this->total -= this->data[this->insert_point]; + this->data[this->insert_point] = value; + this->total += this->data[this->insert_point]; + this->insert_point = (this->insert_point + 1) % (this->ticks_per_frame * 100); +} + +static void next_tick(struct scrolltti *this) +{ + this->next_tick_tick++; + if (this->next_tick_tick == this->ticks_per_frame) { + this->next_tick_tick = 0; + this->next_tick_frame++; + this->next_tick_frame %= 1024; + } +} + +static void append(view *_this, int frame, int tick, double value) { struct scrolltti *this = (struct scrolltti *)_this; if (pthread_mutex_lock(&this->lock)) abort(); - this->total -= this->data[this->insert_point]; - this->data[this->insert_point] = value; - this->total += this->data[this->insert_point]; - this->insert_point = (this->insert_point + 1) % 1000; + while (this->next_tick_frame != frame || this->next_tick_tick != tick) { + insert(this, 0); + next_tick(this); + } + insert(this, value); + next_tick(this); if (pthread_mutex_unlock(&this->lock)) abort(); } view *new_view_scrolltti(float refresh_rate, gui *g, widget *w, int color, - widget *throughput_textarea) + widget *throughput_textarea, int ticks_per_frame) { struct scrolltti *ret = calloc(1, sizeof(struct scrolltti)); if (ret == NULL) abort(); @@ -92,6 +115,14 @@ view *new_view_scrolltti(float refresh_rate, gui *g, widget *w, int color, ret->throughput_textarea = throughput_textarea; ret->plot = xy_plot_new_plot(g, w, color); + ret->ticks_per_frame = ticks_per_frame; + ret->data = calloc(ticks_per_frame * 100, sizeof(unsigned long)); + if (ret->data == NULL) abort(); + ret->xout = calloc(ticks_per_frame * 100, sizeof(float)); + if (ret->xout == NULL) abort(); + ret->yout = calloc(ticks_per_frame * 100, sizeof(float)); + if (ret->yout == NULL) abort(); + if (pthread_mutex_init(&ret->lock, NULL)) abort(); new_thread(scrolltti_thread, ret); diff --git a/common/utils/T/tracer/view/tti.c b/common/utils/T/tracer/view/tti.c index ebf9fc657c..73d43b539b 100644 --- a/common/utils/T/tracer/view/tti.c +++ b/common/utils/T/tracer/view/tti.c @@ -5,31 +5,36 @@ #include #include #include +#include struct tti { view common; gui *g; widget *w; + int automax; + widget *w2; int plot; float refresh_rate; pthread_mutex_t lock; - float data[1024*10]; - int valid[1024*10]; - float xout[1024*10]; - float yout[1024*10]; + float *data; + int *valid; + float *xout; + float *yout; int last_insert_point; + int ticks_per_frame; }; -static int far_enough(int i, int last_insert, int plot_width) +static int far_enough(int i, int last_insert, int plot_width, + int ticks_per_frame) { int p1; int p2; int hole_size_px; int hole_size_tti; hole_size_px = 10; - hole_size_tti = 10240 * hole_size_px / plot_width; + hole_size_tti = 1024 * ticks_per_frame * hole_size_px / plot_width; p1 = last_insert; - p2 = (last_insert + hole_size_tti) % (1024*10); + p2 = (last_insert + hole_size_tti) % (1024 * ticks_per_frame); if (p1 < p2) { return !(i > p1 && i < p2); } @@ -48,15 +53,31 @@ static void *tti_thread(void *_this) if (pthread_mutex_lock(&this->lock)) abort(); xy_plot_get_dimensions(this->g, this->w, &plot_width, &plot_height); length = 0; + double max = 0; /* TODO: optimize */ - for (i = 0; i < 1024*10; i++) + for (i = 0; i < 1024 * this->ticks_per_frame; i++) /* do not take points too close after last insertion point */ if (this->valid[i] && - far_enough(i, this->last_insert_point, plot_width)) { + far_enough(i, this->last_insert_point, plot_width, + this->ticks_per_frame)) { this->xout[length] = i; this->yout[length] = this->data[i]; + if (this->data[i] > max) max = this->data[i]; length++; } + if (this->automax) { + char o[128]; + sprintf(o, "%d", (int)max); + textarea_set_text(this->g, this->w2, o); + /* for Y range we want 10, 20, 50, 100, 200, 500, etc. */ + if (max < 10) max = 10; + double mlog = pow(10, floor(log10(max))); + static int tolog[11] = { -1, 1, 2, 5, 5, 5, 10, 10, 10, 10, 10 }; + max = tolog[(int)ceil(max/mlog)] * mlog; + float xmin, xmax, ymin, ymax; + xy_plot_get_range(this->g, this->w, &xmin, &xmax, &ymin, &ymax); + xy_plot_set_range(this->g, this->w, xmin, xmax, 0, max); + } xy_plot_set_points(this->g, this->w, this->plot, length, this->xout, this->yout); if (pthread_mutex_unlock(&this->lock)) abort(); @@ -71,11 +92,11 @@ static void clear(view *this) /* TODO */ } -static void append(view *_this, int frame, int subframe, double value) +static void append(view *_this, int frame, int tick, double value) { struct tti *this = (struct tti *)_this; int i; - int index = frame * 10 + subframe; + int index = frame * this->ticks_per_frame + tick; if (pthread_mutex_lock(&this->lock)) abort(); @@ -84,10 +105,10 @@ static void append(view *_this, int frame, int subframe, double value) * this may be wrong if delay between two append is * greater than 1024 frames (something like that) */ - i = (this->last_insert_point + 1) % (1024*10); + i = (this->last_insert_point + 1) % (1024 * this->ticks_per_frame); while (i != index) { this->valid[i] = 0; - i = (i + 1) % (1024*10); + i = (i + 1) % (1024 * this->ticks_per_frame); } this->data[index] = value; @@ -98,7 +119,8 @@ static void append(view *_this, int frame, int subframe, double value) if (pthread_mutex_unlock(&this->lock)) abort(); } -view *new_view_tti(float refresh_rate, gui *g, widget *w, int color) +view *new_view_tti(float refresh_rate, gui *g, widget *w, int color, + int ticks_per_frame) { struct tti *ret = calloc(1, sizeof(struct tti)); if (ret == NULL) abort(); @@ -115,7 +137,24 @@ view *new_view_tti(float refresh_rate, gui *g, widget *w, int color) if (pthread_mutex_init(&ret->lock, NULL)) abort(); + ret->ticks_per_frame = ticks_per_frame; + ret->data = calloc(ticks_per_frame * 1024, sizeof(float)); + if (ret->data == NULL) abort(); + ret->valid = calloc(ticks_per_frame * 1024, sizeof(int)); + if (ret->valid == NULL) abort(); + ret->xout = calloc(ticks_per_frame * 1024, sizeof(float)); + if (ret->xout == NULL) abort(); + ret->yout = calloc(ticks_per_frame * 1024, sizeof(float)); + if (ret->yout == NULL) abort(); + new_thread(tti_thread, ret); return (view *)ret; } + +void view_tti_enable_automax(view *_tti, widget *w2) +{ + struct tti *tti = (struct tti *)_tti; + tti->automax = 1; + tti->w2 = w2; +} diff --git a/common/utils/T/tracer/view/view.h b/common/utils/T/tracer/view/view.h index 8167a00ccd..bc37e654d1 100644 --- a/common/utils/T/tracer/view/view.h +++ b/common/utils/T/tracer/view/view.h @@ -17,15 +17,16 @@ view *new_view_stdout(void); view *new_view_textlist(int maxsize, float refresh_rate, gui *g, widget *w); view *new_view_xy(int length, float refresh_rate, gui *g, widget *w, int color, enum xy_mode mode); -view *new_view_tti(float refresh_rate, gui *g, widget *w, - int color); +view *new_view_tti(float refresh_rate, gui *g, widget *w, int color, + int ticks_per_frame); view *new_view_scrolltti(float refresh_rate, gui *g, widget *w, - int color, widget *throughput_label); + int color, widget *throughput_label, int ticks_per_frame); view *new_view_time(int number_of_seconds, float refresh_rate, gui *g, widget *w); view *new_subview_time(view *time, int line, int color, int size); view *new_view_ticktime(float refresh_rate, gui *g, widget *w); view *new_subview_ticktime(view *ticktime, int line, int color, int size); void ticktime_set_tick(view *ticktime, void *logger); +void view_tti_enable_automax(view *tti, widget *w2); #endif /* _VIEW_H_ */ diff --git a/common/utils/data_recording/config/config_data_recording.json b/common/utils/data_recording/config/config_data_recording.json new file mode 100644 index 0000000000..2d4387d664 --- /dev/null +++ b/common/utils/data_recording/config/config_data_recording.json @@ -0,0 +1,84 @@ +{ + "id": 0, + "test_config": { + "test_scenario_id": "", + "test_name": "phy_ul_bler_test", + "test_mode": "rf_real_time", + "dut_type": "trad_rx" + }, + "environment_emulation": { + "target_link_config": { + "ran_config": { + "uplink": { + "ul_used_signal_BW_MHz": 2.16 + } + }, + "wireless_channel": { + "downlink": { + "type": "rf_cable" + }, + "uplink": { + "type": "statistical_var", + "statistical": { + "var_power_delay_profile": "tdl_d", + "speed_mps": 5.0, + "delay_spread_ns": 50.0, + "snr_db": 20.0, + "predef_channel_profile": null + } + }, + "carrierFreqValueList_hz": [ + 3319680000.0 + ], + "ul_used_signal_BW_MHz": 2.16 + } + } + }, + "data_recording_config": { + "data_storage_path": "/home/user/workarea/oai_recorded_data/", + "data_file_format": "SigMF", + "enable_saving_tracer_messages_sigmf": true, + "num_records": 5, + "t_tracer_message_definition_file": "../T/T_messages.txt", + "parameter_map_file": "config/wireless_link_parameter_map.yaml", + "start_frame_number": 5, + "base_station": { + "requested_tracer_messages": [ + "GNB_PHY_UL_FD_PUSCH_IQ", + "GNB_PHY_UL_FD_DMRS", + "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS", + "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL", + "GNB_PHY_UL_PAYLOAD_RX_BITS" + ], + "meta_data":{ + "num_rx_antennas": 1, + "tx_gain": 48.0, + "rx_gain": 30.0, + "hw_type": "USRP X410", + "hw_subtype": "ZBX", + "seid": "328AB35" + } + }, + "user_equipment": { + "requested_tracer_messages": [ + "UE_PHY_UL_SCRAMBLED_TX_BITS", + "UE_PHY_UL_PAYLOAD_TX_BITS" + ], + "meta_data":{ + "num_tx_antennas": 1, + "tx_gain": 48.0, + "rx_gain": 40.0, + "hw_type": "USRP X410", + "hw_subtype": "ZBX", + "seid": "323F75F" + } + }, + "common_meta_data": { + "sample_rate": 61440000.0, + "bandwidth": 40000000.0, + "clock_reference": "external" + }, + "tracer_service_baseStation_address": "127.0.0.1:2021", + "tracer_service_userEquipment_address": "127.0.0.1:2023" + } +} diff --git a/common/utils/data_recording/config/wireless_link_parameter_map.yaml b/common/utils/data_recording/config/wireless_link_parameter_map.yaml new file mode 100644 index 0000000000..deab34434c --- /dev/null +++ b/common/utils/data_recording/config/wireless_link_parameter_map.yaml @@ -0,0 +1,375 @@ +#/* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# file common/utils/data_recording/config/wireless_link_parameter_map.yaml +# brief Wireless Link Parameter Map Dictionary +# author Abdo Gaber +# date 2024 +# version 1.0 +# company Emerson, NI Test and Measurement +# email: +# note +# warning + + +# Wireless Link Parameter Map +# Components: +# Transmitter: list of waveform configuration based on standard +# Parameters pair is given via this parameter map dictionary (Parameter name in Waveform creator vs that in the API ~ SigMF meta-data) +# Having a separate dictionary ease of adoption in case of: +# - Adding new parameters +# - Use different waveform creator that has Different naming scheme +# - Define your own customized standard or new wireless system +# - All changes are limited to parameter map dictionary +# the parameter name of waveform generator has the following style: +# StandardName_WaveformGenerator_parameter, i.e. +# if standard = 5gnr, WaveformGenerator: ni_rfmx_rfws, then the parameter name: 5gnr_ni_rfmx_rfws_parameter +# ===================================================================================== +# ======== list of parameter pairs between waveform config and API ~ SigMF Meta-Data === +# ===================================================================================== + +# List of waveform generators that generate waveforms +# key: +# standard: "name" +# generator: "link or text ... etc" +# key: Used to create parameter names in wireless_link_parameter_map +# Recommended name for each waveform generator to be given as: standard_WaveformGenerator +# Example: 5g NR waveform created using RFmx with RFWS config file: "5gnr_ni_rfmx_rfws" +# Note: The suffix "_parameter" will be added automatically +# standard name: occur in meta-data +# generator: generator description to occur in meta-data + +waveform_generator: + # waveform_source: standard + 5gnr_oai: # Generated using OAI + standard: "5gnr" + generator: "OpenAirInterface: https://www.openairinterface.org/" + 5gnr_ni_rfmx_rfws: # Generated using NI RFmx Tool + standard: "5gnr" + generator: "NI RFmx Waveform Creator: https://www.ni.com/en-ca/shop/wireless-design-test/application-software-for-wireless-design-test-category/what-is-rfmx.html" +transmitter: + # 5G NR subfield + 5gnr: + # frame number + - sigmf_parameter_name: "frame" + description: "5G NR frame number" + 5gnr_oai_parameter: + name: "frame" + # slot number + - sigmf_parameter_name: "slot" + description: "5G NR slot number" + 5gnr_oai_parameter: + name: "slot" + # bandwidth + - sigmf_parameter_name: "bandwidth" + description: "5G NR bandwidth" + 5gnr_ni_rfmx_rfws_parameter: + name: "Bandwidth (Hz)" + 5gnr_oai_parameter: + name: "bandwidth" + # Frame structure + - sigmf_parameter_name: "frame_structure" + description: "5G NR duplexing scheme FDD, TDD, user defined" + 5gnr_ni_rfmx_rfws_parameter: + name: "Duplex Scheme" # not exact, since it depends if the waveform is for UL or DL + 5gnr_oai_parameter: + name: "frame_type" + value_map: # simu value : SigMF value + 0: "fdd" + 1: "tdd" + # Link direction + - sigmf_parameter_name: "link_direction" + description: "Link direction" + 5gnr_ni_rfmx_rfws_parameter: + name: "Link Direction" + # Frequency Range + - sigmf_parameter_name: "frequency_range" + description: "Frequency Range" + 5gnr_ni_rfmx_rfws_parameter: + name: "Frequency Range" + value_map: # simu value : SigMF value + "Range 1": "fr1" + "Range 2": "fr2" + 5gnr_oai_parameter: + name: "freq_range" + value_map: # simu value : SigMF value + 0: "fr1" + 1: "fr2" + # Subcarrier spacing in Hz + - sigmf_parameter_name: "subcarrier_spacing" + description: "Subcarrier spacing in Hz" + 5gnr_ni_rfmx_rfws_parameter: + name: Subcarrier Spacing (Hz) + 5gnr_oai_parameter: + name: subcarrier_spacing + value_map: # simu value : SigMF value + 0: 15000 + 1: 30000 + 2: 60000 + 3: 120000 + # Sampling rate in Hz + - sigmf_parameter_name: "sample_rate" + description: "Sampling rate in Hz" + 5gnr_ni_rfmx_rfws_parameter: + name: "sample_rate_hz" + 5gnr_oai_parameter: + name: "sample_rate" + # Cyclic prefix mode + - sigmf_parameter_name: "cp_mode" + description: "Cyclic prefix mode" + 5gnr_ni_rfmx_rfws_parameter: + name: "Cyclic Prefix Mode" + 5gnr_oai_parameter: + name: "cyclic_prefix" + value_map: # simu value : SigMF value + 0: "normal" + 1: "extended" + # cell ID + - sigmf_parameter_name: "cell_id" + description: "cell ID" + 5gnr_ni_rfmx_rfws_parameter: + name: "Cell ID" + 5gnr_oai_parameter: + name: "Nid_cell" + # rnti + - sigmf_parameter_name: "rnti" + description: "RNTI" + 5gnr_ni_rfmx_rfws_parameter: + name: "rnti" + 5gnr_oai_parameter: + name: "rnti" + # Symbols per slot + - sigmf_parameter_name: "symbols_per_slot" + description: "Symbols per slot" + 5gnr_oai_parameter: + name: "symbols_per_slot" + # PUSCH: content + - sigmf_parameter_name: "pusch:content" + description: "PUSCH: content" + # PUSCH: channel code + - sigmf_parameter_name: "pusch:channel_code" + description: "PUSCH: channel code" + # PUSCH: number of PRBs + - sigmf_parameter_name: "pusch:num_prb" + description: "PUSCH Resource Block Size" + 5gnr_oai_parameter: + name: "rb_size" + # PUSCH RB Start index + - sigmf_parameter_name: "pusch:start_prb" + description: "PUSCH Resource Block Start" + 5gnr_oai_parameter: + name: "rb_start" + # PUSCH MAPPING type + - sigmf_parameter_name: "pusch:mapping_type" + description: "PUSCH Mapping Type" + 5gnr_oai_parameter: + name: "mappingType" + value_map: # simu value : SigMF value + "NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA": "A" + "NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB": "B" + # PUSCH: OFDM symbol start index within slot + - sigmf_parameter_name: "pusch:start_ofdm_symbol" + description: "PUSCH: OFDM symbol start index within slot" + 5gnr_oai_parameter: + name: "start_symbol_index" + # PUSCH: number of OFDM symbols in one slot + - sigmf_parameter_name: "pusch:num_ofdm_symbols" + description: "PUSCH: number of OFDM symbols in one slot" + 5gnr_oai_parameter: + name: "nr_of_symbols" + # PUSCH: modulation + - sigmf_parameter_name: "pusch:modulation" + description: "PUSCH: modulation" + 5gnr_ni_rfmx_rfws_parameter: + name: "UL Modulation Type" + value_map: # simu value : SigMF value + "8PSK": "8_psk" + "QPSK": "qpsk" + "QAM16": "16_qam" + "QAM64": "64_qam" + "QAM256": "256_qam" + "QAM1024": "1024_qam" + "Standard": "" + 5gnr_oai_parameter: + name: "qam_mod_order" + value_map: # simu value : SigMF value + 2 : "qpsk" + 4 : "16_qam" + 6 : "64_qam" + 8 : "256_qam" + "Standard": "" + # PUSCH MCS Index + - sigmf_parameter_name: "pusch:mcs" + description: "PUSCH MCS Index" + 5gnr_oai_parameter: + name: "mcs_index" + # PUSCH MCS Index Table + - sigmf_parameter_name: "pusch:mcs_table_index" + description: "PUSCH MCS Table Index" + 5gnr_oai_parameter: + name: "mcs_table" + # PUSCH: number of transmission layers + - sigmf_parameter_name: "pusch:num_layer" + description: "PUSCH: number of transmission layers" + 5gnr_oai_parameter: + name: "nrOfLayers" + # Transform Precoding + - sigmf_parameter_name: "pusch:transform_precoding" + description: "PUSCH Transform Precoding" + 5gnr_oai_parameter: + name: "transform_precoding" + value_map: # simu value : SigMF value + 0: "enabled" + 1: "disabled" + # PUSCH DMRS: content + - sigmf_parameter_name: "pusch_dmrs:content" + description: "PUSCH DMRS: content" + #"none": "none" + #"random_qpsk": "random_qpsk" + #"compliant": "compliant" + # PUSCH DMRS: resource map configuration + - sigmf_parameter_name: "pusch_dmrs:resource_map_config" + description: "PUSCH DMRS: resource map configuration" + 5gnr_oai_parameter: + name: "dmrs_config_type" + value_map: + 0: "5g nr type 1" + 1: "5g nr type 2" + # PUSCH DMRS: OFDM symbol start index within slot + - sigmf_parameter_name: "pusch_dmrs:start_ofdm_symbol" + description: "PUSCH DMRS: OFDM symbol start index within slot" + 5gnr_oai_parameter: + # to be derived from this OAI parameter + name: "ul_dmrs_symb_pos" + # PUSCH DMRS: DMRS duration in number of OFDM symbols + - sigmf_parameter_name: "pusch_dmrs:duration_num_ofdm_symbols" + description: "PUSCH DMRS: DMRS duration in number of OFDM symbols" + 5gnr_oai_parameter: + # to be derived from this OAI parameter + name: "ul_dmrs_symb_pos" + # PUSCH DMRS: OFDM symbol indices within resource grid + - sigmf_parameter_name: "pusch_dmrs:ofdm_symbol_idx" + description: "PUSCH DMRS: OFDM symbol indices within resource grid" + 5gnr_oai_parameter: + # to be derived from this OAI parameter + name: "ul_dmrs_symb_pos" + # PUSCH DMRS: number of additional PUSCH DMRS positions + - sigmf_parameter_name: "pusch_dmrs:num_add_positions" + description: "PUSCH DMRS: number of additional PUSCH DMRS positions" + 5gnr_oai_parameter: + # to be derived from this OAI parameter + name: "ul_dmrs_symb_pos" + # PUSCH DMRS: antenna port + - sigmf_parameter_name: "pusch_dmrs:antennna_port" + description: "PUSCH DMRS: antenna port" + 5gnr_oai_parameter: + name: "dmrs_port" + # PUSCH DMRS: scrambler initialization + - sigmf_parameter_name: "pusch_dmrs:nscid" + description: "PUSCH DMRS: scrambler initialization" + 5gnr_oai_parameter: + name: "dmrs_nscid" + # number of rx antennas + - sigmf_parameter_name: "num_rx_antennas" + description: "Number of Rx antennas" + 5gnr_oai_parameter: + name: "nb_antennas_rx" + # number of tx antennas + - sigmf_parameter_name: "num_tx_antennas" + description: "Number of Tx antennas" + 5gnr_oai_parameter: + name: "nb_antennas_tx" + +channel: + # Signal-to-noise ratio (Es/N0) in dB + - sigmf_parameter_name: "snr_esn0_db" + description: "Signal-to-noise ratio (Es/N0) in dB" + # Signal-to-noise ratio (Eb/N0) in dB + - sigmf_parameter_name: "snr_ebn0_db" + description: "Signal-to-noise ratio (Eb/N0) in dB" + # Channel model + - sigmf_parameter_name: "channel_model" + description: "Fading channel model" + # Number of channel taps + - sigmf_parameter_name: "num_channel_taps" + description: "Number of channel taps" + # Channel attenuation level in dB + - sigmf_parameter_name: "channel_attenuation_db" + description: "Channel attenuation level in dB" + # Nominal delay spread in s + - sigmf_parameter_name: "delay_spread" + description: "Nominal delay spread in s" + # UE speed in m/s + - sigmf_parameter_name: "speed" + description: "UE speed in m/s" + # Carrier frequency in Hz + - sigmf_parameter_name: "carrier_frequency" + description: "Carrier frequency in Hz" +receiver: + # Frequency domain interpolation method for channel estimation + - sigmf_parameter_name: "channel_estimation_freq_interpolation" + description: "Frequency domain interpolation method for channel estimation" + # Time domain interpolation method for channel estimation + - sigmf_parameter_name: "channel_estimation_time_interpolation" + description: "Time domain interpolation method for channel estimation" + # Channel equalization method + - sigmf_parameter_name: "channel_equalization_method" + description: "Channel equalization method" + # Symbol demapping method + - sigmf_parameter_name: "symbol_demapping_method" + description: "Symbol demapping method" + # Manufacturer of the hardware used to receive the signal + - sigmf_parameter_name: "manufacturer" + description: "Manufacturer" + # Unique ID of the emitter, USRP serial number --> usrp_mboard_serial + - sigmf_parameter_name: "seid" + description: "Emitter ID (USRP serial number)" + # For USRP, use “daughterboard ID, a string read out from the device shortened by the hex ID e.g. ‘(0x0085)’ + - sigmf_parameter_name: "hw_subtype" + description: "Hardware subtype (for USRP: daughterboard ID)" + # RX sync reference source ("internal", "external", "gpsdo") + - sigmf_parameter_name: "clock_reference" + description: "RX clock reference" + required_field: false + # Estimated SNR in dB + - sigmf_parameter_name: "snr_estimate_db" + description: "SNR estimate in dB" + required_field: false + # Result of coarse PSS-based timing estimation (used for synchronization) + - sigmf_parameter_name: "timing_estimate_coarse" + description: "Coarse timing estimate in samples" + required_field: false" + # Result of coarse PSS-based frequency offset estimation (used for synchronization) + - sigmf_parameter_name: "cfo_estimate_coarse" + description: "Coarse frequency estimate in Hz" + required_field: false + # Result of fine CRS-based frequency offset estimation (used for synchronization) + - sigmf_parameter_name: "cfo_estimate_fine" + description: "Fine frequency estimate in Hz" + required_field: false + # Number of transmitted payload bits + - sigmf_parameter_name: "num_payload_bits" + description: "Number of transmitted payload bits" + required_field: false + # Number of bit errors when applying traditional RX processing + - sigmf_parameter_name: "bit_errors_trad_rx" + description: "Bit errors" + required_field: false \ No newline at end of file diff --git a/common/utils/data_recording/data_recording_app_v1.0.py b/common/utils/data_recording/data_recording_app_v1.0.py new file mode 100644 index 0000000000..53b7555b4b --- /dev/null +++ b/common/utils/data_recording/data_recording_app_v1.0.py @@ -0,0 +1,829 @@ +# /* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +# --------------------------------------------------------------------- +# file common/utils/data_recording/data_recording_app_v1.0.py +# brief main application of synchronized real-time data recording +# author Abdo Gaber +# date 2025 +# version 1.0 +# company Emerson, NI Test and Measurement +# email: +# note +# warning + +import sysv_ipc as ipc +import struct +import time +from datetime import datetime +from termcolor import colored +import numpy as np +import json +import concurrent.futures +# from concurrent import futures +import threading +# import related functions +from lib import sigmf_interface +# import library functions +from lib import sync_service +from lib import data_recording_messages_def +from lib import common_utils +from lib import config_interface + +DEBUG_WIRELESS_RECORDED_DATA = True +DEBUG_BUFFER_READING = False + +# globally applicable metadata +global_info = { + "author": "Abdo Gaber", + "description": "Synchronized Real-Time Data Recording", + "timestamp": 0, + "collection_file_prefix": "data-collection", # collection file name prefix "deap-rx + str(...)" + "collection_file": "", # Reserved to be created in the code: “data-collection_rec-0_TIME-STAMP” + "datetime_offset": "", # datetime offset between current location and UTC/Zulu timezone + # Example: "+01:00" for Berlin, Germany + "save_config_data_recording_app_json": True, + "waveform_generator": "5gnr_oai", + "extensions": {}, +} + +# Supported OAI Trace messages +# UL receiver messages +# gNB IQ Msgs: "GNB_PHY_UL_FD_PUSCH_IQ", "GNB_PHY_UL_FD_DMRS", "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS", +# "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL" +# gNB BITS Msgs: "GNB_PHY_UL_PAYLOAD_RX_BITS" +# UE BITS Msgs: "UE_PHY_UL_SCRAMBLED_TX_BITS", "UE_PHY_UL_PAYLOAD_TX_BITS" + +supported_oai_tracer_messages = { + # gNB messages + "GNB_PHY_UL_FD_PUSCH_IQ": { + "file_name_prefix": "rx-fd-data", + "scope": "gNB", + "description": "Frequency-domain RX data", + "serialization_scheme": ["subcarriers", "ofdm_symbols"], + }, + "GNB_PHY_UL_FD_DMRS": { + "file_name_prefix": "tx-pilots-fd-data", + "scope": "gNB", + "description": "Frequency-domain TX PUSCH DMRS data", + "serialization_scheme": ["subcarriers", "ofdm_symbols"], + }, + "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS": { + "file_name_prefix": "raw-ce-fd-data", + "scope": "gNB", + "description": "Frequency-domain raw channel estimates (at DMRS positions)", + "serialization_scheme": ["subcarriers", "ofdm_symbols"], + }, + "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL": { + "file_name_prefix": "raw-inter-ce-fd-data", + "scope": "gNB", + "description": "Interpolcated Frequency-domain raw channel estimates", + "serialization_scheme": ["subcarriers", "ofdm_symbols"], + }, + "GNB_PHY_UL_PAYLOAD_RX_BITS": { + "file_name_prefix": "rx-payload-bits", + "scope": "gNB", + "description": "Received PUSCH payload bits", + "serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"], + }, + # UE messages + "UE_PHY_UL_SCRAMBLED_TX_BITS": { + "file_name_prefix": "tx-scrambled-bits", + "scope": "UE", + "description": "Transmitted scrambled PUSCH bits", + "serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"], + }, + "UE_PHY_UL_PAYLOAD_TX_BITS": { + "file_name_prefix": "tx-payload-bits", + "scope": "UE", + "description": "Transmitted PUSCH payload bits", + "serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"], + }, +} +# ------------------------------------------- +# System configuration: gNB +project_id_gnb = 2335 +read_shm_path_gnb = "/tmp/gnb_app1" +write_shm_path_gnb = "/tmp/gnb_app2" + +# System configuration: UE +project_id_ue = 2336 +read_shm_path_ue = "/tmp/ue_app1" +write_shm_path_ue = "/tmp/ue_app2" + + +# initialize shared memory +def attach_shm(shm_path, project_id): + key = ipc.ftok(shm_path, project_id) + shm = ipc.SharedMemory(key, 0, 0) + # I found if we do not attach ourselves + # it will attach as ReadOnly. + shm.attach(0, 0) + return shm + + +def detach_shm(shm): + try: + shm.detach() + print("Shared memory detached successfully.") + except ipc.ExistentialError: + print("Shared memory segment does not exist.") + + +def remove_shm(shm): + try: + shm.remove() + print("Shared memory removed successfully.") + except ipc.ExistentialError: + print("Shared memory segment does not exist.") + + +# check data if avalible in the shared memory +def is_data_available_in_memory(shm, bufIdx, general_message_header_length, timeout=20): + start_time = time.time() + while True: + buf = shm.read(bufIdx + general_message_header_length) + n_bytes = sum(buf) + print("Data Recording App: Waiting for Measurements!") + if n_bytes > 0: + print("There is data in memory, n_bytes: ", n_bytes) + return True + if (time.time() - start_time) > timeout: + break + time.sleep(1) + return False + + +# Read data from Shared memory based Data Conversion Service message structure +def read_data_from_shm(shm, bufIdx, tracer_msgs_identities): + # print buffer index + if DEBUG_BUFFER_READING: + print("Buffer Index: ", bufIdx) + # get general message header list + general_msg_header_list, general_message_header_length = data_recording_messages_def.get_general_msg_header_list() + buf = shm.read(bufIdx + general_message_header_length) + n_bytes = sum(buf) + if n_bytes == 0: + raise Exception('ERROR: No data available in memory') + msg_id = struct.unpack(' timeout_sync: + raise Exception( + "ERROR: Data Recording NO Sync Found, check Tracer Services if they are connected!") + + # Get gNB data based on the sync data + bufIdx = 0 + while True: + time.sleep(0.0035) + gnb_bufIdx = bufIdx + captured_data, bufIdx = read_data_from_shm( + shm_reading_gnb, bufIdx, tracer_msgs_identities) + if (captured_data["frame"] == sync_info["frame"] + and captured_data["slot"] == sync_info["slot"]): + break + + # Read Synchronized data between gNB and UE + while True: # read all records + print("\nRecord number: ", record_idx) + if DEBUG_BUFFER_READING: + print(f"Buffer Index gNB: {gnb_bufIdx}, Buffer Index UE: {ue_bufIdx}") + # wait for the next record + # To do: check if we need to add exta waiting times between different events in case of + # data streaming via network such as on UE side or gNB side + time.sleep(0.0035) # 2.3 ms = latency of T tracer to capture data from the RAN + + collected_metafiles = [] + # Read data from gNB T-tracer Application + for idx in range(gnb_args.num_requested_tracer_msgs): + time.sleep(0.0015) + if DEBUG_WIRELESS_RECORDED_DATA: + print(f"\nRecord number: {record_idx}, Reading MSG data ", idx) + captured_data, gnb_bufIdx = read_data_from_shm( + shm_reading_gnb, gnb_bufIdx, tracer_msgs_identities) + # drive the collection file time stamp from the first message per record + if idx == 0: + # Get time stamp + time_stamp_ms, time_stamp_ms_file_name = ( + sigmf_interface.time_stamp_formating( + captured_data["time_stamp"], global_info["datetime_offset"])) + global_info["collection_file"] = ( + global_info["collection_file_prefix"] + + "-rec-" + + str(record_idx) + + "-" + + str(time_stamp_ms_file_name) + ) + global_info["timestamp"] = time_stamp_ms + + # Write data into files with the given format + if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]: + collected_metafiles.append( + sigmf_interface.write_recorded_data_to_sigmf( + captured_data, config_meta_data, global_info, record_idx)) + + # Read data from UE T-tracer Application + for idx in range(ue_args.num_requested_tracer_msgs): + time.sleep(0.0015) + if DEBUG_WIRELESS_RECORDED_DATA: + print(f"\nRecord number: {record_idx}, Reading MSG data ", idx) + captured_data, ue_bufIdx = read_data_from_shm( + shm_reading_ue, ue_bufIdx, tracer_msgs_identities) + + # Write data into files with the given format + if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]: + collected_metafiles.append( + sigmf_interface.write_recorded_data_to_sigmf( + captured_data, config_meta_data, global_info, record_idx)) + + # generate SigMF collection file + if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]: + data_storage_path = config_meta_data["data_recording_config"][ + "data_storage_path"] + description = global_info["description"] + sigmf_interface.save_sigmf_collection( + collected_metafiles, global_info, description, data_storage_path) + + frame = captured_data["frame"] + slot = captured_data["slot"] + + # Check for changes in frame or slot + if frame != prev_frame or slot != prev_slot: + record_idx += 1 + # We have reached the end of the data. Break the loop + if record_idx >= config_meta_data["data_recording_config"]["num_records"]: + break + # Update previous frame and slot + prev_frame = frame + prev_slot = slot + + +# data conversion service +def data_conversion_service(shm_reading, config_meta_data, args, sync_info, do_sync): + # Initialize variables + record_idx = 0 + prev_frame = -1 + prev_slot = -1 + bufIdx = 0 + # Read data from T-tracer Application + print("Data Conversion Service: Reading data from T-tracer Application") + print("Requested Tracer Messages: ", args.num_requested_tracer_msgs) + if args.num_requested_tracer_msgs > 0: + num_requested_tracer_msgs = args.num_requested_tracer_msgs + else: + raise Exception("ERROR: No requested tracer messages found!") + + tracer_msgs_identities = config_meta_data["data_recording_config"][ + "tracer_msgs_identities"] + global_info = config_meta_data["data_recording_config"]["global_info"] + + if do_sync: + print(" Find Memory Index of NR MSGs based on Sync info") + while True: + time.sleep(0.0035) + station_bufIdx = bufIdx + captured_data, bufIdx = read_data_from_shm( + shm_reading, bufIdx, tracer_msgs_identities) + print("*Sync Status: NR Captured Data (Frame, slot): (", captured_data["frame"], + ", ", captured_data["slot"], "), Sync Info (Frame, slot): (", sync_info["frame"], + ", ", sync_info["slot"]," )") + if (captured_data["frame"] == sync_info["frame"] + and captured_data["slot"] == sync_info["slot"]): + print("*sync Pass") + break + print("*sync Fail") + bufIdx = station_bufIdx + + # Read data from T-tracer Application + while True: # read all records + print("\nRecord number: ", record_idx) + if DEBUG_BUFFER_READING: + print(f"Buffer Index: {bufIdx}") + # wait for the next record + # To do: check if we need to add exta waiting times between different events in case of + # data streaming via network such as on UE side or gNB side + time.sleep(0.0035) # 2.3 ms = latency of T tracer to capture data from the RAN + + collected_metafiles = [] + for idx in range(num_requested_tracer_msgs): + time.sleep(0.0015) + if DEBUG_WIRELESS_RECORDED_DATA: + print(f"\nRecord number: {record_idx}, Reading MSG data ", idx) + captured_data, bufIdx = read_data_from_shm( + shm_reading, bufIdx, tracer_msgs_identities) + # derive the collection file time stamp from the first message per record + if idx == 0: + # Get time stamp + time_stamp_ms, time_stamp_ms_file_name = ( + sigmf_interface.time_stamp_formating( + captured_data["time_stamp"], global_info["datetime_offset"])) + global_info["collection_file"] = ( + global_info["collection_file_prefix"] + + "-rec-" + + str(record_idx) + + "-" + + str(time_stamp_ms_file_name)) + global_info["timestamp"] = time_stamp_ms + # Write data into files with the given format + if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]: + collected_metafiles.append( + sigmf_interface.write_recorded_data_to_sigmf( + captured_data, config_meta_data, global_info, record_idx)) + + frame = captured_data["frame"] + slot = captured_data["slot"] + + # generate SigMF collection file + if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]: + data_storage_path = config_meta_data["data_recording_config"][ + "data_storage_path"] + description = global_info["description"] + sigmf_interface.save_sigmf_collection( + collected_metafiles, global_info, description, data_storage_path) + + # Check for changes in frame or slot + if frame != prev_frame or slot != prev_slot: + record_idx += 1 + # We have reached the end of the data. Break the loop + if record_idx >= config_meta_data["data_recording_config"]["num_records"]: + break + # Update previous frame and slot + prev_frame = frame + prev_slot = slot + + +# Write Tracer Control Message +def write_shm(shm, args): + # Note: Big Endian >, Little Endian < + # Note: unsigned char B, signed char b, short h, int I, long long q + # Note: float f, double d, string s, char c, bool ? + # 1: config + # 2: record + # 3: quit + print("Write Shared Memory: ", args.action) + if args.action == "config": + # Determine the length of the IP address + ip_length = len(args.bytes_IPaddress) + 1 # String terminator + # Construct the format string dynamically + format_string = f"{ip_length}s" + shm.write( + # Config action + struct.pack(" dict: + """ + Reads main config file. + """ + # read general parameter set from yaml config file + with open(main_config_file, "r") as file: + main_config = json.load(file) + + return main_config + + +# Function to read the main configuration file in YAML format +def read_main_config_file(main_config_file: str) -> dict: + """ + Reads main config file. + """ + # read general parameter set from yaml config file + with open(main_config_file, "r") as file: + main_config = yaml.load(file, Loader=yaml.Loader) + + return main_config + + +# Function to parse the OAI T_messages file and get the index of a given string +def parse_message_file(file_path): + with open(file_path, "r") as file: + content = file.readlines() + # Extract lines that start with 'ID' and remove the 'ID = ' prefix + tracer_msgs_identities = [ + line.strip().replace("ID = ", "") + for line in content + if line.strip().startswith("ID") + ] + + return tracer_msgs_identities + + +# Function to get the index of a given string in the list of ID lines +def get_index_of_id(tracer_msgs_identities, message_id): + try: + return tracer_msgs_identities.index(message_id) + except ValueError: + return -1 # Return -1 if the string is not found + + +# Function to get the indices of requested tracer messages +def get_requested_tracer_msgs_indices(requested_tracer_messages, tracer_msgs_identities): + # get requested tracer messages indices + req_tracer_msgs_indices = [] + for idx, value in enumerate(requested_tracer_messages): + msg_index = get_index_of_id(tracer_msgs_identities, value) + req_tracer_msgs_indices.append(msg_index) + print("Requested Traces IDs: ", req_tracer_msgs_indices) + return req_tracer_msgs_indices + + +# Function to get the data recording configuration +def get_data_recording_config(config_meta_data): + parser = argparse.ArgumentParser(description="request messages IDs") + ue_args = parser.parse_args() + gnb_args = parser.parse_args() + + # get Tracer Messages IDs from the T-Tracer Messages file + # MSG list order should be similar to the T-Tracer Messages txt file + # Be sure that you are using the same T_messages file that is used in the OAI project + # OAI Path: .../common/utils/T/T_messages.txt + + # Parse the T_messages file + tracer_msgs_identities = parse_message_file( + config_meta_data["data_recording_config"]["t_tracer_message_definition_file"]) + config_meta_data["data_recording_config"]["tracer_msgs_identities"] = tracer_msgs_identities + + # get requested tracer messages indices for gNB + gnb_args.requested_tracer_messages = \ + config_meta_data["data_recording_config"]["base_station"]["requested_tracer_messages"] + # get requested tracer messages indices for UE + ue_args.requested_tracer_messages = \ + config_meta_data["data_recording_config"]["user_equipment"]["requested_tracer_messages"] + + # check if gnb_requested_tracer_messages is not empty + if gnb_args.requested_tracer_messages: + config_meta_data["data_recording_config"]["base_station"][ + "req_tracer_msgs_indices"] = get_requested_tracer_msgs_indices( + gnb_args.requested_tracer_messages, tracer_msgs_identities) + + # get gNB Trace Messages + gnb_args.num_records = config_meta_data["data_recording_config"]["num_records"] + gnb_args.start_frame_number = config_meta_data["data_recording_config"]["start_frame_number"] + gnb_args.req_tracer_msgs_indices = \ + config_meta_data["data_recording_config"]["base_station"]["req_tracer_msgs_indices"] + gnb_args.num_requested_tracer_msgs = len(gnb_args.req_tracer_msgs_indices) + # Split the string into IP and port + gnb_args.IPaddress, gnb_args.port = config_meta_data["data_recording_config"][ + "tracer_service_baseStation_address"].split(":") + gnb_args.bytes_IPaddress = bytes(gnb_args.IPaddress, "utf-8") + + # check if ue_requested_tracer_messages is not empty + if ue_args.requested_tracer_messages: + config_meta_data["data_recording_config"]["user_equipment"][ + "req_tracer_msgs_indices"] = get_requested_tracer_msgs_indices( + ue_args.requested_tracer_messages, tracer_msgs_identities) + + # get UE Trace Messages + ue_args.num_records = config_meta_data["data_recording_config"]["num_records"] + ue_args.start_frame_number = config_meta_data["data_recording_config"]["start_frame_number"] + ue_args.req_tracer_msgs_indices = \ + config_meta_data["data_recording_config"]["user_equipment"]["req_tracer_msgs_indices"] + ue_args.num_requested_tracer_msgs = len(ue_args.req_tracer_msgs_indices) + ue_args.IPaddress, ue_args.port = config_meta_data["data_recording_config"][ + "tracer_service_userEquipment_address"].split(":") + ue_args.bytes_IPaddress = bytes(ue_args.IPaddress, "utf-8") + + return config_meta_data, gnb_args, ue_args diff --git a/common/utils/data_recording/lib/data_recording_messages_def.py b/common/utils/data_recording/lib/data_recording_messages_def.py new file mode 100644 index 0000000000..a807058f29 --- /dev/null +++ b/common/utils/data_recording/lib/data_recording_messages_def.py @@ -0,0 +1,107 @@ +# /* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +# --------------------------------------------------------------------- +# file common/utils/data_recording/lib/data_recording_messages_def.py +# brief defination of captured data recording messages +# author Abdo Gaber +# date 2025 +# version 1.0 +# company Emerson, NI Test and Measurement +# email: +# note +# warning + + +# Data Collection Trace Messages - General message structure - number of bytes +def get_general_msg_header_list(): + """ + shared memory layout written from the app: + ================================= + msg_id (uint8) message type ID + frame (uint16) + slot (uint8) + datetime_yyyymmdd (uint32) + datetime_hhmmssmmm (uint32) + frame_type (uint8) + freq_range (uint8) + subcarrier_spacing (uint8) + cyclic_prefix (uint8) + symbols_per_slot (uint8) + Nid_cell (uint16) + rnti (uint16) + rb_size (uint16) + rb_start (uint16) + start_symbol_index (uint8) + nr_of_symbols (uint8) + qam_mod_order (uint8) + mcs_index (uint8) + mcs_table (uint8) + nrOfLayers (uint8) + transform_precoding (uint8) + dmrs_config_type (uint8) + ul_dmrs_symb_pos (uint16) + number_dmrs_symbols (uint8) + dmrs_port (uint16) + dmrs_scid (uint16) + nb_antennas (uint8) + number_of_bits (uint32) + length_bytes (uint32) + For IQ Data: IQ samples: I0, Q0, I1, Q1, ... I_x, Q_x (int16) + For bit data: bits: b0, b1, b2, ... b_x (uint8) + + """ + # Data Collection Trace Messages - General message structure - number of bytes + general_msg_header_list = { + "msg_id": 2, + "frame": 2, + "slot": 1, + "datetime_yyyymmdd": 4, + "datetime_hhmmssmmm": 4, + "frame_type": 1, + "freq_range": 1, + "subcarrier_spacing": 1, + "cyclic_prefix": 1, + "symbols_per_slot": 1, + "Nid_cell": 2, + "rnti": 2, + "rb_size": 2, + "rb_start": 2, + "start_symbol_index": 1, + "nr_of_symbols": 1, + "qam_mod_order": 1, + "mcs_index": 1, + "mcs_table": 1, + "nrOfLayers": 1, + "transform_precoding": 1, + "dmrs_config_type": 1, + "ul_dmrs_symb_pos": 2, + "number_dmrs_symbols": 1, + "dmrs_port": 2, + "dmrs_scid": 2, + "nb_antennas": 1, # for gNB or nb_antennas_tx for UE + "number_of_bits": 4, + "length_bytes": 4, + } + # initial number of bytes to read to get data + general_message_header_length = 0 + for key, value in general_msg_header_list.items(): + general_message_header_length = general_message_header_length + value + return general_msg_header_list, general_message_header_length diff --git a/common/utils/data_recording/lib/sigmf_interface.py b/common/utils/data_recording/lib/sigmf_interface.py new file mode 100644 index 0000000000..74d58a03f8 --- /dev/null +++ b/common/utils/data_recording/lib/sigmf_interface.py @@ -0,0 +1,580 @@ +# /* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +# --------------------------------------------------------------------- +# file common/utils/data_recording/lib/sigmf_interface.py +# brief SigMF Interface to Write data and meta-data to files in SigMF format +# author Abdo Gaber +# date 2025 +# version 1.0 +# company Emerson, NI Test and Measurement +# email: +# note +# warning + +import os +import sigmf +from sigmf import SigMFFile +# from sigmf.utils import get_data_type_str +import numpy as np +from datetime import datetime +import yaml +from sigmf import SigMFCollection + +""" +SERIALIZATION_SCHEMES = { + # gnb + "rx-fd-data": ["subcarriers", "ofdm_symbols"], + "tx-pilots-fd-data": ["subcarriers", "ofdm_symbols"], + "raw-ce-fd-data": ["subcarriers", "ofdm_symbols"], + "rx-payload-bits": ["bits", "subcarriers", "ofdm_symbols"], + # ue + "tx-scrambled-bits": ["bits", "subcarriers", "ofdm_symbols"], + "tx-payload-bits": ["bits", "subcarriers", "ofdm_symbols"], +} +""" +STANDARDS = {"5gnr_oai": "5gnr"} + + +def time_stamp_formating(time_stamp, datetime_offset): + # Parse the input string into a datetime object + time_stamp_ms_obj = datetime.strptime(time_stamp, "%Y%m%d_%H%M%S%f") + + # Format the datetime object into the desired output format with milliseconds + time_stamp_ms_iso = ( + time_stamp_ms_obj.strftime("%Y_%m_%dT%H:%M:%S.%f")[:-3] + datetime_offset + ) + time_stamp_ms = time_stamp_ms_iso + time_stamp_ms_file_name = time_stamp_ms_iso.replace(":", "_").replace(".", "_") + + return time_stamp_ms, time_stamp_ms_file_name + + +def create_serialization_metadata(serialization_scheme, data_source: str, + link_sim_parameters: dict) -> dict: + """Creates dict that specifies the serialization metadata.""" + + # retrieve parameter from LinkSimulator config + if data_source == "5gnr_oai": + num_ofdm_symbol = link_sim_parameters["nr_of_symbols"] + num_subcarriers = link_sim_parameters["rb_size"] * 12 + num_bits_per_symbol = link_sim_parameters["qam_mod_order"] + else: + raise Exception( + f"Invalid data source string '{data_source}'! Only '5gnr_oai' is valid!" + ) + + # create array with scheme dimensions + if len(serialization_scheme) == 2: + counts = [num_subcarriers, num_ofdm_symbol] + elif len(serialization_scheme) == 3: + counts = [num_bits_per_symbol, num_subcarriers, num_ofdm_symbol] + else: + raise Exception( + f"Invalid number of elements in serialization scheme: {len(serialization_scheme)}") + + # create metadata dict + serialization_dict = { + "serialization:scheme": serialization_scheme, + "serialization:counts": counts, + } + + return serialization_dict + + +def map_metadata_to_sigmf_format(scope, waveform_generator, parameter_map_file, captured_data): + """ + Maps metadata from Waveform creator to API and SigMF format. + The used parameters and the mapping pairs are specified in a separate YAML file + that must be provided as well. + """ + # read waveform parameter map from yaml file + dir_path = os.path.dirname(__file__) + src_path = os.path.split(dir_path)[0] + + with open(os.path.join(src_path, parameter_map_file), "r") as file: + parameter_map_dic = yaml.load(file, Loader=yaml.Loader) + # preallocate target dict + sigmf_metadata_dict = {} + + # get standard and name of generator + standard_key = parameter_map_dic["waveform_generator"][waveform_generator] + generator = standard_key["generator"] + + if scope == "tx": + parameter_map_dic = parameter_map_dic["transmitter"][ + STANDARDS[waveform_generator] + ] + elif scope == "channel": + parameter_map_dic = parameter_map_dic["channel"] + elif scope == "rx": + parameter_map_dic = parameter_map_dic["receiver"] + else: + raise Exception( + f"Invalid mapping scope '{scope}'! Only 'tx', 'channel' and 'rx' are valid!" + ) + + # check if standard key is given + if parameter_map_dic is None: + raise Exception( + "Invalid standard key: " + "Name should be corrected or added to wireless_link_parameter_map.yaml, given: " + f"{waveform_generator}" + ) + + for parameter_pair in parameter_map_dic: + # check if key for chosen simulator even exists + if waveform_generator + "_parameter" in parameter_pair.keys(): + # only continue with mapping from file if direct equivalent exists + if parameter_pair[waveform_generator + "_parameter"]["name"]: + # It is not necessary to get all parameters from wireless_link_parameter_map.yaml + # in captured_data since some parameters related to DL or UL only + if (parameter_pair[waveform_generator + "_parameter"]["name"] in captured_data.keys()): + # extract value from waveform config source + value = captured_data[ + parameter_pair[waveform_generator + "_parameter"]["name"]] + # additional mapping if parameter values should come from a discrete set of values + if ("value_map" in parameter_pair[waveform_generator + "_parameter"].keys()): + value = parameter_pair[waveform_generator + "_parameter"]["value_map"][value] + # write to target dictionary for SigMF + sigmf_metadata_dict[parameter_pair["sigmf_parameter_name"]] = value + else: + raise Exception( + f"Incomplete specification in field '{waveform_generator}_parameter'!") + # else: # fill_non_explicit_fields + # waveform_config[parameter_pair["sigmf_parameter_name"]] = "none" + if not sigmf_metadata_dict: + raise Exception( + """ERROR: Check captured meta-data or provided config and meta data """) + + # check for non-JSON-serializable data types + def isfloat(NumberString): + try: + float(NumberString) + return True + except ValueError: + return False + + for key, value in sigmf_metadata_dict.items(): + if isinstance(value, np.integer): + sigmf_metadata_dict[key] = int(value) + elif isinstance(value, (np.float16, np.float32, np.float64)): + sigmf_metadata_dict[key] = np.format_float_positional(value, trim="-") + elif isinstance(value, int): + sigmf_metadata_dict[key] = int(value) + elif isinstance(value, float): + # store value in decimal and not in scientific notation + sigmf_metadata_dict[key] = float(value) + elif isinstance(value, str) and key != "standard": + # convert string to lower case + sigmf_metadata_dict[key] = value.lower() + if isfloat(value): + if value.isdigit(): + sigmf_metadata_dict[key] = int(float(value)) + elif value.replace(".", "", 1).isdigit() and value.count(".") < 2: + sigmf_metadata_dict[key] = float(value) + + return sigmf_metadata_dict, generator + + +def create_system_components_metadata(waveform_generator, parameter_map_file, captured_data): + """Creates system components (TX, channel, RX) metadata that will reside in the annotations.""" + # map metadata of waveform generator to SigMF format + signal_info, generator = map_metadata_to_sigmf_format( + "tx", waveform_generator, parameter_map_file, captured_data + ) + tx_metadata = { + "signal:detail": { + "standard": STANDARDS[waveform_generator], + "generator": generator, + STANDARDS[waveform_generator]: signal_info, + } + } + + channel_metadata = {} # will be filled later + rx_metadata = {} # will be filled later + + return tx_metadata, channel_metadata, rx_metadata + + +def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, idx): + """ + Compiles and saves provided data and metadata into SigMF file format. + """ + # get meta data from config file + base_station_meta_data = config_meta_data["data_recording_config"]["base_station"][ + "meta_data"] + user_equipment_meta_data = config_meta_data["data_recording_config"][ + "user_equipment"]["meta_data"] + + # Check the receive target path is valid, else create folder + data_storage_path = config_meta_data["data_recording_config"]["data_storage_path"] + if not os.path.isdir(data_storage_path): + print("Create new folder for recorded data: " + str(data_storage_path)) + os.makedirs(data_storage_path) + + # Write recorded data to file + # Get time stamp + time_stamp_ms, time_stamp_ms_file_name = time_stamp_formating( + captured_data["time_stamp"], global_info["datetime_offset"]) + # Map OAI Message Name to SigMF Message Name + file_name_prefix = config_meta_data["data_recording_config"][ + "supported_oai_tracer_messages"][captured_data["message_type"]]["file_name_prefix"] + recorded_data_file_name = ( + file_name_prefix + "-rec-" + str(idx) + "-" + time_stamp_ms_file_name) + + dataset_filename = recorded_data_file_name + ".sigmf-data" + dataset_file_path = os.path.join(data_storage_path, dataset_filename) + print(dataset_file_path) + captured_data["recorded_data"].tofile(dataset_file_path) + + # map OAI config data to SigMF metadata + waveform_generator = config_meta_data["data_recording_config"]["global_info"][ + "waveform_generator"] + parameter_map_file = config_meta_data["data_recording_config"]["parameter_map_file"] + tx_metadata, channel_metadata, rx_metadata = create_system_components_metadata( + waveform_generator, parameter_map_file, captured_data) + + # Add other OAI metadata to SigMF metadata + # ---------------------------------------------------- + # Set 1: Parameters needs to be derived from OAI message + # ---------------------------------------------------- + # PUSCH DMRS: OFDM symbol start index within slot + get_pusch_dmrs_start_ofdm_symbol = 0 + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch_dmrs:ofdm_symbol_idx"] = [] + + for symbol in range(captured_data["start_symbol_index"], + captured_data["start_symbol_index"] + captured_data["nr_of_symbols"]): + + dmrs_symbol_flag = (captured_data["ul_dmrs_symb_pos"] >> symbol) & 0x01 + if dmrs_symbol_flag and not get_pusch_dmrs_start_ofdm_symbol: + get_pusch_dmrs_start_ofdm_symbol = 1 + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch_dmrs:start_ofdm_symbol"] = symbol + if dmrs_symbol_flag: + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch_dmrs:ofdm_symbol_idx"].append(symbol) # Append symbol to the list + + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch_dmrs:duration_num_ofdm_symbols"] = 1 + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch_dmrs:num_add_positions"] = (captured_data["number_dmrs_symbols"] - 1) + + # If the message is a BIT message, add number of bits to the signal info + # "UE_PHY_UL_SCRAMBLED_TX_BITS", "GNB_PHY_UL_PAYLOAD_RX_BITS", "UE_PHY_UL_PAYLOAD_TX_BITS" + if "_BITS" in captured_data["message_type"]: + # if "BIT" in captured_data["message_type"]: + tx_metadata["signal:detail"][STANDARDS[waveform_generator]]["num_bits"] = ( + captured_data["number_of_bits"]) + + # If the message is captured from UE, it is UPLink message, + # so number of antennas is num of Tx antennas + # number of antennas on Rx side should be read from global_info given by user + if "UE" in captured_data["message_type"]: + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "num_tx_antennas" + ] = captured_data["nb_antennas"] + rx_metadata.update( + {"num_rx_antennas": base_station_meta_data["num_rx_antennas"]} + ) + # If the message is captured from gNB, it is UPLink message, + # so number of antennas is num of Rx antennas + # number of antennas on Tx side should be read from global_info given by user + else: + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "num_tx_antennas"] = user_equipment_meta_data["num_tx_antennas"] + rx_metadata.update({"num_rx_antennas": captured_data["nb_antennas"]}) + + # Check if the message type contains "UL" + if "UL" in captured_data["message_type"]: + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "link_direction"] = "uplink" + else: + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "link_direction"] = "downlink" + # ---------------------------------------------------- + # Set 2: Parameters that is hardcoded + # ---------------------------------------------------- + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch:content"] = "compliant" + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch:mapping_type"] = "B" + tx_metadata["signal:detail"][STANDARDS[waveform_generator]]["num_slots"] = 1 + if config_meta_data["test_config"]["test_mode"] == "rf_simulation": + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch:payload_bit_pattern"] = "random" + elif config_meta_data["test_config"]["test_mode"] == "rf_real_time": + tx_metadata["signal:detail"][STANDARDS[waveform_generator]][ + "pusch:payload_bit_pattern"] = "zeros" + else: + raise Exception("ERROR: Test mode is not supported in SigMF formatting") + # ---------------------------------------------------- + # Read mean parameters + freq = config_meta_data["environment_emulation"]["target_link_config"][ + "wireless_channel"]["carrierFreqValueList_hz"][0] + bandwidth = config_meta_data["data_recording_config"]["common_meta_data"][ + "bandwidth"] + # used_signal_bandwidth = ( + # pow(10, 6) * config_meta_data["environment_emulation"]["target_link_config"]["ran_config"][ + # "uplink"]["ul_used_signal_BW_MHz"]) + sample_rate = config_meta_data["data_recording_config"]["common_meta_data"][ + "sample_rate"] + + # get signal emitter info + signal_emitter = { + "manufacturer": "NI", + "seid": user_equipment_meta_data["seid"], # Unique ID of the emitter + "hw": user_equipment_meta_data["hw_type"], + "hw_subtype": user_equipment_meta_data["hw_subtype"], + "frequency": freq, + "sample_rate": sample_rate, + "bandwidth": bandwidth, + "gain_tx": user_equipment_meta_data["tx_gain"], + "clock_reference": config_meta_data["data_recording_config"][ + "common_meta_data" + ]["clock_reference"], + } + + # ---------------------------------------------------- + # get channel metadata + # ---------------------------------------------------- + # get downlink channel info + # ch_downlink_config = config_meta_data["environment_emulation"]["target_link_config"]["wireless_channel"]["downlink"] + # ch_downlink ={"channel_model": ch_downlink_config["type"]} + + # ch_downlink_model = {"channel_model": "AWGN"} + # get uplink channel info + ch_uplink_config = config_meta_data["environment_emulation"]["target_link_config"][ + "wireless_channel" + ]["uplink"] + # Real Time RF Emulation + if config_meta_data["test_config"]["test_mode"] == "rf_real_time": + channel_metadata.update({"emulation_mode": "ni rf real time"}) + if ch_uplink_config["type"] == "statistical_predefined": + channel_metadata.update( + { + "channel_model": ch_uplink_config["statistical"]["predef_channel_profile"], + "snr_esn0_db": ch_uplink_config["statistical"]["snr_db"], + } + ) + + elif ch_uplink_config["type"] == "statistical_var": + channel_metadata.update( + { + "channel_model": ch_uplink_config["statistical"]["var_power_delay_profile"], + "snr_esn0_db": ch_uplink_config["statistical"]["snr_db"], + "delay_spread": ch_uplink_config["statistical"]["delay_spread_ns"] * pow(10, -9), + "speed": ch_uplink_config["statistical"]["speed_mps"], + } + ) + else: + raise Exception("ERROR: channel type is not supported in SigMF formatting") + # RF Simulation + elif config_meta_data["test_config"]["test_mode"] == "rf_simulation": + channel_metadata.update({"emulation_mode": "oai rf simulation"}) + channel_metadata.update( + { + "channel_model": ch_uplink_config["statistical"]["predef_channel_profile"], + "snr_esn0_db": ch_uplink_config["statistical"]["snr_db"], + "delay_spread": ch_uplink_config["statistical"]["delay_spread_ns"] + * pow(10, -9), "speed": ch_uplink_config["statistical"]["speed_mps"], + } + ) + else: + raise Exception( + "ERROR: Channel Emulation mode is not supported in SigMF formatting") + + channel_metadata["carrier_frequency"] = config_meta_data["environment_emulation"][ + "target_link_config"]["wireless_channel"]["carrierFreqValueList_hz"][0] + + # ---------------------------------------------------- + # get rx metadata + # ---------------------------------------------------- + rx_metadata.update( + { + "bandwidth": bandwidth, + "gain": base_station_meta_data["rx_gain"], + "manufacturer": "NI", + "seid": base_station_meta_data["seid"], + "hw_subtype": base_station_meta_data["hw_subtype"], + "clock_reference": config_meta_data["data_recording_config"][ + "common_meta_data" + ]["clock_reference"], + "phy_freq_domain_receiver_type": config_meta_data["test_config"][ + "dut_type" + ], + } + ) + # ---------------------------------------------------- + # get test config + # ---------------------------------------------------- + """ + test_config = { + "test_name": config_meta_data["test_config"]["test_name"], + "test_mode": config_meta_data["test_config"]["test_mode"], + "dut_type": config_meta_data["test_config"]["dut_type"], + } + """ + # Create sigmf metadata + # ---------------------- + # Add global parameters to SigMF metadata + # ---------------------- + meta = SigMFFile( + data_file=dataset_file_path, # extension is optional + global_info={ + SigMFFile.DATATYPE_KEY: captured_data[ + "sigmf_data_type" + ], # "cf32_le", # get_data_type_str(rx_data) - 'cf64_le' is not supported yet + SigMFFile.SAMPLE_RATE_KEY: sample_rate, + SigMFFile.NUM_CHANNELS_KEY: 1, + SigMFFile.AUTHOR_KEY: global_info["author"], + SigMFFile.DESCRIPTION_KEY: config_meta_data["data_recording_config"][ + "supported_oai_tracer_messages" + ][captured_data["message_type"]]["description"], + SigMFFile.RECORDER_KEY: "NI Data Recording Application for OAI", + SigMFFile.LICENSE_KEY: "MIT License", + # Since we are focusing on 5G NR UL, the base station is the receiver + SigMFFile.HW_KEY: base_station_meta_data["hw_type"], + # Disable DATASET key to mitigate the warning when read SIGMF data although it is given in the spec. + # It seems SIGMF still has bug here + SigMFFile.DATASET_KEY: dataset_filename, + SigMFFile.VERSION_KEY: sigmf.__version__, + sigmf.SigMFFile.COLLECTION_KEY: global_info["collection_file"], + }, + ) + + # ---------------------- + # Add capture parameters to SigMF metadata + # ---------------------- + serialization_scheme = config_meta_data["data_recording_config"][ + "supported_oai_tracer_messages" + ][captured_data["message_type"]]["serialization_scheme"] + capture_metadata = { + sigmf.SigMFFile.DATETIME_KEY: time_stamp_ms, + SigMFFile.FREQUENCY_KEY: freq, + **create_serialization_metadata( + serialization_scheme, waveform_generator, captured_data + ), + } + meta.add_capture(start_index=0, metadata=capture_metadata) # Sample Start + + # create annotations dict + system_components_dict = { + "system_components:transmitter": [ + { + "transmitter_id": "tx_0", + **tx_metadata, + "signal:emitter": signal_emitter, + } + ] + } + + system_components_dict["system_components:channel"] = [ + {"transmitter_id": "tx_0", **channel_metadata}] + + system_components_dict["system_components:receiver"] = rx_metadata + # ---------------------- + # Add annotation parameters to SigMF metadata + # ---------------------- + meta.add_annotation( + start_index=0, # Sample Start + length=len(captured_data["recorded_data"]), # Sample count + metadata={ + # SigMFFile.FLO_KEY: freq - sample_rate/ 2, # args.freq - args.rate / 2, + # SigMFFile.FHI_KEY: freq + sample_rate/ 2, # args.freq + args.rate / 2, + # SigMFFile.LABEL_KEY: label, + # SigMFFile.COMMENT_KEY: general_config["comment"], + "num_transmitters": 1, + **system_components_dict, + }, + ) + + # Write Meta Data to file + dataset_meta_filename = recorded_data_file_name + ".sigmf-meta" + dataset_meta_file_path = os.path.join(data_storage_path, dataset_meta_filename) + meta.tofile(dataset_meta_file_path) # extension is optional + + print(dataset_meta_file_path) + + return dataset_meta_file_path + + +def save_sigmf_collection(streams: list, global_info: dict, description: str, storage_path: str): + """Save metadata and links to SigMF data/metadata files to SigMF collection file.""" + # construct path + storage_path = os.path.expanduser(storage_path) + collection_filepath = os.path.join(storage_path, global_info["collection_file"]) + # statically configure Collection metadata + collection = SigMFCollection( + streams, + metadata={ + SigMFCollection.COLLECTION_KEY: { + SigMFCollection.VERSION_KEY: sigmf.__version__, + SigMFCollection.DESCRIPTION_KEY: description, + SigMFCollection.AUTHOR_KEY: global_info["author"], + # SigMFCollection.LICENSE_KEY: "License", + # SigMFCollection.EXTENSIONS_KEY: global_info["extensions"], + SigMFCollection.STREAMS_KEY: [], + } + }, + ) + + # save collection file + collection.tofile(collection_filepath) + print("") + print(collection_filepath + ".sigmf-collection") + + +def load_sigmf(filename: str, storage_path: str, scope: str): + """ + Loads metadata and data from SigMF file. + """ + # construct path + storage_path = os.path.expanduser(storage_path) + filepath = os.path.join(storage_path, filename) + # load SigMF file + signal = sigmf.sigmffile.fromfile(filepath) + + # get metadata fields + global_metadata = signal.get_global_info() + annotations_metadata = signal.get_annotations() + + # we only consider single annotations metadata element per SigMF file + annotation_start_idx = annotations_metadata[0][sigmf.SigMFFile.START_INDEX_KEY] + annotation_length = annotations_metadata[0][sigmf.SigMFFile.LENGTH_INDEX_KEY] + + # get capture metadata + capture_metadata = signal.get_capture_info(annotation_start_idx) + + # from source code: sigmffile.py + # "autoscale : bool, default True + # If dataset is in a fixed-point representation, scale samples from (min, max) to (-1.0, 1.0) + # raw_components : bool, default False + # If True read and return the sample components (individual I & Q for complex, samples for real) + # with no conversions or interleaved channels."" + # TODO: problem: raw_components flag is not used at all! changes in source code required! + # TODO: data is always converted to float32 after being read + + # read actual data + data = signal.read_samples( + annotation_start_idx, annotation_length, autoscale=False, raw_components=True) + + return data, global_metadata, annotations_metadata diff --git a/common/utils/data_recording/lib/sync_service.py b/common/utils/data_recording/lib/sync_service.py new file mode 100644 index 0000000000..87538173fd --- /dev/null +++ b/common/utils/data_recording/lib/sync_service.py @@ -0,0 +1,150 @@ + +# /* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +# --------------------------------------------------------------------- +# file common/utils/data_recording/lib/sync_service.py +# brief Sync service between captured Data from 5GNR gNB and UE +# author Abdo Gaber +# date 2025 +# version 1.0 +# company Emerson, NI Test and Measurement +# email: +# note +# warning + +import struct +from lib import data_recording_messages_def + +DEBUG_POW_MEAS_SYNC = True + + +# check if first frame ahead: +def is_frame_ahead(frame1, frame2, max_frame=1023): + """ + Check if frame1 is ahead of frame2, considering wrap-around from max_frame to 0. + + Args: + frame1 (int): The first frame number. + frame2 (int): The second frame number. + max_frame (int): The maximum frame number before wrap-around. Default is 1023. + + Returns: + bool: True if frame1 is ahead of frame2, False otherwise. + """ + # Calculate the difference considering wrap-around + diff = (frame1 - frame2 + (max_frame + 1)) % (max_frame + 1) + # If the difference is less than half the range, frame1 is ahead + return diff < (max_frame + 1) // 2 + + +# find the frame and slot start +def find_frame_slot_start(dataset1_start, dataset2_start): + """ + Function to find the frame and slot start for data sync + Args: + dataset1_start_info: Dictionary containing the start information of dataset1 + dataset2_start_info: Dictionary containing the start information of dataset2 + Returns: + sync_info: Dictionary containing the sync information + sync_info["frame"] = frame_start + sync_info["slot"] = slot_start + + """ + sync_info = {} + + if dataset1_start["frame"] == dataset2_start["frame"]: + frame_diff = 0 + frame_start = dataset1_start["frame"] + slot_start = max(dataset1_start["slot"], dataset2_start["slot"]) + + elif is_frame_ahead(dataset1_start["frame"], dataset2_start["frame"]): + frame_start = dataset1_start["frame"] + slot_start = dataset1_start["slot"] + frame_diff = (dataset1_start["frame"]- dataset2_start["frame"] + 1024) % 1024 + elif is_frame_ahead(dataset2_start["frame"], dataset1_start["frame"]): + frame_start = dataset2_start["frame"] + slot_start = dataset2_start["slot"] + frame_diff = (dataset2_start["frame"] - dataset1_start["frame"] + 1024) % 1024 + # check first if the delta time between the two datasets is larger than expected offset time. + # So, the sync will not be applied + # check during the calculation of the frame the ramp-around from 1023 to 0 + if abs(frame_diff) > 6: + raise Exception( + f"Frame difference between dataset1 and dataset2 is too large: {frame_diff}. " + "This may indicate a problem with the data collection or synchronization." + ) + + # Determine the starting frame and slot for data sync + sync_info["frame"] = frame_start + sync_info["slot"] = slot_start + return sync_info + + +# Read data from gNB T-tracer Application +def get_frame_slot_start(shm_reading, bufIdx, general_msg_header_list, + general_message_header_length): + buf = shm_reading.read(bufIdx + general_message_header_length) + msg_id = struct.unpack("pos == b->b.len) + return 0; + + b->b.buf[b->pos] = byte; + b->pos++; + + return 1; +} + +/* put an u32 number as big endian in a byte array if there is space + * returns 1 on success, 0 on error + */ +int byte_array_producer_put_u32_be(byte_array_producer_t *b, uint32_t v) +{ + return byte_array_producer_put_byte(b, (v >> 24) & 0xff) + && byte_array_producer_put_byte(b, (v >> 16) & 0xff) + && byte_array_producer_put_byte(b, (v >> 8) & 0xff) + && byte_array_producer_put_byte(b, v & 0xff); +} + +/* put an u24 number as big endian in a byte array if there is space + * returns 1 on success, 0 on error + */ +int byte_array_producer_put_u24_be(byte_array_producer_t *b, uint32_t v) +{ + return byte_array_producer_put_byte(b, (v >> 16) & 0xff) + && byte_array_producer_put_byte(b, (v >> 8) & 0xff) + && byte_array_producer_put_byte(b, v & 0xff); +} diff --git a/common/utils/ds/byte_array_producer.h b/common/utils/ds/byte_array_producer.h new file mode 100644 index 0000000000..2087c77af1 --- /dev/null +++ b/common/utils/ds/byte_array_producer.h @@ -0,0 +1,40 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef BYTE_ARRAY_PRODUCER_H +#define BYTE_ARRAY_PRODUCER_H + +#include + +#include "byte_array.h" + +typedef struct { + byte_array_t b; + size_t pos; +} byte_array_producer_t; + +byte_array_producer_t byte_array_producer_from_buffer(uint8_t *buffer, int len); + +int byte_array_producer_put_byte(byte_array_producer_t *b, uint8_t v); +int byte_array_producer_put_u32_be(byte_array_producer_t *b, uint32_t v); +int byte_array_producer_put_u24_be(byte_array_producer_t *b, uint32_t v); + +#endif diff --git a/common/utils/ds/seq_arr.c b/common/utils/ds/seq_arr.c index 708552a24e..50a332a16b 100644 --- a/common/utils/ds/seq_arr.c +++ b/common/utils/ds/seq_arr.c @@ -123,11 +123,10 @@ void seq_arr_erase_it(seq_arr_t* arr, void* start_it, void* end_it, void (*free_ return; if (free_func != NULL) { - void* start_it = seq_arr_front(arr); - void* end_it = seq_arr_end(arr); - while (start_it != end_it) { - free_func(start_it); - start_it = seq_arr_next(arr, start_it); + void* it = start_it; + while (it != end_it) { + free_func(it); + it = seq_arr_next(arr, it); } } diff --git a/common/utils/ds/tests/test_seq_array.c b/common/utils/ds/tests/test_seq_array.c index 28a7c98b1e..e06f72c881 100644 --- a/common/utils/ds/tests/test_seq_array.c +++ b/common/utils/ds/tests/test_seq_array.c @@ -36,6 +36,13 @@ static int compar(const void* m0, const void* m1) return 1; } +static int free_func_call_count = 0; + +static void dummy_free_func(void* it) +{ + ++free_func_call_count; +} + int main() { seq_arr_t arr = {0}; @@ -83,6 +90,19 @@ int main() void* it = bsearch(&key, base, nmemb, size, compar); assert(seq_arr_dist(&arr, seq_arr_front(&arr), it) == 4); + // Regression test: erase a partial range only + // Erase 92, 93, 94 (i.e., indices 1 to 3) + int* start = seq_arr_at(&arr, 1); + int* end = seq_arr_at(&arr, 4); + seq_arr_erase_it(&arr, start, end, dummy_free_func); + + // Now values should be: [91, 95, 96, 97, 98, 99] + assert(free_func_call_count == 3); + assert(seq_arr_size(&arr) == 6); + assert(*(int*)seq_arr_at(&arr, 0) == 91); + assert(*(int*)seq_arr_at(&arr, 1) == 95); + assert(*(int*)seq_arr_at(&arr, 5) == 99); + // Free data structure seq_arr_free(&arr, NULL); diff --git a/common/utils/mem/memory.c b/common/utils/mem/memory.c index d4f09279aa..44b806dbe9 100644 --- a/common/utils/mem/memory.c +++ b/common/utils/mem/memory.c @@ -25,52 +25,6 @@ #include "common/utils/mem/oai_memory.h" #include "common/utils/LOG/log.h" -/**************************************************************************** - ** ** - ** Name: memory_get_path() ** - ** ** - ** Description: Gets the absolute path of the file where non-volatile ** - ** data are located ** - ** ** - ** Inputs: dirname: The directory where data file is located ** - ** filename: The name of the data file ** - ** Others: None ** - ** ** - ** Outputs: None ** - ** Return: The absolute path of the non-volatile data ** - ** file. The returned value is a dynamically ** - ** allocated octet string that needs to be ** - ** freed after usage. ** - ** Others: None ** - ** ** - ***************************************************************************/ -char* memory_get_path(const char* dirname, const char* filename) -{ - /* Get non-volatile data directory */ - const char* path = getenv(dirname); - - if (path == NULL) { - path = getenv(DEFAULT_NAS_PATH); - } - - if (path == NULL) { - path = "."; - } - - /* Append non-volatile data file name */ - size_t size = strlen(path) + strlen(filename) + 1; - char* data_filename = (char*)malloc(size + 1); - - if (data_filename != NULL) { - if (size != sprintf(data_filename, "%s/%s", path, filename)) { - free(data_filename); - return NULL; - } - } - - return data_filename; -} - char* memory_get_path_from_ueid(const char* dirname, const char* filename, int ueid) { /* Get non-volatile data directory */ diff --git a/common/utils/mem/oai_memory.h b/common/utils/mem/oai_memory.h index 311ad6f4d0..c09fe0b072 100644 --- a/common/utils/mem/oai_memory.h +++ b/common/utils/mem/oai_memory.h @@ -35,8 +35,6 @@ typedef unsigned char uint8_t; //----------------------------------------------------------------------------- -char* memory_get_path(const char* dirname, const char* filename); - char* memory_get_path_from_ueid(const char* dirname, const char* filename, int ueid); int memory_read(const char* datafile, void* data, size_t size); diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 5d98a99bb4..8e6a16c97d 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -152,6 +152,17 @@ void reverse_bits_u8(uint8_t const* in, size_t sz, uint8_t* out) #endif } +/** @brief 3GPP TS 38.133 Table 10.1.6.1-1 mapping from dBm to RSRP index */ +uint8_t get_rsrp_index(int rsrp_dBm) +{ + int index = rsrp_dBm + 157; + if (rsrp_dBm > -44) + index = 113; + if (rsrp_dBm < -140) + index = 16; + return (uint8_t)index; +} + // Reverse bits implementation based on http://graphics.stanford.edu/~seander/bithacks.html uint64_t reverse_bits(uint64_t in, int n_bits) { @@ -1160,6 +1171,7 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, const int ssb_offset_point_a = ((scaled_abs_diff / 12) - 10) * scaling; // Offset to point A needs to be divisible by scaling AssertFatal(ssb_offset_point_a % scaling == 0, "PRB offset %d not valid for scs %d\n", ssb_offset_point_a, ssbSubcarrierSpacing); + AssertFatal(ssb_offset_point_a >= 0, "ssb offset is negative %d for scs %d\n", ssb_offset_point_a, ssbSubcarrierSpacing); return ssb_offset_point_a; } @@ -1415,6 +1427,11 @@ uint32_t nr_timer_elapsed_time(const NR_timer_t *timer) return timer->counter; } +uint32_t nr_timer_remaining_time(const NR_timer_t *timer) +{ + return timer->target - timer->counter; +} + void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t step) { timer->target = target; @@ -1459,13 +1476,13 @@ frequency_range_t get_freq_range_from_band(uint16_t band) return band <= 256 ? FR1 : FR2; } -float get_beta_dmrs_pusch(int num_cdm_groups_no_data, pusch_dmrs_type_t dmrs_type) +float get_beta_dmrs(int num_cdm_groups_no_data, bool is_type2) { float beta_dmrs_pusch = 1.0; if (num_cdm_groups_no_data == 2) { beta_dmrs_pusch = powf(10.0, 3.0 / 20.0); } else if (num_cdm_groups_no_data == 3) { - if (dmrs_type == pusch_dmrs_type2) + if (is_type2) beta_dmrs_pusch = powf(10.0, 4.77 / 20.0); } return beta_dmrs_pusch; diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index f98ce510a2..e0d68a45ad 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -175,6 +175,20 @@ typedef struct { uint32_t step; } NR_timer_t; +typedef struct val_init { + int val; + bool init; +} val_init_t; + +typedef struct meas_s { + uint16_t Nid_cell; + val_init_t ss_rsrp_dBm; + val_init_t csi_rsrp_dBm; +} meas_t; + +/** @brief Returns NR RSRP index per 3GPP TS 38.133 Table 10.1.6.1-1 */ +uint8_t get_rsrp_index(int rsrp_dBm); + /** * @brief To start a timer * @param timer Timer to be started @@ -222,6 +236,12 @@ bool nr_timer_is_active(const NR_timer_t *timer); * @return Time passed since start of timer */ uint32_t nr_timer_elapsed_time(const NR_timer_t *timer); +/** + * @brief To return how much time is left until the timer expires + * @param timer Timer to be checked + * @return Time left until the timer expires + */ +uint32_t nr_timer_remaining_time(const NR_timer_t *timer); int set_default_nta_offset(frequency_range_t freq_range, uint32_t samples_per_subframe); @@ -246,6 +266,12 @@ static __attribute__((always_inline)) inline int count_bits64(uint64_t v) return __builtin_popcountll(v); } +static __attribute__((always_inline)) inline int count_bits64_with_mask(uint64_t v, int start, int num) +{ + uint64_t mask = ((1LL << num) - 1) << start; + return count_bits64(v & mask); +} + uint64_t reverse_bits(uint64_t in, int n_bits); void reverse_bits_u8(uint8_t const* in, size_t sz, uint8_t* out); @@ -308,15 +334,15 @@ frequency_range_t get_freq_range_from_arfcn(uint32_t arfcn); frequency_range_t get_freq_range_from_band(uint16_t band); /** - * @brief Calculates the scaling factor for the ratio of PUSCH EPRE to DMRS EPRE. + * @brief Calculates the scaling factor for the ratio of PUSCH/PDSCH EPRE to DMRS EPRE. * * @param num_cdm_groups_no_data The number of CDM groups without data. - * @param dmrs_type The DMRS type. - * @return The calculated beta scaling factor for the ratio of PUSCH EPRE to DMRS EPRE. + * @param is_type2 true if calculating for DMRS configuration type 2 + * @return The calculated beta scaling factor for the ratio of PUSCH/PDSCH EPRE to DMRS EPRE. * - * @note The values are derived from TS 38.214 Table 6.2.2-1. + * @note The values are the same for PUSCH and PDSCH and are derived from TS 38.214 Table 6.2.2-1./4.1-1 */ -float get_beta_dmrs_pusch(int num_cdm_groups_no_data, pusch_dmrs_type_t dmrs_type); +float get_beta_dmrs(int num_cdm_groups_no_data, bool is_type2); #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index 84dbd15365..8f4e25d8b1 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -321,8 +321,6 @@ typedef struct { TASK_DEF(TASK_DU_F1, 200) \ TASK_DEF(TASK_CUCP_E1, 200) \ TASK_DEF(TASK_CUUP_E1, 200) \ - TASK_DEF(TASK_RRC_NSA_UE, 200) \ - TASK_DEF(TASK_RRC_NSA_NRUE, 200) \ TASK_DEF(TASK_NAS_NRUE, 200) \ TASK_DEF(TASK_MAX, 200) diff --git a/common/utils/shm_iq_channel/shm_td_iq_channel.c b/common/utils/shm_iq_channel/shm_td_iq_channel.c index 89e09ddb1f..ecebbaf494 100644 --- a/common/utils/shm_iq_channel/shm_td_iq_channel.c +++ b/common/utils/shm_iq_channel/shm_td_iq_channel.c @@ -40,7 +40,6 @@ typedef struct { int num_antennas_tx; int num_antennas_rx; uint64_t timestamp; - bool is_connected; pthread_mutex_t mutex; pthread_cond_t cond; } ShmTDIQChannelData; @@ -48,10 +47,10 @@ typedef struct { typedef struct ShmTDIQChannel_s { IQChannelType type; ShmTDIQChannelData *data; - uint64_t last_timestamp; char name[256]; sample_t *tx_iq_data; sample_t *rx_iq_data; + bool abort; } ShmTDIQChannel; ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int num_rx_ant) @@ -75,14 +74,12 @@ ShmTDIQChannel *shm_td_iq_channel_create(const char *name, int num_tx_ant, int n memset(shm_ptr, 0, total_size); shm_ptr->num_antennas_tx = num_tx_ant; shm_ptr->num_antennas_rx = num_rx_ant; - shm_ptr->is_connected = false; ShmTDIQChannel *channel = calloc_or_fail(1, sizeof(ShmTDIQChannel)); strncpy(channel->name, name, sizeof(channel->name) - 1); channel->tx_iq_data = (sample_t *)(shm_ptr + 1); channel->rx_iq_data = channel->tx_iq_data + tx_buffer_size / sizeof(sample_t); channel->data = shm_ptr; channel->type = IQ_CHANNEL_TYPE_SERVER; - channel->last_timestamp = 0; pthread_mutexattr_t mutex_attr; pthread_condattr_t cond_attr; int ret = pthread_mutexattr_init(&mutex_attr); @@ -137,12 +134,10 @@ ShmTDIQChannel *shm_td_iq_channel_connect(const char *name, int timeout_in_secon size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * channel->data->num_antennas_tx; channel->rx_iq_data = channel->tx_iq_data + tx_buffer_size / sizeof(sample_t); channel->type = IQ_CHANNEL_TYPE_CLIENT; - channel->last_timestamp = 0; while (shm_ptr->magic != SHM_MAGIC_NUMBER) { printf("Waiting for server to initialize shared memory\n"); sleep(1); } - shm_ptr->is_connected = true; close(fd); return channel; } @@ -154,9 +149,6 @@ IQChannelErrorType shm_td_iq_channel_tx(ShmTDIQChannel *channel, const sample_t *tx_iq_data) { ShmTDIQChannelData *data = channel->data; - if (data->is_connected == false) { - return CHANNEL_ERROR_NOT_CONNECTED; - } // timestamp in the past uint64_t current_time = data->timestamp; if (timestamp < current_time) { @@ -193,9 +185,6 @@ IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel, sample_t *tx_iq_data) { ShmTDIQChannelData *data = channel->data; - if (data->is_connected == false) { - return CHANNEL_ERROR_NOT_CONNECTED; - } // timestamp in the future uint64_t current_time = data->timestamp; if (timestamp > current_time) { @@ -228,37 +217,54 @@ IQChannelErrorType shm_td_iq_channel_rx(ShmTDIQChannel *channel, void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_samples) { ShmTDIQChannelData *data = channel->data; - if (channel->type != IQ_CHANNEL_TYPE_SERVER) { - return; - } - if (data->is_connected == false) { - return; - } mutexlock(data->mutex); data->timestamp += num_samples; condbroadcast(data->cond); mutexunlock(data->mutex); } -void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp) +int shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS) { ShmTDIQChannelData *data = channel->data; - if (data->is_connected == false) { - abort(); - return; - } - size_t current_timestamp = data->timestamp; if (current_timestamp >= timestamp) { - return; + return 0; } - mutexlock(data->mutex); - while (current_timestamp < timestamp) { - condwait(data->cond, data->mutex); - current_timestamp = data->timestamp; + if (timeout_uS == 0) { + mutexlock(data->mutex); + while (current_timestamp < timestamp && !channel->abort) { + condwait(data->cond, data->mutex); + current_timestamp = data->timestamp; + } + mutexunlock(data->mutex); + } else { + struct timespec ts = {.tv_sec = 0, .tv_nsec = 0}; + if (clock_gettime(CLOCK_REALTIME, &ts) != 0) { + fprintf(stderr, "Error: clock_gettime failed: %s\n", strerror(errno)); + return 1; + } + + ts.tv_sec += timeout_uS / 1000000; // Convert microseconds to seconds + ts.tv_nsec += (timeout_uS % 1000000) * 1000; // Convert remaining microseconds to nanoseconds + + mutexlock(data->mutex); + while (current_timestamp < timestamp && !channel->abort) { + int ret = pthread_cond_timedwait(&data->cond, &data->mutex, &ts); + if (ret == ETIMEDOUT) { + fprintf(stderr, "Error: Timed out waiting for samples.\n"); + mutexunlock(data->mutex); + return 1; + } else if (ret != 0) { + fprintf(stderr, "Error: pthread_cond_timedwait failed: %s\n", strerror(ret)); + mutexunlock(data->mutex); + return 1; + } else { + current_timestamp = data->timestamp; + } + } + mutexunlock(data->mutex); } - mutexunlock(data->mutex); - return; + return 0; } uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel) @@ -267,9 +273,18 @@ uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel) return data->timestamp; } -bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel) +void shm_td_iq_channel_abort(ShmTDIQChannel *channel) { - return channel->data->is_connected; + ShmTDIQChannelData *data = channel->data; + mutexlock(data->mutex); + channel->abort = true; + condbroadcast(data->cond); + mutexunlock(data->mutex); +} + +bool shm_td_iq_channel_is_aborted(const ShmTDIQChannel *channel) +{ + return channel->abort; } void shm_td_iq_channel_destroy(ShmTDIQChannel *channel) @@ -278,9 +293,11 @@ void shm_td_iq_channel_destroy(ShmTDIQChannel *channel) size_t tx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_tx; size_t rx_buffer_size = CIRCULAR_BUFFER_SIZE * sizeof(sample_t) * data->num_antennas_rx; size_t total_size = sizeof(ShmTDIQChannelData) + tx_buffer_size + rx_buffer_size; - munmap(data, total_size); if (channel->type == IQ_CHANNEL_TYPE_SERVER) { + munmap(data, total_size); shm_unlink(channel->name); + } else { + munmap(data, total_size); } free(channel); } diff --git a/common/utils/shm_iq_channel/shm_td_iq_channel.h b/common/utils/shm_iq_channel/shm_td_iq_channel.h index 7c5a730914..b71720c1f9 100644 --- a/common/utils/shm_iq_channel/shm_td_iq_channel.h +++ b/common/utils/shm_iq_channel/shm_td_iq_channel.h @@ -118,16 +118,27 @@ void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, uint64_t num_sam * @brief Wait until sample at the specified timestamp is available * * @param channel The ShmTDIQChannel structure. + * @param timestamp The timestamp for which to wait. + * @param timeout_uS The timeout in microseconds to wait for the sample. 0 means wait indefinitely. + * + * @return 0 if the sample is available, 1 if timed out */ -void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp); +int shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS); /** - * @brief Checks if the IQ channel is connected. + * @brief Aborts the IQ channel causing the wait to return immediately * * @param channel The ShmTDIQChannel structure. - * @return True if the channel is connected, false otherwise. */ -bool shm_td_iq_channel_is_connected(const ShmTDIQChannel *channel); +void shm_td_iq_channel_abort(ShmTDIQChannel *channel); + +/** + * @brief Checks if the IQ channel is aborted. + * + * @param channel The ShmTDIQChannel structure. + * @return True if the channel is aborted, false otherwise. + */ +bool shm_td_iq_channel_is_aborted(const ShmTDIQChannel *channel); /** * @brief Destroys the shared memory IQ channel. diff --git a/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c b/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c index f5170b8144..05140a0f63 100644 --- a/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c +++ b/common/utils/shm_iq_channel/tests/test_shm_td_iq_channel.c @@ -87,15 +87,6 @@ void server(void) int num_ant_tx = 1; int num_ant_rx = 1; ShmTDIQChannel *channel = shm_td_iq_channel_create(SHM_CHANNEL_NAME, num_ant_tx, num_ant_rx); - for (int i = 0; i < 10; i++) { - if (shm_td_iq_channel_is_connected(channel)) { - printf("Server connected\n"); - break; - } - printf("Waiting for client\n"); - sleep(1); - } - AssertFatal(shm_td_iq_channel_is_connected(channel), "Server failed to connect\n"); pthread_t producer_thread; int ret = pthread_create(&producer_thread, NULL, produce_symbols, channel); @@ -104,7 +95,7 @@ void server(void) uint64_t timestamp = 0; int iq_contents = 0; while (timestamp < num_samples_per_update * num_updates) { - shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update); + shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update, 0); uint64_t target_timestamp = timestamp + num_samples_per_update; timestamp += num_samples_per_update; uint32_t iq_data[num_samples_per_update]; @@ -127,21 +118,12 @@ int client(void) { int total_errors = 0; ShmTDIQChannel *channel = shm_td_iq_channel_connect(SHM_CHANNEL_NAME, 10); - for (int i = 0; i < 10; i++) { - if (shm_td_iq_channel_is_connected(channel)) { - printf("Client connected\n"); - break; - } - printf("Waiting for server\n"); - sleep(1); - } - AssertFatal(shm_td_iq_channel_is_connected(channel), "Client failed to connect\n"); uint64_t timestamp = 0; int iq_contents = 0; while (timestamp < num_samples_per_update * num_updates) { - shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update); + shm_td_iq_channel_wait(channel, timestamp + num_samples_per_update, 0); // Server starts producing from second slot if (timestamp > num_samples_per_update) { uint64_t target_timestamp = timestamp - num_samples_per_update; diff --git a/common/utils/telnetsrv/CMakeLists.txt b/common/utils/telnetsrv/CMakeLists.txt index 5f190edc02..a249596d97 100644 --- a/common/utils/telnetsrv/CMakeLists.txt +++ b/common/utils/telnetsrv/CMakeLists.txt @@ -44,7 +44,7 @@ add_library(telnetsrv_enb MODULE telnetsrv_enb_phycmd.c ) add_dependencies(telnetsrv telnetsrv_enb) -target_link_libraries(telnetsrv_enb PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +target_link_libraries(telnetsrv_enb PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs log_headers) message(STATUS "No specific telnet functions for gnb") @@ -62,7 +62,7 @@ add_dependencies(telnetsrv telnetsrv_ci) message(STATUS "Add CI specific telnet functions for nrUE in telnetsrv_ciUE.so") add_library(telnetsrv_ciUE MODULE telnetsrv_ciUE.c) -target_link_libraries(telnetsrv_ciUE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) +target_link_libraries(telnetsrv_ciUE PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs UTIL) add_dependencies(telnetsrv telnetsrv_ciUE) message(STATUS "Add bearer specific telnet functions in libtelnetsrv_bearer.so") diff --git a/common/utils/telnetsrv/telnetsrv.c b/common/utils/telnetsrv/telnetsrv.c index de1c26d2e1..03b67506bc 100644 --- a/common/utils/telnetsrv/telnetsrv.c +++ b/common/utils/telnetsrv/telnetsrv.c @@ -375,32 +375,32 @@ char *telnet_getvarvalue(telnetshell_vardef_t *var, int varindex) char *val; switch (var[varindex].vartype) { case TELNET_VARTYPE_INT32: - val = malloc(64); + val = calloc_or_fail(1, 64); snprintf(val, 64, "%i", *(int32_t *)(var[varindex].varvalptr)); break; case TELNET_VARTYPE_INT64: - val = malloc(128); + val = calloc_or_fail(1, 128); snprintf(val, 128, "%lli", (long long)*(int64_t *)(var[varindex].varvalptr)); break; case TELNET_VARTYPE_INT16: - val = malloc(16); + val = calloc_or_fail(1, 16); snprintf(val, 16, "%hi", *(short *)(var[varindex].varvalptr)); break; case TELNET_VARTYPE_INT8: - val = malloc(16); + val = calloc_or_fail(1, 16); snprintf(val, 16, "%i", (int)(*(int8_t *)(var[varindex].varvalptr))); break; case TELNET_VARTYPE_UINT: - val = malloc(64); + val = calloc_or_fail(1, 64); snprintf(val, 64, "%u", *(unsigned int *)(var[varindex].varvalptr)); break; case TELNET_VARTYPE_DOUBLE: - val = malloc(32); + val = calloc_or_fail(1, 32); snprintf(val, 32, "%g\n", *(double *)(var[varindex].varvalptr)); break; @@ -409,7 +409,7 @@ char *telnet_getvarvalue(telnetshell_vardef_t *var, int varindex) break; default: - val = malloc(64); + val = calloc_or_fail(1, 64); snprintf(val, 64, "ERR:var %i unknown type", varindex); break; } @@ -692,8 +692,8 @@ void run_telnetsrv(void) { break; } - if (telnetparams.telnetdbg > 0) - TELNET_LOG("Command received: readc %i filled %i \"%s\"\n", readc, filled, buf); + //if (telnetparams.telnetdbg > 0) + TELNET_LOG("Command received: readc %i filled %i \"%s\"\n", readc, filled, buf); if (buf[0] == '!') { if (buf[1] == '!') { @@ -927,7 +927,7 @@ int add_telnetcmd(char *modulename, telnetshell_vardef_t *var, telnetshell_cmdde for (int j = 0; cmd[j].cmdfunc != NULL; j++) { if (cmd[j].cmdflags & TELNETSRV_CMDFLAG_PUSHINTPOOLQ) { if (afifo == NULL) { - afifo = malloc(sizeof(notifiedFIFO_t)); + afifo = calloc_or_fail(1, sizeof(notifiedFIFO_t)); initNotifiedFIFO(afifo); } cmd[j].qptr = afifo; @@ -956,8 +956,8 @@ int telnetsrv_checkbuildver(char *mainexec_buildversion, char **shlib_buildvers } int telnetsrv_getfarray(loader_shlibfunc_t **farray) { - int const num_func_tln_srv = 3; - *farray = malloc(sizeof(loader_shlibfunc_t) * num_func_tln_srv); + int const num_func_tln_srv = 3; + *farray = calloc_or_fail(num_func_tln_srv, sizeof(loader_shlibfunc_t)); (*farray)[0].fname=TELNET_ADDCMD_FNAME; (*farray)[0].fptr=(int (*)(void) )add_telnetcmd; (*farray)[1].fname=TELNET_POLLCMDQ_FNAME; diff --git a/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c b/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c index 82f791cd2a..6f2d1c7516 100644 --- a/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c +++ b/common/utils/telnetsrv/telnetsrv_5Gue_measurements.c @@ -86,7 +86,7 @@ int get_measurgroups(telnet_measurgroupdef_t **measurgroups) { void measurcmd_display_phycpu(telnet_printfunc_t prnt) { PHY_VARS_NR_UE *UE = PHY_vars_UE_g[0][0]; - telnet_cpumeasurdef_t cpumeasur[MAX_CPU_STAT_TYPE]; + telnet_cpumeasurdef_t cpumeasur[MAX_CPU_STAT_TYPE] = {}; for (int i = 0; i < MAX_CPU_STAT_TYPE; i++) { sprintf(cpumeasur[i].statname, "%s", UE->phy_cpu_stats.cpu_time_stats[i].meas_name); cpumeasur[i].astatptr = &UE->phy_cpu_stats.cpu_time_stats[i]; diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index fff1423c16..291f1f37a2 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -38,11 +38,12 @@ #include "openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" +#include "openair2/RRC/NR/rrc_gNB_mobility.h" #define TELNETSERVERCODE #include "telnetsrv.h" -#define ERROR_MSG_RET(mSG, aRGS...) do { prnt(mSG, ##aRGS); return 1; } while (0) +#define ERROR_MSG_RET(mSG, aRGS...) do { prnt(mSG, ##aRGS); return -1; } while (0) static int get_single_ue_rnti_mac(void) { @@ -136,6 +137,8 @@ int trigger_reestab(char *buf, int debug, telnet_printfunc_t prnt) if (!RC.nrmac) ERROR_MSG_RET("no MAC/RLC present, cannot trigger reestablishment\n"); int rnti = fetch_rnti(buf, prnt); + if (rnti < 0) + ERROR_MSG_RET("could not identify UE (no UE, no such RNTI, or multiple UEs)\n"); nr_rlc_test_trigger_reestablishment(rnti); prnt("Reset RLC counters of UE RNTI %04x to trigger reestablishment\n", rnti); return 0; @@ -194,11 +197,60 @@ int rrc_gNB_trigger_f1_ho(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +extern void nr_HO_N2_trigger_telnet(gNB_RRC_INST *rrc, uint32_t neighbour_pci, uint32_t rrc_ue_id); + +/** @brief Trigger N2 handover for UE + * @param buf: Neighbour PCI, SCell PCI, RRC UE ID + * @param debug: Debug flag + * @param prnt: Print function + * @return 0 on success, -1 on failure */ +int rrc_gNB_trigger_n2_ho(char *buf, int debug, telnet_printfunc_t prnt) +{ + if (!RC.nrrrc) + ERROR_MSG_RET("no RRC present, cannot list counts\n"); + + if (!buf) { + ERROR_MSG_RET("Please provide neighbour cell id and ue id\n"); + } else { + // Parse neighbour cell PCI + char *token = strtok(buf, ","); + if (!token) { + ERROR_MSG_RET("Invalid input. Expected format: Neighbour PCI, ueId\n"); + } + uint32_t neighbour_pci = strtol(token, NULL, 10); + + // Parse ueId + token = strtok(NULL, ","); + if (!token) { + ERROR_MSG_RET("Missing UE ID\n"); + } + uint32_t ueId = strtol(token, NULL, 10); + + // Retrieve UE context + rrc_gNB_ue_context_t *ue_p = rrc_gNB_get_ue_context(RC.nrrrc[0], ueId); + if (!ue_p) { + ERROR_MSG_RET("UE with id %u not found\n", ueId); + } + gNB_RRC_UE_t *UE = &ue_p->ue_context; + + // Trigger N2 handover + nr_HO_N2_trigger_telnet(RC.nrrrc[0], neighbour_pci, UE->rrc_ue_id); + + // Print success message + prnt("RRC N2 handover triggered for UE %u with neighbour cell id %u\n", + ueId, + neighbour_pci); + } + return 0; +} + int force_ul_failure(char *buf, int debug, telnet_printfunc_t prnt) { if (!RC.nrmac) ERROR_MSG_RET("no MAC/RLC present, force_ul_failure failed\n"); int rnti = fetch_rnti(buf, prnt); + if (rnti < 0) + ERROR_MSG_RET("could not identify UE (no UE, no such RNTI, or multiple UEs)\n"); NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, rnti); nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); return 0; @@ -208,6 +260,8 @@ int force_ue_release(char *buf, int debug, telnet_printfunc_t prnt) { force_ul_failure(buf, debug, prnt); int rnti = fetch_rnti(buf, prnt); + if (rnti < 0) + ERROR_MSG_RET("could not identify UE (no UE, no such RNTI, or multiple UEs)\n"); NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, rnti); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; sched_ctrl->ul_failure_timer = 2; @@ -215,6 +269,21 @@ int force_ue_release(char *buf, int debug, telnet_printfunc_t prnt) return 0; } +static int get_current_bwp(char *buf, int debug, telnet_printfunc_t prnt) +{ + int rnti = fetch_rnti(buf, prnt); + if (rnti < 0) + ERROR_MSG_RET("could not identify UE (no UE, no such RNTI, or multiple UEs)\n"); + NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, rnti); + int dl_bwp = UE->current_DL_BWP.bwp_id; + const char *dl_bwp_text = dl_bwp > 0 ? "dedicated" : "initial"; + int ul_bwp = UE->current_UL_BWP.bwp_id; + const char *ul_bwp_text = ul_bwp > 0 ? "dedicated" : "initial"; + + prnt("UE %04x DL BWP ID %d (%s) UL BWP ID %d (%s)\n", UE->rnti, dl_bwp, dl_bwp_text, ul_bwp, ul_bwp_text); + return 0; +} + static telnetshell_cmddef_t cicmds[] = { {"get_single_rnti", "", get_single_rnti}, {"force_reestab", "[rnti(hex,opt)]", trigger_reestab}, @@ -223,6 +292,8 @@ static telnetshell_cmddef_t cicmds[] = { {"force_ul_failure", "[rnti(hex,opt)]", force_ul_failure}, {"trigger_f1_ho", "[rrc_ue_id(int,opt)]", rrc_gNB_trigger_f1_ho}, {"fetch_du_by_ue_id", "[rrc_ue_id(int,opt)]", fetch_du_by_ue_id}, + {"get_current_bwp", "[rnti(hex,opt)]", get_current_bwp}, + {"trigger_n2_ho", "[neighbour_pci(uint32_t),ueId(uint32_t)]", rrc_gNB_trigger_n2_ho}, {"", "", NULL}, }; diff --git a/common/utils/telnetsrv/telnetsrv_enb_measurements.c b/common/utils/telnetsrv/telnetsrv_enb_measurements.c index b8898b665e..7bd18c802b 100644 --- a/common/utils/telnetsrv/telnetsrv_enb_measurements.c +++ b/common/utils/telnetsrv/telnetsrv_enb_measurements.c @@ -160,7 +160,7 @@ void measurcmd_display_rlcstats(telnet_printfunc_t prnt) { UE_info_t *UE_info = &(RC.mac[eNB_id]->UE_info); telnet_ltemeasurdef_t statsptr[]=LTE_RLCMEASURE; int num_rlcmeasure = sizeof(statsptr)/sizeof(telnet_ltemeasurdef_t ); - unsigned int *rlcstats = malloc(num_rlcmeasure*sizeof(unsigned int)); + unsigned int *rlcstats = calloc_or_fail(num_rlcmeasure,sizeof(unsigned int)); eNB_MAC_INST *eNB = RC.mac[eNB_id]; for(int i=0; i trials += src_ts->trials; dst_ts->diff += src_ts->diff; + dst_ts->diff_square += src_ts->diff_square; if (src_ts->max > dst_ts->max) dst_ts->max = src_ts->max; } diff --git a/common/utils/tun_if.c b/common/utils/tun_if.c index 4bb1f7ec58..f74ab3c7f2 100644 --- a/common/utils/tun_if.c +++ b/common/utils/tun_if.c @@ -120,7 +120,7 @@ static bool setInterfaceParameter(int sock_fd, const char *ifn, int af, const ch { DevAssert(af == AF_INET || af == AF_INET6); struct ifreq ifr = {0}; - strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name) - 1); struct in6_ifreq ifr6 = {0}; void *ioctl_opt = NULL; @@ -167,7 +167,7 @@ static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_ const char *action = if_action == INTERFACE_DOWN ? "DOWN" : "UP"; struct ifreq ifr = {0}; - strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name)); + strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name) - 1); /* get flags of this interface: see netdevice(7) */ bool success = ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t)&ifr) == 0; diff --git a/doc/Aerial_FAPI_Split_Tutorial.md b/doc/Aerial_FAPI_Split_Tutorial.md index 8d4ea54c3d..6eef02dc34 100644 --- a/doc/Aerial_FAPI_Split_Tutorial.md +++ b/doc/Aerial_FAPI_Split_Tutorial.md @@ -41,12 +41,12 @@ PTP enabled switches and grandmaster clock we have tested with: These are the radio units we've used for testing: -| Vendor | Software Version | -|-------------|------------------| -| Foxconn RPQN-7801E RU | 2.6.9r254 | -| Foxconn RPQN-7801E RU | 3.1.15_0p4 | -| Foxconn RPQN-7801E RU | v3.2.0q.551.12.E.rc2.srs-AIO | - +| Vendor | Software Version | +|-----------------------|-----------------------------| +| Foxconn RPQN-7801E RU | 2.6.9r254 | +| Foxconn RPQN-7801E RU | 3.1.15_0p4 | +| Foxconn RPQN-7801E RU | 3.2.0q.551.12.E.rc2.srs-AIO | +| WNC R1220-078LE | 1.9.0 | The UEs that have been tested and confirmed working with Aerial are the following: @@ -66,6 +66,8 @@ The UEs that have been tested and confirmed working with Aerial are the followin To set up the L1 and install the components manually refer to this [instructions page](https://docs.nvidia.com/aerial/cuda-accelerated-ran/index.html). **Note**: +- As of wk36, the L1 must be compiled with the following CMake flag: `-DSCF_FAPI_10_04_SRS=ON` , this is due to the usage +of the FAPI 10.04 version of the SRS PDU, and RX_Beamforming PDU. - To configure the Gigabyte server please refer to these [instructions](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/2025.w13/doc/Aerial_FAPI_Split_Tutorial.md) - The last release to support the Gigabyte server is **Aerial CUDA-Accelerated RAN 24-1**. @@ -80,7 +82,7 @@ To set up the L1 and install the components manually refer to this [instructions | Applicative Threads | Allocated CPUs | |------------------------|----------------| | PTP & PHC2SYS Services | 41 | -| OAI `nr-softmodem` | 13-20 | +| OAI `nr-softmodem` | 13-14 | ## PTP configuration @@ -213,8 +215,8 @@ With the nvIPC sources in the project directory, the docker image can be built. In order to build the target image (`oai-gnb-aerial`), first you should build a common shared image (`ran-base`) ```bash ~$ cd ~/openairinterface5g/ -~/openairinterface5g$ docker build . -f docker/Dockerfile.base.ubuntu22 --tag ran-base:latest -~/openairinterface5g$ docker build . -f docker/Dockerfile.gNB.aerial.ubuntu22 --tag oai-gnb-aerial:latest +~/openairinterface5g$ docker build . -f docker/Dockerfile.base.ubuntu --tag ran-base:latest +~/openairinterface5g$ docker build . -f docker/Dockerfile.gNB.aerial.ubuntu --tag oai-gnb-aerial:latest ``` @@ -230,10 +232,10 @@ After preparing the L1 software, the container needs to be committed to create a In this file the RU MAC address needs to be specified before commiting the image. ```bash -~$ docker commit nv-cubb cubb-build:24-3 +~$ docker commit nv-cubb cubb-build:25-2.1 ~$ docker image ls .. -cubb-build 24-3 824156e0334c 2 weeks ago 23.9GB +cubb-build 25-2.1 824156e0334c 2 weeks ago 23.9GB -.. ``` diff --git a/doc/BUILD.md b/doc/BUILD.md index 4d629007b0..8298204859 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -185,7 +185,7 @@ Some libraries have further dependencies and might not build on every system: - `enbscope`, `uescope`, `nrscope`: libforms/X - `ldpc_cuda`: CUDA - `websrv`: npm and others -- `ldpc_t2`: DPDK with patch +- `ldpc_aal`: DPDK with patch # Running `cmake` directly diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 2b6c1dd0bb..7f46dc1517 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,4 +1,4 @@ -add_boolean_option(GENERATE_DOXYGEN False "Generate source code doc using doxygen" OFF) +add_boolean_option(GENERATE_DOXYGEN OFF "Generate source code doc using doxygen" OFF) if(GENERATE_DOXYGEN) find_package(Doxygen REQUIRED) diff --git a/doc/Doxyfile b/doc/Doxyfile index f128e3eb88..5f96bc2e4a 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -51,7 +51,7 @@ PROJECT_BRIEF = "Full experimental OpenSource LTE and NR implementation # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = @CMAKE_SOURCE_DIR@/doc/oai_logo.png +PROJECT_LOGO = @CMAKE_SOURCE_DIR@/doc/images/oai_logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -1021,7 +1021,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_ue_context.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_management_procedures.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_context_management_procedures.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_common.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_decoder.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_management_procedures.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair3/S1AP/s1ap_eNB_handlers.h \ @@ -1837,7 +1836,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/common.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/rrc_UE.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/rrc_sl_preconfig.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/rrc_nsa.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/rrc_proto.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/rrc_vars.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/sl_preconfig_paramvalues.h \ diff --git a/doc/E1AP/E1-design.md b/doc/E1AP/E1-design.md index 8fafd09f66..d9a7131393 100644 --- a/doc/E1AP/E1-design.md +++ b/doc/E1AP/E1-design.md @@ -1,6 +1,6 @@ [[_TOC_]] -# 1. Introduction +## 1. Introduction E1 is the interface that lies between the nodes CU Control Plane (CUCP) and CU User Plane (CUUP). Once the nodes are configured, all user plane traffic flows through CUUP. @@ -77,11 +77,11 @@ sequenceDiagram ``` More details about the E1AP procedures in OAI are available in this document: [E1 Procedures](./e1ap_procedures.md). -# 2. Running the E1 Split +## 2. Running the E1 Split The setup is assuming that all modules are running on the same machine. The user can refer to the [F1 design document](./../F1AP/F1-design.md) for local deployment of the DU. -## 2.1 Configuration File +### 2.1 Configuration File The gNB is started based on the node type that is specified in the configuration file. The following parameters must be configured accordingly. @@ -130,9 +130,9 @@ The CUUP uses the IP address specified in `gNBs.[0].local_s_address` for F1-U an Alternatively, you can use the config files `ci-scripts/conf_files/gnb-cucp.sa.f1.conf` and `ci-scripts/conf_files/gnb-cuup.sa.f1.conf`. -## 2.2 Steps to Run the Split in rfsimulator with OAI UE +### 2.2 Steps to Run the Split in rfsimulator with OAI UE -Note: A 5G core must be running at this point. Steps to start the OAI 5G core can be found [in the oai-cn5g-fed repository](https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed/-/blob/master/docs/DEPLOY_HOME.md) or [here](NR_SA_CN5G_gNB_USRP_COTS_UE_Tutorial.md). +Note: A 5G core must be running at this point. Steps to start the OAI 5G core can be found [in the oai-cn5g-fed repository](https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-fed/-/blob/master/docs/DEPLOY_HOME.md) or [here](../NR_SA_Tutorial_OAI_CN5G.md). 0. Open wireshark to capture the E1AP messages. You might set the capture filter to `sctp` to limit the number of captured packages. @@ -165,7 +165,7 @@ OAI UE: sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --rfsimulator.serveraddr 127.0.0.1 ``` -# 3. Configuration file IP addresses of network functions +## 3. Configuration file IP addresses of network functions You can also run the nodes on different machines. If you do so please change the interface parameters accordingly and make sure the interfaces are reachable. Please refer to the following figure for an overview of all parameters. @@ -173,7 +173,7 @@ You can also run the nodes on different machines. If you do so please change the [PDF version](./images/e1-archi.pdf) | [LaTeX/TikZ version](./images/e1-archi.tex) if you want to modify to reflect your setup -# 4. Multiple CU-UP +## 4. Multiple CU-UP It is possible to connect multiple CU-UP to the same CU-CP. In the handler of the E1 Setup Request, the CU-CP verifies that the PLMN(s) (MCC, MNC) between @@ -195,6 +195,6 @@ that you have to restart the CU-CP if you want to connect the CU-UP again (e.g., after a crash). The CU-CP might also misfunction during attach if a CU-UP was connected, but disconnected in the meantime. -# 5. Abnormal conditions +## 5. Abnormal conditions * The CU-UP goes offline during normal operation (e.g. UEs have a valid PDU Session and are exchanging data on the UP): after restarting the CU-UP, the UP is not restored and the user will notice GTP errors. In this case the UEs have to reconnect. diff --git a/doc/F1AP/F1-design.md b/doc/F1AP/F1-design.md index 65ea6b38cf..5290426ea3 100644 --- a/doc/F1AP/F1-design.md +++ b/doc/F1AP/F1-design.md @@ -2,7 +2,7 @@ - + @@ -14,7 +14,7 @@ [[_TOC_]] -# Introduction +## Introduction The F1 interface is the functional split of 3GPP between the CU (centralized unit: PDCP, RRC, SDAP) and the DU (distributed unit: RLC, MAC, PHY). It is @@ -33,17 +33,17 @@ F1-U: No equivalent for 4G exists. -## Control plane (F1-C) +### Control plane (F1-C) The interface F1-C is designed for the exchange of signalling messages between the Radio Network Layer (RNL) and the Transport Network Layer (TNL). It consists of F1 Application Protocol messages (F1-AP) exchanged over SCTP. -## Data plane (F1-U) +### Data plane (F1-U) F1-U uses GTP-U for information exchange. -# OAI Implementation Status +## OAI Implementation Status The implementation of F1AP messages is seamlessly integrated into OAI, supporting both Monolithic SA and CU/DU functional split modes. The F1 code is therefore always compiled with nr-softmodem. @@ -63,13 +63,13 @@ This is the current status: - Not supported: * NSA -## F1-C +### F1-C -### F1AP messages +#### F1AP messages -Refer to [FEATURE_SET.md](FEATURE_SET.md#gNB-F1AP) to learn about the current F1AP implementation status. +Refer to [FEATURE_SET.md](../FEATURE_SET.md#gnb-f1ap) to learn about the current F1AP implementation status. -### High-level F1-C code structure +#### High-level F1-C code structure The F1 interface is used internally between CU (mostly RRC) and DU (mostly MAC) to exchange information. In DL, the CU sends messages as defined by the @@ -170,7 +170,7 @@ sequenceDiagram TASK_MAC_GNB->>+TASK_RRC_GNB: raw F1AP message (ITTI) ``` -## F1-U +### F1-U Current status: @@ -178,7 +178,7 @@ Current status: * Each packet is acknowledged individually * Support of multiple DUs per CU -# How to run +## How to run As mentioned earlier, OAI uses F1 internally. It is always compiled in. To start CU/DU, you use `./nr-softmodem` with the appropriate configuration @@ -190,7 +190,7 @@ sudo cmake_targets/ran_build/build/nr-softmodem -O ci-scripts/conf_files/gnb-du. ``` These files are tested in the CI, and are configured for use in docker, -see [this `docker-compose` file](../ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml). +see [this `docker-compose` file](../../ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml). The rules to decide if a config triggers a start of a DU, CU, or monolithic gNB, are, in order: @@ -200,7 +200,7 @@ gNB, are, in order: (`tr_s_preference`), it is a CU. 3. It is a (monolithic) gNB. -## F1 IP configuration for Local network deployment of F1 +### F1 IP configuration for Local network deployment of F1 The following paragraphs explain the IP configuration for F1 in the OAI config files on the example of a a local deployment. We assume that the CU will bind @@ -221,9 +221,7 @@ In the CU file: ignored, but we recommend to put `0.0.0.0` ("any") - Ports should match the ones in the DU config, but for simplicity and standards-conformity, simply set all to 2152: - - `local_s_portc` in CU should match `remote_n_portc` in DU - `local_s_portd` in CU should match `remote_n_portd` in DU - - `remote_s_portc` in CU should match `local_n_portc` in DU - `remote_s_portd` in CU should match `local_n_portd` in DU In the DU file: @@ -244,7 +242,7 @@ the options `MACRLCs.[0].local_n_address` and `MACRLCs.[0].local_n_address_f1u`, respectively. Note that this is not foreseen for the CU; in the case of the CU, please use separate CU-UP and CU-CP. -## Configuration of multiple DUs +### Configuration of multiple DUs Upon F1 Setup Request of a new DU, the CU cross-checks that @@ -262,9 +260,9 @@ You have to of course make sure that the local interface of the DU Assuming you use RFsim, you should make the RFsimulator server side (typically the gNB) bind on different hosts (`rfsimulator.serverport`). -# Code documentation +## Code documentation -## Common multi-threading architecture +### Common multi-threading architecture The CU and DU interfaces are based on ITTI threads (see `common/utils/ocp_itti/itti.md`) adopted by all OAI upper layers to run isolated threads dedicated to one feature. @@ -303,7 +301,7 @@ All GTP-U tunnels are managed in a Linux Thread, that have partially ITTI design 3. incoming packets are sent to the tunnel creator using a C callback (the callback function is given in tunnel creation order). The callback should not block -## F1-C messages towards the CU +### F1-C messages towards the CU The CU thread starts when the CU starts. It opens listening socket on the configuration-specified IP/port by sending the appropriate message to @@ -334,7 +332,7 @@ You might also want to consult TS 38.401 regarding the message exchange. | UE Context Release Request | `F1AP_UE_CONTEXT_RELEASE_REQ` | `rrc_CU_process_ue_context_release_request()` | RRC will trigger UE release | | UE Context Release Complete | `F1AP_UE_CONTEXT_RELEASE_COMPLETE` | `rrc_CU_process_ue_context_release_complete()` | frees UE Context, signals to NGAP | -## F1-C Messages towards the DU +### F1-C Messages towards the DU The task "gNB app", after reading the configuration file, sends a message `F1AP_DU_REGISTER_REQ` to the DU task. This message contains network @@ -373,9 +371,9 @@ You might also want to consult TS 38.401 regarding the message exchange. a reconfiguration has to be triggered if the CU receives a CellGroupConfig, originating at the DU. See also flag `expect_reconfiguration`. -## F1-U messages +### F1-U messages -### General +#### General In the DU in UL, RLC checks in `deliver_sdu()` if we are operating in split mode, and either (direct) calls `pdcp_data_ind` (DRB) or (f1ap) sends a GTP @@ -389,10 +387,10 @@ into the RLC via `enqueue_rlc_data_req()`, or (f1ap) sends a GTP message through the GTP API. In the DU in DL, assuming the GTP-U tunnel exists, GTP decapsulates the packet -and calls the reception call back `du_rlc_data_req()`, which calls -`enqueue_rlc_data_req()` in turn. +and calls the reception call back `nr_rlc_data_req()`, which enqueues the +packet into the UE's RLC buffer. -## Tunnel Setup +### Tunnel Setup In GTP-U, TS 29.281 specifies a optional header (NR RAN Container). This extension header may be transmitted in a G-PDU over the X2-U, Xn-U and F1-U user diff --git a/doc/F1AP/F1AP-lib.md b/doc/F1AP/F1AP-lib.md index 46712914ed..86db97ec8b 100644 --- a/doc/F1AP/F1AP-lib.md +++ b/doc/F1AP/F1AP-lib.md @@ -2,7 +2,7 @@ - + diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 3c7490d937..43b8367e3b 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -11,12 +11,12 @@ - FAPI (IF2) : specified by Small Cell Forum (open-nFAPI implementation) - IF1 : F1 in 3GPP Release 15 -![Functional Split Architecture](./oai_enb_func_split_arch.png) +![Functional Split Architecture](./images/oai_enb_func_split_arch.png) # OpenAirInterface Block Diagram # -![Block Diagram](./oai_enb_block_diagram.png) +![Block Diagram](./images/oai_enb_block_diagram.png) # OpenAirInterface 5G-NR Feature Set # @@ -25,7 +25,7 @@ The following features are valid for the gNB and the 5G-NR UE. * Static TDD - - Multi TDD pattern supported refer [TDD Configuration](NR_SA_Multi_TDD_Pattern.md) + - Multi TDD pattern supported refer [TDD Configuration](MAC/mac-usage.md) * Static FDD * Normal CP * Subcarrier spacings: 15 and 30kHz (FR1), 120kHz (FR2) @@ -139,6 +139,10 @@ These modes of operation are supported: - evaluation of CQI report - MAC scheduling of SR reception - Intra-frequency handover +- Inter-frequency handover + - Measurement gaps are automatically computed at the DU if the CU has neighbor information and the configured + neighbors include cells operating on different frequencies + - DUs must be synchronized with each other for the measurements to be properly performed - Initial support for RedCap - Scheduling of SIBs (2, 19) @@ -275,6 +279,7 @@ These modes of operation are supported: - DCI formats: 00, 10, 01 and 11 * Reception of NR-PDSCH (including Segmentation, LDPC decoding, rate de-matching, de-scrambling, de-modulation, RB de-mapping, etc). - PDSCH mapping type A and B + - Downlink resource allocation type 0 and 1 - DMRS configuration type 1 and 2 - Single and multiple DMRS symbols - PTRS support diff --git a/doc/L2NFAPI.md b/doc/L2NFAPI.md index d9f0ad0435..282e6eeedf 100644 --- a/doc/L2NFAPI.md +++ b/doc/L2NFAPI.md @@ -40,48 +40,7 @@ Normally it should be fine to run both executables on the same host using the `l **2022/03/08: Starting the `2022.w01` tag on the `develop` branch, the L2 nFAPI simulation is using a proxy.** -## 5G L2 nFAPI simulator - -**Note: L2 simulator does not work anymore.** - -### Download and Build the Proxy Server (from EpiSci) - -```bash -$ cd ~ -$ git clone https://github.com/EpiSci/oai-lte-5g-multi-ue-proxy.git -$ cd oai-lte-multi-ue-proxy -$ make -``` - -### Start Proxy Server -Set the number of UEs to connect to server as 1 and the mode is SA. -```bash -$ number_of_ues=1 -$ sudo -E ./build/proxy $number_of_ues --nr -``` - -### Start gNB -```bash -$ sudo -E ./nr-softmodem -O ../ci-scripts/conf_files/episci/proxy_rcc.band78.tm1.106PRB.nfapi.conf --nfapi VNF --noS1 --emulate-l1 -``` -### Start UE -```bash -$ sudo -E ./nr-uesoftmodem -O ../ci-scripts/conf_files/nrue.uicc.conf --nfapi STANDALONE_PNF --node-number 2 --emulate-l1 -``` ### EpiSci's Documentation A more detailed tutorial is available on the [EpiSci GitHub Repository](https://github.com/EpiSci/oai-lte-5g-multi-ue-proxy#readme). -This proxy allows to perform L2 nFAPI simulator for: - -* LTE -* 5G-NSA -* 5G-SA - -### L2 Simulator as Docker Containers - -There used to be docker deployment with L2sim that was run in the CI. Since L2 -simulator does not work anymore, it has been removed. However, you can see the -old `README.md` from tag `2024.w44` -[here](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/2024.w44/ci-scripts/yaml_files/5g_l2sim_tdd/README.md). -In the same directory is a `docker-compose.yaml` file that can be used to run -L2sim. +Since 5G code has been removed, this proxy allows to perform L2 nFAPI simulator for LTE only. diff --git a/doc/LDPC_OFFLOAD_SETUP.md b/doc/LDPC_OFFLOAD_SETUP.md new file mode 100644 index 0000000000..c7473fffe2 --- /dev/null +++ b/doc/LDPC_OFFLOAD_SETUP.md @@ -0,0 +1,344 @@ + + + + + +
+ + + + + + OAI LDPC offload (O-RAN AAL/DPDK BBDEV) +
+ +**Table of Contents** + +[[_TOC_]] + +This documentation describes the integration of LDPC coding for lookaside acceleration using O-RAN AAL/DPDK BBDEV in OAI, along with its usage. +For details on the implementation, please consult the [developer notes](../openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/README.md). + +# Requirements + +In principle, any lookaside LDPC accelerator supporting the O-RAN AAL/DPDK BBDEV should work. +However, the current implementation has only been validated for the Xilinx T2, Intel ACC100, and Intel ACC200 (VRB1). +Therefore, your mileage may vary when using other BBDEV devices as there may be some hardware-specific changes required -- contributions are welcome! + +## DPDK Version Requirements + +The following DPDK versions are supported: +- For the Xilinx T2 card, DPDK20.11+ is supported. +- As for the Intel ACC100/ACC200, only DPDK22.11+ is supported. + +## Tested Devices/ DPDK versions + +### Xilinx T2 + +- DPDK20.11.9*. +- DPDK22.11.7*. +> Note: FPGA bitstream image and the corresponding patch file (e.g., `ACCL_BBDEV_DPDK20.11.3_ldpc_3.1.918.patch` for DPDK20.11) from Accelercomm required. + +### Intel ACC100 + +- DPDK22.11.7*. +- DPDK23.11.3*. +- DPDK24.11.2. +> Note: [Patch]((https://github.com/DPDK/dpdk/commit/fdde63a1dfc129d0a510a831aa98253b36a2a1cd)) required for pre-DPDK24.11 versions when using the Intel ACC100. + +### Intel ACC200 (also known as VRB1) +- DPDK22.11.7. +- DPDK23.11.3. +- DPDK24.11.2. + +# System Setup +## DPDK installation + +> Important: +> - If you are using the Xilinx T2 card, you will need to apply the vendor-supplied patches before compiling DPDK. +> - If you are using the Intel ACC100, you will need to [patch](https://github.com/DPDK/dpdk/commit/fdde63a1dfc129d0a510a831aa98253b36a2a1cd) the ACC100's driver if you are using DPDK22.11 or DPDK23.11. + + +Refer to the guide [here](./ORAN_FHI7.2_Tutorial.md?ref_type=heads#dpdk-data-plane-development-kit) to install, and then validate your DPDK installation. + +
+ Notes on DPDK patching/installation for Xilinx T2. + +*Note: The following instructions apply to `ACCL_BBDEV_DPDK20.11.3_ldpc_3.1.918.patch`, compatible with DPDK 20.11.9. For older patches (e.g., `ACL_BBDEV_DPDK20.11.3_BL_1006_build_1105_dev_branch_MCT_optimisations_1106_physical_std.patch`), refer to the T2 documentation in `2023.w48`.* + +```bash +# Get DPDK source code +git clone https://github.com/DPDK/dpdk-stable.git ~/dpdk-stable +cd ~/dpdk-stable +git checkout v20.11.9 +git apply ~/ACL_BBDEV_DPDK20.11.3_ldpc_3.1.918.patch +``` +Replace `~/ACL_BBDEV_DPDK20.11.3_ldpc_3.1.918.patch` by patch file provided by +Accelercomm. + +If you would like to install DPDK to a custom directory, here is an example. +```bash +cd ~/dpdk-stable +# meson setup build +meson setup --prefix=/opt/dpdk-t2 build # for installation with non-default installation prefix +cd build +ninja +sudo ninja install +sudo ldconfig + +``` +
+ +## System configuration + +### Setting up Hugepages + +First, we must setup hugepages on the system. +In our setup, we setup 16 of the 1G hugepages. +Apart from 1G, 2MB hugepages works too, but make sure to allocate a sufficient number of them. + +``` +# sudo dpdk-hugepages.py -p 1G --setup 16G +``` + +### Locating the Accelerator + +Next, we check whether our system can detect our accelerator using `dpdk-devbind.py`. +You should see Baseband devices detected by DPDK, as follows: +``` +# sudo dpdk-devbind.py -s +... +Baseband devices using DPDK-compatible driver +============================================= +0000:f7:00.0 'Device 57c0' unused=vfio-pci +... +``` + +As you can see here, our Intel ACC200 has the address of `0000:f7:00.0`. +Depending on the accelerator you are using, the address may vary. + +### Loading VFIO-PCI and enabling SR-IOV +Following, make sure to load the `vfio-pci` kernel modules and ensure that SR-IOV is enabled. + +``` +# sudo modprobe vfio-pci enable_sriov=1 disable_idle_d3=1 +``` + +### Binding the Accelerator with `vfio-pci` + +Lastly, we bind our accelerator with the `vfio-pci` driver. +``` +# sudo dpdk-devbind.py --bind=vfio-pci 0000:f7:00.0 +``` + +> Note: For the Xilinx T2, we can use this device directly. +If you use an Intel vRAN accelerator, read on. + +### Additional Steps for Intel vRAN Accelerators + +> IMPORTANT NOTE: +> - Currently, we only support using the Virtual Functions (VFs) of the Intel vRAN accelerators, but not the Physical Function (PF). +> - One key advantage of using VFs is that this allows us to share the accelerator with other DU instances on the same machine, which is common in practice. + +If you are using an Intel vRAN accelerator, you will need to use the [pf_bb_config](https://github.com/intel/pf-bb-config) tool to configure the accelerator beforehand. + +#### pf_bb_config +For more details, please consult the `pf_bb_config` README. + +``` +# git clone https://github.com/intel/pf-bb-config +# cd ~/pf-bb-config +# ./build.sh +``` +This clones and builds the `pf_bb_config` binary. + +Next, we show an example for the Intel ACC200. +We use an existing configuration located at `./vrb1/vrb1_config_16vf.cfg`. + +Here, it is necessary to specify a VFIO token (in this case, we use the UUID `00112233-4455-6677-8899-aabbccddeeff`). +Note that in practice, a random UUID should be used. +``` +# sudo ./pf_bb_config VRB1 -v 00112233-4455-6677-8899-aabbccddeeff -c vrb1/vrb1_config_16vf.cfg +== pf_bb_config Version v25.01-0-g812e032 == +VRB1 PF [0000:f7:00.0] configuration complete! +Log file = /var/log/pf_bb_cfg_0000:f7:00.0.log +``` + +#### Creating VFs + +Finally, we create the VF(s) for our accelerator. +In this example, we only create one SR-IOV VF. +``` +# echo 1 | sudo tee /sys/bus/pci/devices/0000:f7:00.0/sriov_numvfs +``` + +If you encounter any error when creating the VF(s), e.g., `tee: '/sys/bus/pci/devices/0000:f7:00.0/sriov_numvfs': No such file or directory`, then try enabling SR-IOV again. +``` +# echo 1 | sudo tee /sys/module/vfio_pci/parameters/enable_sriov +``` + +After you have successfully created the VF, you should see an additional baseband device, in our case, it is `0000:f7:00.1`. +We will use this device with OAI later. +The newly created VF should also be using the same `vfio-pci` driver as the PF, if it is not, you will need to do a `dpdk-devbind.py` to bind it with `vfio-pci`. +``` +# sudo dpdk-devbind.py -s +... +Baseband devices using DPDK-compatible driver +============================================= +0000:f7:00.0 'Device 57c0' drv=vfio-pci unused= +0000:f7:00.1 'Device 57c0' drv=vfio-pci unused= +... +``` + +# Building OAI with ORAN-AAL +OTA deployment is precisely described in the following tutorial: +- [NR_SA_Tutorial_COTS_UE](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/NR_SA_Tutorial_COTS_UE.md) +Instead of section *3.2 Build OAI gNB* from the tutorial, run the following commands: + +```bash +# Get openairinterface5g source code +git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g +cd ~/openairinterface5g +git checkout develop + +# Install OAI dependencies +cd ~/openairinterface5g/cmake_targets +./build_oai -I + +# Build OAI gNB +cd ~/openairinterface5g +source oaienv +cd cmake_targets +./build_oai -w USRP --ninja --gNB -P --build-lib "ldpc_aal" -C +``` + +A shared object file `libldpc_aal.so` will be created during the compilation. +This object is conditionally compiled. +The selection of the library to compile is done using `--build-lib ldpc_aal`. + +> Note: The required DPDK poll mode driver has to be present on the host machine and required DPDK version has to be installed on the host, prior to building OAI. + +# O-RAN AAL DPDK EAL parameters +To configure O-RAN AAL/DPDK BBDEV, you can set the following parameters via the command line of PHY simulators or nr-softmodem: + +> Note: the group parameter name has been renamed from `nrLDPC_coding_t2` to +> `nrLDPC_coding_aal` to better reflect that it is a generic AAL accelerator +> card. + +- `nrLDPC_coding_aal.dpdk_dev` - **mandatory** parameter, specifies the PCI address of our accelerator. It must follow the format `WWWW:XX:YY.Z`. + +- `nrLDPC_coding_aal.dpdk_core_list` - **mandatory** parameter, specifies the CPU cores assigned to DPDK . +Ensure that the CPU cores specified in `nrLDPC_coding_aal.dpdk_core_list` are available and not used by other processes to avoid conflicts. + +- `nrLDPC_coding_aal.dpdk_prefix` - optional parameter, DPDK shared data file prefix, by default set to *b6*. + +- `nrLDPC_coding_aal.vfio_vf_token` - optional parameter, VFIO token set for the VF, if applicable. + +- `nrLDPC_coding_aal.num_harq_codeblock` - optional parameter, size of the HARQ buffer in terms of the number of 32kB blocks, by default set to *512* (maximum for the T2; as for the ACCs, this can be further increased). + +- `nrLDPC_coding_aal.is_t2` - optional parameter, set this to 1 when using the Xilinx T2 card. + +**Note:** These parameters can also be provided in a configuration file. +Example for the ACC200: +``` +nrLDPC_coding_aal : { + dpdk_dev : "0000:f7:00.1"; + dpdk_core_list : "14-15"; + vfio_vf_token: "00112233-4455-6677-8899-aabbccddeeff"; +}; + +loader : { + ldpc : { + shlibversion : "_aal"; + }; +}; +``` + +# Running OAI with O-RAN AAL + +In general, to offload of the channel coding to the LDPC accelerator, we use use the `--loader.ldpc.shlibversion _aal` option. +Reminder, if you are using the Xilinx T2 card, make sure to set `--nrLDPC_coding_aal.is_t2 1`. + +## 5G PHY simulators + +### nr_ulsim + +Example command: +```bash +cd ~/openairinterface5g +source oaienv +cd cmake_targets/ran_build/build +sudo ./nr_ulsim -n100 -s20 -m20 -r273 -R273 --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev 0000:f7:00.1 --nrLDPC_coding_aal.dpdk_core_list 0-1 --nrLDPC_coding_aal.vfio_vf_token 00112233-4455-6677-8899-aabbccddeeff +``` +### nr_dlsim + +Example command: +```bash +cd ~/openairinterface5g +source oaienv +cd cmake_targets/ran_build/build +sudo ./nr_dlsim -n300 -s30 -R 106 -e 27 --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev 0000:f7:00.1 --nrLDPC_coding_aal.dpdk_core_list 0-1 --nrLDPC_coding_aal.vfio_vf_token 00112233-4455-6677-8899-aabbccddeeff +``` + +## OTA test + +### Running OAI gNB with USRP B210/FHI72 + +When running the gNB **with FHI 7.2**, it is not necessary to provide the `--nrLDPC_coding_aal.dpdk_core_list` argument +since the core list specified for FHI 7.2 will be used for DPDK. +If it is provided, the AAL core list wil be ignored. + +Example command: +```bash +cd ~/openairinterface5g +source oaienv +cd cmake_targets/ran_build/build +sudo ./nr-softmodem -O ~/gnb.conf --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev 0000:f7:00.1 --nrLDPC_coding_aal.dpdk_core_list 14-15 --nrLDPC_coding_aal.vfio_vf_token 00112233-4455-6677-8899-aabbccddeeff +``` + +# Known Issue(s) + +## Potential Low Throughput + +The current implementation has been tested to work in an end-to-end setup and is functional. +However, depending on the accelerator in use, +there are still opportunities for optimization, particularly in LDPC decoding performance, which is an area of ongoing improvement. +As such, downlink/uplink throughput may be suboptimal with the default configurations, but enhancements are actively being explored. + +For example, to achieve better E2E performance with the current implementation with Intel ACC 100 and 200 (vRAN Boost), +we recommend the following adjustments: +1. Increasing the number of LDPC decoding iterations of the L1, e.g., `max_ldpc_iterations` to 200. +2. Increasing the BLER targets of the MAC scheduler. + +Example configuration snippet: +``` +... +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 180; + pucch_TargetSNRx10 = 220; + dl_bler_target_upper = .35; + dl_bler_target_lower = .15; + ul_bler_target_upper = .35; + ul_bler_target_lower = .15; + pusch_FailureThres = 1000; + ul_max_mcs = 28; + +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 100; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 + max_ldpc_iterations = 200; +} +); +... +``` diff --git a/doc/LDPC_T2_OFFLOAD_SETUP.md b/doc/LDPC_T2_OFFLOAD_SETUP.md deleted file mode 100644 index 24d36e39cf..0000000000 --- a/doc/LDPC_T2_OFFLOAD_SETUP.md +++ /dev/null @@ -1,158 +0,0 @@ - - - - - -
- - - - - - OAI T1/T2 LDPC offload -
- -**Table of Contents** - -[[_TOC_]] - -This documentation aims to provide a tutorial for AMD Xilinx T2 Telco card integration into OAI and its usage. - -# Requirements - - - bitstream image and PMD driver for the T2 card provided by AccelerComm - - DPDK 20.11.9 with patch from Accelercomm: version ACCL_BBDEV_DPDK20.11.3_ldpc_3.1.918.patch - - tested on RHEL7.9, RHEL9.2, Ubuntu 22.04 - -# DPDK setup -## DPDK installation -*Note: Following instructions are valid for ACCL_BBDEV_DPDK20.11.3_ldpc_3.1.918.patch version, which is compatible with DPDK 20.11.9. Installation steps, which should be followed for older versions of the patch file (for example ACL_BBDEV_DPDK20.11.3_BL_1006_build_1105_dev_branch_MCT_optimisations_1106_physical_std.patch) are present in older version of this documentation, under the tag 2023.w48.* - -``` -# Get DPDK source code -git clone https://github.com/DPDK/dpdk-stable.git ~/dpdk-stable -cd ~/dpdk-stable -git checkout v20.11.9 -git apply ~/ACL_BBDEV_DPDK20.11.3_ldpc_3.1.918.patch -``` -Replace `~/ACL_BBDEV_DPDK20.11.3_ldpc_3.1.918.patch` by patch file provided by -Accelercomm. -``` -cd ~/dpdk-stable -meson setup build -# meson setup --prefix=/opt/dpdk-t2 build for installation with non-default installation prefix -cd build -ninja -sudo ninja install -sudo ldconfig -``` -## DPDK configuration - - load required kernel module -``` -sudo modprobe vfio-pci -``` - - check presence of the card and its PCI addres on the host machine -``` -lspci | grep "Xilinx" -``` - - bind the card with vfio-pci driver -``` -sudo python3 ~/dpdk-stable/usertools/dpdk-devbind.py --bind=vfio-pci 41:00.0 -``` -Replace PCI address of the card *41:00.0* by address detected by *lspci | grep "Xilinx"* command - - hugepages setup (10 x 1GB hugepages) -``` -sudo python3 ~/dpdk-stable/usertools/dpdk-hugepages.py -p 1G --setup 10G -``` - -*Note: device binding and hugepages setup has to be done after every reboot of -the host machine* - -# Modifications in the OAI code -## DPDK lib and PMD path specification -If DPDK library was installed into custom path, you have to point to the right directory with `PKG_CONFIG_PATH`, prior to the OAI build. Sample command to set the DPDK path to `/opt/dpdk-t2/lib64/pkgconfig/`: -``` -export PKG_CONFIG_PATH=/opt/dpdk-t2/lib64/pkgconfig/:$PKG_CONFIG_PATH -``` - -# OAI Build -OTA deployment is precisely described in the following tutorial: -- [NR_SA_Tutorial_COTS_UE](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/NR_SA_Tutorial_COTS_UE.md) -Instead of section *3.2 Build OAI gNB* from the tutorial, run following commands: - -``` -# Get openairinterface5g source code -git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git ~/openairinterface5g -cd ~/openairinterface5g -git checkout develop - -# Install OAI dependencies -cd ~/openairinterface5g/cmake_targets -./build_oai -I - -# Build OAI gNB -cd ~/openairinterface5g -source oaienv -cd cmake_targets -./build_oai -w USRP --ninja --gNB -P --build-lib "ldpc_t2" -C -``` - -Shared object file *libldpc_t2.so* is created during the compilation. This object is conditionally compiled. Selection of the library to compile is done using *--build-lib ldpc_t2*. - -*Required poll mode driver has to be present on the host machine and required DPDK version has to be installed on the host, prior to the build of OAI* - -# Setup of T2-related DPDK EAL parameters -To configure T2-related DPDK Environment Abstraction Layer (EAL) parameters, you can set the following parameters via the command line of PHY simulators or softmodem: -- `nrLDPC_coding_t2.dpdk_dev` - **mandatory** parameter, specifies PCI address of the T2 card. PCI address of the T2 card can be detected by `lspci | grep "Xilinx"` command. -- `nrLDPC_coding_t2.dpdk_core_list` - **mandatory** parameter, specifies CPU cores assigned to DPDK for T2 processing. Ensure that the CPU cores specified in *nrLDPC_coding_t2.dpdk_core_list* are available and not used by other processes to avoid conflicts. -- `nrLDPC_coding_t2.dpdk_prefix` - DPDK shared data file prefix, by default set to *b6*. - -**Note:** These parameters can also be provided in a configuration file: -``` -nrLDPC_coding_t2 : { - dpdk_dev : "41:00.0"; - dpdk_core_list : "14-15"; -}; - -loader : { - ldpc : { - shlibversion : "_t2"; - }; -}; -``` - -# 5G PHY simulators - -## nr_ulsim test -Offload of the channel decoding to the T2 card is in nr_ulsim specified by *--loader.ldpc.shlibversion _t2* option. Example command for running nr_ulsim with LDPC decoding offload to the T2 card: -``` -cd ~/openairinterface5g -source oaienv -cd cmake_targets/ran_build/build -sudo ./nr_ulsim -n100 -s20 -m20 -r273 -R273 --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1 -``` -## nr_dlsim test -Offload of the channel encoding to the AMD Xilinx T2 card is in nr_dlsim specified by *-c* option. Example command for running nr_dlsim with LDPC encoding offload to the T2 card: -``` -cd ~/openairinterface5g -source oaienv -cd cmake_targets/ran_build/build -sudo ./nr_dlsim -n300 -s30 -R 106 -e 27 --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1 -``` - -# OTA test -Offload of the channel encoding and decoding to the AMD Xilinx T2 card is enabled by *--loader.ldpc.shlibversion _t2* option. - -## Run OAI gNB with USRP B210 -``` -cd ~/openairinterface5g -source oaienv -cd cmake_targets/ran_build/build -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1 -``` - -# Limitations -## AMD Xilinx T2 card - - functionality of the LDPC encoding and decoding offload verified in OTA SISO setup with USRP N310 and Quectel RM500Q, blocking of the card reported for MIMO setup (2 layers) - -*Note: AMD Xilinx T1 Telco card is not supported anymore.* diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index ae4f3a626b..f4583b7a23 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -38,7 +38,7 @@ The actual scheduler implementation can be found in functions `pf_dl()` and [`gNB_scheduler_ulsch.c`](../../openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c) (for UL), respectively. -## PDDCH aggregation level +## PDCCH aggregation level PDCCH aggregation level is selected using closed loop controller, where DL HARQ feedback is the controller feedback signal. It is used to increment `pdcch_cl_adjust` @@ -49,16 +49,18 @@ The value of `pdcch_cl_adjust` is clamped to range <0,1>, the increment value is the decrement value is 0.01. These values are selected to ensure PDCCH success rate is high. See Examples below for futher explaination. -The possible values of aggregation level on UE SS can be configured via `uess_agg_levels` configuration -option. By default the gNB uses only aggregation level 2 which translates to `uess_agg_levels` set to -`[0, 1, 0, 0, 0]`. For example, to enable aggregation level 2 and 4 set `uess_agg_levels` to `[0, 1, 1, 0, 0]`. +The possible values of aggregation level on UE SS can be configured via +`uess_agg_levels` configuration option. By default the gNB uses two candidates +in aggregation level 2 which translates to `uess_agg_levels` set to `[0, 2, 0, +0, 0]`. For example, to enable one candidate on aggregation levels 2 and 4 set +`uess_agg_levels` to `[0, 1, 1, 0, 0]`. ### Examples: #### Example 1: Say we have 90% PDCCH success rate at aggregation level 1, `pdcch_cl_adjust` will stay at 0 for most of the time. 2 consecutive PDCCH failures will not result in increasing the aggregation level (because (0.05 + 0.05) * 4 = 0.4 which is closer to 0 than to 1). If PDCCH fails 3 times -in a row the aggregation level will change to 2 and hopefully back to 1 once more PDDCH successes +in a row the aggregation level will change to 2 and hopefully back to 1 once more PDCCH successes happen. ### Example 2 @@ -76,11 +78,11 @@ available in the the file `nrMAC-stats.log` in the same directory in which Example: ``` -UE RNTI 2460 CU-UE-ID 2 in-sync PH 28 dB PCMAX 24 dBm, average RSRP -74 (8 meas) +UE RNTI 2460 CU-UE-ID 2 in-sync PH 28 dB PCMAX 24 dBm, average RSRP -74 (8 meas), average SINR 40.0 (32 meas) UE 2460: CQI 15, RI 2, PMI (14,1) UE 2460: UL-RI 2 TPMI 0 -UE 2460: dlsch_rounds 32917/5113/1504/560, dlsch_errors 211, pucch0_DTX 1385, BLER 0.19557 MCS (1) 23 -UE 2460: ulsch_rounds 3756/353/182/179, ulsch_errors 170, ulsch_DTX 285, BLER 0.33021 MCS (1) 27 (Qm 8 dB) NPRB 5 SNR 31.0 dB +UE 2460: dlsch_rounds 32917/5113/1504/560, dlsch_errors 211, pucch0_DTX 1385, BLER 0.19557 MCS (1) 23 CCE fail 3 +UE 2460: ulsch_rounds 3756/353/182/179, ulsch_errors 170, ulsch_DTX 285, BLER 0.33021 MCS (1) 27 (Qm 8 dB) NPRB 5 SNR 31.0 dB CCE fail 0 UE 2460: MAC: TX 1530943191 RX 194148 bytes UE 2460: LCID 1: TX 651 RX 3031 bytes UE 2460: LCID 2: TX 0 RX 0 bytes @@ -101,6 +103,8 @@ In the first line, * `RSRP` (`-74`): measured power of the DL reference signals at the UE. >-80dBm you should have full DL throughput. <-95 dBm, you are very limited in terms of connectivity. +* `SINR` (`40.0`): measured signal to interference and noise ratio of the SSB + received at the UE. Maximum value that can be reported by the UE is 40.0 dB. The second and third line reflect channel state information (CSI) as reported by the UE, and only appear if CSI-RS/SRS are enabled and _received_ @@ -159,6 +163,9 @@ The fourth and fifth line show HARQ-related information: should be close to the target in the gNB configuration file, `pusch_TargetSNRx10`, which should be around 10 times the value shown in the log +* Both ULSCH/DLSCH `CCE fail`: lists the number of failed CCE attempts. If this + number gets high, it signifies that the scheduler tried to scheduled this UE, + but could not allocate the DCI. In the last lines: * `MAC` shows the amount of MAC PDU bytes scheduled in transmit (`TX`, @@ -176,7 +183,7 @@ See [nFAPI documentation](../nfapi.md) or [Aerial tutorial](../Aerial_FAPI_Split_Tutorial.md) for information about the (n)FAPI split. -See [F1 documentation](../F1-design.md) for information about the F1 split. +See [F1 documentation](../F1AP/F1-design.md) for information about the F1 split. ## MAC scheduler-related configuration options @@ -205,17 +212,17 @@ In the `MACRLCs` section of the gNB/DU configuration file: retransmission over initial transmission) to decrease MCS by 1 * `dl_bler_target_lower` (default 0.05): lower threshold of BLER (first round retransmission over initial transmission) to increase MCS by 1 -* `dl_max_mcs` (default 28): maximum MCS to use +* `dl_min_mcs` (default 0): minimum MCS to use for any UE +* `dl_max_mcs` (default 28): maximum MCS to use for any UE * `ul_bler_target_upper` (default 0.15): as `dl_bler_target_upper` * `ul_bler_target_lower` (default 0.05): as `dl_bler_target_lower` +* `ul_min_mcs` (default 0): as `dl_min_mcs` * `ul_max_mcs` (default 28): as `dl_max_mcs` * `dl_harq_round_max` (default 4): maximum number of HARQ rounds, i.e., retransmissions to perform, in DL * `ul_harq_round_max` (default 4): as `dl_harq_round_max` * `min_grant_prb` (default 5): number of PRBs to schedule for UE after activity (see `ulsch_max_frame_inactivity`) or after scheduling request (SR) -* `min_grant_mcs` (default 9): MCS to use for UE after activity (see - `ulsch_max_frame_inactivity`) or after scheduling request (SR) * `identity_precoding_matrix` (default 0=false): flag to enable to use only the identity precoding matrix in DL precoding * `set_analog_beamforming` (default 0=false): flag to enable analog @@ -397,3 +404,13 @@ pattern2: { nrofUplinkSymbols2 = 0; }; ``` + +#### UL-heavy TDD patterns + +"UL-heavy TDD patterns", i.e., TDD patterns that have many UL slots are +supported. Examples for such patterns would be DSUUU or DDDSUUUUUU. + +Note that you should increase the aggregation level candidates as described in +[the corresponding section above](#pdcch-aggregation-level). This is because the +scheduler has to schedule multiple DCIs in a single DL slots for multiple UL +slots. As a suggestion, you could try `uess_agg_levels = [4, 2, 2, 0, 0]`. diff --git a/doc/NR_NFAPI_archi.md b/doc/NR_NFAPI_archi.md index 59c511fb52..8065ddb4fc 100644 --- a/doc/NR_NFAPI_archi.md +++ b/doc/NR_NFAPI_archi.md @@ -1,53 +1,90 @@ -# global +This document describes the broad way in which the VNF and PNF work internally, +from configuration, to P5 and P7 message exchange and processing. +Their internal processing is broadly independent on which transport mechanism +is responsible for exchanging data between the 2 components. -xnf is pnf or vnf +To read more about the transport mechanisms available, and how to run the split, please refer to +[this file](./nfapi.md). -The xnf starting functions are configure_nfapi_xnf() +[[_TOC_]] -The OAI code that read the configuration parameters call these functions that will create autonomous thread for xnf control part +# VNF/PNF Split -These control threads create a SCTP socket by Linux API call (no use of OpenAir internal architecture with SCTP itti thread). +The gNB is split into VNF(L2+) and PNF(L1) -The main() function of softmodem has to create and start the other threads+loop on event for appropriate work: RF Rx in pnf, NGAP, GTP-U, X2, RLC, PDCP for vnf +These component are configured via the functions: -NFAPI has it's own code directly on Linux+Posix, it doesn't reuse any piece of the OpenAir framework: SCTP thread, thread creation and management, ... +- configure_nr_nfapi_vnf() +- configure_nr_nfapi_pnf() -## signaling (P5) xnf main loop +These functions initialize the configuration appropriate for the transport mechanism selected ( setting the +pack/unpack function pointers, as well as the appropriate send functions ) -nfapi_vnf_start() create the SCTP socket, then do event waiting in a infinite loop while(vnf->terminate == 0). It accepts the pnf connections, then process the messages on reception +After this, a thread is created for the P5 receive loop, which initializes the transport and receive loop -nfapi_pnf_start() initiate connection to vnf until it has a link. Then it enter a similar infinite loop in pnf_message_pump() +This created thread may be only for P5 messages, or P5 and P7, depending on the transport type -After some checks, when a message is obtained, it calls pnf_handle_p5_message() or vnf_handle_p4_p5_message() that have a switch on each p5 message types: the enum nfapi_message_id_e +- When using socket-based communication (which uses nFAPI encoding), the receiving loop for P7 messages is separate from + P5, it starts upon the PNF_START exchange +- In the other transport mechanisms (WLS and nvIPC, which use FAPI encoding), the receiving loop is the same for P5 and + P7 messages, the P7 configuration is done immediately after the P5 configuration. + +Since the first P7 messages is only sent/received after the START exchange, we can logically treat the loops as separate +, we won't receive P7 messages before finishing the P5 ones ( except for the STOP exchange ) + +## P5 interface main loop + +After the P5 configuration, both the VNF and PNF have a thread waiting to "consume" (n)FAPI messages exchanged between +them + +Upon the reception of a message (whether in its entirety or segmented in the case of nFAPI), the messages are sent to +the appropriate handler: + +- pnf_nr_handle_p5_message +- vnf_nr_handle_p4_p5_message + +In each of these functions, there's a switch calling the appropriate handler according to the message ID, for example: -Each message type has it's own processing function in the switch, like ``` -case NFAPI_START_RESPONSE: - vnf_handle_start_response(pRecvMsg, recvMsgLen, config, p5_idx); - break; +case NFAPI_NR_PHY_MSG_TYPE_START_RESPONSE: + vnf_nr_handle_start_response(pRecvMsg, recvMsgLen, config, p5_idx); + break; ``` These loops are autonomous in their thread waiting incoming message. -## P7 xnf main loop +## P7 interface main loop -When the p5 interface receives appropriate message, it starts the p7 interface by launching a thread (see the calls to pthread_create() in nfapi/oai_integration/nfapi_xnf.c) +- Note: As explained before, the P7 reception loop is the same as the P5 messages when not using socket-based + communication -The p7 main loops starting is a bit simpler, thanks to UDP non connected protocol. The xnf_dispatch_p7_message() do p7 fragments re-assembly, then -calls xnf_dispatch_p7_message() that have the big switch on message type (as in p5 above description) +In this case, when the P5 interface receives appropriate message, it starts the p7 interface by launching a thread -So, we have the logic for UL reception in vnf, and DL reception in pnf +- On the PNF, this is done in the START.request handler ( nr_start_request(...) ) +- On the VNF, this is done in ( configure_nr_p7_vnf(...) ) + +Much in the same way as when processing P5 messages, the following functions are called to unpack and process them: + +- pnf_nr_handle_p7_message +- vnf_nr_handle_p7_message + +``` +case NFAPI_NR_PHY_MSG_TYPE_SLOT_INDICATION: + vnf_handle_nr_slot_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; +``` ## P7 UL transmission by PNF -RF samples are received, and decoding is done by the PNF using control data transmitted by the VNF to the PNF through downlink p7 messages (UL_TTI_req and UL_DCI_req). +RF samples are received, and decoding is done by the PNF using control data transmitted by the VNF to the PNF through +downlink p7 messages (UL_TTI.request and UL_DCI.request). -After decoding, results are accumulated into the xNB->UL_INFO structure at the PNF. +After decoding, results are accumulated into the gNB->UL_INFO structure at the PNF. -The data in the UL_INFO struct is transmitted through a socket in the form of 'uplink indication functions' from the PNF to the VNF. Each uplink indication message is transmitted from their respective handle functions in NR_UL_indication(). For example, +The data in the UL_INFO struct is transmitted through the configured send function pointer (send_p7_msg), which packs +the message into a buffer according to the encoding and sends it to the VNF ``` - void handle_nr_rach(NR_UL_IND_t *UL_info) { if(NFAPI_MODE == NFAPI_MODE_PNF) { if (UL_info->rach_ind.number_of_pdus>0) { @@ -56,67 +93,186 @@ void handle_nr_rach(NR_UL_IND_t *UL_info) { } } -``` +.... -## P7 UL reception at VNF +int oai_nfapi_nr_rach_indication(nfapi_nr_rach_indication_t *ind) { + ind->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!! + ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION; + return nfapi_pnf_p7_nr_rach_ind(p7_config_g, ind); +} -Through the infinite loop [while(vnf_p7->terminate == 0)] running in nfapi_nr_vnf_p7_start(), the VNF receives and unpacks the uplink indication message received on its socket. Based on the unpacked messages, UL_INFO struct on the VNF side gets populated. +..... -``` - -// have a p7 message - if(FD_ISSET(vnf_p7->socket, &rfds)) - { - vnf_nr_p7_read_dispatch_message(vnf_p7); - } - -``` - -vnf_nr_dispatch_p7_message() is the function that contains the switch on various message headers so that the appropriate unpack function is called. - -## P7 DL Transmission by VNF - -DL messages are scheduled at the VNF, through NR_UL_indication(). NR_UL_indication() is called when the SFN/slot in the UL_info structure changes (this acts as a trigger for next slot processing, instead of running a separate clock at the VNF). The SFN/slot at the VNF in UL_info is updated using the slot_indication uplink p7 message, which is sent at the beginning of every slot by the PNF. The slot_indication message contains SFN/slot of the TX_thread, so that the scheduler operates slot_ahead slots ahead of the RX thread. This ensures that UL_tti_req is received before RX slot processing at the PNF. - -The function NR_schedule_response calls oai_nfapi_[DL P7 msg]_req(), which contains the routines for packing + transmission of scheduled messages through the socket to the PNF. For example, to send the 'TX_data_req' p7 message - -``` - -if (Sched_INFO->TX_req->Number_of_PDUs > 0) +int nfapi_pnf_p7_nr_rach_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_rach_indication_t* ind) { - oai_nfapi_tx_data_req(Sched_INFO->TX_req); + if(config == NULL || ind == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: invalid input params\n", __FUNCTION__); + return -1; + } + + pnf_p7_t* _this = (pnf_p7_t*)(config); + AssertFatal(_this->_public.send_p7_msg, "Function pointer must be configured|"); + return _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_rach_indication_t)); } ``` +## P7 UL reception at VNF + +Through the P7 reception loop, the VNF receives a buffer containing the messages, which it handles by the following +process: + +- Unpack the header by use of the hdr_unpack_func function pointer +- According to the Message ID in the header, send the buffer to the appropriate handler by use of a switch statement: + +``` + case NFAPI_NR_PHY_MSG_TYPE_SLOT_INDICATION: + vnf_handle_nr_slot_indication(pRecvMsg, recvMsgLen, vnf_p7); + break; + +``` + +- In the handler function, unpack the entire message, by using the unpack_func function pointer. +- If the unpack procedure is successful, call the previously configure callback for that message type: + +``` + nfapi_nr_slot_indication_scf_t ind = {0}; + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config); + if(!result) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "%s: Handling NR SLOT Indication\n", __FUNCTION__); + if(vnf_p7->_public.nr_slot_indication) + { + (vnf_p7->_public.nr_slot_indication)(&ind); + } + free_slot_indication(&ind); + } + +``` + +vnf_nr_dispatch_p7_message() is the function that contains the switch on various message headers so that the appropriate +unpack function is called. + +## P7 DL Transmission by VNF + +DL messages are scheduled at the VNF, through gNB_dlsch_ulsch_scheduler(). gNB_dlsch_ulsch_scheduler() is called when +handling a SLOT.indication message in trigger_scheduler(). + +The function trigger_scheduler(nfapi_nr_slot_indication_scf_t *slot_ind) calls the functions oai_nfapi_[DL P7 msg]_ +req(), calling in turn call the send_p7_msg function pointer, which contain the logic to pack the message into a buffer +and send it to the PNF. +Finally, NR_UL_indication is called to process the other P7 messages received from the PNF that were put in theire +respective queues. +For example, the TX_DATA.request message is sent in the following manner: + +``` + if (g_sched_resp.TX_req.Number_of_PDUs > 0) + oai_nfapi_tx_data_req(&g_sched_resp.TX_req); + +... + +int oai_nfapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req) +{ + LOG_D(NR_PHY, "Entering oai_nfapi_nr_tx_data_req sfn:%d,slot:%d\n", tx_data_req->SFN, tx_data_req->Slot); + nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config; + tx_data_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!! + tx_data_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST; + //LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_req->sfn_sf), tx_req->tx_request_body.number_of_pdus); + bool retval = nfapi_vnf_p7_tx_data_req(p7_config, tx_data_req); + + if (!retval) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + tx_data_req->Number_of_PDUs = 0; + } + + return retval; +} + +... + +bool nfapi_vnf_p7_tx_data_req(nfapi_vnf_p7_config_t* config, nfapi_nr_tx_data_request_t* req) +{ + if(config == 0 || req == 0) + return -1; + + vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; + AssertFatal(config->send_p7_msg, "Function pointer must be configured|"); + return config->send_p7_msg(vnf_p7, &req->header); +} + +``` + +## VNF functional flowchart + ```mermaid graph TD - pselect[VNF socket pselect] -- timed out : end of slot --> call_sched[Call Scheduler NR_UL_indication] -- oai_nfapi_***_req sends the DL p7 msg--> slot_inc[Increment sfn/slot]; - pselect[VNF socket pselect] -- UL p7 xyz msg recvd --> msg_recvd[Read message vnf_nr_p7_read_dispatch_message] --> header_unpack[Unpack Header] -- switch cases on header --> unpack_msg[Handle Message vnf_handle_nr_xyz] --> fill_ul_info[Fill UL info struct with fn pointer vnf_p7->_public.nr_rx_xyz]; - fill_ul_info -- update pselect_timeout: next_slot_start - time_xyz_msg_recvd-->pselect; - slot_inc -- next slot --> pselect + softmodem_start[nr-softmodem init] --> P5_configuration[configure_nr_nfapi_vnf] --> transport_init[Transport mechanism init] --> send_first_msg[Send first P5 message to PNF] + transport_init[Transport mechanism init] --> P5_recv_loop[P5 receive loop] -- P5 Message processing --> P5_recv_loop[P5 receive loop] + P5_recv_loop[P5 receive loop] -- Start.response callback called --> P7_config[P7 Configuration] --> P7_loop[P7 Loop] --> P7_msg_recv[P7 message received] --> call_vnf_handle_p7[Call vnf_nr_handle_p7_msg] --> hdr_unpack[Unpack header] --> call_specific_p7_handler[Call specific P7 message handler] --> slot_ind[Is a SLOT.indication?] -- Yes --> trig_scheduler[Call trigger_scheduler] --> gNB_ulsch_dlsch_sched[Call gNB_dlsch_ulsch_scheduler] --> send_p7_dl[Process and send P7 messages to PNF] --> call_ul_ind[Call NR_UL_indication] --> proc_p7[Process P7 messages in queue] --> P7_loop[P7 Loop] + slot_ind[Is a SLOT.indication?] -- No --> put_queue[Put message in queue] --> P7_loop[P7 Loop]; + ``` -Note that since DL P7 message reception and TX/RX processing are done on separate threads, there is the issue of the L1 processing threads trying to do their job before the required P7 message is received. In the case of RX processing, since the scheduler operates slot_ahead slots ahead of the RX thread, the required messages conveniently arrive earlier than they are required. However, in the case of TX processing, this cannot be ensured if the scheduler is exactly in sync with the TX thread. -Therefore, we operate the VNF vnf_slot_ahead (which is currently 2) slots ahead of the PNF. This is to ensure that the DL fapi structures for a particular TX slot are all received before TX processing for that slot. +## P7 DL Reception at PNF -## P7 DL Reception at PNF +Through the infinite loop [while(pnf_p7->terminate == 0)] running in pnf_nr_p7_message_pump(), the PNF receives and +unpacks the downlink P7 message received on its socket. Based on the unpacked message, the appropriate message +structures are filled in the PNF, and these are used further down the pipeline for processing. +Through the P7 reception loop, the PNF receives a buffer containing a P7 message from the VNF, which it processes the +following way: -Through the infinite loop [while(pnf_p7->terminate == 0)] running in pnf_nr_p7_message_pump(), the PNF receives and unpacks the downlink P7 message received on its socket. Based on the unpacked message, the appropriate message structures are filled in the PNF, and these are used further down the pipeline for processing. +- Unpack the header by use of the hdr_unpack_func function pointer +- According to the Message ID in the header, send the buffer to the appropriate handler by use of a switch statement: -While receiving the DL P7 message, we check whether the message was received within a timing window from which it was sent. The duration of the window can be set by the user (set as a parameter for xnf in the p5 messages). Note that the DL information must be received by the PNF within a timing window at least lesser than the duration of slot_ahead variable (timing_window <= slot_ahead * slot_duration). +``` + case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST: + pnf_handle_dl_tti_request(pRecvMsg, recvMsgLen, pnf_p7); + break; +``` + +- In the handler function, the SFN and Slot are peeked from the message +- The SFN and slot are checked to determine if the message is inside the appropriate timing window +- If so, the message is unpacked into the P7 Slot buffer: + +``` + pnf_p7->slot_buffer[buffer_index].sfn = frame; + pnf_p7->slot_buffer[buffer_index].slot = slot; + nfapi_nr_dl_tti_request_t *req = &pnf_p7->slot_buffer[buffer_index].dl_tti_req; + pnf_p7->nr_stats.dl_tti.ontime++; + + NFAPI_TRACE(NFAPI_TRACE_DEBUG, + "POPULATE DL_TTI_REQ current tx sfn/slot:%d.%d p7 msg sfn/slot: %d.%d buffer_index:%d\n", + pnf_p7->sfn, + pnf_p7->slot, + frame, + slot, + buffer_index); + const bool result = pnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, req, sizeof(*req), &(pnf_p7->_public.codec_config)); + + ``` + +- The messages are later processed in the NR_slot_indication function, which is called in the tx_func function ( + L1_tx_thread ) + +## PNF functional flowchart ```mermaid -graph TB - pselect[PNF socket pselect] -- timed out : end of slot --> slot_inc[Increment sfn/slot]; - pselect[PNF socket pselect] -- DL p7 xyz msg recvd --> msg_recvd[Read message pnf_nr_nfapi_p7_read_dispatch_message] --> header_unpack[Unpack Header] -- switch cases on header --> unpack_msg[Unpack Message pnf_handle_nr_xyz] --> fill_pnf_p7[Fill pnf_p7 global structure pnf_handle_nr_xyz] --Data from pnf_p7 struct copied to fapi structures using pnf_phy_***_req. Called every slot from handle_nr_slot_ind-->pselect; - - slot_inc -- next slot --> pselect +graph TD + softmodem_start[nr-softmodem init] --> init_l1_tx_thread[Init L1 TX Thread] --> tx_func[Call tx_func] --> nr_slot_ind[Call NR_slot_indication] --> pnf_slot_ind[Call handle_nr_slot_ind] --> send_slot_ind[Send SLOT.ind to VNF] --> get_from_slot_buffer[Get P7 messages from slot_buffer] --> proc_p7_dl[Process P7 messages from VNF] --> tx_func + softmodem_start[nr-softmodem init] --> init_l1_rx_thread[Init L1 RX Thread] --> rx_func[Call rx_func] --> nr_ul_ind[Call NR_UL_indication] --> send_p7_vnf[Send P7 messages to VNF] --> rx_func + softmodem_start[nr-softmodem init] --> P5_configuration[configure_nr_nfapi_pnf] --> transport_init[Transport mechanism init] --> p5_loop[P5 Loop] -- Process P5 messages --> p5_loop + p5_loop -- START.request callback called --> p7_config[P7 Configuration] --> l1_north_init_gnb[Call l1_north_init_gNB] --> nr_if_module_init[Call NR_IF_Module_Init] --> install_slot_ind_cb[Install NR_slot_indication callback] + p7_config[P7 Configuration] --> p7_loop[P7 Loop] --> p7_recv[Receive P7 message] --> pnf_handle_p7[Call pnf_nr_handle_p7_message] --> hdr_unpack[Unpack header with hdr_unpack] --> p7_handler[Call pnf_handle_] --> peek_sfn[Peek SFN/Slot and check if in timing window] --> p7_unpack[Unpack message into slot_buffer] --> p7_loop ``` -Once the messages are received, they are filled into slot buffers, and are stored until the processing of the slot that they were meant for. diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md index 7aff02f9df..1d7169f29f 100644 --- a/doc/ORAN_FHI7.2_Tutorial.md +++ b/doc/ORAN_FHI7.2_Tutorial.md @@ -1235,7 +1235,13 @@ You should be able to connect a UE now. # OAI Management Plane -We support Configuration Management in OAI gNB, where gNB configures CU-planes, interfaces, TX/RX antennas, and TX/RX carriers for the RU. +In OAI gNB, we support: +* Configuration Management: interface(s) creation, configuration of RU CU-planes, Tx/Rx antennas, and Tx/Rx carriers. +* Performance Management: activation/deactivation of available RU performance measurements and its notification reception with 10s periodicity: +```bash +[HW] [MPLANE] [PM: "192.168.80.9"][RX_ON_TIME 773428][RX_EARLY 0][RX_LATE 0][RX_TOTAL 878881][RX_ON_TIME_C 104744][RX_EARLY_C 0][RX_LATE_C 0][TX_TOTAL 435922] +``` + The reference specifications: * `O-RAN.WG4.MP.0-v05.00` * `O-RAN.WG4.MP-YANGs-v04.00` @@ -1375,7 +1381,7 @@ Once the mplane service is successfully enabled on the RU, two new users are bei oranbenetel:x:1000:1000::/home/oranbenetel:/bin/sh oranext:x:1001:1001::/home/oranext:/bin/sh ``` -Create `oranbenetel` home directory: +OAI gNB requires the `sudo` access group for NETCONF session. In the case of Benetel O-RUs, the corresponding user is `oranbenetel`. Therefore, please create its home directory: ```bash mkdir /home/oranbenetel && chown oranbenetel:oranbenetel /home/oranbenetel ``` @@ -1393,7 +1399,7 @@ The reference gNB configuration file for one Benetel RAN550: The reference DU configuration file for two Benetel RAN650: [gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf) -In order to run gNB/DU with M-plane, we need to modify the `fhi_72` section in the configuration file. +In order to run gNB/DU with M-plane, we need to modify Tx gain `att_tx` in RU section, as well as the `fhi_72` section in the configuration file. Example for one RU: ```bash fhi_72 = { @@ -1404,6 +1410,7 @@ fhi_72 = { du_key_pair = ("/.ssh/id_rsa.pub", "/.ssh/id_rsa"); du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67"); # only one needed if one VF configured vlan_tag = (9, 9); # only one needed if one VF configured + ru_username = ("oranbenetel"); ru_ip_addr = ("192.168.80.9"); fh_config = ({ T1a_cp_dl = (419, 470); @@ -1423,6 +1430,7 @@ fhi_72 = { du_key_pair = ("/home/oaicicd/.ssh/id_rsa.pub", "/home/oaicicd/.ssh/id_rsa"); du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69"); # only two needed if two VFs configured vlan_tag = (9, 9, 11, 11); # only two needed if two VFs configured + ru_username = ("oranbenetel", "oranbenetel"); ru_ip_addr = ("192.168.80.9", "192.168.80.10"); fh_config = ( # RAN550 #1 @@ -1451,6 +1459,7 @@ fhi_72 = { * `du_key_pair`: ssh public and private keys to authenticate RU with NETCONF * `du_addr`: DU MAC address(es) to create CU-plane interface(s) in the RU * `vlan_tag`: VLAN U and C plane tags to create CU-plane interface(s) in the RU + * `ru_username`: Username with `sudo` access to connect to the RU via M-plane * `ru_ip_addr`: RU IP address to connect to the RU via M-plane * `dpdk_mem_size`: [*] * `dpdk_iova_mode`: [*] @@ -1557,7 +1566,9 @@ sequenceDiagram note over du: DU configures xran - du->ru: 12. DU and RU exchange packets + du->ru: 12. DU activates Performance Measurements + + du->ru: 13. DU and RU exchange packets ``` @@ -1596,7 +1607,9 @@ sequenceDiagram Band sector ID 0 CC ID 0 RU port ID 0 + max Tx gain 24.0 [HW] [MPLANE] Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names. +[HW] [MPLANE] Successfully retreived all performance measurement names. [HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-yang-metadata". [HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "yang". [HW] [MPLANE] RPC request to RU "192.168.80.9" = for module "ietf-inet-types". @@ -1636,6 +1649,59 @@ sequenceDiagram 9 + + 10 + 10 + 10 + + RX_ON_TIME + false + RU + COUNT + + + RX_EARLY + false + RU + COUNT + + + RX_LATE + false + RU + COUNT + + + RX_TOTAL + false + RU + COUNT + + + RX_ON_TIME_C + false + RU + COUNT + + + RX_EARLY_C + false + RU + COUNT + + + RX_LATE_C + false + RU + COUNT + + + TX_TOTAL + false + RU + COUNT + + ETH-INTERFACE @@ -1729,8 +1795,10 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 61440 @@ -1746,8 +1814,10 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 61440 @@ -1763,8 +1833,10 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 61440 @@ -1780,8 +1852,10 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 61440 @@ -1797,9 +1871,15 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 + + KHZ_30 + 0 + 61440 3840 @@ -1807,6 +1887,7 @@ sequenceDiagram 15 0 + true LowLevelRxPrachEndpoint0 @@ -1814,9 +1895,15 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 + + KHZ_30 + 0 + 61440 3840 @@ -1824,6 +1911,7 @@ sequenceDiagram 15 4 + true LowLevelRxEndpoint1 @@ -1831,9 +1919,15 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 + + KHZ_30 + 0 + 61440 3840 @@ -1841,6 +1935,7 @@ sequenceDiagram 15 1 + true LowLevelRxPrachEndpoint1 @@ -1848,9 +1943,15 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 + + KHZ_30 + 0 + 61440 3840 @@ -1858,6 +1959,7 @@ sequenceDiagram 15 5 + true LowLevelRxEndpoint2 @@ -1865,9 +1967,15 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 + + KHZ_30 + 0 + 61440 3840 @@ -1875,6 +1983,7 @@ sequenceDiagram 15 2 + true LowLevelRxPrachEndpoint2 @@ -1882,9 +1991,15 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 + + KHZ_30 + 0 + 61440 3840 @@ -1892,6 +2007,7 @@ sequenceDiagram 15 6 + true LowLevelRxEndpoint3 @@ -1899,9 +2015,15 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 + + KHZ_30 + 0 + 61440 3840 @@ -1909,6 +2031,7 @@ sequenceDiagram 15 3 + true LowLevelRxPrachEndpoint3 @@ -1916,9 +2039,15 @@ sequenceDiagram 9 STATIC - 0 - 0 + 193 + NORMAL + 352 + 288 0 + + KHZ_30 + 0 + 61440 3840 @@ -1926,6 +2055,7 @@ sequenceDiagram 15 7 + true TxArray0 @@ -1933,7 +2063,7 @@ sequenceDiagram 3950400000 100000000 ACTIVE - 0.0 + 24.0 0 0 @@ -1957,7 +2087,7 @@ sequenceDiagram [HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.80.9". [HW] [MPLANE] RPC request to RU "192.168.80.9" = candidate datastore. [HW] [MPLANE] RPC reply = OK. -[HW] [MPLANE] Successfully commited CU-planes configuration into running datastore for RU "192.168.80.9". +[HW] [MPLANE] Successfully commited configuration into running datastore for RU "192.168.80.9". [HW] [MPLANE] Usage state = "idle" for RU "192.168.80.9". [HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.049085102+00:00) { @@ -2025,9 +2155,71 @@ sequenceDiagram "operation": "create" }, ... -} - [HW] [MPLANE] RU "192.168.80.9" is now ready. +[HW] [MPLANE] RPC request to RU "192.168.80.9" = : + + 10 + 10 + 10 + + RX_ON_TIME + true + RU + COUNT + + + RX_EARLY + true + RU + COUNT + + + RX_LATE + true + RU + COUNT + + + RX_TOTAL + true + RU + COUNT + + + RX_ON_TIME_C + true + RU + COUNT + + + RX_EARLY_C + true + RU + COUNT + + + RX_LATE_C + true + RU + COUNT + + + TX_TOTAL + true + RU + COUNT + + + +[HW] [MPLANE] RPC reply = OK. +[HW] [MPLANE] Successfully edited the candidate datastore for RU "192.168.80.9". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = candidate datastore. +[HW] [MPLANE] RPC reply = OK. +[HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.80.9". +[HW] [MPLANE] RPC request to RU "192.168.80.9" = candidate datastore. +[HW] [MPLANE] RPC reply = OK. +[HW] [MPLANE] Successfully commited configuration into running datastore for RU "192.168.80.9". +[HW] [MPLANE] Sucessfully activated PM after start-up procedure for RU "192.168.80.9". ``` diff --git a/doc/README.md b/doc/README.md index 24050666a7..927360c887 100644 --- a/doc/README.md +++ b/doc/README.md @@ -52,28 +52,27 @@ There is some general information in the [OpenAirInterface Gitlab Wiki](https:// * IF setups and arbitrary frequencies * MIMO - [How to run OAI with O-RAN 7.2 FHI](./ORAN_FHI7.2_Tutorial.md) -- [How to run a 5G-NSA setup](./TESTING_GNB_W_COTS_UE.md) +- [How to run a 5G-NSA setup](./TESTING_OAI_NSA_COTS_UE.md) - [How to run a 4G setup using L1 simulator](./L1SIM.md) _Note: we recommend the RFsimulator_ - [How to use the L2 simulator](./L2NFAPI.md) - [How to use the OAI channel simulator](../openair1/SIMULATION/TOOLS/DOC/channel_simulation.md) - [How to use multiple BWPs](./RUN_NR_multiple_BWPs.md) -- [How to run OAI-VNF and OAI-PNF](./nfapi.md): how to run the nFAPI split, +- [How to run OAI-VNF and OAI-PNF](./nfapi.md): how to run the FAPI/nFAPI split, including some general remarks on FAPI/nFAPI. - [How to use the positioning reference signal (PRS)](./RUN_NR_PRS.md) -- [How to use device-to-device communication (D2D, 4G)](./d2d_emulator_setup.txt) +- [How to use device-to-device communication (D2D, 4G)](./d2d_emulator_setup.md) - [How to run with E2 agent](../openair2/E2AP/README.md) - [How to run the physical simulators](./physical-simulators.md) - [How to setup OAI with Nvidia Aerial and Foxconn](./Aerial_FAPI_Split_Tutorial.md) -- [How to setup OAI with AMD T2 Telco card](./LDPC_T2_OFFLOAD_SETUP.md) +- [How to setup OAI with LDPC accelerators (Xilinx T2/Intel ACCs)](./LDPC_OFFLOAD_SETUP.md) +- [How to setup OAI with the XDMA FPGA LDPC accelerator](./LDPC_XDMA_offload_setup.md) - [How to do a handover](./handover-tutorial.md) - [How to setup gNB frequency](./gNB_frequency_setup.md) +- [How to use the RT data recording app](./data_recording.md) Legacy unmaintained files: - [`L2NFAPI_NOS1.md`](./L2NFAPI_NOS1.md), [`L2NFAPI_S1.md`](./L2NFAPI_S1.md): old L2simulator, not valid anymore -- [`SystemX-tutorial-design.md`](./SystemX-tutorial-design.md): old, high-level - documentation -- [`UL_MIMO.txt`](./UL_MIMO.txt): UL-MIMO specific notes # Designs @@ -87,6 +86,7 @@ Legacy unmaintained files: - [Information on gNB RRC](./RRC/rrc-usage.md) - [Information on analog beamforming implementation](./analog_beamforming.md) - [Information on the UE 5G NAS implementation](./5Gnas.md) +- [Information on UL-MIMO](./UL_MIMO.md): UL-MIMO specific notes # Building and running from images @@ -118,6 +118,7 @@ Some directories under `radio` contain READMEs: - [IQPlayer](../radio/iqplayer/DOC/iqrecordplayer_usage.md), and [general documentation](./iqrecordplayer_usage.md) - [fhi_72](../radio/fhi_72/README.md) - [vrtsim](../radio/vrtsim/README.md) +- [rf_emulator](../radio/emulator/README.md) The other SDRs (AW2S, LimeSDR, ...) have no READMEs. @@ -130,10 +131,14 @@ The other SDRs (AW2S, LimeSDR, ...) have no READMEs. # Testing - [UnitTests.md](./UnitTests.md) explains the unit testing setup +- Component tests are under `tests/`. Currently, there is a simple CU-UP + tester, see the corresponding [README.md](../tests/nr-cuup/README.md). - [TESTBenches.md](./TESTBenches.md) lists the CI setup and links to pipelines +- The CI setup uses a [custom framework](../ci-scripts/README.md) to run + end-to-end tests. # Developer tools - [formatting](../tools/formatting/README.md) is a clang-format error detection tool - [iwyu](../tools/iwyu/README.md) is a tool to detect `#include` errors -- [docker-dev-env](../tools/docker-dev-env/README.md) is a ubuntu22 docker development environment +- [docker-dev-env](../tools/docker-dev-env/README.md) is a ubuntu24 docker development environment diff --git a/doc/RRC/rrc-dev.md b/doc/RRC/rrc-dev.md index d511421b01..43f0c7ed93 100644 --- a/doc/RRC/rrc-dev.md +++ b/doc/RRC/rrc-dev.md @@ -210,7 +210,7 @@ sequenceDiagram end ``` -## Handover +## Inter-DU Handover (F1) The basic handover (HO) structure is as follows. In order to support various handover "message passing implementation" (F1AP, NGAP, XnAP), RRC employs @@ -264,6 +264,94 @@ sequenceDiagram sdu->>cucp: F1AP UE Context Release Complete Note over ue,tdu: UE active on target DU ``` +## Inter-gNB Handover (N2) + +This is an inter-NG-RAN procedure. The N2 handover specification is defined in the following documents: + +* 3GPP TS 23.502, 4.9.1.3 Inter NG-RAN node N2 based handover: + - Outlines detailed handover signaling flows for N2-based handovers. + - Covers both intra-system (between 5G gNBs) and inter-system (between 5G and LTE eNBs) handovers. +* 3GPP TS 38.300, section 9 Mobility and State Transitions: + - describes mobility procedures at the NG-RAN level, depending on the RRC state. +* 3GPP TS 38.413 (NGAP), section 8.4 UE Mobility Management Procedures: + - Specifies the signaling procedures over the N2 interface. + - Includes messages like Handover Request, Handover Command, and Handover Preparation. +* 3GPP TS 38.331 (RRC): details the UE-level RRC procedures involved during handovers + +### End-to-end flow + +```mermaid +sequenceDiagram + participant ue as UE + participant sdu as source DU + participant scucp as source CU-CP + participant scuup as source CU-UP + participant tdu as target DU + participant tcucp as target CU-CP + participant tcuup as target CU-UP + participant amf as AMF + + Note over ue,sdu: UE active on source DU + alt HO triggered through A3 event + ue->>sdu: RRC Measurement Report + sdu->>scucp: F1AP UL RRC Msg Transfer (RRC Measurement Report) + Note over scucp: Handover decision (A3 event trigger) + else Manual Trigger + Note over scucp: Handover decision (e.g., telnet) + end + Note over scucp: nr_rrc_trigger_n2_ho() ("on source CU") + scucp->>amf: HANDOVER REQUIRED + amf->>tcucp: HANDOVER REQUEST + Note over tcucp: rrc_gNB_process_Handover_Request + Note over tcucp: trigger_bearer_setup + tcucp->>tcuup: Bearer Context Setup Request + tcuup->>tcucp: Bearer Context Setup Response + Note over tcucp: rrc_gNB_process_e1_bearer_context_setup_resp + Note over tcucp: nr_rrc_trigger_n2_ho_target() ("on target CU") + Note over tcucp: nr_initiate_handover() + tcucp->>tdu: F1AP UE Context Setup Req + Note over tdu: Create UE context + tdu->>tcucp: F1AP UE Context Setup Resp (incl. CellGroupConfig) + Note over tcucp: rrc_CU_process_ue_context_setup_response() ("on target CU") + Note over tcucp: e1_send_bearer_updates() + tcucp->>tcuup: E1AP Bearer Context Modification Req + tcuup->>tcucp: E1AP Bearer Context Modification Resp + tcucp-->>tcucp: callback: ho_req_ack() + Note over tcucp: nr_rrc_n2_ho_acknowledge() ("on target CU") + tcucp->>amf: HANDOVER REQUEST ACKNOWLEDGE (data forwarding info) + amf->>scucp: HANDOVER COMMAND + scucp->>sdu: F1AP UE Context Modification Req (RRC Reconfiguration) + sdu->>ue: RRC Reconfiguration + sdu->>scucp: F1AP UE Context Modification Resp + Note over sdu: Stop scheduling UE + Note over scucp: rrc_CU_process_ue_context_modification_response() + Note over scucp: e1_send_bearer_updates() + scucp->>scuup: E1 Bearer Context Modification Req (PDCP Status Request) + scuup->>scucp: E1 Bearer Context Modification Resp (PDCP Status Info) + scucp->>amf: NG Uplink RAN Status Transfer + amf->>tcucp: NG Downlink RAN Status Transfer + tcucp->>tcuup: E1 Bearer Context Modification Req (PDCP Status Info) + tcuup->>tcucp: E1 Bearer Context Modification Resp + Note over ue: UE attachment to target DU + Note over ue,tdu: RA (Msg1 + Msg2) + ue->>tdu: RRC Reconfiguration Complete + tdu->>tcucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete) + tcucp-->>tcucp: callback: ho_success() + Note over tcucp: nr_rrc_n2_ho_complete() ("on target CU") + Note over tcucp: handle_rrcReconfigurationComplete() ("on target CU") + tcucp->>amf: HANDOVER NOTIFY + amf->>scucp: UE Context Release Command + note over scucp: ngap_gNB_handle_ue_context_release_command + note over scucp: rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND + scucp->>scuup: E1 Bearer Context Release Command + scuup->>scucp: E1 Bearer Context Release Complete + Note over scucp: rrc_gNB_generate_RRCRelease + scucp->>sdu: F1 UE Context Release Command + sdu->>scucp: F1 UE Context Release Complete + note over scucp: rrc_CU_process_ue_context_release_complete + note over scucp: rrc_remove_ue + Note over ue,tdu: UE active on target DU +``` # Structures @@ -291,7 +379,7 @@ Note that while 38.331 requires only one RRC transaction to happen at a time, the 5G RRC does not actually ensure this; it only tries to prevent it by chaining of transactions and some checks. For instance, the Security Mode procedure is followed by a UE capability procedure, and some procedures are not -executed if others are ongoing (ex.: handover if there is reconfiguratio). +executed if others are ongoing (ex.: handover if there is reconfiguration). However, it might be possible to trigger a procedure while another is ongoing. As of now, no queueing mechanims exists to ensure only one operation is @@ -303,12 +391,13 @@ Handover-related data is stored in a per-UE structure of type `nr_handover_context_t`. It is a pointer and only set during handover operation. This data structure has in turn two pointers, one to the source CU (`nr_ho_source_cu_t`), and one to the target CU (`nr_ho_target_cu_t`). In F1, -both are present. In N2 and Xn, only one pointer is supposed to be set a the +both are present. In N2 and Xn, only one pointer is supposed to be set at the corresponding CU. `nr_ho_source_cu_t` contains notably a function pointer `ho_cancel` for handover cancel. `nr_ho_target_cu_t` contains function pointers `ho_req_ack` -for handover request acknowledge and `ho_success` for handover success. As can +for handover request acknowledge, `ho_success` for handover success, +`ho_failure` for handover failure (N2 only). be seen in the sequence diagram above, either the "target CU" or "source CU" needs to do an operation, and a "switch" from target to source CU is done using these function pointers. For instance, in F1, the handover request acknowledge diff --git a/doc/RRC/rrc-usage.md b/doc/RRC/rrc-usage.md index 09c8952889..44d04ba73a 100644 --- a/doc/RRC/rrc-usage.md +++ b/doc/RRC/rrc-usage.md @@ -12,7 +12,7 @@ The RRC layer controls the basic connection setup of UEs as well as additional procedures. It is the fundamental building block of OAI's CU-CP, and interacts with lower layers (DU, basically MAC and RLC) through F1AP messages, and with the CU-UP through E1AP messages. More information can be found in the -respective [F1AP page](../F1-design.md) and [E1AP page](../E1AP/E1-design.md). +respective [F1AP page](../F1AP/F1-design.md) and [E1AP page](../E1AP/E1-design.md). # Periodic output and interpretation @@ -57,7 +57,7 @@ As of now, it does not print information about connected CU-UPs or AMFs. ## Split-related options (when running in a CU or CU-CP) -See [F1 documentation](../F1-design.md) for information about the F1 split. +See [F1 documentation](../F1AP/F1-design.md) for information about the F1 split. See [E1 documentation](../E1AP/E1-design.md) for information about the E1 split. ## RRC-specific configuration options @@ -99,6 +99,43 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration. ### Neighbor-gNB configuration - TBD +Refer to the [handover tutorial](../handover-tutorial.md) for detailed information about gNB neighbors and handover procedures. -Refer to the [handover tutorial](../handover-tutorial.md) for more information. +#### Required configuration parameters + +To define a neighbor cell in the configuration file, the following parameters are required: + +- `gNB_ID` - identifier of the neighbor gNB (e.g., `0xe01`) +- `nr_cellid` - cell identifier of the neighbor cell (e.g., `11111111`) +- `physical_cellId` - physical cell ID for radio identification (e.g., `1`) +- `absoluteFrequencySSB` - SSB frequency in ARFCN notation (e.g., `643296`) +- `subcarrierSpacing` - numerology index: 0=15kHz, 1=30kHz, 2=60kHz, 3=120kHz +- `band` - 3GPP frequency band number (e.g., `78` for 3.5GHz) +- `plmn` - PLMN configuration object with: + - `mcc` - mobile country code (3 digits, e.g., `001`) + - `mnc` - mobile network code (2-3 digits, e.g., `01`) + - `mnc_length` - number of digits in MNC (must be `2` or `3`) +- `tracking_area_code` - tracking area identifier (e.g., `1`) + +Example configuration structure: +``` +neighbour_list = ( + { + nr_cellid = 12345678; + neighbour_cell_configuration = ( + { + gNB_ID = 0xe01; + nr_cellid = 11111111; + physical_cellId = 1; + absoluteFrequencySSB = 643296; + subcarrierSpacing = 1; # 30 kHz + band = 78; + plmn = { mcc = 001; mnc = 01; mnc_length = 2 }; + tracking_area_code = 1; + } + ); + } +); +``` + +Refer to the [handover tutorial](../handover-tutorial.md) for complete examples and detailed setup instructions. diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index f2e71390c7..6e46a361fe 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -85,10 +85,8 @@ The standalone mode is the default mode. Before tag `2024.w45`, the default mode was NSA. Thus, in the past, to run either the gNB or the UE in standalone mode, it was necessary to provide the -`--sa` flag in the command line. This is not necessary anymore; if in doubt, -you can provide `--sa` on the command line. The gNB will ignore this option if -not relevant; the UE might complain that it does not know this option, which -means that standalone is already active. +`--sa` flag in the command line. This is not the case anymore. If provided +the softmodem exits reporting that it does not know this option. The default (SA) mode does the following: - At the gNB: @@ -231,6 +229,9 @@ Or by providing this the the command line parameters: The main parameters to cope with the large NTN propagation delay are cellSpecificKoffset, ta-Common, ta-CommonDrift and the ephemeris data (satellite position and velocity vectors). +The parameter `ntn-UlSyncValidityDuration-r17` indicates the maximum time duration from epochtime during which the UE can apply assistance information without having acquired new assistance information. i.e this enables UE to re-read SIB19 before timer with value ulSyncValidityDuration expires. The unit of the field is in seconds. Example values for GEO: 240s, MEO: 20s, LEO: 5s. +As epochtime is not implemented yet, UE starts the timer from the TTI where SIB19 is received with ntn-UlSyncValidityDuration-r17 IE. + The parameter `cellSpecificKoffset_r17` is the scheduling offset used for the timing relationships that are modified for NTN (see TS 38.213). The unit of the field Koffset is number of slots for a given subcarrier spacing of 15 kHz. diff --git a/doc/RUN_NR_multiple_BWPs.md b/doc/RUN_NR_multiple_BWPs.md index 7b79374fd7..e8598a0445 100644 --- a/doc/RUN_NR_multiple_BWPs.md +++ b/doc/RUN_NR_multiple_BWPs.md @@ -17,35 +17,28 @@ A UE can be configured with a set of 4 BWPs in uplink (UL) and downlink (DL) dir A maximum of 4 dedicated BWPs can be configured for a UE. -To configure multiple BWPs, add the following parameters to the gNB configuration file under "servingCellConfigDedicated": +To configure multiple BWPs, add the following parameters in the physical parameters section: ## Setup of the Configuration files ## + +In the configuration file you have the option to select the 1st active BWP, the RIV and SCS of each BWP in the following way (example with 3 additional BWPs): ``` - firstActiveDownlinkBWP-Id = 1; #BWP-Id - defaultDownlinkBWP-Id = 1; #BWP-Id - firstActiveUplinkBWP-Id = 1; #BWP-Id + first_active_bwp = 1; + bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;}, + { scs = 1; bwpStart = 0; bwpSize = 51;}, + { scs = 1; bwpStart = 0; bwpSize = 24;}); ``` -Each dedicated BWP must have: -``` - # BWP 1 Configuration - dl_bwp-Id_1 = 1; - dl_bwp1_locationAndBandwidth = 28875; // RBstart=0, L=106 (40 MHz BW) - # subcarrierSpacing - # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 - dl_bwp1_subcarrierSpacing = 1; -``` - - Find these parameters in this configuration file: "targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf" +This example configures 3 additional BWPs, with IDs from 1 to 3. Find these parameters in this configuration file: "ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf" # Testing gNB and UE in RF simulator ## gNB command: ``` - sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --rfsim + sudo ./nr-softmodem -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf --rfsim --rfsimulator.serveraddr server ``` ## UE command: ``` - sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --uicc0.imsi 208990000000001 --rfsimulator.serveraddr 127.0.0.1 + sudo ./nr-uesoftmodem -C 3319680000 -r 106 --numerology 1 --ssb 516 --band 78 --rfsim --rfsimulator.serveraddr 127.0.0.1 ``` diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 433a1ac3d1..9c3736ac2a 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -151,7 +151,7 @@ populates UL_INFO.uci_ind, actual uci data is in gNB->pucch {: .func4} * nr_ulsch_extract_rbs_single() {: .func4} - * nr_ulsch_scale_channel() + * nr_scale_channel() {: .func4} * nr_ulsch_channel_level() {: .func4} diff --git a/doc/SystemX-tutorial-design.md b/doc/SystemX-tutorial-design.md deleted file mode 100644 index 1e099abafd..0000000000 --- a/doc/SystemX-tutorial-design.md +++ /dev/null @@ -1,143 +0,0 @@ -# OpenAirInterface for SystemX - -# Terminology - -****This document use the 5G terminology**** - -**Central Unit (CU):** It is a logical node that includes the gNB -functions like Transfer of user data, Mobility control, Radio access -network sharing, Positioning, Session Management etc., except those -functions allocated exclusively to the DU. CU controls the operation of -DUs over front-haul (Fs) interface. A central unit (CU) may also be -known as BBU/REC/RCC/C-RAN/V-RAN/VNF - -**Distributed Unit (DU):** This logical node includes a subset of the -gNB functions, depending on the functional split option. Its operation -is controlled by the CU. Distributed Unit (DU) also known with other -names like RRH/RRU/RE/RU/PNF. - -In OpenAir code, the terminology is often RU and BBU. - -# OpenAirUsage - -## EPC and general environment - -### OAI EPC - -Use the stable OAI EPC, that can run in one machine (VM or standalone) - -Draft description: - - -## Standalone 4G - -EPC+eNB on one machine, the UE can be commercial or OAI UE. - -### USRP B210 - -Main current issue: traffic is good only on coaxial link between UE and -eNB (probably power management issue). - -### Simulated RF - -Running eNB+UE both OAI can be done over a virtual RF link. - -The UE current status is that threads synchronization is implicit in -some cases. As the RF simulator is very quick, a “sleep()” is required -in the UE main loop - -(line 1744, targets/RT/USER/lte-ue.c). - -Running also the UE in the same machine is possible with simulated RF. - -Running in same machine is simpler, offers about infinite speed for -virtual RF samples transmission. - -A specific configuration is required because the EPC Sgi interface has -the same IP tunnel end point as the UE. - -So, we have to create a network namespace for the UE and to route data -in/out of the namespace. - -```bash -ip netns delete aNameSpace 2> /dev/null - -ip link delete v-eth1 2> /dev/null - -ip netns add aNameSpace - -ip link add v-eth1 type veth peer name v-peer1 - -ip link set v-peer1 netns aNameSpace - -ip addr add 10.200.1.1/24 dev v-eth1 - -ip link set v-eth1 up - -iptables -t nat -A POSTROUTING -s 10.200.1.0/255.255.255.0 -o enp0s31f6 \ --j MASQUERADE - -iptables -A FORWARD -i enp0s31f6 -o v-eth1 -j ACCEPT - -iptables -A FORWARD -o enp0s31f6 -i v-eth1 -j ACCEPT - -ip netns exec aNameSpace ip link set dev lo up - -ip netns exec aNameSpace ip addr add 10.200.1.2/24 dev v-peer1 - -ip netns exec aNameSpace ip link set v-peer1 up - -ip netns exec aNameSpace bash -``` - -After the last command, the Linux shell is in the new namespace, ready -to run the UE. - -To make user plan traffic, the traffic generator has to run in the same -namespace - -```bash -ip netns exec aNameSpace bash -``` - -The traffic genenrator has to specify the interface: - -```bash -route add default oaitun_ue1 -``` - -or specify the outgoing route in the traffic generator (like option “-I” -in ping command). - -## 5G and F1 - -Today 5G achievement is limited to physical layer. - -The available modulation is 40MHz, that require one X310 or N300 for the -gNB and a X310 or N300 for the nrUE. - -### Usage with X310 - -Linux configuration: - - -We included most of this configuration included in OAI source code. - -Remain to set the NIC (network interface card) MTU to 9000 (jumbo -frames). - -### Running 5G - -Usage with RFsimulator: - -**gNB** - -```bash -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf -``` - -**nrUE** - -```bash -sudo ./nr-uesoftmodem --numerology 1 -r 106 -C 3510000000 -d --rfsimulator.serveraddr 127.0.0.1 -``` diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index 53d54e45ec..8674103a1a 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -23,6 +23,10 @@ | matix | Matix | gNB (n77) | N310 | | gracehopper1-oai | Gracehopper1 | gNB (n78, PNF/Nvidia CUBB + VNF) | Foxconn RU, _Nvidia Aerial integration_ | | gracehopper3-oai | Gracehopper3 | build | -- | +| acamas | Acamas | 4G and 5G rfsimulator| -- | +| groot | Groot | gNB (n77) | B210 (30AD30F) | +| rocket | Rocket | gNB (n77) | B210 (31F8010) | +| raspix | Raspix | COTS UE | Quectel RM520N | Note: The available resources, and their current usage, is indicated here: - [Lockable resources of jenkins-oai](https://jenkins-oai.eurecom.fr/lockable-resources/): @@ -87,8 +91,8 @@ information on how the images are built. - [RAN-ARM-Cross-Compile-Builder](https://jenkins-oai.eurecom.fr/job/RAN-ARM-Cross-Compile-Builder/) ~BUILD-ONLY ~4G-LTE ~5G-NR ~nrUE - orion: Cross-compilation from Intel to ARM - - base image from `Dockerfile.base.ubuntu22.cross-arm64` - - build image from `Dockerfile.build.ubuntu22.cross-arm64` (no target images) + - base image from `Dockerfile.base.ubuntu.cross-arm64` + - build image from `Dockerfile.build.ubuntu.cross-arm64` (no target images) - [RAN-cppcheck](https://jenkins-oai.eurecom.fr/job/RAN-cppcheck/) ~BUILD-ONLY ~4G-LTE ~5G-NR ~nrUE - bellatrix @@ -111,29 +115,37 @@ information on how the images are built. - build image from `Dockerfile.clang.rhel9` (compilation only, artifacts not used currently) - [RAN-Ubuntu18-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu18-Image-Builder/) ~BUILD-ONLY ~4G-LTE ~5G-NR ~nrUE - - run formatting check from `ci-scripts/docker/Dockerfile.formatting.bionic` - - obelix: Ubuntu 22 image build using docker (Note: builds U22 images while pipeline is named U18!) - - base image from `Dockerfile.base.ubuntu22` - - build image from `Dockerfile.build.ubuntu22`, followed by - - target image from `Dockerfile.eNB.ubuntu22` - - target image from `Dockerfile.gNB.ubuntu22` - - target image from `Dockerfile.nr-cuup.ubuntu22` - - target image from `Dockerfile.nrUE.ubuntu22` - - target image from `Dockerfile.lteUE.ubuntu22` - - target image from `Dockerfile.lteRU.ubuntu22` - - target image from `Dockerfile.gNB.aerial.ubuntu22` - - build image from `Dockerfile.build.fhi72.ubuntu22`, followed by - - target image from `Dockerfile.gNB.fhi72.ubuntu22` - - build unit tests from `ci-scripts/docker/Dockerfile.unittest.ubuntu22`, and run them + - run formatting check from `ci-scripts/docker/Dockerfile.formatting.ubuntu` + - obelix: Ubuntu image build using docker (Note: builds Ubuntu images of newer version while pipeline is named U18!) + - base image from `Dockerfile.base.ubuntu` + - build image from `Dockerfile.build.ubuntu`, followed by + - target image from `Dockerfile.eNB.ubuntu` + - target image from `Dockerfile.gNB.ubuntu` + - target image from `Dockerfile.nr-cuup.ubuntu` + - target image from `Dockerfile.nrUE.ubuntu` + - target image from `Dockerfile.lteUE.ubuntu` + - target image from `Dockerfile.lteRU.ubuntu` + - target image from `Dockerfile.gNB.aerial.ubuntu` + - build image from `Dockerfile.build.fhi72.ubuntu`, followed by + - target image from `Dockerfile.gNB.fhi72.ubuntu` + - build unit tests from `ci-scripts/docker/Dockerfile.unittest.ubuntu`, and run them - [RAN-Ubuntu-ARM-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu-ARM-Image-Builder/) ~BUILD-ONLY ~4G-LTE ~5G-NR - - gracehopper3-oai: ARM Ubuntu 22 image build using docker - - base image from `Dockerfile.base.ubuntu22` - - build image from `Dockerfile.build.ubuntu22`, followed by - - target image from `Dockerfile.gNB.ubuntu22` - - target image from `Dockerfile.nr-cuup.ubuntu22` - - target image from `Dockerfile.nrUE.ubuntu22` - - target image from `Dockerfile.gNB.aerial.ubuntu22` + - gracehopper3-oai: ARM Ubuntu image build using docker + - base image from `Dockerfile.base.ubuntu` + - build image from `Dockerfile.build.ubuntu`, followed by + - target image from `Dockerfile.gNB.ubuntu` + - target image from `Dockerfile.nr-cuup.ubuntu` + - target image from `Dockerfile.nrUE.ubuntu` + - target image from `Dockerfile.gNB.aerial.ubuntu` +- [RAN-Ubuntu-Jetson-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu-Jetson-Image-Builder/) + ~BUILD-ONLY ~4G-LTE ~5G-NR + - jetson3-oai: ARMv8 Ubuntu image build using docker + - base image from `Dockerfile.base.ubuntu` + - build image from `Dockerfile.build.ubuntu`, followed by + - target image from `Dockerfile.gNB.ubuntu` + - target image from `Dockerfile.nr-cuup.ubuntu` + - target image from `Dockerfile.nrUE.ubuntu` #### Image Test pipelines @@ -171,18 +183,25 @@ information on how the images are built. ~4G-LTE ~5G-NR - nepes + B200 (eNB), ofqot + B200 (gNB), idefix + Quectel, nepes w/ ltebox - basic NSA test -- [RAN-PhySim-Cluster](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster/) - ~4G-LTE ~5G-NR ~nrUE - - cluster (`RAN_OC` resource), tests in OpenShift Cluster - - unitary simulators (`nr_dlsim`, etc.) +- [RAN-PhySim-Cluster-4G](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster-4G/) + ~4G-LTE + - tests 4G physical simulators (`nr_dlsim`, etc.) in OpenShift Cluster (x86) + - see [`./physical-simulators.md`](./physical-simulators.md) for an overview +- [RAN-PhySim-Cluster-5G](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster-5G/) + ~5G-NR ~nrUE + - tests 5G physical simulators (`nr_dlsim`, etc.) in OpenShift Cluster (x86) + - see [`./physical-simulators.md`](./physical-simulators.md) for an overview +- [RAN-PhySim-GraceHopper-5G](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-GraceHopper-5G/) + ~5G-NR ~nrUE + - tests 5G physical simulators (`nr_dlsim`, etc.) on Nvidia GraceHopper (ARMv9) - see [`./physical-simulators.md`](./physical-simulators.md) for an overview - [RAN-RF-Sim-Test-4G](https://jenkins-oai.eurecom.fr/job/RAN-RF-Sim-Test-4G/) ~4G-LTE - - cacofonix (eNB, lteUE, OAI EPC) + - acamas (eNB, lteUE, OAI EPC) - uses RFsimulator, for FDD 5, 10, 20MHz with core, 5MHz noS1 - [RAN-RF-Sim-Test-5G](https://jenkins-oai.eurecom.fr/job/RAN-RF-Sim-Test-5G/) ~5G-NR ~nrUE - - cacofonix (gNB, nrUE, OAI 5GC) + - acamas (gNB, nrUE, OAI 5GC) - uses RFsimulator, TDD 40MHz, FDD 40MHz, F1 split - [RAN-SA-AW2S-CN5G](https://jenkins-oai.eurecom.fr/job/RAN-SA-AW2S-CN5G/) ~5G-NR @@ -210,6 +229,11 @@ information on how the images are built. - cacofonix + FHI72 + Metanoia (gNB), up2 (Quectel RM520N UE), OAI CN5G - OpenShift cluster for CN deployment - FHI 7.2 testing with 100 MHz bandwidth, 2 layers in DL +- [RAN-SA-Handover-CN5G](https://jenkins-oai.eurecom.fr/job/RAN-SA-Handover-CN5G/) + ~5G-NR + - groot (CU+DU0) + B210, rocket (DU1) + B210, raspix (Quectel RM520N UE), OAI CN5G + - OpenShift cluster for CN deployment + - Attenuator (mini circuits RC4DAT-6G-60) - controlled from rocket ### RAN-CI-NSA-Trigger diff --git a/doc/TESTING_GNB_W_COTS_UE.md b/doc/TESTING_OAI_NSA_COTS_UE.md similarity index 85% rename from doc/TESTING_GNB_W_COTS_UE.md rename to doc/TESTING_OAI_NSA_COTS_UE.md index f44e140e22..f53e7fe9a1 100644 --- a/doc/TESTING_GNB_W_COTS_UE.md +++ b/doc/TESTING_OAI_NSA_COTS_UE.md @@ -7,12 +7,12 @@ STATUS 2020/10/15 : added External Resources section and links ## External Resources Additional Resources to this page can be found here (special mention to Walter Maguire ) : -https://docs.google.com/document/d/1pL8Szm0ocGxdl5ESVp12Ff71a4PbhCb9SpvbLZzwYbo/edit?usp=sharing +[Additional Notes Supporting the OAI COTS NSA](https://docs.google.com/document/d/1pL8Szm0ocGxdl5ESVp12Ff71a4PbhCb9SpvbLZzwYbo/edit?usp=sharing) At time of writing, the openairinterface5G Commit Tag is 2020.w39 Faraday Cages can be found here : -http://www.saelig.com/MFR00066/ste2300.htm +[Faraday Cage](http://www.saelig.com/MFR00066/ste2300.htm) ## Configuration Overview @@ -37,32 +37,32 @@ Our code might not work with all 5G phones yet, but we are constantly improving * Simcom SIMCOM8200EA * Quectel RM500Q-GL -Note1: In the version we have at Eurecom, you need to set the PLMN to 50501, and you also need to change the firmware to "11.0.0 (RD1A.201105.003.B1, Nov 2020, EU carriers)" (see https://developers.google.com/android/images) +Note1: In the version we have at Eurecom, you need to set the PLMN to 50501, and you also need to change the firmware to "11.0.0 (RD1A.201105.003.B1, Nov 2020, EU carriers)" (see [Factory Images for Nexus and Pixel Devices](https://developers.google.com/android/images)) ## Repository -https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop +[OAI](https://gitlab.eurecom.fr/oai/openairinterface5g/tree/develop) ## Architecture Setup The scheme below depicts our typical setup: -![image info](./testing_gnb_w_cots_ue_resources/oai_fr1_setup.jpg) +![image info](./images/oai_fr1_setup.jpg) The photo depicts the FR1 setup part of the scheme above: -![image info](./testing_gnb_w_cots_ue_resources/oai_fr1_lab.jpg) +![image info](./images/oai_fr1_lab.jpg) ## Build and Install General guidelines to build eNB and gNB : -See https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/doc/BUILD.md#building-ues-enodeb-and-gnodeb-executables +See [Building UE, eNB and gNb executables](https://gitlab.eurecom.fr/oai/openairinterface5g/blob/develop/doc/BUILD.md#building-ues-enodeb-and-gnodeb-executables) - **eNB** -``` +```bash cd /openairinterface5g/ source oaienv cd cmake_targets/ @@ -72,7 +72,7 @@ cd cmake_targets/ - **gNB** -``` +```bash cd /openairinterface5g/ source oaienv cd cmake_targets/ @@ -83,8 +83,7 @@ cd cmake_targets/ - **EPC** for reference: -https://github.com/OPENAIRINTERFACE/openair-epc-fed/blob/master/docs/DEPLOY_HOME.md - +[DEPLOY_HOME_MAGMA_MME](https://github.com/OPENAIRINTERFACE/openair-epc-fed/blob/master/docs/DEPLOY_HOME_MAGMA_MME.md) ## Configuration Files @@ -93,15 +92,17 @@ Each component (EPC, eNB, gNB) has its own configuration file. These config files are passed as arguments of the run command line, using the option -O \ The **REFERENCE** files for eNB and gNB, **used by the CI**, can be found here: -[enb conf file](../ci-scripts/conf_files/enb.band7.tm1.fr1.25PRB.usrpb210.conf) -[gnb conf file](../ci-scripts/conf_files/gnb.band78.tm1.fr1.106PRB.usrpb210.conf) +* [enb conf file](../ci-scripts/conf_files/enb.band7.25prb.usrpb200.tm1.conf) +* [gnb conf file](../ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf) These files have to be updated manually to set the IP addresses and frequency. - -**ATTENTION** : an **EXTERNAL** clock is used to sync the eNB and gNB, -whether the clock is internal or external is defined in the configuration files (!! details needed !!) - +--- +>**⚠️ ATTENTION ⚠️** +> +>An **EXTERNAL** clock is used to sync the eNB and gNB, whether the clock is internal or external is defined in the configuration files (!! details needed !!) +> +--- 1- In the **eNB configuration file** : - look for MME IP address, and update the **ipv4 field** with the IP address of the **EPC** server @@ -198,14 +199,13 @@ The test takes typically a few seconds, max 10-15 seconds. If it takes more than - **EPC** (on EPC host): for reference: -https://github.com/OPENAIRINTERFACE/openair-epc-fed/blob/master/docs/DEPLOY_HOME.md - +[DEPLOY_HOME_MAGMA_MME](https://github.com/OPENAIRINTERFACE/openair-epc-fed/blob/master/docs/DEPLOY_HOME_MAGMA_MME.md) - **eNB** (on the eNB host): Execute: -``` +```bash ~/openairinterface5g/cmake_targets/ran_build/build$ sudo ./lte-softmodem -O **YOUR_ENB_CONF_FILE** | tee **YOUR_LOG_FILE** ``` @@ -213,13 +213,16 @@ Execute: - **gNB** (on the gNB host) - -**ATTENTION** : for the gNB execution, -The **-E** option is required to enable the tri-quarter sampling rate when using a B2xx serie USRP -The **-E** option is **NOT supported** when using a a N300 USRP +--- +>**⚠️ ATTENTION ⚠️** +> +> For the gNB execution: +> - The **-E** option is required to enable the tri-quarter sampling rate when using a B2xx serie USRP +> - The **-E** option is **NOT supported** when using a a N300 USRP +--- Execute: -``` +```bash ~/openairinterface5g/cmake_targets/ran_build/build$ sudo ./nr-softmodem -O **YOUR_GNB_CONF_FILE** -E --nsa | tee **YOUR_LOG_FILE** ``` @@ -229,9 +232,9 @@ Execute: The test case corresponds to the UE attachement, that is the UE connection and its initial access in 5G, as depicted below: -**Source** : https://www.sharetechnote.com/html/5G/5G_LTE_Interworking.html +**Source** : [5G/LTE interworking](https://www.sharetechnote.com/html/5G/5G_LTE_Interworking.html ) -![image info](./testing_gnb_w_cots_ue_resources/attach_signaling_scheme.jpg) +![image info](./images/attach_signaling_scheme.jpg) The test reaches step **12. E-RAB modifcation confirmation** , eventhough not all the messages will appear in the log file. @@ -239,8 +242,8 @@ The test reaches step **12. E-RAB modifcation confirmation** , eventhough not al From the log file that is generated, we can monitor several important steps, to assess that the test was successful. Log files examples can be found here: -[enb log file](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/rh_doc_update_3/doc/testing_gnb_w_cots_ue_resources/oai_enb.log) -[gnb log file](https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/rh_doc_update_3/doc/testing_gnb_w_cots_ue_resources/oai_gnb.log) +* [enb log file](./testing_oai_nsa_w_cots_ue_resources/oai_enb.log) +* [gnb log file](./testing_oai_nsa_w_cots_ue_resources/oai_gnb.log) - eNB receives UE capabilities information, including its NR capabilites, and triggers sGNB Addition Request message: diff --git a/doc/UL_MIMO.md b/doc/UL_MIMO.md new file mode 100644 index 0000000000..6adf5f2790 --- /dev/null +++ b/doc/UL_MIMO.md @@ -0,0 +1,88 @@ +# UpLink Multiple Input Multiple Output (UL MIMO) +## What is UL MIMO ? + +UpLink MIMO refers to the use of multiple antennas at both the UE (User Equipment) as transmitter and the base station as receiver. They are used to send multiple data streams simultaneously from the user to the network. + +## How to use it ? + +## Step 1: build phy sim + +```bash +cd cmake_targets/ +sudo ./build_oai --phy_simulators -c +cd phy_simulators/build/ +``` + +## Step 2: Use the sim + +### Option 1: launch ULSCH sim +On UpLink Shared CHannel(ULSCH), multiple users share the same radio resources (time and frequency slots), the base station schedules and assigns the resources dynamically. The goal here is to simulate the sending of data from an UE to a base station. + +Example: +| Parameter | Value | Description | +|--- |:-: |--: | +| R | 106 | R_NB_UL=106| +| m | 9 | MCS=9 | +| s | 13 | Start SNR | +| n | 100 | Will simulate 100 frames | +| y | 4 | 4 antennas used in eNB | +| z | 4 | 4 antennas used in UE | +| W | 4 | Will use 4 layers | + + +```bash +sudo ./nr_ulschsim -R 106 -m9 -s13 -n100 -y4 -z4 -W4 +``` + +### Option 2: launch UL sim +On UpLink Channel, a single user is dealing with a single base station. The goal is here to simulate the sending of the data from an UE to a base station. + +It's focusing on: +- UpLink chain validation +- PUSCH (whole chain) on UE side and gNB side +- No channel model on data domain signal, which means an ideal scenario is used +- No cross-path connection, which means no signal leakage or interference are present +- PMI = 0 is only unitary precoding matrix + +The same parameters are used. + +```bash +sudo ./nr_ulsim -n100 -m9 -r106 -s13 -W4 -y4 -z4 +``` +### Option 3: Use RFSIM + +#### Build + +RF simulator allows to test OAI without an RF board. It replaces an actual RF board driver. + +```bash +sudo ./build_oai -c --gNB --nrUE -w SIMU +``` + +#### Run +##### 4x4 RANK 4 + +Example: +| Parameter | Value | Description | +|--- |:-: |--: | +| O | [...] | Use a configuration file | +| l | 2 | Set the number of layers for downlink to 2 for PHY test mode | +| L | 4 | Set the number of layers for uplink to 4 for PHY test mode | +| ue-nb-ant-rx | 4 | Set UE number of rx antennas to 4 | +| ue-nb-ant-tx | 4 | Set UE number of tx antennas to 4 | + +```bash +sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf --rfsim --phy-test --l 2 --L 4 +sudo ./nr-uesoftmodem --rfsim --phy-test --ue-nb-ant-rx 4 --ue-nb-ant-tx 4 +``` + +##### 4x4 RANK 2 + +The same parameters are used excepted uplink number of layers set to 2. + +```bash +sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf --rfsim --phy-test --l 2 --L 2 +sudo ./nr-uesoftmodem --rfsim --phy-test --ue-nb-ant-rx 4 --ue-nb-ant-tx 4 +``` + + diff --git a/doc/UL_MIMO.txt b/doc/UL_MIMO.txt deleted file mode 100644 index c06bc78c4c..0000000000 --- a/doc/UL_MIMO.txt +++ /dev/null @@ -1,31 +0,0 @@ -# how to build phy sim -cd cmake_targets/ -sudo ./build_oai --phy_simulators -c - -cd phy_simulators/build/ -# ULSCH sim -# bit level validation -# PUSCH encoding and decoding for 4 layers 2 CMD without data -sudo ./nr_ulschsim -R 106 -m9 -s13 -n100 -y4 -z4 -W4 - -# UL sim -# Uplink chain validation -# PUSCH on UE side and gNB side,whole chain for PUSCH -# No channel model on data domain signal -# No cross-path connection -# PMI = 0 is only unitary prcoding matrix -sudo ./nr_ulsim -n100 -m9 -r106 -s13 -W4 -y4 -z4 - -# How to build rfsim -sudo ./build_oai -c --gNB --nrUE -w SIMU - -# How to run with rfsim -# 4x4 RANK 4 -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf --rfsim --phy-test --l 2 --L 4 -sudo ./nr-uesoftmodem --rfsim --phy-test --ue-nb-ant-rx 4 --ue-nb-ant-tx 4 -# 4x4 RANK 2 -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf --rfsim --phy-test --l 2 --L 2 -sudo ./nr-uesoftmodem --rfsim --phy-test --ue-nb-ant-rx 4 --ue-nb-ant-tx 4 - - - diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 4ff208343e..45f93bf44c 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -17,11 +17,13 @@ Analog beamforming implementation also allows to enable distributed antenna syst A set of parameters in configuration files controls the implementation of analog beamforming and instructs the scheduler on how to behave in such scenarios. Since most notably this technique in 5G is employed in FR2, the configuration file example currently available is a RFsim one for band 261. [Config file example](../ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf) In the `MACRLC` section of configuration files, there are three new parameters: `set_analog_beamforming`, `beam_duration` and `beams_per_period`. The explanation of these parameters is here provided: -- `set_analog_beamforming` can be set to 1 or 0 to activate or desactivate analog beamforming (default value is 0) +- `set_analog_beamforming` can be set a value equal to 1 or 2 to activate or 0 to desactivate analog beamforming (default value is 0) - `beam_duration` is the number of slots (currently minimum duration of a beam) the scheduler is tied to a beam (default value is 1) - `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1) - `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted +Setting analog beamforming to 1 or 2 changes the way FAPI beam index is treated. By setting 1, we instruct L1 to look up in Hi-PHY preconfigured DBM beam index. By setting 2, we instruct L2 to directly signal to Lo-PHY the beam index (e.g. over 7.2x fronthaul). + DAS is enabled by setting to 1 the parameter `enable_das` in the L1 section of the configuration file. In case of DAS enabled, the field `beam_weights` in `MACRLC` section can be omitted. # Implementation in OAI scheduler diff --git a/doc/cross-compile.md b/doc/cross-compile.md index 0a0ce3b1ba..79c4bae761 100644 --- a/doc/cross-compile.md +++ b/doc/cross-compile.md @@ -36,8 +36,8 @@ sudo cp /etc/apt/sources.list "/etc/apt/sources.list.`date`.backup" sudo sed -i -E "s/(deb)\ (http:.+)/\1\ [arch=amd64]\ \2/" /etc/apt/sources.list sudo apt update -sudo apt install -y gcc-11-aarch64-linux-gnu \ - g++-11-aarch64-linux-gnu +sudo apt install -y gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu sudo apt-get install -y \ libblas-dev:arm64 \ @@ -97,5 +97,5 @@ ninja params_libconfig coding rfsimulator # Further information You can do the above steps using docker, see dockerfiles -`docker/Dockerfile.base.ubuntu22.cross-arm64` and -`docker/Dockerfile.build.ubuntu22.cross-arm64` for more information. +`docker/Dockerfile.base.ubuntu.cross-arm64` and +`docker/Dockerfile.build.ubuntu.cross-arm64` for more information. diff --git a/doc/d2d_emulator_setup.md b/doc/d2d_emulator_setup.md new file mode 100644 index 0000000000..8b529d97fa --- /dev/null +++ b/doc/d2d_emulator_setup.md @@ -0,0 +1,207 @@ +# How to use device-to-device communication (D2D, 4G) + +--- +>**⚠️ ATTENTION ⚠️** +> +>D2D is currently unfinished, the following documentation steps are likely not enough to make it work. +--- + +## Scenario 1 : **Off-network UE2UE link** +SynchREF UE (UE1) + +```mermaid +graph LR + UE1[UE1
eth0: 10.10.10.1] --- UE2[UE2
eno1: 10.10.10.2] +``` + +### Example of /etc/network/interfaces configuration for UE1 +```text +auto eth0 + iface eth0 inet static + address 10.10.10.1 + netmask 255.255.255.0 + gateway 10.10.10.1 +``` + +### Prepare the environment: +```bash +git clone https://gitlab.eurecom.fr/matzakos/LTE-D2D.git +cd LTE-D2D +git checkout master +``` + +This branch contains all the current development for **DDPS**, including: + - **UE MAC <-> UE MAC** for **Scenario 1** (off-network communication) + - **eNB MAC <-> UE MAC** using **NFAPI Transport** (on-network communication) + - **RRC Extensions** to support on-network cases + +### NFAPI configuration (required even for Scenario 1 target) +```bash +git clone https://github.com/cisco/open-nFAPI.git +cd open-nfapi +patch -p1 --dry-run < $OPENAIR_HOME/open-nfapi.oai.patch +``` +Validate that there are no errors: + +```patch -p1 < $OPENAIR_HOME/open-nfapi.oai.patch``` + +### OAI build/execute +```bash +export NFAPI_DIR=XXX (place where NFAPI was installed) +cd cmake_targets +./build_oai --UE --ninja #If necessary, use ./build_oai -I --UE to install required packages +cd ran_build/build/ +``` + +### UE1 +``` bash +sudo ifconfig oip0 10.0.0.1 +sudo iptables -A POSTROUTING -t mangle -o oip0 -d 224.0.0.3 -j MARK --set-mark 3 +``` +--- +>**NOTE** +> +>If necessary, add a default gateway: +> +>```sudo route add default gw 10.10.10.1 eth0``` +--- + + +### UE2 +```bash +sudo ifconfig oip0 10.0.0.2 +sudo iptables -A POSTROUTING -t mangle -o oip0 -d 224.0.0.3 -j MARK --set-mark 3 +``` +--- +>**NOTE** +> +>If necessary, add a default gateway: +> +>```sudo route add default gw 10.10.10.1 eno1``` +--- + + +### UE1 and UE2: Get and build `vencore_app` from `d2d-l3-stub` (branch: `l3_stub`) +```bash +gcc -I . vencore_app.c -o vencore_app -lpthread +``` + + +## TEST ONE-TO-MANY + +### Run UE1 then UE2, for example: +- UE1: +```bash +sudo ./lte-softmodem-stub -U --emul-iface eth0 +``` +- UE2: +```bash +sudo ./lte-softmodem-stub -U --emul-iface eno1 +``` + +### Test with Ping +- Sender - UE1: +```bash +ping -I oip0 224.0.0.3 +``` +- Receiver - UE2: *using wireshark* + +### Test with Iperf +- Sender - UE1: +```bash +iperf -c 224.0.0.3 -u -b 0.1M --bind 10.0.0.1 -t 100 +``` + +- Receiver - UE2: +```bash +sudo ./mcreceive 224.0.0.3 5001 +``` + +Filter the incoming packets according to GroupL2Id: receiver (one-to-many) can discard the packets if it doesn't belong to this group. +For the moment, both sender and receiver use the same set of Ids (hardcoded) + +- UE1 (sender): + ```bash + sudo ./lte-softmodem-stub -U --emul-iface eth0 + ./vencore_app #send the sourceL2Id, groupL2Id to OAI + ping -I oip0 224.0.0.3 + ``` + +- UE2(receiver) + ```bash + sudo ./lte-softmodem-stub -U --emul-iface eno1 + #we can see the incomming packets from OAI log, however, cannot see from Wireshark -> they are discarded at MAC layer + ./vencore_app #we can see the packets appearing in Wireshark + ``` + + +## TEST PC5-S (UE1 -sender, UE2 - receiver) and PC5-U for ONE-TO-ONE scenario +### Configure UE1/UE2 + +Configure ports and routing table for UE1 and UE2 + +**UE1:** + ```bash + sudo ifconfig oip0 10.0.0.1 + sudo iptables -A POSTROUTING -t mangle -o oip0 -d 10.0.0.2 -j MARK --set-mark 3 + sudo route add default gw 10.10.10.1 eth0 + ``` +**UE2:** + ```bash + sudo ifconfig oip0 10.0.0.2 + sudo iptables -A POSTROUTING -t mangle -o oip0 -d 10.0.0.1 -j MARK --set-mark 3 + sudo route add default gw 10.10.10.1 eno1 + ``` + +#### Step 1: +Run the traffic emulated over Ethernet on UE1 using lte-softmodem-stub to test the behaviour without RF board. + +**UE1:** +```bash +sudo ./lte-softmodem-stub -U --emul-iface eth0 +``` + +#### Step 2: +Run the traffic emulated over Ethernet on UE2 and set it as listening to incoming messages from PC5-S + +**UE2:** +```bash +sudo ./lte-softmodem-stub -U --emul-iface eno1 +./vencore_app -r #listen to incomming message from PC5-S +``` + +#### Step 3: +Send a message from UE1 to UE2 + +**UE1:** +```bash +./vencore_app -s #send a message via PC5-S (e.g., DirectCommunicationRequest) +``` + +#### Generate unicast traffic +**UE1:** +```bash +ping -I oip0 10.0.0.2 +``` + + +## TEST PC5-D + +#### Step 1: +Run the traffic emulated over Ethernet on UE1 and send a discovery message via PC5-D + +**UE1:** +```bash +sudo ./lte-softmodem-stub -U --emul-iface eth0 +./vencore_app -d #send a PC5-Discovery-Announcement via PC5D +``` + +#### Step 2: +Run the traffic emulated over Ethernet on UE2 and send a discovery message via PC5-D + +**UE2:** +```bash +sudo ./lte-softmodem-stub -U --emul-iface eno1 +./vencore_app -d #send a PC5-Discovery-Announcement via PC5D +``` + diff --git a/doc/d2d_emulator_setup.txt b/doc/d2d_emulator_setup.txt deleted file mode 100644 index fe26e3f9d1..0000000000 --- a/doc/d2d_emulator_setup.txt +++ /dev/null @@ -1,104 +0,0 @@ -Scenario 1 : Off-network UE2UE link -SynchREF UE (UE1) - -UE1(eth0 - 10.10.10.1)--------UE2(eno1 - 10.10.10.2) - -Here's an example of /etc/network/interfaces configuration for UE1 -auto eth0 - iface eth0 inet static - address 10.10.10.1 - netmask 255.255.255.0 - gateway 10.10.10.1 - -Prepare the environment: - - git clone https://gitlab.eurecom.fr/matzakos/LTE-D2D.git #branch: master -This branch contains all the current development for DDPS - - UE MAC<-> UE MAC for Scenario 1 - - eNB MAC<->UE MAC (NFAPI Transport) - - RRC Extensions for “on-network” cases - -NFAPI configuration (required even for Scenario 1 target) - - git clone https://github.com/cisco/open-nFAPI.git - - cd open-nfapi - - patch -p1 --dry-run < $OPENAIR_HOME/open-nfapi.oai.patch -Validate that there are no errors - - patch -p1 < $OPENAIR_HOME/open-nfapi.oai.patch - -OAI build/execute - - export NFAPI_DIR=XXX (place where NFAPI was installed) - - cd cmake_targets - - ./build_oai --UE --ninja - (if necessary, use ./build_oai -I --UE to install required packages) - - cd ran_build/build/ - -UE1: - - sudo ifconfig oip0 10.0.0.1 - - sudo iptables -A POSTROUTING -t mangle -o oip0 -d 224.0.0.3 -j MARK --set-mark 3 - - (if necessary) sudo route add default gw 10.10.10.1 eth0 -UE2: - - sudo ifconfig oip0 10.0.0.2 - - sudo iptables -A POSTROUTING -t mangle -o oip0 -d 224.0.0.3 -j MARK --set-mark 3 - - (if necessary) sudo route add default gw 10.10.10.1 eno1 - -UE1 and UE2: Get and build vencore_app from d2d-l3-stub (branch: l3_stub) - - gcc -I . vencore_app.c -o vencore_app -lpthread - --------------------------------- -TEST ONE-TO-MANY -Run UE1 then UE2, for example: -UE1: sudo ./lte-softmodem-stub -U --emul-iface eth0 -UE2: sudo ./lte-softmodem-stub -U --emul-iface eno1 - -Test with Ping -- Sender - UE1: ping -I oip0 224.0.0.3 -- Receiver - UE2: using wireshark - -Test with Iperf -- Sender - UE1: iperf -c 224.0.0.3 -u -b 0.1M --bind 10.0.0.1 -t 100 -- Receiver - UE2: sudo ./mcreceive 224.0.0.3 5001 - -Filter the incomming packets according to GroupL2Id: receiver (one-to-many) can discard the packets if it doesn't belong to this group. -For the moment, both sender and receiver use the same set of Ids (hardcoded) - -UE1 (sender) - - sudo ./lte-softmodem-stub -U --emul-iface eth0 - - ./vencore_app #send the sourceL2Id, groupL2Id to OAI - - ping -I oip0 224.0.0.3 - UE2(receiver) - - sudo ./lte-softmodem-stub -U --emul-iface eno1 - #we can see the incomming packets from OAI log, however, cannot see from Wireshark -> they are discarded at MAC layer - - ./vencore_app #we can see the packets appearing in Wireshark - - -------------------------------------- -TEST PC5-S (UE1 -sender, UE2 - receiver) and PC5-U for ONE-TO-ONE scenario -Configure UE1/UE2 -UE1: - - sudo ifconfig oip0 10.0.0.1 - - sudo iptables -A POSTROUTING -t mangle -o oip0 -d 10.0.0.2 -j MARK --set-mark 3 - - sudo route add default gw 10.10.10.1 eth0 -UE2: - - sudo ifconfig oip0 10.0.0.2 - - sudo iptables -A POSTROUTING -t mangle -o oip0 -d 10.0.0.1 -j MARK --set-mark 3 - - sudo route add default gw 10.10.10.1 eno1 - -step 1: -- UE1: sudo ./lte-softmodem-stub -U --emul-iface eth0 -step 2: -- UE2: sudo ./lte-softmodem-stub -U --emul-iface eno1 -- UE2: ./vencore_app -r #listen to incomming message from PC5-S -step 3: -- UE1: ./vencore_app -s #send a message via PC5-S (e.g., DirectCommunicationRequest) - -Generate unicast traffic -UE1: ping -I oip0 10.0.0.2 - - - -------------------------------------- -TEST PC5-D -step 1: -- UE1: sudo ./lte-softmodem-stub -U --emul-iface eth0 -- UE1: ./vencore_app -d #send a PC5-Discovery-Announcement via PC5D -step 2: -- UE2: sudo ./lte-softmodem-stub -U --emul-iface eno1 -- UE2: ./vencore_app -d #send a PC5-Discovery-Announcement via PC5D - diff --git a/doc/data_recording.md b/doc/data_recording.md new file mode 100644 index 0000000000..8d4680a4cf --- /dev/null +++ b/doc/data_recording.md @@ -0,0 +1,488 @@ +# Synchronized Real-Time Data Recording Application + +The Data Recording Application runs in parallel to the system components on one of the LINUX servers. It makes use of OAI T-tracer framework. It is able to communicate with the Base station (gNB) and User terminal (UE). +In addition, it synchronizes and combines data traces and control information (metadata) from Base station and User terminal into consistent [Signal Metadata Format (SigMF) format](https://github.com/gnuradio/SigMF) data sets. SigMF is an open-source standard that specifies a way to describe sets of recorded digital signal samples with metadata (data properties and scenario descriptions) provided in [JSON](http://www.json.org/) files. These recorded data sets have a wide range of uses in research and applications. + +## Data Recording Application Architecture + +Data Recording Application designed to have multiple services in different simulation environments: +- Data Control Service (Python) +- Data collection (T-Tracer) Service (C) +- Data Conversion Service (Python) + +Regarding to the APIs between different services, they are such as the following: +- Data Control Service -> Data Collection (T–Tracer) Service: The API is based on a shared memory. +- Data Collection (T–Tracer) Service -> 5G NR Stack: T-Tracer Framework, ethernet connection. +- Data Collection (T–Tracer) Service -> Data Conversion Service: The API is based on a shared memory. + +The following figure shows OAI gNB and UE with the Data Recording App system architecture. + +OAI gNB and UE with the Data Recording App system architectur + +## Required Packages +Install all required system packages with the following commands: +```bash +sudo apt-get update +sudo apt-get install -y python3-sysv-ipc libxft-dev +``` + +Then, install all required python packages with the following commands: +```bash +python3 -m pip install sigmf==1.2.1 termcolor bitarray pandas numpy==1.23 +``` + +User can install all required python packages also using the `requirements.txt` file: +```bash +python3 -m pip install -r common/utils/data_recording/requirements.txt +``` + +## Configuration Files +### Main Data Recording JSON Configuration File +The Data Recording application provides configuration file in [JSON](http://www.json.org/) format. It is stored in [common/utils/data_recording/config/config_data_recording.json](../common/utils/data_recording/config/config_data_recording.json) folder. The main parameters are: +- **data_storage_path**: Path to directory for data storage +- **num_records**: Number of requested data records in slots +- **t_tracer_message_definition_file**: T-Tracer message definition file +- **parameter_map_file**: Parameter mapping dictionary (OAI parameters to standardized metadata). It is located here: [common/utils/data_recording/config/wireless_link_parameter_map.yaml](../common/utils/data_recording/config/wireless_link_parameter_map.yaml) +- **start_frame_number**: It can be used to start the recording from a specific frame, but it is not yet supported. +- **base_station**: + - requested_tracer_messages: Requested base station data traces. The supported messages are: + - GNB_PHY_UL_FD_PUSCH_IQ + - GNB_PHY_UL_FD_DMRS + - GNB_PHY_UL_FD_CHAN_EST_DMRS_POS + - GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL + - GNB_PHY_UL_PAYLOAD_RX_BITS + - meta_data: Additional base station metadata (additional fixed base station parameters that cannot be read from the system yet, but shall be included into the SigMF metadata) +- **user_equipment** + - requested_tracer_messages: Requested user equipment data traces. The supported messages are: + - UE_PHY_UL_SCRAMBLED_TX_BITS + - UE_PHY_UL_PAYLOAD_TX_BITS + - meta_data: Additional user equipment metadata (additional fixed UE parameters that are not read from the system yet, but shall be included into the SigMF metadata) +- **common_meta_data**: Common metadata parameters that are not read from the system yet, but shall be included into the SigMF metadata such as the sampling rate, the bandwidth, and the clock reference of USRP. +- **tracer_service_baseStation_address**: The IP address and port number of base station server. If the Data Recording App and the Data Collection (T–Tracer) Service are running on the same server of base station, the IP address and port number are : `127.0.0.1:2021` +- **tracer_service_userEquipment_address**: The IP address and port number of UE server. + +**Notes**: +- The data can be recorded from base station and UE or from base station only or UE only. To disable the recording from any station, make the list of `requested_tracer_messages` empty such as: `requested_tracer_messages:[]` + +The figure below illustrates an example of a JSON Data Recording App configuration file. + +```json +{ +"data_recording_config": { + "data_storage_path": "/home/user/workarea/oai_recorded_data/", + "data_file_format": "SigMF", + "enable_saving_tracer_messages_sigmf": true, + "num_records": 5, + "t_tracer_message_definition_file": "../T/T_messages.txt", + "parameter_map_file": "config/wireless_link_parameter_map.yaml", + "start_frame_number": 5, + "base_station": { + "requested_tracer_messages": [ + "GNB_PHY_UL_FD_PUSCH_IQ", + "GNB_PHY_UL_FD_DMRS", + "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS", + "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL", + "GNB_PHY_UL_PAYLOAD_RX_BITS" + ], + "meta_data":{ + "num_rx_antennas": 1, + "tx_gain": 48.0, + "rx_gain": 30.0, + "hw_type": "USRP X410", + "hw_subtype": "ZBX", + "seid": "328AB35" + } + }, + "user_equipment": { + "requested_tracer_messages": [ + "UE_PHY_UL_SCRAMBLED_TX_BITS", + "UE_PHY_UL_PAYLOAD_TX_BITS" + ], + "meta_data":{ + "num_tx_antennas": 1, + "tx_gain": 48.0, + "rx_gain": 40.0, + "hw_type": "USRP X410", + "hw_subtype": "ZBX", + "seid": "323F75F" + } + }, + "common_meta_data": { + "sample_rate": 61440000.0, + "bandwidth": 40000000.0, + "clock_reference": "external" + }, + "tracer_service_baseStation_address": "127.0.0.1:2021", + "tracer_service_userEquipment_address": "127.0.0.1:2023" + } +} +``` + +### Wireless Link Parameter Map Dictionary +Since every signal recorder has related configuration with different naming scheme, the [common/utils/data_recording/config/wireless_link_parameter_map.yaml](../common/utils/data_recording/config/wireless_link_parameter_map.yaml) is a dictionary to do the parameters pair between the signal configuration and the SigMF metadata (e.g. OAI parameter name vs. SigMF metadata parameter name). It eases of adoption in case of adding new parameters. In case of changing the name of given parameters in OAI and we need to get those parameters in metadata, the required changes need to be done in the parameter map dictionary. + +The following figure shows an example of Wireless Link Parameter Map Dictionary. For example, the frequency range is called in standardized SigMF metadata `frequency_range` while it is called in OAI `freq_range` and it is called in NI 5G NR RFmx `frequency range`. + +```yaml + # Frequency Range + - sigmf_parameter_name: "frequency_range" + description: "Frequency Range" + 5gnr_ni_rfmx_rfws_parameter: + name: "Frequency Range" + value_map: # simu value : SigMF value + "Range 1": "fr1" + "Range 2": "fr2" + 5gnr_oai_parameter: + name: "freq_range" + value_map: # simu value : SigMF value + 0: "fr1" + 1: "fr2" +``` + +### Global Metadata +There are some metadata parameters that the user may need to change only once. Those parameters have been hard coded in the Data Recording App header. +[common/utils/data_recording/data_recording_app_v1.0.py](../common/utils/data_recording/data_recording_app_v1.0.py). Those are: +- The global metadata such as: author, description, sigmf collection file prefix, datetime_offset, enable saving config Data Recording App in json file with recorded data, and name of signal generator (i.e. 5gnr_oai). The name of signal generator is used for parameter mapping dictionary (OAI parameters to standardized metadata). +- The mapping between supported OAI messages and file_name_prefix, scope, and description. + +The following figure shows an example of global metadata. + +```python +# globally applicable metadata +global_info = { + "author": "Abdo Gaber", + "description": "Synchronized Real-Time Data Recording", + "timestamp": 0, + "collection_file_prefix": "data-collection", # collection file name prefix "deap-rx + str(...)" + "collection_file": "", # Reserved to be created in the code: “data-collection_rec-0_TIME-STAMP” + "datetime_offset": "", # datetime offset between current location and UTC/Zulu timezone + # Example: "+01:00" for Berlin, Germany + "save_config_data_recording_app_json": True, + "waveform_generator": "5gnr_oai", + "extensions": {}, +} +``` + +The following figure shows an example of mapping between supported OAI messages by Data recorrding App and file_name_prefix. + +```python +supported_oai_tracer_messages = { + # gNB messages + "GNB_PHY_UL_FD_PUSCH_IQ": { + "file_name_prefix": "rx-fd-data", + "scope": "gNB", + "description": "Frequency-domain RX data", + "serialization_scheme": ["subcarriers", "ofdm_symbols"], + }, + "GNB_PHY_UL_FD_DMRS": { + "file_name_prefix": "tx-pilots-fd-data", + "scope": "gNB", + "description": "Frequency-domain TX PUSCH DMRS data", + "serialization_scheme": ["subcarriers", "ofdm_symbols"], + }, + "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS": { + "file_name_prefix": "raw-ce-fd-data", + "scope": "gNB", + "description": "Frequency-domain raw channel estimates (at DMRS positions)", + "serialization_scheme": ["subcarriers", "ofdm_symbols"], + }, + "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL": { + "file_name_prefix": "raw-inter-ce-fd-data", + "scope": "gNB", + "description": "Interpolcated Frequency-domain raw channel estimates", + "serialization_scheme": ["subcarriers", "ofdm_symbols"], + }, + "GNB_PHY_UL_PAYLOAD_RX_BITS": { + "file_name_prefix": "rx-payload-bits", + "scope": "gNB", + "description": "Received PUSCH payload bits", + "serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"], + }, + # UE messages + "UE_PHY_UL_SCRAMBLED_TX_BITS": { + "file_name_prefix": "tx-scrambled-bits", + "scope": "UE", + "description": "Transmitted scrambled PUSCH bits", + "serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"], + }, + "UE_PHY_UL_PAYLOAD_TX_BITS": { + "file_name_prefix": "tx-payload-bits", + "scope": "UE", + "description": "Transmitted PUSCH payload bits", + "serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"], + }, +} +``` + +## How to run Data Recording Application +The data recording application can be hosted on the gNB Server or in another server (for example the data lake server). The T-Tracer framework is a Network socket-based (TCP) communication between OAI 5G RAN stack and external tracer program. + +### Step1: Run NR gNB Softmodem with enabling T-Tracer Option + +It is worth mentioning that there is no need to set the T-Tracer port number via NR gNB Softmodem command, the default port `2021` is going to be used. If the Data Recording App is running on the same server of gNB, the parameter `tracer_service_baseStation_address` should be `"tracer_service_baseStation_address": "127.0.0.1:2021`. The gNB T-tracer App will read captured data then from port `2021`. +For the test simplicity, user can run the system in PHY-test mode. We will show how to run using PHY-Test mode: + +Run NR gNB Softmodem with USRP: +``` +sudo ./cmake_targets/ran_build/build/nr-softmodem -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.106PRB.1x1.usrpx410_3300MHz.conf --gNBs.[0].min_rxtxtime 6 --usrp-tx-thread-config 1 --phy-test -d --T_stdout 2 --T_nowait +``` +Run NR gNB Softmodem in RF Simulation: +``` +sudo ./cmake_targets/ran_build/build/nr-softmodem -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.106PRB.1x1.usrpx410_3300MHz.conf --gNBs.[0].min_rxtxtime 6 --rfsim --rfsimulator.serveraddr server --phy-test -d --T_stdout 2 --T_nowait +``` +Note: User needs to change the name of gNB config file to your gNB config file. + +It is worth mentioning that the possible values for T-tracer control options +- --T_stdout option: default 1 + - --T_stdout = 0: Disable output on the terminal and only use the T tracer + - --T_stdout = 1: Disable the T tracer and only output on the terminal + - --T_stdout = 2: Both Eeable the T tracer and output on the terminal +- --T_nowait: Starting gNB without waiting for T-Tracer to be connected +- --T_port [port]: Default port 2021 + +### Step2: Run NR UE Softmodem with enabling T-Tracer Option + +User needs to set the T-Tracer port number via NR UE Softmodem command, assume `2023`. The UE T-tracer App will read captured data then from port `2023`. The IP address and port number are configured in JSON file via the parameter: `"tracer_service_userEquipment_address": "192.168.100.3:2023”`, where the IP address `192.168.100.3` is the IP address of the UE server. +In OAI PHY-test mode, after running the NR gNB softmodem, copy from gNB Server the following two RRC files `reconfig.raw` and `rbconfig.raw` to UE Server (assume to `/home/user/workarea/rrc_files/`): + +Run OAI Soft UE with USRP: +``` +sudo ./cmake_targets/ran_build/build/nr-uesoftmodem --usrp-args "type=x4xx,addr=192.168.10.2,second_addr=192.168.11.2,clock_source=external,time_source=external" --phy-test -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --reconfig-file /home/user/workarea/rrc_files/reconfig.raw --rbconfig-file /home/user/workarea/rrc_files/rbconfig.raw --ue-rxgain 40 --ue-txgain 12 --T_stdout 2 --T_nowait --T_port 2023 +``` + + +Run OAI Soft UE in RF Simulation, assume the IP address of gNB server is `192.168.100.2`: +``` +sudo ./cmake_targets/ran_build/build/nr-uesoftmodem --rfsim --rfsimulator.serveraddr 192.168.100.2 --phy-test -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --reconfig-file /home/user/workarea/rrc_files/reconfig.raw --rbconfig-file /home/user/workarea/rrc_files/rbconfig.raw --T_stdout 2 --T_nowait --T_port 2023 +``` + +### Step3: Run Data Recording Application Services +First, compile the Data Collection (T-Tracer) Services: +- Go to: `common/utils/T/tracer` +- Compile gNB and UE Data Collection Services (T-Tracer Apps) +``` +make t_tracer_app_gnb +make t_tracer_app_ue +``` + +Run gNB Data Collection service on one terminal: +``` +./t_tracer_app_gnb -d ../T_messages.txt +``` +Run UE Data Collection service on another terminal: +``` +./t_tracer_app_ue -d ../T_messages.txt +``` + +Second, run main Data Recording Application: +- Go to: `common/utils/data_recording` + +Run the following python script: +``` +python3 data_recording_app_v1.0.py +``` + +The recorded data set will be stored in the configured path, assume `/home/user/workarea/oai_recorded_data/`. +The following figure shows an example of recorded data set. + +Example from SigMF recorded data set + +## Overview on Collected Data Set + +SigMF supports heterogeneous data via SigMF collections. It is used to bundle multiple SigMF files into one recording. +A heterogeneous data set generated for a certain scenario is stored in a SigMF collection which consists of (as it is shown in the figure above) +- One SigMF collection file per each record, e.g. + - data-collection-rec-idx-timestamp.sigmf-collection +- SigMF recordings (.sigmf-meta file + .sigmf-data file). Per each message, there are two files: + - rx-fd-data-rec-idx-timestamp.sigmf-meta + - rx-fd-data-rec-idx-timestamp.sigmf-data + - tx-pilots-fd-data-rec-idx-timestamp.sigmf-meta + - tx-pilots-fd-data-rec-idx-timestamp.sigmf-data + - raw-ce-fd-data-rec-idx-timestamp.sigmf-meta + - raw-ce-fd-data-rec-idx-timestamp.sigmf-data + - tx-scrambled-bits-rec-idx-timestamp.sigmf-meta + - tx-scrambled-bits-rec-idx-timestamp.sigmf-data + +The following figure shows an example of SigMF collection file and how it bundles multiple SigMF files of a single record. + +```json +{ + "collection": { + "core:author": "Abdo Gaber", + "core:description": "Synchronized Real-Time Data Recording", + "core:streams": [ + { + "hash": "0a39edb03eb86fb0d368a0511f17b0e99d3314d09b1d271c8bc893dffbb6b06b8987362bd15a334f8da40091ca83f6201218084fc602b562b5b012933bc4608a", + "name": "/home/user/workarea/oai_recorded_data/tx-pilots-fd-data-rec-0-2025_06_19T11_19_00_037" + }, + { + "hash": "f2062ff3a7020e2569c9d1d3c5a8403dacf83a1e842b126f889262d56a1b2efc818962d198cd5219bf563aba5e0709e80eba40bd973de95787319e8380d339ba", + "name": "/home/user/workarea/oai_recorded_data/raw-ce-fd-data-rec-0-2025_06_19T11_19_00_037" + }, + { + "hash": "283b62908321db17db6a53c77d41a385360e9f11128627934f4f41746b797b77e41dbc18e72d096126673766edb5d4a9408712f5071d064fae0a792644c16bdd", + "name": "/home/user/workarea/oai_recorded_data/rx-fd-data-rec-0-2025_06_19T11_19_00_037" + }, + { + "hash": "e72f2d6ea3e353d666e7635726ea6a5bd096e6fc14c965c7c2803705bcd0cf934ac9dc3a0c12f190171afc2db7d4b3fd7d5acc8e18796c48d5ee6e7bbd0551b7", + "name": "/home/user/workarea/oai_recorded_data/raw-inter-ce-fd-data-rec-0-2025_06_19T11_19_00_037" + }, + { + "hash": "7eddf8eb4564c03a1505e3288052cc583416617158dbff0bad942af7cc2477449c6c7ff2f02a55849449ba6956800b446f5c0880d418d80fffc24fb236038ef3", + "name": "/home/user/workarea/oai_recorded_data/rx-payload-bits-rec-0-2025_06_19T11_19_00_037" + }, + { + "hash": "ec128fd8691975995df84f96db3740b773cb060d9803f1ae2664e0d081011e59d623f7fe909552e807a4e63cb02e7f9005e8a19ab2a680004d8af9f6b49fff06", + "name": "/home/user/workarea/oai_recorded_data/tx-payload-bits-rec-0-2025_06_19T11_19_00_029" + }, + { + "hash": "d8300b206ede81639c0d8f25030d85ff3b4e848456a7d73c706350fbc2b4ce7b114cddf29173e069335fcf4aeab37818129259afacf0fd02efa34b9b6d985edb", + "name": "/home/user/workarea/oai_recorded_data/tx-scrambled-bits-rec-0-2025_06_19T11_19_00_029" + } + ], + "core:version": "1.2.1" + } +} +``` + +Each SigMF metadata has three sections: +- global: The standardized global parameters are presented here to understand and read the binary data. +- captures: The standardized capture parameters provide details about the capture process. +- annotations: It provides details about the recording scenario. + +The following figure shows an example of SigMF metadata file, for example for the frequency-domain RX data. + +```json +{ + "global": { + "core:author": "Abdo Gaber", + "core:collection": "data-collection-rec-0-2025_06_19T11_19_00_037", + "core:dataset": "raw-ce-fd-data-rec-0-2025_06_19T11_19_00_037.sigmf-data", + "core:datatype": "cf32_le", + "core:description": "Frequency-domain raw channel estimates (at DMRS positions)", + "core:hw": "USRP X410", + "core:license": "MIT License", + "core:num_channels": 1, + "core:recorder": "NI Data Recording Application for OAI", + "core:sample_rate": 61440000.0, + "core:sha512": "55ae5bc81b4812e68f6e1c195600f240fc3ca71113c732271ee42a5524da98636c3c7ac587c46fd87c6d1b9253ca6504a4b94eafba8f4065099096fc7721228c", + "core:version": "1.2.1" + }, + "captures": [ + { + "core:datetime": "2025_06_19T11:19:00.037", + "core:frequency": 3319680000.0, + "core:sample_start": 0, + "serialization:counts": [ + 600, + 13 + ], + "serialization:scheme": [ + "subcarriers", + "ofdm_symbols" + ] + } + ], + "annotations": [ + { + "core:sample_count": 7800, + "core:sample_start": 0, + "num_transmitters": 1, + "system_components:channel": [ + { + "carrier_frequency": 3319680000.0, + "channel_model": "tdl_d", + "delay_spread": 5.0000000000000004e-08, + "emulation_mode": "ni rf real time", + "snr_esn0_db": 20.0, + "speed": 5.0, + "transmitter_id": "tx_0" + } + ], + "system_components:receiver": { + "bandwidth": 40000000.0, + "clock_reference": "external", + "gain": 30.0, + "hw_subtype": "ZBX", + "manufacturer": "NI", + "num_rx_antennas": 1, + "phy_freq_domain_receiver_type": "trad_rx", + "seid": "328AB35" + }, + "system_components:transmitter": [ + { + "signal:detail": { + "5gnr": { + "cell_id": 0, + "cp_mode": "normal", + "frame": 785, + "frame_structure": "tdd", + "frequency_range": "fr1", + "link_direction": "uplink", + "num_slots": 1, + "num_tx_antennas": 1, + "pusch:content": "compliant", + "pusch:mapping_type": "B", + "pusch:mcs": 9, + "pusch:mcs_table_index": 0, + "pusch:modulation": "qpsk", + "pusch:num_layer": 1, + "pusch:num_ofdm_symbols": 13, + "pusch:num_prb": 50, + "pusch:payload_bit_pattern": "zeros", + "pusch:start_ofdm_symbol": 0, + "pusch:start_prb": 0, + "pusch:transform_precoding": "disabled", + "pusch_dmrs:antennna_port": 0, + "pusch_dmrs:duration_num_ofdm_symbols": 1, + "pusch_dmrs:num_add_positions": 2, + "pusch_dmrs:ofdm_symbol_idx": [ + 0, + 5, + 10 + ], + "pusch_dmrs:resource_map_config": "5g nr type 1", + "pusch_dmrs:start_ofdm_symbol": 0, + "rnti": 4660, + "slot": 8, + "subcarrier_spacing": 30000 + }, + "generator": "OpenAirInterface: https://www.openairinterface.org/", + "standard": "5gnr" + }, + "signal:emitter": { + "bandwidth": 40000000.0, + "clock_reference": "external", + "frequency": 3319680000.0, + "gain_tx": 48.0, + "hw": "USRP X410", + "hw_subtype": "ZBX", + "manufacturer": "NI", + "sample_rate": 61440000.0, + "seid": "323F75F" + }, + "transmitter_id": "tx_0" + } + ] + } + ] +} +``` + +## Synchronization Validation +For synchronization validation and to show how to read SigMF metadata, a simple script `common/utils/data_recording/sync_validation_demo.py` has been created to validate that, for example: the recorded bits from gNB and UE are in sync. + +## Data Recording Application Limitation + +- MIMO Support: The data recording app is ready, tested and validated for SISO. For MIMO, it should be enhanced, tested, and validated. +- It supports the uplink gNB and UE messages listed above. If the user would like to record another message for example from DL, the user needs to define the required meta-data. User can use the existing meta-data definition of UL as a template. Then, add those messages to the headers of different Data Recording App services. +- Data serialization in Tx scrambled bits message without considering location of DMRS symbols: Only captured valid data bits is stored. It means the location of DMRS symbols are not considered and filled with zeros and stored as it is in the grid presented on the figure below. For example: + - Number of bits per IQ Symbol = 4 + - Number of subcarrier = 72 + - Number of OFDM symbols = 13 + - So, the valid number of bits in the transport block (slot) is: 3312 bits. If we will fill DMRS locations by zeros, the number of bits is: 3744 bits, but it is not done due to the real-timing issues. For Tx scrambled bits data de-serialization, the user can reconstruct the Tx Scrambled Bits Grid (2D Grid) by using the captured DMRS grid or Channel Estimates Grid as a reference and no need to derive the DMRS symbols locations based on 5G NR config parameters. + +Data serialization + +### To Do List: +- Provide an overview about the different services of the Data Recording App (Data Control Service, Data collection (T-Tracer) Service, Data Conversion Service) and the APIs definition between them. diff --git a/doc/environment-variables.md b/doc/environment-variables.md index 9778665afe..767afa6db4 100644 --- a/doc/environment-variables.md +++ b/doc/environment-variables.md @@ -3,14 +3,13 @@ OAI uses/supports a number of environment variables, documented in the following: - `NFAPI_TRACE_LEVEL`: set the nfapi custom logging framework's log level; can be one of `error`, `warn`, `note`, `info`, `debug`. Default is `warn`. -- `NR_AWGN_RESULTS_DIR`: directory containing BLER curves for L2simulator channel modelling in SISO case -- `NR_MIMO2x2_AWGN_RESULTS_DIR`: directory containing BLER curves for L2simulator channel modelling in 2x2 MIMO case +- `NR_AWGN_RESULTS_DIR`: directory containing BLER curves for NR L2simulator channel modelling in SISO case +- `NR_MIMO2x2_AWGN_RESULTS_DIR`: directory containing BLER curves for NR L2simulator channel modelling in 2x2 MIMO case +- `OPENAIR_DIR`: should point to the root directory of OpenAirInterface; BLER curves for LTE L2sim channel emulation - `NVRAM_DIR`: directory to read/write NVRAM data in (5G) `nvram` tool; if not defined, will use `PWD` (working directory) - `OAI_CONFIGMODULE`: can be used to pass the configuration file instead of `-O` - `OAI_GDBSTACKS`: if defined when hitting an assertion (`DevAssert()`, `AssertFatal()`, ...), OAI will load `gdb` and provide a backtrace for every thread - `OAI_RNGSEED`: overwrites any seed for random number generators (RNG) in simulators -- `OAI_THREADPOOLMEASUREMENTS`: path to a file to store thread pool debugging information, see the [thread pool documentation](..common/utils/threadPool/thread-pool.md) -- `OPENAIR_DIR`: should point to the root directory of OpenAirInterface; some code relies on this to get a filename, e.g., BLER curves for L2sim channel emulation - `USIM_DIR`: directory to read/write USIM data in (4G) `usim` tool; if not defined, will use `PWD` (working directory) Furthermore, these variables appear in code that is not maintained and maybe not even compiled anywhere: @@ -19,3 +18,5 @@ Furthermore, these variables appear in code that is not maintained and maybe not - `SSH_CLIENT`: alternative host to connect to, for CLI, if `REMADDR` is not defined - `USER`: user name in the command-line interface - `rftestInputFile`: input file for the `calibration_test` tool +- `OPENAIR2_DIR` : OMV and OMG modules, obsolete +- `TITLE`: OTG module, obsolete diff --git a/doc/handover-tutorial.md b/doc/handover-tutorial.md index a367de868a..b6e60746aa 100644 --- a/doc/handover-tutorial.md +++ b/doc/handover-tutorial.md @@ -1,5 +1,5 @@ -This tutorial explains how to perform handovers. For the moment, only F1 -handovers are supported. +This tutorial explains how to perform handovers. It covers both F1 handovers +(intra-gNB, within a single gNB between DUs) and N2 handovers (inter-gNB). [[_TOC_]] @@ -13,6 +13,23 @@ same. ![F1 Handover setup](./RRC/ho.png) +# What is a gNB neighbor? + +Network continuity is a key aspect of 5G. In the 5G architecture, gNB neighbors +play a central role in maintaining service continuity through mechanisms such +as handover and load balancing. By definition, a gNB neighbor is another gNB +that can be measured and linked by the UE. If the current serving gNB is no +longer optimal, the UE may connect to a neighbor gNB. + +To support this behavior, the network configuration specifies additional frequencies +and cells that the UE should measure. The UE reports these measurements to the +network, which then decides whether or not to initiate a handover. + +Neighbor types include: +- **Intra-gNB neighbors** - cells belonging to the same gNB +- **Inter-gNB neighbors** - cells belonging to different gNBs +- **Inter-RAT neighbors** - cells belonging to another RAT (e.g., LTE) + # Steps to run F1 handover with OAI UE Measurement reporting and processing of RRC Reconfiguration for Mobility are @@ -54,7 +71,11 @@ Start DU0: sudo ./nr-softmodem --rfsim -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf --rfsimulator.serveraddr 127.0.0.1 -Start the UE, and let it connect completely: +This will show an error `[HW] connect() to 127.0.0.1:4043 failed, +errno(111)`. _This is expected_, because the RFsim server is at the UE (to be +able to serve two RFsim clients, one DU each; see below for more info). Proceed +by starting the UE, and let it connect completely (this should make the error +go away): sudo ./nr-uesoftmodem -C 3450720000 -r 106 --numerology 1 --ssb 516 -O --rfsim --rfsimulator.serveraddr server @@ -119,7 +140,7 @@ You can do handover across DUs with a COTS UE. Note that these DUs should be separated by at least multiple meters to ensure that the UE will receive different signal strengths when moving between cells. -We only support intra-frequency handovers yet. We have verified with USRPs +We support both intra-frequency and inter-frequency handovers. We have verified with USRPs only, although other radios should work as well. For UEs, we verified Quectel modules and iPhones. Note, though, that not all @@ -142,7 +163,7 @@ neighbour relation of the DUs at the CU. To do so, proceed as follows: ``` cat nrRRC_stats.log ``` -1. Fill in the `neighbour-config.conf` configuration file as shown below, and +1. Fill in the [`neighbour-config.conf`](../ci-scripts/conf_files/neighbour-config.conf) configuration file as shown below, and `@include` it in the CU file. 1. Start the CU and both DUs. 1. Bring the phone close to one cell, and leave flight mode. It should connect @@ -157,7 +178,7 @@ triggered: - Make sure that both DUs use the same hardware. - Make sure that the UE sees both cells. For instance, you can switch to flight mode, go closer to the other DU, and switch off flight mode -- the UE should - connect to that second UE. + connect to that second DU. - We did not manage handover with every phone yet -- make sure you use one of the list provided above. @@ -203,6 +224,7 @@ neighbour_list = ( physical_cellId = 1; absoluteFrequencySSB = 643296; subcarrierSpacing = 1; #30 KHz + band = 78; plmn = { mcc = 001; mnc = 01; mnc_length = 2}; tracking_area_code = 1; } @@ -217,6 +239,7 @@ neighbour_list = ( physical_cellId = 0; absoluteFrequencySSB = 643296; subcarrierSpacing = 1; #30 KHz + band = 78; plmn = { mcc = 001; mnc = 01; mnc_length = 2}; tracking_area_code = 1; } @@ -246,6 +269,15 @@ nr_measurement_configuration = { }) }; ``` +`@include` this configuration file inside the gNB section of CU file as shown below. + +``` + plmn_list = ({ mcc = 222; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff })}); + + + @include "neighbour-config.conf" + +``` # Handovers triggers and NTN @@ -327,3 +359,160 @@ while true; do sleep 15 done ``` + +# N2 Handover + +## Run the setup + +An N2 handover involves the transfer of a UE from one gNB to another via the 5G core network. Unlike F1 handover, where the CU handles the process internally between its DUs, N2 handover requires signaling through the AMF, making it a core-network-based handover. + +We assume: + +* Two independent gNBs connected to the same 5GC via N2 interface. +* A UE initially connected to gNB-PCI0, which will be handed over to gNB-PCI1. +* Handover is triggered by either a decision based measurement event (e.g. A3) or telnet command. + +## Steps to run N2 handover with OAI UE + +**Note for same-machine setup:** When running both gNBs on the same machine, you need to assign a unique IP address to the second gNB to avoid network conflicts. For example: + +```sh +sudo ip addr add 192.168.71.180/24 dev rfsim5g-public +``` + +1. Similarly to F1 handover, UE does not support any measurement reporting and handover is triggered by +telnet command. Therefore, ensure that both gNBs and UE are built with telnet support: + +```sh +./build_oai --ninja --nrUE --gNB --build-lib telnetsrv +``` + +Run the 5G Core Network if not already running. See [OAI CN5G tutorial](./NR_SA_Tutorial_OAI_CN5G.md). + +2. Start the source gNB (gNB-PCI0) e.g. + +```sh +sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci0.rfsim.conf --telnetsrv --telnetsrv.shrmod ci --gNBs.[0].min_rxtxtime 6 --rfsim --rfsimulator.serveraddr 127.0.0.1 +``` + +3. Start the UE e.g. + +```sh +sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --uicc0.imsi 001010000000001 -O ../../../ci-scripts/conf_files/nrue.uicc.conf --rfsimulator.serveraddr server +``` + +Ensure the UE successfully registers with the network. + +4. Start the target gNB (gNB-PCI1) e.g. + +```sh +sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf --rfsim --telnetsrv --telnetsrv.shrmod ci --gNBs.[0].min_rxtxtime 6 --rfsimulator.serveraddr 127.0.0.1 +``` + +**Note for same-machine setup:** When running both gNBs on the same machine, add the following network interface options to the target gNB command, e.g.: + +```sh +--gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF 192.168.71.180 +--gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NGU 192.168.71.180 +``` + +5. Trigger the N2 handover, e.g. + +From gNB-PCI0, trigger handover on target gNB with PCI 1 for UE ID 1: + +```sh +echo ci trigger_n2_ho 1,1 | nc 127.0.0.1 9090 && echo +``` +where the input parameters correspond to the PCI of the neighbor cell and the RRC ID of the UE. + +This will initiate the N2 handover on the source gNB. + +## Neighbour list and measurement configuration + +Make sure the configuration file contains a neighbour list and measurement configuration, e.g. [neighbour-config-rfsim.conf](../../ci-scripts/conf_files/neighbour-config.conf). This configuration can also be present in a different file and included in the gNB configuration file with `@include "neighbour-config-rfsim.conf"`. + +For each gNB there is a `neighbour_cell_configuration` linked to its serving cell ID. + +The measurement configuration is based on A2 and A3 measurement events in 5G NR. These events are used by the UE to report radio conditions to the gNB. The A2 Measurement Event indicates that the serving cell’s signal quality has degraded below a defined threshold and the UE shall initiate measurement of neighboring cells. The A3 Measurement Event indicates that a neighboring cell’s signal quality is better than that of the serving cell by a certain offset and the UE shall trigger handover to a stronger neighboring cell + +This is an example with comments on how to use the configuration file: + +``` +############################################################ +# gNB-to-gNB neighbour list + measurement configuration # +# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) # +############################################################ + +neighbour_list = ( + ########################################################## + # Entry USED BY gNB_ID = 0xe00 (nr_cellid = 12345678L) # + ########################################################## + { + nr_cellid = 12345678L; # Serving cell of gNB 0xe00 + neighbour_cell_configuration = ( + { + gNB_ID = 0xb00; + nr_cellid = 720898; # Cell served by gNB 0xb00 + physical_cellId = 1; + absoluteFrequencySSB= 621312; + subcarrierSpacing = 1; # 30 kHz + band = 78; + plmn = { mcc = 208; mnc = 99; mnc_length = 2 }; + tracking_area_code = 1; + } + ); + }, + + ########################################################## + # Entry USED BY gNB_ID = 0xb00 (nr_cellid = 720898) # + ########################################################## + { + nr_cellid = 720898; # Serving cell of gNB 0xb00 + neighbour_cell_configuration = ( + { + gNB_ID = 0xe00; + nr_cellid = 12345678L; # Cell served by gNB 0xe00 + physical_cellId = 0; + absoluteFrequencySSB= 641280; + subcarrierSpacing = 1; # 30 kHz + band = 78; + plmn = { mcc = 208; mnc = 99; mnc_length = 2 }; + tracking_area_code = 1; + } + ); + } +); + +############################################################ +# Common NR measurement-event configuration # +############################################################ + +nr_measurement_configuration = { + Periodical = { + enable = 1; + includeBeamMeasurements = 1; + maxNrofRS_IndexesToReport = 4; + }; + + A2 = { + enable = 1; + threshold = 60; + timeToTrigger = 1; + }; + + A3 = ( + { + cell_id = 720898; # neighbour of gNB 0xe00 + offset = 10; + hysteresis = 0; + timeToTrigger = 1; + }, + { + cell_id = 12345678; # neighbour of gNB 0xb00 + offset = 5; + hysteresis = 1; + timeToTrigger = 2; + } + ); +}; +``` diff --git a/doc/testing_gnb_w_cots_ue_resources/attach_signaling_scheme.jpg b/doc/images/attach_signaling_scheme.jpg similarity index 100% rename from doc/testing_gnb_w_cots_ue_resources/attach_signaling_scheme.jpg rename to doc/images/attach_signaling_scheme.jpg diff --git a/doc/images/data_recording_arch.svg b/doc/images/data_recording_arch.svg new file mode 100644 index 0000000000..ea5019210c --- /dev/null +++ b/doc/images/data_recording_arch.svg @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/doc/images/data_serialization_tx_scrambled_bit_message.svg b/doc/images/data_serialization_tx_scrambled_bit_message.svg new file mode 100644 index 0000000000..a86047134a --- /dev/null +++ b/doc/images/data_serialization_tx_scrambled_bit_message.svg @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/doc/nr-ue-threads.svg b/doc/images/nr-ue-threads.svg similarity index 100% rename from doc/nr-ue-threads.svg rename to doc/images/nr-ue-threads.svg diff --git a/doc/oai_enb_func_split_arch.png b/doc/images/oai_enb_func_split_arch.png similarity index 100% rename from doc/oai_enb_func_split_arch.png rename to doc/images/oai_enb_func_split_arch.png diff --git a/doc/testing_gnb_w_cots_ue_resources/oai_fr1_lab.jpg b/doc/images/oai_fr1_lab.jpg similarity index 100% rename from doc/testing_gnb_w_cots_ue_resources/oai_fr1_lab.jpg rename to doc/images/oai_fr1_lab.jpg diff --git a/doc/testing_gnb_w_cots_ue_resources/oai_fr1_setup.jpg b/doc/images/oai_fr1_setup.jpg similarity index 100% rename from doc/testing_gnb_w_cots_ue_resources/oai_fr1_setup.jpg rename to doc/images/oai_fr1_setup.jpg diff --git a/doc/oai_logo.png b/doc/images/oai_logo.png similarity index 100% rename from doc/oai_logo.png rename to doc/images/oai_logo.png diff --git a/doc/images/sigmf_dataset.svg b/doc/images/sigmf_dataset.svg new file mode 100644 index 0000000000..42393f488a --- /dev/null +++ b/doc/images/sigmf_dataset.svg @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/doc/nfapi.md b/doc/nfapi.md index 366b5fb4ac..214aa2799f 100644 --- a/doc/nfapi.md +++ b/doc/nfapi.md @@ -1,5 +1,6 @@ This document describes the SmallCellForum (SCF) (n)FAPI split in 5G, i.e., -between the MAC/L2 and PHY/L1. +between the MAC/L2 and PHY/L1. It also describes how to make use of the +multiple transport mechanisms between the 2. The interested reader is recommended to read a copy of the SCF 222.10 specification ("FAPI"). This includes information on what is P5, P7, and how @@ -7,6 +8,8 @@ FAPI works. The currently used version is SCF 222.10.02, with some messages upgraded to SCF 222.10.04 due to bugfixes in the spec. Further information about nFAPI can be found in SCF 225.2.0. +[[_TOC_]] + # Quickstart Compile OAI as normal. Start the CN and make sure that the VNF configuration @@ -92,8 +95,9 @@ can proceed as follows: - in `vnf.conf` * modify `MACRLCs` section to configure south-bound nFAPI transport * delete `L1s`, `RUs`, and radio-specific sections. - * in `gNBs` section, increase the `ra_ResponseWindow` by one to extend the RA - window: this is necessary because the PNF triggers the scheduler in the VNF + * in `gNBs` section, select a sufficiently large `ra_ResponseWindow` if a UE + does not connect with a message that the response window timed out: + this is necessary because the PNF triggers the scheduler in the VNF in advance, which might make the RA window more likely to run out - copy `monolithic.conf`, which will be your PNF file (`pnf.conf`) - in `pnf.conf` @@ -108,6 +112,125 @@ can proceed as follows: Note: all L1-specific options have to be passed to the PNF, and remaining options to the VNF. +## Transport mechanisms between VNF and PNF + +Currently, the VNF/PNF split supports three transport mechanisms between each +other: + +1. Socket communication (either regular, or SCTP), this is the default + + The socket type may be changed by editing `nfapi_pnf_config_create()` and + `nfapi_vnf_config_create()`, in both of which `_this->sctp = ;` indicate whether SCTP or regular sockets are to be used. Note: The + value of `_this->sctp` **must** be the same on the VNF and PNF. +2. Intel WLS Lib, which uses DPDK to achieve a shared memory communication between components. +3. nvIPC, which is used exclusively for the NVIDIA Aerial L1. Thus, it is only + applicable for the VNF. + +The change between transport mechanisms is done at compilation time: +- No changes to the `build_oai` call are required in order to select socket communication, as it is the default. +- In order to select WLS as the transport mechanism between VNF and PNF, first install the WLS library, and afterwards use `-t WLS` as a parameter of `build_oai`: + +### How to use nFAPI + +nFAPI is used by default. Compile and configure as indicated above. + +### How to use Aerial + +Refer to [this document](./Aerial_FAPI_Split_Tutorial.md) for more information. + +### How to use WLS lib + +Before the first compilation with WLS support, the [WLS +library](https://docs.o-ran-sc.org/projects/o-ran-sc-o-du-phy/en/latest/wls-lib.html) +must first be compiled and installed to the system. + +The WLS library has a few dependencies: + - [DPDK](https://doc.dpdk.org/guides/prog_guide/build-sdk-meson.html), specifically version [20.11.3](https://fast.dpdk.org/rel/dpdk-20.11.3.tar.xz). + - libelf-dev + - libhugetlbfs-dev + +Additionally, a patch needs to be applied to the WLS lib Makefile in order for +the shared library and headers to be installed into the system, the necessary +patch is available [here](../cmake_targets/tools/install_wls_lib.patch) + +Clone the code and apply the patch + + git clone -b oran_f_release https://gerrit.o-ran-sc.org/r/o-du/phy.git + cd phy/wls_lib/ + git apply ~/openairinterface5g/cmake_targets/tools/install_wls_lib.patch + +Then compile and install the library + + WIRELESS_SDK_TOOLCHAIN=gcc WIRELESS_SDK_TARGET_ISA=avx2 make + sudo WIRELESS_SDK_TOOLCHAIN=gcc WIRELESS_SDK_TARGET_ISA=avx2 make install + +After installing WLS, you can run the build command as shown below: + + ./build_oai -t WLS -w USRP --gNB --nrUE --ninja -C + +#### How to run OAI PNF with OAI VNF + +Refer to the above steps in [Quickstart](#quickstart), but run the PNF first as it is the WLS "master". + +#### How to run OAI PNF with OSC/Radisys O-DU + +Set up the hugepages for DPDK (1GB page size, 6 pages; this only needs to be +done once): + + sudo nano /etc/default/grub + GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_DEFAULT} default_hugepagesz=1G hugepagesz=1G hugepages=6" + +Then rewrite the bootloader and reboot + + sudo update-grub + sudo reboot + +Install dependencies: + + sudo apt-get install libstdc++-14-dev libnsl-dev libpcap-dev libxml2-dev + +Clone the Radisys repository (We're currently using the `oai_integration` branch): + + git clone https://gerrit.o-ran-sc.org/r/o-du/l2 -b oai-integration + +Build the O-DU + + cd ~/l2/build/odu + make clean_all;make odu PHY=INTEL_L1 MACHINE=BIT64 MODE=TDD;make cu_stub NODE=TEST_STUB MACHINE=BIT64 MODE=TDD;make ric_stub NODE=TEST_STUB MACHINE=BIT64 MODE=TDD + +Setup local interfaces for the cu_stub, ric_stub and o_du + + sudo ifconfig enp7s0:ODU "192.168.130.81" && sudo ifconfig enp7s0:CU_STUB "192.168.130.82" && sudo ifconfig enp7s0:RIC_STUB "192.168.130.80" + +Run cu_stu and ric_stub in separate terminals + + cd ~/l2/bin/ + ./cu_stub/cu_stub + clear && ./ric_stub/ric_stub + +Run the OAI PNF first, as it is the WLS memory master + + sudo NFAPI_TRACE_LEVEL=info ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-pnf.band78.rfsim.2x2.conf --nfapi PNF --rfsim --rfsimulator.serveraddr server + +Run the O-DU over GDB + + sudo -E gdb -ex run --readnever --args ./odu/odu + +Note: If you see the following prompt in GDB + + This GDB supports auto-downloading debuginfo from the following URLs: + + Enable debuginfod for this session? (y or [n]) + +You can run the following command one time before executing gdb to disable it: + + export DEBUGINFOD_URLS= + +Run the OAI-UE + + sudo ./nr-uesoftmodem -r 273 --numerology 1 --band 78 -C 3400140000 --ssb 1518 --uicc0.imsi 001010000000001 --rfsim + # nFAPI logging system nFAPI has its own logging system, independent of OAI's. It can be activated by diff --git a/doc/nr-ue-design.md b/doc/nr-ue-design.md index 9ca95c1a00..1648e6b7c5 100644 --- a/doc/nr-ue-design.md +++ b/doc/nr-ue-design.md @@ -15,7 +15,7 @@ The UE exits when at any point in operation it gets out of synchronization. When UE uses actors which are threads dedicated to particular activity. Sync Actor handles initial sync. DL Actors handle DLSCH PHY procedures. UL procedures are are run on the UL Actor -![design](nr-ue-threads.svg) +![design](images/nr-ue-threads.svg) ## Initial Synchronization Block ```mermaid diff --git a/doc/oai_enb_block_diagram.png b/doc/oai_enb_block_diagram.png deleted file mode 100644 index 58c8eb9e95..0000000000 Binary files a/doc/oai_enb_block_diagram.png and /dev/null differ diff --git a/doc/physical-simulators.md b/doc/physical-simulators.md index 662daa2a95..b74531fd20 100644 --- a/doc/physical-simulators.md +++ b/doc/physical-simulators.md @@ -18,6 +18,13 @@ Physims are essential for: * Regression testing * Ensuring correctness before merging new contributions into the repository +These tests are run automatically as part of the following +pipelines: + +- [RAN-PhySim-Cluster-4G](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster-4G/) +- [RAN-PhySim-Cluster-5G](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster-5G/) +- [RAN-PhySim-GraceHopper-5G](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-GraceHopper-5G/) + ## Examples of Simulators | Technology | Simulators | Description | @@ -31,7 +38,7 @@ Physims are essential for: | | `nr_psbchsim` | Sidelink simulation | | Coding | `ldpctest`, `polartest`, `smallblocktest` | LDPC, Polar, and other FEC tests | -### Source Locations +## Source Locations * 4G PHY simulators: `openair1/SIMULATION/LTE_PHY/` * 5G PHY simulators: `openair1/SIMULATION/NR_PHY/` @@ -48,6 +55,9 @@ openair1/SIMULATION/NR_PHY/dlsim.c ## Option 1: Using CMake +Build the simulators and tests using the dedicated cmake option, then run +`ctest` which will run all registered tests. + ```bash cd openairinterface5g mkdir build && cd build @@ -67,9 +77,7 @@ cd ran_build/build ctest ``` -# `ctest` Usage Tips - -## Useful Options +## `ctest` Usage Tips Use the following options to customize test execution: @@ -84,50 +92,77 @@ Use the following options to customize test execution: For the complete list of `ctest` options, refer to the manual: -```bash -man ctest -``` + man ctest -## Example +For instance, to run only all run NR ULSCH simulator tests, with 4 jobs in +parallel, type -```bash -# Run only NR ULSCH simulator tests, in parallel -ctest -L nr_ulsch -j 4 -``` + ctest -L nr_ulschsim -j 4 # Adding a New Physim Test To define a new test or modify existing ones, update the following file: ``` -openair1/PHY/CODING/tests/CMakeLists.txt +openair1/SIMULATION/tests/CMakeLists.txt ``` -Use the `add_physim_test` macro with the following arguments: +## `add_physim_test()` -```cmake -add_physim_test( ) -``` +Use the `add_physim_test()` macro with the following arguments: -### Arguments: + add_physim_test( ) -* ``: Test generation (e.g., `4g` or `5g`) -* ``: Name of the test executable (e.g., `nr_prachsim`) -* ``: Description shown in `ctest` output, useful for categorization and indexing. -* ``: Label used for filtering tests (via `-L`), shown in the ctest output summary as a descriptive tag. -* ``: Command line options passed to the test +where: +- `` can be any name, but the canonical, historical format is to put + it `physim...test` where `` is 4g/5g, and `` + is an increasing number +- `` is a human-readable description of the test +- ` ` is the test invocation, where `` must + be a target built by OAI cmake (e.g., `nr_prachsim`), followed by any options. -### Example: +For instance, a PRACHsim looks like this: -```cmake -# add_physim_test( ) -add_physim_test(5g nr_prachsim test8 "15kHz SCS, 25 PRBs" -a -s -30 -n 300 -p 99 -R 25 -m 0) -``` + add_physim_test(physim.5g.nr_prachsim.test8 "15kHz SCS, 25 PRBs" nr_prachsim -a -s -30 -n 300 -p 99 -R 25 -m 0) -These tests are run automatically as part of the following -pipelines: [RAN-PhySim-Cluster-4G](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster-4G/) and [RAN-PhySim-Cluster-5G](https://jenkins-oai.eurecom.fr/job/RAN-PhySim-Cluster-5G/) +## `add_timed_physim_test()` -### How to rerun failed CI tests using `ctest` +Use the `add_timed_physim_test()` macro to add a test the same way as with +`add_physim_test()` above. Additionally, it allows to check for thresholds with +`check_threshold()`: + + check_threshold( ) + +where: +- `` is any test that must have been added with + `add_timed_physim_test()` +- `` is a threshold to check for, e.g., `PHY tx proc`, and +- `` a condition to check, e.g. `< 200` + +There are two convenience functions to simplify the use of `check_threshold()`: + + check_threshold_range( LOWER UPPER ) + check_threshold_variance( AVG ABS_VAR ) + +where +- `` and `` are a lower and upper threshold, respectively, where + either one or both variables can be provided, and +- `` and `` are average and the variation in absolute numbers + (not a percentage!) can be provided. + +Both functions internally use `check_threshold()`. + +Thus upon execution of the test, the test will be run, but additionally ctest +will check for a match of `PHY tx proc ` (where ` is of format +`[0-9]+(\.[0-9]+)?`), and a matching number will be checked against condition +`< 200`. + +For instance, this could look like this: + + add_timed_physim_test(physim.5g.nr_dlsim.test3 "Some description" nr_dlsim -P) + check_physim_threshold(physim.5g.nr_dlsim.test3 "DLSCH encoding time" "< 50") + +# How to rerun failed CI tests using `ctest` Ctest automatically logs the failed tests in LastTestsFailed.log. This log is archived in the CI artifacts and can be reused locally to rerun only those failed tests. @@ -159,3 +194,11 @@ For legacy support or archival purposes, you can still find this implementation ```bash git checkout 2025.w18 ``` + +# Unmaintained tests + +A few tests dedicated to 4G are unmaintained: + +- `mbmssim` +- `scansim` +- all simulators of format `www-tmyyyy` (for instance, `dlsim_tm4`) diff --git a/doc/testing_gnb_w_cots_ue_resources/enb.conf b/doc/testing_oai_nsa_w_cots_ue_resources/enb.conf similarity index 100% rename from doc/testing_gnb_w_cots_ue_resources/enb.conf rename to doc/testing_oai_nsa_w_cots_ue_resources/enb.conf diff --git a/doc/testing_gnb_w_cots_ue_resources/gnb.conf b/doc/testing_oai_nsa_w_cots_ue_resources/gnb.conf similarity index 98% rename from doc/testing_gnb_w_cots_ue_resources/gnb.conf rename to doc/testing_oai_nsa_w_cots_ue_resources/gnb.conf index 44d339c951..c9cc393abc 100755 --- a/doc/testing_gnb_w_cots_ue_resources/gnb.conf +++ b/doc/testing_oai_nsa_w_cots_ue_resources/gnb.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/doc/testing_gnb_w_cots_ue_resources/oai_enb.log b/doc/testing_oai_nsa_w_cots_ue_resources/oai_enb.log similarity index 100% rename from doc/testing_gnb_w_cots_ue_resources/oai_enb.log rename to doc/testing_oai_nsa_w_cots_ue_resources/oai_enb.log diff --git a/doc/testing_gnb_w_cots_ue_resources/oai_fr1_setup.vsdx b/doc/testing_oai_nsa_w_cots_ue_resources/oai_fr1_setup.vsdx similarity index 100% rename from doc/testing_gnb_w_cots_ue_resources/oai_fr1_setup.vsdx rename to doc/testing_oai_nsa_w_cots_ue_resources/oai_fr1_setup.vsdx diff --git a/doc/testing_gnb_w_cots_ue_resources/oai_gnb.log b/doc/testing_oai_nsa_w_cots_ue_resources/oai_gnb.log similarity index 100% rename from doc/testing_gnb_w_cots_ue_resources/oai_gnb.log rename to doc/testing_oai_nsa_w_cots_ue_resources/oai_gnb.log diff --git a/docker/Dockerfile.base.rhel9 b/docker/Dockerfile.base.rhel9 index 28992918e2..dde540556b 100644 --- a/docker/Dockerfile.base.rhel9 +++ b/docker/Dockerfile.base.rhel9 @@ -32,7 +32,7 @@ ARG NEEDED_GIT_PROXY ARG TARGETARCH ENV TZ=Europe/Paris ENV BUILD_UHD_FROM_SOURCE=True -ENV UHD_VERSION=4.4.0.0 +ENV UHD_VERSION=4.8.0.0 # Copy the entitlements COPY ./etc-pki-entitlement /etc/pki/entitlement diff --git a/docker/Dockerfile.base.rocky b/docker/Dockerfile.base.rocky index 2d83389418..98a9ef703a 100644 --- a/docker/Dockerfile.base.rocky +++ b/docker/Dockerfile.base.rocky @@ -30,7 +30,7 @@ FROM $BASE_IMAGE AS ran-base ARG TARGETARCH ENV TZ=Europe/Paris ENV BUILD_UHD_FROM_SOURCE=True -ENV UHD_VERSION=4.4.0.0 +ENV UHD_VERSION=4.8.0.0 RUN dnf install 'dnf-command(config-manager)' -y && \ dnf install epel-release -y && crb enable && \ diff --git a/docker/Dockerfile.base.ubuntu b/docker/Dockerfile.base.ubuntu index 2928040331..e0fbacf09e 100644 --- a/docker/Dockerfile.base.ubuntu +++ b/docker/Dockerfile.base.ubuntu @@ -14,8 +14,6 @@ RUN apt-get update && \ ccache \ psmisc \ git \ - gcc-12 \ - g++-12 \ xxd \ libpcre2-dev \ python3-dev \ @@ -45,6 +43,7 @@ COPY cmake_targets/build_oai . WORKDIR /oai-ran COPY oaienv . +#run build_oai -I to get the builder image RUN /bin/sh oaienv && \ cd cmake_targets && \ mkdir -p log && \ diff --git a/docker/Dockerfile.base.ubuntu22.cross-arm64 b/docker/Dockerfile.base.ubuntu.cross-arm64 similarity index 79% rename from docker/Dockerfile.base.ubuntu22.cross-arm64 rename to docker/Dockerfile.base.ubuntu.cross-arm64 index 1bcba7bdd6..1365df71fe 100644 --- a/docker/Dockerfile.base.ubuntu22.cross-arm64 +++ b/docker/Dockerfile.base.ubuntu.cross-arm64 @@ -21,12 +21,12 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 to cross-compile for ARM64 +# Valid for Ubuntu 24.04 to cross-compile for ARM64 # #--------------------------------------------------------------------- -# Very important, the jammy image shall not be using mirrors. A lot of them do NOT support ARM64. -FROM ubuntu:jammy AS ran-base +# Very important, the noble image shall not be using mirrors. A lot of them do NOT support ARM64. +FROM ubuntu:noble AS ran-base ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe/Paris # Specifying a working version of SIMDE for ARM: @@ -34,22 +34,23 @@ ENV SIMDE_VERSION=389f360a66d4a3bec62b7d71ad8be877487809ba #install developers pkg/repo RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ + apt-get upgrade --yes && \ #enabling arm64 architecture dpkg --add-architecture arm64 && \ - echo "deb [arch=arm64] http://ports.ubuntu.com/ jammy main restricted\n" \ - "deb [arch=arm64] http://ports.ubuntu.com/ jammy-updates main restricted\n" \ - "deb [arch=arm64] http://ports.ubuntu.com/ jammy universe\n" \ - "deb [arch=arm64] http://ports.ubuntu.com/ jammy-updates universe\n" \ - "deb [arch=arm64] http://ports.ubuntu.com/ jammy multiverse\n" \ - "deb [arch=arm64] http://ports.ubuntu.com/ jammy-updates multiverse\n" \ - "deb [arch=arm64] http://ports.ubuntu.com/ jammy-backports main restricted universe multiverse" \ + echo "deb [arch=arm64] http://ports.ubuntu.com/ noble main restricted\n" \ + "deb [arch=arm64] http://ports.ubuntu.com/ noble-updates main restricted\n" \ + "deb [arch=arm64] http://ports.ubuntu.com/ noble universe\n" \ + "deb [arch=arm64] http://ports.ubuntu.com/ noble-updates universe\n" \ + "deb [arch=arm64] http://ports.ubuntu.com/ noble multiverse\n" \ + "deb [arch=arm64] http://ports.ubuntu.com/ noble-updates multiverse\n" \ + "deb [arch=arm64] http://ports.ubuntu.com/ noble-backports main restricted universe multiverse" \ | tee /etc/apt/sources.list.d/arm-cross-compile-sources.list && \ cp /etc/apt/sources.list "/etc/apt/sources.list.`date`.backup" && \ sed -i -E "s/(deb)\ (http:.+)/\1\ [arch=amd64]\ \2/" /etc/apt/sources.list && \ + sed -i '/^Components:/a Architectures: amd64' /etc/apt/sources.list.d/ubuntu.sources && \ apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ build-essential \ psmisc \ git \ @@ -69,8 +70,8 @@ RUN apt-get update && \ libyaml-cpp-dev:arm64 \ # cross build libs and compilers libc6-dev-i386 \ - gcc-11-aarch64-linux-gnu \ - g++-11-aarch64-linux-gnu && \ + gcc-aarch64-linux-gnu \ + g++-aarch64-linux-gnu && \ apt-get clean # Add "Tini - A tiny but valid init for containers", https://github.com/krallin/tini diff --git a/docker/Dockerfile.build.fhi72.native_arm.ubuntu22 b/docker/Dockerfile.build.fhi72.native_arm.ubuntu similarity index 92% rename from docker/Dockerfile.build.fhi72.native_arm.ubuntu22 rename to docker/Dockerfile.build.fhi72.native_arm.ubuntu index 4ea1bcd7bb..96f50fa485 100644 --- a/docker/Dockerfile.build.fhi72.native_arm.ubuntu22 +++ b/docker/Dockerfile.build.fhi72.native_arm.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface RAN Build for FHI 7.2 -# Valid for UBUNTU 22.04 +# Valid for UBUNTU 24.04 # #--------------------------------------------------------------------- @@ -32,8 +32,8 @@ ARG KPM_VERSION=KPM_V3_00 ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ meson \ wget \ xz-utils \ @@ -78,7 +78,7 @@ RUN /bin/sh oaienv && \ cd cmake_targets && \ mkdir -p log && \ ./build_oai \ - --gNB \ + --ninja --gNB \ --build-lib "telnetsrv enbscope uescope nrscope" \ -t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \ --build-e2 --cmake-opt -DXAPP_MULTILANGUAGE=OFF --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \ @@ -94,8 +94,6 @@ RUN mkdir -p openair2/E2AP/flexric/build && \ cmake -GNinja -DCMAKE_BUILD_TYPE=Release \ -DXAPP_MULTILANGUAGE=OFF \ -DKPM_VERSION=$KPM_VERSION \ - -DE2AP_VERSION=$E2AP_VERSION \ - -DCMAKE_C_COMPILER=gcc-12 \ - -DCMAKE_CXX_COMPILER=g++-12 .. && \ + -DE2AP_VERSION=$E2AP_VERSION .. && \ ninja && \ ninja install diff --git a/docker/Dockerfile.build.fhi72.rhel9 b/docker/Dockerfile.build.fhi72.rhel9 index b8ad1560ba..472378935d 100644 --- a/docker/Dockerfile.build.fhi72.rhel9 +++ b/docker/Dockerfile.build.fhi72.rhel9 @@ -58,7 +58,7 @@ RUN /bin/sh oaienv && \ mkdir -p log && \ scl enable gcc-toolset-13 "\ ./build_oai \ - --gNB \ + --ninja --gNB \ --build-lib 'telnetsrv enbscope uescope nrscope' \ -t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \ --build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION" &&\ diff --git a/docker/Dockerfile.build.fhi72.ubuntu22 b/docker/Dockerfile.build.fhi72.ubuntu similarity index 91% rename from docker/Dockerfile.build.fhi72.ubuntu22 rename to docker/Dockerfile.build.fhi72.ubuntu index 5da6d0b608..7b3ade05b0 100644 --- a/docker/Dockerfile.build.fhi72.ubuntu22 +++ b/docker/Dockerfile.build.fhi72.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface RAN Build for FHI 7.2 -# Valid for UBUNTU 22.04 +# Valid for UBUNTU 24.04 # #--------------------------------------------------------------------- @@ -32,8 +32,8 @@ ARG KPM_VERSION=KPM_V3_00 ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ meson \ wget \ xz-utils \ @@ -68,7 +68,7 @@ RUN /bin/sh oaienv && \ cd cmake_targets && \ mkdir -p log && \ ./build_oai \ - --gNB \ + --ninja --gNB \ --build-lib "telnetsrv enbscope uescope nrscope" \ -t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \ --build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \ @@ -83,8 +83,6 @@ RUN mkdir -p openair2/E2AP/flexric/build && \ cd openair2/E2AP/flexric/build && \ cmake -GNinja -DCMAKE_BUILD_TYPE=Release \ -DKPM_VERSION=$KPM_VERSION \ - -DE2AP_VERSION=$E2AP_VERSION \ - -DCMAKE_C_COMPILER=gcc-12 \ - -DCMAKE_CXX_COMPILER=g++-12 .. && \ + -DE2AP_VERSION=$E2AP_VERSION .. && \ ninja && \ ninja install diff --git a/docker/Dockerfile.build.ubuntu22.cross-arm64 b/docker/Dockerfile.build.ubuntu.cross-arm64 similarity index 74% rename from docker/Dockerfile.build.ubuntu22.cross-arm64 rename to docker/Dockerfile.build.ubuntu.cross-arm64 index 78c7a64f64..b7bc7d6dbb 100644 --- a/docker/Dockerfile.build.ubuntu22.cross-arm64 +++ b/docker/Dockerfile.build.ubuntu.cross-arm64 @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 to cross-compile for ARM64 +# Valid for Ubuntu 24.04 to cross-compile for ARM64 # #--------------------------------------------------------------------- @@ -37,20 +37,11 @@ RUN /bin/sh oaienv && \ mkdir -p log ran_build/build ran_build/build-cross && \ cd ran_build/build && \ cmake ../../.. -GNinja && \ - echo "====== Start of log for host-tools ======" && \ - ninja ldpc_generators generate_T > ../../log/host-tools.txt 2>&1 && \ - echo "====== End of log for host-tools ======" && \ + ninja ldpc_generators generate_T && \ cd ../build-cross/ && \ # install missing libyaml-cpp-dev for arm64 apt install -y libyaml-cpp-dev:arm64 && \ cmake ../../.. -GNinja -DENABLE_TELNETSRV=ON \ -DCMAKE_TOOLCHAIN_FILE=../../../cmake_targets/cross-arm.cmake -DNATIVE_DIR=../build \ -DCMAKE_C_FLAGS="-Werror" -DCMAKE_CXX_FLAGS="-Werror" && \ - echo "====== Start of log for cross-build executables ======" && \ - # making always passing so we can analyze the all.txt file - ninja -k10 dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim lte-softmodem nr-softmodem nr-cuup oairu lte-uesoftmodem nr-uesoftmodem params_libconfig coding rfsimulator telnetsrv > ../../log/all.txt 2>&1; \ - # displaying errors and warnings - grep -E -A3 "warning:|error:" ../../log/all.txt || true && \ - # will fail only if string "errors:" is found - grep -E "error:" -vqz ../../log/all.txt && \ - echo "====== End of log for cross-build executables ======" + ninja -k10 dlsim ulsim ldpctest polartest smallblocktest nr_pbchsim nr_dlschsim nr_ulschsim nr_dlsim nr_ulsim nr_pucchsim nr_prachsim lte-softmodem nr-softmodem nr-cuup oairu lte-uesoftmodem nr-uesoftmodem params_libconfig coding rfsimulator telnetsrv diff --git a/docker/Dockerfile.eNB.rhel9 b/docker/Dockerfile.eNB.rhel9 index 391f2a6594..3cd1018634 100644 --- a/docker/Dockerfile.eNB.rhel9 +++ b/docker/Dockerfile.eNB.rhel9 @@ -90,7 +90,7 @@ COPY --from=enb-base \ # Now we are copying from builder-image the UHD files. COPY --from=enb-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=enb-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=enb-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=enb-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-enb/bin WORKDIR /usr/local/share/uhd/rfnoc @@ -111,7 +111,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/liboai_iqplayer.so \ /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_enb.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-enb diff --git a/docker/Dockerfile.eNB.rocky b/docker/Dockerfile.eNB.rocky index eee61a7dda..1ff2b42e7a 100644 --- a/docker/Dockerfile.eNB.rocky +++ b/docker/Dockerfile.eNB.rocky @@ -91,7 +91,7 @@ COPY --from=enb-base \ # Now we are copying from builder-image the UHD files. COPY --from=enb-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=enb-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=enb-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=enb-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-enb/bin WORKDIR /usr/local/share/uhd/rfnoc @@ -112,7 +112,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/liboai_iqplayer.so \ /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_enb.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-enb diff --git a/docker/Dockerfile.eNB.ubuntu22 b/docker/Dockerfile.eNB.ubuntu similarity index 83% rename from docker/Dockerfile.eNB.ubuntu22 rename to docker/Dockerfile.eNB.ubuntu index 44797cd7f5..d0312f8cce 100644 --- a/docker/Dockerfile.eNB.ubuntu22 +++ b/docker/Dockerfile.eNB.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 +# Valid for Ubuntu 24.04 # #--------------------------------------------------------------------- @@ -31,25 +31,25 @@ FROM ran-build:latest AS enb-build #start from scratch for target executable -FROM ubuntu:jammy AS oai-enb +FROM ubuntu:noble AS oai-enb ARG BUILD_OPTION ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe/Paris RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ software-properties-common \ procps \ libsctp1 \ - libboost-chrono1.74.0 \ - libboost-date-time1.74.0 \ - libboost-filesystem1.74.0 \ - libboost-regex1.74.0 \ - libboost-serialization1.74.0 \ - libboost-thread1.74.0 \ - libboost-system1.74.0 \ - libboost-program-options1.74.0 \ + libboost-chrono1.83.0 \ + libboost-date-time1.83.0 \ + libboost-filesystem1.83.0 \ + libboost-regex1.83.0 \ + libboost-serialization1.83.0 \ + libboost-thread1.83.0 \ + libboost-system1.83.0 \ + libboost-program-options1.83.0 \ tzdata \ libblas3 \ libconfig9 \ @@ -73,18 +73,12 @@ RUN apt-get update && \ apt-get remove -y wget && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - #libasan5 \ # see below + libasan8 \ libubsan1 \ liblapacke; fi' && \ apt-get clean -y && \ rm -rf /var/lib/apt/lists/* -# we select another compile (gcc-12) for compilation, requiring another libasan -# library version. Installing it above would install the wrong version. Hence, -# copy the right version from ran-build. When upgrading to Ubuntu24, install -# the correct one above! -COPY --from=enb-build /usr/lib/x86_64-linux-gnu/libasan.so.8.0.0 /usr/lib/x86_64-linux-gnu/ - WORKDIR /opt/oai-enb/bin COPY --from=enb-build \ /oai-ran/cmake_targets/ran_build/build/lte-softmodem ./ @@ -104,7 +98,7 @@ COPY --from=enb-build \ # Now we are copying from builder-image the UHD files. COPY --from=enb-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=enb-base /usr/local/lib/libuhd.so.4.4.0 /usr/local/lib +COPY --from=enb-base /usr/local/lib/libuhd.so.4.8.0 /usr/local/lib COPY --from=enb-base /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-enb/bin RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai_device.so" && \ @@ -121,7 +115,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/liboai_iqplayer.so \ /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_enb.so \ - /usr/local/lib/libuhd.so.4.4.0 + /usr/local/lib/libuhd.so.4.8.0 WORKDIR /opt/oai-enb diff --git a/docker/Dockerfile.gNB.aerial.ubuntu22 b/docker/Dockerfile.gNB.aerial.ubuntu similarity index 94% rename from docker/Dockerfile.gNB.aerial.ubuntu22 rename to docker/Dockerfile.gNB.aerial.ubuntu index c5b090f551..04bed658fe 100644 --- a/docker/Dockerfile.gNB.aerial.ubuntu22 +++ b/docker/Dockerfile.gNB.aerial.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 +# Valid for Ubuntu 24.04 # #--------------------------------------------------------------------- @@ -45,7 +45,7 @@ WORKDIR /oai-ran COPY . . RUN /bin/sh oaienv && \ - tar -xvzf nvipc_src.*.tar.gz && \ + tar -xvzf nvipc_src.*.tar.gz && \ cd nvipc_src.* && \ rm -rf build && mkdir build && cd build && \ cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \ @@ -59,13 +59,13 @@ RUN /bin/sh oaienv && \ #start from scratch for target executable -FROM ubuntu:jammy AS oai-gnb-aerial +FROM ubuntu:noble AS oai-gnb-aerial ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ software-properties-common \ procps \ libsctp1 \ diff --git a/docker/Dockerfile.gNB.aerial.ubuntu22.sanitize-address b/docker/Dockerfile.gNB.aerial.ubuntu.sanitize-address similarity index 94% rename from docker/Dockerfile.gNB.aerial.ubuntu22.sanitize-address rename to docker/Dockerfile.gNB.aerial.ubuntu.sanitize-address index 4d613718b4..07b6d7111b 100644 --- a/docker/Dockerfile.gNB.aerial.ubuntu22.sanitize-address +++ b/docker/Dockerfile.gNB.aerial.ubuntu.sanitize-address @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 +# Valid for Ubuntu 24.04 # #--------------------------------------------------------------------- @@ -45,7 +45,7 @@ WORKDIR /oai-ran COPY . . RUN /bin/sh oaienv && \ - tar -xvzf nvipc_src.*.tar.gz && \ + tar -xvzf nvipc_src.*.tar.gz && \ cd nvipc_src.* && \ rm -rf build && mkdir build && cd build && \ cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \ @@ -58,13 +58,13 @@ RUN /bin/sh oaienv && \ #start from scratch for target executable -FROM ubuntu:jammy AS oai-gnb-aerial +FROM ubuntu:noble AS oai-gnb-aerial ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ software-properties-common \ procps \ libsctp1 \ diff --git a/docker/Dockerfile.gNB.aw2s.ubuntu22 b/docker/Dockerfile.gNB.aw2s.ubuntu similarity index 95% rename from docker/Dockerfile.gNB.aw2s.ubuntu22 rename to docker/Dockerfile.gNB.aw2s.ubuntu index 11893171db..b55977dfab 100644 --- a/docker/Dockerfile.gNB.aw2s.ubuntu22 +++ b/docker/Dockerfile.gNB.aw2s.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 +# Valid for Ubuntu 24.04 # #--------------------------------------------------------------------- @@ -38,13 +38,13 @@ RUN /bin/sh oaienv && \ ./build_oai -w AW2SORI -t Ethernet #start from scratch for target executable -FROM ubuntu:jammy as oai-gnb-aw2s +FROM ubuntu:noble AS oai-gnb-aw2s ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ procps \ libsctp1 \ tzdata \ diff --git a/docker/Dockerfile.gNB.fhi72.rhel9 b/docker/Dockerfile.gNB.fhi72.rhel9 index 5f68599873..122b3b668d 100644 --- a/docker/Dockerfile.gNB.fhi72.rhel9 +++ b/docker/Dockerfile.gNB.fhi72.rhel9 @@ -71,6 +71,7 @@ WORKDIR /opt/oai-gnb/bin COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh +COPY ./docker/scripts/check-prach-io.sh ./check-prach-io.sh COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/librfsimulator.so \ diff --git a/docker/Dockerfile.gNB.fhi72.rocky b/docker/Dockerfile.gNB.fhi72.rocky index 3fdc2f97af..f95310059d 100644 --- a/docker/Dockerfile.gNB.fhi72.rocky +++ b/docker/Dockerfile.gNB.fhi72.rocky @@ -59,6 +59,7 @@ WORKDIR /opt/oai-gnb/bin COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh +COPY ./docker/scripts/check-prach-io.sh ./check-prach-io.sh COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/librfsimulator.so \ diff --git a/docker/Dockerfile.gNB.fhi72.ubuntu22 b/docker/Dockerfile.gNB.fhi72.ubuntu similarity index 95% rename from docker/Dockerfile.gNB.fhi72.ubuntu22 rename to docker/Dockerfile.gNB.fhi72.ubuntu index 069055d63b..fb9d1d43f7 100644 --- a/docker/Dockerfile.gNB.fhi72.ubuntu22 +++ b/docker/Dockerfile.gNB.fhi72.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface 7.2 Fronthaul -# Valid for Ubuntu22.04 +# Valid for Ubuntu24.04 # #--------------------------------------------------------------------- @@ -31,14 +31,14 @@ FROM ran-build-fhi72:latest AS gnb-build #start from scratch for target executable -FROM ubuntu:jammy AS oai-gnb +FROM ubuntu:noble AS oai-gnb ARG BUILD_OPTION ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ software-properties-common \ procps \ pkg-config \ @@ -62,7 +62,7 @@ RUN apt-get update && \ libyaml-cpp-dev && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - libasan5 \ + libasan8 \ libubsan1 \ liblapacke; fi' && \ rm -rf /var/lib/apt/lists/* @@ -71,6 +71,7 @@ WORKDIR /opt/oai-gnb/bin COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh +COPY ./docker/scripts/check-prach-io.sh ./check-prach-io.sh COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/librfsimulator.so \ diff --git a/docker/Dockerfile.gNB.rhel9 b/docker/Dockerfile.gNB.rhel9 index 824e3b3833..1c201eeeab 100644 --- a/docker/Dockerfile.gNB.rhel9 +++ b/docker/Dockerfile.gNB.rhel9 @@ -60,6 +60,7 @@ WORKDIR /opt/oai-gnb/bin COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh +COPY ./docker/scripts/check-prach-io.sh ./check-prach-io.sh COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/liboai_eth_transpro.so \ @@ -96,7 +97,7 @@ COPY --from=gnb-base \ # Now we are copying from builder-image the UHD files. COPY --from=gnb-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=gnb-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=gnb-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=gnb-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-gnb/bin ## Copy E2 SM models @@ -119,7 +120,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libldpc*.so \ /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_ci.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-gnb #EXPOSE 2152/udp # S1U, GTP/UDP diff --git a/docker/Dockerfile.gNB.rocky b/docker/Dockerfile.gNB.rocky index 225432fdab..d005c36c9f 100644 --- a/docker/Dockerfile.gNB.rocky +++ b/docker/Dockerfile.gNB.rocky @@ -57,6 +57,7 @@ WORKDIR /opt/oai-gnb/bin COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh +COPY ./docker/scripts/check-prach-io.sh ./check-prach-io.sh COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/liboai_eth_transpro.so \ @@ -93,7 +94,7 @@ COPY --from=gnb-base \ # Now we are copying from builder-image the UHD files. COPY --from=gnb-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=gnb-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=gnb-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=gnb-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-gnb/bin WORKDIR /usr/local/share/uhd/rfnoc @@ -113,7 +114,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libldpc*.so \ /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_ci.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-gnb #EXPOSE 2152/udp # S1U, GTP/UDP diff --git a/docker/Dockerfile.gNB.ubuntu22 b/docker/Dockerfile.gNB.ubuntu similarity index 75% rename from docker/Dockerfile.gNB.ubuntu22 rename to docker/Dockerfile.gNB.ubuntu index 68c903450a..2259aa39c9 100644 --- a/docker/Dockerfile.gNB.ubuntu22 +++ b/docker/Dockerfile.gNB.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu20.04 +# Valid for Ubuntu24.04 # #--------------------------------------------------------------------- @@ -31,25 +31,25 @@ FROM ran-build:latest AS gnb-build #start from scratch for target executable -FROM ubuntu:jammy AS oai-gnb +FROM ubuntu:noble AS oai-gnb ARG BUILD_OPTION ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe/Paris RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ software-properties-common \ procps \ libsctp1 \ - libboost-chrono1.74.0 \ - libboost-date-time1.74.0 \ - libboost-filesystem1.74.0 \ - libboost-regex1.74.0 \ - libboost-serialization1.74.0 \ - libboost-thread1.74.0 \ - libboost-system1.74.0 \ - libboost-program-options1.74.0 \ + libboost-chrono1.83.0 \ + libboost-date-time1.83.0 \ + libboost-filesystem1.83.0 \ + libboost-regex1.83.0 \ + libboost-serialization1.83.0 \ + libboost-thread1.83.0 \ + libboost-system1.83.0 \ + libboost-program-options1.83.0 \ tzdata \ libblas3 \ libconfig9 \ @@ -67,33 +67,17 @@ RUN apt-get update && \ libyaml-cpp-dev && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - #libasan5 \ # see below + libasan8 \ libubsan1 \ liblapacke; fi' && \ apt-get clean -y && \ rm -rf /var/lib/apt/lists/* -# we select another compile (gcc-12) for compilation, requiring another libasan -# library version. Installing it above would install the wrong version. Hence, -# copy the right version from ran-build. When upgrading to Ubuntu24, install -# the correct one above! -# note: this dockerfile should work for both x86 and arm, hence the glob below -# which should either match "x86_64" (x86) or "aarch64" (ARM); since the target -# directory needs to be also one of those two, but globs don't work in target -# directories, work around this with mv -COPY --from=gnb-build /usr/lib/*-linux-gnu/libasan.so.8.0.0 /usr/lib/ -ARG TARGETPLATFORM -RUN case "${TARGETPLATFORM}" in \ - "linux/amd64") TARGET_DIR=x86_64-linux-gnu ;; \ - "linux/arm64") TARGET_DIR=aarch64-linux-gnu ;; \ - *) exit 1 ;; \ - esac; \ - mv /usr/lib/libasan.so.8.0.0 /usr/lib/$TARGET_DIR/libasan.so.8.0.0 - WORKDIR /opt/oai-gnb/bin COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh +COPY ./docker/scripts/check-prach-io.sh ./check-prach-io.sh COPY --from=gnb-build \ /oai-ran/cmake_targets/ran_build/build/liboai_eth_transpro.so \ @@ -115,7 +99,7 @@ COPY --from=gnb-build \ # Now we are copying from builder-image the UHD files. COPY --from=gnb-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=gnb-base /usr/local/lib/libuhd.so.4.4.0 /usr/local/lib +COPY --from=gnb-base /usr/local/lib/libuhd.so.4.8.0 /usr/local/lib COPY --from=gnb-base /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-gnb/bin ## Copy E2 SM models COPY --from=gnb-build /usr/local/lib/flexric /usr/local/lib/flexric @@ -134,7 +118,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libldpc*.so \ /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_ci.so \ - /usr/local/lib/libuhd.so.4.4.0 + /usr/local/lib/libuhd.so.4.8.0 WORKDIR /opt/oai-gnb #EXPOSE 2152/udp # S1U, GTP/UDP diff --git a/docker/Dockerfile.lteRU.rhel9 b/docker/Dockerfile.lteRU.rhel9 index 18ef1e8cfd..736ae2a884 100644 --- a/docker/Dockerfile.lteRU.rhel9 +++ b/docker/Dockerfile.lteRU.rhel9 @@ -80,7 +80,7 @@ COPY --from=ru-base \ # Copying from the ran-build image the USRP needed packages COPY --from=ru-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=ru-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=ru-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=ru-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ru/bin WORKDIR /usr/local/share/uhd/rfnoc @@ -96,7 +96,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/liboai_usrpdevif.so \ /usr/local/lib/libparams_libconfig.so \ /usr/local/lib/libdfts.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-lte-ru diff --git a/docker/Dockerfile.lteRU.ubuntu22 b/docker/Dockerfile.lteRU.ubuntu similarity index 80% rename from docker/Dockerfile.lteRU.ubuntu22 rename to docker/Dockerfile.lteRU.ubuntu index 0f5f68932a..dbfc94055a 100644 --- a/docker/Dockerfile.lteRU.ubuntu22 +++ b/docker/Dockerfile.lteRU.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 +# Valid for Ubuntu 24.04 # #--------------------------------------------------------------------- @@ -31,16 +31,24 @@ FROM ran-build:latest AS ru-build #start from scratch for target executable -FROM ubuntu:jammy AS oai-lte-ru +FROM ubuntu:noble AS oai-lte-ru ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe/Paris RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ tzdata \ procps \ software-properties-common \ + libboost-chrono1.83.0 \ + libboost-date-time1.83.0 \ + libboost-filesystem1.83.0 \ + libboost-regex1.83.0 \ + libboost-serialization1.83.0 \ + libboost-thread1.83.0 \ + libboost-system1.83.0 \ + libboost-program-options1.83.0 \ libblas3 \ libconfig9 \ net-tools \ @@ -68,18 +76,9 @@ COPY --from=ru-build \ # Now we are copying from builder-image the UHD files. COPY --from=ru-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=ru-base /usr/local/lib/libuhd.so.4.4.0 /usr/local/lib +COPY --from=ru-base /usr/local/lib/libuhd.so.4.8.0 /usr/local/lib COPY --from=ru-base /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ru/bin -COPY --from=ru-base \ - /usr/lib/x86_64-linux-gnu/libboost_chrono.so.1.74.0 \ - /usr/lib/x86_64-linux-gnu/libboost_date_time.so.1.74.0 \ - /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.74.0 \ - /usr/lib/x86_64-linux-gnu/libboost_regex.so.1.74.0 \ - /usr/lib/x86_64-linux-gnu/libboost_serialization.so.1.74.0 \ - /usr/lib/x86_64-linux-gnu/libboost_thread.so.1.74.0 \ - /usr/lib/x86_64-linux-gnu/libboost_system.so.1.74.0 \ - /usr/lib/x86_64-linux-gnu/ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai_device.so" && \ ldconfig && \ @@ -91,7 +90,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/liboai_usrpdevif.so \ /usr/local/lib/libparams_libconfig.so \ /usr/local/lib/libdfts.so \ - /usr/local/lib/libuhd.so.4.4.0 + /usr/local/lib/libuhd.so.4.8.0 WORKDIR /opt/oai-lte-ru diff --git a/docker/Dockerfile.lteUE.rhel9 b/docker/Dockerfile.lteUE.rhel9 index 9ddf9e1f32..7f1199c897 100644 --- a/docker/Dockerfile.lteUE.rhel9 +++ b/docker/Dockerfile.lteUE.rhel9 @@ -55,9 +55,9 @@ RUN dnf update -y && \ WORKDIR /opt/oai-lte-ue/bin COPY --from=lte-ue-build \ /oai-ran/cmake_targets/ran_build/build/lte-uesoftmodem \ - /oai-ran/cmake_targets/nas_sim_tools/build/conf2uedata \ - /oai-ran/cmake_targets/nas_sim_tools/build/nvram \ - /oai-ran/cmake_targets/nas_sim_tools/build/usim \ + /oai-ran/cmake_targets/ran_build/build/conf2uedata \ + /oai-ran/cmake_targets/ran_build/build/nvram \ + /oai-ran/cmake_targets/ran_build/build/usim \ ./ COPY ./docker/scripts/lte_ue_entrypoint.sh ./entrypoint.sh @@ -95,7 +95,7 @@ COPY --from=lte-ue-base \ # Now we are copying from builder-image the UHD files. COPY --from=lte-ue-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=lte-ue-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=lte-ue-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=lte-ue-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ue/bin WORKDIR /usr/local/share/uhd/rfnoc @@ -113,7 +113,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libparams_libconfig.so \ /usr/local/lib/libdfts.so \ /usr/local/lib/libtelnetsrv.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-lte-ue COPY --from=lte-ue-base /tini /tini diff --git a/docker/Dockerfile.lteUE.rocky b/docker/Dockerfile.lteUE.rocky index 4d98776c1d..5f968b266a 100644 --- a/docker/Dockerfile.lteUE.rocky +++ b/docker/Dockerfile.lteUE.rocky @@ -56,9 +56,9 @@ RUN dnf update -y && \ WORKDIR /opt/oai-lte-ue/bin COPY --from=lte-ue-build \ /oai-ran/cmake_targets/ran_build/build/lte-uesoftmodem \ - /oai-ran/cmake_targets/nas_sim_tools/build/conf2uedata \ - /oai-ran/cmake_targets/nas_sim_tools/build/nvram \ - /oai-ran/cmake_targets/nas_sim_tools/build/usim \ + /oai-ran/cmake_targets/ran_build/build/conf2uedata \ + /oai-ran/cmake_targets/ran_build/build/nvram \ + /oai-ran/cmake_targets/ran_build/build/usim \ ./ COPY ./docker/scripts/lte_ue_entrypoint.sh ./entrypoint.sh @@ -96,7 +96,7 @@ COPY --from=lte-ue-base \ # Now we are copying from builder-image the UHD files. COPY --from=lte-ue-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=lte-ue-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=lte-ue-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=lte-ue-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ue/bin WORKDIR /usr/local/share/uhd/rfnoc @@ -114,7 +114,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libparams_libconfig.so \ /usr/local/lib/libdfts.so \ /usr/local/lib/libtelnetsrv.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-lte-ue COPY --from=lte-ue-base /tini /tini diff --git a/docker/Dockerfile.lteUE.ubuntu22 b/docker/Dockerfile.lteUE.ubuntu similarity index 78% rename from docker/Dockerfile.lteUE.ubuntu22 rename to docker/Dockerfile.lteUE.ubuntu index 5174dab36a..909c137ddd 100644 --- a/docker/Dockerfile.lteUE.ubuntu22 +++ b/docker/Dockerfile.lteUE.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu20.04 +# Valid for Ubuntu24.04 # #--------------------------------------------------------------------- @@ -31,25 +31,25 @@ FROM ran-build:latest AS lte-ue-build #start from scratch for target executable -FROM ubuntu:jammy AS oai-lte-ue +FROM ubuntu:noble AS oai-lte-ue ARG BUILD_OPTION ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe/Paris RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ software-properties-common \ procps \ libsctp1 \ - libboost-chrono1.74.0 \ - libboost-date-time1.74.0 \ - libboost-filesystem1.74.0 \ - libboost-regex1.74.0 \ - libboost-serialization1.74.0 \ - libboost-thread1.74.0 \ - libboost-system1.74.0 \ - libboost-program-options1.74.0 \ + libboost-chrono1.83.0 \ + libboost-date-time1.83.0 \ + libboost-filesystem1.83.0 \ + libboost-regex1.83.0 \ + libboost-serialization1.83.0 \ + libboost-thread1.83.0 \ + libboost-system1.83.0 \ + libboost-program-options1.83.0 \ tzdata \ liblapacke \ libblas3 \ @@ -59,7 +59,7 @@ RUN apt-get update && \ python3 \ python3-six \ python3-requests \ - libpython3.10 \ + libpython3.12 \ libusb-1.0-0 \ iputils-ping \ iproute2 \ @@ -74,24 +74,18 @@ RUN apt-get update && \ apt-get remove -y wget && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - #libasan5 \ # see below + libasan8 \ libubsan1 \ liblapacke; fi' && \ apt-get clean -y && \ rm -rf /var/lib/apt/lists/* -# we select another compile (gcc-12) for compilation, requiring another libasan -# library version. Installing it above would install the wrong version. Hence, -# copy the right version from ran-build. When upgrading to Ubuntu24, install -# the correct one above! -COPY --from=lte-ue-build /usr/lib/x86_64-linux-gnu/libasan.so.8.0.0 /usr/lib/x86_64-linux-gnu/ - WORKDIR /opt/oai-lte-ue/bin COPY --from=lte-ue-build \ /oai-ran/cmake_targets/ran_build/build/lte-uesoftmodem \ - /oai-ran/cmake_targets/nas_sim_tools/build/conf2uedata \ - /oai-ran/cmake_targets/nas_sim_tools/build/nvram \ - /oai-ran/cmake_targets/nas_sim_tools/build/usim \ + /oai-ran/cmake_targets/ran_build/build/conf2uedata \ + /oai-ran/cmake_targets/ran_build/build/nvram \ + /oai-ran/cmake_targets/ran_build/build/usim \ ./ COPY ./docker/scripts/lte_ue_entrypoint.sh ./entrypoint.sh @@ -107,7 +101,7 @@ COPY --from=lte-ue-build \ # Now we are copying from builder-image the UHD files. COPY --from=lte-ue-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=lte-ue-base /usr/local/lib/libuhd.so.4.4.0 /usr/local/lib +COPY --from=lte-ue-base /usr/local/lib/libuhd.so.4.8.0 /usr/local/lib COPY --from=lte-ue-base /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-lte-ue/bin RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai_device.so" && \ @@ -122,7 +116,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libparams_libconfig.so \ /usr/local/lib/libdfts.so \ /usr/local/lib/libtelnetsrv.so \ - /usr/local/lib/libuhd.so.4.4.0 + /usr/local/lib/libuhd.so.4.8.0 WORKDIR /opt/oai-lte-ue COPY --from=lte-ue-base /tini /tini diff --git a/docker/Dockerfile.nr-cuup.ubuntu22 b/docker/Dockerfile.nr-cuup.ubuntu similarity index 69% rename from docker/Dockerfile.nr-cuup.ubuntu22 rename to docker/Dockerfile.nr-cuup.ubuntu index 2952afa34b..2c3c58e7e3 100644 --- a/docker/Dockerfile.nr-cuup.ubuntu22 +++ b/docker/Dockerfile.nr-cuup.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu20.04 +# Valid for Ubuntu24.04 # #--------------------------------------------------------------------- @@ -30,14 +30,14 @@ FROM ran-base:latest AS gnb-base FROM ran-build:latest AS gnb-build -FROM ubuntu:jammy AS oai-nr-cuup +FROM ubuntu:noble AS oai-nr-cuup ARG BUILD_OPTION ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ libsctp1 \ libconfig9 \ iproute2 \ @@ -45,27 +45,11 @@ RUN apt-get update && \ openssl && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - #libasan5 \ see below + libasan8 \ libubsan1 \ liblapacke; fi' && \ rm -rf /var/lib/apt/lists/* -# we select another compile (gcc-12) for compilation, requiring another libasan -# library version. Installing it above would install the wrong version. Hence, -# copy the right version from ran-build. When upgrading to Ubuntu24, install -# the correct one above! -# note: this dockerfile should work for both x86 and arm, hence the glob below -# which should either match "x86_64" (x86) or "aarch64" (ARM); since the target -# directory needs to be also one of those two, but globs don't work in target -# directories, work around this with mv -COPY --from=gnb-build /usr/lib/*-linux-gnu/libasan.so.8.0.0 /usr/lib/ -ARG TARGETPLATFORM -RUN case "${TARGETPLATFORM}" in \ - "linux/amd64") TARGET_DIR=x86_64-linux-gnu ;; \ - "linux/arm64") TARGET_DIR=aarch64-linux-gnu ;; \ - *) exit 1 ;; \ - esac; \ - mv /usr/lib/libasan.so.8.0.0 /usr/lib/$TARGET_DIR/libasan.so.8.0.0 ## Copy E2 SM models COPY --from=gnb-build /usr/local/lib/flexric /usr/local/lib/flexric diff --git a/docker/Dockerfile.nrUE.rhel9 b/docker/Dockerfile.nrUE.rhel9 index 3a2900da27..0929ab3df0 100644 --- a/docker/Dockerfile.nrUE.rhel9 +++ b/docker/Dockerfile.nrUE.rhel9 @@ -99,7 +99,7 @@ COPY --from=nr-ue-base \ # Now we are copying from builder-image the UHD files. COPY --from=nr-ue-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=nr-ue-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=nr-ue-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=nr-ue-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-nr-ue/bin WORKDIR /usr/local/share/uhd/rfnoc @@ -119,7 +119,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libldpc*.so \ /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_5Gue.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-nr-ue COPY --from=nr-ue-base /tini /tini diff --git a/docker/Dockerfile.nrUE.rocky b/docker/Dockerfile.nrUE.rocky index 7f112af53a..bfe84dc011 100644 --- a/docker/Dockerfile.nrUE.rocky +++ b/docker/Dockerfile.nrUE.rocky @@ -96,7 +96,7 @@ COPY --from=nr-ue-base \ # Now we are copying from builder-image the UHD files. COPY --from=nr-ue-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=nr-ue-base /usr/local/lib64/libuhd.so.4.4.0 /usr/local/lib64 +COPY --from=nr-ue-base /usr/local/lib64/libuhd.so.4.8.0 /usr/local/lib64 COPY --from=nr-ue-base /usr/local/lib64/uhd/utils/uhd_images_downloader.py /opt/oai-nr-ue/bin WORKDIR /usr/local/share/uhd/rfnoc @@ -116,7 +116,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libldpc*.so \ /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_5Gue.so \ - /usr/local/lib64/libuhd.so.4.4.0 + /usr/local/lib64/libuhd.so.4.8.0 WORKDIR /opt/oai-nr-ue COPY --from=nr-ue-base /tini /tini diff --git a/docker/Dockerfile.nrUE.ubuntu22 b/docker/Dockerfile.nrUE.ubuntu similarity index 74% rename from docker/Dockerfile.nrUE.ubuntu22 rename to docker/Dockerfile.nrUE.ubuntu index c3b6592753..a395004cc1 100644 --- a/docker/Dockerfile.nrUE.ubuntu22 +++ b/docker/Dockerfile.nrUE.ubuntu @@ -21,7 +21,7 @@ #--------------------------------------------------------------------- # # Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 +# Valid for Ubuntu 24.04 # #--------------------------------------------------------------------- @@ -31,25 +31,25 @@ FROM ran-build:latest AS nr-ue-build #start from scratch for target executable -FROM ubuntu:jammy AS oai-nr-ue +FROM ubuntu:noble AS oai-nr-ue ARG BUILD_OPTION ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe/Paris RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + apt-get upgrade --yes && \ + apt-get install --yes \ software-properties-common \ procps \ libsctp1 \ - libboost-chrono1.74.0 \ - libboost-date-time1.74.0 \ - libboost-filesystem1.74.0 \ - libboost-regex1.74.0 \ - libboost-serialization1.74.0 \ - libboost-thread1.74.0 \ - libboost-system1.74.0 \ - libboost-program-options1.74.0 \ + libboost-chrono1.83.0 \ + libboost-date-time1.83.0 \ + libboost-filesystem1.83.0 \ + libboost-regex1.83.0 \ + libboost-serialization1.83.0 \ + libboost-thread1.83.0 \ + libboost-system1.83.0 \ + libboost-program-options1.83.0 \ tzdata \ liblapacke \ libblas3 \ @@ -68,28 +68,11 @@ RUN apt-get update && \ libyaml-cpp-dev && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - #libasan5 \ # see below + libasan8 \ libubsan1; fi' && \ apt-get clean -y && \ rm -rf /var/lib/apt/lists/* -# we select another compile (gcc-12) for compilation, requiring another libasan -# library version. Installing it above would install the wrong version. Hence, -# copy the right version from ran-build. When upgrading to Ubuntu24, install -# the correct one above! -# note: this dockerfile should work for both x86 and arm, hence the glob below -# which should either match "x86_64" (x86) or "aarch64" (ARM); since the target -# directory needs to be also one of those two, but globs don't work in target -# directories, work around this with mv -COPY --from=nr-ue-build /usr/lib/*-linux-gnu/libasan.so.8.0.0 /usr/lib/ -ARG TARGETPLATFORM -RUN case "${TARGETPLATFORM}" in \ - "linux/amd64") TARGET_DIR=x86_64-linux-gnu ;; \ - "linux/arm64") TARGET_DIR=aarch64-linux-gnu ;; \ - *) exit 1 ;; \ - esac; \ - mv /usr/lib/libasan.so.8.0.0 /usr/lib/$TARGET_DIR/libasan.so.8.0.0 - WORKDIR /opt/oai-nr-ue/bin COPY --from=nr-ue-build \ /oai-ran/cmake_targets/ran_build/build/nr-uesoftmodem \ @@ -115,7 +98,7 @@ COPY --from=nr-ue-build \ # Now we are copying from builder-image the UHD files. COPY --from=nr-ue-base /usr/local/bin/uhd_find_devices /usr/local/bin -COPY --from=nr-ue-base /usr/local/lib/libuhd.so.4.4.0 /usr/local/lib +COPY --from=nr-ue-base /usr/local/lib/libuhd.so.4.8.0 /usr/local/lib COPY --from=nr-ue-base /usr/local/lib/uhd/utils/uhd_images_downloader.py /opt/oai-nr-ue/bin RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai_device.so" && \ @@ -133,7 +116,7 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai /usr/local/lib/libtelnetsrv.so \ /usr/local/lib/libtelnetsrv_ciUE.so \ /usr/local/lib/libtelnetsrv_5Gue.so \ - /usr/local/lib/libuhd.so.4.4.0 + /usr/local/lib/libuhd.so.4.8.0 WORKDIR /opt/oai-nr-ue COPY --from=nr-ue-base /tini /tini diff --git a/docker/Dockerfile.phySim.rhel9 b/docker/Dockerfile.phySim.rhel9 index e9ccf68b00..eb6d92d78c 100644 --- a/docker/Dockerfile.phySim.rhel9 +++ b/docker/Dockerfile.phySim.rhel9 @@ -36,9 +36,14 @@ RUN dnf install -y libasan libubsan #run build_oai to build the target image RUN /bin/sh oaienv && \ - cd cmake_targets && \ - mkdir -p log && \ - ./build_oai --phy_simulators --ninja --sanitize --build-tool-opt -k10 --noavx512 -c --cmake-opt -DCMAKE_C_FLAGS=-Werror --cmake-opt -DCMAKE_CXX_FLAGS=-Werror --cmake-opt -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/opt/oai-physim/bin + mkdir -p cmake_targets/ran_build/build && \ + cd cmake_targets/ran_build/build && \ + cmake3 -GNinja ../../.. \ + -DAVX512=OFF -DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror \ + -DENABLE_PHYSIM_TESTS=ON \ + -DSANITIZE_ADDRESS=ON -DSANITIZE_UNDEFINED=ON \ + -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/opt/oai-physim/bin && \ + ninja -k10 -j36 #start from scratch for target executable FROM registry.access.redhat.com/ubi9/ubi:latest AS oai-physim @@ -98,7 +103,14 @@ RUN ldconfig && \ WORKDIR /opt/oai-physim/ COPY --from=phy-sim-build \ - /oai-ran/cmake_targets/ran_build/build/openair1/PHY/CODING/tests/CTestTestfile.cmake \ + /oai-ran/cmake_targets/ran_build/build/openair1/SIMULATION/tests/CTestTestfile.cmake \ /opt/oai-physim/ +RUN mkdir -p /oai-ran/openair1/SIMULATION/tests + +COPY --from=phy-sim-build \ + /oai-ran/openair1/SIMULATION/tests/RunTimedTest.cmake \ + /oai-ran/openair1/SIMULATION/tests/analyze-timing.sh \ + /oai-ran/openair1/SIMULATION/tests/ + #CMD ["sleep", "infinity"] diff --git a/docker/README.md b/docker/README.md index 36ec65698a..d5045840bb 100644 --- a/docker/README.md +++ b/docker/README.md @@ -78,7 +78,7 @@ Targets can be: The currently-supported OS are: - `rhel9` for Red Hat Enterprise Linux and Openshift Universal Base Image -- `ubuntu22` for Ubuntu 22.04 LTS +- `ubuntu` for Ubuntu 24.04 LTS - `rocky` for Rocky-Linux 9 For more details regarding the build on an Openshift Cluster, see [OpenShift README](../openshift/README.md). @@ -91,6 +91,24 @@ For more details regarding the build on an Openshift Cluster, see [OpenShift REA * `docker-ce` installed * Pulling `ubuntu:jammy` from DockerHub +The docker files in this directory rely on [automatic Docker platform +arguments](https://docs.docker.com/reference/dockerfile/#automatic-platform-args-in-the-global-scope) +`TARGETARCH` and `TARGETPLATFORM` to be defined. This is the case when using +[BuildKit](https://docs.docker.com/build/buildkit/), which is automatically +enabled in newer (v23.0+) docker versions. + +If you are running an older version of docker that does not have BuildKit +enabled and do not wish to upgrade to a newer docker version, you have two +possibilities: + +1. [Enable BuildKit](https://docs.docker.com/build/buildkit/#getting-started) + when building: `DOCKER_BUILDKIT=1 docker build ...` +2. You should be able to define these variables manually. + - x86: `docker build --build-arg TARGETARCH=amd64 --build-arg + TARGETPLATFORM=linux/amd64 ...` + - arm: `docker build --build-arg TARGETARCH=arm64 --build-arg + TARGETPLATFORM=linux/arm64 ...` + ## 3.2. Building the shared images ## There are two shared images: one that has all dependencies, and a second that compiles all targets (eNB, gNB, [nr]UE). @@ -99,11 +117,11 @@ There are two shared images: one that has all dependencies, and a second that co git clone https://gitlab.eurecom.fr/oai/openairinterface5g.git cd openairinterface5g # default branch is develop, to change use git checkout -docker build --target ran-base --tag ran-base:latest --file docker/Dockerfile.base.ubuntu22 . +docker build --target ran-base --tag ran-base:latest --file docker/Dockerfile.base.ubuntu . # if you want use USRP, AW2S and RFSimulator radios -docker build --target ran-build --tag ran-build:latest --file docker/Dockerfile.build.ubuntu22 . +docker build --target ran-build --tag ran-build:latest --file docker/Dockerfile.build.ubuntu . # if you want to use front-haul 7.2 and RFSimulator radios -docker build --tag ran-build-fhi72:latest --file docker/Dockerfile.build.fhi72.ubuntu22 . +docker build --tag ran-build-fhi72:latest --file docker/Dockerfile.build.fhi72.ubuntu . ``` After building: @@ -126,7 +144,7 @@ This is only available for the Ubuntu version of Dockerfiles. You can, for example, create a `sanitizer` version of the ran-build image. ```bash -docker build --target ran-build --tag ran-build:latest --file docker/Dockerfile.build.ubuntu22 --build-arg "BUILD_OPTION=--sanitize" . +docker build --target ran-build --tag ran-build:latest --file docker/Dockerfile.build.ubuntu --build-arg "BUILD_OPTION=--sanitize" . ``` Currently the `--sanitize` option for `build_oai` enables: @@ -152,13 +170,13 @@ You can also use this docker build arguments to pass any available option(s) on For example, the eNB: ```bash -docker build --target oai-enb --tag oai-enb:latest --file docker/Dockerfile.eNB.ubuntu22 . +docker build --target oai-enb --tag oai-enb:latest --file docker/Dockerfile.eNB.ubuntu . ``` To build gNB/DU with 7.2 fronthaul support: ```bash -docker build --target oai-gnb-fhi72 --tag oai-gnb-fhi72:latest --file docker/Dockerfile.gNB.fhi72.ubuntu22 . +docker build --target oai-gnb-fhi72 --tag oai-gnb-fhi72:latest --file docker/Dockerfile.gNB.fhi72.ubuntu . ``` After a while: @@ -182,7 +200,7 @@ Note that the steps are identical for `rocky-linux`. If you have used the sanitizer option, then you should also pass it when building the target image: ```bash -docker build --target oai-gnb --tag oai-gnb:latest --file docker/Dockerfile.gNB.ubuntu22 --build-arg "BUILD_OPTION=--sanitize" . +docker build --target oai-gnb --tag oai-gnb:latest --file docker/Dockerfile.gNB.ubuntu --build-arg "BUILD_OPTION=--sanitize" . ``` Normally the target image will be around 200 Mbytes bigger. diff --git a/docker/debug_core_image.sh b/docker/debug_core_image.sh index 3b2fc5db0a..307bd90bc5 100755 --- a/docker/debug_core_image.sh +++ b/docker/debug_core_image.sh @@ -54,7 +54,7 @@ fi # the source directory to show correct line numbers docker run --rm -it \ -v $COREDUMP:/tmp/coredump \ - -v $SOURCES:/opt/$TYPEPATH/src \ + -v $SOURCES:/oai-ran/ \ --entrypoint bash \ $IMAGE \ -c "gdb --dir=src/cmake_targets/ran_build/build $EXEC /tmp/coredump" diff --git a/docker/scripts/check-prach-io.sh b/docker/scripts/check-prach-io.sh new file mode 100755 index 0000000000..1e1544dadf --- /dev/null +++ b/docker/scripts/check-prach-io.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -eo pipefail + +test -f /opt/oai-gnb/nrL1_stats.log && grep -oP 'PRACH I0 = \K[0-9.]*' /opt/oai-gnb/nrL1_stats.log | awk '{if ($1 > 0.0) exit 0; else exit 1}' diff --git a/executables/create_tasks.c b/executables/create_tasks.c index ad81beca09..a36cf410e5 100644 --- a/executables/create_tasks.c +++ b/executables/create_tasks.c @@ -52,7 +52,7 @@ int create_tasks(uint32_t enb_nb) { rrc_enb_init(); itti_mark_task_ready(TASK_RRC_ENB); - if (get_softmodem_params()->emulate_l1 || !IS_SOFTMODEM_NOS1) { + if (!IS_SOFTMODEM_NOS1) { rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); AssertFatal(rc >= 0, "Create task for SCTP failed\n"); } diff --git a/executables/create_tasks_ue.c b/executables/create_tasks_ue.c index 50b9221f3f..46b80a0496 100644 --- a/executables/create_tasks_ue.c +++ b/executables/create_tasks_ue.c @@ -64,15 +64,6 @@ int create_tasks_ue(uint32_t ue_nb) LOG_E(RRC, "Create task for RRC UE failed\n"); return -1; } - - if (get_softmodem_params()->nsa) { - init_connections_with_nr_ue(); - LOG_I(RRC, "Started LTE-NR link in the LTE UE\n"); - if (itti_create_task (TASK_RRC_NSA_UE, recv_msgs_from_nr_ue, NULL) < 0) { - LOG_E(RRC, "Create task for RRC NSA UE failed\n"); - return -1; - } - } } itti_wait_ready(0); diff --git a/executables/lte-enb.c b/executables/lte-enb.c index 39f72db86c..c86a916c7a 100644 --- a/executables/lte-enb.c +++ b/executables/lte-enb.c @@ -1229,7 +1229,8 @@ void init_eNB() LOG_I(PHY,"Initializing eNB %d CC_id %d\n",inst,CC_id); LOG_I(PHY,"Initializing eNB %d CC_id %d\n",inst,CC_id); LOG_I(PHY,"Registering with MAC interface module\n"); - AssertFatal((eNB->if_inst = IF_Module_init(inst))!=NULL,"Cannot register interface"); + eNB->if_inst = IF_Module_init(inst); + AssertFatal(eNB->if_inst, "Cannot register interface"); eNB->if_inst->schedule_response = schedule_response; eNB->if_inst->PHY_config_req = phy_config_request; eNB->if_inst->PHY_config_update_sib2_req = phy_config_update_sib2_request; diff --git a/executables/lte-ru.c b/executables/lte-ru.c index 326e55b288..9c47c92a0d 100644 --- a/executables/lte-ru.c +++ b/executables/lte-ru.c @@ -531,44 +531,6 @@ volatile late_control_e late_control=STATE_BURST_NORMAL; /* add fail safe for late command end */ -static void *emulatedRF_thread(void *param) { - RU_proc_t *proc = (RU_proc_t *) param; - int microsec = 500; // length of time to sleep, in miliseconds - int numerology = 0 ; - struct timespec req = {0}; - req.tv_sec = 0; - req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(1,&cpuset); - pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - int policy; - int ret; - struct sched_param sparam; - memset(&sparam, 0, sizeof(sparam)); - sparam.sched_priority = sched_get_priority_max(SCHED_FIFO); - policy = SCHED_FIFO ; - pthread_setschedparam(pthread_self(), policy, &sparam); - wait_sync("emulatedRF_thread"); - - while(!oai_exit) { - nanosleep(&req, (struct timespec *)NULL); - - if(proc->emulate_rf_busy ) { - LOG_E(PHY,"rf being delayed in emulated RF\n"); - } - - proc->emulate_rf_busy = 1; - AssertFatal((ret=pthread_mutex_lock(&proc->mutex_emulateRF))==0,"mutex_lock returns %d\n",ret); - ++proc->instance_cnt_emulateRF; - pthread_cond_signal(&proc->cond_emulateRF); - AssertFatal((ret=pthread_mutex_unlock(&proc->mutex_emulateRF))==0,"mutex_unlock returns %d\n",ret); - } - - return 0; -} - - void rx_rf(RU_t *ru, int *frame, int *subframe) { @@ -586,17 +548,7 @@ void rx_rf(RU_t *ru, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); old_ts = proc->timestamp_rx; - if(ru->emulate_rf) { - wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - rxs = fp->samples_per_tti; - } else { - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, - &ts, - rxp, - fp->samples_per_tti, - ru->nb_rx); - } + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, fp->samples_per_tti, ru->nb_rx); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); ru->south_in_cnt++; @@ -613,11 +565,7 @@ void rx_rf(RU_t *ru, resynch=1; } - if(get_softmodem_params()->emulate_rf) { - proc->timestamp_rx = old_ts + fp->samples_per_tti; - } else { - proc->timestamp_rx = ts-ru->ts_offset; - } + proc->timestamp_rx = ts-ru->ts_offset; // AssertFatal(rxs == fp->samples_per_tti, // "rx_rf: Asked for %d samples, got %d from SDR\n",fp->samples_per_tti,rxs); @@ -1229,7 +1177,6 @@ void wakeup_L1s(RU_t *ru) { // pthread_mutex_unlock(&proc->mutex_RU); // LOG_D(PHY,"wakeup eNB top for for subframe %d\n", ru->proc.tti_rx); // ru->eNB_top(eNB_list[0],ru->proc.frame_rx,ru->proc.tti_rx,string); - ru->proc.emulate_rf_busy = 0; } @@ -1497,7 +1444,6 @@ static void *ru_thread_tx( void *param ) { L1_rxtx_proc_t *L1_proc; cpu_set_t cpuset; CPU_ZERO(&cpuset); - char filename[256]; thread_top_init("ru_thread_tx",1,400000,500000,500000); //CPU_SET(5, &cpuset); //pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); @@ -1530,24 +1476,12 @@ static void *ru_thread_tx( void *param ) { // do OFDM if needed if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru,frame_tx,tti_tx); - if(!(ru->emulate_rf)) { //if(!emulate_rf){ - // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru,frame_tx,tti_tx,timestamp_tx); + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) + ru->fh_south_out(ru, frame_tx, tti_tx, timestamp_tx); - if (ru->fh_north_out) ru->fh_north_out(ru); - } else { - for (int i=0; inb_tx; i++) { - if(frame_tx == 2) { - sprintf(filename,"txdataF%d_frame%d_sf%d.m",i,frame_tx,tti_tx); - LOG_M(filename,"txdataF_frame",ru->common.txdataF_BF[i],fp->symbols_per_tti*fp->ofdm_symbol_size, 1, 1); - } - - if(frame_tx == 2 && tti_tx==0) { - sprintf(filename,"txdata%d_frame%d.m",i,frame_tx); - LOG_M(filename,"txdata_frame",ru->common.txdata[i],fp->samples_per_tti*10, 1, 1); - } - } - } + if (ru->fh_north_out) + ru->fh_north_out(ru); LOG_D(PHY,"ru_thread_tx: releasing RU TX in %d.%d\n", frame_tx, tti_tx); release_thread(&proc->mutex_eNBs,&proc->instance_cnt_eNBs,"ru_thread_tx"); @@ -1612,7 +1546,6 @@ static void *ru_thread( void *param ) { int ret; cpu_set_t cpuset; CPU_ZERO(&cpuset); - char filename[256]; // set default return value #if defined(PRE_SCD_THREAD) dlsch_ue_select_tbl_in_use = 1; @@ -1625,21 +1558,7 @@ static void *ru_thread( void *param ) { LOG_I(PHY,"thread ru created id=%ld\n", syscall(__NR_gettid)); LOG_I(PHY,"Starting RU %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]); - if(get_softmodem_params()->emulate_rf) { - phy_init_RU(ru); - - if (setup_RU_buffers(ru)!=0) { - LOG_I(PHY,"Exiting, cannot initialize RU Buffers\n"); - exit(-1); - } - - LOG_I(PHY, "Signaling main thread that RU %d is ready\n",ru->idx); - AssertFatal((ret=pthread_mutex_lock(ru->ru_mutex))==0,"mutex_lock returns %d\n",ret); - *ru->ru_mask &= ~(1<idx); - pthread_cond_signal(ru->ru_cond); - AssertFatal((ret=pthread_mutex_unlock(ru->ru_mutex))==0,"mutex_unlock returns %d\n",ret); - ru->state = RU_RUN; - } else if (ru->has_ctrl_prt == 0) { + if (ru->has_ctrl_prt == 0) { // There is no control port: start everything here LOG_I(PHY, "RU %d has no OAI ctrl port\n",ru->idx); @@ -1695,18 +1614,22 @@ static void *ru_thread( void *param ) { } else wait_sync("ru_thread"); LOG_D(PHY,"RU %d: Got start from control thread\n",ru->idx); - if(!(ru->emulate_rf)) { - if (ru->is_slave == 0) AssertFatal(ru->state == RU_RUN,"ru-%d state = %s != RU_RUN\n",ru->idx,ru_states[ru->state]); - else if (ru->is_slave == 1) AssertFatal(ru->state == RU_SYNC || ru->state == RU_RUN || - ru->state == RU_CHECK_SYNC,"ru %d state = %s != RU_SYNC or RU_RUN or RU_CHECK_SYNC\n",ru->idx,ru_states[ru->state]); + if (ru->is_slave == 0) + AssertFatal(ru->state == RU_RUN, "ru-%d state = %s != RU_RUN\n", ru->idx, ru_states[ru->state]); + else if (ru->is_slave == 1) + AssertFatal(ru->state == RU_SYNC || ru->state == RU_RUN || ru->state == RU_CHECK_SYNC, + "ru %d state = %s != RU_SYNC or RU_RUN or RU_CHECK_SYNC\n", + ru->idx, + ru_states[ru->state]); - // Start RF device if any - if (ru->start_rf) { - if (ru->start_rf(ru) != 0) - AssertFatal(1==0,"Could not start the RF device\n"); - else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); - } else LOG_D(PHY,"RU %d no rf device\n",ru->idx); - } + // Start RF device if any + if (ru->start_rf) { + if (ru->start_rf(ru) != 0) + AssertFatal(1 == 0, "Could not start the RF device\n"); + else + LOG_I(PHY, "RU %d rf device ready\n", ru->idx); + } else + LOG_D(PHY, "RU %d no rf device\n", ru->idx); // if an asnych_rxtx thread exists // wakeup the thread because the devices are ready at this point @@ -1864,26 +1787,13 @@ static void *ru_thread( void *param ) { // do OFDM if needed if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru, proc->frame_tx, proc->tti_tx); - if(!(ru->emulate_rf)) { //if(!emulate_rf){ - // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx); + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) + ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx); - if ((ru->fh_north_out) && (ru->state!=RU_CHECK_SYNC)) ru->fh_north_out(ru); - } else { - for (int i=0; inb_tx; i++) { - if(proc->frame_tx == 2) { - sprintf(filename,"txdataF%d_frame%d_sf%d.m",i,proc->frame_tx,proc->tti_tx); - LOG_M(filename,"txdataF_frame",ru->common.txdataF_BF[i],ru->frame_parms->symbols_per_tti*ru->frame_parms->ofdm_symbol_size, 1, 1); - } + if ((ru->fh_north_out) && (ru->state != RU_CHECK_SYNC)) + ru->fh_north_out(ru); - if(proc->frame_tx == 2 && proc->tti_tx==0) { - sprintf(filename,"txdata%d_frame%d.m",i,proc->frame_tx); - LOG_M(filename,"txdata_frame",ru->common.txdata[i],ru->frame_parms->samples_per_tti*10, 1, 1); - } - } - } - - proc->emulate_rf_busy = 0; } #else @@ -1903,12 +1813,11 @@ static void *ru_thread( void *param ) { LOG_I(PHY, "Exiting ru_thread \n"); - if (!(ru->emulate_rf)) { - if (ru->stop_rf != NULL) { - if (ru->stop_rf(ru) != 0) - LOG_E(HW,"Could not stop the RF device\n"); - else LOG_I(PHY,"RU %d rf device stopped\n",ru->idx); - } + if (ru->stop_rf != NULL) { + if (ru->stop_rf(ru) != 0) + LOG_E(HW, "Could not stop the RF device\n"); + else + LOG_I(PHY, "RU %d rf device stopped\n", ru->idx); } return NULL; @@ -2128,12 +2037,12 @@ static void *rf_tx( void *param ) { // do OFDM if needed if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) ru->feptx_ofdm(ru,proc->frame_tx,proc->tti_tx); - if(!ru->emulate_rf) { - // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) ru->fh_south_out(ru,proc->frame_tx,proc->tti_tx,proc->timestamp_tx); + // do outgoing fronthaul (south) if needed + if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) + ru->fh_south_out(ru, proc->frame_tx, proc->tti_tx, proc->timestamp_tx); - if (ru->fh_north_out) ru->fh_north_out(ru); - } + if (ru->fh_north_out) + ru->fh_north_out(ru); } if (release_thread(&proc->mutex_rf_tx,&proc->instance_cnt_rf_tx,"rf_tx") < 0) break; @@ -2205,7 +2114,7 @@ int start_write_thread(RU_t *ru) { void init_RU_proc(RU_t *ru) { int i=0; RU_proc_t *proc; - pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL, *attr_prach=NULL, *attr_asynch=NULL, *attr_synch=NULL, *attr_emulateRF=NULL, *attr_ctrl=NULL, *attr_prach_br=NULL; + pthread_attr_t *attr_FH=NULL, *attr_FH1=NULL, *attr_prach=NULL, *attr_asynch=NULL, *attr_synch=NULL, *attr_ctrl=NULL, *attr_prach_br=NULL; //pthread_attr_t *attr_fep=NULL; LOG_I(PHY,"Initializing RU proc %d (%s,%s),\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing]); proc = &ru->proc; @@ -2215,7 +2124,6 @@ void init_RU_proc(RU_t *ru) { proc->instance_cnt_synch = -1; proc->instance_cnt_FH = -1; proc->instance_cnt_FH1 = -1; - proc->instance_cnt_emulateRF = -1; proc->instance_cnt_asynch_rxtx = -1; proc->instance_cnt_ru = -1; proc->instance_cnt_eNBs = -1; @@ -2232,20 +2140,17 @@ void init_RU_proc(RU_t *ru) { pthread_mutex_init( &proc->mutex_synch,NULL); pthread_mutex_init( &proc->mutex_FH,NULL); pthread_mutex_init( &proc->mutex_FH1,NULL); - pthread_mutex_init( &proc->mutex_emulateRF,NULL); pthread_mutex_init( &proc->mutex_eNBs, NULL); pthread_mutex_init( &proc->mutex_ru,NULL); pthread_cond_init( &proc->cond_prach, NULL); pthread_cond_init( &proc->cond_FH, NULL); pthread_cond_init( &proc->cond_FH1, NULL); - pthread_cond_init( &proc->cond_emulateRF, NULL); pthread_cond_init( &proc->cond_asynch_rxtx, NULL); pthread_cond_init( &proc->cond_synch,NULL); pthread_cond_init( &proc->cond_eNBs, NULL); pthread_cond_init( &proc->cond_ru_thread,NULL); pthread_attr_init( &proc->attr_FH); pthread_attr_init( &proc->attr_FH1); - pthread_attr_init( &proc->attr_emulateRF); pthread_attr_init( &proc->attr_prach); pthread_attr_init( &proc->attr_synch); pthread_attr_init( &proc->attr_asynch_rxtx); @@ -2289,9 +2194,6 @@ void init_RU_proc(RU_t *ru) { pthread_create( &proc->pthread_rf_tx, NULL, rf_tx, (void *)ru ); #endif - if (ru->emulate_rf) - pthread_create( &proc->pthread_emulateRF, attr_emulateRF, emulatedRF_thread, (void *)proc ); - if (get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) pthread_create( &proc->pthread_FH1, attr_FH1, ru_thread_tx, (void *)ru ); @@ -2884,11 +2786,10 @@ RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mas config_getlist(config_get_if(), &RUParamList, RUParams, sizeofArray(RUParams), NULL); RU_t **ru=NULL; if ( RUParamList.numelt > 0) { - ru = (RU_t **)malloc(nb_RU*sizeof(RU_t *)); + ru = malloc_or_fail(nb_RU * sizeof(RU_t *)); for (int j = 0; j < nb_RU; j++) { - ru[j] = (RU_t *)malloc(sizeof(RU_t)); - memset((void *)ru[j],0,sizeof(RU_t)); + ru[j] = calloc_or_fail(1,sizeof(RU_t)); ru[j]->idx = j; LOG_I(PHY,"Creating ru[%d]:%p\n", j, ru[j]); ru[j]->if_timing = synch_to_ext_device; diff --git a/executables/lte-softmodem.c b/executables/lte-softmodem.c index 6a7e607586..77fdb21eb4 100644 --- a/executables/lte-softmodem.c +++ b/executables/lte-softmodem.c @@ -138,7 +138,6 @@ RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mas RU_t **RCconfig_RU(int nb_RU,int nb_L1_inst,PHY_VARS_eNB ***eNB,uint64_t *ru_mask,pthread_mutex_t *ru_mutex,pthread_cond_t *ru_cond); int transmission_mode=1; -int emulate_rf = 0; int numerology = 0; THREAD_STRUCT thread_struct; @@ -204,55 +203,6 @@ void nr_slot_select() {}; void NR_UL_indication(NR_UL_IND_t *UL_INFO) {}; void gNB_dlsch_ulsch_scheduler() {}; -/*---------------------BMC: timespec helpers -----------------------------*/ - -struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; -struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - -struct timespec clock_difftime(struct timespec start, struct timespec end) { - struct timespec temp; - - if ((end.tv_nsec-start.tv_nsec)<0) { - temp.tv_sec = end.tv_sec-start.tv_sec-1; - temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; - } else { - temp.tv_sec = end.tv_sec-start.tv_sec; - temp.tv_nsec = end.tv_nsec-start.tv_nsec; - } - - return temp; -} - -void print_difftimes(void) { -#ifdef DEBUG - printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); -#else - LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); -#endif -} - -void update_difftimes(struct timespec start, struct timespec end) { - struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - int changed = 0; - diff_time = clock_difftime(start, end); - - if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { - min_diff_time.tv_nsec = diff_time.tv_nsec; - changed = 1; - } - - if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { - max_diff_time.tv_nsec = diff_time.tv_nsec; - changed = 1; - } - -#if 1 - - if (changed) print_difftimes(); - -#endif -} - /*------------------------------------------------------------------------*/ unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { @@ -547,12 +497,10 @@ int main ( int argc, char **argv ) L1_rxtx_proc_t *L1proc= &RC.eNB[x][CC_id]->proc.L1_proc; L1_rxtx_proc_t *L1proctx= &RC.eNB[x][CC_id]->proc.L1_proc_tx; L1proc->threadPool = (tpool_t *)malloc(sizeof(tpool_t)); - L1proc->respDecode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); if ( strlen(get_softmodem_params()->threadPoolConfig) > 0 ) initTpool(get_softmodem_params()->threadPoolConfig, L1proc->threadPool, true); else initTpool("n", L1proc->threadPool, true); - initNotifiedFIFO(L1proc->respDecode); L1proctx->threadPool = L1proc->threadPool; } diff --git a/executables/lte-softmodem.h b/executables/lte-softmodem.h index 8c55f0dc65..db6136c351 100644 --- a/executables/lte-softmodem.h +++ b/executables/lte-softmodem.h @@ -127,7 +127,6 @@ extern int sync_var; extern int transmission_mode; extern double cpuf; -extern int emulate_rf; extern int numerology; extern int usrp_tx_thread; diff --git a/executables/lte-uesoftmodem.c b/executables/lte-uesoftmodem.c index ea48edd801..b212ceb3f1 100644 --- a/executables/lte-uesoftmodem.c +++ b/executables/lte-uesoftmodem.c @@ -174,55 +174,6 @@ instance_t CUuniqInstance=0; /* forward declarations */ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]); -/*---------------------BMC: timespec helpers -----------------------------*/ - -struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; -struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - -struct timespec clock_difftime(struct timespec start, struct timespec end) { - struct timespec temp; - - if ((end.tv_nsec-start.tv_nsec)<0) { - temp.tv_sec = end.tv_sec-start.tv_sec-1; - temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; - } else { - temp.tv_sec = end.tv_sec-start.tv_sec; - temp.tv_nsec = end.tv_nsec-start.tv_nsec; - } - - return temp; -} - -void print_difftimes(void) { -#ifdef DEBUG - printf("difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); -#else - LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); -#endif -} - -void update_difftimes(struct timespec start, struct timespec end) { - struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - int changed = 0; - diff_time = clock_difftime(start, end); - - if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { - min_diff_time.tv_nsec = diff_time.tv_nsec; - changed = 1; - } - - if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { - max_diff_time.tv_nsec = diff_time.tv_nsec; - changed = 1; - } - -#if 1 - - if (changed) print_difftimes(); - -#endif -} - /*------------------------------------------------------------------------*/ unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { @@ -384,7 +335,8 @@ void set_default_frame_parms(LTE_DL_FRAME_PARMS *frame_parms[MAX_NUM_CCs]) { } } -void init_openair0(LTE_DL_FRAME_PARMS *frame_parms,int rxgain) { +static void init_openair0(LTE_DL_FRAME_PARMS *frame_parms, int rxgain) +{ int card; int i; diff --git a/executables/main_ru.c b/executables/main_ru.c index 86a26f9ac3..3579c26f7a 100644 --- a/executables/main_ru.c +++ b/executables/main_ru.c @@ -97,11 +97,19 @@ void exit_function(const char *file, const char *function, const int line, const oai_exit = 1; if (ru_m.rfdevice.trx_end_func) { + if (ru_m.rfdevice.trx_get_stats_func) { + ru_m.rfdevice.trx_get_stats_func(&ru_m.rfdevice); + ru_m.rfdevice.trx_get_stats_func = NULL; + } ru_m.rfdevice.trx_end_func(&ru_m.rfdevice); ru_m.rfdevice.trx_end_func = NULL; } if (ru_m.ifdevice.trx_end_func) { + if (ru_m.ifdevice.trx_get_stats_func) { + ru_m.ifdevice.trx_get_stats_func(&ru_m.ifdevice); + ru_m.ifdevice.trx_get_stats_func = NULL; + } ru_m.ifdevice.trx_end_func(&ru_m.ifdevice); ru_m.ifdevice.trx_end_func = NULL; } @@ -363,11 +371,19 @@ int main ( int argc, char **argv ) end_configmodule(uniqCfg); if (ru->rfdevice.trx_end_func) { + if (ru->rfdevice.trx_get_stats_func) { + ru->rfdevice.trx_get_stats_func(&ru->rfdevice); + ru->rfdevice.trx_get_stats_func = NULL; + } ru->rfdevice.trx_end_func(&ru->rfdevice); ru->rfdevice.trx_end_func = NULL; } if (ru->ifdevice.trx_end_func) { + if (ru->ifdevice.trx_get_stats_func) { + ru->ifdevice.trx_get_stats_func(&ru->ifdevice); + ru->ifdevice.trx_get_stats_func = NULL; + } ru->ifdevice.trx_end_func(&ru->ifdevice); ru->ifdevice.trx_end_func = NULL; } diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 6467683cac..403f78ddb3 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -37,7 +37,6 @@ RAN_CONTEXT_t RC; THREAD_STRUCT thread_struct; uint64_t downlink_frequency[MAX_NUM_CCs][4]; int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; -int asn1_xer_print; int oai_exit = 0; instance_t CUuniqInstance = 0; diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index acab30751b..505adf825c 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -114,7 +114,7 @@ static void tx_func(processingData_L1tx_t *info) pushNotifiedFIFO(&gNB->resp_L1, res); int tx_slot_type = nr_slot_select(cfg, frame_tx, slot_tx); - if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx) { + if (tx_slot_type == NR_DOWNLINK_SLOT || tx_slot_type == NR_MIXED_SLOT || get_softmodem_params()->continuous_tx || IS_SOFTMODEM_RFSIM) { start_meas(&info->gNB->phy_proc_tx); phy_procedures_gNB_TX(info, frame_tx, slot_tx, 1); @@ -174,6 +174,8 @@ static void rx_func(processingData_L1_t *info) int slot_rx = info->slot_rx; nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config; + T(T_GNB_PHY_UL_TICK, T_INT(gNB->Mod_id), T_INT(frame_rx), T_INT(slot_rx)); + // RX processing int rx_slot_type = nr_slot_select(cfg, frame_rx, slot_rx); if (rx_slot_type == NR_UPLINK_SLOT || rx_slot_type == NR_MIXED_SLOT) { @@ -231,6 +233,9 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size output += print_meas_log(&gNB->dlsch_resource_mapping_stats, "DLSCH resource mapping", NULL, NULL, output,end-output); output += print_meas_log(&gNB->dlsch_precoding_stats, "DLSCH precoding", NULL, NULL, output,end-output); output += print_meas_log(&gNB->phy_proc_rx, "L1 Rx processing", NULL, NULL, output, end - output); + output += print_meas_log(&gNB->ts_deinterleave, "UL segment deinterleaving", NULL, NULL, output, end - output); + output += print_meas_log(&gNB->ts_rate_unmatch, "UL segment rate recovery", NULL, NULL, output, end - output); + output += print_meas_log(&gNB->ts_ldpc_decode, "UL segments decoding", NULL, NULL, output, end - output); output += print_meas_log(&gNB->ul_indication_stats, "UL Indication", NULL, NULL, output, end - output); output += print_meas_log(&gNB->slot_indication_stats, "Slot Indication", NULL, NULL, output, end - output); output += print_meas_log(&gNB->rx_pusch_stats, "PUSCH inner-receiver", NULL, NULL, output, end - output); @@ -239,14 +244,26 @@ static size_t dump_L1_meas_stats(PHY_VARS_gNB *gNB, RU_t *ru, char *output, size if (ru->feprx) output += print_meas_log(&ru->ofdm_demod_stats, "feprx", NULL, NULL, output, end - output); + bool full_slot = ru->half_slot_parallelization == 0; if (ru->feptx_prec) { - output += print_meas_log(&ru->precoding_stats,"feptx_prec",NULL,NULL, output, end - output); + output += print_meas_log(&ru->precoding_stats, + full_slot ? "feptx_prec (per port)" : "feptx_prec (per port, half_slot)", + NULL, + NULL, + output, + end - output); } if (ru->feptx_ofdm) { output += print_meas_log(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL, output, end - output); - output += print_meas_log(&ru->ofdm_mod_stats,"feptx_ofdm",NULL,NULL, output, end - output); + output += print_meas_log(&ru->ofdm_mod_stats, + full_slot ? "feptx_ofdm (per port)" : "feptx_ofdm (per port, half_slot)", + NULL, + NULL, + output, + end - output); output += print_meas_log(&ru->ofdm_total_stats,"feptx_total",NULL,NULL, output, end - output); + output += print_meas_log(&ru->txdataF_copy_stats, "txdataF_copy", NULL, NULL, output, end - output); } if (ru->fh_north_asynch_in) @@ -276,6 +293,9 @@ void *nrL1_stats_thread(void *param) { reset_meas(&gNB->phy_proc_tx); reset_meas(&gNB->dlsch_encoding_stats); reset_meas(&gNB->phy_proc_rx); + reset_meas(&gNB->ts_deinterleave); + reset_meas(&gNB->ts_rate_unmatch); + reset_meas(&gNB->ts_ldpc_decode); reset_meas(&gNB->ul_indication_stats); reset_meas(&gNB->slot_indication_stats); reset_meas(&gNB->rx_pusch_stats); @@ -312,15 +332,10 @@ void init_gNB_Tpool(int inst) gNB->num_pusch_symbols_per_thread = 1; // ULSCH decoding threadpool initTpool(get_softmodem_params()->threadPoolConfig, &gNB->threadPool, cpumeas(CPUMEAS_GETSTATE)); - // ULSCH decoder result FIFO - initNotifiedFIFO(&gNB->respPuschSymb); - initNotifiedFIFO(&gNB->respDecode); // L1 RX result FIFO initNotifiedFIFO(&gNB->resp_L1); - // L1 TX result FIFO - initNotifiedFIFO(&gNB->L1_tx_free); - initNotifiedFIFO(&gNB->L1_tx_filled); + // L1 TX result FIFO initNotifiedFIFO(&gNB->L1_tx_out); initNotifiedFIFO(&gNB->L1_rx_out); @@ -349,10 +364,6 @@ void term_gNB_Tpool(int inst) { pthread_join(gNB->L1_tx_thread, NULL); abortTpool(&gNB->threadPool); - abortNotifiedFIFO(&gNB->respPuschSymb); - abortNotifiedFIFO(&gNB->respDecode); - abortNotifiedFIFO(&gNB->L1_tx_free); - abortNotifiedFIFO(&gNB->L1_tx_filled); abortNotifiedFIFO(&gNB->L1_rx_out); gNB_L1_proc_t *proc = &gNB->proc; diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 411caf9a63..20deff5725 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -63,7 +63,6 @@ static int DEFRUTPCORES[] = {-1,-1,-1,-1}; #include - #include "T.h" #include "nfapi_interface.h" #include @@ -74,63 +73,69 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg); /*************************************************************/ /* Functions to attach and configure RRU */ -int attach_rru(RU_t *ru) { - ssize_t msg_len,len; +int attach_rru(RU_t *ru) +{ RRU_CONFIG_msg_t rru_config_msg; int received_capabilities=0; wait_gNBs(); // Wait for capabilities while (received_capabilities==0) { - memset((void *)&rru_config_msg,0,sizeof(rru_config_msg)); - rru_config_msg.type = RAU_tick; - rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; + rru_config_msg = (RRU_CONFIG_msg_t){.type = RAU_tick, .len = sizeof(rru_config_msg.msg)}; LOG_D(PHY, "Sending RAU tick to RRU %d\n", ru->idx); AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), "RU %d cannot access remote radio\n",ru->idx); - msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); - + ssize_t msg_len = rru_config_msg.len + sizeof(RRU_capabilities_t); // wait for answer with timeout - if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, - &rru_config_msg, - msg_len))<0) { + ssize_t len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, msg_len); + if (len < 0) { LOG_D(PHY, "Waiting for RRU %d\n", ru->idx); } else if (rru_config_msg.type == RRU_capabilities) { - AssertFatal(rru_config_msg.len==msg_len,"Received capabilities with incorrect length (%d!=%d)\n",(int)rru_config_msg.len,(int)msg_len); - LOG_I(PHY,"Received capabilities from RRU %d (len %d/%d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n",ru->idx, - (int)rru_config_msg.len,(int)msg_len, - ((RRU_capabilities_t *)&rru_config_msg.msg[0])->num_bands, - ((RRU_capabilities_t *)&rru_config_msg.msg[0])->max_pdschReferenceSignalPower[0], - ((RRU_capabilities_t *)&rru_config_msg.msg[0])->max_rxgain[0], - ((RRU_capabilities_t *)&rru_config_msg.msg[0])->nb_tx[0], - ((RRU_capabilities_t *)&rru_config_msg.msg[0])->nb_rx[0]); + AssertFatal(rru_config_msg.len == msg_len, + "Received capabilities with incorrect length (%ld!=%ld)\n", + rru_config_msg.len, + msg_len); + RRU_capabilities_t *cap = (RRU_capabilities_t *)rru_config_msg.msg; + LOG_I(PHY, + "Received capabilities from RRU %d (len %ld/%ld, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx " + "%d, nb_rx %d)\n", + ru->idx, + rru_config_msg.len, + msg_len, + cap->num_bands, + cap->max_pdschReferenceSignalPower[0], + cap->max_rxgain[0], + cap->nb_tx[0], + cap->nb_rx[0]); received_capabilities=1; } else { LOG_E(PHY,"Received incorrect message %d from RRU %d\n",rru_config_msg.type,ru->idx); } } - configure_ru(ru, (RRU_capabilities_t *)&rru_config_msg.msg[0]); + configure_ru(ru, (RRU_capabilities_t *)rru_config_msg.msg); rru_config_msg.type = RRU_config; rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); - LOG_I(PHY,"Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n",ru->idx, - ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, - ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); + RRU_config_t *conf = (RRU_config_t *)rru_config_msg.msg; + LOG_I(PHY, + "Sending Configuration to RRU %d (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL " + "%d,3/4FS %d, prach_FO %d, prach_CI %d)\n", + ru->idx, + conf->num_bands, + conf->band_list[0], + conf->tx_freq[0], + conf->rx_freq[0], + conf->att_tx[0], + conf->att_rx[0], + conf->N_RB_DL[0], + conf->N_RB_UL[0], + conf->threequarter_fs[0], + conf->prach_FreqOffset[0], + conf->prach_ConfigIndex[0]); AssertFatal((ru->ifdevice.trx_ctlsend_func(&ru->ifdevice,&rru_config_msg,rru_config_msg.len)!=-1), "RU %d failed send configuration to remote radio\n",ru->idx); - - if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, - &rru_config_msg, - msg_len))<0) { + int len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, sizeof(rru_config_msg.msg)); + if (len < 0) { LOG_I(PHY,"Waiting for RRU %d\n",ru->idx); } else if (rru_config_msg.type == RRU_config_ok) { LOG_I(PHY, "RRU_config_ok received\n"); @@ -142,58 +147,57 @@ int attach_rru(RU_t *ru) { } int connect_rau(RU_t *ru) { - RRU_CONFIG_msg_t rru_config_msg; - ssize_t msg_len; - int tick_received = 0; - int configuration_received = 0; - RRU_capabilities_t *cap; - int i; - int len; + RRU_CONFIG_msg_t rru_config_msg; // wait for RAU_tick + int tick_received = 0; while (tick_received == 0) { - msg_len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE; - - if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, - &rru_config_msg, - msg_len))<0) { + ssize_t msg_len = sizeof(rru_config_msg.msg); + int len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, msg_len); + if (len < 0) { LOG_I(PHY,"Waiting for RAU\n"); } else { if (rru_config_msg.type == RAU_tick) { LOG_I(PHY,"Tick received from RAU\n"); tick_received = 1; - } else LOG_E(PHY,"Received erroneous message (%d)from RAU, expected RAU_tick\n",rru_config_msg.type); + } else + LOG_E(PHY, "Received erroneous message (%d)from RAU, expected RAU_tick\n", rru_config_msg.type); } } // send capabilities rru_config_msg.type = RRU_capabilities; rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_capabilities_t); - cap = (RRU_capabilities_t *)&rru_config_msg.msg[0]; - LOG_I(PHY,"Sending Capabilities (len %d, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n", - (int)rru_config_msg.len,ru->num_bands,ru->max_pdschReferenceSignalPower,ru->max_rxgain,ru->nb_tx,ru->nb_rx); + RRU_capabilities_t *cap = (RRU_capabilities_t *)rru_config_msg.msg; + LOG_I(PHY, + "Sending Capabilities (len %ld, num_bands %d,max_pdschReferenceSignalPower %d, max_rxgain %d, nb_tx %d, nb_rx %d)\n", + rru_config_msg.len, + ru->num_bands, + ru->max_pdschReferenceSignalPower, + ru->max_rxgain, + ru->nb_tx, + ru->nb_rx); switch (ru->function) { case NGFI_RRU_IF4p5: - cap->FH_fmt = OAI_IF4p5_only; + cap->FH_fmt = OAI_IF4p5_only; break; case NGFI_RRU_IF5: - cap->FH_fmt = OAI_IF5_only; + cap->FH_fmt = OAI_IF5_only; break; case MBP_RRU_IF5: - cap->FH_fmt = MBP_IF5; + cap->FH_fmt = MBP_IF5; break; default: - AssertFatal(1==0,"RU_function is unknown %d\n",RC.ru[0]->function); + AssertFatal(false, "RU_function is unknown %d\n", RC.ru[0]->function); break; } - cap->num_bands = ru->num_bands; - - for (i=0; inum_bands; i++) { + cap->num_bands = ru->num_bands; + for (int i = 0; i < ru->num_bands; i++) { LOG_I(PHY,"Band %d: nb_rx %d nb_tx %d pdschReferenceSignalPower %d rxgain %d\n", ru->band[i],ru->nb_rx,ru->nb_tx,ru->max_pdschReferenceSignalPower,ru->max_rxgain); cap->band_list[i] = ru->band[i]; @@ -208,25 +212,28 @@ int connect_rau(RU_t *ru) { // wait for configuration rru_config_msg.len = sizeof(RRU_CONFIG_msg_t)-MAX_RRU_CONFIG_SIZE+sizeof(RRU_config_t); + int configuration_received = 0; while (configuration_received == 0) { - if ((len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, - &rru_config_msg, - rru_config_msg.len))<0) { + int len = ru->ifdevice.trx_ctlrecv_func(&ru->ifdevice, &rru_config_msg, rru_config_msg.len); + if (len < 0) { LOG_I(PHY,"Waiting for configuration from RAU\n"); } else { - LOG_I(PHY,"Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL %d,3/4FS %d, prach_FO %d, prach_CI %d)\n", - ((RRU_config_t *)&rru_config_msg.msg[0])->num_bands, - ((RRU_config_t *)&rru_config_msg.msg[0])->band_list[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->tx_freq[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->rx_freq[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->att_tx[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->att_rx[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_DL[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->N_RB_UL[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->threequarter_fs[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->prach_FreqOffset[0], - ((RRU_config_t *)&rru_config_msg.msg[0])->prach_ConfigIndex[0]); - configure_rru(ru, (void *)&rru_config_msg.msg[0]); + RRU_config_t *conf = (RRU_config_t *)rru_config_msg.msg; + LOG_I(PHY, + "Configuration received from RAU (num_bands %d,band0 %d,txfreq %u,rxfreq %u,att_tx %d,att_rx %d,N_RB_DL %d,N_RB_UL " + "%d,3/4FS %d, prach_FO %d, prach_CI %d)\n", + conf->num_bands, + conf->band_list[0], + conf->tx_freq[0], + conf->rx_freq[0], + conf->att_tx[0], + conf->att_rx[0], + conf->N_RB_DL[0], + conf->N_RB_UL[0], + conf->threequarter_fs[0], + conf->prach_FreqOffset[0], + conf->prach_ConfigIndex[0]); + configure_rru(ru, (void *)rru_config_msg.msg); configuration_received = 1; } } @@ -238,15 +245,23 @@ int connect_rau(RU_t *ru) { // southbound IF5 fronthaul for 16-bit OAI format void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { - if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); + if (ru == RC.ru[0]) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx & 0xffffffff); int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0); void *buffs[ru->nb_tx]; for (int aid = 0; aid < ru->nb_tx; aid++) buffs[aid] = (void*)&ru->common.txdata[aid][offset]; struct timespec txmeas; clock_gettime(CLOCK_MONOTONIC, &txmeas); - LOG_D(NR_PHY,"IF5 TX %d.%d, TS %llu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n",frame,slot,(unsigned long long)timestamp,buffs[0],buffs[1], - 10*log10((double)signal_energy(buffs[0],ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms))),(int)txmeas.tv_nsec); + LOG_D(NR_PHY, + "IF5 TX %d.%d, TS %lu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n", + frame, + slot, + timestamp, + buffs[0], + buffs[1], + 10 * log10((double)signal_energy(buffs[0], ru->nr_frame_parms->get_samples_per_slot(slot, ru->nr_frame_parms))), + (int)txmeas.tv_nsec); ru->ifdevice.trx_write_func2(&ru->ifdevice, timestamp, buffs, @@ -258,13 +273,12 @@ void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { // southbound IF4p5 fronthaul void fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { - nfapi_nr_config_request_scf_t *cfg = &ru->config; - - if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); + if (ru == RC.ru[0]) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx & 0xffffffff); LOG_D(PHY,"Sending IF4p5 for frame %d subframe %d\n",ru->proc.frame_tx,ru->proc.tti_tx); - if ((nr_slot_select(cfg,ru->proc.frame_tx,ru->proc.tti_tx)&NR_DOWNLINK_SLOT) > 0) + if ((nr_slot_select(&ru->config, ru->proc.frame_tx, ru->proc.tti_tx) & NR_DOWNLINK_SLOT) > 0) send_IF4p5(ru,frame, slot, IF4p5_PDLFFT); } @@ -281,11 +295,11 @@ void fh_if5_south_in(RU_t *ru, VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5, 1 ); start_meas(&ru->rx_fhaul); - ru->ifdevice.trx_read_func2(&ru->ifdevice,&proc->timestamp_rx,NULL,fp->get_samples_per_slot(*tti,fp)); - if (proc->first_rx == 1) ru->ts_offset = proc->timestamp_rx; - proc->frame_rx = ((proc->timestamp_rx-ru->ts_offset) / (fp->samples_per_subframe*10))&1023; - proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx-ru->ts_offset,fp); - + ru->ifdevice.trx_read_func2(&ru->ifdevice, &proc->timestamp_rx, NULL, fp->get_samples_per_slot(*tti, fp)); + if (proc->first_rx == 1) + ru->ts_offset = proc->timestamp_rx; + proc->frame_rx = ((proc->timestamp_rx - ru->ts_offset) / (fp->samples_per_subframe * 10)) & 1023; + proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx - ru->ts_offset, fp); if (proc->first_rx == 0) { if (proc->tti_rx != *tti) { @@ -311,8 +325,26 @@ void fh_if5_south_in(RU_t *ru, struct timespec rxmeas; clock_gettime(CLOCK_MONOTONIC, &rxmeas); double fhtime = ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0); - if (fhtime > 800) LOG_W(PHY,"IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %d\n",*frame,*tti,proc->frame_rx,proc->tti_rx,proc->first_rx,ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0),(int)rxmeas.tv_nsec); - else LOG_D(PHY,"IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %d\n",*frame,*tti,proc->frame_rx,proc->tti_rx,proc->first_rx,ru->rx_fhaul.p_time/(cpu_freq_GHz*1000.0),(int)rxmeas.tv_nsec); + if (fhtime > 800) + LOG_W(PHY, + "IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %ld\n", + *frame, + *tti, + proc->frame_rx, + proc->tti_rx, + proc->first_rx, + ru->rx_fhaul.p_time / (cpu_freq_GHz * 1000.0), + rxmeas.tv_nsec); + else + LOG_D(PHY, + "IF5 %d.%d => RX %d.%d first_rx %d: time %f, rxstart %ld\n", + *frame, + *tti, + proc->frame_rx, + proc->tti_rx, + proc->first_rx, + ru->rx_fhaul.p_time / (cpu_freq_GHz * 1000.0), + rxmeas.tv_nsec); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, proc->timestamp_rx&0xffffffff ); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_RECV_IF5, 0 ); @@ -329,21 +361,16 @@ void fh_if4p5_south_in(RU_t *ru, uint32_t symbol_number=0; uint32_t symbol_mask_full=0; - /* - if ((fp->frame_type == TDD) && (subframe_select(fp,*slot)==SF_S)) - symbol_mask_full = (1<ul_symbols_in_S_subframe)-1; - else - symbol_mask_full = (1<symbols_per_slot)-1; - - AssertFatal(proc->symbol_mask[*slot]==0,"rx_fh_if4p5: proc->symbol_mask[%d] = %x\n",*slot,proc->symbol_mask[*slot]);*/ do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! recv_IF4p5(ru, &f, &sl, &packet_type, &symbol_number); if (packet_type == IF4p5_PULFFT) proc->symbol_mask[sl] = proc->symbol_mask[sl] | (1<first_rx==0) && (f!=*frame)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received frame %d != expected %d\n",f,*frame); + if ((proc->first_rx == 0) && (f != *frame)) + LOG_E(PHY, "rx_fh_if4p5: PULTICK received frame %d != expected %d\n", f, *frame); - if ((proc->first_rx==0) && (sl!=*slot)) LOG_E(PHY,"rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n",sl,*slot,proc->first_rx); + if ((proc->first_rx == 0) && (sl != *slot)) + LOG_E(PHY, "rx_fh_if4p5: PULTICK received subframe %d != expected %d (first_rx %d)\n", sl, *slot, proc->first_rx); break; } else if (packet_type == IF4p5_PRACH) { @@ -359,7 +386,7 @@ void fh_if4p5_south_in(RU_t *ru, proc->timestamp_rx = (proc->frame_rx * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(proc->tti_rx, fp, 0); // proc->timestamp_tx = proc->timestamp_rx + (4*fp->samples_per_subframe); proc->tti_tx = (sl+ru->sl_ahead)%fp->slots_per_frame; - proc->frame_tx = (sl>(fp->slots_per_frame-1-(ru->sl_ahead))) ? (f+1)&1023 : f; + proc->frame_tx = (sl > (fp->slots_per_frame - 1 - (ru->sl_ahead))) ? (f + 1) & 1023 : f; if (proc->first_rx == 0) { if (proc->tti_rx != *slot) { @@ -394,20 +421,12 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *slot) { NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; RU_proc_t *proc = &ru->proc; uint16_t packet_type; - uint32_t symbol_number,symbol_mask,prach_rx; - // uint32_t got_prach_info=0; - symbol_number = 0; - symbol_mask = (1<<(fp->symbols_per_slot))-1; - prach_rx = 0; + uint32_t symbol_number = 0; + uint32_t symbol_mask = (1 << fp->symbols_per_slot) - 1; + uint32_t prach_rx = 0; do { // Blocking, we need a timeout on this !!!!!!!!!!!!!!!!!!!!!!! recv_IF4p5(ru, &proc->frame_rx, &proc->tti_rx, &packet_type, &symbol_number); - - // grab first prach information for this new subframe - /*if (got_prach_info==0) { - prach_rx = is_prach_subframe(fp, proc->frame_rx, proc->tti_rx); - got_prach_info = 1; - }*/ if (proc->first_rx != 0) { *frame = proc->frame_rx; *slot = proc->tti_rx; @@ -417,22 +436,19 @@ void fh_if4p5_south_asynch_in(RU_t *ru,int *frame,int *slot) { LOG_E(PHY,"frame_rx %d is not what we expect %d\n",proc->frame_rx,*frame); exit_fun("Exiting"); } - if (proc->tti_rx != *slot) { LOG_E(PHY,"tti_rx %d is not what we expect %d\n",proc->tti_rx,*slot); exit_fun("Exiting"); } } - if (packet_type == IF4p5_PULFFT) symbol_mask &= (~(1< 0) || (prach_rx >0)); // haven't received all PUSCH symbols and PRACH information + if (packet_type == IF4p5_PULFFT) + symbol_mask &= ~(1 << symbol_number); + else if (packet_type == IF4p5_PRACH) + prach_rx &= ~0x1; + } while (symbol_mask > 0 || prach_rx > 0); // haven't received all PUSCH symbols and PRACH information } - - - - /*************************************************************/ /* Input Fronthaul from North RRU */ @@ -459,26 +475,9 @@ void fh_if4p5_north_in(RU_t *ru,int *frame,int *slot) { } } -void fh_if5_north_asynch_in(RU_t *ru,int *frame,int *slot) { - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - RU_proc_t *proc = &ru->proc; - int tti_tx,frame_tx; - openair0_timestamp timestamp_tx = 0; +void fh_if5_north_asynch_in(RU_t *ru, int *frame, int *slot) +{ AssertFatal(1 == 0, "Shouldn't get here\n"); - frame_tx = (timestamp_tx / (fp->samples_per_subframe*10))&1023; - uint32_t idx_sf = timestamp_tx / fp->samples_per_subframe; - tti_tx = (idx_sf * fp->slots_per_subframe + (int)round((float)(timestamp_tx % fp->samples_per_subframe) / fp->samples_per_slot0))%(fp->slots_per_frame); - - if (proc->first_tx != 0) { - *slot = tti_tx; - *frame = frame_tx; - proc->first_tx = 0; - } else { - AssertFatal(tti_tx == *slot, - "tti_tx %d is not what we expect %d\n",tti_tx,*slot); - AssertFatal(frame_tx == *frame, - "frame_tx %d is not what we expect %d\n",frame_tx,*frame); - } } void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) { @@ -486,17 +485,18 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) { nfapi_nr_config_request_scf_t *cfg = &ru->config; RU_proc_t *proc = &ru->proc; uint16_t packet_type; - uint32_t symbol_number,symbol_mask,symbol_mask_full=0; + uint32_t symbol_mask_full = 0; int slot_tx,frame_tx; LOG_D(PHY, "%s(ru:%p frame, subframe)\n", __FUNCTION__, ru); - symbol_number = 0; - symbol_mask = 0; + uint32_t symbol_number = 0; + uint32_t symbol_mask = 0; // symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_slot))-1; do { recv_IF4p5(ru, &frame_tx, &slot_tx, &packet_type, &symbol_number); - if (((nr_slot_select(cfg,frame_tx,slot_tx) & NR_DOWNLINK_SLOT) > 0) && (symbol_number == 0)) start_meas(&ru->rx_fhaul); + if (((nr_slot_select(cfg, frame_tx, slot_tx) & NR_DOWNLINK_SLOT) > 0) && (symbol_number == 0)) + start_meas(&ru->rx_fhaul); LOG_D(PHY,"slot %d (%d): frame %d, slot %d, symbol %d\n", *slot,nr_slot_select(cfg,frame_tx,*slot),frame_tx,slot_tx,symbol_number); @@ -505,7 +505,6 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) { *frame = frame_tx; *slot = slot_tx; proc->first_tx = 0; - //symbol_mask_full = ((subframe_select(fp,*slot) == SF_S) ? (1<dl_symbols_in_S_subframe) : (1<symbols_per_slot))-1; } else { AssertFatal(frame_tx == *frame, "frame_tx %d is not what we expect %d\n",frame_tx,*frame); @@ -515,18 +514,22 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) { if (packet_type == IF4p5_PDLFFT) { symbol_mask = symbol_mask | (1<0) stop_meas(&ru->rx_fhaul); + if ((nr_slot_select(cfg, frame_tx, slot_tx) & NR_DOWNLINK_SLOT) > 0) + stop_meas(&ru->rx_fhaul); proc->tti_tx = slot_tx; proc->frame_tx = frame_tx; - if ((frame_tx == 0)&&(slot_tx == 0)) proc->frame_tx_unwrap += 1024; + if (frame_tx == 0 && slot_tx == 0) + proc->frame_tx_unwrap += 1024; - proc->timestamp_tx = (((uint64_t)frame_tx + (uint64_t)proc->frame_tx_unwrap) * fp->samples_per_subframe * 10) + fp->get_samples_slot_timestamp(slot_tx, fp, 0); - LOG_D(PHY,"RU %d/%d TST %llu, frame %d, subframe %d\n",ru->idx,0,(long long unsigned int)proc->timestamp_tx,frame_tx,slot_tx); + proc->timestamp_tx = + ((uint64_t)frame_tx + proc->frame_tx_unwrap) * fp->samples_per_subframe * 10 + fp->get_samples_slot_timestamp(slot_tx, fp, 0); + LOG_D(PHY, "RU %d/%d TST %lu, frame %d, subframe %d\n", ru->idx, 0, proc->timestamp_tx, frame_tx, slot_tx); // dump VCD output for first RU in list if (ru == RC.ru[0]) { @@ -544,48 +547,20 @@ void fh_if4p5_north_asynch_in(RU_t *ru,int *frame,int *slot) { void fh_if5_north_out(RU_t *ru) { /// **** send_IF5 of rxdata to BBU **** /// VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 1 ); - AssertFatal(1==0,"Shouldn't get here\n"); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_SEND_IF5, 0 ); + AssertFatal(1 == 0, "Shouldn't get here\n"); } // RRU IF4p5 northbound interface (RX) void fh_if4p5_north_out(RU_t *ru) { RU_proc_t *proc=&ru->proc; + if (ru->idx == 0) + VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx); - //NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - //const int subframe = proc->tti_rx; - if (ru->idx==0) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_RX0_RU, proc->tti_rx ); - - /* - if ((fp->frame_type == TDD) && (subframe_select(fp,subframe)!=SF_UL)) { - /// **** in TDD during DL send_IF4 of ULTICK to RCC **** /// - send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULTICK); - return; - }*/ start_meas(&ru->tx_fhaul); send_IF4p5(ru, proc->frame_rx, proc->tti_rx, IF4p5_PULFFT); stop_meas(&ru->tx_fhaul); } -void *emulatedRF_thread(void *param) { - RU_proc_t *proc = (RU_proc_t *) param; - int microsec = 500; // length of time to sleep, in miliseconds - struct timespec req = {0}; - req.tv_sec = 0; - req.tv_nsec = (numerology>0)? ((microsec * 1000L)/numerology):(microsec * 1000L)*2; - wait_sync("emulatedRF_thread"); - - while(!oai_exit) { - nanosleep(&req, (struct timespec *)NULL); - pthread_mutex_lock(&proc->mutex_emulateRF); - ++proc->instance_cnt_emulateRF; - pthread_mutex_unlock(&proc->mutex_emulateRF); - pthread_cond_signal(&proc->cond_emulateRF); - } - - return 0; -} - static void rx_rf(RU_t *ru, int *frame, int *slot) { RU_proc_t *proc = &ru->proc; @@ -606,20 +581,11 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) openair0_timestamp ts; unsigned int rxs; - if(emulate_rf) { - wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); - rxs = samples_per_slot; - ts = old_ts + rxs; - } else { - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb); - } + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); proc->timestamp_rx = ts-ru->ts_offset; - //AssertFatal(rxs == fp->samples_per_subframe, - //"rx_rf: Asked for %d samples, got %d from USRP\n",fp->samples_per_subframe,rxs); if (rxs != samples_per_slot) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n", samples_per_slot, rxs); @@ -636,23 +602,26 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) } } - //compute system frame number (SFN) according to O-RAN-WG4-CUS.0-v02.00 (using alpha=beta=0) - // this assumes that the USRP has been synchronized to the GPS time - // OAI uses timestamps in sample time stored in int64_t, but it will fit in double precision for many years to come. - double gps_sec = ((double) ts)/cfg->sample_rate; - //proc->frame_rx = ((int64_t) (gps_sec/0.01)) & 1023; + // compute system frame number (SFN) according to O-RAN-WG4-CUS.0-v02.00 (using alpha=beta=0) + // this assumes that the USRP has been synchronized to the GPS time + // OAI uses timestamps in sample time stored in int64_t, but it will fit in double precision for many years to come. + double gps_sec = ((double)ts) / cfg->sample_rate; // in fact the following line is the same as long as the timestamp_rx is synchronized to GPS. proc->frame_rx = (proc->timestamp_rx / (fp->samples_per_subframe*10))&1023; proc->tti_rx = fp->get_slot_from_timestamp(proc->timestamp_rx,fp); // synchronize first reception to frame 0 subframe 0 - LOG_D(PHY,"RU %d/%d TS %ld, GPS %f, SR %f, frame %d, slot %d.%d / %d\n", + LOG_D(PHY, + "RU %d/%d TS %ld, GPS %f, SR %f, frame %d, slot %d.%d / %d\n", ru->idx, 0, - ts, //(unsigned long long int)(proc->timestamp_rx+ru->ts_offset), - gps_sec, - cfg->sample_rate, - proc->frame_rx,proc->tti_rx,proc->tti_tx,fp->slots_per_frame); + ts, + gps_sec, + cfg->sample_rate, + proc->frame_rx, + proc->tti_rx, + proc->tti_tx, + fp->slots_per_frame); // dump VCD output for first RU in list if (ru == RC.ru[0]) { @@ -662,15 +631,19 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) if (proc->first_rx == 0) { if (proc->tti_rx != *slot) { - LOG_E(PHY,"Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->tti_rx %d, slot %d)\n",(long long unsigned int)proc->timestamp_rx,proc->tti_rx,*slot); + LOG_E(PHY, + "Received Timestamp (%lu) doesn't correspond to the time we think it is (proc->tti_rx %d, slot %d)\n", + proc->timestamp_rx, + proc->tti_rx, + *slot); exit_fun("Exiting"); } if (proc->frame_rx != *frame) { LOG_E(PHY, - "Received Timestamp (%llu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d, proc->tti_rx %d, " + "Received Timestamp (%lu) doesn't correspond to the time we think it is (proc->frame_rx %d frame %d, proc->tti_rx %d, " "slot %d)\n", - (long long unsigned int)proc->timestamp_rx, + proc->timestamp_rx, proc->frame_rx, *frame, proc->tti_rx, @@ -683,10 +656,8 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) *slot = proc->tti_rx; } - if (!emulate_rf) { - metadata mt = {.slot = *slot, .frame = *frame}; - gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt); - } + metadata mt = {.slot = *slot, .frame = *frame}; + gNBscopeCopyWithMetadata(ru, gNbTimeDomainSamples, rxp[0], sizeof(c16_t), 1, samples_per_slot, 0, &mt); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TS, (proc->timestamp_rx+ru->ts_offset)&0xffffffff ); @@ -720,6 +691,7 @@ static radio_tx_gpio_flag_t get_gpio_flags(RU_t *ru, int slot) } } break; + case RU_GPIO_CONTROL_INTERDIGITAL: { // the beam index is written in bits 8-10 of the flags // bit 11 enables the gpio programming @@ -759,7 +731,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) radio_tx_burst_flag_t flags_burst = TX_BURST_INVALID; radio_tx_gpio_flag_t flags_gpio = 0; - if (cfg->cell_config.frame_duplex_type.value == TDD && !get_softmodem_params()->continuous_tx) { + if (cfg->cell_config.frame_duplex_type.value == TDD && !get_softmodem_params()->continuous_tx && !IS_SOFTMODEM_RFSIM) { int slot_type = nr_slot_select(cfg,frame,slot%fp->slots_per_frame); if(slot_type == NR_MIXED_SLOT) { int txsymb = 0; @@ -805,9 +777,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) flags_gpio = get_gpio_flags(ru, slot); const int flags = flags_burst | (flags_gpio << 4); - - if (proc->first_tx == 1) - proc->first_tx = 0; + proc->first_tx = 0; VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_WRITE_FLAGS, flags); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame); @@ -828,10 +798,10 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) nt, flags); LOG_D(PHY, - "[TXPATH] RU %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, " + "[TXPATH] RU %d tx_rf, writing to TS %lu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, " "returned %d, E %f\n", ru->idx, - (long long unsigned int)(timestamp + ru->ts_offset - sf_extension), + timestamp + ru->ts_offset - sf_extension, frame, slot, proc->frame_tx_unwrap, @@ -841,7 +811,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) txs, 10 * log10((double)signal_energy(txp[0], siglen + sf_extension))); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_WRITE, 0); - // AssertFatal(txs == 0,"trx write function error %d\n", txs); } static void fill_rf_config(RU_t *ru, char *rf_config_file) @@ -880,12 +849,12 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { if (ru->if_frequency == 0) { - cfg->tx_freq[i] = (double)fp->dl_CarrierFreq; + cfg->tx_freq[i] = fp->dl_CarrierFreq; } else if (ru->if_freq_offset) { - cfg->tx_freq[i] = (double)(ru->if_frequency); + cfg->tx_freq[i] = ru->if_frequency; LOG_I(PHY, "Setting IF TX frequency to %lu Hz with IF TX frequency offset %d Hz\n", ru->if_frequency, ru->if_freq_offset); } else { - cfg->tx_freq[i] = (double)ru->if_frequency; + cfg->tx_freq[i] = ru->if_frequency; } cfg->tx_gain[i] = ru->att_tx; @@ -895,12 +864,12 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) { if (ru->if_frequency == 0) { - cfg->rx_freq[i] = (double)fp->ul_CarrierFreq; + cfg->rx_freq[i] = fp->ul_CarrierFreq; } else if (ru->if_freq_offset) { - cfg->rx_freq[i] = (double)(ru->if_frequency + ru->if_freq_offset); + cfg->rx_freq[i] = ru->if_frequency + ru->if_freq_offset; LOG_I(PHY, "Setting IF RX frequency to %lu Hz with IF RX frequency offset %d Hz\n", ru->if_frequency, ru->if_freq_offset); } else { - cfg->rx_freq[i] = (double)(ru->if_frequency+fp->ul_CarrierFreq-fp->dl_CarrierFreq); + cfg->rx_freq[i] = ru->if_frequency + fp->ul_CarrierFreq - fp->dl_CarrierFreq; } cfg->rx_gain[i] = ru->max_rxgain-ru->att_rx; @@ -909,11 +878,12 @@ 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, uint16_t ofdm_symbol_size) +static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp) { const nfapi_nr_prach_config_t *prach_config = &config->prach_config; const nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table; const nfapi_nr_cell_config_t *cell_config = &config->cell_config; + const nfapi_nr_carrier_config_t *carrier_config = &config->carrier_config; DevAssert(prach_config->prach_ConfigurationIndex.tl.tag == NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG); split7->prach_index = prach_config->prach_ConfigurationIndex.value; @@ -924,7 +894,7 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_ if (cell_config->frame_duplex_type.value == 1 /* TDD */) { DevAssert(tdd_table->tdd_period.tl.tag == NFAPI_NR_CONFIG_TDD_PERIOD_TAG); int nb_periods_per_frame = get_nb_periods_per_frame(tdd_table->tdd_period.value); - split7->n_tdd_period = slots_per_frame / nb_periods_per_frame; + split7->n_tdd_period = fp->slots_per_frame / nb_periods_per_frame; for (int slot = 0; slot < split7->n_tdd_period; ++slot) { for (int sym = 0; sym < 14; ++sym) { split7->slot_dirs[slot].sym_dir[sym] = tdd_table->max_tdd_periodicity_list[slot].max_num_of_symbol_per_slot_list[sym].slot_config.value; @@ -932,7 +902,15 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_ } } - split7->fftSize = log2(ofdm_symbol_size); + split7->fftSize = log2(fp->ofdm_symbol_size); + + // M-plane related parameters + for (size_t i = 0; i < 5 ; i++) { + split7->dl_k0[i] = carrier_config->dl_k0[i].value; + split7->ul_k0[i] = carrier_config->ul_k0[i].value; + } + split7->cp_prefix0 = fp->nb_prefix_samples0; + split7->cp_prefix_other = fp->nb_prefix_samples; } /* this function maps the RU tx and rx buffers to the available rf chains. @@ -941,17 +919,11 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_ antennas are mapped to successive RF chains on the same card. */ int setup_RU_buffers(RU_t *ru) { - int card,ant; - //uint16_t N_TA_offset = 0; - NR_DL_FRAME_PARMS *fp; + if (!ru) + return (-1); + + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; nfapi_nr_config_request_scf_t *config = &ru->config; - - if (ru) { - fp = ru->nr_frame_parms; - } else { - return(-1); - } - int mu = config->ssb_config.scs_common.value; int N_RB = config->carrier_config.dl_grid_size[config->ssb_config.scs_common.value].value; @@ -963,8 +935,8 @@ int setup_RU_buffers(RU_t *ru) if (ru->openair0_cfg.mmapped_dma == 1) { // replace RX signal buffers with mmaped HW versions for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) { - card = i / 4; - ant = i % 4; + int card = i / 4; + int ant = i % 4; LOG_D(PHY, "Mapping RU id %u, rx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant); free(ru->common.rxdata[i]); ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain + ant]; @@ -975,8 +947,8 @@ int setup_RU_buffers(RU_t *ru) } for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { - card = i / 4; - ant = i % 4; + int card = i / 4; + int ant = i % 4; LOG_D(PHY, "Mapping RU id %u, tx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant); free(ru->common.txdata[i]); ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain + ant]; @@ -985,99 +957,33 @@ int setup_RU_buffers(RU_t *ru) ru->common.txdata[i][j] = 16 - j; } } - } else { // not memory-mapped DMA - //nothing to do, everything already allocated in lte_init + } else { + // not memory-mapped DMA + // nothing to do, everything already allocated in lte_init } return(0); } -void *ru_stats_thread(void *param) { - RU_t *ru = (RU_t *)param; - wait_sync("ru_stats_thread"); - - while (!oai_exit) { - sleep(1); - - if (cpu_meas_enabled) { - if (ru->feprx) print_meas(&ru->ofdm_demod_stats,"feprx (all ports)",NULL,NULL); - - if (ru->feptx_ofdm) { - print_meas(&ru->precoding_stats,(ru->half_slot_parallelization==0)?"feptx_prec (per port)":"feptx_prec (per port, half_slot)",NULL,NULL); - print_meas(&ru->ofdm_mod_stats,(ru->half_slot_parallelization==0)?"feptx_ofdm (per port)":"feptx_ofdm (per port, half_slot)",NULL,NULL); - print_meas(&ru->txdataF_copy_stats,"txdataF_copy",NULL,NULL); - print_meas(&ru->ofdm_total_stats,"feptx_total",NULL,NULL); - } - print_meas(&ru->rx_fhaul,"rx_fhaul",NULL,NULL); - if (ru->if_south == REMOTE_IF5) print_meas(&ru->ifdevice.tx_fhaul,"tx_fhaul (IF5)",NULL,NULL); - else print_meas(&ru->tx_fhaul,"tx_fhaul",NULL,NULL); - - if (ru->fh_north_out) { - print_meas(&ru->compression,"compression",NULL,NULL); - print_meas(&ru->transport,"transport",NULL,NULL); - } - } - } - - return(NULL); -} - void ru_tx_func(void *param) { processingData_RU_t *info = (processingData_RU_t *) param; RU_t *ru = info->ru; - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int frame_tx = info->frame_tx; int slot_tx = info->slot_tx; - int print_frame = 8; - char filename[40]; // do TX front-end processing if needed (precoding and/or IDFTs) if (ru->feptx_prec) ru->feptx_prec(ru,frame_tx,slot_tx); // do OFDM with/without TX front-end processing if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->feptx_ofdm)) + if (ru->fh_north_asynch_in == NULL && ru->feptx_ofdm) ru->feptx_ofdm(ru, frame_tx, slot_tx); - if(!emulate_rf) { - // do outgoing fronthaul (south) if needed - if ((ru->fh_north_asynch_in == NULL) && (ru->fh_south_out)) - ru->fh_south_out(ru, frame_tx, slot_tx, info->timestamp_tx); - - if (ru->fh_north_out) - ru->fh_north_out(ru); - } else { - if(frame_tx == print_frame) { - for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { - if(slot_tx == 0) { - sprintf(filename,"gNBdataF_frame%d_sl%d.m", print_frame, slot_tx); - LOG_M(filename,"txdataF_frame",&ru->gNB_list[0]->common_vars.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1); - sprintf(filename,"tx%ddataF_frame%d_sl%d.m", i, print_frame, slot_tx); - LOG_M(filename,"txdataF_frame",&ru->common.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1); - sprintf(filename,"tx%ddataF_BF_frame%d_sl%d.m", i, print_frame, slot_tx); - LOG_M(filename,"txdataF_BF_frame",&ru->common.txdataF_BF[i][0],fp->samples_per_subframe_wCP, 1, 1); - } - - if(slot_tx == 9) { - sprintf(filename,"tx%ddata_frame%d.m", i, print_frame); - LOG_M(filename,"txdata_frame",&ru->common.txdata[i][0],fp->samples_per_frame, 1, 1); - sprintf(filename,"tx%ddata_frame%d.dat", i, print_frame); - FILE *output_fd = fopen(filename,"w"); - - if (output_fd) { - fwrite(&ru->common.txdata[i][0], - sizeof(int32_t), - fp->samples_per_frame, - output_fd); - fclose(output_fd); - } else { - LOG_E(PHY,"Cannot write to file %s\n",filename); - } - }//if(slot_tx == 9) - }//for (i=0; inb_tx; i++) - }//if(frame_tx == print_frame) - }//else emulate_rf + if (ru->fh_north_asynch_in == NULL && ru->fh_south_out) + ru->fh_south_out(ru, frame_tx, slot_tx, info->timestamp_tx); + if (ru->fh_north_out) + ru->fh_north_out(ru); } /* @brief wait for the next RX TTI to be free @@ -1141,62 +1047,60 @@ void *ru_thread(void *param) // set default return value sprintf(threadname,"ru_thread %u",ru->idx); LOG_I(PHY,"Starting RU %d (%s,%s) on cpu %d\n",ru->idx,NB_functions[ru->function],NB_timing[ru->if_timing],sched_getcpu()); - memcpy((void *)&ru->config,(void *)&RC.gNB[0]->gNB_config,sizeof(ru->config)); + ru->config = RC.gNB[0]->gNB_config; nr_init_frame_parms(&ru->config, fp); 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, fp->ofdm_symbol_size); + fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp); - if(!emulate_rf) { - // Start IF device if any - if (ru->nr_start_if) { - LOG_I(PHY, "starting transport\n"); - ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params); - AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport protocol\n", ru->idx, ret); - - if (ru->ifdevice.get_internal_parameter != NULL) { - /* it seems the device can "overwrite" (request?) to set the callbacks - * for fh_south_in()/fh_south_out() differently */ - void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in"); - if (t != NULL) - ru->fh_south_in = t; - t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out"); - if (t != NULL) - ru->fh_south_out = t; - } else { - - malloc_IF4p5_buffer(ru); - } - - int cpu = sched_getcpu(); - if (ru->ru_thread_core > -1 && cpu != ru->ru_thread_core) { - /* we start the ru_thread using threadCreate(), which already sets CPU - * affinity; let's force it here again as per feature request #732 */ - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(ru->ru_thread_core, &cpuset); - int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - AssertFatal(ret == 0, "Error in pthread_getaffinity_np(): ret: %d, errno: %d", ret, errno); - LOG_I(PHY, "RU %d: manually set CPU affinity to CPU %d\n", ru->idx, ru->ru_thread_core); - } - - LOG_I(PHY,"Starting IF interface for RU %d, nb_rx %d\n",ru->idx,ru->nb_rx); - AssertFatal(ru->nr_start_if(ru,NULL) == 0, "Could not start the IF device\n"); - - if (ru->has_ctrl_prt > 0) { - if (ru->if_south == LOCAL_RF) ret = connect_rau(ru); - else ret = attach_rru(ru); - - AssertFatal(ret==0,"Cannot connect to remote radio\n"); - } + // Start IF device if any + if (ru->nr_start_if) { + LOG_I(PHY, "starting transport\n"); + ret = openair0_transport_load(&ru->ifdevice, &ru->openair0_cfg, &ru->eth_params); + AssertFatal(ret == 0, "RU %u: openair0_transport_init() ret %d: cannot initialize transport protocol\n", ru->idx, ret); + if (ru->ifdevice.get_internal_parameter != NULL) { + /* it seems the device can "overwrite" (request?) to set the callbacks + * for fh_south_in()/fh_south_out() differently */ + void *t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_in"); + if (t != NULL) + ru->fh_south_in = t; + t = ru->ifdevice.get_internal_parameter("fh_if4p5_south_out"); + if (t != NULL) + ru->fh_south_out = t; + } else { + malloc_IF4p5_buffer(ru); } - else if (ru->if_south == LOCAL_RF) { // configure RF parameters only - ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); - AssertFatal(ret==0,"Cannot connect to local radio\n"); + + int cpu = sched_getcpu(); + if (ru->ru_thread_core > -1 && cpu != ru->ru_thread_core) { + /* we start the ru_thread using threadCreate(), which already sets CPU + * affinity; let's force it here again as per feature request #732 */ + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(ru->ru_thread_core, &cpuset); + int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + AssertFatal(ret == 0, "Error in pthread_getaffinity_np(): ret: %d, errno: %d", ret, errno); + LOG_I(PHY, "RU %d: manually set CPU affinity to CPU %d\n", ru->idx, ru->ru_thread_core); } + + LOG_I(PHY, "Starting IF interface for RU %d, nb_rx %d\n", ru->idx, ru->nb_rx); + AssertFatal(ru->nr_start_if(ru, NULL) == 0, "Could not start the IF device\n"); + + if (ru->has_ctrl_prt > 0) { + if (ru->if_south == LOCAL_RF) + ret = connect_rau(ru); + else + ret = attach_rru(ru); + + AssertFatal(ret == 0, "Cannot connect to remote radio\n"); + } + + } else if (ru->if_south == LOCAL_RF) { // configure RF parameters only + ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); + AssertFatal(ret==0,"Cannot connect to local radio\n"); } if (setup_RU_buffers(ru)!=0) { @@ -1211,31 +1115,31 @@ void *ru_thread(void *param) pthread_mutex_unlock(&RC.ru_mutex); wait_sync("ru_thread"); - if(!emulate_rf) { - // Start RF device if any - if (ru->start_rf) { - if (ru->start_rf(ru) != 0) - LOG_E(HW,"Could not start the RF device\n"); - else LOG_I(PHY,"RU %d rf device ready\n",ru->idx); - } else LOG_I(PHY,"RU %d no rf device\n",ru->idx); + // Start RF device if any + if (ru->start_rf) { + if (ru->start_rf(ru) != 0) + LOG_E(HW, "Could not start the RF device\n"); + else + LOG_I(PHY, "RU %d rf device ready\n", ru->idx); + } else + LOG_I(PHY, "RU %d no rf device\n", ru->idx); - LOG_I(PHY, "RU %d RF started cpu_meas_enabled %d\n", ru->idx, cpu_meas_enabled); - // start trx write thread - if(usrp_tx_thread == 1) { - if (ru->start_write_thread) { - if(ru->start_write_thread(ru) != 0) { - LOG_E(HW,"Could not start tx write thread\n"); - } else { - LOG_I(PHY,"tx write thread ready\n"); - } + LOG_I(PHY, "RU %d RF started cpu_meas_enabled %d\n", ru->idx, cpu_meas_enabled); + // start trx write thread + if (usrp_tx_thread == 1) { + if (ru->start_write_thread) { + if (ru->start_write_thread(ru) != 0) { + LOG_E(HW, "Could not start tx write thread\n"); + } else { + LOG_I(PHY, "tx write thread ready\n"); } } } // This is a forever while loop, it loops over subframes which are scheduled by incoming samples from HW devices struct timespec slot_start; - clock_gettime(CLOCK_MONOTONIC, &slot_start); - + clock_gettime(CLOCK_MONOTONIC, &slot_start); + while (!oai_exit) { if (slot==(fp->slots_per_frame-1)) { slot=0; @@ -1252,8 +1156,8 @@ void *ru_thread(void *param) // synchronization on input FH interface, acquire signals/data and block LOG_D(PHY,"[RU_thread] read data: frame_rx = %d, tti_rx = %d\n", frame, slot); - if (ru->fh_south_in) ru->fh_south_in(ru,&frame,&slot); - else AssertFatal(1==0, "No fronthaul interface at south port"); + AssertFatal(ru->fh_south_in, "No fronthaul interface at south port"); + ru->fh_south_in(ru, &frame, &slot); if (initial_wait == 1 && proc->frame_rx < 300) { if (proc->frame_rx > 0 && ((proc->frame_rx % 100) == 0) && proc->tti_rx == 0) { @@ -1338,14 +1242,14 @@ void *ru_thread(void *param) } // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) { notifiedFIFO_elt_t *resTx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_out, NULL); - processingData_L1tx_t *syncMsgTx = NotifiedFifoData(resTx); - syncMsgTx->gNB = gNB; - syncMsgTx->frame = proc->frame_tx; - syncMsgTx->slot = proc->tti_tx; - syncMsgTx->frame_rx = proc->frame_rx; - syncMsgTx->slot_rx = proc->tti_rx; - syncMsgTx->timestamp_tx = proc->timestamp_tx; resTx->key = proc->tti_tx; + processingData_L1tx_t *syncMsgTx = NotifiedFifoData(resTx); + *syncMsgTx = (processingData_L1tx_t){.gNB = gNB, + .frame = proc->frame_tx, + .slot = proc->tti_tx, + .frame_rx = proc->frame_rx, + .slot_rx = proc->tti_rx, + .timestamp_tx = proc->timestamp_tx}; pushNotifiedFIFO(&gNB->L1_tx_out, resTx); } @@ -1355,15 +1259,16 @@ void *ru_thread(void *param) int start_streaming(RU_t *ru) { LOG_I(PHY,"Starting streaming on third-party RRU\n"); - return(ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice)); + return ru->ifdevice.thirdparty_startstreaming(&ru->ifdevice); } int nr_start_if(struct RU_t_s *ru, struct PHY_VARS_gNB_s *gNB) { if (ru->if_south <= REMOTE_IF5) - for (int i=0;inb_rx;i++) ru->openair0_cfg.rxbase[i] = ru->common.rxdata[i]; + for (int i = 0; i < ru->nb_rx; i++) + ru->openair0_cfg.rxbase[i] = ru->common.rxdata[i]; ru->openair0_cfg.rxsize = ru->nr_frame_parms->samples_per_subframe*10; reset_meas(&ru->ifdevice.tx_fhaul); - return(ru->ifdevice.trx_start_func(&ru->ifdevice)); + return ru->ifdevice.trx_start_func(&ru->ifdevice); } int start_rf(RU_t *ru) { @@ -1371,36 +1276,20 @@ int start_rf(RU_t *ru) { } int stop_rf(RU_t *ru) { + if (ru->rfdevice.trx_get_stats_func) { + ru->rfdevice.trx_get_stats_func(&ru->rfdevice); + } ru->rfdevice.trx_end_func(&ru->rfdevice); return 0; } int start_write_thread(RU_t *ru) { - return(ru->rfdevice.trx_write_init(&ru->rfdevice)); + return ru->rfdevice.trx_write_init(&ru->rfdevice); } -void init_RU_proc(RU_t *ru) { - int i=0; - RU_proc_t *proc; - proc = &ru->proc; - memset((void *)proc,0,sizeof(RU_proc_t)); - proc->ru = ru; - proc->instance_cnt_emulateRF = -1; - proc->first_rx = 1; - proc->first_tx = 1; - proc->frame_offset = 0; - proc->num_slaves = 0; - proc->frame_tx_unwrap = 0; - - for (i=0; i<10; i++) proc->symbol_mask[i]=0; - - pthread_mutex_init( &proc->mutex_emulateRF,NULL); - pthread_cond_init( &proc->cond_emulateRF, NULL); - - if(emulate_rf) - threadCreate( &proc->pthread_emulateRF, emulatedRF_thread, (void *)proc, "emulateRF", -1, OAI_PRIORITY_RT ); - if (cpu_meas_enabled) - threadCreate(&ru->ru_stats_thread, ru_stats_thread, (void *)ru, "ru_stats", -1, OAI_PRIORITY_RT); +void init_RU_proc(RU_t *ru) +{ + ru->proc = (RU_proc_t){.ru = ru, .first_rx = 1, .first_tx = 1}; LOG_I(PHY, "Initialized RU proc %d (%s,%s),\n", ru->idx, NB_functions[ru->function], NB_timing[ru->if_timing]); } @@ -1424,17 +1313,12 @@ void kill_NR_RU_proc(int inst) { * mutex_fep/cond_fep. Thus, we unlocked above for pthread_FH above and do * the same for FEP thread below again (using broadcast() to ensure both * threads get the signal). This one will also destroy the mutex and cond. */ - pthread_mutex_lock(&proc->mutex_fep[0]); + pthread_mutex_lock(proc->mutex_fep); proc->instance_cnt_fep[0] = 0; - pthread_cond_broadcast(&proc->cond_fep[0]); - pthread_mutex_unlock( &proc->mutex_fep[0] ); + pthread_cond_broadcast(proc->cond_fep); + pthread_mutex_unlock(proc->mutex_fep); pthread_join(proc->pthread_FH, NULL); - if (cpu_meas_enabled) { - LOG_D(PHY, "Joining ru_stats_thread\n"); - pthread_join(ru->ru_stats_thread, NULL); - } - // everything should be stopped now, we can safely stop the RF device if (ru->stop_rf == NULL) { LOG_W(PHY, "No stop_rf() for RU %d defined, cannot stop RF!\n", ru->idx); @@ -1451,19 +1335,15 @@ void kill_NR_RU_proc(int inst) { int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) { FH_fmt_options_t fmt = cap->FH_fmt; int i; - int found_band=0; LOG_I(PHY,"RRU %d, num_bands %d, looking for band %d\n",ru->idx,cap->num_bands,ru->nr_frame_parms->nr_band); for (i=0; inum_bands; i++) { LOG_I(PHY,"band %d on RRU %d\n",cap->band_list[i],ru->idx); - - if (ru->nr_frame_parms->nr_band == cap->band_list[i]) { - found_band=1; + if (ru->nr_frame_parms->nr_band == cap->band_list[i]) break; - } } - if (found_band == 0) { + if (i == cap->num_bands) { LOG_I(PHY,"Couldn't find target NR band %d on RRU %d\n",ru->nr_frame_parms->nr_band,ru->idx); return(-1); } @@ -1475,18 +1355,18 @@ int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) { break; case REMOTE_IF5: - if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5) return(0); - + if (fmt == OAI_IF5_only || fmt == OAI_IF5_and_IF4p5) + return (0); break; case REMOTE_IF4p5: - if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5) return(0); - + if (fmt == OAI_IF4p5_only || fmt == OAI_IF5_and_IF4p5) + return (0); break; case REMOTE_MBP_IF5: - if (fmt == MBP_IF5) return(0); - + if (fmt == MBP_IF5) + return (0); break; default: @@ -1498,46 +1378,40 @@ int check_capabilities(RU_t *ru,RRU_capabilities_t *cap) { } const char rru_format_options[4][20] = {"OAI_IF5_only", "OAI_IF4p5_only", "OAI_IF5_and_IF4p5", "MBP_IF5"}; - const char rru_formats[3][20] = {"OAI_IF5", "MBP_IF5", "OAI_IF4p5"}; const char ru_if_formats[4][20] = {"LOCAL_RF", "REMOTE_OAI_IF5", "REMOTE_MBP_IF5", "REMOTE_OAI_IF4p5"}; void configure_ru(void *ruu, void *arg) { RU_t *ru = (RU_t *)ruu; - RRU_config_t *config = (RRU_config_t *)arg; - RRU_capabilities_t *capabilities = (RRU_capabilities_t *)arg; nfapi_nr_config_request_scf_t *cfg = &ru->config; int ret; LOG_I(PHY, "Received capabilities from RRU %d\n", ru->idx); - if (capabilities->FH_fmt < MAX_FH_FMTs) LOG_I(PHY, "RU FH options %s\n",rru_format_options[capabilities->FH_fmt]); + RRU_capabilities_t *capabilities = (RRU_capabilities_t *)arg; + if (capabilities->FH_fmt < MAX_FH_FMTs) + LOG_I(PHY, "RU FH options %s\n", rru_format_options[capabilities->FH_fmt]); ret = check_capabilities(ru,capabilities); AssertFatal(ret == 0, "Cannot configure RRU %d, check_capabilities returned %d\n", ru->idx, ret); // take antenna capabilities of RRU - ru->nb_tx = capabilities->nb_tx[0]; - ru->nb_rx = capabilities->nb_rx[0]; + ru->nb_tx = capabilities->nb_tx[0]; + ru->nb_rx = capabilities->nb_rx[0]; // Pass configuration to RRU LOG_I(PHY, "Using %s fronthaul (%d), band %d \n",ru_if_formats[ru->if_south],ru->if_south,ru->nr_frame_parms->nr_band); + // wait for configuration - config->FH_fmt = ru->if_south; - config->num_bands = 1; - config->band_list[0] = ru->nr_frame_parms->nr_band; - config->tx_freq[0] = ru->nr_frame_parms->dl_CarrierFreq; - config->rx_freq[0] = ru->nr_frame_parms->ul_CarrierFreq; - //config->tdd_config[0] = ru->nr_frame_parms->tdd_config; - //config->tdd_config_S[0] = ru->nr_frame_parms->tdd_config_S; - config->att_tx[0] = ru->att_tx; - config->att_rx[0] = ru->att_rx; - config->N_RB_DL[0] = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value; - config->N_RB_UL[0] = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value; - config->threequarter_fs[0] = ru->nr_frame_parms->threequarter_fs; - /* if (ru->if_south==REMOTE_IF4p5) { - config->prach_FreqOffset[0] = ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset; - config->prach_ConfigIndex[0] = ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex; - LOG_I(PHY,"REMOTE_IF4p5: prach_FrequOffset %d, prach_ConfigIndex %d\n", - config->prach_FreqOffset[0],config->prach_ConfigIndex[0]);*/ + RRU_config_t *config = (RRU_config_t *)arg; + *config = (RRU_config_t){.FH_fmt = ru->if_south, + .num_bands = 1, + .band_list[0] = ru->nr_frame_parms->nr_band, + .tx_freq[0] = ru->nr_frame_parms->dl_CarrierFreq, + .rx_freq[0] = ru->nr_frame_parms->ul_CarrierFreq, + .att_tx[0] = ru->att_tx, + .att_rx[0] = ru->att_rx, + .N_RB_DL[0] = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value, + .N_RB_UL[0] = cfg->carrier_config.dl_grid_size[cfg->ssb_config.scs_common.value].value, + .threequarter_fs[0] = ru->nr_frame_parms->threequarter_fs}; nr_init_frame_parms(&ru->config, ru->nr_frame_parms); nr_phy_init_RU(ru); } @@ -1547,37 +1421,31 @@ void configure_rru(void *ruu, void *arg) RRU_config_t *config = (RRU_config_t *)arg; RU_t *ru = (RU_t *)ruu; nfapi_nr_config_request_scf_t *cfg = &ru->config; - ru->nr_frame_parms->nr_band = config->band_list[0]; - ru->nr_frame_parms->dl_CarrierFreq = config->tx_freq[0]; - ru->nr_frame_parms->ul_CarrierFreq = config->rx_freq[0]; + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - if (ru->nr_frame_parms->dl_CarrierFreq == ru->nr_frame_parms->ul_CarrierFreq) { - cfg->cell_config.frame_duplex_type.value = TDD; - //ru->nr_frame_parms->tdd_config = config->tdd_config[0]; - //ru->nr_frame_parms->tdd_config_S = config->tdd_config_S[0]; + fp->nr_band = config->band_list[0]; + fp->dl_CarrierFreq = config->tx_freq[0]; + fp->ul_CarrierFreq = config->rx_freq[0]; + + if (fp->dl_CarrierFreq == fp->ul_CarrierFreq) { + cfg->cell_config.frame_duplex_type.value = TDD; } else - cfg->cell_config.frame_duplex_type.value = FDD; + cfg->cell_config.frame_duplex_type.value = FDD; - ru->att_tx = config->att_tx[0]; - ru->att_rx = config->att_rx[0]; + ru->att_tx = config->att_tx[0]; + ru->att_rx = config->att_rx[0]; int mu = cfg->ssb_config.scs_common.value; - cfg->carrier_config.dl_grid_size[mu].value = config->N_RB_DL[0]; - cfg->carrier_config.dl_grid_size[mu].value = config->N_RB_UL[0]; - ru->nr_frame_parms->threequarter_fs = config->threequarter_fs[0]; + cfg->carrier_config.dl_grid_size[mu].value = config->N_RB_DL[0]; + cfg->carrier_config.dl_grid_size[mu].value = config->N_RB_UL[0]; + fp->threequarter_fs = config->threequarter_fs[0]; - //ru->nr_frame_parms->pdsch_config_common.referenceSignalPower = ru->max_pdschReferenceSignalPower-config->att_tx[0]; if (ru->function==NGFI_RRU_IF4p5) { - ru->nr_frame_parms->att_rx = ru->att_rx; - ru->nr_frame_parms->att_tx = ru->att_tx; - /* - LOG_I(PHY,"Setting ru->function to NGFI_RRU_IF4p5, prach_FrequOffset %d, prach_ConfigIndex %d, att (%d,%d)\n", - config->prach_FreqOffset[0],config->prach_ConfigIndex[0],ru->att_tx,ru->att_rx); - ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_FreqOffset = config->prach_FreqOffset[0]; - ru->nr_frame_parms->prach_config_common.prach_ConfigInfo.prach_ConfigIndex = config->prach_ConfigIndex[0]; */ + fp->att_rx = ru->att_rx; + fp->att_tx = ru->att_tx; } fill_rf_config(ru,ru->rf_config_file); - nr_init_frame_parms(&ru->config, ru->nr_frame_parms); + nr_init_frame_parms(&ru->config, fp); nr_phy_init_RU(ru); } @@ -1634,17 +1502,6 @@ void set_function_spec_param(RU_t *ru) ru->stop_rf = stop_rf; ru->start_write_thread = start_write_thread; // starting RF TX in different thread } - - /* - fill_rf_config(ru,rf_config_file); - init_frame_parms(&ru->frame_parms,1); - nr_phy_init_RU(ru); - - ret = openair0_device_load(&ru->rfdevice,&ru->openair0_cfg); - if (setup_RU_buffers(ru)!=0) { - exit(-1); - } - */ break; case REMOTE_IF5: // the remote unit is IF5 RRU @@ -1693,12 +1550,6 @@ void set_function_spec_param(RU_t *ru) void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) { - int ru_id; - RU_t *ru; - PHY_VARS_gNB *gNB_RC; - PHY_VARS_gNB *gNB0= (PHY_VARS_gNB *)NULL; - NR_DL_FRAME_PARMS *fp = (NR_DL_FRAME_PARMS *)NULL; - int i; // create status mask RC.ru_mask = 0; pthread_mutex_init(&RC.ru_mutex,NULL); @@ -1708,9 +1559,9 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_nr_L1_inst,RC.nb_RU,get_nprocs()); LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU); - for (ru_id=0; ru_idrf_config_file = rf_config_file; ru->idx = ru_id; ru->ts_offset = 0; @@ -1727,23 +1578,18 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) } } - gNB_RC = RC.gNB[0]; - gNB0 = ru->gNB_list[0]; - fp = ru->nr_frame_parms; + PHY_VARS_gNB *gNB_RC = RC.gNB[0]; + PHY_VARS_gNB *gNB0 = ru->gNB_list[0]; LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south); if (gNB0) { - if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5)) - AssertFatal(gNB0, "gNB0 is null!\n"); - - if (gNB0 && gNB_RC) { + if (gNB_RC) { LOG_D(PHY, "Copying frame parms from gNB in RC to gNB %d in ru %d and frame_parms in ru\n", gNB0->Mod_id, ru->idx); - memcpy((void *)fp, &gNB_RC->frame_parms, sizeof(NR_DL_FRAME_PARMS)); - memcpy((void *)&gNB0->frame_parms, (void *)&gNB_RC->frame_parms, sizeof(NR_DL_FRAME_PARMS)); + *ru->nr_frame_parms = gNB_RC->frame_parms; + gNB0->frame_parms = gNB_RC->frame_parms; // attach all RU to all gNBs in its list/ LOG_D(PHY,"ru->num_gNB:%d gNB0->num_RU:%d\n", ru->num_gNB, gNB0->num_RU); - - for (i=0; inum_gNB; i++) { + for (int i = 0; i < ru->num_gNB; i++) { gNB0 = ru->gNB_list[i]; gNB0->RU_list[gNB0->num_RU++] = ru; } @@ -1757,22 +1603,21 @@ void init_NR_RU(configmodule_interface_t *cfg, char *rf_config_file) LOG_E(PHY, "Number of threads for gNB should be more than 1. Allocated only %d\n", threadCnt); char pool[80]; int s_offset = sprintf(pool,"%d",ru->tpcores[0]); - for (int icpu=1; icputpcores[icpu]); + for (int icpu = 1; icpu < threadCnt; icpu++) { + s_offset += sprintf(pool + s_offset, ",%d", ru->tpcores[icpu]); } LOG_I(PHY, "RU thread-pool core string %s (size %d)\n", pool, threadCnt); - ru->threadPool = (tpool_t*)malloc(sizeof(tpool_t)); + ru->threadPool = malloc(sizeof(tpool_t)); initTpool(pool, ru->threadPool, cpumeas(CPUMEAS_GETSTATE)); // FEP RX result FIFO - ru->respfeprx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + ru->respfeprx = malloc(sizeof(notifiedFIFO_t)); initNotifiedFIFO(ru->respfeprx); // FEP TX result FIFO - ru->respfeptx = (notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); + ru->respfeptx = malloc(sizeof(notifiedFIFO_t)); initNotifiedFIFO(ru->respfeptx); } } // for ru_id - // sleep(1); LOG_D(HW,"[nr-softmodem.c] RU threads created\n"); } @@ -1789,7 +1634,6 @@ void stop_RU(int nb_ru) { } } - /* --------------------------------------------------------*/ /* from here function to use configuration module */ static void NRRCconfig_RU(configmodule_interface_t *cfg) @@ -1798,199 +1642,199 @@ static void NRRCconfig_RU(configmodule_interface_t *cfg) paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST, NULL, 0}; config_getlist(cfg, &RUParamList, RUParams, sizeofArray(RUParams), NULL); - if (RUParamList.numelt > 0) { - RC.ru = (RU_t **)malloc(RC.nb_RU*sizeof(RU_t *)); - RC.ru_mask = (1 << RC.nb_RU) - 1; + if (RUParamList.numelt <= 0) + return; - for (int j = 0; j < RC.nb_RU; j++) { - RC.ru[j] = calloc(1, sizeof(*RC.ru[j])); - RC.ru[j]->idx = j; - RC.ru[j]->nr_frame_parms = calloc(1, sizeof(*RC.ru[j]->nr_frame_parms)); - RC.ru[j]->frame_parms = calloc(1, sizeof(*RC.ru[j]->frame_parms)); - RC.ru[j]->if_timing = synch_to_ext_device; + RC.ru = (RU_t **)malloc(RC.nb_RU * sizeof(RU_t *)); + RC.ru_mask = (1 << RC.nb_RU) - 1; - if (RC.nb_nr_L1_inst > 0) - RC.ru[j]->num_gNB = RUParamList.paramarray[j][RU_ENB_LIST_IDX].numelt; - else - RC.ru[j]->num_gNB = 0; + for (int j = 0; j < RC.nb_RU; j++) { + RU_t *ru = RC.ru[j] = calloc(1, sizeof(*RC.ru[j])); + ru->idx = j; + ru->nr_frame_parms = calloc(1, sizeof(*ru->nr_frame_parms)); + ru->frame_parms = calloc(1, sizeof(*ru->frame_parms)); + ru->if_timing = synch_to_ext_device; + paramdef_t *param = RUParamList.paramarray[j]; + if (RC.nb_nr_L1_inst > 0) + ru->num_gNB = param[RU_ENB_LIST_IDX].numelt; + else + ru->num_gNB = 0; - for (int i = 0; i < RC.ru[j]->num_gNB; i++) - RC.ru[j]->gNB_list[i] = RC.gNB[RUParamList.paramarray[j][RU_ENB_LIST_IDX].iptr[i]]; + for (int i = 0; i < ru->num_gNB; i++) + ru->gNB_list[i] = RC.gNB[param[RU_ENB_LIST_IDX].iptr[i]]; - if (config_isparamset(RUParamList.paramarray[j], RU_SDR_ADDRS)) { - RC.ru[j]->openair0_cfg.sdr_addrs = strdup(*(RUParamList.paramarray[j][RU_SDR_ADDRS].strptr)); - } + if (config_isparamset(param, RU_SDR_ADDRS)) { + ru->openair0_cfg.sdr_addrs = strdup(*param[RU_SDR_ADDRS].strptr); + } - if (config_isparamset(RUParamList.paramarray[j], RU_GPIO_CONTROL)) { - if (strcmp(*RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr, "generic") == 0) { - RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_GENERIC; - LOG_I(PHY, "RU GPIO control set as 'generic'\n"); - } else if (strcmp(*RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr, "interdigital") == 0) { - RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_INTERDIGITAL; - LOG_I(PHY, "RU GPIO control set as 'interdigital'\n"); - } else { - AssertFatal(false, - "bad GPIO controller in configuration file: '%s'\n", - *(RUParamList.paramarray[j][RU_GPIO_CONTROL].strptr)); - } - } else - RC.ru[j]->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_NONE; - - if (config_isparamset(RUParamList.paramarray[j], RU_TX_SUBDEV)) { - RC.ru[j]->openair0_cfg.tx_subdev = strdup(*(RUParamList.paramarray[j][RU_TX_SUBDEV].strptr)); - LOG_I(PHY, "RU USRP tx subdev == %s\n", RC.ru[j]->openair0_cfg.tx_subdev); - } - - if (config_isparamset(RUParamList.paramarray[j], RU_RX_SUBDEV)) { - RC.ru[j]->openair0_cfg.rx_subdev = strdup(*(RUParamList.paramarray[j][RU_RX_SUBDEV].strptr)); - LOG_I(PHY, "RU USRP rx subdev == %s\n", RC.ru[j]->openair0_cfg.rx_subdev); - } - - if (config_isparamset(RUParamList.paramarray[j], RU_SDR_CLK_SRC)) { - if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "internal") == 0) { - RC.ru[j]->openair0_cfg.clock_source = internal; - LOG_I(PHY, "RU clock source set as internal\n"); - } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "external") == 0) { - RC.ru[j]->openair0_cfg.clock_source = external; - LOG_I(PHY, "RU clock source set as external\n"); - } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr), "gpsdo") == 0) { - RC.ru[j]->openair0_cfg.clock_source = gpsdo; - LOG_I(PHY, "RU clock source set as gpsdo\n"); - } else { - LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr)); - } + if (config_isparamset(param, RU_GPIO_CONTROL)) { + char *str = *param[RU_GPIO_CONTROL].strptr; + if (strcmp(str, "generic") == 0) { + ru->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_GENERIC; + LOG_I(PHY, "RU GPIO control set as 'generic'\n"); + } else if (strcmp(str, "interdigital") == 0) { + ru->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_INTERDIGITAL; + LOG_I(PHY, "RU GPIO control set as 'interdigital'\n"); } else { - LOG_D(PHY, "Setting clock source to internal\n"); - RC.ru[j]->openair0_cfg.clock_source = internal; + AssertFatal(false, "bad GPIO controller in configuration file: '%s'\n", str); } + } else + ru->openair0_cfg.gpio_controller = RU_GPIO_CONTROL_NONE; - if (config_isparamset(RUParamList.paramarray[j], RU_SDR_TME_SRC)) { - if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "internal") == 0) { - RC.ru[j]->openair0_cfg.time_source = internal; - LOG_I(PHY, "RU time source set as internal\n"); - } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "external") == 0) { - RC.ru[j]->openair0_cfg.time_source = external; - LOG_I(PHY, "RU time source set as external\n"); - } else if (strcmp(*(RUParamList.paramarray[j][RU_SDR_TME_SRC].strptr), "gpsdo") == 0) { - RC.ru[j]->openair0_cfg.time_source = gpsdo; - LOG_I(PHY, "RU time source set as gpsdo\n"); - } else { - LOG_E(PHY, "Erroneous RU time source in the provided configuration file: '%s'\n", *(RUParamList.paramarray[j][RU_SDR_CLK_SRC].strptr)); - } + if (config_isparamset(param, RU_TX_SUBDEV)) { + ru->openair0_cfg.tx_subdev = strdup(*param[RU_TX_SUBDEV].strptr); + LOG_I(PHY, "RU USRP tx subdev == %s\n", ru->openair0_cfg.tx_subdev); + } + + if (config_isparamset(param, RU_RX_SUBDEV)) { + ru->openair0_cfg.rx_subdev = strdup(*param[RU_RX_SUBDEV].strptr); + LOG_I(PHY, "RU USRP rx subdev == %s\n", ru->openair0_cfg.rx_subdev); + } + + if (config_isparamset(param, RU_SDR_CLK_SRC)) { + char *str = *param[RU_SDR_CLK_SRC].strptr; + if (strcmp(str, "internal") == 0) { + ru->openair0_cfg.clock_source = internal; + LOG_I(PHY, "RU clock source set as internal\n"); + } else if (strcmp(str, "external") == 0) { + ru->openair0_cfg.clock_source = external; + LOG_I(PHY, "RU clock source set as external\n"); + } else if (strcmp(str, "gpsdo") == 0) { + ru->openair0_cfg.clock_source = gpsdo; + LOG_I(PHY, "RU clock source set as gpsdo\n"); } else { - LOG_D(PHY, "Setting time source to internal\n"); - RC.ru[j]->openair0_cfg.time_source = internal; + LOG_E(PHY, "Erroneous RU clock source in the provided configuration file: '%s'\n", str); + } + } else { + LOG_D(PHY, "Setting clock source to internal\n"); + ru->openair0_cfg.clock_source = internal; + } + + if (config_isparamset(param, RU_SDR_TME_SRC)) { + char *str = *param[RU_SDR_TME_SRC].strptr; + if (strcmp(str, "internal") == 0) { + ru->openair0_cfg.time_source = internal; + LOG_I(PHY, "RU time source set as internal\n"); + } else if (strcmp(str, "external") == 0) { + ru->openair0_cfg.time_source = external; + LOG_I(PHY, "RU time source set as external\n"); + } else if (strcmp(str, "gpsdo") == 0) { + ru->openair0_cfg.time_source = gpsdo; + LOG_I(PHY, "RU time source set as gpsdo\n"); + } else { + LOG_E(PHY, "Erroneous RU time source in the provided configuration file: '%s'\n", str); + } + } else { + LOG_D(PHY, "Setting time source to internal\n"); + ru->openair0_cfg.time_source = internal; + } + + ru->openair0_cfg.tune_offset = get_softmodem_params()->tune_offset; + + if (strcmp(*param[RU_LOCAL_RF_IDX].strptr, "yes") == 0) { + if (!config_isparamset(param, RU_LOCAL_IF_NAME_IDX)) { + ru->if_south = LOCAL_RF; + ru->function = gNodeB_3GPP; + LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j); + } else { + ru->eth_params.local_if_name = strdup(*param[RU_LOCAL_IF_NAME_IDX].strptr); + ru->eth_params.my_addr = strdup(*param[RU_LOCAL_ADDRESS_IDX].strptr); + ru->eth_params.remote_addr = strdup(*param[RU_REMOTE_ADDRESS_IDX].strptr); + ru->eth_params.my_portc = *param[RU_LOCAL_PORTC_IDX].uptr; + ru->eth_params.remote_portc = *param[RU_REMOTE_PORTC_IDX].uptr; + ru->eth_params.my_portd = *param[RU_LOCAL_PORTD_IDX].uptr; + ru->eth_params.remote_portd = *param[RU_REMOTE_PORTD_IDX].uptr; + char *str = *param[RU_TRANSPORT_PREFERENCE_IDX].strptr; + if (strcmp(str, "udp") == 0) { + ru->if_south = LOCAL_RF; + ru->function = NGFI_RRU_IF5; + ru->eth_params.transp_preference = ETH_UDP_MODE; + LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (udp)\n", j); + } else if (strcmp(str, "raw") == 0) { + ru->if_south = LOCAL_RF; + ru->function = NGFI_RRU_IF5; + ru->eth_params.transp_preference = ETH_RAW_MODE; + LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (raw)\n", j); + } else if (strcmp(str, "udp_if4p5") == 0) { + ru->if_south = LOCAL_RF; + ru->function = NGFI_RRU_IF4p5; + ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; + LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n", j); + } else if (strcmp(str, "raw_if4p5") == 0) { + ru->if_south = LOCAL_RF; + ru->function = NGFI_RRU_IF4p5; + ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; + LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n", j); + } } - RC.ru[j]->openair0_cfg.tune_offset = get_softmodem_params()->tune_offset; + ru->max_pdschReferenceSignalPower = *param[RU_MAX_RS_EPRE_IDX].uptr; + ru->max_rxgain = *param[RU_MAX_RXGAIN_IDX].uptr; + ru->sf_extension = *param[RU_SF_EXTENSION_IDX].uptr; + } // strcmp(local_rf, "yes") == 0 + else { + char *str = *param[RU_TRANSPORT_PREFERENCE_IDX].strptr; + LOG_D(PHY, "RU %d: Transport %s\n", j, str); + ru->eth_params.local_if_name = strdup(*param[RU_LOCAL_IF_NAME_IDX].strptr); + ru->eth_params.my_addr = strdup(*param[RU_LOCAL_ADDRESS_IDX].strptr); + ru->eth_params.remote_addr = strdup(*param[RU_REMOTE_ADDRESS_IDX].strptr); + ru->eth_params.my_portc = *param[RU_LOCAL_PORTC_IDX].uptr; + ru->eth_params.remote_portc = *param[RU_REMOTE_PORTC_IDX].uptr; + ru->eth_params.my_portd = *param[RU_LOCAL_PORTD_IDX].uptr; + ru->eth_params.remote_portd = *param[RU_REMOTE_PORTD_IDX].uptr; - if (strcmp(*(RUParamList.paramarray[j][RU_LOCAL_RF_IDX].strptr), "yes") == 0) { - if (!(config_isparamset(RUParamList.paramarray[j],RU_LOCAL_IF_NAME_IDX))) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = gNodeB_3GPP; - LOG_D(PHY, "Setting function for RU %d to gNodeB_3GPP\n", j); - } else { - RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); - RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); - RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); - RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); - RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); - - if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = NGFI_RRU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; - LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (udp)\n", j); - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = NGFI_RRU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; - LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF5 (raw)\n", j); - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = NGFI_RRU_IF4p5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; - LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (udp)\n", j); - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { - RC.ru[j]->if_south = LOCAL_RF; - RC.ru[j]->function = NGFI_RRU_IF4p5; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; - LOG_D(PHY, "Setting function for RU %d to NGFI_RRU_IF4p5 (raw)\n", j); - } - } - - RC.ru[j]->max_pdschReferenceSignalPower = *(RUParamList.paramarray[j][RU_MAX_RS_EPRE_IDX].uptr);; - RC.ru[j]->max_rxgain = *(RUParamList.paramarray[j][RU_MAX_RXGAIN_IDX].uptr); - RC.ru[j]->sf_extension = *(RUParamList.paramarray[j][RU_SF_EXTENSION_IDX].uptr); - } //strcmp(local_rf, "yes") == 0 - else { - LOG_D(PHY, "RU %d: Transport %s\n", j, *(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr)); - RC.ru[j]->eth_params.local_if_name = strdup(*(RUParamList.paramarray[j][RU_LOCAL_IF_NAME_IDX].strptr)); - RC.ru[j]->eth_params.my_addr = strdup(*(RUParamList.paramarray[j][RU_LOCAL_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.remote_addr = strdup(*(RUParamList.paramarray[j][RU_REMOTE_ADDRESS_IDX].strptr)); - RC.ru[j]->eth_params.my_portc = *(RUParamList.paramarray[j][RU_LOCAL_PORTC_IDX].uptr); - RC.ru[j]->eth_params.remote_portc = *(RUParamList.paramarray[j][RU_REMOTE_PORTC_IDX].uptr); - RC.ru[j]->eth_params.my_portd = *(RUParamList.paramarray[j][RU_LOCAL_PORTD_IDX].uptr); - RC.ru[j]->eth_params.remote_portd = *(RUParamList.paramarray[j][RU_REMOTE_PORTD_IDX].uptr); - - if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp") == 0) { - RC.ru[j]->if_south = REMOTE_IF5; - RC.ru[j]->function = NGFI_RAU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_ecpri_if5") == 0) { - RC.ru[j]->if_south = REMOTE_IF5; - RC.ru[j]->function = NGFI_RAU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw") == 0) { - RC.ru[j]->if_south = REMOTE_IF5; - RC.ru[j]->function = NGFI_RAU_IF5; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "udp_if4p5") == 0) { - RC.ru[j]->if_south = REMOTE_IF4p5; - RC.ru[j]->function = NGFI_RAU_IF4p5; - RC.ru[j]->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; - } else if (strcmp(*(RUParamList.paramarray[j][RU_TRANSPORT_PREFERENCE_IDX].strptr), "raw_if4p5") == 0) { - RC.ru[j]->if_south = REMOTE_IF4p5; - RC.ru[j]->function = NGFI_RAU_IF4p5; - RC.ru[j]->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; - } - } /* strcmp(local_rf, "yes") != 0 */ - - RC.ru[j]->nb_tx = *(RUParamList.paramarray[j][RU_NB_TX_IDX].uptr); - RC.ru[j]->nb_rx = *(RUParamList.paramarray[j][RU_NB_RX_IDX].uptr); - RC.ru[j]->att_tx = *(RUParamList.paramarray[j][RU_ATT_TX_IDX].uptr); - RC.ru[j]->att_rx = *(RUParamList.paramarray[j][RU_ATT_RX_IDX].uptr); - RC.ru[j]->if_frequency = *(RUParamList.paramarray[j][RU_IF_FREQUENCY].u64ptr); - RC.ru[j]->if_freq_offset = *(RUParamList.paramarray[j][RU_IF_FREQ_OFFSET].iptr); - RC.ru[j]->sl_ahead = *(RUParamList.paramarray[j][RU_SL_AHEAD].iptr); - RC.ru[j]->num_bands = RUParamList.paramarray[j][RU_BAND_LIST_IDX].numelt; - for (int i = 0; i < RC.ru[j]->num_bands; i++) - RC.ru[j]->band[i] = RUParamList.paramarray[j][RU_BAND_LIST_IDX].iptr[i]; - RC.ru[j]->openair0_cfg.nr_flag = *(RUParamList.paramarray[j][RU_NR_FLAG].iptr); - RC.ru[j]->openair0_cfg.nr_band = RC.ru[j]->band[0]; - RC.ru[j]->openair0_cfg.nr_scs_for_raster = *(RUParamList.paramarray[j][RU_NR_SCS_FOR_RASTER].iptr); - LOG_D(PHY, - "[RU %d] Setting nr_flag %d, nr_band %d, nr_scs_for_raster %d\n", - j, - RC.ru[j]->openair0_cfg.nr_flag, - RC.ru[j]->openair0_cfg.nr_band, - RC.ru[j]->openair0_cfg.nr_scs_for_raster); - RC.ru[j]->openair0_cfg.rxfh_cores[0] = *(RUParamList.paramarray[j][RU_RXFH_CORE_ID].iptr); - RC.ru[j]->openair0_cfg.txfh_cores[0] = *(RUParamList.paramarray[j][RU_TXFH_CORE_ID].iptr); - RC.ru[j]->num_tpcores = *(RUParamList.paramarray[j][RU_NUM_TP_CORES].iptr); - RC.ru[j]->half_slot_parallelization = *(RUParamList.paramarray[j][RU_HALF_SLOT_PARALLELIZATION].iptr); - RC.ru[j]->ru_thread_core = *(RUParamList.paramarray[j][RU_RU_THREAD_CORE].iptr); - LOG_D(PHY, "[RU %d] Setting half-slot parallelization to %d\n", j, RC.ru[j]->half_slot_parallelization); - AssertFatal(RC.ru[j]->num_tpcores <= RUParamList.paramarray[j][RU_TP_CORES].numelt, "Number of TP cores should be <=16\n"); - for (int i = 0; i < RC.ru[j]->num_tpcores; i++) - RC.ru[j]->tpcores[i] = RUParamList.paramarray[j][RU_TP_CORES].iptr[i]; - }// j=0..num_rus - } else { - RC.nb_RU = 0; - } // setting != NULL + if (strcmp(str, "udp") == 0) { + ru->if_south = REMOTE_IF5; + ru->function = NGFI_RAU_IF5; + ru->eth_params.transp_preference = ETH_UDP_MODE; + } else if (strcmp(str, "udp_ecpri_if5") == 0) { + ru->if_south = REMOTE_IF5; + ru->function = NGFI_RAU_IF5; + ru->eth_params.transp_preference = ETH_UDP_IF5_ECPRI_MODE; + } else if (strcmp(str, "raw") == 0) { + ru->if_south = REMOTE_IF5; + ru->function = NGFI_RAU_IF5; + ru->eth_params.transp_preference = ETH_RAW_MODE; + } else if (strcmp(str, "udp_if4p5") == 0) { + ru->if_south = REMOTE_IF4p5; + ru->function = NGFI_RAU_IF4p5; + ru->eth_params.transp_preference = ETH_UDP_IF4p5_MODE; + } else if (strcmp(str, "raw_if4p5") == 0) { + ru->if_south = REMOTE_IF4p5; + ru->function = NGFI_RAU_IF4p5; + ru->eth_params.transp_preference = ETH_RAW_IF4p5_MODE; + } + } /* strcmp(local_rf, "yes") != 0 */ + ru->nb_tx = *param[RU_NB_TX_IDX].uptr; + ru->nb_rx = *param[RU_NB_RX_IDX].uptr; + ru->att_tx = *param[RU_ATT_TX_IDX].uptr; + ru->att_rx = *param[RU_ATT_RX_IDX].uptr; + ru->if_frequency = *param[RU_IF_FREQUENCY].u64ptr; + ru->if_freq_offset = *param[RU_IF_FREQ_OFFSET].iptr; + ru->sl_ahead = *param[RU_SL_AHEAD].iptr; + ru->num_bands = param[RU_BAND_LIST_IDX].numelt; + for (int i = 0; i < ru->num_bands; i++) + ru->band[i] = param[RU_BAND_LIST_IDX].iptr[i]; + ru->openair0_cfg.nr_flag = *param[RU_NR_FLAG].iptr; + ru->openair0_cfg.nr_band = ru->band[0]; + ru->openair0_cfg.nr_scs_for_raster = *param[RU_NR_SCS_FOR_RASTER].iptr; + LOG_D(PHY, + "[RU %d] Setting nr_flag %d, nr_band %d, nr_scs_for_raster %d\n", + j, + ru->openair0_cfg.nr_flag, + ru->openair0_cfg.nr_band, + ru->openair0_cfg.nr_scs_for_raster); + ru->openair0_cfg.rxfh_cores[0] = *param[RU_RXFH_CORE_ID].iptr; + ru->openair0_cfg.txfh_cores[0] = *param[RU_TXFH_CORE_ID].iptr; + ru->num_tpcores = *param[RU_NUM_TP_CORES].iptr; + ru->half_slot_parallelization = *param[RU_HALF_SLOT_PARALLELIZATION].iptr; + ru->ru_thread_core = *param[RU_RU_THREAD_CORE].iptr; + LOG_D(PHY, "[RU %d] Setting half-slot parallelization to %d\n", j, ru->half_slot_parallelization); + AssertFatal(ru->num_tpcores <= param[RU_TP_CORES].numelt, "Number of TP cores should be <=16\n"); + for (int i = 0; i < ru->num_tpcores; i++) + ru->tpcores[i] = param[RU_TP_CORES].iptr[i]; + } // j=0..num_rus return; } diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h index 3ab6d1e73d..8541135bb6 100644 --- a/executables/nr-softmodem-common.h +++ b/executables/nr-softmodem-common.h @@ -126,14 +126,12 @@ extern int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; extern int oai_exit; -extern openair0_config_t openair0_cfg[MAX_CARDS]; extern pthread_cond_t sync_cond; extern pthread_mutex_t sync_mutex; extern int sync_var; extern int transmission_mode; extern double cpuf; -extern int emulate_rf; extern int numerology; extern int usrp_tx_thread; void wait_gNBs(void); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 332e06e7af..0bd583662b 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -24,7 +24,6 @@ #include "common/config/config_userapi.h" #include "common/utils/load_module_shlib.h" -#include "RRC/LTE/rrc_vars.h" #ifdef SMBV #include "PHY/TOOLS/smbv.h" unsigned short config_frames[4] = {2,9,11,13}; @@ -119,7 +118,6 @@ double rx_gain_off = 0.0; static int tx_max_power[MAX_NUM_CCs]; /* = {0,0}*/; int chain_offset = 0; -int emulate_rf = 0; int numerology = 0; double cpuf; @@ -130,52 +128,6 @@ void pdcp_run(const protocol_ctxt_t *const ctxt_pP) abort(); } -/*---------------------BMC: timespec helpers -----------------------------*/ - -struct timespec min_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; -struct timespec max_diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - -struct timespec clock_difftime(struct timespec start, struct timespec end) { - struct timespec temp; - - if ((end.tv_nsec-start.tv_nsec)<0) { - temp.tv_sec = end.tv_sec-start.tv_sec-1; - temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; - } else { - temp.tv_sec = end.tv_sec-start.tv_sec; - temp.tv_nsec = end.tv_nsec-start.tv_nsec; - } - - return temp; -} - -void print_difftimes(void) -{ - LOG_I(HW, "difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec); -} - -void update_difftimes(struct timespec start, struct timespec end) { - struct timespec diff_time = { .tv_sec = 0, .tv_nsec = 0 }; - int changed = 0; - diff_time = clock_difftime(start, end); - - if ((min_diff_time.tv_nsec == 0) || (diff_time.tv_nsec < min_diff_time.tv_nsec)) { - min_diff_time.tv_nsec = diff_time.tv_nsec; - changed = 1; - } - - if ((max_diff_time.tv_nsec == 0) || (diff_time.tv_nsec > max_diff_time.tv_nsec)) { - max_diff_time.tv_nsec = diff_time.tv_nsec; - changed = 1; - } - -#if 1 - - if (changed) print_difftimes(); - -#endif -} - /*------------------------------------------------------------------------*/ unsigned int build_rflocal(int txi, int txq, int rxi, int rxq) { @@ -207,11 +159,19 @@ void exit_function(const char *file, const char *function, const int line, const for (ru_id=0; ru_idrfdevice.trx_end_func) { + if (RC.ru[ru_id]->rfdevice.trx_get_stats_func) { + RC.ru[ru_id]->rfdevice.trx_get_stats_func(&RC.ru[ru_id]->rfdevice); + RC.ru[ru_id]->rfdevice.trx_get_stats_func = NULL; + } RC.ru[ru_id]->rfdevice.trx_end_func(&RC.ru[ru_id]->rfdevice); RC.ru[ru_id]->rfdevice.trx_end_func = NULL; } if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) { + if (RC.ru[ru_id]->ifdevice.trx_get_stats_func) { + RC.ru[ru_id]->ifdevice.trx_get_stats_func(&RC.ru[ru_id]->ifdevice); + RC.ru[ru_id]->ifdevice.trx_get_stats_func = NULL; + } RC.ru[ru_id]->ifdevice.trx_end_func(&RC.ru[ru_id]->ifdevice); RC.ru[ru_id]->ifdevice.trx_end_func = NULL; } @@ -253,9 +213,9 @@ static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cf RC.nrrrc = calloc(1, sizeof(*RC.nrrrc)); RC.nrrrc[0] = RCconfig_NRRRC(); - if (!get_softmodem_params()->nsa && !(node_type == ngran_gNB_DU)) { + if (node_type != ngran_gNB_DU) { // we start pdcp in both cuup (for drb) and cucp (for srb) - init_pdcp(); + nr_pdcp_layer_init(); } if (get_softmodem_params()->nsa) { //&& !NODE_IS_DU(node_type) @@ -423,11 +383,17 @@ int stop_L1(module_id_t gnb_id) stop_RU(RC.nb_RU); /* stop trx devices, multiple carrier currently not supported by RU */ + if (ru->rfdevice.trx_get_stats_func) { + ru->rfdevice.trx_get_stats_func(&ru->rfdevice); + } if (ru->rfdevice.trx_stop_func) { ru->rfdevice.trx_stop_func(&ru->rfdevice); LOG_I(GNB_APP, "turned off RU rfdevice\n"); } + if (ru->ifdevice.trx_get_stats_func) { + ru->ifdevice.trx_get_stats_func(&ru->rfdevice); + } if (ru->ifdevice.trx_stop_func) { ru->ifdevice.trx_stop_func(&ru->ifdevice); LOG_I(GNB_APP, "turned off RU ifdevice\n"); @@ -499,12 +465,6 @@ static void wait_nfapi_init(char *thread_name) pthread_mutex_unlock(&nfapi_sync_mutex); } -void init_pdcp(void) { - if (!NODE_IS_DU(get_node_type())) { - nr_pdcp_layer_init(); - } -} - #ifdef E2_AGENT static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args) { @@ -753,6 +713,11 @@ int main( int argc, char **argv ) { // wait for end of program printf("TYPE TO TERMINATE\n"); + // Sleep a while before checking all parameters have been used + // Some are used directly in external threads, asynchronously + sleep(2); + config_check_unknown_cmdlineopt(uniqCfg, CONFIG_CHECKALLSECTIONS); + itti_wait_tasks_end(NULL); printf("Returned from ITTI signal handler\n"); diff --git a/executables/nr-ue.c b/executables/nr-ue.c index d0a8f27a0f..f789484465 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -31,13 +31,10 @@ #include "SCHED_NR_UE/defs.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" #include "executables/softmodem-common.h" -#include "PHY/NR_REFSIG/refsig_defs_ue.h" #include "radio/COMMON/common_lib.h" #include "LAYER2/nr_pdcp/nr_pdcp_oai_api.h" #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" -#include "RRC/NR/MESSAGES/asn1_msg.h" #include "openair1/PHY/TOOLS/phy_scope_interface.h" -#include "PHY/MODULATION/nr_modulation.h" #include "instrumentation.h" #include "common/utils/threadPool/notified_fifo.h" #include "position_interface.h" @@ -102,8 +99,6 @@ * */ -static void *NRUE_phy_stub_standalone_pnf_task(void *arg); - static void start_process_slot_tx(void* arg) { notifiedFIFO_elt_t *newTx = arg; nr_rxtx_thread_data_t *curMsgTx = NotifiedFifoData(newTx); @@ -194,189 +189,6 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id) ue->ta_slot = -1; } -void init_nrUE_standalone_thread(int ue_idx) -{ - int standalone_tx_port = 3611 + ue_idx * 2; - int standalone_rx_port = 3612 + ue_idx * 2; - nrue_init_standalone_socket(standalone_tx_port, standalone_rx_port); - - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - pthread_mutex_init(&mac->mutex_dl_info, NULL); - - pthread_t thread; - if (pthread_create(&thread, NULL, nrue_standalone_pnf_task, NULL) != 0) { - LOG_E(NR_MAC, "pthread_create failed for calling nrue_standalone_pnf_task"); - } - pthread_setname_np(thread, "oai:nrue-stand"); - pthread_t phy_thread; - if (pthread_create(&phy_thread, NULL, NRUE_phy_stub_standalone_pnf_task, NULL) != 0) { - LOG_E(NR_MAC, "pthread_create failed for calling NRUE_phy_stub_standalone_pnf_task"); - } - pthread_setname_np(phy_thread, "oai:nrue-stand-phy"); -} - -static void process_queued_nr_nfapi_msgs(NR_UE_MAC_INST_t *mac, int sfn, int slot) -{ - struct sfn_slot_s sfn_slot = {.sfn = sfn, .slot = slot}; - nfapi_nr_rach_indication_t *rach_ind = unqueue_matching(&nr_rach_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot); - nfapi_nr_dl_tti_request_t *dl_tti_request = get_queue(&nr_dl_tti_req_queue); - nfapi_nr_ul_dci_request_t *ul_dci_request = get_queue(&nr_ul_dci_req_queue); - - for (int i = 0; i < NR_MAX_HARQ_PROCESSES; i++) { - LOG_D(NR_MAC, - "Try to get a ul_tti_req by matching CRC active sfn/slot %d.%d from queue with %lu items\n", - sfn, - slot, - nr_ul_tti_req_queue.num_items); - struct sfn_slot_s sfn_sf = {.sfn = mac->nr_ue_emul_l1.harq[i].active_ul_harq_sfn, .slot = mac->nr_ue_emul_l1.harq[i].active_ul_harq_slot }; - nfapi_nr_ul_tti_request_t *ul_tti_request_crc = unqueue_matching(&nr_ul_tti_req_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_sf); - if (ul_tti_request_crc && ul_tti_request_crc->n_pdus > 0) { - check_and_process_dci(NULL, NULL, NULL, ul_tti_request_crc); - free_and_zero(ul_tti_request_crc); - } - } - - if (rach_ind && rach_ind->number_of_pdus > 0) { - NR_UL_IND_t UL_INFO = { - .rach_ind = *rach_ind, - }; - send_nsa_standalone_msg(&UL_INFO, rach_ind->header.message_id); - free_and_zero(rach_ind->pdu_list); - free_and_zero(rach_ind); - } - if (dl_tti_request) { - struct sfn_slot_s sfn_slot = {.sfn = dl_tti_request->SFN, .slot = dl_tti_request->Slot}; - nfapi_nr_tx_data_request_t *tx_data_request = unqueue_matching(&nr_tx_req_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot); - if (!tx_data_request) { - LOG_E(NR_MAC, "[%d.%d] No corresponding tx_data_request for given dl_tti_request sfn/slot\n", - dl_tti_request->SFN, dl_tti_request->Slot); - if (get_softmodem_params()->nsa) - save_nr_measurement_info(dl_tti_request); - free_and_zero(dl_tti_request); - } - else if (dl_tti_request->dl_tti_request_body.nPDUs > 0 && tx_data_request->Number_of_PDUs > 0) { - if (get_softmodem_params()->nsa) - save_nr_measurement_info(dl_tti_request); - check_and_process_dci(dl_tti_request, tx_data_request, NULL, NULL); - free_and_zero(dl_tti_request); - free_and_zero(tx_data_request); - } - else { - AssertFatal(false, "We dont have PDUs in either dl_tti %d or tx_req %d\n", - dl_tti_request->dl_tti_request_body.nPDUs, tx_data_request->Number_of_PDUs); - } - } - if (ul_dci_request && ul_dci_request->numPdus > 0) { - check_and_process_dci(NULL, NULL, ul_dci_request, NULL); - free_and_zero(ul_dci_request); - } -} - -static void *NRUE_phy_stub_standalone_pnf_task(void *arg) -{ - LOG_I(MAC, "Clearing Queues\n"); - reset_queue(&nr_rach_ind_queue); - reset_queue(&nr_rx_ind_queue); - reset_queue(&nr_crc_ind_queue); - reset_queue(&nr_uci_ind_queue); - reset_queue(&nr_dl_tti_req_queue); - reset_queue(&nr_tx_req_queue); - reset_queue(&nr_ul_dci_req_queue); - reset_queue(&nr_ul_tti_req_queue); - - int last_sfn_slot = -1; - uint16_t sfn_slot = 0; - - module_id_t mod_id = 0; - NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id); - for (int i = 0; i < NR_MAX_HARQ_PROCESSES; i++) { - mac->nr_ue_emul_l1.harq[i].active = false; - mac->nr_ue_emul_l1.harq[i].active_ul_harq_sfn = -1; - mac->nr_ue_emul_l1.harq[i].active_ul_harq_slot = -1; - } - - while (!oai_exit) { - if (sem_wait(&sfn_slot_semaphore) != 0) { - LOG_E(NR_MAC, "sem_wait() error\n"); - abort(); - } - uint16_t *slot_ind = get_queue(&nr_sfn_slot_queue); - nr_phy_channel_params_t *ch_info = get_queue(&nr_chan_param_queue); - if (!slot_ind && !ch_info) { - LOG_D(MAC, "get nr_sfn_slot_queue and nr_chan_param_queue == NULL!\n"); - continue; - } - if (slot_ind) { - sfn_slot = *slot_ind; - free_and_zero(slot_ind); - } - else if (ch_info) { - sfn_slot = ch_info->sfn_slot; - free_and_zero(ch_info); - } - - int mu = 1; // NR-UE emul-L1 is hardcoded to 30kHZ, see check_and_process_dci() - frame_t frame = NFAPI_SFNSLOTDEC2SFN(mu, sfn_slot); - int slot = NFAPI_SFNSLOTDEC2SLOT(mu, sfn_slot); - if (sfn_slot == last_sfn_slot) { - LOG_D(NR_MAC, "repeated sfn_sf = %d.%d\n", - frame, slot); - continue; - } - last_sfn_slot = sfn_slot; - - LOG_D(NR_MAC, "The received sfn/slot [%d %d] from proxy\n", - frame, slot); - - if (IS_SA_MODE(get_softmodem_params()) && mac->mib == NULL) { - LOG_D(NR_MAC, "We haven't gotten MIB. Lets see if we received it\n"); - nr_ue_dl_indication(&mac->dl_info); - process_queued_nr_nfapi_msgs(mac, frame, slot); - } - - int CC_id = 0; - uint8_t gNB_id = 0; - int slots_per_frame = 20; //30 kHZ subcarrier spacing - int slot_ahead = 2; // TODO: Make this dynamic - nr_uplink_indication_t ul_info = {.cc_id = CC_id, - .gNB_index = gNB_id, - .module_id = mod_id, - .slot = (slot + slot_ahead) % slots_per_frame, - .frame = (slot + slot_ahead >= slots_per_frame) ? (frame + 1) % 1024 : frame}; - - if (pthread_mutex_lock(&mac->mutex_dl_info)) abort(); - - if (ch_info) { - mac->nr_ue_emul_l1.pmi = ch_info->csi[0].pmi; - mac->nr_ue_emul_l1.ri = ch_info->csi[0].ri; - mac->nr_ue_emul_l1.cqi = ch_info->csi[0].cqi; - free_and_zero(ch_info); - } - - if (is_dl_slot(slot, &mac->frame_structure)) { - memset(&mac->dl_info, 0, sizeof(mac->dl_info)); - mac->dl_info.cc_id = CC_id; - mac->dl_info.gNB_index = gNB_id; - mac->dl_info.module_id = mod_id; - mac->dl_info.frame = frame; - mac->dl_info.slot = slot; - mac->dl_info.dci_ind = NULL; - mac->dl_info.rx_ind = NULL; - nr_ue_dl_indication(&mac->dl_info); - } - - if (pthread_mutex_unlock(&mac->mutex_dl_info)) abort(); - - if (is_ul_slot(ul_info.slot, &mac->frame_structure)) { - LOG_D(NR_MAC, "Slot %d. calling nr_ue_ul_ind()\n", ul_info.slot); - nr_ue_ul_scheduler(mac, &ul_info); - } - process_queued_nr_nfapi_msgs(mac, frame, slot); - } - return NULL; -} - - /*! * It performs band scanning and synchonization. * \param arg is a pointer to a \ref PHY_VARS_NR_UE structure. @@ -414,7 +226,7 @@ static void UE_synch(void *arg) { syncData_t *syncD = (syncData_t *)arg; PHY_VARS_NR_UE *UE = syncD->UE; UE->is_synchronized = 0; - openair0_config_t *cfg0 = &openair0_cfg[UE->rf_map.card]; + openair0_config_t *cfg0 = &UE->openair0_cfg[UE->rf_map.card]; if (UE->target_Nid_cell != -1) { LOG_W(NR_PHY, "Starting re-sync detection for target Nid_cell %i\n", UE->target_Nid_cell); @@ -523,7 +335,7 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action, c16_t **tx radio_tx_burst_flag_t flags = TX_BURST_INVALID; if (UE->received_config_request) { - if (openair0_cfg[0].duplex_mode == duplex_mode_FDD || get_softmodem_params()->continuous_tx) { + if (UE->openair0_cfg[0].duplex_mode == duplex_mode_FDD || get_softmodem_params()->continuous_tx) { flags = TX_BURST_MIDDLE; // In case of Sidelink, USRP write needed only in case transmission // needs to be done in this slot and not based on tdd ULDL configuration. @@ -696,8 +508,8 @@ static int handle_sync_req_from_mac(PHY_VARS_NR_UE *UE) if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) { fp->dl_CarrierFreq = dl_CarrierFreq; fp->ul_CarrierFreq = ul_CarrierFreq; - nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_CarrierFreq, dl_CarrierFreq, 0); - UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &openair0_cfg[0]); + nr_rf_card_config_freq(&UE->openair0_cfg[UE->rf_map.card], ul_CarrierFreq, dl_CarrierFreq, 0); + UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &UE->openair0_cfg[UE->rf_map.card]); init_symbol_rotation(fp); } @@ -731,12 +543,14 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, fp = &UE->SL_UE_PHY_PARAMS.sl_frame_params; // process what RRC thread sent to MAC - MessageDef *msg = NULL; do { - itti_poll_msg(TASK_MAC_UE, &msg); - if (msg) - process_msg_rcc_to_mac(msg); - } while (msg); + notifiedFIFO_elt_t *elt = pollNotifiedFIFO(&get_mac_inst(UE->Mod_id)->input_nf); + if (!elt) { + break; + } + process_msg_rcc_to_mac(NotifiedFifoData(elt), UE->Mod_id); + delNotifiedFIFO_elt(elt); + } while (true); if (UE->if_inst) UE->if_inst->slot_indication(UE->Mod_id, false); @@ -825,7 +639,8 @@ void dummyWrite(PHY_VARS_NR_UE *UE,openair0_timestamp timestamp, int writeBlockS AssertFatal(writeBlockSize == tmp, ""); } -void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, bool toTrash) { +void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, int duration_rx_to_tx, bool toTrash) +{ NR_DL_FRAME_PARMS *fp = &UE->frame_parms; // two frames for initial sync int num_frames = 2; @@ -853,7 +668,8 @@ void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, bool toTrash) AssertFatal(read_block_size == tmp, ""); if (IS_SOFTMODEM_RFSIM) { - const openair0_timestamp writeTimestamp = *timestamp + fp->get_samples_slot_timestamp(slot, fp, NR_UE_CAPABILITY_SLOT_RX_TO_TX) - UE->N_TA_offset; + const openair0_timestamp writeTimestamp = + *timestamp + fp->get_samples_slot_timestamp(slot, fp, duration_rx_to_tx) - UE->N_TA_offset - UE->timing_advance; dummyWrite(UE, writeTimestamp, fp->get_samples_per_slot(slot, fp)); } } @@ -864,7 +680,7 @@ void readFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, bool toTrash) free(rxp[i]); } -static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, openair0_timestamp rx_offset) +static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, int duration_rx_to_tx, openair0_timestamp rx_offset) { NR_DL_FRAME_PARMS *fp = &UE->frame_parms; if (UE->sl_mode == 2) @@ -879,7 +695,8 @@ static void syncInFrame(PHY_VARS_NR_UE *UE, openair0_timestamp *timestamp, opena const int res = UE->rfdevice.trx_read_func(&UE->rfdevice, timestamp, (void **)UE->common_vars.rxdata, unitTransfer, fp->nb_antennas_rx); DevAssert(unitTransfer == res); if (IS_SOFTMODEM_RFSIM) { - const openair0_timestamp writeTimestamp = *timestamp + fp->get_samples_slot_timestamp(slot, fp, NR_UE_CAPABILITY_SLOT_RX_TO_TX) - UE->N_TA_offset; + const openair0_timestamp writeTimestamp = + *timestamp + fp->get_samples_slot_timestamp(slot, fp, duration_rx_to_tx) - UE->N_TA_offset - UE->timing_advance; dummyWrite(UE, writeTimestamp, unitTransfer); } slot = (slot + 1) % fp->slots_per_subframe; @@ -905,7 +722,8 @@ static inline int get_readBlockSize(uint16_t slot, NR_DL_FRAME_PARMS *fp) { static inline void apply_ntn_config(PHY_VARS_NR_UE *UE, NR_DL_FRAME_PARMS *fp, - int slot_nr, + int frame_rx, + int slot_rx, int *duration_rx_to_tx, int *timing_advance, int *ntn_koffset) @@ -913,22 +731,43 @@ static inline void apply_ntn_config(PHY_VARS_NR_UE *UE, if (UE->ntn_config_message->update) { UE->ntn_config_message->update = false; - double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms; - UE->timing_advance = fp->samples_per_subframe * total_ta_ms; + const int mu = fp->numerology_index; + const int koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; - int mu = fp->numerology_index; - int koffset = UE->ntn_config_message->ntn_config_params.cell_specific_k_offset; - if (*ntn_koffset != koffset) { - *duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu); - *timing_advance += fp->get_samples_slot_timestamp(slot_nr, fp, (koffset - *ntn_koffset) << mu); - *ntn_koffset = koffset; - } + *duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX + (koffset << mu); + if (koffset > *ntn_koffset) + *timing_advance += fp->get_samples_slot_timestamp(slot_rx, fp, (koffset - *ntn_koffset) << mu); + else if (koffset < *ntn_koffset) + *timing_advance -= fp->get_samples_slot_timestamp(slot_rx, fp, (*ntn_koffset - koffset) << mu); + *ntn_koffset = koffset; + + const int abs_subframe_tx = 10 * frame_rx + ((slot_rx + *duration_rx_to_tx) >> mu); + const int abs_subframe_epoch = + 10 * UE->ntn_config_message->ntn_config_params.epoch_sfn + UE->ntn_config_message->ntn_config_params.epoch_subframe; + int ms_since_epoch = abs_subframe_tx - abs_subframe_epoch; + // cope with sfn wrap-around + // this currently limits us to epoch times that are not more than 5.12 seconds in the future (allowed are up to 10.24 seconds) + // and ntn-UlSyncValidityDuration < 5.12 seconds (allowed are up to 900 seconds) + // TODO: fix this limitation by introducing the hyper frame number HFN + if (ms_since_epoch < -5120) + ms_since_epoch += 10240; + else if (ms_since_epoch > 5120) + ms_since_epoch -= 10240; + + const double total_ta_ms = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms; + const double total_ta_drift = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift; // µs/s + const double total_ta_drift_variant = UE->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift_variant; // µs/s² + UE->timing_advance = fp->samples_per_subframe * (total_ta_ms + (total_ta_drift / 1000.0) * (ms_since_epoch / 1000.0) + (total_ta_drift_variant / 1000.0) * (ms_since_epoch / 1000.0) * (ms_since_epoch / 1000.0)); LOG_I(PHY, - "k_offset = %d ms (%d slots), ntn_total_time_advance_ms = %f ms (%d samples)\n", + "k_offset = %d ms (%d slots), total_ta_ms = %f ms, total_ta_drift = %f µs/s, total_ta_drift_variant = %f µs/s², ms_since_epoch = %d ms, computed " + "timing_advance = %d samples\n", *ntn_koffset, *ntn_koffset << mu, total_ta_ms, + total_ta_drift, + total_ta_drift_variant, + ms_since_epoch, UE->timing_advance); } } @@ -941,7 +780,7 @@ void *UE_thread(void *arg) void *rxp[NB_ANTENNAS_RX]; enum stream_status_e stream_status = STREAM_STATUS_UNSYNC; fapi_nr_config_request_t *cfg = &UE->nrUE_config; - int tmp = openair0_device_load(&(UE->rfdevice), &openair0_cfg[0]); + int tmp = openair0_device_load(&(UE->rfdevice), &UE->openair0_cfg[0]); AssertFatal(tmp == 0, "Could not load the device\n"); NR_DL_FRAME_PARMS *fp = &UE->frame_parms; sl_nr_phy_config_request_t *sl_cfg = NULL; @@ -965,6 +804,10 @@ void *UE_thread(void *arg) notifiedFIFO_t freeBlocks; initNotifiedFIFO_nothreadSafe(&freeBlocks); + double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift; + int ntn_koffset = 0; + + int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX; int timing_advance = UE->timing_advance; UE->N_TA_offset = determine_N_TA_offset(UE); NR_UE_MAC_INST_t *mac = get_mac_inst(UE->Mod_id); @@ -988,13 +831,9 @@ void *UE_thread(void *arg) //warm up the RF board int64_t tmp; for (int i = 0; i < 50; i++) - readFrame(UE, &tmp, true); + readFrame(UE, &tmp, duration_rx_to_tx, true); } - double ntn_init_time_drift = get_nrUE_params()->ntn_init_time_drift; - int ntn_koffset = 0; - int duration_rx_to_tx = NR_UE_CAPABILITY_SLOT_RX_TO_TX; - while (!oai_exit) { if (syncRunning) { notifiedFIFO_elt_t *res = pollNotifiedFIFO(&nf); @@ -1007,12 +846,10 @@ void *UE_thread(void *arg) decoded_frame_rx = UE->SL_UE_PHY_PARAMS.sync_params.DFN; else { // We must wait the RRC layer decoded the MIB and sent us the frame number - MessageDef *msg = NULL; - itti_receive_msg(TASK_MAC_UE, &msg); - if (msg) - process_msg_rcc_to_mac(msg); - else - LOG_E(PHY, "It seems we arbort while trying to sync\n"); + notifiedFIFO_elt_t *elt = pullNotifiedFIFO(&mac->input_nf); + AssertFatal(elt != NULL, "fifo error while waiting for MIB"); + process_msg_rcc_to_mac(NotifiedFifoData(elt), UE->Mod_id); + delNotifiedFIFO_elt(elt); decoded_frame_rx = mac->mib_frame; } LOG_A(PHY, @@ -1034,11 +871,11 @@ void *UE_thread(void *arg) */ const unsigned int sync_in_frames = UE->rfdevice.openair0_cfg->recplay_conf->u_f_sync; while (trashed_frames != sync_in_frames) { - readFrame(UE, &sync_timestamp, true); + readFrame(UE, &sync_timestamp, duration_rx_to_tx, true); trashed_frames += 2; } } else { - readFrame(UE, &sync_timestamp, true); + readFrame(UE, &sync_timestamp, duration_rx_to_tx, true); trashed_frames += ((UE->sl_mode == 2) ? SL_NR_PSBCH_REPETITION_IN_FRAMES : 2); } continue; @@ -1048,7 +885,7 @@ void *UE_thread(void *arg) AssertFatal(!syncRunning, "At this point synchronization can't be running\n"); if (!UE->is_synchronized) { - readFrame(UE, &sync_timestamp, false); + readFrame(UE, &sync_timestamp, duration_rx_to_tx, 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}; @@ -1065,8 +902,10 @@ void *UE_thread(void *arg) syncMsg->UE = UE; memset(&syncMsg->proc, 0, sizeof(syncMsg->proc)); pushNotifiedFIFO(&UE->sync_actor.fifo, Msg); - timing_advance = 0; - UE->timing_advance = 0; + if (ntn_koffset == 0) { // reset timing_advance for TN + timing_advance = 0; + UE->timing_advance = 0; + } trashed_frames = 0; syncRunning = true; continue; @@ -1074,7 +913,7 @@ void *UE_thread(void *arg) if (stream_status == STREAM_STATUS_UNSYNC) { stream_status = STREAM_STATUS_SYNCING; - syncInFrame(UE, &sync_timestamp, intialSyncOffset); + syncInFrame(UE, &sync_timestamp, duration_rx_to_tx, intialSyncOffset); openair0_write_reorder_clear_context(&UE->rfdevice); if (get_nrUE_params()->time_sync_I) // ntn_init_time_drift is in µs/s, max_pos_acc * time_sync_I is in samples/frame @@ -1083,9 +922,6 @@ void *UE_thread(void *arg) UE->max_pos_acc = 0; shiftForNextFrame = -(UE->init_sync_frame + trashed_frames + 2) * UE->max_pos_acc * get_nrUE_params()->time_sync_I; // compensate for the time drift that happened during initial sync LOG_D(PHY, "max_pos_acc = %d, shiftForNextFrame = %d\n", UE->max_pos_acc, shiftForNextFrame); - // TODO: remove this autonomous TA and use up-to-date values of ta-Common, ta-CommonDrift and ta-CommonDriftVariant from received SIB19 instead - if (get_nrUE_params()->autonomous_ta) - UE->timing_advance -= 2 * shiftForNextFrame; // read in first symbol AssertFatal(fp->ofdm_symbol_size + fp->nb_prefix_samples0 == UE->rfdevice.trx_read_func(&UE->rfdevice, @@ -1200,7 +1036,7 @@ void *UE_thread(void *arg) int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply; int new_timing_advance = UE->timing_advance; if (new_timing_advance != timing_advance) { - writeBlockSize -= new_timing_advance- timing_advance; + writeBlockSize -= new_timing_advance - timing_advance; timing_advance = new_timing_advance; } int new_N_TA_offset = determine_N_TA_offset(UE); @@ -1210,8 +1046,8 @@ void *UE_thread(void *arg) UE->N_TA_offset = new_N_TA_offset; } - if (curMsg.proc.nr_slot_tx == 0) - nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.frame_tx, curMsg.proc.gNB_id); + if (curMsg.proc.nr_slot_rx == 0) + nr_ue_rrc_timer_trigger(UE->Mod_id, curMsg.proc.frame_rx, curMsg.proc.gNB_id); // RX slot processing. We launch and forget. notifiedFIFO_elt_t *newRx = newNotifiedFIFO_elt(sizeof(nr_rxtx_thread_data_t), curMsg.proc.nr_slot_tx, NULL, UE_dl_processing); @@ -1227,7 +1063,7 @@ void *UE_thread(void *arg) } // apply new NTN timing information - apply_ntn_config(UE, fp, slot_nr, &duration_rx_to_tx, &timing_advance, &ntn_koffset); + apply_ntn_config(UE, fp, curMsg.proc.frame_rx, curMsg.proc.nr_slot_rx, &duration_rx_to_tx, &timing_advance, &ntn_koffset); // Start TX slot processing here. It runs in parallel with RX slot processing // in current code, DURATION_RX_TO_TX constant is the limit to get UL data to encode from a RX slot @@ -1260,20 +1096,19 @@ void *UE_thread(void *arg) void init_NR_UE(int nb_inst, char *uecap_file, char *reconfig_file, char *rbconfig_file) { - NR_UE_RRC_INST_t *rrc_inst = nr_rrc_init_ue(uecap_file, nb_inst, get_nrUE_params()->nb_antennas_tx); - NR_UE_MAC_INST_t *mac_inst = nr_l2_init_ue(nb_inst); - AssertFatal(mac_inst, "Couldn't allocate MAC module\n"); + for (int instance_id = 0; instance_id < nb_inst; instance_id++) { + NR_UE_RRC_INST_t* rrc = nr_rrc_init_ue(uecap_file, instance_id, get_nrUE_params()->nb_antennas_tx); + NR_UE_MAC_INST_t *mac = nr_l2_init_ue(instance_id); - for (int i = 0; i < nb_inst; i++) { - NR_UE_MAC_INST_t *mac = get_mac_inst(i); - mac->if_module = nr_ue_if_module_init(i); + nr_rrc_set_mac_queue(instance_id, &mac->input_nf); + mac->if_module = nr_ue_if_module_init(instance_id); AssertFatal(mac->if_module, "can not initialize IF module\n"); if (!IS_SA_MODE(get_softmodem_params()) && !get_softmodem_params()->sl_mode) { - init_nsa_message(&rrc_inst[i], reconfig_file, rbconfig_file); - nr_rlc_activate_srb0(mac_inst[i].crnti, NULL, send_srb0_rrc); + init_nsa_message(rrc, reconfig_file, rbconfig_file); + nr_rlc_activate_srb0(mac->crnti, NULL, send_srb0_rrc); } //TODO: Move this call to RRC - start_sidelink((&rrc_inst[i])->ue_id); + start_sidelink(instance_id); } } diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index f1e94e9e55..fbac6402f5 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -93,15 +93,6 @@ unsigned short config_frames[4] = {2,9,11,13}; THREAD_STRUCT thread_struct; nrUE_params_t nrUE_params = {0}; -// Thread variables -pthread_cond_t nfapi_sync_cond; -pthread_mutex_t nfapi_sync_mutex; -int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex -pthread_cond_t sync_cond; -pthread_mutex_t sync_mutex; -int sync_var=-1; //!< protected by mutex \ref sync_mutex. -int config_sync_var=-1; - // not used in UE instance_t CUuniqInstance=0; instance_t DUuniqInstance=0; @@ -111,7 +102,6 @@ int get_node_type() {return -1;} RAN_CONTEXT_t RC; int oai_exit = 0; - static int tx_max_power[MAX_NUM_CCs] = {0}; double rx_gain_off = 0.0; @@ -121,12 +111,7 @@ int32_t uplink_frequency_offset[MAX_NUM_CCs][4]; uint64_t sidelink_frequency[MAX_NUM_CCs][4]; // UE and OAI config variables - -openair0_config_t openair0_cfg[MAX_CARDS]; -int16_t node_synch_ref[MAX_NUM_CCs]; -int otg_enabled; double cpuf; -uint32_t N_RB_DL = 106; int create_tasks_nrue(uint32_t ue_nb) { LOG_D(NR_RRC, "%s(ue_nb:%d)\n", __FUNCTION__, ue_nb); @@ -139,13 +124,6 @@ int create_tasks_nrue(uint32_t ue_nb) { LOG_E(NR_RRC, "Create task for RRC UE failed\n"); return -1; } - if (get_softmodem_params()->nsa) { - init_connections_with_lte_ue(); - if (itti_create_task (TASK_RRC_NSA_NRUE, recv_msgs_from_lte_ue, NULL) < 0) { - LOG_E(NR_RRC, "Create task for RRC NSA nr-UE failed\n"); - return -1; - } - } const ittiTask_parms_t parmsNAS = {NULL, nas_nrue}; if (itti_create_task(TASK_NAS_NRUE, nas_nrue_task, &parmsNAS) < 0) { LOG_E(NR_RRC, "Create task for NAS UE failed\n"); @@ -170,8 +148,12 @@ void exit_function(const char *file, const char *function, const int line, const if (PHY_vars_UE_g && PHY_vars_UE_g[0]) { for(CC_id=0; CC_idrfdevice.trx_end_func) + if (PHY_vars_UE_g[0][CC_id] && PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func) { + if (PHY_vars_UE_g[0][CC_id]->rfdevice.trx_get_stats_func) { + PHY_vars_UE_g[0][CC_id]->rfdevice.trx_get_stats_func(&PHY_vars_UE_g[0][CC_id]->rfdevice); + } PHY_vars_UE_g[0][CC_id]->rfdevice.trx_end_func(&PHY_vars_UE_g[0][CC_id]->rfdevice); + } } } @@ -197,11 +179,15 @@ nrUE_params_t *get_nrUE_params(void) { } static void get_options(configmodule_interface_t *cfg) { - paramdef_t cmdline_params[] =CMDLINE_NRUEPARAMS_DESC ; + paramdef_t cmdline_params[] = CMDLINE_NRUEPARAMS_DESC; int numparams = sizeofArray(cmdline_params); config_get(cfg, cmdline_params, numparams, NULL); if (nrUE_params.vcdflag > 0) ouput_vcd = 1; + AssertFatal(nrUE_params.extra_pdu_id != get_softmodem_params()->default_pdu_session_id, + "Default PDU ID (%d) and Extra PDU ID (%d) must be different!\n", + get_softmodem_params()->default_pdu_session_id, + nrUE_params.extra_pdu_id); } // set PHY vars from command line @@ -241,42 +227,42 @@ void set_options(int CC_id, PHY_VARS_NR_UE *UE){ } -void init_openair0() +void init_openair0(PHY_VARS_NR_UE *ue) { int card; int freq_off = 0; - NR_DL_FRAME_PARMS *frame_parms = &PHY_vars_UE_g[0][0]->frame_parms; + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; bool is_sidelink = (get_softmodem_params()->sl_mode) ? true : false; if (is_sidelink) - frame_parms = &PHY_vars_UE_g[0][0]->SL_UE_PHY_PARAMS.sl_frame_params; + frame_parms = &ue->SL_UE_PHY_PARAMS.sl_frame_params; for (card=0; cardopenair0_cfg[card]; uint64_t dl_carrier, ul_carrier; - openair0_cfg[card].configFilename = NULL; - openair0_cfg[card].threequarter_fs = frame_parms->threequarter_fs; - openair0_cfg[card].sample_rate = frame_parms->samples_per_subframe * 1e3; - openair0_cfg[card].samples_per_frame = frame_parms->samples_per_frame; + cfg->configFilename = NULL; + cfg->sample_rate = frame_parms->samples_per_subframe * 1e3; + cfg->samples_per_frame = frame_parms->samples_per_frame; if (frame_parms->frame_type==TDD) - openair0_cfg[card].duplex_mode = duplex_mode_TDD; + cfg->duplex_mode = duplex_mode_TDD; else - openair0_cfg[card].duplex_mode = duplex_mode_FDD; + cfg->duplex_mode = duplex_mode_FDD; - openair0_cfg[card].Mod_id = 0; - openair0_cfg[card].num_rb_dl = frame_parms->N_RB_DL; - openair0_cfg[card].clock_source = get_softmodem_params()->clock_source; - openair0_cfg[card].time_source = get_softmodem_params()->timing_source; - openair0_cfg[card].tune_offset = get_softmodem_params()->tune_offset; - openair0_cfg[card].tx_num_channels = min(4, frame_parms->nb_antennas_tx); - openair0_cfg[card].rx_num_channels = min(4, frame_parms->nb_antennas_rx); + cfg->Mod_id = 0; + cfg->num_rb_dl = frame_parms->N_RB_DL; + cfg->clock_source = get_softmodem_params()->clock_source; + cfg->time_source = get_softmodem_params()->timing_source; + cfg->tune_offset = get_softmodem_params()->tune_offset; + cfg->tx_num_channels = min(4, frame_parms->nb_antennas_tx); + cfg->rx_num_channels = min(4, frame_parms->nb_antennas_rx); LOG_I(PHY, "HW: Configuring card %d, sample_rate %f, tx/rx num_channels %d/%d, duplex_mode %s\n", card, - openair0_cfg[card].sample_rate, - openair0_cfg[card].tx_num_channels, - openair0_cfg[card].rx_num_channels, - duplex_mode_txt[openair0_cfg[card].duplex_mode]); + cfg->sample_rate, + cfg->tx_num_channels, + cfg->rx_num_channels, + duplex_mode_txt[cfg->duplex_mode]); if (is_sidelink) { dl_carrier = frame_parms->dl_CarrierFreq; @@ -284,27 +270,21 @@ void init_openair0() } else nr_get_carrier_frequencies(PHY_vars_UE_g[0][0], &dl_carrier, &ul_carrier); - nr_rf_card_config_freq(&openair0_cfg[card], ul_carrier, dl_carrier, freq_off); + nr_rf_card_config_freq(cfg, ul_carrier, dl_carrier, freq_off); - nr_rf_card_config_gain(&openair0_cfg[card], rx_gain_off); + nr_rf_card_config_gain(cfg, rx_gain_off); - openair0_cfg[card].configFilename = get_softmodem_params()->rf_config_file; - - if (get_nrUE_params()->usrp_args) openair0_cfg[card].sdr_addrs = get_nrUE_params()->usrp_args; - if (get_nrUE_params()->tx_subdev) openair0_cfg[card].tx_subdev = get_nrUE_params()->tx_subdev; - if (get_nrUE_params()->rx_subdev) openair0_cfg[card].rx_subdev = get_nrUE_params()->rx_subdev; + cfg->configFilename = get_softmodem_params()->rf_config_file; + if (get_nrUE_params()->usrp_args) + cfg->sdr_addrs = get_nrUE_params()->usrp_args; + if (get_nrUE_params()->tx_subdev) + cfg->tx_subdev = get_nrUE_params()->tx_subdev; + if (get_nrUE_params()->rx_subdev) + cfg->rx_subdev = get_nrUE_params()->rx_subdev; } } -static void init_pdcp(int ue_id) -{ - if (get_softmodem_params()->nsa && nr_rlc_module_init(NR_RLC_OP_MODE_UE) != 0) { - LOG_I(RLC, "Problem at RLC initiation \n"); - } - nr_pdcp_layer_init(); -} - // Stupid function addition because UE itti messages queues definition is common with eNB void *rrc_enb_process_msg(void *notUsed) { return NULL; @@ -319,9 +299,11 @@ static void trigger_stop(int sig) static void trigger_deregistration(int sig) { if (!stop_immediately && IS_SA_MODE(get_softmodem_params())) { - MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_DEREGISTRATION_REQ); - NAS_DEREGISTRATION_REQ(msg).cause = AS_DETACH; - itti_send_msg_to_task(TASK_NAS_NRUE, 0, msg); + for (int ue_inst = 0; ue_inst < NB_UE_INST; ue_inst++) { + MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, ue_inst, NAS_DEREGISTRATION_REQ); + NAS_DEREGISTRATION_REQ(msg).cause = AS_DETACH; + itti_send_msg_to_task(TASK_NAS_NRUE, ue_inst, msg); + } stop_immediately = true; static const char m[] = "Press ^C again to trigger immediate shutdown\n"; __attribute__((unused)) int unused = write(STDOUT_FILENO, m, sizeof(m) - 1); @@ -332,40 +314,6 @@ static void trigger_deregistration(int sig) } } -static void get_channel_model_mode(configmodule_interface_t *cfg) -{ - paramdef_t GNBParams[] = GNBPARAMS_DESC; - config_get(cfg, GNBParams, sizeofArray(GNBParams), NULL); - int num_xp_antennas = *GNBParams[GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr; - - if (num_xp_antennas == 2) - init_nr_bler_table("NR_MIMO2x2_AWGN_RESULTS_DIR"); - else - init_nr_bler_table("NR_AWGN_RESULTS_DIR"); -} - -void start_oai_nrue_threads() -{ - init_queue(&nr_rach_ind_queue); - init_queue(&nr_rx_ind_queue); - init_queue(&nr_crc_ind_queue); - init_queue(&nr_uci_ind_queue); - init_queue(&nr_sfn_slot_queue); - init_queue(&nr_chan_param_queue); - init_queue(&nr_dl_tti_req_queue); - init_queue(&nr_tx_req_queue); - init_queue(&nr_ul_dci_req_queue); - init_queue(&nr_ul_tti_req_queue); - - if (sem_init(&sfn_slot_semaphore, 0, 0) != 0) - { - LOG_E(MAC, "sem_init() error\n"); - abort(); - } - - init_nrUE_standalone_thread(ue_id_g); -} - int NB_UE_INST = 1; configmodule_interface_t *uniqCfg = NULL; nrLDPC_coding_interface_t nrLDPC_coding_interface = {0}; @@ -379,7 +327,6 @@ int main(int argc, char **argv) } //set_softmodem_sighandler(); CONFIG_SETRTFLAG(CONFIG_NOEXITONHELP); - memset(openair0_cfg,0,sizeof(openair0_config_t)*MAX_CARDS); memset(tx_max_power,0,sizeof(int)*MAX_NUM_CCs); // initialize logging logInit(); @@ -418,12 +365,11 @@ int main(int argc, char **argv) char *pckg = strdup(OAI_PACKAGE_VERSION); LOG_I(HW, "Version: %s\n", pckg); - PHY_vars_UE_g = malloc(sizeof(*PHY_vars_UE_g) * NB_UE_INST); + PHY_vars_UE_g = calloc_or_fail(NB_UE_INST, sizeof(*PHY_vars_UE_g)); for (int inst = 0; inst < NB_UE_INST; inst++) { - PHY_vars_UE_g[inst] = malloc(sizeof(*PHY_vars_UE_g[inst]) * MAX_NUM_CCs); + PHY_vars_UE_g[inst] = calloc_or_fail(MAX_NUM_CCs, sizeof(*PHY_vars_UE_g[inst])); for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - PHY_vars_UE_g[inst][CC_id] = malloc(sizeof(*PHY_vars_UE_g[inst][CC_id])); - memset(PHY_vars_UE_g[inst][CC_id], 0, sizeof(*PHY_vars_UE_g[inst][CC_id])); + PHY_vars_UE_g[inst][CC_id] = calloc_or_fail(1, sizeof(*PHY_vars_UE_g[inst][CC_id])); // All instances use the same coding interface PHY_vars_UE_g[inst][CC_id]->nrLDPC_coding_interface = nrLDPC_coding_interface; } @@ -434,24 +380,11 @@ int main(int argc, char **argv) exit(-1); // need a softer mode } - int mode_offset = get_softmodem_params()->nsa ? NUMBER_OF_UE_MAX : 1; - uint16_t node_number = get_softmodem_params()->node_number; - ue_id_g = (node_number == 0) ? 0 : node_number - 2; - AssertFatal(ue_id_g >= 0, "UE id is expected to be nonnegative.\n"); - - if (node_number == 0) - init_pdcp(0); - else - init_pdcp(mode_offset + ue_id_g); + nr_pdcp_layer_init(); nas_init_nrue(NB_UE_INST); init_NR_UE(NB_UE_INST, get_nrUE_params()->uecap_file, get_nrUE_params()->reconfig_file, get_nrUE_params()->rbconfig_file); - if (get_softmodem_params()->emulate_l1) { - RCconfig_nr_ue_macrlc(); - get_channel_model_mode(uniqCfg); - } - // start time manager with some reasonable default for the running mode // (may be overwritten in configuration file or command line) void nr_pdcp_ms_tick(void); @@ -467,95 +400,90 @@ int main(int argc, char **argv) IS_SOFTMODEM_RFSIM ? TIME_SOURCE_IQ_SAMPLES : TIME_SOURCE_REALTIME); - if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1) - start_oai_nrue_threads(); - - if (!get_softmodem_params()->emulate_l1) { - for (int inst = 0; inst < NB_UE_INST; inst++) { - PHY_VARS_NR_UE *UE[MAX_NUM_CCs]; - for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { - UE[CC_id] = PHY_vars_UE_g[inst][CC_id]; - - set_options(CC_id, UE[CC_id]); - NR_UE_MAC_INST_t *mac = get_mac_inst(inst); - init_nr_ue_phy_cpu_stats(&UE[CC_id]->phy_cpu_stats); - - if (IS_SA_MODE(get_softmodem_params()) || get_softmodem_params()->sl_mode) { // set frame config to initial values from command line - // and assume that the SSB is centered on the grid - uint16_t nr_band = get_softmodem_params()->band; - mac->nr_band = nr_band; - mac->ssb_start_subcarrier = UE[CC_id]->frame_parms.ssb_start_subcarrier; - nr_init_frame_parms_ue_sa(&UE[CC_id]->frame_parms, - downlink_frequency[CC_id][0], - uplink_frequency_offset[CC_id][0], - get_softmodem_params()->numerology, - nr_band); - } else { - MessageDef *msg = NULL; - do { - itti_poll_msg(TASK_MAC_UE, &msg); - if (msg) - process_msg_rcc_to_mac(msg); - } while (msg); - fapi_nr_config_request_t *nrUE_config = &UE[CC_id]->nrUE_config; - nr_init_frame_parms_ue(&UE[CC_id]->frame_parms, nrUE_config, mac->nr_band); - } - - UE[CC_id]->sl_mode = get_softmodem_params()->sl_mode; - init_actor(&UE[CC_id]->sync_actor, "SYNC_", -1); - if (get_nrUE_params()->num_dl_actors > 0) { - UE[CC_id]->dl_actors = calloc_or_fail(get_nrUE_params()->num_dl_actors, sizeof(*UE[CC_id]->dl_actors)); - for (int i = 0; i < get_nrUE_params()->num_dl_actors; i++) { - init_actor(&UE[CC_id]->dl_actors[i], "DL_", -1); + for (int inst = 0; inst < NB_UE_INST; inst++) { + PHY_VARS_NR_UE *UE[MAX_NUM_CCs]; + for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { + UE[CC_id] = PHY_vars_UE_g[inst][CC_id]; + set_options(CC_id, UE[CC_id]); + NR_UE_MAC_INST_t *mac = get_mac_inst(inst); + init_nr_ue_phy_cpu_stats(&UE[CC_id]->phy_cpu_stats); + // set frame config to initial values from command line and assume that the SSB is centered on the grid + if (IS_SA_MODE(get_softmodem_params()) || get_softmodem_params()->sl_mode) { + uint16_t nr_band = get_softmodem_params()->band; + mac->nr_band = nr_band; + mac->ssb_start_subcarrier = UE[CC_id]->frame_parms.ssb_start_subcarrier; + nr_init_frame_parms_ue_sa(&UE[CC_id]->frame_parms, + downlink_frequency[CC_id][0], + uplink_frequency_offset[CC_id][0], + get_softmodem_params()->numerology, + nr_band); + } else { + do { + notifiedFIFO_elt_t *elt = pollNotifiedFIFO(&mac->input_nf); + if (!elt) { + break; } - } - if (get_nrUE_params()->num_ul_actors > 0) { - UE[CC_id]->ul_actors = calloc_or_fail(get_nrUE_params()->num_ul_actors, sizeof(*UE[CC_id]->ul_actors)); - for (int i = 0; i < get_nrUE_params()->num_ul_actors; i++) { - init_actor(&UE[CC_id]->ul_actors[i], "UL_", -1); - } - } - init_nr_ue_vars(UE[CC_id], inst); + process_msg_rcc_to_mac(NotifiedFifoData(elt), inst); + delNotifiedFIFO_elt(elt); + } while (true); + fapi_nr_config_request_t *nrUE_config = &UE[CC_id]->nrUE_config; + nr_init_frame_parms_ue(&UE[CC_id]->frame_parms, nrUE_config, mac->nr_band); + } - if (UE[CC_id]->sl_mode) { - AssertFatal(UE[CC_id]->sl_mode == 2, "Only Sidelink mode 2 supported. Mode 1 not yet supported\n"); - DevAssert(mac->if_module != NULL && mac->if_module->sl_phy_config_request != NULL); - nr_sl_phy_config_t *phycfg = &mac->SL_MAC_PARAMS->sl_phy_config; - phycfg->sl_config_req.sl_carrier_config.sl_num_rx_ant = get_nrUE_params()->nb_antennas_rx; - phycfg->sl_config_req.sl_carrier_config.sl_num_tx_ant = get_nrUE_params()->nb_antennas_tx; - mac->if_module->sl_phy_config_request(phycfg); - sl_nr_ue_phy_params_t *sl_phy = &UE[CC_id]->SL_UE_PHY_PARAMS; - nr_init_frame_parms_ue_sl(&sl_phy->sl_frame_params, - &sl_phy->sl_config, - get_softmodem_params()->threequarter_fs, - get_nrUE_params()->ofdm_offset_divisor); - sl_ue_phy_init(UE[CC_id]); + UE[CC_id]->sl_mode = get_softmodem_params()->sl_mode; + init_actor(&UE[CC_id]->sync_actor, "SYNC_", -1); + if (get_nrUE_params()->num_dl_actors > 0) { + UE[CC_id]->dl_actors = calloc_or_fail(get_nrUE_params()->num_dl_actors, sizeof(*UE[CC_id]->dl_actors)); + for (int i = 0; i < get_nrUE_params()->num_dl_actors; i++) { + init_actor(&UE[CC_id]->dl_actors[i], "DL_", -1); } } - } + if (get_nrUE_params()->num_ul_actors > 0) { + UE[CC_id]->ul_actors = calloc_or_fail(get_nrUE_params()->num_ul_actors, sizeof(*UE[CC_id]->ul_actors)); + for (int i = 0; i < get_nrUE_params()->num_ul_actors; i++) { + init_actor(&UE[CC_id]->ul_actors[i], "UL_", -1); + } + } + init_nr_ue_vars(UE[CC_id], inst); - init_openair0(); - lock_memory_to_ram(); - - if (IS_SOFTMODEM_DOSCOPE) { - load_softscope("nr", PHY_vars_UE_g[0][0]); + if (UE[CC_id]->sl_mode) { + AssertFatal(UE[CC_id]->sl_mode == 2, "Only Sidelink mode 2 supported. Mode 1 not yet supported\n"); + DevAssert(mac->if_module != NULL && mac->if_module->sl_phy_config_request != NULL); + nr_sl_phy_config_t *phycfg = &mac->SL_MAC_PARAMS->sl_phy_config; + phycfg->sl_config_req.sl_carrier_config.sl_num_rx_ant = get_nrUE_params()->nb_antennas_rx; + phycfg->sl_config_req.sl_carrier_config.sl_num_tx_ant = get_nrUE_params()->nb_antennas_tx; + mac->if_module->sl_phy_config_request(phycfg); + sl_nr_ue_phy_params_t *sl_phy = &UE[CC_id]->SL_UE_PHY_PARAMS; + nr_init_frame_parms_ue_sl(&sl_phy->sl_frame_params, + &sl_phy->sl_config, + get_softmodem_params()->threequarter_fs, + get_nrUE_params()->ofdm_offset_divisor); + sl_ue_phy_init(UE[CC_id]); + } + init_openair0(UE[CC_id]); } - if (IS_SOFTMODEM_IMSCOPE_ENABLED) { - load_softscope("im", PHY_vars_UE_g[0][0]); - } - AssertFatal(!(IS_SOFTMODEM_IMSCOPE_ENABLED && IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED), - "Data recoding and ImScope cannot be enabled at the same time\n"); - if (IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED) { - load_module_shlib("imscope_record", NULL, 0, PHY_vars_UE_g[0][0]); - } - - for (int inst = 0; inst < NB_UE_INST; inst++) { - LOG_I(PHY,"Intializing UE Threads for instance %d ...\n", inst); - init_NR_UE_threads(PHY_vars_UE_g[inst][0]); - } - printf("UE threads created by %ld\n", gettid()); } + lock_memory_to_ram(); + + if (IS_SOFTMODEM_DOSCOPE) { + load_softscope("nr", PHY_vars_UE_g[0][0]); + } + if (IS_SOFTMODEM_IMSCOPE_ENABLED) { + load_softscope("im", PHY_vars_UE_g[0][0]); + } + AssertFatal(!(IS_SOFTMODEM_IMSCOPE_ENABLED && IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED), + "Data recoding and ImScope cannot be enabled at the same time\n"); + if (IS_SOFTMODEM_IMSCOPE_RECORD_ENABLED) { + load_module_shlib("imscope_record", NULL, 0, PHY_vars_UE_g[0][0]); + } + + for (int inst = 0; inst < NB_UE_INST; inst++) { + LOG_I(PHY,"Intializing UE Threads for instance %d ...\n", inst); + init_NR_UE_threads(PHY_vars_UE_g[inst][0]); + } + printf("UE threads created by %ld\n", gettid()); + // wait for end of program printf("TYPE TO TERMINATE\n"); @@ -591,6 +519,8 @@ int main(int argc, char **argv) ret = pthread_join(phy_vars->stat_thread, NULL); AssertFatal(ret == 0, "pthread_join error %d, errno %d (%s)\n", ret, errno, strerror(errno)); } + if (phy_vars->rfdevice.trx_get_stats_func) + phy_vars->rfdevice.trx_get_stats_func(&phy_vars->rfdevice); if (phy_vars->rfdevice.trx_end_func) phy_vars->rfdevice.trx_end_func(&phy_vars->rfdevice); } diff --git a/executables/nr-uesoftmodem.h b/executables/nr-uesoftmodem.h index 2eb9138e78..df13e2e02e 100644 --- a/executables/nr-uesoftmodem.h +++ b/executables/nr-uesoftmodem.h @@ -5,6 +5,7 @@ #include "common/utils/threadPool/thread-pool.h" #include "PHY/defs_nr_UE.h" +#define MAX_NUM_NR_UE_INST 32 extern int NB_UE_INST; extern uint16_t ue_id_g; @@ -24,6 +25,7 @@ extern uint16_t ue_id_g; #define CONFIG_HLP_AGC "Rx Gain control used for UE\n" #define CONFIG_HLP_NUM_UL_ACTORS "Number of UL actors to use. Set to 0 to disable UL actor framework and do processing inline\n" #define CONFIG_HLP_NUM_DL_ACTORS "Number of DL actors to use. Set to 0 to disable DL actor framework and do processing inline\n" +#define CONFIG_HLP_EXTRA_PDU_ID "ID of an additional PDU session to configure alongside default PDU session\n" /***************************************************************************************************************************************/ /* command line options definitions, CMDLINE_XXXX_DESC macros are used to initialize paramdef_t arrays which are then used as argument @@ -81,6 +83,7 @@ extern uint16_t ue_id_g; {"agc", CONFIG_HLP_AGC, PARAMFLAG_BOOL, .iptr=&(nrUE_params.agc), .defintval=0, TYPE_INT, 0}, \ {"num-ul-actors", CONFIG_HLP_NUM_UL_ACTORS, 0, .iptr=&nrUE_params.num_ul_actors, .defintval=2, TYPE_INT, 0}, \ {"num-dl-actors", CONFIG_HLP_NUM_DL_ACTORS, 0, .iptr=&nrUE_params.num_dl_actors, .defintval=4, TYPE_INT, 0}, \ + {"extra-pdu-id", CONFIG_HLP_EXTRA_PDU_ID, 0, .iptr=&nrUE_params.extra_pdu_id, .defintval=-1, TYPE_INT, 0}, \ } // clang-format on @@ -122,6 +125,7 @@ typedef struct { int tx_max_power; int num_ul_actors; int num_dl_actors; + int extra_pdu_id; } nrUE_params_t; extern uint64_t get_nrUE_optmask(void); extern uint64_t set_nrUE_optmask(uint64_t bitmask); @@ -133,8 +137,6 @@ extern int setup_nr_ue_buffers(PHY_VARS_NR_UE **phy_vars_ue, openair0_config_t * extern void fill_ue_band_info(void); extern void init_NR_UE(int, char *, char *, char *); extern void init_NR_UE_threads(PHY_VARS_NR_UE *ue); -void start_oai_nrue_threads(void); void *UE_thread(void *arg); void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id); -void init_nrUE_standalone_thread(int ue_idx); #endif diff --git a/executables/position_interface.h b/executables/position_interface.h index 0324bceb15..8ef0b3144b 100644 --- a/executables/position_interface.h +++ b/executables/position_interface.h @@ -41,16 +41,16 @@ /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ // clang-format off #define POSITION_CONFIG_PARAMS_DEF { \ - {CONFIG_STRING_POSITION_X, HELP_STRING_POSITION, 0, .dblptr=&(position->positionX), .defuintval=0, TYPE_DOUBLE, 0}, \ - {CONFIG_STRING_POSITION_Y, HELP_STRING_POSITION, 0, .dblptr=&(position->positionY), .defuintval=0, TYPE_DOUBLE, 0}, \ - {CONFIG_STRING_POSITION_Z, HELP_STRING_POSITION, 0, .dblptr=&(position->positionZ), .defuintval=0, TYPE_DOUBLE, 0} \ + {CONFIG_STRING_POSITION_X, HELP_STRING_POSITION, 0, .dblptr=&(position->X), .defuintval=0, TYPE_DOUBLE, 0}, \ + {CONFIG_STRING_POSITION_Y, HELP_STRING_POSITION, 0, .dblptr=&(position->Y), .defuintval=0, TYPE_DOUBLE, 0}, \ + {CONFIG_STRING_POSITION_Z, HELP_STRING_POSITION, 0, .dblptr=&(position->Z), .defuintval=0, TYPE_DOUBLE, 0} \ } // clang-format on typedef struct position { - double positionX; - double positionY; - double positionZ; + double X; + double Y; + double Z; } position_t; void get_position_coordinates(int Mod_id, position_t *position); diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 8bd3558ff1..4dfa5eb680 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -66,7 +66,6 @@ extern "C" #define CONFIG_HLP_CLK "tells hardware to use a clock reference (0:internal, 1:external, 2:gpsdo)\n" #define CONFIG_HLP_TME "tells hardware to use a time reference (0:internal, 1:external, 2:gpsdo)\n" #define CONFIG_HLP_TUNE_OFFSET "LO tuning offset to use in Hz\n" -#define CONFIG_HLP_USIM "use XOR autentication algo in case of test usim mode\n" #define CONFIG_HLP_NOSNGLT "Disables single-thread mode in lte-softmodem\n" #define CONFIG_HLP_DLF "Set the downlink frequency for all component carriers\n" #define CONFIG_HLP_ULF "Set the uplink frequency offset for all component carriers\n" @@ -97,7 +96,6 @@ extern "C" #define CONFIG_HLP_NUMEROLOGY "adding numerology for 5G\n" #define CONFIG_HLP_BAND "band index\n" -#define CONFIG_HLP_EMULATE_RF "Emulated RF enabled(disable by defult)\n" #define CONFIG_HLP_PARALLEL_CMD "three config for level of parallelism 'PARALLEL_SINGLE_THREAD', 'PARALLEL_RU_L1_SPLIT', or 'PARALLEL_RU_L1_TRX_SPLIT'\n" #define CONFIG_HLP_WORKER_CMD "two option for worker 'WORKER_DISABLE' or 'WORKER_ENABLE'\n" #define CONFIG_HLP_USRP_THREAD "having extra thead for usrp tx\n" @@ -107,7 +105,6 @@ extern "C" #define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n" #define CONFIG_HLP_USRP_THREAD "having extra thead for usrp tx\n" #define CONFIG_HLP_NFAPI "Change the nFAPI mode for NR 'MONOLITHIC', 'PNF', 'VNF', 'AERIAL','UE_STUB_PNF','UE_STUB_OFFNET','STANDALONE_PNF'\n" -#define CONFIG_L1_EMULATOR "Run in L1 emulated mode (disable PHY layer)\n" #define CONFIG_HLP_CONTINUOUS_TX "perform continuous transmission, even in TDD mode (to work around USRP issues)\n" #define CONFIG_HLP_STATS_DISABLE "disable globally the stats generation and persistence" #define CONFIG_HLP_NOITTI "Do not start itti threads, call queue processing in place, inside the caller thread" @@ -129,19 +126,16 @@ extern "C" #define CHAIN_OFFSET softmodem_params.chain_offset #define NUMEROLOGY softmodem_params.numerology #define BAND softmodem_params.band -#define EMULATE_RF softmodem_params.emulate_rf #define CLOCK_SOURCE softmodem_params.clock_source #define TIMING_SOURCE softmodem_params.timing_source #define TUNE_OFFSET softmodem_params.tune_offset #define SEND_DMRSSYNC softmodem_params.send_dmrs_sync -#define USIM_TEST softmodem_params.usim_test #define CHEST_FREQ softmodem_params.chest_freq #define CHEST_TIME softmodem_params.chest_time #define NFAPI softmodem_params.nfapi #define NSA softmodem_params.nsa #define NODE_NUMBER softmodem_params.node_number #define NON_STOP softmodem_params.non_stop -#define EMULATE_L1 softmodem_params.emulate_l1 #define CONTINUOUS_TX softmodem_params.continuous_tx #define SYNC_REF softmodem_params.sync_ref #define DEFAULT_PDU_ID softmodem_params.default_pdu_session_id @@ -156,7 +150,6 @@ extern int usrp_tx_thread; {"phy-test", CONFIG_HLP_PHYTST, PARAMFLAG_BOOL, .iptr=&PHY_TEST, .defintval=0, TYPE_INT, 0}, \ {"do-ra", CONFIG_HLP_DORA, PARAMFLAG_BOOL, .iptr=&DO_RA, .defintval=0, TYPE_INT, 0}, \ {"sl-mode", CONFIG_HLP_SL_MODE, 0, .u8ptr=&SL_MODE, .defintval=0, TYPE_UINT8, 0}, \ - {"usim-test", CONFIG_HLP_USIM, PARAMFLAG_BOOL, .u8ptr=&USIM_TEST, .defintval=0, TYPE_UINT8, 0}, \ {"clock-source", CONFIG_HLP_CLK, 0, .uptr=&CLOCK_SOURCE, .defintval=0, TYPE_UINT, 0}, \ {"time-source", CONFIG_HLP_TME, 0, .uptr=&TIMING_SOURCE, .defintval=0, TYPE_UINT, 0}, \ {"tune-offset", CONFIG_HLP_TUNE_OFFSET, 0, .dblptr=&TUNE_OFFSET, .defintval=0, TYPE_DOUBLE, 0}, \ @@ -167,7 +160,6 @@ extern int usrp_tx_thread; {"q" , CONFIG_HLP_STMON, PARAMFLAG_BOOL, .iptr=&cpu_meas_enabled, .defintval=0, TYPE_INT, 0}, \ {"numerology" , CONFIG_HLP_NUMEROLOGY, 0, .iptr=&NUMEROLOGY, .defintval=1, TYPE_INT, 0}, \ {"band" , CONFIG_HLP_BAND, 0, .iptr=&BAND, .defintval=78, TYPE_INT, 0}, \ - {"emulate-rf" , CONFIG_HLP_EMULATE_RF, PARAMFLAG_BOOL, .iptr=&EMULATE_RF, .defintval=0, TYPE_INT, 0}, \ {"parallel-config", CONFIG_HLP_PARALLEL_CMD, 0, .strptr=¶llel_config, .defstrval=NULL, TYPE_STRING, 0}, \ {"worker-config", CONFIG_HLP_WORKER_CMD, 0, .strptr=&worker_config, .defstrval=NULL, TYPE_STRING, 0}, \ {"noS1", CONFIG_HLP_NOS1, PARAMFLAG_BOOL, .uptr=&noS1, .defintval=0, TYPE_UINT, 0}, \ @@ -180,7 +172,6 @@ extern int usrp_tx_thread; {"usrp-tx-thread-config", CONFIG_HLP_USRP_THREAD, 0, .iptr=&usrp_tx_thread, .defstrval=0, TYPE_INT, 0}, \ {"nfapi", CONFIG_HLP_NFAPI, 0, .strptr=NULL, .defstrval="MONOLITHIC", TYPE_STRING, 0}, \ {"non-stop", CONFIG_HLP_NONSTOP, PARAMFLAG_BOOL, .iptr=&NON_STOP, .defintval=0, TYPE_INT, 0}, \ - {"emulate-l1", CONFIG_L1_EMULATOR, PARAMFLAG_BOOL, .iptr=&EMULATE_L1, .defintval=0, TYPE_INT, 0}, \ {"continuous-tx", CONFIG_HLP_CONTINUOUS_TX, PARAMFLAG_BOOL, .iptr=&CONTINUOUS_TX, .defintval=0, TYPE_INT, 0}, \ {"disable-stats", CONFIG_HLP_STATS_DISABLE, PARAMFLAG_BOOL, .iptr=&stats_disabled, .defintval=0, TYPE_INT, 0}, \ {"no-itti-threads", CONFIG_HLP_NOITTI, PARAMFLAG_BOOL, .iptr=&softmodem_params.no_itti, .defintval=0, TYPE_INT, 0}, \ @@ -189,7 +180,7 @@ extern int usrp_tx_thread; {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \ {"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \ {"imscope-record" , CONFIG_HLP_IMSCOPE_RECORD,PARAMFLAG_BOOL, .uptr=&enable_imscope_record, .defintval=0, TYPE_UINT, 0}, \ - {"default_pdu_id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=10, TYPE_INT, 0}, \ + {"default-pdu-id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=10, TYPE_INT, 0}, \ } // clang-format on @@ -220,8 +211,6 @@ extern int usrp_tx_thread; { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ - { .s5 = { NULL } }, \ - { .s5 = { NULL } }, \ { .s3a = { config_checkstr_assign_integer, \ {"MONOLITHIC", "PNF", "VNF", "AERIAL","UE_STUB_PNF","UE_STUB_OFFNET","STANDALONE_PNF"}, \ {NFAPI_MONOLITHIC, NFAPI_MODE_PNF, NFAPI_MODE_VNF, NFAPI_MODE_AERIAL,NFAPI_UE_STUB_PNF,NFAPI_UE_STUB_OFFNET,NFAPI_MODE_STANDALONE_PNF}, \ @@ -236,7 +225,6 @@ extern int usrp_tx_thread; { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ - { .s5 = { NULL } }, \ } // clang-format on @@ -324,8 +312,6 @@ typedef struct { int phy_test; int do_ra; uint8_t sl_mode; - uint8_t usim_test; - int emulate_rf; int chain_offset; int numerology; int band; @@ -341,12 +327,12 @@ typedef struct { int nsa; uint16_t node_number; int non_stop; - int emulate_l1; int continuous_tx; uint32_t sync_ref; int no_itti; int threequarter_fs; int default_pdu_session_id; + int extra_pdu_session_id; } softmodem_params_t; #define IS_SA_MODE(sM_params) (!(sM_params)->phy_test && !(sM_params)->do_ra && !(sM_params)->nsa) diff --git a/nfapi/CMakeLists.txt b/nfapi/CMakeLists.txt index d6c5b0e92a..6b9c75b5a8 100644 --- a/nfapi/CMakeLists.txt +++ b/nfapi/CMakeLists.txt @@ -1,3 +1,9 @@ add_subdirectory(oai_integration/aerial) +if (OAI_WLS) + add_subdirectory(oai_integration/wls_integration) +else () # Not WLS, means its SOCKET-based comms, maybe add a flag specific for UDP + message(STATUS "No Support for WLS") + add_subdirectory(oai_integration/socket) +endif () add_subdirectory(open-nFAPI) add_subdirectory(tests) diff --git a/nfapi/oai_integration/aerial/CMakeLists.txt b/nfapi/oai_integration/aerial/CMakeLists.txt index 74b1ad9fbf..2df4eb7ee0 100644 --- a/nfapi/oai_integration/aerial/CMakeLists.txt +++ b/nfapi/oai_integration/aerial/CMakeLists.txt @@ -3,7 +3,6 @@ if (OAI_AERIAL) add_library(aerial_lib fapi_nvIPC.c fapi_vnf_p7.c - fapi_vnf_p5.c ) find_library(NVIPC_LIB nvipc REQUIRED) diff --git a/nfapi/oai_integration/aerial/fapi_nvIPC.c b/nfapi/oai_integration/aerial/fapi_nvIPC.c index ed087204b0..b1bfae5415 100644 --- a/nfapi/oai_integration/aerial/fapi_nvIPC.c +++ b/nfapi/oai_integration/aerial/fapi_nvIPC.c @@ -48,12 +48,13 @@ #include #include #include "fapi_nvIPC.h" +#include +#include #include "nfapi_interface.h" #include "nfapi.h" #include "nfapi_nr_interface_scf.h" #include "nfapi/open-nFAPI/vnf/inc/vnf_p7.h" - -#include "fapi_vnf_p5.h" +#include "system.h" #include "fapi_vnf_p7.h" #define MAX_EVENTS 10 @@ -93,90 +94,12 @@ static int ipc_handle_rx_msg(nv_ipc_t *ipc, nv_ipc_msg_t *msg) return -1; } + vnf_p7_t *vnf_p7_config = (vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config; switch (fapi_msg.message_id) { - case NFAPI_NR_PHY_MSG_TYPE_PARAM_RESPONSE: - - if (vnf_config->nr_param_resp) { - nfapi_nr_param_response_scf_t msg_param_resp; - aerial_unpack_nr_param_response(&pReadPackedMessage, end, &msg_param_resp, &vnf_config->codec_config); - (vnf_config->nr_param_resp)(vnf_config, vnf_config->pnf_list->p5_idx, &msg_param_resp); - } + case NFAPI_NR_PHY_MSG_TYPE_PARAM_RESPONSE ... NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION: + vnf_nr_handle_p4_p5_message(msg->msg_buf, msg->msg_len, 1, vnf_config); break; - - case NFAPI_NR_PHY_MSG_TYPE_CONFIG_RESPONSE: { - // unpack message - nfapi_nr_config_response_scf_t msg_config_response; - aerial_unpack_nr_config_response(&pReadPackedMessage, end, &msg_config_response, &vnf_config->codec_config); - // Check the error code - if (msg_config_response.error_code == NFAPI_NR_CONFIG_MSG_OK) { - // Invoke the call back - if (vnf_config->nr_config_resp) { - (vnf_config->nr_config_resp)(vnf_config, vnf_config->pnf_list->p5_idx, &msg_config_response); - } - } else { - // Error code not OK (MSG_INVALID_CONFIG) - /* MSG_INVALID_CONFIG.response structure - * Error code uint8_t - * Number of invalid or unsupported TLVs uint8_t - * Number of invalid TLVs that can only be configured in IDLE state uint8_t - * Number of invalid TLVs that can only be configured in RUNNING state uint8_t - * Number of missing TLVs uint8_t - * List of invalid or unsupported TLVs - * List of invalid TLVs that can only be configured in IDLE state - * List of invalid TLVs that can only be configured in RUNNING state - * List of missing TLVs - * */ - } - break; - } - - case NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION: { - // TODO : ADD Support for NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION (0x06) - LOG_D(NFAPI_VNF,"Received NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION\n"); - break; - } - - case NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION: { - // TODO: Add Support for NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION (0x07) - LOG_D(NFAPI_VNF,"Received NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION\n"); - //for (int i = 0; i < msg->msg_len; i++) { - // printf(" msg->msg_buf[%d] = 0x%02x\n", i, ((uint8_t *) msg->msg_buf)[i]); - //} - LOG_D(NFAPI_VNF,"old sfn %u\n", old_sfn); - LOG_D(NFAPI_VNF,"old slot %u\n", old_slot); - - break; - } // P7 Messages - // P7 Message Handlers -> ((vnf_info *)vnf_config->user_data)->p7_vnfs->config-> - case NFAPI_NR_PHY_MSG_TYPE_SLOT_INDICATION: { - nfapi_nr_slot_indication_scf_t ind; - aerial_unpack_nr_slot_indication(&pReadPackedMessage, - end, - &ind, - &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); - // check if the sfn/slot unpacked come wrong at any time, should be old + 1 (slot 0 -- 19, sfn 0 -- 1023) - // add 1 to current sfn number - uint16_t old_slot_plus = ((old_slot + 1) % 20); - uint16_t old_sfn_plus = old_slot_plus == 0 ? ((old_sfn + 1) % 1024) : old_sfn; - if (old_slot_plus != ind.slot || old_sfn_plus != ind.sfn) { - LOG_E(NFAPI_VNF, - "\n============================================================================\n" - "sfn slot doesn't match unpacked one! L2->L1 %d.%d vs L1->L2 %d.%d \n" - "============================================================================\n", - old_sfn, - old_slot, - ind.sfn, - ind.slot); - } - old_sfn = ind.sfn; - old_slot = ind.slot; - if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_slot_indication) { - (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_slot_indication)(&ind); - } - break; - } - case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION: { uint8_t *pReadData = msg->data_buf; int dataBufLen = msg->data_len; @@ -190,10 +113,10 @@ static int ipc_handle_rx_msg(nv_ipc_t *ipc, nv_ipc_msg_t *msg) &pReadData, data_end, &ind, - &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); + &vnf_p7_config->_public.codec_config); NFAPI_TRACE(NFAPI_TRACE_INFO, "%s: Handling RX Indication\n", __FUNCTION__); - if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_rx_data_indication) { - (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_rx_data_indication)(&ind); + if (vnf_p7_config->_public.nr_rx_data_indication) { + (vnf_p7_config->_public.nr_rx_data_indication)(&ind); for (int i = 0; i < ind.number_of_pdus; ++i) { free(ind.pdu_list[i].pdu); } @@ -202,53 +125,6 @@ static int ipc_handle_rx_msg(nv_ipc_t *ipc, nv_ipc_msg_t *msg) break; } - case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION: { - nfapi_nr_crc_indication_t crc_ind; - crc_ind.header.message_id = fapi_msg.message_id; - crc_ind.header.message_length = fapi_msg.message_length; - aerial_unpack_nr_crc_indication(&pReadPackedMessage, - end, - &crc_ind, - &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); - if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_crc_indication) { - (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_crc_indication)(&crc_ind); - free(crc_ind.crc_list); - } - break; - } - - case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION: { - nfapi_nr_uci_indication_t ind; - aerial_unpack_nr_uci_indication(&pReadPackedMessage, - end, - &ind, - &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); - - if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_uci_indication) { - (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_uci_indication)(&ind); - for (int i = 0; i < ind.num_ucis; i++) { - if (ind.uci_list[i].pdu_type == NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE) { - if (ind.uci_list[i].pucch_pdu_format_2_3_4.sr.sr_payload) { - free(ind.uci_list[i].pucch_pdu_format_2_3_4.sr.sr_payload); - } - if(ind.uci_list[i].pucch_pdu_format_2_3_4.harq.harq_payload){ - free(ind.uci_list[i].pucch_pdu_format_2_3_4.harq.harq_payload); - } - if(ind.uci_list[i].pucch_pdu_format_2_3_4.csi_part1.csi_part1_payload){ - free(ind.uci_list[i].pucch_pdu_format_2_3_4.csi_part1.csi_part1_payload); - } - if(ind.uci_list[i].pucch_pdu_format_2_3_4.csi_part2.csi_part2_payload){ - free(ind.uci_list[i].pucch_pdu_format_2_3_4.csi_part2.csi_part2_payload); - } - } - } - free(ind.uci_list); - ind.uci_list = NULL; - } - - break; - } - case NFAPI_NR_PHY_MSG_TYPE_SRS_INDICATION: { uint8_t *pReadData = msg->data_buf; int dataBufLen = msg->data_len; @@ -259,26 +135,47 @@ static int ipc_handle_rx_msg(nv_ipc_t *ipc, nv_ipc_msg_t *msg) &pReadData, data_end, &ind, - &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); - if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_srs_indication) { - (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_srs_indication)(&ind); + &vnf_p7_config->_public.codec_config); + if (vnf_p7_config->_public.nr_srs_indication) { + (vnf_p7_config->_public.nr_srs_indication)(&ind); } break; } + case NFAPI_NR_PHY_MSG_TYPE_SLOT_INDICATION: { + nfapi_nr_slot_indication_scf_t ind; + if (!vnf_p7_config->_public.unpack_func(msg->msg_buf, msg->msg_len, &ind, sizeof(ind), &vnf_p7_config->_public.codec_config)) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); + } else { + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "%s: Handling NR SLOT Indication\n", __FUNCTION__); + // check if the sfn/slot unpacked come wrong at any time, should be old + 1 (slot 0 -- 19, sfn 0 -- 1023) + // add 1 to current sfn number + uint16_t old_slot_plus = ((old_slot + 1) % 20); + uint16_t old_sfn_plus = old_slot_plus == 0 ? ((old_sfn + 1) % 1024) : old_sfn; + if (old_slot_plus != ind.slot || old_sfn_plus != ind.sfn) { + LOG_E(NFAPI_VNF, + "\n============================================================================\n" + "sfn slot doesn't match unpacked one! L2->L1 %d.%d vs L1->L2 %d.%d \n" + "============================================================================\n", + old_sfn, + old_slot, + ind.sfn, + ind.slot); + } + old_sfn = ind.sfn; + old_slot = ind.slot; + if (vnf_p7_config->_public.nr_slot_indication) { + (vnf_p7_config->_public.nr_slot_indication)(&ind); + } + } + break; + } + case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION: case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: { - nfapi_nr_rach_indication_t ind; - aerial_unpack_nr_rach_indication(&pReadPackedMessage, - end, - &ind, - &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); - if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_rach_indication) { - (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_rach_indication)(&ind); - free(ind.pdu_list); - } + vnf_nr_handle_p7_message(msg->msg_buf, msg->msg_len, vnf_p7_config); break; } - default: { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s P5 Unknown message ID %d\n", __FUNCTION__, fapi_msg.message_id); @@ -293,10 +190,26 @@ int8_t buf[1024]; nv_ipc_config_t nv_ipc_config; -int aerial_send_P5_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p4_p5_message_header_t *header) +bool aerial_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) +{ + nfapi_vnf_pnf_info_t *pnf = nfapi_vnf_pnf_list_find(&(vnf->_public), p5_idx); + + if (pnf) { + uint8_t tx_messagebufferFAPI[sizeof(vnf->tx_message_buffer)]; + int packedMessageLengthFAPI = -1; + packedMessageLengthFAPI = + vnf->_public.pack_func(msg, msg_len, tx_messagebufferFAPI, sizeof(tx_messagebufferFAPI), &vnf->_public.codec_config); + return aerial_send_P5_msg(tx_messagebufferFAPI, packedMessageLengthFAPI, msg) == 0; + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find pnf info for p5_idx:%d\n", __FUNCTION__, p5_idx); + return false; + } +} + +bool aerial_send_P5_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p4_p5_message_header_t *header) { if (ipc == NULL) { - return -1; + return false; } nv_ipc_msg_t send_msg = {0}; // look for the specific message @@ -334,7 +247,7 @@ int aerial_send_P5_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p4_p5 if (alloc_retval != 0) { LOG_E(NFAPI_VNF, "%s error: allocate TX buffer failed Error: %d\n", __FUNCTION__, alloc_retval); ipc->tx_release(ipc, &send_msg); - return alloc_retval; + return false; } memcpy(send_msg.msg_buf, packedBuf, send_msg.msg_len); @@ -350,17 +263,17 @@ int aerial_send_P5_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p4_p5 if (send_retval < 0) { LOG_E(NFAPI_VNF, "%s error: send TX message failed Error: %d\n", __FUNCTION__, send_retval); ipc->tx_release(ipc, &send_msg); - return send_retval; + return false; } ipc->notify(ipc, 1); // notify that there's 1 message in queue - return 0; + return true; } -int aerial_send_P7_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p7_message_header_t *header) +bool aerial_send_P7_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p7_message_header_t *header) { if (ipc == NULL) { - return -1; + return false; } nv_ipc_msg_t send_msg; uint8_t *pPacketBodyField = &((uint8_t *)packedBuf)[8]; @@ -421,7 +334,7 @@ int aerial_send_P7_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p7_me if (alloc_retval != 0) { LOG_E(NFAPI_VNF, "%s error: allocate TX buffer failed Error: %d\n", __FUNCTION__, alloc_retval); ipc->tx_release(ipc, &send_msg); - return alloc_retval; + return false; } memcpy(send_msg.msg_buf, packedBuf, send_msg.msg_len); @@ -437,21 +350,21 @@ int aerial_send_P7_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p7_me if (send_retval < 0) { LOG_E(NFAPI_VNF, "%s error: send TX message failed Error: %d\n", __FUNCTION__, send_retval); ipc->tx_release(ipc, &send_msg); - return send_retval; + return false; } ipc->notify(ipc, 1); // notify that there's 1 message in queue - return 0; + return true; } -int aerial_send_P7_msg_with_data(void *packedBuf, +bool aerial_send_P7_msg_with_data(void *packedBuf, uint32_t packedMsgLength, void *dataBuf, uint32_t dataLength, nfapi_nr_p7_message_header_t *header) { if (ipc == NULL) { - return -1; + return false; } nv_ipc_msg_t send_msg; uint8_t *pPacketBodyField = &((uint8_t *)packedBuf)[8]; @@ -510,7 +423,7 @@ int aerial_send_P7_msg_with_data(void *packedBuf, if (alloc_retval != 0) { LOG_E(NFAPI_VNF, "%s error: allocate TX buffer failed Error: %d\n", __FUNCTION__, alloc_retval); ipc->tx_release(ipc, &send_msg); - return alloc_retval; + return false; } memcpy(send_msg.msg_buf, packedBuf, send_msg.msg_len); @@ -527,11 +440,11 @@ int aerial_send_P7_msg_with_data(void *packedBuf, if (send_retval != 0) { LOG_E(NFAPI_VNF, "%s error: send TX message failed Error: %d\n", __FUNCTION__, send_retval); ipc->tx_release(ipc, &send_msg); - return send_retval; + return false; } ipc->notify(ipc, 1); // notify that there's 1 message in queue - return 0; + return true; } // Always allocate message buffer, but allocate data buffer only when data_len > 0 @@ -656,6 +569,87 @@ int nvIPC_Init(nvipc_params_t nvipc_params_s) sleep(1); create_recv_thread(nvipc_params_s.nvipc_poll_core); while(!recv_task_running){usleep(100000);} - aerial_pnf_nr_connection_indication_cb(vnf_config, 1); + nfapi_nr_param_response_scf_t resp_msg; + vnf_config->nr_param_resp(vnf_config, 1, &resp_msg); return 0; } + +int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req) +{ + nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config); + + ul_tti_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + ul_tti_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST; + + // int retval = nfapi_vnf_p7_ul_tti_req(p7_config, ul_tti_req); + int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &ul_tti_req->header); + + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + // Reset number of PDUs so that it is not resent + ul_tti_req->n_pdus = 0; + ul_tti_req->n_group = 0; + ul_tti_req->n_ulcch = 0; + ul_tti_req->n_ulsch = 0; + } + return retval; +} + +int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req) +{ + nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config); + ul_dci_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + ul_dci_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST; + // int retval = nfapi_vnf_p7_ul_dci_req(p7_config, ul_dci_req); + int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &ul_dci_req->header); + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + ul_dci_req->numPdus = 0; + } + return retval; +} + +int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req) +{ + nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config); + tx_data_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + tx_data_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST; + // LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_data_req->SFN), + // tx_data_req->Number_of_PDUs); int retval = nfapi_vnf_p7_tx_data_req(p7_config, tx_data_req); + int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &tx_data_req->header); + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + tx_data_req->Number_of_PDUs = 0; + } + + return retval; +} + +int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) +{ + nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config); + dl_config_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST; + dl_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &dl_config_req->header); + dl_config_req->dl_tti_request_body.nPDUs = 0; + dl_config_req->dl_tti_request_body.nGroup = 0; + + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } + return retval; +} + +int oai_fapi_send_end_request(int cell, uint32_t frame, uint32_t slot){ + nfapi_vnf_p7_config_t *p7_config = (((vnf_info *)vnf_config->user_data)->p7_vnfs[0].config); + nfapi_nr_slot_indication_scf_t nr_slot_resp = {.header.message_id = 0x8F, .sfn = frame, .slot = slot}; + int retval = p7_config->send_p7_msg((vnf_p7_t *)p7_config, &nr_slot_resp.header); + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } + return retval; +} + diff --git a/nfapi/oai_integration/aerial/fapi_nvIPC.h b/nfapi/oai_integration/aerial/fapi_nvIPC.h index 5b8b995964..482d8103f0 100644 --- a/nfapi/oai_integration/aerial/fapi_nvIPC.h +++ b/nfapi/oai_integration/aerial/fapi_nvIPC.h @@ -36,6 +36,7 @@ #include "nv_ipc_utils.h" #include "nvlog.h" #include "nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h" +#include "vnf.h" #include "debug.h" #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" @@ -47,14 +48,19 @@ typedef struct { uint32_t message_length; } fapi_phy_api_msg; -int aerial_send_P5_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p4_p5_message_header_t *header); -int aerial_send_P7_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p7_message_header_t *header); -int aerial_send_P7_msg_with_data(void *packedBuf, +bool aerial_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len); +bool aerial_send_P5_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p4_p5_message_header_t *header); +bool aerial_send_P7_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_nr_p7_message_header_t *header); +bool aerial_send_P7_msg_with_data(void *packedBuf, uint32_t packedMsgLength, void *dataBuf, uint32_t dataLength, nfapi_nr_p7_message_header_t *header); void set_config(nfapi_vnf_config_t *conf); int nvIPC_Init(nvipc_params_t nvipc_params_s); - +int oai_fapi_send_end_request(int cell_id, uint32_t frame, uint32_t slot); +int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req); +int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req); +int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req); +int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req); #endif // OPENAIRINTERFACE_FAPI_NVIPC_H diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p5.c b/nfapi/oai_integration/aerial/fapi_vnf_p5.c deleted file mode 100644 index 1b01fd6c09..0000000000 --- a/nfapi/oai_integration/aerial/fapi_vnf_p5.c +++ /dev/null @@ -1,610 +0,0 @@ -/* -* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The OpenAirInterface Software Alliance licenses this file to You under -* the OAI Public License, Version 1.1 (the "License"); you may not use this file -* except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.openairinterface.org/?page_id=698 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*------------------------------------------------------------------------------- -* For more information about the OpenAirInterface (OAI) Software Alliance: -* contact@openairinterface.org - */ - -/*! \file fapi/oai-integration/fapi_vnf_p5.c -* \brief OAI FAPI VNF P5 message handler procedures -* \author Ruben S. Silva -* \date 2023 -* \version 0.1 -* \company OpenAirInterface Software Alliance -* \email: contact@openairinterface.org, rsilva@allbesmart.pt -* \note -* \warning - */ - -#include "fapi_vnf_p5.h" -#include "fapi_vnf_p7.h" -#include "nfapi/open-nFAPI/vnf/inc/vnf_p7.h" -#include "nr_fapi.h" -#include "nr_fapi_p5.h" - -extern RAN_CONTEXT_t RC; -extern UL_RCC_IND_t UL_RCC_INFO; -extern int sf_ahead; -extern int slot_ahead; - -void *aerial_vnf_nr_p7_config_init(void *ptr) -{ - vnf_p7_info *p7_vnf = (vnf_p7_info *)ptr; - - init_queue(&gnb_rach_ind_queue); - init_queue(&gnb_rx_ind_queue); - init_queue(&gnb_crc_ind_queue); - init_queue(&gnb_uci_ind_queue); - - p7_vnf->config->port = p7_vnf->local_port; - p7_vnf->config->sync_indication = NULL; - p7_vnf->config->slot_indication = NULL; - p7_vnf->config->harq_indication = NULL; - p7_vnf->config->nr_crc_indication = &aerial_phy_nr_crc_indication; - p7_vnf->config->nr_rx_data_indication = &aerial_phy_nr_rx_data_indication; - p7_vnf->config->nr_rach_indication = &aerial_phy_nr_rach_indication; - p7_vnf->config->nr_uci_indication = &aerial_phy_nr_uci_indication; - p7_vnf->config->srs_indication = NULL; - p7_vnf->config->sr_indication = NULL; - p7_vnf->config->cqi_indication = NULL; - p7_vnf->config->lbt_dl_indication = NULL; - p7_vnf->config->nb_harq_indication = NULL; - p7_vnf->config->nrach_indication = NULL; - p7_vnf->config->nr_slot_indication = &aerial_phy_nr_slot_indication; - p7_vnf->config->nr_srs_indication = &aerial_phy_nr_srs_indication; - p7_vnf->config->malloc = &aerial_vnf_allocate; - p7_vnf->config->free = &aerial_vnf_deallocate; - p7_vnf->config->vendor_ext = &aerial_phy_vendor_ext; - p7_vnf->config->user_data = p7_vnf; - p7_vnf->mac->user_data = p7_vnf; - p7_vnf->config->codec_config.unpack_p7_vendor_extension = &aerial_phy_unpack_p7_vendor_extension; - p7_vnf->config->codec_config.pack_p7_vendor_extension = &aerial_phy_pack_p7_vendor_extension; - p7_vnf->config->codec_config.unpack_vendor_extension_tlv = &aerial_phy_unpack_vendor_extension_tlv; - p7_vnf->config->codec_config.pack_vendor_extension_tlv = &aerial_phy_pack_vendor_extension_tlv; - p7_vnf->config->codec_config.allocate = &aerial_vnf_allocate; - p7_vnf->config->codec_config.deallocate = &aerial_vnf_deallocate; - p7_vnf->config->allocate_p7_vendor_ext = &aerial_phy_allocate_p7_vendor_ext; - p7_vnf->config->deallocate_p7_vendor_ext = &aerial_phy_deallocate_p7_vendor_ext; - - return 0; -} - - -int aerial_pnf_nr_connection_indication_cb(nfapi_vnf_config_t *config, int p5_idx) -{ - printf("[VNF] pnf connection indication idx:%d\n", p5_idx); - // in aerial, send first CONFIG.request, not PARAM.request - nfapi_nr_config_request_scf_t conf_req; - memset(&conf_req, 0, sizeof(conf_req)); - conf_req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_CONFIG_REQUEST; - printf("Try to send first CONFIG.request\n"); - aerial_nr_send_config_request(config, p5_idx); - return 0; -} - -int aerial_pnf_disconnection_indication_cb(nfapi_vnf_config_t *config, int p5_idx) -{ - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] pnf disconnection indication idx:%d\n", p5_idx); - vnf_info *vnf = (vnf_info *)(config->user_data); - pnf_info *pnf = vnf->pnfs; - phy_info *phy = pnf->phys; - vnf_p7_info *p7_vnf = vnf->p7_vnfs; - nfapi_vnf_p7_del_pnf((p7_vnf->config), phy->id); - return 0; -} - -int aerial_pnf_nr_param_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_param_response_t *resp) -{ - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] pnf param response idx:%d error:%d\n", p5_idx, resp->error_code); - vnf_info *vnf = (vnf_info *)(config->user_data); - pnf_info *pnf = vnf->pnfs; - - for (int i = 0; i < resp->pnf_phy.number_of_phys; ++i) { - phy_info phy; - memset(&phy, 0, sizeof(phy)); - phy.index = resp->pnf_phy.phy[i].phy_config_index; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) phy_config_idx:%d\n", i, resp->pnf_phy.phy[i].phy_config_index); - nfapi_vnf_allocate_phy(config, p5_idx, &(phy.id)); - - for (int j = 0; j < resp->pnf_phy.phy[i].number_of_rfs; ++j) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) (RF%d) %d\n", i, j, resp->pnf_phy.phy[i].rf_config[j].rf_config_index); - phy.rfs[0] = resp->pnf_phy.phy[i].rf_config[j].rf_config_index; - } - - pnf->phys[0] = phy; - } - nfapi_nr_pnf_config_request_t req; - memset(&req, 0, sizeof(req)); - req.header.message_id = NFAPI_PNF_CONFIG_REQUEST; - req.pnf_phy_rf_config.tl.tag = NFAPI_PNF_PHY_RF_TAG; - req.pnf_phy_rf_config.number_phy_rf_config_info = 2; // DJP pnf.phys.size(); - NFAPI_TRACE(NFAPI_TRACE_INFO, "DJP:Hard coded num phy rf to 2\n"); - - for (unsigned i = 0; i < 2; ++i) { - req.pnf_phy_rf_config.phy_rf_config[i].phy_id = pnf->phys[i].id; - req.pnf_phy_rf_config.phy_rf_config[i].phy_config_index = pnf->phys[i].index; - req.pnf_phy_rf_config.phy_rf_config[i].rf_config_index = pnf->phys[i].rfs[0]; - } - - nfapi_nr_vnf_pnf_config_req(config, p5_idx, &req); - return 0; -} - -int aerial_pnf_nr_config_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_config_response_t *resp) -{ - NFAPI_TRACE(NFAPI_TRACE_INFO, - "[VNF] pnf config response idx:%d resp[header[phy_id:%u message_id:%02x message_length:%u]]\n", - p5_idx, - resp->header.phy_id, - resp->header.message_id, - resp->header.message_length); - - if (1) { - nfapi_nr_pnf_start_request_t req; - memset(&req, 0, sizeof(req)); - req.header.phy_id = resp->header.phy_id; - req.header.message_id = NFAPI_PNF_START_REQUEST; - nfapi_nr_vnf_pnf_start_req(config, p5_idx, &req); - } else { - // Rather than send the pnf_start_request we will demonstrate - // sending a vendor extention message. The start request will be - // send when the vendor extension response is received - // vnf_info* vnf = (vnf_info*)(config->user_data); - vendor_ext_p5_req req; - memset(&req, 0, sizeof(req)); - req.header.message_id = P5_VENDOR_EXT_REQ; - req.dummy1 = 45; - req.dummy2 = 1977; - nfapi_vnf_vendor_extension(config, p5_idx, &req.header); - } - - return 0; -} - -int aerial_pnf_nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_start_response_t *resp) -{ - vnf_info *vnf = (vnf_info *)(config->user_data); - vnf_p7_info *p7_vnf = vnf->p7_vnfs; - pnf_info *pnf = vnf->pnfs; - nfapi_nr_param_request_scf_t req; - NFAPI_TRACE(NFAPI_TRACE_INFO, - "[VNF] pnf start response idx:%d config:%p user_data:%p p7_vnf[config:%p thread_started:%d]\n", - p5_idx, - config, - config->user_data, - vnf->p7_vnfs[0].config, - vnf->p7_vnfs[0].thread_started); - - aerial_vnf_nr_p7_config_init(p7_vnf); - - // start all the phys in the pnf. - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Sending NFAPI_VNF_PARAM_REQUEST phy_id:%d\n", pnf->phys[0].id); - memset(&req, 0, sizeof(req)); - req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST; - req.header.phy_id = pnf->phys[0].id; - nfapi_nr_vnf_param_req(config, p5_idx, &req); - return 0; -} - -int aerial_nr_param_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_param_response_scf_t *resp) -{ - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Received NFAPI_PARAM_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); - vnf_info *vnf = (vnf_info *)(config->user_data); - vnf_p7_info *p7_vnf = vnf->p7_vnfs; - pnf_info *pnf = vnf->pnfs; - phy_info *phy = pnf->phys; - struct sockaddr_in pnf_p7_sockaddr; - nfapi_nr_config_request_scf_t *req = &RC.nrmac[0]->config[0]; // check - phy->remote_port = resp->nfapi_config.p7_pnf_port.value; - // phy->remote_port = 32123;//resp->nfapi_config.p7_pnf_port.value; - memcpy(&pnf_p7_sockaddr.sin_addr.s_addr, &(resp->nfapi_config.p7_pnf_address_ipv4.address[0]), 4); - phy->remote_addr = inet_ntoa(pnf_p7_sockaddr.sin_addr); - // for now just 1 - NFAPI_TRACE(NFAPI_TRACE_INFO, - "[VNF] %d.%d pnf p7 %s:%d timing %u %u %u %u\n", - p5_idx, - phy->id, - phy->remote_addr, - phy->remote_port, - p7_vnf->timing_window, - p7_vnf->periodic_timing_period, - p7_vnf->aperiodic_timing_enabled, - p7_vnf->periodic_timing_period); - req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_CONFIG_REQUEST; - req->header.phy_id = phy->id; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Send NFAPI_CONFIG_REQUEST\n"); - // NFAPI_TRACE(NFAPI_TRACE_INFO, "\n NR bandP =%d\n",req->nfapi_config.rf_bands.rf_band[0]); - - req->nfapi_config.p7_vnf_port.tl.tag = NFAPI_NR_NFAPI_P7_VNF_PORT_TAG; - req->nfapi_config.p7_vnf_port.value = p7_vnf->local_port; - req->num_tlv++; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] DJP local_port:%d\n", ntohs(p7_vnf->local_port)); - req->nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; - struct sockaddr_in vnf_p7_sockaddr; - vnf_p7_sockaddr.sin_addr.s_addr = inet_addr(p7_vnf->local_addr); - memcpy(&(req->nfapi_config.p7_vnf_address_ipv4.address[0]), &vnf_p7_sockaddr.sin_addr.s_addr, 4); - req->num_tlv++; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] DJP local_addr:%s\n", p7_vnf->local_addr); - req->nfapi_config.timing_window.tl.tag = NFAPI_NR_NFAPI_TIMING_WINDOW_TAG; - req->nfapi_config.timing_window.value = p7_vnf->timing_window; - NFAPI_TRACE(NFAPI_TRACE_INFO, - "\n[VNF]Timing window tag : %d Timing window:%u\n", - NFAPI_NR_NFAPI_TIMING_WINDOW_TAG, - p7_vnf->timing_window); - req->num_tlv++; - - if (p7_vnf->periodic_timing_enabled || p7_vnf->aperiodic_timing_enabled) { - req->nfapi_config.timing_info_mode.tl.tag = NFAPI_NR_NFAPI_TIMING_INFO_MODE_TAG; - req->nfapi_config.timing_info_mode.value = (p7_vnf->aperiodic_timing_enabled << 1) | (p7_vnf->periodic_timing_enabled); - req->num_tlv++; - - if (p7_vnf->periodic_timing_enabled) { - req->nfapi_config.timing_info_period.tl.tag = NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG; - req->nfapi_config.timing_info_period.value = p7_vnf->periodic_timing_period; - req->num_tlv++; - } - } - // TODO: Assign tag and value for P7 message offsets - req->nfapi_config.dl_tti_timing_offset.tl.tag = NFAPI_NR_NFAPI_DL_TTI_TIMING_OFFSET; - req->nfapi_config.ul_tti_timing_offset.tl.tag = NFAPI_NR_NFAPI_UL_TTI_TIMING_OFFSET; - req->nfapi_config.ul_dci_timing_offset.tl.tag = NFAPI_NR_NFAPI_UL_DCI_TIMING_OFFSET; - req->nfapi_config.tx_data_timing_offset.tl.tag = NFAPI_NR_NFAPI_TX_DATA_TIMING_OFFSET; - - vendor_ext_tlv_2 ve2; - memset(&ve2, 0, sizeof(ve2)); - ve2.tl.tag = VENDOR_EXT_TLV_2_TAG; - ve2.dummy = 2016; - req->vendor_extension = &ve2.tl; - nfapi_nr_vnf_config_req(config, p5_idx, req); - printf("[VNF] Sent NFAPI_VNF_CONFIG_REQ num_tlv:%u\n", req->num_tlv); - return 0; -} - -int aerial_nr_send_config_request(nfapi_vnf_config_t *config, int p5_idx) -{ - vnf_info *vnf = (vnf_info *)(config->user_data); - vnf_p7_info *p7_vnf = vnf->p7_vnfs; - pnf_info *pnf = vnf->pnfs; - phy_info *phy = pnf->phys; - - nfapi_nr_config_request_scf_t *req = &RC.nrmac[0]->config[0]; - - NFAPI_TRACE(NFAPI_TRACE_INFO, - "[VNF] %d.%d pnf p7 %s:%d timing %u %u %u %u\n", - p5_idx, - phy->id, - phy->remote_addr, - phy->remote_port, - p7_vnf->timing_window, - p7_vnf->periodic_timing_period, - p7_vnf->aperiodic_timing_enabled, - p7_vnf->periodic_timing_period); - req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_CONFIG_REQUEST; - req->header.phy_id = phy->id; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Send NFAPI_CONFIG_REQUEST\n"); - - vnf_t *_this = (vnf_t *)(config); - - nfapi_vnf_phy_info_t *vnf_phy = nfapi_vnf_phy_info_list_find(config, req->header.phy_id); - - if (vnf_phy == NULL) { - printf("%s failed to find phy information phy_id:%d\n", __FUNCTION__, req->header.phy_id); - return -1; - } - - nfapi_nr_p4_p5_message_header_t *msg = &req->header; - uint16_t msg_len = sizeof(nfapi_nr_config_request_scf_t); - uint8_t tx_messagebufferFAPI[sizeof(_this->tx_message_buffer)]; - int packedMessageLengthFAPI = -1; - packedMessageLengthFAPI = - fapi_nr_p5_message_pack(msg, msg_len, tx_messagebufferFAPI, sizeof(tx_messagebufferFAPI), &_this->_public.codec_config); - - aerial_send_P5_msg(tx_messagebufferFAPI, packedMessageLengthFAPI, msg); - - return 0; -} - -int aerial_nr_config_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_config_response_scf_t *resp) -{ - nfapi_nr_start_request_scf_t req; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Received NFAPI_CONFIG_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); - LOG_I(NFAPI_VNF, "Received CONFIG.response, gNB is ready! \n"); - - memset(&req, 0, sizeof(req)); - req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_START_REQUEST; - req.header.phy_id = resp->header.phy_id; - nfapi_nr_vnf_start_req(config, p5_idx, &req); - return 0; -} - -int aerial_nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_start_response_scf_t *resp) -{ - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Received NFAPI_START_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); - return 0; -} - -int aerial_vendor_ext_cb(nfapi_vnf_config_t *config, int p5_idx, void *msg) -{ - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %s\n", __FUNCTION__); - - switch (((nfapi_nr_p4_p5_message_header_t *)msg)->message_id) { - case P5_VENDOR_EXT_RSP: { - vendor_ext_p5_rsp *rsp = (vendor_ext_p5_rsp *)msg; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] P5_VENDOR_EXT_RSP error_code:%d\n", rsp->error_code); - // send the start request - nfapi_nr_pnf_start_request_t req; - memset(&req, 0, sizeof(req)); - req.header.message_id = NFAPI_PNF_START_REQUEST; - nfapi_nr_vnf_pnf_start_req(config, p5_idx, &req); - } break; - } - - return 0; -} - -int aerial_vnf_unpack_vendor_extension_tlv(nfapi_tl_t *tl, - uint8_t **ppReadPackedMessage, - uint8_t *end, - void **ve, - nfapi_p4_p5_codec_config_t *codec) -{ - return -1; -} - -int aerial_vnf_pack_vendor_extension_tlv(void *vext, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *codec) -{ - nfapi_tl_t *tlv = (nfapi_tl_t *)vext; - - switch (tlv->tag) { - case VENDOR_EXT_TLV_2_TAG: { - vendor_ext_tlv_2 *ve = (vendor_ext_tlv_2 *)tlv; - - if (!push32(ve->dummy, ppWritePackedMsg, end)) - return 0; - - return 1; - } break; - } - - return -1; -} - -int aerial_vnf_unpack_p4_p5_vendor_extension(void *header, - uint8_t **ppReadPackedMessage, - uint8_t *end, - nfapi_p4_p5_codec_config_t *codec) -{ - if (((nfapi_nr_p4_p5_message_header_t *)header)->message_id == P5_VENDOR_EXT_RSP) { - vendor_ext_p5_rsp *req = (vendor_ext_p5_rsp *)(header); - return (!pull16(ppReadPackedMessage, &req->error_code, end)); - } - - return 0; -} - -int aerial_vnf_pack_p4_p5_vendor_extension(void *header, - uint8_t **ppWritePackedMsg, - uint8_t *end, - nfapi_p4_p5_codec_config_t *codec) -{ - if (((nfapi_nr_p4_p5_message_header_t *)header)->message_id == P5_VENDOR_EXT_REQ) { - vendor_ext_p5_req *req = (vendor_ext_p5_req *)(header); - return (!(push16(req->dummy1, ppWritePackedMsg, end) && push16(req->dummy2, ppWritePackedMsg, end))); - } - - return 0; -} - -void *aerial_vnf_allocate_p4_p5_vendor_ext(uint16_t message_id, uint16_t *msg_size) -{ - if (message_id == P5_VENDOR_EXT_RSP) { - *msg_size = sizeof(vendor_ext_p5_rsp); - return malloc(sizeof(vendor_ext_p5_rsp)); - } - - return 0; -} - -void aerial_vnf_deallocate_p4_p5_vendor_ext(void *header) -{ - free(header); -} - -void *aerial_vnf_p5_allocate(size_t size) -{ - // return (void*)memory_pool::allocate(size); - return (void *)malloc(size); -} - -void aerial_vnf_p5_deallocate(void *ptr) -{ - // memory_pool::deallocate((uint8_t*)ptr); - free(ptr); -} - -static vnf_info aerial_vnf; -void aerial_configure_nr_fapi_vnf() -{ - // TODO: Implement for FAPI - // nfapi_setmode(NFAPI_MODE_VNF); - memset(&aerial_vnf, 0, sizeof(aerial_vnf)); - memset(aerial_vnf.p7_vnfs, 0, sizeof(aerial_vnf.p7_vnfs)); - aerial_vnf.p7_vnfs[0].timing_window = 30; - aerial_vnf.p7_vnfs[0].periodic_timing_enabled = 0; - aerial_vnf.p7_vnfs[0].aperiodic_timing_enabled = 0; - aerial_vnf.p7_vnfs[0].periodic_timing_period = 10; - aerial_vnf.p7_vnfs[0].config = nfapi_vnf_p7_config_create(); - aerial_vnf.p7_vnfs[0].mac = (mac_t *)malloc(sizeof(mac_t)); - nfapi_vnf_config_t *config = nfapi_vnf_config_create(); - config->malloc = malloc; - config->free = free; - config->vnf_ipv4 = 1; - config->vnf_ipv6 = 0; - config->pnf_list = 0; - config->phy_list = 0; - - config->pnf_nr_connection_indication = &aerial_pnf_nr_connection_indication_cb; - config->pnf_disconnect_indication = &aerial_pnf_disconnection_indication_cb; - - config->pnf_nr_param_resp = &aerial_pnf_nr_param_resp_cb; - config->pnf_nr_config_resp = &aerial_pnf_nr_config_resp_cb; - config->pnf_nr_start_resp = &aerial_pnf_nr_start_resp_cb; - config->nr_param_resp = &aerial_nr_param_resp_cb; - config->nr_config_resp = &aerial_nr_config_resp_cb; - config->nr_start_resp = &aerial_nr_start_resp_cb; - config->vendor_ext = &aerial_vendor_ext_cb; - config->user_data = &aerial_vnf; - // To allow custom vendor extentions to be added to nfapi - config->codec_config.unpack_vendor_extension_tlv = &aerial_vnf_unpack_vendor_extension_tlv; - config->codec_config.pack_vendor_extension_tlv = &aerial_vnf_pack_vendor_extension_tlv; - config->codec_config.unpack_p4_p5_vendor_extension = &aerial_vnf_unpack_p4_p5_vendor_extension; - config->codec_config.pack_p4_p5_vendor_extension = &aerial_vnf_pack_p4_p5_vendor_extension; - config->allocate_p4_p5_vendor_ext = &aerial_vnf_allocate_p4_p5_vendor_ext; - config->deallocate_p4_p5_vendor_ext = &aerial_vnf_deallocate_p4_p5_vendor_ext; - config->codec_config.allocate = &aerial_vnf_allocate; - config->codec_config.deallocate = &aerial_vnf_deallocate; - memset(&UL_RCC_INFO, 0, sizeof(UL_RCC_IND_t)); - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); - set_config(config); - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Created VNF NFAPI start thread %s\n", __FUNCTION__); - nfapi_vnf_pnf_info_t *pnf = (nfapi_vnf_pnf_info_t *)malloc(sizeof(nfapi_vnf_pnf_info_t)); - NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf); - memset(pnf, 0, sizeof(nfapi_vnf_pnf_info_t)); - pnf->p5_idx = 1; - pnf->connected = 1; - // Add needed parameters - - vnf_info *vnf = (vnf_info *)(config->user_data); - pnf_info *pnf_info = vnf->pnfs; - - for (int i = 0; i < 1; ++i) { - phy_info phy; - memset(&phy, 0, sizeof(phy)); - phy.index = 0; - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) phy_config_idx:%d\n", i, 0); - nfapi_vnf_allocate_phy(config, 1, &(phy.id)); - - for (int j = 0; j < 1; ++j) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) (RF%d) %d\n", i, j, 0); - phy.rfs[0] = 0; - } - - pnf_info->phys[0] = phy; - } - - - nfapi_vnf_pnf_list_add(config, pnf); - - vnf_p7_info *p7_vnf = vnf->p7_vnfs; - - NFAPI_TRACE(NFAPI_TRACE_INFO, - "[VNF] pnf start response idx:%d config:%p user_data:%p p7_vnf[config:%p thread_started:%d]\n", - 1, - config, - config->user_data, - vnf->p7_vnfs[0].config, - vnf->p7_vnfs[0].thread_started); - - aerial_vnf_nr_p7_config_init(p7_vnf); -} -uint8_t aerial_unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config) -{ - return unpack_nr_param_response(ppReadPackedMsg, end, msg, config); -} -uint8_t aerial_unpack_nr_config_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config) -{ - return unpack_nr_config_response(ppReadPackedMsg, end, msg, config); -} - -int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req) -{ - nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; - - ul_tti_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! - ul_tti_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST; - - // int retval = nfapi_vnf_p7_ul_tti_req(p7_config, ul_tti_req); - int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &ul_tti_req->header); - - if (retval != 0) { - LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); - } else { - // Reset number of PDUs so that it is not resent - ul_tti_req->n_pdus = 0; - ul_tti_req->n_group = 0; - ul_tti_req->n_ulcch = 0; - ul_tti_req->n_ulsch = 0; - } - return retval; -} - -int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req) -{ - nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; - ul_dci_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! - ul_dci_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST; - // int retval = nfapi_vnf_p7_ul_dci_req(p7_config, ul_dci_req); - int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &ul_dci_req->header); - if (retval != 0) { - LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); - } else { - ul_dci_req->numPdus = 0; - } - return retval; -} - -int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req) -{ - nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; - tx_data_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! - tx_data_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST; - // LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_data_req->SFN), - // tx_data_req->Number_of_PDUs); int retval = nfapi_vnf_p7_tx_data_req(p7_config, tx_data_req); - int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &tx_data_req->header); - if (retval != 0) { - LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); - } else { - tx_data_req->Number_of_PDUs = 0; - } - - return retval; -} - -int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) -{ - nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; - dl_config_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST; - dl_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! - int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &dl_config_req->header); - dl_config_req->dl_tti_request_body.nPDUs = 0; - dl_config_req->dl_tti_request_body.nGroup = 0; - - if (retval != 0) { - LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); - } - return retval; -} - -int oai_fapi_send_end_request(int cell, uint32_t frame, uint32_t slot){ - nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; - nfapi_nr_slot_indication_scf_t nr_slot_resp = {.header.message_id = 0x8F, .sfn = frame, .slot = slot}; - int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &nr_slot_resp.header); - if (retval != 0) { - LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); - } - return retval; -} diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p5.h b/nfapi/oai_integration/aerial/fapi_vnf_p5.h deleted file mode 100644 index 84fb3ec2f8..0000000000 --- a/nfapi/oai_integration/aerial/fapi_vnf_p5.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -* contributor license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright ownership. -* The OpenAirInterface Software Alliance licenses this file to You under -* the OAI Public License, Version 1.1 (the "License"); you may not use this file -* except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.openairinterface.org/?page_id=698 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*------------------------------------------------------------------------------- -* For more information about the OpenAirInterface (OAI) Software Alliance: -* contact@openairinterface.org - */ - -/*! \file fapi/oai-integration/fapi_vnf_p5.h -* \brief Header file for fapi_vnf_p5.c -* \author Ruben S. Silva -* \date 2023 -* \version 0.1 -* \company OpenAirInterface Software Alliance -* \email: contact@openairinterface.org, rsilva@allbesmart.pt -* \note -* \warning - */ - -#ifndef OPENAIRINTERFACE_FAPI_VNF_P5_H -#define OPENAIRINTERFACE_FAPI_VNF_P5_H -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nfapi_nr_interface_scf.h" -#include "nfapi_vnf_interface.h" -#include "nfapi_vnf.h" -#include "nfapi.h" -#include "nfapi/oai_integration/vendor_ext.h" -#include "fapi_nvIPC.h" - -#include "PHY/defs_eNB.h" -#include "PHY/LTE_TRANSPORT/transport_proto.h" - -#include "common/ran_context.h" -#include "openair2/PHY_INTERFACE/queue_t.h" -#include "gnb_ind_vars.h" -#include "nfapi/open-nFAPI/vnf/inc/vnf.h" - -void aerial_configure_nr_fapi_vnf(); -int aerial_nr_send_config_request(nfapi_vnf_config_t *config, int p5_idx); -int oai_fapi_send_end_request(int cell_id, uint32_t frame, uint32_t slot); -uint8_t aerial_unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config); -uint8_t aerial_unpack_nr_config_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config); -int aerial_pnf_nr_connection_indication_cb(nfapi_vnf_config_t *config, int p5_idx); - -int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req); -int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req); -int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req); -int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req); -#endif //OPENAIRINTERFACE_FAPI_VNF_P5_H diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p7.c b/nfapi/oai_integration/aerial/fapi_vnf_p7.c index cb8fa4550f..d9e3e0027b 100644 --- a/nfapi/oai_integration/aerial/fapi_vnf_p7.c +++ b/nfapi/oai_integration/aerial/fapi_vnf_p7.c @@ -35,200 +35,6 @@ #include "nr_fapi_p7.h" #include "nr_fapi_p7_utils.h" -#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" // for handle_nr_srs_measurements() - -extern pthread_cond_t nfapi_sync_cond; -extern pthread_mutex_t nfapi_sync_mutex; -extern int nfapi_sync_var; - -int aerial_phy_nr_crc_indication(nfapi_nr_crc_indication_t *ind) -{ - nfapi_nr_crc_indication_t *crc_ind = CALLOC(1, sizeof(*crc_ind)); - copy_crc_indication(ind, crc_ind); - if (!put_queue(&gnb_crc_ind_queue, crc_ind)) { - LOG_E(NR_MAC, "Put_queue failed for crc_ind\n"); - free_crc_indication(crc_ind); - free(crc_ind); - } - return 1; -} - -int aerial_phy_nr_rx_data_indication(nfapi_nr_rx_data_indication_t *ind) -{ - nfapi_nr_rx_data_indication_t *rx_ind = CALLOC(1, sizeof(*rx_ind)); - copy_rx_data_indication(ind, rx_ind); - if (!put_queue(&gnb_rx_ind_queue, rx_ind)) { - LOG_E(NR_MAC, "Put_queue failed for rx_ind\n"); - free_rx_data_indication(rx_ind); - free(rx_ind); - } - return 1; -} - -int aerial_phy_nr_rach_indication(nfapi_nr_rach_indication_t *ind) -{ - nfapi_nr_rach_indication_t *rach_ind = CALLOC(1, sizeof(*rach_ind)); - copy_rach_indication(ind, rach_ind); - if (!put_queue(&gnb_rach_ind_queue, rach_ind)) { - LOG_E(NR_MAC, "Put_queue failed for rach_ind\n"); - free_rach_indication(rach_ind); - free(rach_ind); - } else { - LOG_I(NR_MAC, "RACH.indication put_queue successfull\n"); - } - return 1; -} - -int aerial_phy_nr_uci_indication(nfapi_nr_uci_indication_t *ind) -{ - nfapi_nr_uci_indication_t *uci_ind = CALLOC(1, sizeof(*uci_ind)); - AssertFatal(uci_ind, "Memory not allocated for uci_ind in phy_nr_uci_indication."); - copy_uci_indication(ind, uci_ind); - if (!put_queue(&gnb_uci_ind_queue, uci_ind)) { - LOG_E(NR_MAC, "Put_queue failed for uci_ind\n"); - free_uci_indication(uci_ind); - free(uci_ind); - uci_ind = NULL; - } - return 1; -} - -void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slot, NR_Sched_Rsp_t* sched_info); -int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req); -int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req); -int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t* tx_data_req); -int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t* ul_dci_req); -int oai_fapi_send_end_request(int cell, uint32_t frame, uint32_t slot); -extern int trigger_scheduler(nfapi_nr_slot_indication_scf_t *slot_ind); - -int aerial_phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind) -{ - LOG_D(MAC, "VNF SFN/Slot %d.%d \n", ind->sfn, ind->slot); - trigger_scheduler(ind); - - return 1; -} - -int aerial_phy_nr_srs_indication(nfapi_nr_srs_indication_t *ind) -{ - // or queue to decouple, but I think it should be fast (in all likelihood, - // the VNF has nothing to do) - for (int i = 0; i < ind->number_of_pdus; ++i) - handle_nr_srs_measurements(0, ind->sfn, ind->slot, &ind->pdu_list[i]); - return 1; -} - -void *aerial_vnf_allocate(size_t size) -{ - // return (void*)memory_pool::allocate(size); - return (void *)malloc(size); -} - -void aerial_vnf_deallocate(void *ptr) -{ - // memory_pool::deallocate((uint8_t*)ptr); - free(ptr); -} - -int aerial_phy_vendor_ext(struct nfapi_vnf_p7_config *config, void *msg) -{ - if (((nfapi_nr_p7_message_header_t *)msg)->message_id == P7_VENDOR_EXT_IND) { - // vendor_ext_p7_ind* ind = (vendor_ext_p7_ind*)msg; - // NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] vendor_ext (error_code:%d)\n", ind->error_code); - } else { - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] unknown %02x\n", ((nfapi_nr_p7_message_header_t *)msg)->message_id); - } - - return 0; -} - -int aerial_phy_unpack_p7_vendor_extension(void *header, - uint8_t **ppReadPackedMessage, - uint8_t *end, - nfapi_p7_codec_config_t *config) -{ - // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); - if (((nfapi_nr_p7_message_header_t *)header)->message_id == P7_VENDOR_EXT_IND) { - vendor_ext_p7_ind *req = (vendor_ext_p7_ind *)(header); - - if (!pull16(ppReadPackedMessage, &req->error_code, end)) - return 0; - } - - return 1; -} - -int aerial_phy_pack_p7_vendor_extension(void *header, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *config) -{ - // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); - if (((nfapi_nr_p7_message_header_t *)header)->message_id == P7_VENDOR_EXT_REQ) { - // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); - vendor_ext_p7_req *req = (vendor_ext_p7_req *)(header); - - if (!(push16(req->dummy1, ppWritePackedMsg, end) && push16(req->dummy2, ppWritePackedMsg, end))) - return 0; - } - - return 1; -} - -int aerial_phy_unpack_vendor_extension_tlv(nfapi_tl_t *tl, - uint8_t **ppReadPackedMessage, - uint8_t *end, - void **ve, - nfapi_p7_codec_config_t *codec) -{ - (void)tl; - (void)ppReadPackedMessage; - (void)ve; - return -1; -} - -int aerial_phy_pack_vendor_extension_tlv(void *ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *codec) -{ - // NFAPI_TRACE(NFAPI_TRACE_INFO, "phy_pack_vendor_extension_tlv\n"); - nfapi_tl_t *tlv = (nfapi_tl_t *)ve; - - switch (tlv->tag) { - case VENDOR_EXT_TLV_1_TAG: { - // NFAPI_TRACE(NFAPI_TRACE_INFO, "Packing VENDOR_EXT_TLV_1\n"); - vendor_ext_tlv_1 *ve = (vendor_ext_tlv_1 *)tlv; - - if (!push32(ve->dummy, ppWritePackedMsg, end)) - return 0; - - return 1; - } break; - - default: - return -1; - break; - } -} - -void *aerial_phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t *msg_size) -{ - if (message_id == P7_VENDOR_EXT_IND) { - *msg_size = sizeof(vendor_ext_p7_ind); - return (nfapi_nr_p7_message_header_t *)malloc(sizeof(vendor_ext_p7_ind)); - } - - return 0; -} - -void aerial_phy_deallocate_p7_vendor_ext(void *header) -{ - free(header); -} - -uint8_t aerial_unpack_nr_slot_indication(uint8_t **ppReadPackedMsg, - uint8_t *end, - nfapi_nr_slot_indication_scf_t *msg, - nfapi_p7_codec_config_t *config) -{ - return unpack_nr_slot_indication(ppReadPackedMsg, end, msg, config); -} - static uint8_t aerial_unpack_nr_rx_data_indication_body(nfapi_nr_rx_data_pdu_t *value, uint8_t **ppReadPackedMsg, uint8_t *end, @@ -247,6 +53,7 @@ static uint8_t aerial_unpack_nr_rx_data_indication_body(nfapi_nr_rx_data_pdu_t * return 1; } + uint8_t aerial_unpack_nr_rx_data_indication(uint8_t **ppReadPackedMsg, uint8_t *end, uint8_t **pDataMsg, @@ -273,11 +80,11 @@ uint8_t aerial_unpack_nr_rx_data_indication(uint8_t **ppReadPackedMsg, } // After unpacking the PDU headers, unpack the PDU data from the separate buffer for (int i = 0; i < pNfapiMsg->number_of_pdus; i++) { - if(!pullarray8(pDataMsg, - pNfapiMsg->pdu_list[i].pdu, - pNfapiMsg->pdu_list[i].pdu_length, - pNfapiMsg->pdu_list[i].pdu_length, - data_end)){ + if (!pullarray8(pDataMsg, + pNfapiMsg->pdu_list[i].pdu, + pNfapiMsg->pdu_list[i].pdu_length, + pNfapiMsg->pdu_list[i].pdu_length, + data_end)) { return 0; } } @@ -285,19 +92,6 @@ uint8_t aerial_unpack_nr_rx_data_indication(uint8_t **ppReadPackedMsg, return 1; } -uint8_t aerial_unpack_nr_crc_indication(uint8_t **ppReadPackedMsg, - uint8_t *end, - nfapi_nr_crc_indication_t *msg, - nfapi_p7_codec_config_t *config) -{ - return unpack_nr_crc_indication(ppReadPackedMsg, end, msg, config); -} - -uint8_t aerial_unpack_nr_uci_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config) -{ - return unpack_nr_uci_indication(ppReadPackedMsg, end, msg, config); -} - uint8_t aerial_unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, uint8_t **pDataMsg, @@ -316,20 +110,13 @@ uint8_t aerial_unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, return retval; } -uint8_t aerial_unpack_nr_rach_indication(uint8_t **ppReadPackedMsg, - uint8_t *end, - nfapi_nr_rach_indication_t *msg, - nfapi_p7_codec_config_t *config) -{ - return unpack_nr_rach_indication(ppReadPackedMsg, end, msg, config); -} - static int32_t aerial_pack_tx_data_request(void *pMessageBuf, void *pPackedBuf, void *pDataBuf, uint32_t packedBufLen, uint32_t dataBufLen, nfapi_p7_codec_config_t *config, + nfapi_vnf_p7_config_t *p7_config, uint32_t *data_len) { if (pMessageBuf == NULL || pPackedBuf == NULL) { @@ -386,16 +173,15 @@ static int32_t aerial_pack_tx_data_request(void *pMessageBuf, uintptr_t dataEnd = (uintptr_t)pPackedDataField; data_len[0] = dataEnd - dataHead; - - if (!fapi_nr_p7_message_pack(pMessageBuf, pPackedBuf, packedBufLen, config)) { - return -1; - } + if (!p7_config->pack_func(pMessageBuf, pPackedBuf, packedBufLen, config)) { + return -1; + } return (int32_t)(pMessageHeader->message_length); } -int fapi_nr_pack_and_send_p7_message(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *header) +bool aerial_nr_send_p7_message(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *header) { uint8_t FAPI_buffer[1024 * 64]; // Check if TX_DATA request, if true, need to pack to data_buf @@ -414,17 +200,20 @@ int fapi_nr_pack_and_send_p7_message(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_heade sizeof(FAPI_buffer), sizeof(FAPI_data_buffer), &vnf_p7->_public.codec_config, + ((nfapi_vnf_p7_config_t *)vnf_p7), &data_len); if (len_FAPI <= 0) { LOG_E(NFAPI_VNF, "Problem packing TX_DATA_request\n"); - return len_FAPI; + return false; } else { - int retval = aerial_send_P7_msg_with_data(FAPI_buffer, len_FAPI, FAPI_data_buffer, data_len, header); - return retval; + return aerial_send_P7_msg_with_data(FAPI_buffer, len_FAPI, FAPI_data_buffer, data_len, header) == 0; } } else { // Create and send FAPI P7 message - int len_FAPI = fapi_nr_p7_message_pack(header, FAPI_buffer, sizeof(FAPI_buffer), &vnf_p7->_public.codec_config); - return aerial_send_P7_msg(FAPI_buffer, len_FAPI, header); + int len_FAPI = ((nfapi_vnf_p7_config_t *)vnf_p7)->pack_func(header, + FAPI_buffer, + sizeof(FAPI_buffer), + &vnf_p7->_public.codec_config); + return aerial_send_P7_msg(FAPI_buffer, len_FAPI, header) == 0; } } diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p7.h b/nfapi/oai_integration/aerial/fapi_vnf_p7.h index ca75b02276..3722411578 100644 --- a/nfapi/oai_integration/aerial/fapi_vnf_p7.h +++ b/nfapi/oai_integration/aerial/fapi_vnf_p7.h @@ -47,187 +47,21 @@ #include "nfapi_interface.h" #include "nfapi_nr_interface_scf.h" #include "nfapi_vnf_interface.h" -#include "nfapi_vnf.h" -#include "nfapi.h" -#include "nfapi/oai_integration/vendor_ext.h" #include "fapi_nvIPC.h" - -#include "PHY/defs_eNB.h" -#include "PHY/LTE_TRANSPORT/transport_proto.h" -#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" -#include "lte-softmodem.h" - -#include "common/ran_context.h" #include "openair2/PHY_INTERFACE/queue_t.h" -#include "gnb_ind_vars.h" -#include "nfapi/open-nFAPI/vnf/inc/vnf.h" #include "nfapi/open-nFAPI/vnf/inc/vnf_p7.h" -typedef struct { - uint8_t enabled; - uint32_t rx_port; - uint32_t tx_port; - char tx_addr[80]; -} udp_data; - -typedef struct { - uint16_t index; - uint16_t id; - uint8_t rfs[2]; - uint8_t excluded_rfs[2]; - - udp_data udp; - - char local_addr[80]; - int local_port; - - char *remote_addr; - int remote_port; - - uint8_t duplex_mode; - uint16_t dl_channel_bw_support; - uint16_t ul_channel_bw_support; - uint8_t num_dl_layers_supported; - uint8_t num_ul_layers_supported; - uint16_t release_supported; - uint8_t nmm_modes_supported; - - uint8_t dl_ues_per_subframe; - uint8_t ul_ues_per_subframe; - - uint8_t first_subframe_ind; - - // timing information recevied from the vnf - uint8_t timing_window; - uint8_t timing_info_mode; - uint8_t timing_info_period; - -} phy_info; - -typedef struct { - uint16_t index; - uint16_t band; - int16_t max_transmit_power; - int16_t min_transmit_power; - uint8_t num_antennas_supported; - uint32_t min_downlink_frequency; - uint32_t max_downlink_frequency; - uint32_t max_uplink_frequency; - uint32_t min_uplink_frequency; -} rf_info; - -typedef struct { - int release; - phy_info phys[2]; - rf_info rfs[2]; - - uint8_t sync_mode; - uint8_t location_mode; - uint8_t location_coordinates[6]; - uint32_t dl_config_timing; - uint32_t ul_config_timing; - uint32_t tx_timing; - uint32_t hi_dci0_timing; - - uint16_t max_phys; - uint16_t max_total_bw; - uint16_t max_total_dl_layers; - uint16_t max_total_ul_layers; - uint8_t shared_bands; - uint8_t shared_pa; - int16_t max_total_power; - uint8_t oui; - - uint8_t wireshark_test_mode; - -} pnf_info; - -typedef struct mac mac_t; -typedef struct mac { - void *user_data; - - void (*dl_config_req)(mac_t *mac, nfapi_dl_config_request_t *req); - void (*ul_config_req)(mac_t *mac, nfapi_ul_config_request_t *req); - void (*hi_dci0_req)(mac_t *mac, nfapi_hi_dci0_request_t *req); - void (*tx_req)(mac_t *mac, nfapi_tx_request_t *req); -} mac_t; - -typedef struct { - int local_port; - char local_addr[80]; - - unsigned timing_window; - unsigned periodic_timing_enabled; - unsigned aperiodic_timing_enabled; - unsigned periodic_timing_period; - - // This is not really the right place if we have multiple PHY, - // should be part of the phy struct - udp_data udp; - - uint8_t thread_started; - - nfapi_vnf_p7_config_t *config; - - mac_t *mac; - -} vnf_p7_info; - -typedef struct { - uint8_t wireshark_test_mode; - pnf_info pnfs[2]; - vnf_p7_info p7_vnfs[2]; - -} vnf_info; - -int aerial_phy_nr_crc_indication(nfapi_nr_crc_indication_t *ind); -int aerial_phy_nr_rx_data_indication(nfapi_nr_rx_data_indication_t *ind); -int aerial_phy_nr_rach_indication(nfapi_nr_rach_indication_t *ind); -int aerial_phy_nr_uci_indication(nfapi_nr_uci_indication_t *ind); -int aerial_phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind); -int aerial_phy_nr_srs_indication(nfapi_nr_srs_indication_t *ind); -void *aerial_vnf_allocate(size_t size); -void aerial_vnf_deallocate(void *ptr); -int aerial_phy_vendor_ext(struct nfapi_vnf_p7_config *config, void *msg); -int aerial_phy_unpack_p7_vendor_extension(void *header, - uint8_t **ppReadPackedMessage, - uint8_t *end, - nfapi_p7_codec_config_t *config); -int aerial_phy_pack_p7_vendor_extension(void *header, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *config); -int aerial_phy_unpack_vendor_extension_tlv(nfapi_tl_t *tl, - uint8_t **ppReadPackedMessage, - uint8_t *end, - void **ve, - nfapi_p7_codec_config_t *codec); -int aerial_phy_pack_vendor_extension_tlv(void *ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *codec); -void *aerial_phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t *msg_size); -void aerial_phy_deallocate_p7_vendor_ext(void *header); - -uint8_t aerial_unpack_nr_slot_indication(uint8_t **ppReadPackedMsg, - uint8_t *end, - nfapi_nr_slot_indication_scf_t *msg, - nfapi_p7_codec_config_t *config); uint8_t aerial_unpack_nr_rx_data_indication(uint8_t **ppReadPackedMsg, uint8_t *end, uint8_t **pDataMsg, uint8_t *data_end, nfapi_nr_rx_data_indication_t *msg, nfapi_p7_codec_config_t *config); -uint8_t aerial_unpack_nr_crc_indication(uint8_t **ppReadPackedMsg, - uint8_t *end, - nfapi_nr_crc_indication_t *msg, - nfapi_p7_codec_config_t *config); -uint8_t aerial_unpack_nr_uci_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config); + uint8_t aerial_unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, uint8_t **pDataMsg, uint8_t *data_end, void *msg, nfapi_p7_codec_config_t *config); -uint8_t aerial_unpack_nr_rach_indication(uint8_t **ppReadPackedMsg, - uint8_t *end, - nfapi_nr_rach_indication_t *msg, - nfapi_p7_codec_config_t *config); - -// int fapi_nr_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t* config); -int fapi_nr_pack_and_send_p7_message(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *header); +bool aerial_nr_send_p7_message(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *header); #endif // OPENAIRINTERFACE_FAPI_VNF_P7_H diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c index 21b3e1e90e..3de11d8003 100644 --- a/nfapi/oai_integration/nfapi_pnf.c +++ b/nfapi/oai_integration/nfapi_pnf.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include "fapi_stub.h" @@ -62,6 +63,16 @@ #include "executables/lte-softmodem.h" #include "nfapi/open-nFAPI/pnf/inc/pnf_p7.h" +#ifdef ENABLE_WLS +#include +#include +#include "nfapi/oai_integration/wls_integration/include/wls_pnf.h" +#endif + +#ifdef ENABLE_SOCKET +#include +#endif + #define NUM_P5_PHY 2 #define _GNU_SOURCE @@ -77,7 +88,6 @@ extern int nfapi_sync_var; extern int sync_var; nfapi_tx_request_pdu_t *tx_request_pdu[1023][10][10]; // [frame][subframe][max_num_pdus] -nfapi_nr_pdu_t *tx_data_request[1023][20][10]; //[frame][slot][max_num_pdus] uint8_t tx_pdus[32][8][4096]; nfapi_ue_release_request_body_t release_rntis; @@ -185,7 +195,7 @@ typedef struct { } pnf_phy_user_data_t; static pnf_info pnf; -static pthread_t pnf_start_pthread; +static pthread_t pnf_p5_init_and_receive_pthread; int nfapitooai_level(int nfapi_level) { switch(nfapi_level) { @@ -219,12 +229,7 @@ void *pnf_p7_thread_start(void *ptr) { return 0; } -void *pnf_nr_p7_thread_start(void *ptr) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "[NR_PNF] NR P7 THREAD %s\n", __FUNCTION__); - nfapi_pnf_p7_config_t *config = (nfapi_pnf_p7_config_t *)ptr; - nfapi_nr_pnf_p7_start(config); - return 0; -} + int pnf_nr_param_request(nfapi_pnf_config_t *config, nfapi_nr_pnf_param_request_t *req) { @@ -991,6 +996,10 @@ int nr_config_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, n phy_info->timing_window, req->nfapi_config.timing_window.value); num_tlv++; + }else { + // This is a nFAPI TLV, thus not sent when working with FAPI. + // When not sent, we still need a default value, otherwise every message from the L2 is treated as late and not processed + phy_info->timing_window = 30; } if (req->nfapi_config.timing_info_mode.tl.tag == NFAPI_NR_NFAPI_TIMING_INFO_MODE_TAG) { @@ -1747,9 +1756,26 @@ int nr_start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nf p7_config->codec_config.pack_p7_vendor_extension = &pnf_nr_phy_pack_p7_vendor_extension; p7_config->codec_config.unpack_vendor_extension_tlv = &pnf_nr_phy_unpack_vendor_extension_tlv; p7_config->codec_config.pack_vendor_extension_tlv = &pnf_nr_phy_pack_vendor_extention_tlv; + +#ifdef ENABLE_WLS + p7_config->unpack_func = &fapi_nr_p7_message_unpack; + p7_config->hdr_unpack_func = &fapi_nr_p7_message_header_unpack; + p7_config->pack_func = &fapi_nr_p7_message_pack; + p7_config->send_p7_msg = &wls_pnf_nr_send_p7_message; + // pass p7_config to WLS handler + wls_pnf_set_p7_config(p7_config); +#endif + +#ifdef ENABLE_SOCKET + p7_config->unpack_func = &nfapi_nr_p7_message_unpack; + p7_config->hdr_unpack_func = &nfapi_nr_p7_message_header_unpack; + p7_config->pack_func = &nfapi_nr_p7_message_pack; + p7_config->send_p7_msg = &pnf_nr_send_p7_message; NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating P7 thread %s\n", __FUNCTION__); pthread_t p7_thread; threadCreate(&p7_thread, &pnf_nr_p7_thread_start, p7_config, "pnf_p7_thread", -1, OAI_PRIORITY_RT); +#endif + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Calling l1_north_init_eNB() %s\n", __FUNCTION__); l1_north_init_gNB(); NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] HACK - Set p7_config global ready for subframe ind%s\n", __FUNCTION__); @@ -1794,10 +1820,11 @@ int nr_start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nf usleep(50000); printf("[PNF] waiting for OAI to be started\n"); } - +#ifndef ENABLE_WLS printf("[PNF] Sending PNF_START_RESP\n"); nfapi_nr_send_pnf_start_resp(config, p7_config->phy_id); printf("[PNF] Sending first P7 slot indication\n"); +#endif #if 1 nfapi_pnf_p7_slot_ind(p7_config, p7_config->phy_id, 0, 0); printf("[PNF] Sent first P7 slot ind\n"); @@ -2132,15 +2159,6 @@ void *pnf_start_thread(void *ptr) { return (void *)0; } -void *pnf_nr_start_thread(void *ptr) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] IN PNF NFAPI start thread %s\n", __FUNCTION__); - nfapi_pnf_config_t *config = (nfapi_pnf_config_t *)ptr; - struct sched_param sp; - sp.sched_priority = 20; - pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp); - nfapi_nr_pnf_start(config); - return (void *)0; -} void configure_nr_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port) { @@ -2188,9 +2206,29 @@ void configure_nr_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_add config->deallocate_p4_p5_vendor_ext = &pnf_nr_sim_deallocate_p4_p5_vendor_ext; config->codec_config.unpack_p4_p5_vendor_extension = &pnf_nr_sim_unpack_p4_p5_vendor_extension; config->codec_config.pack_p4_p5_vendor_extension = &pnf_nr_sim_pack_p4_p5_vendor_extension; + +#ifdef ENABLE_WLS + printf("WLS MODE PNF\n"); + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating WLS PNF NFAPI start thread %s\n", __FUNCTION__); + // Assume it's the FAPI handler, change from within the PNF if it's not the case + config->unpack_func = &fapi_nr_p5_message_unpack; + config->hdr_unpack_func = &fapi_nr_message_header_unpack; + config->pack_func = &fapi_nr_p5_message_pack; + config->send_p5_msg = &wls_pnf_nr_send_p5_message; + //wls_fapi_pnf_nr_start_thread(config); + threadCreate(&pnf_p5_init_and_receive_pthread, wls_fapi_pnf_nr_start_thread, config, "NFAPI_WLS_PNF", -1, OAI_PRIORITY_RT_MAX); +#endif + +#ifdef ENABLE_SOCKET NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating PNF NFAPI start thread %s\n", __FUNCTION__); - pthread_create(&pnf_start_pthread, NULL, &pnf_nr_start_thread, config); - pthread_setname_np(pnf_start_pthread, "NFAPI_PNF"); + config->unpack_func = &nfapi_nr_p5_message_unpack; + config->hdr_unpack_func = &nfapi_nr_p5_message_header_unpack; + config->pack_func = &nfapi_nr_p5_message_pack; + config->send_p5_msg = &pnf_nr_send_p5_message; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating PNF NFAPI start thread %s\n", __FUNCTION__); + pthread_create(&pnf_p5_init_and_receive_pthread, NULL, &pnf_start_p5_thread, config); + pthread_setname_np(pnf_p5_init_and_receive_pthread, "NFAPI_PNF"); +#endif } void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port) { @@ -2240,8 +2278,8 @@ void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, config->codec_config.unpack_p4_p5_vendor_extension = &pnf_sim_unpack_p4_p5_vendor_extension; config->codec_config.pack_p4_p5_vendor_extension = &pnf_sim_pack_p4_p5_vendor_extension; NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating PNF NFAPI start thread %s\n", __FUNCTION__); - pthread_create(&pnf_start_pthread, NULL, &pnf_start_thread, config); - pthread_setname_np(pnf_start_pthread, "NFAPI_PNF"); + pthread_create(&pnf_p5_init_and_receive_pthread, NULL, &pnf_start_thread, config); + pthread_setname_np(pnf_p5_init_and_receive_pthread, "NFAPI_PNF"); } void oai_subframe_ind(uint16_t sfn, uint16_t sf) { @@ -2300,7 +2338,11 @@ void handle_nr_slot_ind(uint16_t sfn, uint16_t slot) //send VNF slot indication, which is aligned with TX thread, so that it can call the scheduler //we give four additional slots (2ms) which should be enough time for the VNF to //answer +#ifndef ENABLE_WLS int slot_ahead = 2 << mu; +#else + int slot_ahead = 1; +#endif uint16_t sfn_tx = sfn; uint16_t slot_tx = slot; sfnslot_add_slot(mu, &sfn_tx, &slot_tx, slot_ahead); // modify: do in place diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c index e30c939c83..5ea99de7ea 100644 --- a/nfapi/oai_integration/nfapi_vnf.c +++ b/nfapi/oai_integration/nfapi_vnf.c @@ -32,8 +32,19 @@ #include #include "nfapi_nr_interface_scf.h" -#include "nfapi_vnf_interface.h" #include "nfapi_vnf.h" +#include +#include +#ifdef ENABLE_WLS +#include +#include "nr_fapi_p5.h" +#include "nr_fapi_p7.h" +#endif + +#ifdef ENABLE_SOCKET +#include +#endif + #include "nfapi.h" #include "vendor_ext.h" @@ -48,10 +59,14 @@ #include "openair2/PHY_INTERFACE/queue_t.h" #include "gnb_ind_vars.h" #include "nr_fapi_p7_utils.h" +#include "nr_fapi_p5_utils.h" #include #ifdef ENABLE_AERIAL -#include "aerial/fapi_vnf_p5.h" +#include "aerial/fapi_nvIPC.h" +#include "aerial/fapi_vnf_p7.h" +#include "nr_fapi_p5.h" +#include "nr_fapi_p7.h" #endif #define TEST @@ -59,128 +74,6 @@ extern RAN_CONTEXT_t RC; extern UL_RCC_IND_t UL_RCC_INFO; -typedef struct { - uint8_t enabled; - uint32_t rx_port; - uint32_t tx_port; - char tx_addr[80]; -} udp_data; - -typedef struct { - uint16_t index; - uint16_t id; - uint8_t rfs[2]; - uint8_t excluded_rfs[2]; - - udp_data udp; - - char local_addr[80]; - int local_port; - - char *remote_addr; - int remote_port; - - uint8_t duplex_mode; - uint16_t dl_channel_bw_support; - uint16_t ul_channel_bw_support; - uint8_t num_dl_layers_supported; - uint8_t num_ul_layers_supported; - uint16_t release_supported; - uint8_t nmm_modes_supported; - - uint8_t dl_ues_per_subframe; - uint8_t ul_ues_per_subframe; - - uint8_t first_subframe_ind; - - // timing information recevied from the vnf - uint8_t timing_window; - uint8_t timing_info_mode; - uint8_t timing_info_period; - -} phy_info; - -typedef struct { - uint16_t index; - uint16_t band; - int16_t max_transmit_power; - int16_t min_transmit_power; - uint8_t num_antennas_supported; - uint32_t min_downlink_frequency; - uint32_t max_downlink_frequency; - uint32_t max_uplink_frequency; - uint32_t min_uplink_frequency; -} rf_info; - -typedef struct { - - int release; - phy_info phys[2]; - rf_info rfs[2]; - - uint8_t sync_mode; - uint8_t location_mode; - uint8_t location_coordinates[6]; - uint32_t dl_config_timing; - uint32_t ul_config_timing; - uint32_t tx_timing; - uint32_t hi_dci0_timing; - - uint16_t max_phys; - uint16_t max_total_bw; - uint16_t max_total_dl_layers; - uint16_t max_total_ul_layers; - uint8_t shared_bands; - uint8_t shared_pa; - int16_t max_total_power; - uint8_t oui; - - uint8_t wireshark_test_mode; - -} pnf_info; - -typedef struct mac mac_t; - -typedef struct mac { - - void *user_data; - - void (*dl_config_req)(mac_t *mac, nfapi_dl_config_request_t *req); - void (*ul_config_req)(mac_t *mac, nfapi_ul_config_request_t *req); - void (*hi_dci0_req)(mac_t *mac, nfapi_hi_dci0_request_t *req); - void (*tx_req)(mac_t *mac, nfapi_tx_request_t *req); -} mac_t; - -typedef struct { - - int local_port; - char local_addr[80]; - - unsigned timing_window; - unsigned periodic_timing_enabled; - unsigned aperiodic_timing_enabled; - unsigned periodic_timing_period; - - // This is not really the right place if we have multiple PHY, - // should be part of the phy struct - udp_data udp; - - uint8_t thread_started; - - nfapi_vnf_p7_config_t *config; - - mac_t *mac; - -} vnf_p7_info; - -typedef struct { - - uint8_t wireshark_test_mode; - pnf_info pnfs[2]; - vnf_p7_info p7_vnfs[2]; - -} vnf_info; - int vnf_pack_vendor_extension_tlv(void *ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *codec) { //NFAPI_TRACE(NFAPI_TRACE_INFO, "vnf_pack_vendor_extension_tlv\n"); nfapi_tl_t *tlv = (nfapi_tl_t *)ve; @@ -707,7 +600,7 @@ int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indicatio int phy_nr_rach_indication(nfapi_nr_rach_indication_t *ind) { - if (NFAPI_MODE == NFAPI_MODE_VNF) { + if (NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { nfapi_nr_rach_indication_t *rach_ind = CALLOC(1, sizeof(*rach_ind)); copy_rach_indication(ind, rach_ind); if (!put_queue(&gnb_rach_ind_queue, rach_ind)) { @@ -724,7 +617,7 @@ int phy_nr_rach_indication(nfapi_nr_rach_indication_t *ind) int phy_nr_uci_indication(nfapi_nr_uci_indication_t *ind) { LOG_D(NR_MAC, "In %s() NFAPI SFN/SF: %d/%d number_of_pdus :%u\n", __FUNCTION__, ind->sfn, ind->slot, ind->num_ucis); - if (NFAPI_MODE == NFAPI_MODE_VNF) { + if (NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { nfapi_nr_uci_indication_t *uci_ind = CALLOC(1, sizeof(*uci_ind)); AssertFatal(uci_ind, "Memory not allocated for uci_ind in phy_nr_uci_indication."); copy_uci_indication(ind, uci_ind); @@ -829,7 +722,7 @@ int phy_nr_crc_indication(nfapi_nr_crc_indication_t *ind) { LOG_D(NR_MAC, "In %s() NFAPI SFN/SF: %d/%d number_of_pdus :%u\n", __FUNCTION__, ind->sfn, ind->slot, ind->number_crcs); - if (NFAPI_MODE == NFAPI_MODE_VNF) { + if (NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { nfapi_nr_crc_indication_t *crc_ind = CALLOC(1, sizeof(*crc_ind)); copy_crc_indication(ind, crc_ind); if (!put_queue(&gnb_crc_ind_queue, crc_ind)) { @@ -930,7 +823,7 @@ int phy_nr_rx_data_indication(nfapi_nr_rx_data_indication_t *ind) ind->number_of_pdus, ind->pdu_list[0].pdu); - if (NFAPI_MODE == NFAPI_MODE_VNF) { + if (NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { nfapi_nr_rx_data_indication_t *rx_ind = CALLOC(1, sizeof(*rx_ind)); copy_rx_data_indication(ind, rx_ind); if (!put_queue(&gnb_rx_ind_queue, rx_ind)) { @@ -1389,16 +1282,9 @@ int vnf_nr_pack_p4_p5_vendor_extension(void *header, uint8_t **ppWritePackedMsg, return 0; } -static pthread_t vnf_start_pthread; +static pthread_t vnf_p5_init_and_receive_pthread; static pthread_t vnf_p7_start_pthread; -void *vnf_nr_p7_start_thread(void *ptr) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); - pthread_setname_np(pthread_self(), "VNF_P7"); - nfapi_vnf_p7_config_t *config = (nfapi_vnf_p7_config_t *)ptr; - nfapi_nr_vnf_p7_start(config); - return config; -} void *vnf_p7_start_thread(void *ptr) { NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); @@ -1408,7 +1294,7 @@ void *vnf_p7_start_thread(void *ptr) { return config; } -void *vnf_nr_p7_thread_start(void *ptr) +void *configure_nr_p7_vnf(void *ptr) { init_queue(&gnb_rach_ind_queue); init_queue(&gnb_rx_ind_queue); @@ -1417,19 +1303,23 @@ void *vnf_nr_p7_thread_start(void *ptr) vnf_p7_info *p7_vnf = (vnf_p7_info *)ptr; p7_vnf->config->port = p7_vnf->local_port; +#ifndef ENABLE_AERIAL p7_vnf->config->sync_indication = &phy_sync_indication; p7_vnf->config->slot_indication = &phy_slot_indication; p7_vnf->config->harq_indication = &phy_harq_indication; +#endif p7_vnf->config->nr_crc_indication = &phy_nr_crc_indication; p7_vnf->config->nr_rx_data_indication = &phy_nr_rx_data_indication; p7_vnf->config->nr_rach_indication = &phy_nr_rach_indication; p7_vnf->config->nr_uci_indication = &phy_nr_uci_indication; +#ifndef ENABLE_AERIAL p7_vnf->config->srs_indication = &phy_srs_indication; p7_vnf->config->sr_indication = &phy_sr_indication; p7_vnf->config->cqi_indication = &phy_cqi_indication; p7_vnf->config->lbt_dl_indication = &phy_lbt_dl_indication; p7_vnf->config->nb_harq_indication = &phy_nb_harq_indication; p7_vnf->config->nrach_indication = &phy_nrach_indication; +#endif p7_vnf->config->nr_slot_indication = &phy_nr_slot_indication; p7_vnf->config->nr_srs_indication = &phy_nr_srs_indication; p7_vnf->config->malloc = &vnf_allocate; @@ -1445,8 +1335,30 @@ void *vnf_nr_p7_thread_start(void *ptr) p7_vnf->config->codec_config.deallocate = &vnf_deallocate; p7_vnf->config->allocate_p7_vendor_ext = &phy_nr_allocate_p7_vendor_ext; p7_vnf->config->deallocate_p7_vendor_ext = &phy_nr_deallocate_p7_vendor_ext; + +#ifdef ENABLE_WLS + p7_vnf->config->unpack_func = &fapi_nr_p7_message_unpack; + p7_vnf->config->hdr_unpack_func = &fapi_nr_p7_message_header_unpack; + p7_vnf->config->pack_func = &fapi_nr_p7_message_pack; + p7_vnf->config->send_p7_msg = &wls_vnf_nr_send_p7_message; + wls_vnf_set_p7_config(p7_vnf->config); +#endif + +#ifdef ENABLE_SOCKET + p7_vnf->config->unpack_func = &nfapi_nr_p7_message_unpack; + p7_vnf->config->hdr_unpack_func = &nfapi_nr_p7_message_header_unpack; + p7_vnf->config->pack_func = &nfapi_nr_p7_message_pack; + p7_vnf->config->send_p7_msg = &vnf_nr_send_p7_msg; NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI P7 start thread %s\n", __FUNCTION__); - pthread_create(&vnf_p7_start_pthread, NULL, &vnf_nr_p7_start_thread, p7_vnf->config); + threadCreate(&vnf_p7_start_pthread, &vnf_nr_start_p7_thread, p7_vnf->config, "vnf_p7_thread", -1, OAI_PRIORITY_RT); +#endif + +#ifdef ENABLE_AERIAL + p7_vnf->config->unpack_func = &fapi_nr_p7_message_unpack; + p7_vnf->config->hdr_unpack_func = &fapi_nr_p7_message_header_unpack; + p7_vnf->config->pack_func = &fapi_nr_p7_message_pack; + p7_vnf->config->send_p7_msg = &aerial_nr_send_p7_message; +#endif return 0; } @@ -1494,7 +1406,7 @@ int pnf_nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_st if(p7_vnf->thread_started == 0) { pthread_t vnf_p7_thread; - threadCreate(&vnf_p7_thread, &vnf_nr_p7_thread_start, p7_vnf, "vnf_p7_thread", -1, OAI_PRIORITY_RT); + threadCreate(&vnf_p7_thread, &configure_nr_p7_vnf, p7_vnf, "vnf_p7_thread", -1, OAI_PRIORITY_RT); p7_vnf->thread_started = 1; } else { // P7 thread already running. @@ -1504,7 +1416,12 @@ int pnf_nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_st NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Sending NFAPI_VNF_PARAM_REQUEST phy_id:%d\n", pnf->phys[0].id); memset(&req, 0, sizeof(req)); req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST; +#ifdef ENABLE_WLS + req.header.phy_id = 0; +#endif +#ifdef ENABLE_SOCKET req.header.phy_id = pnf->phys[0].id; +#endif nfapi_nr_vnf_param_req(config, p5_idx, &req); return 0; } @@ -1542,8 +1459,9 @@ int nr_param_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_param_resp vnf_p7_info *p7_vnf = vnf->p7_vnfs; pnf_info *pnf = vnf->pnfs; phy_info *phy = pnf->phys; - struct sockaddr_in pnf_p7_sockaddr; nfapi_nr_config_request_scf_t *req = &RC.nrmac[0]->config[0]; // check +#ifndef ENABLE_AERIAL + struct sockaddr_in pnf_p7_sockaddr; phy->remote_port = resp->nfapi_config.p7_pnf_port.value; //phy->remote_port = 32123;//resp->nfapi_config.p7_pnf_port.value; memcpy(&pnf_p7_sockaddr.sin_addr.s_addr, &(resp->nfapi_config.p7_pnf_address_ipv4.address[0]), 4); @@ -1551,6 +1469,7 @@ int nr_param_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_param_resp // for now just 1 NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %d.%d pnf p7 %s:%d timing %u %u %u %u\n", p5_idx, phy->id, phy->remote_addr, phy->remote_port, p7_vnf->timing_window, p7_vnf->periodic_timing_period, p7_vnf->aperiodic_timing_enabled, p7_vnf->periodic_timing_period); +#endif // Hack? the VNF might need the subcarrier spacing for some calculations // (that we actually don't use as of now...). We therefore need to save the // mu, for the current PNF connection (together with where we have frame/slot @@ -1566,7 +1485,7 @@ int nr_param_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_param_resp req->header.phy_id = phy->id; NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Send NFAPI_CONFIG_REQUEST\n"); //NFAPI_TRACE(NFAPI_TRACE_INFO, "\n NR bandP =%d\n",req->nfapi_config.rf_bands.rf_band[0]); - +#ifndef ENABLE_AERIAL req->nfapi_config.p7_vnf_port.tl.tag = NFAPI_NR_NFAPI_P7_VNF_PORT_TAG; req->nfapi_config.p7_vnf_port.value = p7_vnf->local_port; req->num_tlv++; @@ -1604,6 +1523,7 @@ req->nfapi_config.tx_data_timing_offset.tl.tag = NFAPI_NR_NFAPI_TX_DATA_TIMING_O ve2.tl.tag = VENDOR_EXT_TLV_2_TAG; ve2.dummy = 2016; req->vendor_extension = &ve2.tl; +#endif nfapi_nr_vnf_config_req(config, p5_idx, req); printf("[VNF] Sent NFAPI_VNF_CONFIG_REQ num_tlv:%u\n",req->num_tlv); return 0; @@ -1703,6 +1623,21 @@ int nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_start_resp return 0; } +int nr_error_ind_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_error_indication_scf_t *resp) +{ + NFAPI_TRACE(NFAPI_TRACE_WARN, + "[VNF] Received NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION idx:%d phy_id:%d\n", + p5_idx, + resp->header.phy_id); + NFAPI_TRACE(NFAPI_TRACE_WARN, "[VNF] Previous message 0x%02x resulted in an error on the PNF \n", resp->message_id); + NFAPI_TRACE(NFAPI_TRACE_WARN, + "[VNF] Received error code 0x%02x (%s)\n", + resp->error_code, + error_ind_code_to_str(resp->error_code)); + // TODO: add error handling to the VNF instead of only reporting the received error + return 0; +} + int vendor_ext_cb(nfapi_vnf_config_t *config, int p5_idx, void *msg) { NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %s\n", __FUNCTION__); @@ -1794,28 +1729,19 @@ void vnf_nr_deallocate_p4_p5_vendor_ext(void *header) { free(header); } - -nfapi_vnf_config_t *config = 0; - -void vnf_nr_start_thread(void *ptr) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] VNF NFAPI thread - nfapi_vnf_start()%s\n", __FUNCTION__); - pthread_setname_np(pthread_self(), "VNF"); - config = (nfapi_vnf_config_t *)ptr; - nfapi_nr_vnf_start(config); -} - void vnf_start_thread(void *ptr) { NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] VNF NFAPI thread - nfapi_vnf_start()%s\n", __FUNCTION__); pthread_setname_np(pthread_self(), "VNF"); - config = (nfapi_vnf_config_t *)ptr; - nfapi_vnf_start(config); + nfapi_vnf_start((nfapi_vnf_config_t *)ptr); } static vnf_info vnf; -void configure_nr_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port) +void configure_nr_nfapi_vnf(eth_params_t params) { +#ifndef ENABLE_AERIAL nfapi_setmode(NFAPI_MODE_VNF); +#endif memset(&vnf, 0, sizeof(vnf)); memset(vnf.p7_vnfs, 0, sizeof(vnf.p7_vnfs)); vnf.p7_vnfs[0].timing_window = 30; @@ -1823,19 +1749,21 @@ void configure_nr_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, vnf.p7_vnfs[0].aperiodic_timing_enabled = 0; vnf.p7_vnfs[0].periodic_timing_period = 1; vnf.p7_vnfs[0].config = nfapi_vnf_p7_config_create(); +#ifndef ENABLE_AERIAL NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %s() vnf.p7_vnfs[0].config:%p VNF ADDRESS:%s:%d\n", __FUNCTION__, vnf.p7_vnfs[0].config, - vnf_addr, - vnf_p5_port); - strcpy(vnf.p7_vnfs[0].local_addr, vnf_addr); - vnf.p7_vnfs[0].local_port = vnf_p7_port; + params.my_addr, + params.my_portc); + strcpy(vnf.p7_vnfs[0].local_addr, params.my_addr); + vnf.p7_vnfs[0].local_port = params.my_portd; +#endif vnf.p7_vnfs[0].mac = (mac_t *)malloc(sizeof(mac_t)); nfapi_vnf_config_t *config = nfapi_vnf_config_create(); config->malloc = malloc; config->free = free; - config->vnf_p5_port = vnf_p5_port; + config->vnf_p5_port = params.my_portc; config->vnf_ipv4 = 1; config->vnf_ipv6 = 0; config->pnf_list = 0; @@ -1850,6 +1778,7 @@ void configure_nr_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, config->nr_param_resp = &nr_param_resp_cb; config->nr_config_resp = &nr_config_resp_cb; config->nr_start_resp = &nr_start_resp_cb; + config->nr_error_ind = &nr_error_ind_cb; config->vendor_ext = &vendor_nr_ext_cb; config->user_data = &vnf; // To allow custom vendor extentions to be added to nfapi @@ -1862,9 +1791,73 @@ void configure_nr_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, config->codec_config.allocate = &vnf_nr_allocate; config->codec_config.deallocate = &vnf_nr_deallocate; memset(&UL_RCC_INFO, 0, sizeof(UL_RCC_IND_t)); + +#ifdef ENABLE_WLS + config->unpack_func = &fapi_nr_p5_message_unpack; + config->hdr_unpack_func = &fapi_nr_message_header_unpack; + config->pack_func = &fapi_nr_p5_message_pack; + config->send_p5_msg = &wls_vnf_nr_send_p5_message; + printf("WLS MODE PNF\n"); + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] Creating WLS VNF NFAPI start thread %s\n", __FUNCTION__); + //wls_fapi_pnf_nr_start_thread(config); + threadCreate(&vnf_p5_init_and_receive_pthread, wls_fapi_vnf_nr_start_thread, config, "NFAPI_WLS_VNF", -1, OAI_PRIORITY_RT_MAX); +#endif + +#ifdef ENABLE_SOCKET + config->unpack_func = &nfapi_nr_p5_message_unpack; + config->hdr_unpack_func = &nfapi_nr_p5_message_header_unpack; + config->pack_func = &nfapi_nr_p5_message_pack; + config->send_p5_msg = &vnf_nr_send_p5_msg; NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); - pthread_create(&vnf_start_pthread, NULL, (void *)&vnf_nr_start_thread, config); + pthread_create(&vnf_p5_init_and_receive_pthread, NULL, (void *)&vnf_start_p5_thread, config); NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Created VNF NFAPI start thread %s\n", __FUNCTION__); +#endif +#ifdef ENABLE_AERIAL + config->unpack_func = &fapi_nr_p5_message_unpack; + config->hdr_unpack_func = &fapi_nr_message_header_unpack; + config->pack_func = &fapi_nr_p5_message_pack; + config->send_p5_msg = &aerial_nr_send_p5_message; + set_config(config); + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Created VNF NFAPI start thread %s\n", __FUNCTION__); + nfapi_vnf_pnf_info_t *pnf = (nfapi_vnf_pnf_info_t *)malloc(sizeof(nfapi_vnf_pnf_info_t)); + NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf); + memset(pnf, 0, sizeof(nfapi_vnf_pnf_info_t)); + pnf->p5_idx = 1; + pnf->connected = 1; + // Add needed parameters + + vnf_info *vnf = (vnf_info *)(config->user_data); + pnf_info *pnf_info = vnf->pnfs; + + for (int i = 0; i < 1; ++i) { + phy_info phy; + memset(&phy, 0, sizeof(phy)); + phy.index = 0; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) phy_config_idx:%d\n", i, 0); + nfapi_vnf_allocate_phy(config, 1, &(phy.id)); + + for (int j = 0; j < 1; ++j) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) (RF%d) %d\n", i, j, 0); + phy.rfs[0] = 0; + } + + pnf_info->phys[0] = phy; + } + + + nfapi_vnf_pnf_list_add(config, pnf); + + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + + NFAPI_TRACE(NFAPI_TRACE_INFO, + "[VNF] pnf start response idx:%d config:%p user_data:%p p7_vnf[config:%p thread_started:%d]\n", + 1, + config, + config->user_data, + vnf->p7_vnfs[0].config, + vnf->p7_vnfs[0].thread_started); + configure_nr_p7_vnf(p7_vnf); +#endif } @@ -1912,7 +1905,7 @@ void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int config->codec_config.deallocate = &vnf_deallocate; memset(&UL_RCC_INFO,0,sizeof(UL_RCC_IND_t)); NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); - pthread_create(&vnf_start_pthread, NULL, (void *)&vnf_start_thread, config); + pthread_create(&vnf_p5_init_and_receive_pthread, NULL, (void *)&vnf_start_thread, config); NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Created VNF NFAPI start thread %s\n", __FUNCTION__); } @@ -1957,13 +1950,13 @@ int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) dl_config_req->header.message_id= NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST; dl_config_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!! - int retval = nfapi_vnf_p7_nr_dl_config_req(p7_config, dl_config_req); + bool retval = nfapi_vnf_p7_nr_dl_config_req(p7_config, dl_config_req); dl_config_req->dl_tti_request_body.nPDUs = 0; dl_config_req->dl_tti_request_body.nGroup = 0; - if (retval!=0) { + if (!retval) { LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); } return retval; @@ -1976,9 +1969,9 @@ int oai_nfapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req) tx_data_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!! tx_data_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST; //LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_req->sfn_sf), tx_req->tx_request_body.number_of_pdus); - int retval = nfapi_vnf_p7_tx_data_req(p7_config, tx_data_req); + bool retval = nfapi_vnf_p7_tx_data_req(p7_config, tx_data_req); - if (retval!=0) { + if (!retval) { LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); } else { tx_data_req->Number_of_PDUs = 0; @@ -2009,9 +2002,9 @@ int oai_nfapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req) { ul_dci_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!! ul_dci_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST; //LOG_D(PHY, "[VNF] %s() HI_DCI0_REQ sfn_sf:%d dci:%d hi:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(hi_dci0_req->sfn_sf), hi_dci0_req->hi_dci0_request_body.number_of_dci, hi_dci0_req->hi_dci0_request_body.number_of_hi); - int retval = nfapi_vnf_p7_ul_dci_req(p7_config, ul_dci_req); + bool retval = nfapi_vnf_p7_ul_dci_req(p7_config, ul_dci_req); - if (retval!=0) { + if (!retval) { LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); } else { ul_dci_req->numPdus = 0; @@ -2062,9 +2055,9 @@ int oai_nfapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req) { ul_tti_req->header.phy_id = 1; // HACK TODO FIXME - need to pass this around!!!! ul_tti_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST; - int retval = nfapi_vnf_p7_ul_tti_req(p7_config, ul_tti_req); + bool retval = nfapi_vnf_p7_ul_tti_req(p7_config, ul_tti_req); - if (retval!=0) { + if (!retval) { LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); } else { // Reset number of PDUs so that it is not resent diff --git a/nfapi/oai_integration/nfapi_vnf.h b/nfapi/oai_integration/nfapi_vnf.h index 71cc50c2f7..104cff44f4 100644 --- a/nfapi/oai_integration/nfapi_vnf.h +++ b/nfapi/oai_integration/nfapi_vnf.h @@ -21,8 +21,132 @@ #ifndef NFAPI_VNF_H_ #define NFAPI_VNF_H_ +#include + +#include "nfapi_vnf_interface.h" +typedef struct { + uint8_t enabled; + uint32_t rx_port; + uint32_t tx_port; + char tx_addr[80]; +} udp_data; + +typedef struct { + uint16_t index; + uint16_t id; + uint8_t rfs[2]; + uint8_t excluded_rfs[2]; + + udp_data udp; + + char local_addr[80]; + int local_port; + + char *remote_addr; + int remote_port; + + uint8_t duplex_mode; + uint16_t dl_channel_bw_support; + uint16_t ul_channel_bw_support; + uint8_t num_dl_layers_supported; + uint8_t num_ul_layers_supported; + uint16_t release_supported; + uint8_t nmm_modes_supported; + + uint8_t dl_ues_per_subframe; + uint8_t ul_ues_per_subframe; + + uint8_t first_subframe_ind; + + // timing information recevied from the vnf + uint8_t timing_window; + uint8_t timing_info_mode; + uint8_t timing_info_period; + +} phy_info; + +typedef struct { + uint16_t index; + uint16_t band; + int16_t max_transmit_power; + int16_t min_transmit_power; + uint8_t num_antennas_supported; + uint32_t min_downlink_frequency; + uint32_t max_downlink_frequency; + uint32_t max_uplink_frequency; + uint32_t min_uplink_frequency; +} rf_info; + +typedef struct { + + int release; + phy_info phys[2]; + rf_info rfs[2]; + + uint8_t sync_mode; + uint8_t location_mode; + uint8_t location_coordinates[6]; + uint32_t dl_config_timing; + uint32_t ul_config_timing; + uint32_t tx_timing; + uint32_t hi_dci0_timing; + + uint16_t max_phys; + uint16_t max_total_bw; + uint16_t max_total_dl_layers; + uint16_t max_total_ul_layers; + uint8_t shared_bands; + uint8_t shared_pa; + int16_t max_total_power; + uint8_t oui; + + uint8_t wireshark_test_mode; + +} pnf_info; + +typedef struct mac mac_t; + +typedef struct mac { + + void *user_data; + + void (*dl_config_req)(mac_t *mac, nfapi_dl_config_request_t *req); + void (*ul_config_req)(mac_t *mac, nfapi_ul_config_request_t *req); + void (*hi_dci0_req)(mac_t *mac, nfapi_hi_dci0_request_t *req); + void (*tx_req)(mac_t *mac, nfapi_tx_request_t *req); +} mac_t; + +typedef struct { + + int local_port; + char local_addr[80]; + + unsigned timing_window; + unsigned periodic_timing_enabled; + unsigned aperiodic_timing_enabled; + unsigned periodic_timing_period; + + // This is not really the right place if we have multiple PHY, + // should be part of the phy struct + udp_data udp; + + uint8_t thread_started; + + nfapi_vnf_p7_config_t *config; + + mac_t *mac; + +} vnf_p7_info; + +typedef struct { + + uint8_t wireshark_test_mode; + pnf_info pnfs[2]; + vnf_p7_info p7_vnfs[2]; + +} vnf_info; void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port); -void configure_nr_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port); +void configure_nr_nfapi_vnf(eth_params_t params); #endif /* NFAPI_VNF_H_ */ diff --git a/nfapi/oai_integration/socket/CMakeLists.txt b/nfapi/oai_integration/socket/CMakeLists.txt new file mode 100644 index 0000000000..a909372d37 --- /dev/null +++ b/nfapi/oai_integration/socket/CMakeLists.txt @@ -0,0 +1,13 @@ +add_library(nfapi_socket_lib + socket_pnf.c + socket_vnf.c + socket_common.c +) + +target_include_directories(nfapi_socket_lib PRIVATE include/) + +target_compile_definitions(nfapi_socket_lib PUBLIC ENABLE_SOCKET) +target_link_libraries(nfapi_socket_lib PRIVATE NFAPI_LIB NFAPI_USER_LIB) +target_link_libraries(nfapi_socket_lib PRIVATE log_headers) +target_link_libraries(nfapi_socket_lib PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) +target_link_libraries(nfapi_socket_lib PRIVATE nr_fapi_p5 nr_fapi_p7) diff --git a/nfapi/oai_integration/socket/include/socket_common.h b/nfapi/oai_integration/socket/include/socket_common.h new file mode 100644 index 0000000000..1817507733 --- /dev/null +++ b/nfapi/oai_integration/socket/include/socket_common.h @@ -0,0 +1,45 @@ +/* + * 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 SOCKET_COMMON_H +#define SOCKET_COMMON_H + +#define _GNU_SOURCE /* required for pthread_getname_np */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int socket_send_p5_msg(const int sctp, + const int socket, + const void* remote_addr, + const void* msg, + const uint32_t len, + const uint16_t stream); +int socket_send_p7_msg(const int socket, const void* remote_addr, const void* msg, const uint32_t len); + +#endif // SOCKET_COMMON_H diff --git a/nfapi/oai_integration/socket/include/socket_pnf.h b/nfapi/oai_integration/socket/include/socket_pnf.h new file mode 100644 index 0000000000..ccb3eaea3a --- /dev/null +++ b/nfapi/oai_integration/socket/include/socket_pnf.h @@ -0,0 +1,39 @@ +/* + * 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 SOCKET_PNF_H +#define SOCKET_PNF_H +#include "socket_common.h" +#include +#include +#include +#include "pnf.h" +#include "pnf_p7.h" +#include "nr_fapi_p5.h" +#include "nr_nfapi_p7.h" + +int pnf_connect_socket(pnf_t *pnf); +int pnf_nr_message_pump(pnf_t *pnf); +bool pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len); +bool pnf_nr_send_p7_message(pnf_p7_t* pnf_p7, nfapi_nr_p7_message_header_t* header, uint32_t msg_len); +void *pnf_start_p5_thread(void *ptr); +void *pnf_nr_p7_thread_start(void *ptr); +#endif // SOCKET_PNF_H diff --git a/nfapi/oai_integration/socket/include/socket_vnf.h b/nfapi/oai_integration/socket/include/socket_vnf.h new file mode 100644 index 0000000000..c11e009153 --- /dev/null +++ b/nfapi/oai_integration/socket/include/socket_vnf.h @@ -0,0 +1,34 @@ +/* + * 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 SOCKET_VNF_H +#define SOCKET_VNF_H +#include "socket_common.h" +#include "vnf.h" +#include "vnf_p7.h" +#include "nr_fapi_p5.h" +#include "nr_nfapi_p7.h" +#include "nr_fapi_p7.h" +bool vnf_nr_send_p5_msg(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len); +bool vnf_nr_send_p7_msg(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t* header); +void vnf_start_p5_thread(void* ptr); +void* vnf_nr_start_p7_thread(void* ptr); +#endif // SOCKET_VNF_H diff --git a/nfapi/oai_integration/socket/socket_common.c b/nfapi/oai_integration/socket/socket_common.c new file mode 100644 index 0000000000..5ec9a13ac6 --- /dev/null +++ b/nfapi/oai_integration/socket/socket_common.c @@ -0,0 +1,58 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ +#include "socket_common.h" +#include "LOG/log.h" + +int socket_send_p5_msg(const int sctp, + const int socket, + const void* remote_addr, + const void* msg, + const uint32_t len, + const uint16_t stream) +{ + if (sctp == 1) { + struct sockaddr* to = (struct sockaddr*)remote_addr; + const int retval = sctp_sendmsg(socket, msg, len, to, 0, 42, 0, stream, 0, 0); + if (retval < 0) { + LOG_E(NR_PHY, "sctp_sendmsg failed errno: %d\n", errno); + return -1; + } + } else { + if (send(socket, msg, len, 0) != len) { + LOG_E(NR_PHY, "write failed errno: %d\n", errno); + return -1; + } + } + + return len; +} + +int socket_send_p7_msg(const int socket, const void* remote_addr, const void* msg, const uint32_t len) +{ + const struct sockaddr* to = (struct sockaddr*)remote_addr; + const long sendto_result = sendto(socket, msg, len, 0, to, sizeof(struct sockaddr_in)); + if (sendto_result != len) { + LOG_E(NR_PHY, "%s() sendto_result %ld %d\n", __FUNCTION__, sendto_result, errno); + return -1; + } + + return 0; +} diff --git a/nfapi/oai_integration/socket/socket_pnf.c b/nfapi/oai_integration/socket/socket_pnf.c new file mode 100644 index 0000000000..fe4999c998 --- /dev/null +++ b/nfapi/oai_integration/socket/socket_pnf.c @@ -0,0 +1,867 @@ +/* + * 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 "socket_pnf.h" +#include "nfapi.h" + +bool pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) +{ + int packed_len = + pnf->_public.pack_func(msg, msg_len, pnf->tx_message_buffer, sizeof(pnf->tx_message_buffer), &pnf->_public.codec_config); + + if (packed_len < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "p5_message_pack failed (%d)\n", packed_len); + return false; + } + + return socket_send_p5_msg(pnf->sctp, pnf->p5_sock, NULL, pnf->tx_message_buffer, packed_len, 0) == packed_len; +} + +static int send_p7_msg(pnf_p7_t *pnf_p7, uint8_t *msg, uint32_t len) +{ + // todo : consider how to do this only once + struct sockaddr_in remote_addr = {.sin_family = AF_INET, .sin_port = htons(pnf_p7->_public.remote_p7_port)}; + + if (inet_aton(pnf_p7->_public.remote_p7_addr, &remote_addr.sin_addr) == -1) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "inet_aton failed %d\n", errno); + return -1; + } + + socklen_t remote_addr_len = sizeof(struct sockaddr_in); + + int sendto_result = socket_send_p7_msg((int)pnf_p7->p7_sock, &remote_addr, msg, len); + if (sendto_result < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "%s %s:%d sendto(%d, %p, %d) %d failed errno: %d\n", + __FUNCTION__, + pnf_p7->_public.remote_p7_addr, + pnf_p7->_public.remote_p7_port, + (int)pnf_p7->p7_sock, + (const char *)msg, + len, + remote_addr_len, + errno); + return -1; + } + + if (sendto_result != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s sendto failed to send the entire message %d %d\n", __FUNCTION__, sendto_result, len); + } + return 0; +} + +bool pnf_nr_send_p7_message(pnf_p7_t *pnf_p7, nfapi_nr_p7_message_header_t *header, uint32_t msg_len) +{ + header->m_segment_sequence = NFAPI_NR_P7_SET_MSS(0, 0, pnf_p7->sequence_number); + + // Need to guard against different threads calling the encode function at the same time + if (pthread_mutex_lock(&(pnf_p7->pack_mutex)) != 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); + return false; + } + + uint8_t tx_buf[131072]; // four times NFAPI_MAX_PACKED_MESSAGE_SIZE as of this commit + int len = pnf_p7->_public.pack_func(header, tx_buf, sizeof(tx_buf), &pnf_p7->_public.codec_config); + + if (len < 0) { + if (pthread_mutex_unlock(&(pnf_p7->pack_mutex)) != 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return false; + } + + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p7_message_pack failed with return %d\n", len); + return false; + } + + if (len > pnf_p7->_public.segment_size) { + int msg_body_len = len - NFAPI_NR_P7_HEADER_LENGTH; + int seg_body_len = pnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; + int segment_count = (msg_body_len / (seg_body_len)) + ((msg_body_len % seg_body_len) ? 1 : 0); + + int segment = 0; + int offset = NFAPI_NR_P7_HEADER_LENGTH; + uint8_t buffer[pnf_p7->_public.segment_size]; + for (segment = 0; segment < segment_count; ++segment) { + uint8_t last = 0; + uint32_t size = pnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; + if (segment + 1 == segment_count) { + last = 1; + size = (msg_body_len) - (seg_body_len * segment); + } + + uint32_t segment_size = size + NFAPI_NR_P7_HEADER_LENGTH; + + // Update the header with the m and segement + memcpy(&buffer[0], tx_buf, NFAPI_NR_P7_HEADER_LENGTH); + + // set the segment length , update and push m_segment_sequence + uint8_t *buf_ptr = &buffer[4]; + uint8_t *buf_ptr_end = &buffer[10]; + push32(segment_size, (&buf_ptr), buf_ptr_end); + header->m_segment_sequence = NFAPI_NR_P7_SET_MSS((!last), segment, pnf_p7->sequence_number); + push16(header->m_segment_sequence, (&buf_ptr), buf_ptr_end); + memcpy(&buffer[NFAPI_NR_P7_HEADER_LENGTH], tx_buf + offset, size); + offset += size; + + if (pnf_p7->_public.checksum_enabled) { + nfapi_nr_p7_update_checksum(buffer, segment_size); + } + + send_p7_msg(pnf_p7, &buffer[0], segment_size); + } + } else { + if (pnf_p7->_public.checksum_enabled) { + nfapi_nr_p7_update_checksum(tx_buf, len); + } + + // simple case that the message fits in a single segment + send_p7_msg(pnf_p7, tx_buf, len); + } + + pnf_p7->sequence_number++; + + if (pthread_mutex_unlock(&(pnf_p7->pack_mutex)) != 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); + return false; + } + + return true; +} + +void *pnf_start_p5_thread(void *ptr) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] IN PNF NFAPI start thread %s\n", __FUNCTION__); + nfapi_pnf_config_t *config = (nfapi_pnf_config_t *)ptr; + struct sched_param sp; + sp.sched_priority = 20; + pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp); + + // Verify that config is not null + if (config == 0) + return (void *)-1; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + + pnf_t *_this = (pnf_t *)(config); + + while (_this->terminate == 0) { + int connect_result = pnf_connect_socket(_this); + + if (connect_result > 0) { + pnf_nr_message_pump(_this); + } else if (connect_result < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s() Error connecting to P5 socket\n", __FUNCTION__); + return 0; + } + + sleep(1); + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() terminate=1 - EXITTING............\n", __FUNCTION__); + + return 0; +} + +int pnf_connect_socket(pnf_t *pnf) +{ + uint8_t socketConnected = 0; + + if (pnf->_public.vnf_ip_addr == 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnfIpAddress is null\n"); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Starting P5 PNF connection to VNF at %s:%u\n", pnf->_public.vnf_ip_addr, pnf->_public.vnf_p5_port); + + // todo split the vnf address list. currently only supporting 1 + + struct addrinfo hints = {0}, *servinfo; + + hints.ai_socktype = SOCK_STREAM; // For SCTP we are only interested in SOCK_STREAM + // todo : allow the client to restrict IPV4 or IPV6 + // todo : randomize which address to connect to? + + char port_str[8]; + snprintf(port_str, sizeof(port_str), "%d", pnf->_public.vnf_p5_port); + if (getaddrinfo(pnf->_public.vnf_ip_addr, port_str, &hints, &servinfo) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to get host (%s) addr info h_errno:%d \n", pnf->_public.vnf_ip_addr, h_errno); + return -1; + } + + struct addrinfo *p = servinfo; + int connected = 0; + + while (p != NULL && connected == 0) { +#ifdef NFAPI_TRACE_ENABLED + char *family = "Unknown"; + char *address = "Unknown"; + char _addr[128]; + + if (p->ai_family == AF_INET6) { + family = "IPV6"; + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)p->ai_addr; + inet_ntop(AF_INET6, &addr->sin6_addr, _addr, sizeof(_addr)); + address = &_addr[0]; + } else if (p->ai_family == AF_INET) { + family = "IPV4"; + struct sockaddr_in *addr = (struct sockaddr_in *)p->ai_addr; + address = inet_ntoa(addr->sin_addr); + } + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Host address info %d Family:%s Address:%s\n", i++, family, address); +#endif + + if (pnf->sctp) { + // open the SCTP socket + if ((pnf->p5_sock = socket(p->ai_family, SOCK_STREAM, IPPROTO_SCTP)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P5 socket errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + int noDelay; + struct sctp_initmsg initMsg = {0}; + + // configure the socket options + NFAPI_TRACE(NFAPI_TRACE_NOTE, "PNF Setting the SCTP_INITMSG\n"); + initMsg.sinit_num_ostreams = 5; // MAX_SCTP_STREAMS; // number of output streams can be greater + initMsg.sinit_max_instreams = 5; // MAX_SCTP_STREAMS; // number of output streams can be greater + if (setsockopt(pnf->p5_sock, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + noDelay = 1; + if (setsockopt(pnf->p5_sock, IPPROTO_SCTP, SCTP_NODELAY, &noDelay, sizeof(noDelay)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + + struct sctp_event_subscribe events = {0}; + events.sctp_data_io_event = 1; + + if (setsockopt(pnf->p5_sock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + } else { + // Create an IP socket point + if ((pnf->p5_sock = socket(p->ai_family, SOCK_STREAM, IPPROTO_IP)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P5 socket errno: %d\n", errno); + freeaddrinfo(servinfo); + return -1; + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "P5 socket created...\n"); + + if (connect(pnf->p5_sock, p->ai_addr, p->ai_addrlen) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "After connect (address:%s port:%d) errno: %d\n", + pnf->_public.vnf_ip_addr, + pnf->_public.vnf_p5_port, + errno); + + if (errno == EINVAL) { + freeaddrinfo(servinfo); + return -1; + } + if (pnf->terminate != 0) { + freeaddrinfo(servinfo); + return 0; + } + close(pnf->p5_sock); + sleep(1); + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "connect succeeded...\n"); + + connected = 1; + } + + p = p->ai_next; + } + + freeaddrinfo(servinfo); + + // If we have failed to connect return 0 and it is retry + if (connected == 0) + return 0; + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "After connect loop\n"); + if (pnf->sctp) { + socklen_t optLen; + struct sctp_status status = {0}; + + // check the connection status + optLen = (socklen_t)sizeof(struct sctp_status); + if (getsockopt(pnf->p5_sock, IPPROTO_SCTP, SCTP_STATUS, &status, &optLen) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno); + return -1; + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Association ID = %d\n", status.sstat_assoc_id); + NFAPI_TRACE(NFAPI_TRACE_INFO, "Receiver window size = %d\n", status.sstat_rwnd); + NFAPI_TRACE(NFAPI_TRACE_INFO, "In Streams = %d\n", status.sstat_instrms); + NFAPI_TRACE(NFAPI_TRACE_INFO, "Out Streams = %d\n", status.sstat_outstrms); + + socketConnected = 1; + } + } else { + int error; + socklen_t len = sizeof(error); + + if (getsockopt(pnf->p5_sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno); + return -1; + } else { + // If error is zero, the socket is connected + if (error == 0) { + socketConnected = 1; + } + } + } + + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Socket %s\n", socketConnected ? "CONNECTED" : "NOT_CONNECTED"); + return socketConnected; +} + +static int pnf_nr_read_dispatch_message(pnf_t *pnf) +{ + int socket_connected = 1; + + // 1. Peek the message header + // 2. If the message is larger than the stack buffer, then create a dynamic buffer + // 3. Read the buffer + // 4. Handle the p5 message + + uint32_t header_buffer_size = NFAPI_NR_P5_HEADER_LENGTH; + uint8_t header_buffer[header_buffer_size]; + + uint32_t stack_buffer_size = 32; // should it be the size of then sctp_notificatoin structure + uint8_t stack_buffer[stack_buffer_size]; + + uint8_t *dynamic_buffer = 0; + + uint8_t *read_buffer = &stack_buffer[0]; + uint32_t message_size = 0; + + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + struct sctp_sndrcvinfo sndrcvinfo = {0}; + + { + int flags = MSG_PEEK; + if (pnf->sctp) { + message_size = sctp_recvmsg(pnf->p5_sock, + header_buffer, + header_buffer_size, + /*(struct sockaddr*)&addr, &addr_len*/ + 0, + 0, + &sndrcvinfo, + &flags); + } else { + message_size = recv(pnf->p5_sock, header_buffer, header_buffer_size, flags); + } + + if (message_size < NFAPI_NR_P5_HEADER_LENGTH) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to peek sctp message size errno:%d\n", errno); + return 0; + } + + nfapi_nr_p4_p5_message_header_t header; + const bool result = pnf->_public.hdr_unpack_func(header_buffer, header_buffer_size, &header, sizeof(header), 0); + if (!result) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to unpack p5 message header\n"); + return 0; + } + message_size = header.message_length + header_buffer_size; + + // now have the size of the mesage + } + + if (message_size > stack_buffer_size) { + dynamic_buffer = (uint8_t *)malloc(message_size); + + if (dynamic_buffer == NULL) { + // todo : add error mesage + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to allocate dynamic buffer for sctp_recvmsg size:%d\n", message_size); + return -1; + } + + read_buffer = dynamic_buffer; + } + + { + int flags = 0; + + ssize_t recvmsg_result = 0; + if (pnf->sctp) { + recvmsg_result = + sctp_recvmsg(pnf->p5_sock, read_buffer, message_size, (struct sockaddr *)&addr, &addr_len, &sndrcvinfo, &flags); + } else { + if ((recvmsg_result = recv(pnf->p5_sock, read_buffer, message_size, flags)) <= 0) { + recvmsg_result = -1; + } + } + if (recvmsg_result == -1) { + int tmp = errno; + NFAPI_TRACE(NFAPI_TRACE_INFO, "Failed to read sctp message size error %s errno:%d\n", strerror(tmp), tmp); + } else { +#if 0 + // print the received message + printf("\n MESSAGE RECEIVED: \n"); + for(int i=0; ip5_sock, + inet_ntoa(addr.sin_addr), + ntohs(addr.sin_port), + sndrcvinfo.sinfo_assoc_id, + sndrcvinfo.sinfo_stream, + ntohl(sndrcvinfo.sinfo_ppid), + message_size, + flags); + */ + + // handle now if complete message in one or more segments + if ((flags & 0x80) == 0x80 || !pnf->sctp) { + pnf_nr_handle_p5_message(pnf, read_buffer, message_size); + } else { + int tmp = errno; + NFAPI_TRACE(NFAPI_TRACE_WARN, + "sctp_recvmsg: unhandled mode with flags 0x%x and error %s errno:%d\n", + flags, + strerror(tmp), + tmp); + // assume socket disconnected + NFAPI_TRACE(NFAPI_TRACE_WARN, "Disconnected socket\n"); + socket_connected = 0; + } + } + } + } + + if (dynamic_buffer) { + free(dynamic_buffer); + } + + return socket_connected; +} + +int pnf_nr_message_pump(pnf_t *pnf) +{ + uint8_t socketConnected = 1; + + while (socketConnected && pnf->terminate == 0) { + fd_set rfds; + int selectRetval = 0; + + // select on a timeout and then get the message + FD_ZERO(&rfds); + FD_SET(pnf->p5_sock, &rfds); + + struct timeval timeout; + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + selectRetval = select(pnf->p5_sock + 1, &rfds, NULL, NULL, &timeout); + + if (selectRetval == 0) { + // timeout + continue; + } else if (selectRetval == -1 && (errno == EINTR)) { + // interrupted by signal + NFAPI_TRACE(NFAPI_TRACE_WARN, "P5 Signal Interrupt %d\n", errno); + continue; + } else if (selectRetval == -1) { + NFAPI_TRACE(NFAPI_TRACE_WARN, "P5 select() failed\n"); + sleep(1); + continue; + } + + if (FD_ISSET(pnf->p5_sock, &rfds)) { + socketConnected = pnf_nr_read_dispatch_message(pnf); + } else { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Why are we here\n"); + } + } + + // Drop back to idle if we have lost connection + pnf->_public.state = NFAPI_PNF_IDLE; + + // close the connection and socket + if (close(pnf->p5_sock) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "close(sctpSock) failed errno: %d\n", errno); + } + + return 0; +} + +static void pnf_nr_reassemble_nfapi_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t *pnf_p7, uint32_t rx_hr_time) +{ + nfapi_nr_p7_message_header_t messageHeader; + + // validate the input params + if (pRecvMsg == NULL || recvMsgLen < 4 || pnf_p7 == NULL) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "pnf_handle_p7_message: invalid input params (%p %d %p)\n", pRecvMsg, recvMsgLen, pnf_p7); + return; + } + + // unpack the message header + const bool result = + pnf_p7->_public.hdr_unpack_func(pRecvMsg, recvMsgLen, &messageHeader, sizeof(messageHeader), &pnf_p7->_public.codec_config); + if (!result) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return; + } + + uint8_t m = NFAPI_P7_GET_MORE(messageHeader.m_segment_sequence); + uint8_t sequence_num = NFAPI_P7_GET_SEQUENCE(messageHeader.m_segment_sequence); + uint8_t segment_num = NFAPI_P7_GET_SEGMENT(messageHeader.m_segment_sequence); + + if (pnf_p7->_public.checksum_enabled) { + uint32_t checksum = nfapi_nr_p7_calculate_checksum(pRecvMsg, recvMsgLen); + if (checksum != messageHeader.checksum) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Checksum verification failed %d %d\n", checksum, messageHeader.checksum); + return; + } + } + + if (m == 0 && segment_num == 0) { + // we have a complete message + // ensure the message is sensible + if (recvMsgLen < 8 || pRecvMsg == NULL) { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Invalid message size: %d, ignoring\n", recvMsgLen); + return; + } + + pnf_nr_handle_p7_message(pRecvMsg, recvMsgLen, pnf_p7, rx_hr_time); + } else { + pnf_p7_rx_message_t *rx_msg = pnf_p7_rx_reassembly_queue_add_segment(pnf_p7, + &(pnf_p7->reassembly_queue), + rx_hr_time, + sequence_num, + segment_num, + m, + pRecvMsg, + recvMsgLen); + + if (rx_msg->num_segments_received == rx_msg->num_segments_expected) { + // send the buffer on + uint16_t i = 0; + uint32_t length = 0; + for (i = 0; i < rx_msg->num_segments_expected; ++i) { + length += rx_msg->segments[i].length - (i > 0 ? NFAPI_NR_P7_HEADER_LENGTH : 0); + } + + if (pnf_p7->reassemby_buffer_size < length) { + pnf_p7_free(pnf_p7, pnf_p7->reassemby_buffer); + pnf_p7->reassemby_buffer = 0; + } + + if (pnf_p7->reassemby_buffer == 0) { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Resizing PNF_P7 Reassembly buffer %d->%d\n", pnf_p7->reassemby_buffer_size, length); + pnf_p7->reassemby_buffer = (uint8_t *)pnf_p7_malloc(pnf_p7, length); + + if (pnf_p7->reassemby_buffer == 0) { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Failed to allocate PNF_P7 reassemby buffer len:%d\n", length); + return; + } + memset(pnf_p7->reassemby_buffer, 0, length); + pnf_p7->reassemby_buffer_size = length; + } + + uint32_t offset = 0; + for (i = 0; i < rx_msg->num_segments_expected; ++i) { + if (i == 0) { + memcpy(pnf_p7->reassemby_buffer, rx_msg->segments[i].buffer, rx_msg->segments[i].length); + offset += rx_msg->segments[i].length; + } else { + memcpy(pnf_p7->reassemby_buffer + offset, + rx_msg->segments[i].buffer + NFAPI_NR_P7_HEADER_LENGTH, + rx_msg->segments[i].length - NFAPI_NR_P7_HEADER_LENGTH); + offset += rx_msg->segments[i].length - NFAPI_NR_P7_HEADER_LENGTH; + } + } + + pnf_nr_handle_p7_message(pnf_p7->reassemby_buffer, length, pnf_p7, rx_msg->rx_hr_time); + + // delete the structure + pnf_p7_rx_reassembly_queue_remove_msg(pnf_p7, &(pnf_p7->reassembly_queue), rx_msg); + } + } + + // The timeout used to be 1000, i.e., 1ms, which is too short. The below 10ms + // is selected to be able to encompass any "reasonable" slot ahead time for the VNF. + // Ideally, we would remove old msg (segments) if we detect packet loss + // (e.g., if the sequence numbers advances sufficiently); in the branch of + // this commit, our goal is to make the PNF work, so we content ourselves to + // just remove very old messages. + pnf_p7_rx_reassembly_queue_remove_old_msgs(pnf_p7, &(pnf_p7->reassembly_queue), rx_hr_time, 10000); +} + +static void pnf_nr_nfapi_p7_read_dispatch_message(pnf_p7_t *pnf_p7, uint32_t now_hr_time) +{ + int recvfrom_result = 0; + struct sockaddr_in remote_addr; + socklen_t remote_addr_size = sizeof(remote_addr); + remote_addr.sin_family = 2; // hardcoded + do { + // peek the header + uint8_t header_buffer[NFAPI_NR_P7_HEADER_LENGTH]; + recvfrom_result = recvfrom(pnf_p7->p7_sock, + header_buffer, + NFAPI_NR_P7_HEADER_LENGTH, + MSG_DONTWAIT | MSG_PEEK, + (struct sockaddr *)&remote_addr, + &remote_addr_size); + if (recvfrom_result > 0) { + // get the segment size + nfapi_nr_p7_message_header_t header; + pnf_p7->_public.hdr_unpack_func(header_buffer, NFAPI_NR_P7_HEADER_LENGTH, &header, 34, 0); + + // resize the buffer if we have a large segment + if (header.message_length > pnf_p7->rx_message_buffer_size) { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "reallocing rx buffer %d\n", header.message_length); + pnf_p7->rx_message_buffer = realloc(pnf_p7->rx_message_buffer, header.message_length); + pnf_p7->rx_message_buffer_size = header.message_length; + } + + // read the segment + recvfrom_result = recvfrom(pnf_p7->p7_sock, + pnf_p7->rx_message_buffer, + header.message_length, + MSG_DONTWAIT, + (struct sockaddr *)&remote_addr, + &remote_addr_size); + + now_hr_time = pnf_get_current_time_hr(); // moved to here - get closer timestamp??? + + if (recvfrom_result > 0) { + pnf_nr_reassemble_nfapi_p7_message(pnf_p7->rx_message_buffer, recvfrom_result, pnf_p7, now_hr_time); + // printf("\npnf_handle_p7_message sfn=%d,slot=%d\n",pnf_p7->sfn,pnf_p7->slot); + } + } else if (recvfrom_result == 0) { + // recv zero length message + recvfrom_result = + recvfrom(pnf_p7->p7_sock, header_buffer, 0, MSG_DONTWAIT, (struct sockaddr *)&remote_addr, &remote_addr_size); + } + + if (recvfrom_result == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // return to the select + // NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom would block :%d\n", __FUNCTION__, errno); + } else { + NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom failed errno:%d\n", __FUNCTION__, errno); + } + } + + // need to update the time as we would only use the value from the + // select + } while (recvfrom_result > 0); +} + +int pnf_nr_p7_message_pump(pnf_p7_t *pnf_p7) +{ + // initialize the mutex lock + if (pthread_mutex_init(&(pnf_p7->mutex), NULL) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 mutex init: %d\n", errno); + return -1; + } + + if (pthread_mutex_init(&(pnf_p7->pack_mutex), NULL) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 mutex init: %d\n", errno); + return -1; + } + + // create the pnf p7 socket + if ((pnf_p7->p7_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 socket errno: %d\n", errno); + return -1; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 socket created (%d)...\n", pnf_p7->p7_sock); + + // configure the UDP socket options + int reuseaddr_enable = 1; + if (setsockopt(pnf_p7->p7_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_enable, sizeof(int)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (SOL_SOCKET, SO_REUSEADDR) failed errno: %d\n", errno); + return -1; + } + + /* + int reuseport_enable = 1; + if (setsockopt(pnf_p7->p7_sock, SOL_SOCKET, SO_REUSEPORT, &reuseport_enable, sizeof(int)) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (SOL_SOCKET, SO_REUSEPORT) failed errno: %d\n", errno); + return -1; + } + */ + + int iptos_value = 0; + if (setsockopt(pnf_p7->p7_sock, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (IPPROTO_IP, IP_TOS) failed errno: %d\n", errno); + return -1; + } + + struct sockaddr_in addr = {0}; + addr.sin_family = AF_INET; + addr.sin_port = htons(pnf_p7->_public.local_p7_port); + + if (pnf_p7->_public.local_p7_addr == 0) { + addr.sin_addr.s_addr = INADDR_ANY; + } else { + // addr.sin_addr.s_addr = inet_addr(pnf_p7->_public.local_p7_addr); + if (inet_aton(pnf_p7->_public.local_p7_addr, &addr.sin_addr) == -1) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "inet_aton failed\n"); + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 binding %d too %s:%d\n", pnf_p7->p7_sock, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + if (bind(pnf_p7->p7_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF_P7 bind error fd:%d errno: %d\n", pnf_p7->p7_sock, errno); + return -1; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 bind succeeded...\n"); + + // Initializaing timing structures needed for slot ticking + + struct timespec slot_start; + clock_gettime(CLOCK_MONOTONIC, &slot_start); + + struct timespec pselect_start; + + struct timespec slot_duration; + slot_duration.tv_sec = 0; + slot_duration.tv_nsec = 0.5e6; + + // Infinite loop + + while (pnf_p7->terminate == 0) { + fd_set rfds; + int selectRetval = 0; + + // select on a timeout and then get the message + FD_ZERO(&rfds); + FD_SET(pnf_p7->p7_sock, &rfds); + + struct timespec timeout; + timeout.tv_sec = 100; + timeout.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &pselect_start); + + // setting the timeout + + if ((pselect_start.tv_sec > slot_start.tv_sec) + || ((pselect_start.tv_sec == slot_start.tv_sec) && (pselect_start.tv_nsec > slot_start.tv_nsec))) { + // overran the end of the subframe we do not want to wait + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + + // struct timespec overrun = pnf_timespec_sub(pselect_start, sf_start); + // NFAPI_TRACE(NFAPI_TRACE_INFO, "Subframe overrun detected of %d.%d running to catchup\n", overrun.tv_sec, overrun.tv_nsec); + } else { + // still time before the end of the subframe wait + timeout = pnf_timespec_sub(slot_start, pselect_start); + } + + selectRetval = pselect(pnf_p7->p7_sock + 1, &rfds, NULL, NULL, &timeout, NULL); + + uint32_t now_hr_time = pnf_get_current_time_hr(); + + if (selectRetval == 0) { + // timeout + + // update slot start timing + slot_start = pnf_timespec_add(slot_start, slot_duration); + + // increment sfn/slot + if (++pnf_p7->slot == 20) { + pnf_p7->slot = 0; + pnf_p7->sfn = (pnf_p7->sfn + 1) % 1024; + } + + continue; + } else if (selectRetval == -1 && (errno == EINTR)) { + // interrupted by signal + NFAPI_TRACE(NFAPI_TRACE_WARN, "PNF P7 Signal Interrupt %d\n", errno); + continue; + } else if (selectRetval == -1) { + NFAPI_TRACE(NFAPI_TRACE_WARN, "PNF P7 select() failed\n"); + sleep(1); + continue; + } + + if (FD_ISSET(pnf_p7->p7_sock, &rfds)) + + { + pnf_nr_nfapi_p7_read_dispatch_message(pnf_p7, now_hr_time); + } + } + NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF_P7 Terminating..\n"); + + // close the connection and socket + if (close(pnf_p7->p7_sock) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "close failed errno: %d\n", errno); + } + + if (pthread_mutex_destroy(&(pnf_p7->pack_mutex)) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "mutex destroy failed errno: %d\n", errno); + } + + if (pthread_mutex_destroy(&(pnf_p7->mutex)) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "mutex destroy failed errno: %d\n", errno); + } + + return 0; +} + +static int nfapi_nr_pnf_p7_start(nfapi_pnf_p7_config_t *config) +{ + // Verify that config is not null + if (config == 0) + return -1; + + pnf_p7_t *_this = (pnf_p7_t *)(config); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + + pnf_nr_p7_message_pump(_this); + + return 0; +} + +void *pnf_nr_p7_thread_start(void *ptr) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[NR_PNF] NR P7 THREAD %s\n", __FUNCTION__); + nfapi_pnf_p7_config_t *config = (nfapi_pnf_p7_config_t *)ptr; + nfapi_nr_pnf_p7_start(config); + return 0; +} diff --git a/nfapi/oai_integration/socket/socket_vnf.c b/nfapi/oai_integration/socket/socket_vnf.c new file mode 100644 index 0000000000..6440109ed6 --- /dev/null +++ b/nfapi/oai_integration/socket/socket_vnf.c @@ -0,0 +1,847 @@ +/* + * 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 "socket_vnf.h" + +#include "nfapi.h" +#include "nfapi/oai_integration/vendor_ext.h" //TODO: Remove this include when removing the Aerial transport stuff + +static bool send_p5_msg(vnf_t *vnf, nfapi_vnf_pnf_info_t *pnf, const void *msg, int len, uint8_t stream) +{ + int result = socket_send_p5_msg(vnf->sctp, pnf->p5_sock, &pnf->p5_pnf_sockaddr, msg, len, stream); + + if (result != len) { + if (result < 0) { + // error + NFAPI_TRACE(NFAPI_TRACE_ERROR, "sctp sendto failed errno: %d\n", errno); + } else { + // did not send the entire message + } + } + return result == len; +} + +bool vnf_nr_send_p5_msg(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) +{ + nfapi_vnf_pnf_info_t *pnf = nfapi_vnf_pnf_list_find(&(vnf->_public), p5_idx); + + if (pnf) { + // pack the message for transmission + int packedMessageLength = 0; + + packedMessageLength = + vnf->_public.pack_func(msg, msg_len, vnf->tx_message_buffer, sizeof(vnf->tx_message_buffer), &vnf->_public.codec_config); + + if (packedMessageLength < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_nr_p5_message_pack failed with return %d\n", packedMessageLength); + return false; + } + + return send_p5_msg(vnf, pnf, vnf->tx_message_buffer, packedMessageLength, 0); + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find pnf info for p5_idx:%d\n", __FUNCTION__, p5_idx); + return false; + } +} + +bool vnf_nr_send_p7_msg(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *header) +{ + nfapi_vnf_p7_connection_info_t *p7_connection = vnf_p7_connection_info_list_find(vnf_p7, header->phy_id); + if (p7_connection) { + int send_result = 0; + uint8_t buffer[1024 * 1024 * 3]; + + header->m_segment_sequence = NFAPI_NR_P7_SET_MSS(0, 0, p7_connection->sequence_number); + + int len = vnf_p7->_public.pack_func(header, buffer, sizeof(buffer), &vnf_p7->_public.codec_config); + + if (len < 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() failed to pack p7 message phy_id:%d\n", __FUNCTION__, header->phy_id); + return false; + } + + if (len > vnf_p7->_public.segment_size) { + // todo : consider replacing with the sendmmsg call + // todo : worry about blocking writes? + + // segmenting the transmit + int msg_body_len = len - NFAPI_NR_P7_HEADER_LENGTH; + int seg_body_len = vnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; + int segment_count = (msg_body_len / (seg_body_len)) + ((msg_body_len % seg_body_len) ? 1 : 0); + + int segment = 0; + int offset = NFAPI_NR_P7_HEADER_LENGTH; + uint8_t tx_buffer[vnf_p7->_public.segment_size]; + NFAPI_TRACE(NFAPI_TRACE_DEBUG, + "%s() MORE THAN ONE SEGMENT phy_id:%d nfapi_p7_message_pack()=len=%d vnf_p7->_public.segment_size:%u\n", + __FUNCTION__, + header->phy_id, + len, + vnf_p7->_public.segment_size); + for (segment = 0; segment < segment_count; ++segment) { + uint8_t last = 0; + uint16_t size = vnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; + if (segment + 1 == segment_count) { + last = 1; + size = (msg_body_len) - (seg_body_len * segment); + } + + uint32_t segment_size = size + NFAPI_NR_P7_HEADER_LENGTH; + + // Update the header with the m and segement + memcpy(&tx_buffer[0], buffer, NFAPI_NR_P7_HEADER_LENGTH); + + // set the segment length, update and push m_segment_sequence + uint8_t *buf_ptr = &tx_buffer[4]; + uint8_t *buf_ptr_end = &tx_buffer[10]; + push32(segment_size, (&buf_ptr), buf_ptr_end); + header->m_segment_sequence = NFAPI_NR_P7_SET_MSS((!last), segment, p7_connection->sequence_number); + push16(header->m_segment_sequence, (&buf_ptr), buf_ptr_end); + + memcpy(&tx_buffer[NFAPI_NR_P7_HEADER_LENGTH], &buffer[0] + offset, size); + offset += size; + + if (vnf_p7->_public.checksum_enabled) { + nfapi_nr_p7_update_checksum(tx_buffer, segment_size); + } + const uint32_t time = + calculate_transmit_timestamp(p7_connection->mu, p7_connection->sfn, p7_connection->slot, vnf_p7->slot_start_time_hr); + nfapi_nr_p7_update_transmit_timestamp(tx_buffer, time); + send_result = socket_send_p7_msg(vnf_p7->socket, &(p7_connection->remote_addr), &tx_buffer[0], segment_size); + } + } else { + if (vnf_p7->_public.checksum_enabled) { + nfapi_nr_p7_update_checksum(buffer, len); + } + const uint32_t time = + calculate_transmit_timestamp(p7_connection->mu, p7_connection->sfn, p7_connection->slot, vnf_p7->slot_start_time_hr); + nfapi_nr_p7_update_transmit_timestamp(buffer, time); + send_result = socket_send_p7_msg(vnf_p7->socket, &(p7_connection->remote_addr), &buffer[0], len); + } + p7_connection->sequence_number++; + return send_result == 0; + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find p7 connection info for phy_id:%d\n", __FUNCTION__, header->phy_id); + return false; + } +} + +static int vnf_nr_read_dispatch_message(nfapi_vnf_config_t *config, nfapi_vnf_pnf_info_t *pnf) +{ + if (1) { + int socket_connected = 1; + vnf_t *vnf = (vnf_t *)(config); + // 1. Peek the message header + // 2. If the message is larger than the stack buffer then create a dynamic buffer + // 3. Read the buffer + // 4. Handle the p5 message + + uint32_t header_buffer_size = NFAPI_NR_P5_HEADER_LENGTH; + uint8_t header_buffer[header_buffer_size]; + + uint32_t stack_buffer_size = 32; // should it be the size of then sctp_notificatoin structure + uint8_t stack_buffer[stack_buffer_size]; + + uint8_t *dynamic_buffer = 0; + + uint8_t *read_buffer = &stack_buffer[0]; + uint32_t message_size = 0; + + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + struct sctp_sndrcvinfo sndrcvinfo; + (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); + + { + int flags = MSG_PEEK; + if (vnf->sctp) { + message_size = + sctp_recvmsg(pnf->p5_sock, header_buffer, header_buffer_size, (struct sockaddr *)&addr, &addr_len, &sndrcvinfo, &flags); + } else { + message_size = recv(pnf->p5_sock, header_buffer, header_buffer_size, flags); + } + + if (message_size == -1) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to peek sctp message size errno:%d\n", errno); + return 0; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Peeked message with length :0x%02x\n", message_size); + + for (int i = 0; i < message_size; i++) { + printf("%02x ", header_buffer[i]); + } + printf("\n"); + + nfapi_nr_p4_p5_message_header_t header; + const bool result = config->hdr_unpack_func(header_buffer, header_buffer_size, &header, sizeof(header), 0); + if (!result) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to decode message header\n"); + return 0; + } + message_size = header.message_length + header_buffer_size; + + // now have the size of the mesage + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF After header unpacking msg size is :0x%02x\n", message_size); + } + + if (message_size > stack_buffer_size) { + dynamic_buffer = (uint8_t *)malloc(message_size); + + if (dynamic_buffer == NULL) { + // todo : add error mesage + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to allocate dynamic buffer for sctp_recvmsg size:%d\n", message_size); + return -1; + } + + read_buffer = dynamic_buffer; + } + + { + int flags = 0; + (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); + + ssize_t recvmsg_result = 0; + if (vnf->sctp) { + recvmsg_result = + sctp_recvmsg(pnf->p5_sock, read_buffer, message_size, (struct sockaddr *)&addr, &addr_len, &sndrcvinfo, &flags); + } else { + recvmsg_result = recv(pnf->p5_sock, read_buffer, message_size, 0); + } + + if (recvmsg_result == -1) { + int tmp = errno; + NFAPI_TRACE(NFAPI_TRACE_INFO, "Failed to read sctp message size error %s errno:%d\n", strerror(tmp), tmp); + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF after recv flags are :0x%02x\n", flags); + + if (flags & MSG_NOTIFICATION) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Notification received from %s:%u\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + + // todo - handle the events + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, + "Received message fd:%d from %s:%u assoc:%d on stream %d, PPID %d, length %d, flags 0x%x\n", + pnf->p5_sock, + inet_ntoa(addr.sin_addr), + ntohs(addr.sin_port), + sndrcvinfo.sinfo_assoc_id, + sndrcvinfo.sinfo_stream, + ntohl(sndrcvinfo.sinfo_ppid), + message_size, + flags); + + // handle now if complete message in one or more segments + if ((flags & 0x80) == 0x80 || !vnf->sctp) { + vnf_nr_handle_p4_p5_message(read_buffer, message_size, pnf->p5_idx, config); + } else { + int tmp = errno; + NFAPI_TRACE(NFAPI_TRACE_WARN, + "sctp_recvmsg: unhandled mode with flags 0x%x and error %s errno:%d\n", + flags, + strerror(tmp), + tmp); + // assume socket disconnected + NFAPI_TRACE(NFAPI_TRACE_WARN, "Disconnected socket\n"); + socket_connected = 0; + } + } + } + } + + if (dynamic_buffer) { + free(dynamic_buffer); + } + + return socket_connected; + } +} + +static int nfapi_nr_vnf_p5_start(nfapi_vnf_config_t *config) +{ + // Verify that config is not null + if (config == 0) + return -1; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); + + int p5ListenSock, p5Sock; + + struct sockaddr_in addr = {0}; + socklen_t addrSize; + + struct sockaddr_in6 addr6 = {0}; + + struct sctp_event_subscribe events = {0}; + struct sctp_initmsg initMsg = {0}; + int noDelay; + + vnf_t *vnf = (vnf_t *)(config); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Starting P5 VNF connection on port %u\n", config->vnf_p5_port); + + { + int protocol; + int domain; + + if (vnf->sctp) + protocol = IPPROTO_SCTP; + else + protocol = IPPROTO_IP; + + if (config->vnf_ipv6) { + domain = PF_INET6; + } else { + domain = AF_INET; + } + + // open the SCTP socket + if ((p5ListenSock = socket(domain, SOCK_STREAM, protocol)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P5 socket errno: %d\n", errno); + return 0; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "P5 socket created... %d\n", p5ListenSock); + } + + if (vnf->sctp) { + // configure for MSG_NOTIFICATION + if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(struct sctp_event_subscribe)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_EVENTS) errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + NFAPI_TRACE(NFAPI_TRACE_NOTE, "VNF Setting the SCTP_INITMSG\n"); + // configure the SCTP socket options + initMsg.sinit_num_ostreams = 5; // MAX_SCTP_STREAMS; // number of output streams can be greater + initMsg.sinit_max_instreams = 5; // MAX_SCTP_STREAMS; // number of output streams can be greater + if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_INITMSG) errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + noDelay = 1; + if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_NODELAY, &noDelay, sizeof(noDelay)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (STCP_NODELAY) errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + struct sctp_event_subscribe events; + memset((void *)&events, 0, sizeof(events)); + events.sctp_data_io_event = 1; + + if (setsockopt(p5ListenSock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); + close(p5ListenSock); + return -1; + } + } else { + int error; + socklen_t len = sizeof(error); + + if (getsockopt(p5ListenSock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno); + close(p5ListenSock); + return -1; + } + } + + if (config->vnf_ipv6) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "IPV6 binding to port %d %d\n", config->vnf_p5_port, p5ListenSock); + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(config->vnf_p5_port); + addr6.sin6_addr = in6addr_any; + + // bind to the configured address and port + if (bind(p5ListenSock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + } else if (config->vnf_ipv4) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "IPV4 binding to port %d\n", config->vnf_p5_port); + addr.sin_family = AF_INET; + addr.sin_port = htons(config->vnf_p5_port); + addr.sin_addr.s_addr = INADDR_ANY; + + // bind to the configured address and port + if (bind(p5ListenSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); + close(p5ListenSock); + AssertFatal(1 == 0, "Failed to bind socket with errno: %d\n", errno); + return 0; + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "bind succeeded..%d.\n", p5ListenSock); + + // put the socket into listen mode + if (listen(p5ListenSock, 2) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After listen errno: %d\n", errno); + close(p5ListenSock); + return 0; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "listen succeeded...\n"); + + struct timeval tv; + fd_set read_fd_set; + + int p5_idx = 0; + while (vnf->terminate == 0) { + FD_ZERO(&read_fd_set); + + FD_SET(p5ListenSock, &read_fd_set); + int max_fd = p5ListenSock; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + nfapi_vnf_pnf_info_t *pnf = config->pnf_list; + while (pnf != 0) { + if (pnf->connected) { + FD_SET(pnf->p5_sock, &read_fd_set); + if (pnf->p5_sock > max_fd) { + max_fd = pnf->p5_sock; + } + } + + pnf = pnf->next; + } + + int select_result = select(max_fd + 1, &read_fd_set, 0, 0, &tv); + + if (select_result == -1) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "select result %d errno %d\n", select_result, errno); + close(p5ListenSock); + return 0; + } else if (select_result) { + if (FD_ISSET(p5ListenSock, &read_fd_set)) { + addrSize = sizeof(struct sockaddr_in); + NFAPI_TRACE(NFAPI_TRACE_INFO, "Accepting connection from PNF...\n"); + + p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); + + if (p5Sock < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to accept PNF connection reason:%d\n", errno); + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, + "PNF connection (fd:%d) accepted from %s:%d \n", + p5Sock, + inet_ntoa(addr.sin_addr), + ntohs(addr.sin_port)); + nfapi_vnf_pnf_info_t *pnf = (nfapi_vnf_pnf_info_t *)malloc(sizeof(nfapi_vnf_pnf_info_t)); + NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf); + memset(pnf, 0, sizeof(nfapi_vnf_pnf_info_t)); + pnf->p5_sock = p5Sock; + pnf->p5_idx = p5_idx++; + pnf->p5_pnf_sockaddr = addr; + pnf->connected = 1; + + nfapi_vnf_pnf_list_add(config, pnf); + + // Inform mac that a pnf connection has been established + // todo : allow mac to 'accept' the connection. i.e. to + // reject it. + if (config->pnf_nr_connection_indication != 0) { + (config->pnf_nr_connection_indication)(config, pnf->p5_idx); + } + + // check the connection status + if (vnf->sctp) { + struct sctp_status status; + (void)memset(&status, 0, sizeof(struct sctp_status)); + socklen_t optLen = (socklen_t)sizeof(struct sctp_status); + if (getsockopt(p5Sock, IPPROTO_SCTP, SCTP_STATUS, &status, &optLen) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno); + return -1; + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Association ID = %d\n", status.sstat_assoc_id); + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Receiver window size = %d\n", status.sstat_rwnd); + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF In Streams = %d\n", status.sstat_instrms); + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Out Streams = %d\n", status.sstat_outstrms); + } + } + } + } else { + uint8_t delete_pnfs = 0; + + nfapi_vnf_pnf_info_t *pnf = config->pnf_list; + while (pnf != 0) { + if (FD_ISSET(pnf->p5_sock, &read_fd_set)) { + if (vnf_nr_read_dispatch_message(config, pnf) == 0) { + if (config->pnf_disconnect_indication != 0) { + (config->pnf_disconnect_indication)(config, pnf->p5_idx); + } + + close(pnf->p5_sock); + + pnf->to_delete = 1; + delete_pnfs = 1; + } + } + + pnf = pnf->next; + } + + if (delete_pnfs) { + nfapi_vnf_pnf_info_t *pnf = config->pnf_list; + nfapi_vnf_pnf_info_t *prev = 0; + while (pnf != 0) { + nfapi_vnf_pnf_info_t *curr = pnf; + + if (pnf->to_delete == 1) { + if (prev == 0) { + config->pnf_list = pnf->next; + } else { + prev->next = pnf->next; + } + + pnf = pnf->next; + + free(curr); + } else { + prev = pnf; + pnf = pnf->next; + } + } + } + } + + continue; + } else { + // timeout + + // Should we test for socket closure here every second? + + continue; + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p5Sock socket's\n"); + { + nfapi_vnf_pnf_info_t *curr = config->pnf_list; + while (curr != NULL) { + if (config->pnf_disconnect_indication) { + (config->pnf_disconnect_indication)(config, curr->p5_idx); + } + + close(curr->p5_sock); + curr = curr->next; + } + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p5Listen socket\n"); + close(p5ListenSock); + + return 0; +} + +void vnf_start_p5_thread(void *ptr) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] VNF NFAPI thread - nfapi_vnf_start()%s\n", __FUNCTION__); + pthread_setname_np(pthread_self(), "VNF"); + nfapi_nr_vnf_p5_start((nfapi_vnf_config_t *)ptr); +} + +void vnf_nr_reassemble_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t *vnf_p7) +{ + nfapi_nr_p7_message_header_t messageHeader; + + // validate the input params + if (pRecvMsg == NULL || recvMsgLen < 4 || vnf_p7 == NULL) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_p7_message: invalid input params (%p %d %p)\n", pRecvMsg, recvMsgLen, vnf_p7); + return; + } + + // unpack the message header + const bool result = + vnf_p7->_public.hdr_unpack_func(pRecvMsg, recvMsgLen, &messageHeader, sizeof(messageHeader), &vnf_p7->_public.codec_config); + if (!result) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return; + } + + if (vnf_p7->_public.checksum_enabled) { + uint32_t checksum = nfapi_nr_p7_calculate_checksum(pRecvMsg, recvMsgLen); + if (checksum != messageHeader.checksum) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "Checksum verification failed %d %d msg:%d len:%d\n", + checksum, + messageHeader.checksum, + messageHeader.message_id, + recvMsgLen); + return; + } + } + + uint8_t m = NFAPI_P7_GET_MORE(messageHeader.m_segment_sequence); + uint8_t segment_num = NFAPI_P7_GET_SEGMENT(messageHeader.m_segment_sequence); + uint8_t sequence_num = NFAPI_P7_GET_SEQUENCE(messageHeader.m_segment_sequence); + + if (m == 0 && segment_num == 0) { + // we have a complete message + // ensure the message is sensible + if (recvMsgLen < 8 || pRecvMsg == NULL) { + NFAPI_TRACE(NFAPI_TRACE_WARN, "Invalid message size: %d, ignoring\n", recvMsgLen); + return; + } + + // vnf_dispatch_p7_message(&messageHeader, pRecvMsg, recvMsgLen, vnf_p7); + vnf_nr_handle_p7_message(pRecvMsg, recvMsgLen, vnf_p7); + } else { + nfapi_vnf_p7_connection_info_t *phy = vnf_p7_connection_info_list_find(vnf_p7, messageHeader.phy_id); + + if (phy) { + vnf_p7_rx_message_t *rx_msg = vnf_p7_rx_reassembly_queue_add_segment(vnf_p7, + &(phy->reassembly_queue), + sequence_num, + segment_num, + m, + pRecvMsg, + recvMsgLen); + + if (rx_msg->num_segments_received == rx_msg->num_segments_expected) { + // send the buffer on + uint16_t i = 0; + uint16_t length = 0; + for (i = 0; i < rx_msg->num_segments_expected; ++i) { + length += rx_msg->segments[i].length - (i > 0 ? NFAPI_NR_P7_HEADER_LENGTH : 0); + } + + if (phy->reassembly_buffer_size < length) { + vnf_p7_free(vnf_p7, phy->reassembly_buffer); + phy->reassembly_buffer = 0; + } + + if (phy->reassembly_buffer == 0) { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Resizing VNF_P7 Reassembly buffer %d->%d\n", phy->reassembly_buffer_size, length); + phy->reassembly_buffer = (uint8_t *)vnf_p7_malloc(vnf_p7, length); + + if (phy->reassembly_buffer == 0) { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "Failed to allocate VNF_P7 reassemby buffer len:%d\n", length); + return; + } + memset(phy->reassembly_buffer, 0, length); + phy->reassembly_buffer_size = length; + } + + uint16_t offset = 0; + for (i = 0; i < rx_msg->num_segments_expected; ++i) { + if (i == 0) { + memcpy(phy->reassembly_buffer, rx_msg->segments[i].buffer, rx_msg->segments[i].length); + offset += rx_msg->segments[i].length; + } else { + memcpy(phy->reassembly_buffer + offset, + rx_msg->segments[i].buffer + NFAPI_NR_P7_HEADER_LENGTH, + rx_msg->segments[i].length - NFAPI_NR_P7_HEADER_LENGTH); + offset += rx_msg->segments[i].length - NFAPI_NR_P7_HEADER_LENGTH; + } + } + + vnf_nr_handle_p7_message(phy->reassembly_buffer, length, vnf_p7); + + // delete the structure + vnf_p7_rx_reassembly_queue_remove_msg(vnf_p7, &(phy->reassembly_queue), rx_msg); + } + + // see corresponding comment in pnf_nr_handle_p7_message() [same commit] + vnf_p7_rx_reassembly_queue_remove_old_msgs(vnf_p7, &(phy->reassembly_queue), 10000); + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Unknown phy id %d\n", messageHeader.phy_id); + } + } +} + +int vnf_nr_p7_read_dispatch_message(vnf_p7_t *vnf_p7) +{ + int recvfrom_result = 0; + struct sockaddr_in remote_addr; + socklen_t remote_addr_size = sizeof(remote_addr); + + do { + // peek the header + uint8_t header_buffer[NFAPI_NR_P7_HEADER_LENGTH]; + recvfrom_result = recvfrom(vnf_p7->socket, + header_buffer, + NFAPI_NR_P7_HEADER_LENGTH, + MSG_DONTWAIT | MSG_PEEK, + (struct sockaddr *)&remote_addr, + &remote_addr_size); + + if (recvfrom_result > 0) { + // get the segment size + nfapi_nr_p7_message_header_t header; + const bool result = vnf_p7->_public.hdr_unpack_func(header_buffer, NFAPI_NR_P7_HEADER_LENGTH, &header, sizeof(header), 0); + if (!result) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); + return -1; + } + + // resize the buffer if we have a large segment + if (header.message_length > vnf_p7->rx_message_buffer_size) { + NFAPI_TRACE(NFAPI_TRACE_NOTE, "reallocing rx buffer %d\n", header.message_length); + vnf_p7->rx_message_buffer = realloc(vnf_p7->rx_message_buffer, header.message_length); + vnf_p7->rx_message_buffer_size = header.message_length; + } + + // read the segment + recvfrom_result = recvfrom(vnf_p7->socket, + vnf_p7->rx_message_buffer, + header.message_length, + MSG_WAITALL | MSG_TRUNC, + (struct sockaddr *)&remote_addr, + &remote_addr_size); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "recvfrom_result = %d from %s():%d\n", recvfrom_result, __FUNCTION__, __LINE__); + + // todo : how to handle incomplete readfroms, need some sort of buffer/select + + if (recvfrom_result > 0) { + if (recvfrom_result != header.message_length) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "(%d) Received unexpected number of bytes. %d != %d", + __LINE__, + recvfrom_result, + header.message_length); + break; + } + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Calling vnf_nr_reassemble_p7_message from %d\n", __LINE__); + vnf_nr_reassemble_p7_message(vnf_p7->rx_message_buffer, recvfrom_result, vnf_p7); + return 0; + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "recvfrom failed %d %d\n", recvfrom_result, errno); + } + } + + if (recvfrom_result == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + // return to the select + } else { + NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom failed errno:%d\n", __FUNCTION__, errno); + } + } + } while (recvfrom_result > 0); + + return 0; +} + +static int nfapi_nr_vnf_p7_start(nfapi_vnf_p7_config_t *config) +{ + if (config == 0) + return -1; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); + + vnf_p7_t *vnf_p7 = (vnf_p7_t *)config; + + // Create p7 receive udp port + // todo : this needs updating for Ipv6 + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Initialising VNF P7 port:%u\n", config->port); + + // open the UDP socket + if ((vnf_p7->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 socket errno: %d\n", errno); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 socket created...\n"); + + // configure the UDP socket options + int iptos_value = 0; + if (setsockopt(vnf_p7->socket, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (IP_TOS) errno: %d\n", errno); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 setsockopt succeeded...\n"); + + // Create the address structure + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(config->port); + addr.sin_addr.s_addr = INADDR_ANY; + + // bind to the configured port + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 binding too %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + if (bind(vnf_p7->socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) + // if (sctp_bindx(config->socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), 0) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); + return -1; + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 bind succeeded...\n"); + + // struct timespec original_pselect_timeout; + struct timespec pselect_timeout; + pselect_timeout.tv_sec = 100; + pselect_timeout.tv_nsec = 0; + + struct timespec ref_time; + clock_gettime(CLOCK_MONOTONIC, &ref_time); + while (vnf_p7->terminate == 0) { + fd_set rfds; + int maxSock = 0; + FD_ZERO(&rfds); + int selectRetval = 0; + + // Add the p7 socket + FD_SET(vnf_p7->socket, &rfds); + maxSock = vnf_p7->socket; + + selectRetval = pselect(maxSock + 1, &rfds, NULL, NULL, &pselect_timeout, NULL); + + if (selectRetval == 0) { + // pselect timed out, continue + } else if (selectRetval > 0) { + // have a p7 message + if (FD_ISSET(vnf_p7->socket, &rfds)) { + vnf_nr_p7_read_dispatch_message(vnf_p7); + } + } else { + // pselect error + if (selectRetval == -1 && errno == EINTR) { + // a sigal was received. + } else { + // should we exit now? + if (selectRetval == -1 && errno == 22) // invalid argument??? not sure about timeout duration + { + usleep(100000); + } + } + } + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p7 socket\n"); + close(vnf_p7->socket); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() returning\n", __FUNCTION__); + + return 0; +} + +void *vnf_nr_start_p7_thread(void *ptr) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); + pthread_setname_np(pthread_self(), "VNF_P7"); + nfapi_vnf_p7_config_t *config = (nfapi_vnf_p7_config_t *)ptr; + nfapi_nr_vnf_p7_start(config); + return config; +} diff --git a/nfapi/oai_integration/wls_integration/CMakeLists.txt b/nfapi/oai_integration/wls_integration/CMakeLists.txt new file mode 100644 index 0000000000..6d225f18b8 --- /dev/null +++ b/nfapi/oai_integration/wls_integration/CMakeLists.txt @@ -0,0 +1,22 @@ +message(STATUS "Building with support for WLS") +add_library(wls_integration_lib + wls_pnf.c + wls_vnf.c + wls_common.c +) + +find_library(WLS_LIB wls REQUIRED) +message(STATUS " wls library found in ${WLS_LIB}") + +find_library(hugetlbfs_LIB hugetlbfs REQUIRED) +message(STATUS " hugetlbfs library found in ${hugetlbfs_LIB}") + +pkg_check_modules(dpdk REQUIRED libdpdk=20.11.3) +target_link_libraries(wls_integration_lib PRIVATE ${dpdk_LINK_LIBRARIES}) +target_include_directories(wls_integration_lib PRIVATE ${dpdk_INCLUDE_DIRS}) +target_include_directories(wls_integration_lib PRIVATE include/) + +target_compile_definitions(wls_integration_lib PUBLIC ENABLE_WLS) +target_link_libraries(wls_integration_lib PRIVATE NFAPI_LIB NFAPI_USER_LIB) +target_link_libraries(wls_integration_lib PRIVATE nr_fapi_p5 nr_fapi_p7) +target_link_libraries(wls_integration_lib PRIVATE "${WLS_LIB}" "${hugetlbfs_LIB}") diff --git a/nfapi/oai_integration/wls_integration/include/wls_common.h b/nfapi/oai_integration/wls_integration/include/wls_common.h new file mode 100644 index 0000000000..1b6a8e4cdf --- /dev/null +++ b/nfapi/oai_integration/wls_integration/include/wls_common.h @@ -0,0 +1,108 @@ +/* +* 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 OPENAIRINTERFACE_WLS_COMMON_H +#define OPENAIRINTERFACE_WLS_COMMON_H + +#include +#include +#include +#include "wls_lib.h" +#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h" +#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h" + +#define WLS_DEV_NAME "wls" +#define WLS_MAC_MEMORY_SIZE 0x7F000000 +#define WLS_PHY_MEMORY_SIZE 0x7F000000 + +#define MAX_NUM_LOCATIONS (508) + +#define MIN_DL_BUF_LOCATIONS (0) /* Used for stats collection 0-49 */ +#define MIN_UL_BUF_LOCATIONS (MIN_DL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 50-99 */ + +#define MAX_DL_BUF_LOCATIONS (MIN_DL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 0-49 */ +#define MAX_UL_BUF_LOCATIONS (MIN_UL_BUF_LOCATIONS + MAX_NUM_LOCATIONS) /* Used for stats collection 50-99 */ + +#define ALLOC_TRACK_SIZE ( 16384 ) + +typedef struct { + uint64_t *values; + uint16_t values_size; + uint16_t values_count; +}pa_store_t; + +/* ----- WLS Operation --- */ +#define FAPI_VENDOR_MSG_HEADER_IND 0x1A +// Linked list header present at the top of all messages +typedef struct _fapi_api_queue_elem { + struct _fapi_api_queue_elem *p_next; + // p_tx_data_elm_list used for TX_DATA.request processing + struct _fapi_api_queue_elem *p_tx_data_elm_list; + uint8_t msg_type; + uint8_t num_message_in_block; + uint32_t msg_len; + uint32_t align_offset; + uint64_t time_stamp; +} fapi_api_queue_elem_t, + *p_fapi_api_queue_elem_t; + + +typedef struct wls_mac_mem_array +{ + void **ppFreeBlock; + void *pStorage; + void *pEndOfStorage; + uint32_t nBlockSize; + uint32_t nBlockCount; +} WLS_MAC_MEM_SRUCT, *PWLS_MAC_MEM_SRUCT; + +typedef struct wls_mac_ctx +{ + void *hWls; + void *pWlsMemBase; + void *pWlsMemBaseUsable; + WLS_MAC_MEM_SRUCT sWlsStruct; + + uint64_t nTotalMemorySize; + uint64_t nTotalMemorySizeUsable; + uint32_t nBlockSize; + uint32_t nTotalBlocks; + uint32_t nAllocBlocks; + uint32_t nTotalAllocCnt; + uint32_t nTotalFreeCnt; + uint32_t nTotalUlBufAllocCnt; + uint32_t nTotalUlBufFreeCnt; + uint32_t nTotalDlBufAllocCnt; + uint32_t nTotalDlBufFreeCnt; + // Support for FAPI Translator + uint32_t nPartitionMemSize; + void *pPartitionMemBase; + + volatile pthread_mutex_t lock; + volatile pthread_mutex_t lock_alloc; +} WLS_MAC_CTX, *PWLS_MAC_CTX; + +void fill_fapi_list_elem(p_fapi_api_queue_elem_t currElem, p_fapi_api_queue_elem_t nextElem, const uint8_t msgType, const uint8_t numMsgInBlock, const uint32_t alignOffset); +uint64_t dequeueBlock(PWLS_MAC_CTX pWls); +void wls_return_msg_to_master(PWLS_MAC_CTX pWls, const uint64_t msg_PA); +uint8_t wls_send_fapi_msg(PWLS_MAC_CTX pWls, const uint16_t message_id, const int packed_len, const uint8_t *message ); +uint8_t wls_msg_send(PWLS_MAC_CTX pWls, p_fapi_api_queue_elem_t currMsg); +#endif //OPENAIRINTERFACE_WLS_COMMON_H diff --git a/nfapi/oai_integration/wls_integration/include/wls_pnf.h b/nfapi/oai_integration/wls_integration/include/wls_pnf.h new file mode 100644 index 0000000000..c678345967 --- /dev/null +++ b/nfapi/oai_integration/wls_integration/include/wls_pnf.h @@ -0,0 +1,33 @@ +/* + * 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 OPENAIRINTERFACE_WLS_PNF_H +#define OPENAIRINTERFACE_WLS_PNF_H +#include "nfapi_pnf_interface.h" +#include "pnf.h" +#include "wls_common.h" + +bool wls_pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len); +bool wls_pnf_nr_send_p7_message(pnf_p7_t* pnf_p7,nfapi_nr_p7_message_header_t *msg, uint32_t msg_len); +void *wls_fapi_pnf_nr_start_thread(void *ptr); +int wls_fapi_nr_pnf_start(); +void wls_pnf_set_p7_config(void *p7_config); +#endif // OPENAIRINTERFACE_WLS_PNF_H diff --git a/nfapi/oai_integration/wls_integration/include/wls_vnf.h b/nfapi/oai_integration/wls_integration/include/wls_vnf.h new file mode 100644 index 0000000000..645b24d056 --- /dev/null +++ b/nfapi/oai_integration/wls_integration/include/wls_vnf.h @@ -0,0 +1,33 @@ +/* +* 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 OPENAIRINTERFACE_WLS_VNF_H +#define OPENAIRINTERFACE_WLS_VNF_H +#include "nfapi_vnf_interface.h" +#include "vnf.h" +#include "wls_common.h" + +void *wls_fapi_vnf_nr_start_thread(void *ptr); +int wls_fapi_nr_vnf_start(); +void wls_vnf_set_p7_config(void *p7_config); +bool wls_vnf_nr_send_p5_message(vnf_t *vnf,uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len); +bool wls_vnf_nr_send_p7_message(vnf_p7_t* vnf_p7,nfapi_nr_p7_message_header_t* msg); +#endif //OPENAIRINTERFACE_WLS_VNF_H diff --git a/nfapi/oai_integration/wls_integration/wls_common.c b/nfapi/oai_integration/wls_integration/wls_common.c new file mode 100644 index 0000000000..fe4112eba8 --- /dev/null +++ b/nfapi/oai_integration/wls_integration/wls_common.c @@ -0,0 +1,118 @@ +/* + * 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 "wls_common.h" + +void fill_fapi_list_elem(p_fapi_api_queue_elem_t currElem, p_fapi_api_queue_elem_t nextElem, const uint8_t msgType, const uint8_t numMsgInBlock, const uint32_t alignOffset) +{ + currElem->msg_type = msgType; + currElem->num_message_in_block = numMsgInBlock; + currElem->align_offset = alignOffset; + currElem->msg_len = numMsgInBlock * alignOffset; + currElem->p_next = nextElem; + currElem->p_tx_data_elm_list = NULL; + currElem->time_stamp = 0; +} + +uint64_t dequeueBlock(PWLS_MAC_CTX pWls) +{ + uint64_t pa = WLS_DequeueBlock(pWls->hWls); + AssertFatal(pa, "WLS_DequeueBlock failed for pa_hdr\n"); + unsigned long* va = WLS_PA2VA(pWls->hWls, pa); + AssertFatal(va, "WLS_PA2VA failed for headerElem\n"); + while (*va != -1) { + pa = WLS_DequeueBlock(pWls->hWls); + AssertFatal(pa, "WLS_DequeueBlock failed for pa_hdr\n"); + va = WLS_PA2VA(pWls->hWls, pa); + } + return pa; +} + +uint8_t wls_msg_send(PWLS_MAC_CTX pWls, p_fapi_api_queue_elem_t currMsg) +{ + uint32_t msgLen = 0; + + AssertFatal(currMsg, "currMsg can't be NULL"); + AssertFatal(currMsg->p_next, "There needs to be at least 2 blocks to send!"); + msgLen = currMsg->msg_len + sizeof(fapi_api_queue_elem_t); + // Send the first block + if (WLS_Put(pWls, WLS_VA2PA(pWls, currMsg), msgLen, currMsg->msg_type, WLS_SG_FIRST) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failure in sending the header block\n"); + return false; + } + // Iterate over the linked list, until a NULL block or a block set to 0xFFFFFFFFFFFFFFFF ( invalid ) + while (((currMsg = currMsg->p_next)) && (uint64_t)(currMsg) != -1) { + msgLen = currMsg->msg_len + sizeof(fapi_api_queue_elem_t); + /* Send the block with appropriate flags, either WLS_SG_NEXT or WLS_SG_LAST */ + const unsigned short flags = currMsg->p_next != NULL ? WLS_SG_NEXT : WLS_SG_LAST; + if (WLS_Put(pWls, WLS_VA2PA(pWls, currMsg), msgLen, currMsg->msg_type, flags) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failure in sending the message block\n"); + return false; + } + } + return true; +} + +void wls_return_msg_to_master(PWLS_MAC_CTX pWls,const uint64_t msg_PA) +{ + p_fapi_api_queue_elem_t fapiMsgElem = WLS_PA2VA(pWls->hWls, msg_PA); + AssertFatal(fapiMsgElem, "WLS_PA2VA failed for fapiMsgElem\n"); + const uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle + // No need to return the message contents, just the block + fill_fapi_list_elem(fapiMsgElem, NULL, FAPI_VENDOR_MSG_HEADER_IND, 1, 2); + memcpy((uint8_t *)(fapiMsgElem + 1), wls_header, 2); + const uint32_t msgLen = fapiMsgElem->msg_len + sizeof(fapi_api_queue_elem_t); + /* Send the block with appropriate only WLS_SG_FIRST flag, since we send only 1 block*/ + if (WLS_Put(pWls->hWls, msg_PA, msgLen, FAPI_VENDOR_MSG_HEADER_IND, WLS_SG_FIRST) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR,"Failure in sending block back to master\n"); + } +} + +uint8_t wls_send_fapi_msg(PWLS_MAC_CTX pWls, const uint16_t message_id, const int packed_len, const uint8_t *message) +{ + int num_avail_blocks = WLS_NumBlocks(pWls->hWls); + NFAPI_TRACE(NFAPI_TRACE_DEBUG,"num_avail_blocks is %d\n", num_avail_blocks); + while (num_avail_blocks < 2) { + num_avail_blocks = WLS_NumBlocks(pWls->hWls); + NFAPI_TRACE(NFAPI_TRACE_DEBUG,"num_avail_blocks is %d\n", num_avail_blocks); + } + /* get PA blocks for header and msg */ + uint64_t pa_hdr = dequeueBlock(pWls); + AssertFatal(pa_hdr, "WLS_DequeueBlock failed for pa_hdr\n"); + uint64_t pa_msg = dequeueBlock(pWls); + AssertFatal(pa_msg, "WLS_DequeueBlock failed for pa_msg\n"); + p_fapi_api_queue_elem_t headerElem = WLS_PA2VA(pWls->hWls, pa_hdr); + AssertFatal(headerElem, "WLS_PA2VA failed for headerElem\n"); + p_fapi_api_queue_elem_t fapiMsgElem = WLS_PA2VA(pWls->hWls, pa_msg); + AssertFatal(fapiMsgElem, "WLS_PA2VA failed for fapiMsgElem\n"); + fill_fapi_list_elem(fapiMsgElem, NULL, message_id, 1, packed_len + NFAPI_HEADER_LENGTH); + memcpy((uint8_t *)(fapiMsgElem + 1), message, packed_len + NFAPI_HEADER_LENGTH); + uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle + if (NFAPI_MODE == NFAPI_MODE_VNF) { + // Use the opaque handle to signal to our PNF to not progress the FAPI PNF state machine + wls_header[1] = 0xff; + } + fill_fapi_list_elem(headerElem, fapiMsgElem, FAPI_VENDOR_MSG_HEADER_IND, 1, 2); + memcpy((uint8_t *)(headerElem + 1), wls_header, 2); + uint8_t retval = wls_msg_send(pWls->hWls, headerElem); + return retval; +} + diff --git a/nfapi/oai_integration/wls_integration/wls_pnf.c b/nfapi/oai_integration/wls_integration/wls_pnf.c new file mode 100644 index 0000000000..bed517ad01 --- /dev/null +++ b/nfapi/oai_integration/wls_integration/wls_pnf.c @@ -0,0 +1,290 @@ +/* + * 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 "wls_pnf.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "pnf.h" +#include "nr_nfapi_p7.h" +#include "nr_fapi_p5.h" + +// A copy of the PNF P7 config is needed for the message processing thread, in other transport mechanisms where P7 is handled in a +// different thread, the config is passed to it upon the thread creation +nfapi_pnf_p7_config_t *wls_pnf_p7_config = NULL; + +void wls_pnf_set_p7_config(void *p7_config) +{ + wls_pnf_p7_config = (nfapi_pnf_p7_config_t *)p7_config; +} + +static WLS_MAC_CTX g_phy_wls; +uint8_t phy_dpdk_init(void); +uint8_t phy_wls_init(const char *dev_name, uint64_t nWlsMacMemSize, uint64_t nWlsPhyMemSize); +void phy_mac_recv(); +void wls_mac_print_stats(void); + +pnf_t *_this = NULL; + +static PWLS_MAC_CTX wls_mac_get_ctx(void) +{ + return &g_phy_wls; +} + +static nfapi_pnf_config_t *cfg; + +void *wls_fapi_pnf_nr_start_thread(void *ptr) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] IN WLS PNF NFAPI start thread %s\n", __FUNCTION__); + cfg = (nfapi_pnf_config_t *)ptr; + wls_fapi_nr_pnf_start(); + return (void *)0; +} + +int wls_fapi_nr_pnf_start() +{ + int64_t ret; + // Verify that config is not null + if (cfg == 0) + return -1; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + + _this = (pnf_t *)(cfg); + _this->terminate = 0; + // Init PNF config + nfapi_pnf_phy_config_t *phy = malloc_or_fail(sizeof(nfapi_pnf_phy_config_t)); + memset(phy, 0, sizeof(nfapi_pnf_phy_config_t)); + + phy->state = NFAPI_PNF_PHY_IDLE; + phy->phy_id = 0; + phy->next = (_this->_public).phys; + (_this->_public).phys = phy; + _this->_public.state = NFAPI_PNF_RUNNING; + + // DPDK init + ret = phy_dpdk_init(); + if (!ret) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "[PNF] DPDK Init - Failed\n"); + return false; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] DPDK Init - Done\n"); + + // WLS init + ret = phy_wls_init(WLS_DEV_NAME, WLS_MAC_MEMORY_SIZE, WLS_PHY_MEMORY_SIZE); + if (!ret) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "[PNF] WLS Init - Failed\n"); + return false; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] WLS Init - Done\n"); + + // Start Receiving loop from the VNF + NFAPI_TRACE(NFAPI_TRACE_INFO, "Start Receiving loop from the VNF\n"); + phy_mac_recv(); + // Should never get here, to be removed, align with present implementation of PNF loop + NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] Exiting...\n"); + + return true; +} + +uint8_t phy_dpdk_init(void) +{ + unsigned long i; + char *argv[] = {"OAI_PNF", "--proc-type=primary", "--file-prefix", WLS_DEV_NAME, "--iova-mode=pa", "--no-pci"}; + int argc = RTE_DIM(argv); + /* initialize EAL first */ + NFAPI_TRACE(NFAPI_TRACE_INFO, "\n[PHY] Calling rte_eal_init: "); + + for (i = 0; i < RTE_DIM(argv); i++) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s ", argv[i]); + } + + NFAPI_TRACE(NFAPI_TRACE_INFO, "\n"); + + if (rte_eal_init(argc, argv) < 0) + rte_panic("Cannot init EAL\n"); + + return true; +} + +uint8_t phy_wls_init(const char *dev_name, uint64_t nWlsMacMemSize, uint64_t nWlsPhyMemSize) +// uint8_t phy_wls_init(const char *dev_name, uint64_t nBlockSize) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + pWls->nTotalAllocCnt = 0; + pWls->nTotalFreeCnt = 0; + pWls->nTotalUlBufAllocCnt = 0; + pWls->nTotalUlBufFreeCnt = 0; + pWls->nTotalDlBufAllocCnt = 0; + pWls->nTotalDlBufFreeCnt = 0; + + pWls->hWls = WLS_Open(dev_name, WLS_SLAVE_CLIENT, &nWlsMacMemSize, &nWlsPhyMemSize); + if (pWls->hWls) { + /* allocate chuck of memory */ + if (WLS_Alloc(pWls->hWls, nWlsMacMemSize + nWlsPhyMemSize) != NULL) { + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "WLS Memory allocated successfully\n"); + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unable to alloc WLS Memory\n"); + return false; + } + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "can't open WLS instance"); + return false; + } + return true; +} + +bool wls_pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) +{ + int packed_len = cfg->pack_func(msg, msg_len, pnf->tx_message_buffer, sizeof(pnf->tx_message_buffer), &pnf->_public.codec_config); + + if (packed_len < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p5_message_pack failed (%d)\n", packed_len); + return false; + } + + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "fapi_nr_p5_message_pack succeeded having packed %d bytes\n", packed_len); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "in msg, msg_len is %d\n", msg->message_length); + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + + return wls_send_fapi_msg(pWls, msg->message_id, packed_len, pnf->tx_message_buffer); +} + +bool wls_pnf_nr_send_p7_message(pnf_p7_t *pnf_p7, nfapi_nr_p7_message_header_t *msg, uint32_t msg_len) +{ + UNUSED_VARIABLE(msg_len); + + if (!isFAPIMessageIDValid(msg->message_id)) { + return false; + } + + // if it's an nFAPI message, ignore + if ((msg->message_id == NFAPI_NR_PHY_MSG_TYPE_UL_NODE_SYNC || msg->message_id == NFAPI_NR_PHY_MSG_TYPE_DL_NODE_SYNC + || msg->message_id == NFAPI_NR_PHY_MSG_TYPE_TIMING_INFO)) { + return false; + } + + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + int num_avail_blocks = WLS_NumBlocks(pWls->hWls); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "num_avail_blocks is %d\n", num_avail_blocks); + while (num_avail_blocks < 2) { + num_avail_blocks = WLS_NumBlocks(pWls->hWls); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "num_avail_blocks is %d\n", num_avail_blocks); + } + /* get PA blocks for header and msg */ + const uint64_t pa_hdr = dequeueBlock(pWls); + AssertFatal(pa_hdr, "WLS_DequeueBlock failed for pa_hdr\n"); + const uint64_t pa_msg = dequeueBlock(pWls); + AssertFatal(pa_msg, "WLS_DequeueBlock failed for pa_msg\n"); + p_fapi_api_queue_elem_t headerElem = WLS_PA2VA(pWls->hWls, pa_hdr); + AssertFatal(headerElem, "WLS_PA2VA failed for headerElem\n"); + p_fapi_api_queue_elem_t fapiMsgElem = WLS_PA2VA(pWls->hWls, pa_msg); + AssertFatal(fapiMsgElem, "WLS_PA2VA failed for fapiMsgElem\n"); + const uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle + fill_fapi_list_elem(headerElem, fapiMsgElem, FAPI_VENDOR_MSG_HEADER_IND, 1, 2); + memcpy((uint8_t *)(headerElem + 1), wls_header, 2); + + const int packed_len = ((nfapi_pnf_p7_config_t *)pnf_p7)->pack_func(msg, (fapiMsgElem + 1), NFAPI_MAX_PACKED_MESSAGE_SIZE, NULL); + + if (packed_len < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p7_message_pack failed (%d)\n", packed_len); + return false; + } + fill_fapi_list_elem(fapiMsgElem, NULL, msg->message_id, 1, packed_len + NFAPI_HEADER_LENGTH); + const uint8_t retval = wls_msg_send(pWls->hWls, headerElem); + return retval; +} + +static void procPhyMessages(uint32_t msg_size, void *msg_buf, uint16_t msg_id) +{ + + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "[PHY] Received Msg ID 0x%02x Length %d\n", msg_id, msg_size); + if (msg_buf == NULL || _this == NULL) { + AssertFatal(msg_buf != NULL && _this != NULL, "%s: NULL parameters\n", __FUNCTION__); + } + // Add the size of the header to the message_size, because the size in the header does not include the header length + msg_size += NFAPI_NR_P5_HEADER_LENGTH; + switch (msg_id) { + case NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST ... NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST: + pnf_nr_handle_p5_message(_this, msg_buf, msg_size); + break; + case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST ... NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: { + pnf_nr_handle_p7_message(msg_buf, msg_size, (pnf_p7_t *)wls_pnf_p7_config, 0); + break; + } + default: + printf("\n Unknown Msg ID 0x%02x\n", msg_id); + break; + } +} + +void phy_mac_recv() +{ + /* Number of Memory blocks to get */ + uint32_t msgSize; + uint16_t msgType; + uint16_t flags; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + // This flag is used to determine whether to return the received blocks to the PNF + bool to_return = false; + while (_this->terminate == 0) { + int numMsgToGet = WLS_Wait(pWls->hWls); + if (numMsgToGet == 0) { + continue; + } + uint64_t PAs[numMsgToGet]; + uint8_t pa_idx = 0; + while (numMsgToGet--) { + PAs[pa_idx] = WLS_Get(pWls->hWls, &msgSize, &msgType, &flags); + pa_idx++; + } + for (int i = 0; i < pa_idx; i++) { + p_fapi_api_queue_elem_t msg = WLS_PA2VA(pWls->hWls, PAs[i]); + if (msg->msg_type != FAPI_VENDOR_MSG_HEADER_IND) { + uint8_t *msgt = (uint8_t *)(msg + 1); + uint32_t len = msgt[7] | (msgt[6] << 8) | (msgt[5] << 16) | (msgt[4] << 24); + procPhyMessages(len, (void *)(msg + 1), msg->msg_type); + } else { + // We check the header block to determine if it's the OAI VNF, if so, we're required to return the pages for enqueueing + if (!to_return) { + uint8_t *msgt = (uint8_t *)(msg + 1); + if (msgt[1] == 0xff) { + to_return = true; + } + } + } + } + if (to_return) { + // We only return the pages to be enqueued in case we're using the OAI VNF, + // The Radisys O-DU handles enqueueing the blocks differently, and also doesn't handle receiving a single block + for (int i = 0; i < pa_idx; i++) { + wls_return_msg_to_master(pWls, PAs[i]); + } + } + } +} diff --git a/nfapi/oai_integration/wls_integration/wls_vnf.c b/nfapi/oai_integration/wls_integration/wls_vnf.c new file mode 100644 index 0000000000..ccc68b4905 --- /dev/null +++ b/nfapi/oai_integration/wls_integration/wls_vnf.c @@ -0,0 +1,418 @@ +/* + * 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 "wls_vnf.h" + +#include "vnf_p7.h" + +#include +#include +#include +#include +#include +#include +#include + +static nfapi_vnf_config_t *config; +static WLS_MAC_CTX wls_mac_iface; +vnf_t *_vnf = NULL; +// A copy of the VNF P7 config is needed for the message processing thread, in other transport mechanisms where P7 is handled in a +// different thread, the config is passed to it upon the thread creation +nfapi_vnf_p7_config_t *wls_vnf_p7_config = NULL; + +void wls_vnf_set_p7_config(void *p7_config) +{ + wls_vnf_p7_config = (nfapi_vnf_p7_config_t *)p7_config; +} + +static PWLS_MAC_CTX wls_mac_get_ctx(void) +{ + return &wls_mac_iface; +} + +static uint8_t alloc_track[ALLOC_TRACK_SIZE]; +//------------------------------------------------------------------------------------------- +/** @ingroup group_testmac + * + * @param[in] pMemArray Pointer to WLS Memory management structure + * @param[in] pMemArrayMemory Pointer to flat buffer that was allocated + * @param[in] totalSize Total Size of flat buffer allocated + * @param[in] nBlockSize Size of each block that needs to be partitioned by memory manager + * + * @return 0 if SUCCESS + * + * @description + * This function creates memory blocks from a flat buffer which will be used for communciation + * between MAC and PHY + * + **/ +//------------------------------------------------------------------------------------------- +static bool wls_mac_create_mem_array(PWLS_MAC_MEM_SRUCT pMemArray, void *pMemArrayMemory, uint32_t totalSize, uint32_t nBlockSize) +{ + const uint32_t numBlocks = totalSize / nBlockSize; + + printf("wls_mac_create_mem_array: pMemArray[%p] pMemArrayMemory[%p] totalSize[%d] nBlockSize[%d] numBlocks[%d]\n", + pMemArray, + pMemArrayMemory, + totalSize, + nBlockSize, + numBlocks); + AssertFatal(nBlockSize >= sizeof(void *), "WLS nBlockSize too small"); + AssertFatal(totalSize > sizeof(void *), "WLS Can't allocate less than 1 block"); + pMemArray->ppFreeBlock = (void **)pMemArrayMemory; + pMemArray->pStorage = pMemArrayMemory; + pMemArray->pEndOfStorage = ((unsigned long *)pMemArrayMemory) + numBlocks * nBlockSize / sizeof(unsigned long); + pMemArray->nBlockSize = nBlockSize; + pMemArray->nBlockCount = numBlocks; + + // Initialize single-linked list of free blocks; + void **ptr = (void **)pMemArrayMemory; + for (uint32_t i = 0; i < pMemArray->nBlockCount; i++) { + if (i == pMemArray->nBlockCount - 1) { + *ptr = NULL; // End of list + } else { + // Points to the next block + *ptr = (void **)(((uint8_t *)ptr) + nBlockSize); + ptr += nBlockSize / sizeof(unsigned long); + } + } + + memset(alloc_track, 0, sizeof(uint8_t) * ALLOC_TRACK_SIZE); + + return true; +} + +void mac_dpdk_init() +{ + char *my_argv[] = {"OAI_VNF", "-c3", "--proc-type=auto", "--file-prefix", WLS_DEV_NAME, "--iova-mode=pa"}; + printf("\nCalling rte_eal_init: "); + for (unsigned long i = 0; i < RTE_DIM(my_argv); i++) { + printf("%s ", my_argv[i]); + } + printf("\n"); + + if (rte_eal_init(RTE_DIM(my_argv), my_argv) < 0) + rte_panic("\nCannot init EAL\n"); +} + +static uint32_t wls_mac_alloc_mem_array(PWLS_MAC_MEM_SRUCT pMemArray, void **ppBlock) +{ + int idx; + + if (pMemArray->ppFreeBlock == NULL) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "wls_mac_alloc_mem_array pMemArray->ppFreeBlock = NULL\n"); + return 1; + } + + // FIXME: Remove after debugging + if (((void *)pMemArray->ppFreeBlock < pMemArray->pStorage) || ((void *)pMemArray->ppFreeBlock >= pMemArray->pEndOfStorage)) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "wls_mac_alloc_mem_array ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p\n", + pMemArray, + pMemArray->pStorage, + pMemArray->ppFreeBlock); + return 1; + } + + pMemArray->ppFreeBlock = (void **)((unsigned long)pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0); + *pMemArray->ppFreeBlock = (void **)((unsigned long)*pMemArray->ppFreeBlock & 0xFFFFFFFFFFFFFFF0); + + if ((*pMemArray->ppFreeBlock != NULL) + && (((*pMemArray->ppFreeBlock) < pMemArray->pStorage) || ((*pMemArray->ppFreeBlock) >= pMemArray->pEndOfStorage))) { + fprintf(stderr, + "ERROR: Corrupted MemArray;Arr=%p,Stor=%p,Free=%p,Curr=%p\n", + pMemArray, + pMemArray->pStorage, + pMemArray->ppFreeBlock, + *pMemArray->ppFreeBlock); + return 1; + } + + *ppBlock = (void *)pMemArray->ppFreeBlock; + pMemArray->ppFreeBlock = (void **)(*pMemArray->ppFreeBlock); + + idx = (((uint64_t)*ppBlock - (uint64_t)pMemArray->pStorage)) / pMemArray->nBlockSize; + if (alloc_track[idx]) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "wls_mac_alloc_mem_array Double alloc Arr=%p,Stor=%p,Free=%p,Curr=%p\n", + pMemArray, + pMemArray->pStorage, + pMemArray->ppFreeBlock, + *pMemArray->ppFreeBlock); + } else { + alloc_track[idx] = 1; + } + + return 0; +} + +void wls_mac_print_stats(void) +{ + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "wls_mac_free_list_all:\n"); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, + " nTotalBlocks[%d] nAllocBlocks[%d] nFreeBlocks[%d]\n", + pWls->nTotalBlocks, + pWls->nAllocBlocks, + (pWls->nTotalBlocks - pWls->nAllocBlocks)); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, + " nTotalAllocCnt[%d] nTotalFreeCnt[%d] Diff[%d]\n", + pWls->nTotalAllocCnt, + pWls->nTotalFreeCnt, + (pWls->nTotalAllocCnt - pWls->nTotalFreeCnt)); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, + " nDlBufAllocCnt[%d] nDlBufFreeCnt[%d] Diff[%d]\n", + pWls->nTotalDlBufAllocCnt, + pWls->nTotalDlBufFreeCnt, + (pWls->nTotalDlBufAllocCnt - pWls->nTotalDlBufFreeCnt)); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, + " nUlBufAllocCnt[%d] nUlBufFreeCnt[%d] Diff[%d]\n\n", + pWls->nTotalUlBufAllocCnt, + pWls->nTotalUlBufFreeCnt, + (pWls->nTotalUlBufAllocCnt - pWls->nTotalUlBufFreeCnt)); +} + +static void *wls_mac_alloc_buffer(PWLS_MAC_CTX pWls, uint32_t size, uint32_t loc) +{ + void *pBlock = NULL; + pthread_mutex_lock((pthread_mutex_t *)&pWls->lock_alloc); + if (wls_mac_alloc_mem_array(&pWls->sWlsStruct, &pBlock) != 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "wls_mac_alloc_buffer alloc error size[%d] loc[%d]\n", size, loc); + wls_mac_print_stats(); + pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock_alloc); + return NULL; + } + pWls->nAllocBlocks++; + pWls->nTotalAllocCnt++; + if (loc < MAX_DL_BUF_LOCATIONS) + pWls->nTotalDlBufAllocCnt++; + else if (loc < MAX_UL_BUF_LOCATIONS) + pWls->nTotalUlBufAllocCnt++; + + pthread_mutex_unlock((pthread_mutex_t *)&pWls->lock_alloc); + + return pBlock; +} + +static bool mac_wls_init() +{ + uint64_t nWlsMacMemorySize = 0; + uint64_t nWlsPhyMemorySize = 0; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + pthread_mutex_init((pthread_mutex_t *)&pWls->lock, NULL); + pthread_mutex_init((pthread_mutex_t *)&pWls->lock_alloc, NULL); + + pWls->nTotalAllocCnt = 0; + pWls->nTotalFreeCnt = 0; + pWls->nTotalUlBufAllocCnt = 0; + pWls->nTotalUlBufFreeCnt = 0; + pWls->nTotalDlBufAllocCnt = 0; + pWls->nTotalDlBufFreeCnt = 0; + + /* Start by opening the WLS instance with WLS_MASTER_CLIENT */ + if ((pWls->hWls = WLS_Open(WLS_DEV_NAME, WLS_MASTER_CLIENT, &nWlsMacMemorySize, &nWlsPhyMemorySize)) == NULL) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "\nCould not open WLS Interface \n"); + return false; + } + + /* WLS_Open was successful, we can allocate memory */ + if ((pWls->pWlsMemBase = WLS_Alloc(pWls->hWls, nWlsMacMemorySize + nWlsPhyMemorySize)) == NULL) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "\nCould not allocate WLS Memory \n"); + return false; + } + /* Set the total memory that MAC has access to */ + pWls->nTotalMemorySize = nWlsMacMemorySize; + + /* Partition the WLS memory */ + memset(pWls->pWlsMemBase, 0xCC, pWls->nTotalMemorySize); + pWls->pPartitionMemBase = pWls->pWlsMemBase; + pWls->nPartitionMemSize = pWls->nTotalMemorySize; + pWls->nTotalBlocks = pWls->nTotalMemorySize / (NFAPI_MAX_PACKED_MESSAGE_SIZE); + /* Create the memory array */ + if (!wls_mac_create_mem_array(&pWls->sWlsStruct, pWls->pPartitionMemBase, pWls->nPartitionMemSize, NFAPI_MAX_PACKED_MESSAGE_SIZE)) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "\nCould not create WLS Memory Array \n"); + return false; + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "\nTotalBlocks is %d \n", pWls->nTotalBlocks); +int nBlocks = 0; +for(int i = 0 ; i< pWls->nTotalBlocks; i++){ + void* pMsg = wls_mac_alloc_buffer(pWls, 0, i); + /* Enqueue all blocks */ + nBlocks += WLS_EnqueueBlock(pWls->hWls, WLS_VA2PA(pWls->hWls, pMsg)); +} + NFAPI_TRACE(NFAPI_TRACE_INFO, "\nAllocated %d Blocks \n", nBlocks); + return true; +} + +static int vnf_wls_init() +{ + mac_dpdk_init(); + + if (!mac_wls_init()) { + return 0; + } + + return 1; +} + +void *wls_fapi_vnf_nr_start_thread(void *ptr) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] IN WLS PNF NFAPI start thread %s\n", __FUNCTION__); + wls_fapi_nr_vnf_start((nfapi_vnf_config_t *)ptr); + return (void *)0; +} + +static void procPhyMessages(uint32_t msg_size, void *msg_buf, uint16_t msg_id) +{ + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "[VNF] Received Msg ID 0x%02x\n", msg_id); + if (msg_buf == NULL || _vnf == NULL) { + AssertFatal(msg_buf != NULL && _vnf != NULL, "%s: NULL parameters\n", __FUNCTION__); + } + // Add the size of the header to the message_size, because the size in the header does not include the header length + msg_size += NFAPI_NR_P5_HEADER_LENGTH; + switch (msg_id) { + case NFAPI_NR_PHY_MSG_TYPE_PARAM_RESPONSE: + case NFAPI_NR_PHY_MSG_TYPE_CONFIG_RESPONSE: + case NFAPI_NR_PHY_MSG_TYPE_START_RESPONSE: + case NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION: + vnf_nr_handle_p4_p5_message(msg_buf, msg_size, 0, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST ... NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: { + vnf_nr_handle_p7_message(msg_buf, msg_size + NFAPI_NR_P7_HEADER_LENGTH, (vnf_p7_t *)wls_vnf_p7_config); + break; + } + default: + break; + } +} + +int wls_fapi_nr_vnf_start(nfapi_vnf_config_t *cfg) +{ + config = cfg; + + if (config == 0) { + return -1; + } + _vnf = (vnf_t *)(config); + + // init WLS connection + if (vnf_wls_init() == 0) { + return -1; + } + _vnf->terminate = 0; + + // Connect to the PNF + if (config->pnf_nr_start_resp != 0) { + (config->pnf_nr_start_resp)(config, 0, NULL); + } + /* VNF receive loop */ + /* Number of Memory blocks to get */ + uint32_t msgSize; + uint16_t msgType; + uint16_t flags; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + while (_vnf->terminate == 0) { + int numMsgToGet = WLS_Wait(pWls->hWls); + if (numMsgToGet == 0) { + continue; + } + + uint64_t PAs[numMsgToGet]; + uint8_t pa_idx = 0; + while (numMsgToGet--) { + PAs[pa_idx] = WLS_Get(pWls->hWls, &msgSize, &msgType, &flags); + pa_idx++; + } + for (int i = 0; i < pa_idx; i++) { + p_fapi_api_queue_elem_t msg = WLS_PA2VA(pWls->hWls, PAs[i]); + if (msg->msg_type != FAPI_VENDOR_MSG_HEADER_IND) { + uint8_t *msgt = (uint8_t *)(msg + 1); + uint32_t len = msgt[7] | (msgt[6] << 8) | (msgt[5] << 16) | (msgt[4] << 24); + procPhyMessages(len, (void *)(msg + 1), msg->msg_type); + } + } + for (int i = 0; i < pa_idx; i++) { + if (WLS_EnqueueBlock(pWls->hWls, PAs[i]) == -1) { + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Error in WLS_EnqueueBlock for block %lu\n", PAs[i]); + } + } + } + return 1; +} + +bool wls_vnf_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) +{ + UNUSED_VARIABLE(p5_idx); + int packed_len = + vnf->_public.pack_func(msg, msg_len, vnf->tx_message_buffer, sizeof(vnf->tx_message_buffer), &vnf->_public.codec_config); + + if (packed_len < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p5_message_pack failed (%d)\n", packed_len); + return false; + } + + // printf("fapi_nr_p5_message_pack succeeded having packed %d bytes\n", packed_len); + // printf("in msg, msg_len is %d\n", msg->message_length); + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + + int retval = wls_send_fapi_msg(pWls, msg->message_id, packed_len, vnf->tx_message_buffer); + if (retval) { + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "wls_send_fapi_msg success\n"); + } + return retval; +} + +bool wls_vnf_nr_send_p7_message(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *msg) +{ + uint32_t message_id = msg->message_id; + PWLS_MAC_CTX pWls = wls_mac_get_ctx(); + int num_avail_blocks = WLS_NumBlocks(pWls->hWls); + NFAPI_TRACE(NFAPI_TRACE_DEBUG,"num_avail_blocks is %d\n", num_avail_blocks); + while (num_avail_blocks < 2) { + num_avail_blocks = WLS_NumBlocks(pWls->hWls); + NFAPI_TRACE(NFAPI_TRACE_DEBUG,"num_avail_blocks is %d\n", num_avail_blocks); + } + /* get PA blocks for header and msg */ + uint64_t pa_hdr = dequeueBlock(pWls); + AssertFatal(pa_hdr, "WLS_DequeueBlock failed for pa_hdr\n"); + uint64_t pa_msg = dequeueBlock(pWls); + AssertFatal(pa_msg, "WLS_DequeueBlock failed for pa_msg\n"); + p_fapi_api_queue_elem_t headerElem = WLS_PA2VA(pWls->hWls, pa_hdr); + AssertFatal(headerElem, "WLS_PA2VA failed for headerElem\n"); + p_fapi_api_queue_elem_t fapiMsgElem = WLS_PA2VA(pWls->hWls, pa_msg); + AssertFatal(fapiMsgElem, "WLS_PA2VA failed for fapiMsgElem\n"); + //memcpy((uint8_t *)(fapiMsgElem + 1), message, packed_len + NFAPI_HEADER_LENGTH); + const uint8_t wls_header[] = {1, 0}; // num_messages , opaque_handle + + fill_fapi_list_elem(headerElem, fapiMsgElem, FAPI_VENDOR_MSG_HEADER_IND, 1, 2); + memcpy((uint8_t *)(headerElem + 1), wls_header, 2); + int packed_len = ((nfapi_vnf_p7_config_t *)vnf_p7)->pack_func(msg, (fapiMsgElem + 1), NFAPI_MAX_PACKED_MESSAGE_SIZE, NULL); + if (packed_len < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "fapi_p7_message_pack failed (%d)\n", packed_len); + return false; + } + fill_fapi_list_elem(fapiMsgElem, NULL, message_id, 1, packed_len + NFAPI_HEADER_LENGTH); + uint8_t retval = wls_msg_send(pWls->hWls, headerElem); + return retval; + //return wls_send_fapi_msg(pWls, msg->message_id, packed_len, _vnf->tx_message_buffer); +} diff --git a/nfapi/open-nFAPI/common/src/nfapi.c b/nfapi/open-nFAPI/common/src/nfapi.c index 716387ae7d..f997552c1e 100644 --- a/nfapi/open-nFAPI/common/src/nfapi.c +++ b/nfapi/open-nFAPI/common/src/nfapi.c @@ -889,8 +889,8 @@ int unpack_nr_tlv_list(unpack_tlv_t unpack_fns[], nfapi_tl_t generic_tl; uint8_t numBadTags = 0; uint16_t idx = 0; - - while ((uint8_t *)(*ppReadPackedMsg) < end) { + if (size == 0) { return 1; } + while ((uint8_t *)(*ppReadPackedMsg) + 4 < end) { // unpack the tl and process the values accordingly if (unpack_tl(ppReadPackedMsg, &generic_tl, end) == 0) return 0; diff --git a/nfapi/open-nFAPI/fapi/CMakeLists.txt b/nfapi/open-nFAPI/fapi/CMakeLists.txt index b332ef6a8e..0cddd9d82f 100644 --- a/nfapi/open-nFAPI/fapi/CMakeLists.txt +++ b/nfapi/open-nFAPI/fapi/CMakeLists.txt @@ -19,6 +19,14 @@ target_include_directories(nr_fapi_p7 PUBLIC inc) target_link_libraries(nr_fapi_p7 PUBLIC nr_fapi_common) if (OAI_AERIAL) - target_compile_definitions(nr_fapi_p5 PRIVATE ENABLE_AERIAL) + target_compile_definitions(nr_fapi_p5 PRIVATE ENABLE_AERIAL ENABLE_10_04) target_compile_definitions(nr_fapi_p7 PRIVATE ENABLE_AERIAL) +else() + target_compile_definitions(nr_fapi_p5 PRIVATE ENABLE_10_02) endif () + +if(OAI_WLS) + target_compile_definitions(nr_fapi_common PRIVATE ENABLE_WLS) +else() + target_compile_definitions(nr_fapi_common PRIVATE ENABLE_SOCKET) +endif() diff --git a/nfapi/open-nFAPI/fapi/inc/nr_fapi.h b/nfapi/open-nFAPI/fapi/inc/nr_fapi.h index e8e645b8cf..e71e1bae5c 100644 --- a/nfapi/open-nFAPI/fapi/inc/nr_fapi.h +++ b/nfapi/open-nFAPI/fapi/inc/nr_fapi.h @@ -35,6 +35,9 @@ #include "debug.h" #define INDENTED_PRINTF(format, ...) printf("%*s" format, depth * 2, "", ##__VA_ARGS__) +#define INDENTED_GENERIC_PRINT(string, format, ...) INDENTED_PRINTF(string " = " format "\n", ##__VA_ARGS__) +#define INDENTED_TLV_PRINT(tlv_name, tlv) INDENTED_GENERIC_PRINT("(0x%04x) " tlv_name, "0x%02x", tlv.tl.tag, tlv.value) +#define INDENTED_TLV_FORMAT_PRINT(tlv_name, format, tlv) INDENTED_GENERIC_PRINT("(0x%04x) " tlv_name, format, tlv.tl.tag, tlv.value) #define EQ_TLV(_tlv_a, _tlv_b) \ do { \ @@ -74,10 +77,37 @@ bool isFAPIMessageIDValid(uint16_t id); int check_nr_fapi_unpack_length(nfapi_nr_phy_msg_type_e msgId, uint32_t unpackedBufLen); -int fapi_nr_message_header_unpack(uint8_t **pMessageBuf, +/*! \brief Decodes a FAPI P5 message header + * \param pMessageBuf A pointer to an encoded P5 message header + * \param messageBufLen The size of the encoded P5 message header + * \param pUnpackedBuf A pointer to the fapi_message_header + * \param unpackedBufLen The size of fapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure. + * + * The function will decode a byte stream pointed to by pMessageBuf into a FAPI p5 header structure pointed to by pUnpackedBuf + */ +bool fapi_nr_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t *config); +/*! \brief Decodes a FAPI P7 message header + * \param pMessageBuf A pointer to an encoded P5 message header + * \param messageBufLen The size of the encoded P5 message header + * \param pUnpackedBuf A pointer to the fapi_message_header + * \param unpackedBufLen The size of fapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure. + * + * This function is a dummy function that points to fapi_nr_message_header_unpack, + * since in FAPI there's no difference in the structure of the message headers for P5 and P7 + */ +bool fapi_nr_p7_message_header_unpack(void *pMessageBuf, + uint32_t messageBufLen, + void *pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p7_codec_config_t *config); + #endif // OPENAIRINTERFACE_NR_FAPI_H diff --git a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p5.h b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p5.h index 307b5bad27..d47f0ec929 100644 --- a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p5.h +++ b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p5.h @@ -30,7 +30,7 @@ int fapi_nr_p5_message_pack(void *pMessageBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t *config); -int fapi_nr_p5_message_unpack(void *pMessageBuf, +bool fapi_nr_p5_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, diff --git a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h index 77ed67e2ef..9d96a3be36 100644 --- a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h +++ b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h @@ -23,7 +23,7 @@ #define OPENAIRINTERFACE_NR_FAPI_P5_UTILS_H #include "stdio.h" #include "stdint.h" -#include "nr_fapi.h" +#include "nfapi/open-nFAPI/fapi/inc/nr_fapi.h" #include "nfapi/oai_integration/vendor_ext.h" bool eq_param_request(const nfapi_nr_param_request_scf_t *unpacked_req, const nfapi_nr_param_request_scf_t *req); @@ -64,6 +64,7 @@ void dump_start_request(const nfapi_nr_start_request_scf_t *msg); void dump_start_response(const nfapi_nr_start_response_scf_t *msg); void dump_stop_request(const nfapi_nr_stop_request_scf_t *msg); void dump_stop_indication(const nfapi_nr_stop_indication_scf_t *msg); +char* error_ind_code_to_str(nfapi_nr_phy_notifications_errors_e error_code); void dump_error_indication(const nfapi_nr_error_indication_scf_t *msg); diff --git a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h index c2701acb5f..80b39f7386 100644 --- a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h +++ b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7.h @@ -23,7 +23,7 @@ int fapi_nr_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t *config); -int fapi_nr_p7_message_unpack(void *pMessageBuf, +bool fapi_nr_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, diff --git a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h index f915548783..5c1df2dcef 100644 --- a/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h +++ b/nfapi/open-nFAPI/fapi/inc/nr_fapi_p7_utils.h @@ -33,7 +33,7 @@ #define OPENAIRINTERFACE_NR_FAPI_P7_UTILS_H #include "stdio.h" #include "stdint.h" -#include "nr_fapi.h" +#include "nfapi/open-nFAPI/fapi/inc/nr_fapi.h" bool eq_dl_tti_request(const nfapi_nr_dl_tti_request_t *a, const nfapi_nr_dl_tti_request_t *b); bool eq_ul_tti_request(const nfapi_nr_ul_tti_request_t *a, const nfapi_nr_ul_tti_request_t *b); diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi.c b/nfapi/open-nFAPI/fapi/src/nr_fapi.c index c36fff4b34..4da483db17 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi.c @@ -54,7 +54,6 @@ bool isFAPIMessageIDValid(const uint16_t id) int check_nr_fapi_unpack_length(nfapi_nr_phy_msg_type_e msgId, uint32_t unpackedBufLen) { int retLen = 0; - // check for size of nFAPI struct without the nFAPI specific parameters switch (msgId) { case NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST: @@ -165,24 +164,37 @@ int check_nr_fapi_unpack_length(nfapi_nr_phy_msg_type_e msgId, uint32_t unpacked return retLen; } -int fapi_nr_message_header_unpack(uint8_t **pMessageBuf, +bool fapi_nr_p7_message_header_unpack(void *pMessageBuf, + uint32_t messageBufLen, + void *pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p7_codec_config_t *config) +{ + return fapi_nr_message_header_unpack(pMessageBuf, + messageBufLen, + pUnpackedBuf, + unpackedBufLen, + NULL); +} + +bool fapi_nr_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t *config) { - uint8_t **pReadPackedMessage = pMessageBuf; + uint8_t *pReadPackedMessage = pMessageBuf; nfapi_nr_p4_p5_message_header_t *header = pUnpackedBuf; fapi_message_header_t fapi_msg = {0}; if (pMessageBuf == NULL || pUnpackedBuf == NULL || messageBufLen < NFAPI_HEADER_LENGTH || unpackedBufLen < sizeof(fapi_message_header_t)) { - return -1; + return false; } - uint8_t *end = *pMessageBuf + messageBufLen; + uint8_t *end = pMessageBuf + messageBufLen; // process the header int result = - (pull8(pReadPackedMessage, &fapi_msg.num_msg, end) && pull8(pReadPackedMessage, &fapi_msg.opaque_handle, end) - && pull16(pReadPackedMessage, &header->message_id, end) && pull32(pReadPackedMessage, &header->message_length, end)); - return (result); + (pull8(&pReadPackedMessage, &fapi_msg.num_msg, end) && pull8(&pReadPackedMessage, &fapi_msg.opaque_handle, end) + && pull16(&pReadPackedMessage, &header->message_id, end) && pull32(&pReadPackedMessage, &header->message_length, end)); + return result != 0; } diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c index 281043b6d3..c3e36d9999 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c @@ -128,41 +128,39 @@ int fapi_nr_p5_message_pack(void *pMessageBuf, return packedMsgLen; } -int fapi_nr_p5_message_unpack(void *pMessageBuf, +bool fapi_nr_p5_message_unpack(void *pMessageBuf, const uint32_t messageBufLen, void *pUnpackedBuf, const uint32_t unpackedBufLen, nfapi_p4_p5_codec_config_t *config) { fapi_message_header_t *pMessageHeader = pUnpackedBuf; - uint8_t *pReadPackedMessage = pMessageBuf; AssertFatal(pMessageBuf != NULL && pUnpackedBuf != NULL, "P5 unpack supplied pointers are null"); - uint8_t *end = (uint8_t *)pMessageBuf + messageBufLen; AssertFatal(messageBufLen >= NFAPI_HEADER_LENGTH && unpackedBufLen >= sizeof(fapi_message_header_t), "P5 unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); // clean the supplied buffer for - tag value blanking (void)memset(pUnpackedBuf, 0, unpackedBufLen); - if (fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, pMessageHeader, sizeof(fapi_message_header_t), 0) - < 0) { + if (!fapi_nr_message_header_unpack(pMessageBuf, NFAPI_HEADER_LENGTH, pMessageHeader, sizeof(fapi_message_header_t), 0)) { // failed to read the header - return -1; + return false; } - + uint8_t *pReadPackedMessage = pMessageBuf + NFAPI_HEADER_LENGTH; + uint8_t *end = (uint8_t *)pMessageBuf + messageBufLen; int result = -1; if (check_nr_fapi_unpack_length(pMessageHeader->message_id, unpackedBufLen) == 0) { // the unpack buffer is not big enough for the struct - return -1; + return false; } // look for the specific message switch (pMessageHeader->message_id) { case NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST: // PARAM request has no body; - result = 0; + result = 1; break; case NFAPI_NR_PHY_MSG_TYPE_PARAM_RESPONSE: @@ -210,7 +208,7 @@ int fapi_nr_p5_message_unpack(void *pMessageBuf, break; } - return result; + return result != 0; } uint8_t pack_nr_param_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *config) @@ -723,7 +721,74 @@ uint8_t unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void * config, &pNfapiMsg->vendor_extension)); } +#ifndef ENABLE_AERIAL +static uint8_t pack_dbt_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nr_dbt_tlv_ve_t *dbt_ve = (nfapi_nr_dbt_tlv_ve_t *)tlv; + nfapi_nr_dbt_pdu_t *dbt_config = &dbt_ve->value; + if (!( push16(dbt_config->num_dig_beams, ppWritePackedMsg, end) && push16(dbt_config->num_txrus, ppWritePackedMsg, end) )) { + return 0; + } + for (int i = 0; i< dbt_config->num_dig_beams; i++) { + const nfapi_nr_dig_beam_t *dig_beam = &dbt_config->dig_beam_list[i]; + if (!(push16(dig_beam->beam_idx, ppWritePackedMsg, end))) { + return 0; + } + for (int k = 0; k< dbt_config->num_txrus; k++) { + const nfapi_nr_txru_t *tx_ru = &dig_beam->txru_list[k]; + if (!(push16(tx_ru->dig_beam_weight_Re, ppWritePackedMsg, end) && push16(tx_ru->dig_beam_weight_Im, ppWritePackedMsg, end))) { + return 0; + } + } + } + return 1; +} +static uint8_t pack_pm_table_tlv_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nr_pm_tlv_ve_t *pm_ve = (nfapi_nr_pm_tlv_ve_t *)tlv; + nfapi_nr_pm_list_t *pmi_list = &pm_ve->value; + if (!( push16(pmi_list->num_pm_idx, ppWritePackedMsg, end) )) { + return 0; + } + for (int i = 0; i< pmi_list->num_pm_idx; i++) { + const nfapi_nr_pm_pdu_t *pm_pdu = &pmi_list->pmi_pdu[i]; + if (!(push16(pm_pdu->pm_idx, ppWritePackedMsg, end) && push16(pm_pdu->numLayers, ppWritePackedMsg, end) + && push16(pm_pdu->num_ant_ports, ppWritePackedMsg, end))) { + return 0; + } + for (int k = 0; k < pm_pdu->numLayers; k++) { + for (int j = 0; j < pm_pdu->num_ant_ports; j++) { + const nfapi_nr_pm_weights_t *pm_weight = &pm_pdu->weights[k][j]; + if (!(push16(pm_weight->r, ppWritePackedMsg, end) && push16(pm_weight->i, ppWritePackedMsg, end))) { + return 0; + } + } + } + } + return 1; +} +#endif +#ifdef ENABLE_10_04 +static uint8_t pack_nr_tdd_table_10_04(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) +{ + nfapi_nr_tdd_table_tlv_t *tdd_table_tlv = (nfapi_nr_tdd_table_tlv_t *)tlv; + nfapi_nr_tdd_table_t *tdd_table = tdd_table_tlv->value; +#ifndef ENABLE_AERIAL + if (!push8(tdd_table->tdd_period.value, ppWritePackedMsg, end)) { + return 0; + } +#endif + for (int i = 0; i < tdd_table_tlv->slots_per_frame; i++) { + for (int k = 0; k < tdd_table_tlv->symbols_per_slot; k++) { + if (!push8(tdd_table->max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list[k].slot_config.value, ppWritePackedMsg, end)) { + return 0; + } + } + } + return 1; +} +#endif uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *config) { uint8_t *pNumTLVFields = (uint8_t *)*ppWritePackedMsg; @@ -1005,18 +1070,23 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e &pack_uint8_tlv_value); numTLVs++; } - // END SSB Table +#endif + // START TDD Table if (pNfapiMsg->cell_config.frame_duplex_type.value == 1 /* TDD */) { - retval &= - pack_nr_tlv(NFAPI_NR_CONFIG_TDD_PERIOD_TAG, &(pNfapiMsg->tdd_table.tdd_period), ppWritePackedMsg, end, &pack_uint8_tlv_value); - numTLVs++; const uint8_t slotsperframe[5] = {10, 20, 40, 80, 160}; // Assuming always CP_Normal, because Cyclic prefix is not included in CONFIG.request 10.02, but is present in 10.04 uint8_t cyclicprefix = 1; // 3GPP 38.211 Table 4.3.2.1 & Table 4.3.2.2 uint8_t number_of_symbols_per_slot = cyclicprefix ? 14 : 12; +#ifdef ENABLE_10_02 + retval &= pack_nr_tlv(NFAPI_NR_CONFIG_TDD_PERIOD_TAG, + &(pNfapiMsg->tdd_table.tdd_period), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; for (int i = 0; i < slotsperframe[pNfapiMsg->ssb_config.scs_common.value]; i++) { // TODO check right number of slots for (int k = 0; k < number_of_symbols_per_slot; k++) { // TODO can change? retval &= pack_nr_tlv(NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, @@ -1027,10 +1097,37 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e numTLVs++; } } - } - - // END TDD Table #endif + +#ifdef ENABLE_10_04 +#ifdef ENABLE_AERIAL + retval &= pack_nr_tlv(NFAPI_NR_CONFIG_TDD_PERIOD_TAG, + &(pNfapiMsg->tdd_table.tdd_period), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; + + nfapi_nr_tdd_table_tlv_t tdd_table_tlv = {.tl.tag = NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, .value = &pNfapiMsg->tdd_table, .slots_per_frame = slotsperframe[pNfapiMsg->ssb_config.scs_common.value], .symbols_per_slot = number_of_symbols_per_slot }; + retval &= pack_nr_tlv(NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, + &tdd_table_tlv, + ppWritePackedMsg, + end, + &pack_nr_tdd_table_10_04); + numTLVs++; +#else + nfapi_nr_tdd_table_tlv_t tdd_table_tlv = {.tl.tag = NFAPI_NR_CONFIG_TDD_TABLE, .value = &pNfapiMsg->tdd_table, .slots_per_frame = slotsperframe[pNfapiMsg->ssb_config.scs_common.value], .symbols_per_slot = number_of_symbols_per_slot }; + retval &= pack_nr_tlv(NFAPI_NR_CONFIG_TDD_TABLE, + &tdd_table_tlv, + ppWritePackedMsg, + end, + &pack_nr_tdd_table_10_04); + numTLVs++; +#endif +#endif + } + // END TDD Table + // START Measurement Config // SCF222.10.02 Table 3-27 : Contains only one TLV and is currently unused pNfapiMsg->measurement_config.rssi_measurement.tl.tag = NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG; @@ -1042,15 +1139,23 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e &pack_uint8_tlv_value); numTLVs++; // END Measurement Config - +#ifndef ENABLE_AERIAL // START Digital Beam Table (DBT) PDU - // Struct in nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h nfapi_nr_dbt_pdu_t, currently unused + if (pNfapiMsg->dbt_config.num_dig_beams != 0) { + nfapi_nr_dbt_tlv_ve_t dbt_tlv = {.tl.tag = NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG, .value = pNfapiMsg->dbt_config}; + pack_nr_tlv(NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG, &dbt_tlv, ppWritePackedMsg, end, &pack_dbt_table_tlv_value); + numTLVs++; + } // END Digital Beam Table (DBT) PDU // START Precoding Matrix (PM) PDU - // Struct in nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h nfapi_nr_pm_pdu_t, currently unused, tag to use for AERIAL + if (pNfapiMsg->pmi_list.num_pm_idx != 0) { + nfapi_nr_pm_tlv_ve_t pm_tlv = {.tl.tag = NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG, .value = pNfapiMsg->pmi_list}; + pack_nr_tlv(NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG, &pm_tlv, ppWritePackedMsg, end, &pack_pm_table_tlv_value); + numTLVs++; + } // is 0xA011 END Precoding Matrix (PM) PDU -#ifndef ENABLE_AERIAL + // START nFAPI TLVs included in CONFIG.request for IDLE and CONFIGURED states retval &= pack_nr_tlv(NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), @@ -1156,6 +1261,91 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e return retval; } +static uint8_t unpack_dbt_table_tlv_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nr_dbt_pdu_t *dbt_config = (nfapi_nr_dbt_pdu_t *)tlv; + if (!(pull16(ppReadPackedMsg, &dbt_config->num_dig_beams, end) && pull16(ppReadPackedMsg, &dbt_config->num_txrus, end))) { + return 0; + } + if (dbt_config->num_dig_beams > 0) { + dbt_config->dig_beam_list = calloc(dbt_config->num_dig_beams, sizeof(*dbt_config->dig_beam_list)); + } + for (int i = 0; i < dbt_config->num_dig_beams; i++) { + nfapi_nr_dig_beam_t *dig_beam = &dbt_config->dig_beam_list[i]; + if (!(pull16(ppReadPackedMsg, &dig_beam->beam_idx, end))) { + return 0; + } + if (dbt_config->num_txrus > 0) { + dig_beam->txru_list = calloc(dbt_config->num_txrus, sizeof(*dig_beam->txru_list)); + } + for (int k = 0; k < dbt_config->num_txrus; k++) { + nfapi_nr_txru_t *tx_ru = &dig_beam->txru_list[k]; + if (!(pull16(ppReadPackedMsg, &tx_ru->dig_beam_weight_Re, end) && pull16(ppReadPackedMsg, &tx_ru->dig_beam_weight_Im, end))) { + return 0; + } + } + } + return 1; +} + +static uint8_t unpack_pm_table_tlv_value(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nr_pm_list_t *pm_list = (nfapi_nr_pm_list_t *)tlv; + if (!(pull16(ppReadPackedMsg, &pm_list->num_pm_idx, end))) { + return 0; + } + if (pm_list->num_pm_idx > 0) { + pm_list->pmi_pdu = calloc(pm_list->num_pm_idx, sizeof(*pm_list->pmi_pdu)); + } + for (int i = 0; i < pm_list->num_pm_idx; i++) { + nfapi_nr_pm_pdu_t *pm_pdu = &pm_list->pmi_pdu[i]; + if (!(pull16(ppReadPackedMsg, &pm_pdu->pm_idx, end) && pull16(ppReadPackedMsg, &pm_pdu->numLayers, end) + && pull16(ppReadPackedMsg, &pm_pdu->num_ant_ports, end))) { + return 0; + } + AssertFatal(pm_pdu->numLayers <= 4 && pm_pdu->num_ant_ports <= 4, "Precoding matrix size limited to 4X4 for the time being\n"); + for (int k = 0; k < pm_pdu->numLayers; k++) { + for (int j = 0; j < pm_pdu->num_ant_ports; j++) { + nfapi_nr_pm_weights_t *pm_weight = &pm_pdu->weights[k][j]; + if (!(pulls16(ppReadPackedMsg, &pm_weight->r, end) && pulls16(ppReadPackedMsg, &pm_weight->i, end))) { + return 0; + } + } + } + } + return 1; +} +#ifdef ENABLE_10_04 +static uint8_t unpack_nr_tdd_table_10_04(void *tlv, uint8_t **ppReadPackedMsg, uint8_t *end) +{ + nfapi_nr_tdd_table_tlv_t *tdd_table_tlv = (nfapi_nr_tdd_table_tlv_t *)tlv; + nfapi_nr_tdd_table_t *tdd_table = tdd_table_tlv->value; + + if (!(pull8(ppReadPackedMsg, &tdd_table->tdd_period.value, end))) { + return 0; + } + tdd_table->tdd_period.tl.tag = NFAPI_NR_CONFIG_TDD_PERIOD_TAG; + const int slots = tdd_table_tlv->slots_per_frame; + const int symbols = tdd_table_tlv->symbols_per_slot; + if (!tdd_table->max_tdd_periodicity_list) { + tdd_table->max_tdd_periodicity_list = calloc(slots, sizeof(*tdd_table->max_tdd_periodicity_list)); + } + for (int slot = 0; slot < slots; slot++) { + nfapi_nr_max_tdd_periodicity_t* list = &tdd_table->max_tdd_periodicity_list[slot]; + if (!list->max_num_of_symbol_per_slot_list) { + list->max_num_of_symbol_per_slot_list = calloc(symbols, sizeof(*list->max_num_of_symbol_per_slot_list)); + } + for (int sym = 0; sym < symbols; sym++) { + if (!(pull8(ppReadPackedMsg, &list->max_num_of_symbol_per_slot_list[sym].slot_config.value, end))) { + return 0; + } + list->max_num_of_symbol_per_slot_list[sym].slot_config.tl.tag = NFAPI_NR_CONFIG_SLOT_CONFIG_TAG; + } + } + + return 1; +} +#endif uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config) { // Helper vars for indexed TLVs @@ -1163,8 +1353,10 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * int unused_root_seq_idx = 0; int ssb_mask_idx = 0; int config_beam_idx = 0; +#ifdef ENABLE_10_02 int tdd_periodicity_idx = 0; int symbol_per_slot_idx = 0; +#endif int beam_ve_idx = 0; nfapi_nr_config_request_scf_t *pNfapiMsg = (nfapi_nr_config_request_scf_t *)msg; // unpack TLVs @@ -1215,12 +1407,23 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * &(pNfapiMsg->ssb_table.multiple_cells_ss_pbch_in_a_carrier), &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_TDD_PERIOD_TAG, &(pNfapiMsg->tdd_table.tdd_period), &unpack_uint8_tlv_value}, +#ifdef ENABLE_10_02 {NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, NULL, &unpack_uint8_tlv_value}, +#endif +#ifdef ENABLE_10_04 +#ifdef ENABLE_AERIAL + {NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, NULL, &unpack_nr_tdd_table_10_04}, +#else + {NFAPI_NR_CONFIG_TDD_TABLE, NULL, &unpack_nr_tdd_table_10_04}, +#endif +#endif {NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext), &unpack_uint8_tlv_value}, {NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext), &unpack_uint8_tlv_value}, {NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), &unpack_uint8_tlv_value}, {NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, NULL, &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, &(pNfapiMsg->measurement_config.rssi_measurement), &unpack_uint8_tlv_value}, + {NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG, NULL, &unpack_dbt_table_tlv_value}, + {NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG, NULL, &unpack_pm_table_tlv_value}, {NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), &unpack_ipv4_address_value}, {NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), &unpack_ipv6_address_value}, {NFAPI_NR_NFAPI_P7_VNF_PORT_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_port), &unpack_uint16_tlv_value}, @@ -1230,13 +1433,20 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * {NFAPI_NR_NFAPI_P7_PNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_pnf_address_ipv6), &unpack_ipv6_address_value}, {NFAPI_NR_NFAPI_P7_PNF_PORT_TAG, &(pNfapiMsg->nfapi_config.p7_pnf_port), &unpack_uint16_tlv_value}}; +#ifdef ENABLE_10_04 +#ifdef ENABLE_AERIAL + nfapi_nr_tdd_table_tlv_t tdd_table_tlv = {.tl.tag = NFAPI_NR_CONFIG_SLOT_CONFIG_TAG}; +#else + nfapi_nr_tdd_table_tlv_t tdd_table_tlv = {.tl.tag = NFAPI_NR_CONFIG_TDD_TABLE}; +#endif +#endif pull8(ppReadPackedMsg, &pNfapiMsg->num_tlv, end); pNfapiMsg->vendor_extension = malloc(sizeof(&(pNfapiMsg->vendor_extension))); nfapi_tl_t generic_tl; uint8_t numBadTags = 0; unsigned long idx = 0; - while ((uint8_t *)(*ppReadPackedMsg) < end) { + while ((uint8_t *)(*ppReadPackedMsg) + 4 < end) { // unpack the tl and process the values accordingly if (unpack_tl(ppReadPackedMsg, &generic_tl, end) == 0) return 0; @@ -1268,6 +1478,24 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx], ppReadPackedMsg, end); beam_ve_idx ++; break; + case NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG: + unpack_fns[idx].tlv = &generic_tl; + result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->dbt_config, ppReadPackedMsg, end); + break; + case NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG: + unpack_fns[idx].tlv = &generic_tl; + result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->pmi_list, ppReadPackedMsg, end); + break; +#ifdef ENABLE_10_04 +#ifdef ENABLE_AERIAL + case NFAPI_NR_CONFIG_SLOT_CONFIG_TAG: +#else + case NFAPI_NR_CONFIG_TDD_TABLE: +#endif + unpack_fns[idx].tlv = &generic_tl; + result = (*unpack_fns[idx].unpack_func)(&tdd_table_tlv, ppReadPackedMsg, end); + break; +#endif case NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG: pNfapiMsg->prach_config.num_prach_fd_occasions.tl.tag = generic_tl.tag; pNfapiMsg->prach_config.num_prach_fd_occasions.tl.length = generic_tl.length; @@ -1294,6 +1522,11 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * pNfapiMsg->tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list = calloc(number_of_symbols_per_slot, sizeof(nfapi_nr_max_num_of_symbol_per_slot_t)); } +#ifdef ENABLE_10_04 + tdd_table_tlv.slots_per_frame = slotsperframe[pNfapiMsg->ssb_config.scs_common.value]; + tdd_table_tlv.symbols_per_slot = number_of_symbols_per_slot; + tdd_table_tlv.value = &pNfapiMsg->tdd_table; +#endif } break; case NFAPI_NR_CONFIG_PRACH_ROOT_SEQUENCE_INDEX_TAG: @@ -1412,6 +1645,7 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * end); config_beam_idx++; break; +#ifdef ENABLE_10_02 case NFAPI_NR_CONFIG_SLOT_CONFIG_TAG: unpack_fns[idx].tlv = &(pNfapiMsg->tdd_table.max_tdd_periodicity_list[tdd_periodicity_idx] .max_num_of_symbol_per_slot_list[symbol_per_slot_idx] @@ -1432,6 +1666,7 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * tdd_periodicity_idx++; } break; +#endif default: result = (*unpack_fns[idx].unpack_func)(tl, ppReadPackedMsg, end); break; @@ -1630,22 +1865,23 @@ uint8_t unpack_nr_stop_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void uint8_t pack_nr_error_indication(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *config) { nfapi_nr_error_indication_scf_t *pNfapiMsg = (nfapi_nr_error_indication_scf_t *)msg; - uint8_t retval = push16(pNfapiMsg->sfn, ppWritePackedMsg, end) != 0; - retval &= push16(pNfapiMsg->slot, ppWritePackedMsg, end) != 0; - retval &= push8(pNfapiMsg->message_id, ppWritePackedMsg, end); - retval &= push8(pNfapiMsg->error_code, ppWritePackedMsg, end); - - retval &= pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); - return retval; + if (push16(pNfapiMsg->sfn, ppWritePackedMsg, end) && push16(pNfapiMsg->slot, ppWritePackedMsg, end) + && push8(pNfapiMsg->message_id, ppWritePackedMsg, end) && push8(pNfapiMsg->error_code, ppWritePackedMsg, end) + && pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config)) { + return 1; + } else { + return 0; + } } uint8_t unpack_nr_error_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config) { nfapi_nr_error_indication_scf_t *pNfapiMsg = (nfapi_nr_error_indication_scf_t *)msg; - uint8_t retval = pull16(ppReadPackedMsg, &pNfapiMsg->sfn, end); - retval &= pull16(ppReadPackedMsg, &pNfapiMsg->slot, end); - retval &= pull8(ppReadPackedMsg, &pNfapiMsg->message_id, end); - retval &= pull8(ppReadPackedMsg, &pNfapiMsg->error_code, end); - retval &= unpack_nr_tlv_list(NULL, 0, ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension)); - return retval; + if (pull16(ppReadPackedMsg, &pNfapiMsg->sfn, end) && pull16(ppReadPackedMsg, &pNfapiMsg->slot, end) + && pull8(ppReadPackedMsg, &pNfapiMsg->message_id, end) && pull8(ppReadPackedMsg, &pNfapiMsg->error_code, end) + && unpack_nr_tlv_list(NULL, 0, ppReadPackedMsg, end, config, &(pNfapiMsg->vendor_extension))) { + return 1; + } else { + return 0; + } } diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c index 1b5e3f0ad8..5d1d0ba4e8 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c @@ -259,6 +259,40 @@ bool eq_config_request(const nfapi_nr_config_request_scf_t *unpacked_req, const EQ_TLV(unpacked_req->measurement_config.rssi_measurement, req->measurement_config.rssi_measurement); + EQ(unpacked_req->dbt_config.num_dig_beams, req->dbt_config.num_dig_beams); + + EQ(unpacked_req->dbt_config.num_txrus, req->dbt_config.num_txrus); + + for (int i = 0; i < req->dbt_config.num_dig_beams; i++) { + const nfapi_nr_dig_beam_t *unpacked_dig_beam = &unpacked_req->dbt_config.dig_beam_list[i]; + const nfapi_nr_dig_beam_t *req_dig_beam = &req->dbt_config.dig_beam_list[i]; + EQ(unpacked_dig_beam->beam_idx, req_dig_beam->beam_idx); + for (int k = 0; k < req->dbt_config.num_txrus; ++k) { + const nfapi_nr_txru_t *unpacked_tx_ru = &unpacked_dig_beam->txru_list[k]; + const nfapi_nr_txru_t *req_tx_ru = &req_dig_beam->txru_list[k]; + EQ(unpacked_tx_ru->dig_beam_weight_Re, req_tx_ru->dig_beam_weight_Re); + EQ(unpacked_tx_ru->dig_beam_weight_Im, req_tx_ru->dig_beam_weight_Im); + } + } + + EQ(unpacked_req->pmi_list.num_pm_idx, req->pmi_list.num_pm_idx); + + for (int i = 0; i < req->pmi_list.num_pm_idx; i++) { + const nfapi_nr_pm_pdu_t *req_pmi_pdu = &req->pmi_list.pmi_pdu[i]; + const nfapi_nr_pm_pdu_t *unpacked_pmi_pdu = &unpacked_req->pmi_list.pmi_pdu[i]; + EQ(unpacked_pmi_pdu->pm_idx, req_pmi_pdu->pm_idx); + EQ(unpacked_pmi_pdu->numLayers, req_pmi_pdu->numLayers); + EQ(unpacked_pmi_pdu->num_ant_ports, req_pmi_pdu->num_ant_ports); + for (int j = 0; j < req_pmi_pdu->num_ant_ports; ++j) { + for (int k = 0; k < req_pmi_pdu->num_ant_ports; ++k) { + const nfapi_nr_pm_weights_t* req_pm_weight = &req_pmi_pdu->weights[j][k]; + const nfapi_nr_pm_weights_t* unpacked_pm_weight = &unpacked_pmi_pdu->weights[j][k]; + EQ(unpacked_pm_weight->r, req_pm_weight->r); + EQ(unpacked_pm_weight->i, req_pm_weight->i); + } + } + } + EQ(unpacked_req->nfapi_config.p7_vnf_address_ipv4.tl.tag, req->nfapi_config.p7_vnf_address_ipv4.tl.tag); for (int i = 0; i < NFAPI_IPV4_ADDRESS_LENGTH; ++i) { EQ(unpacked_req->nfapi_config.p7_vnf_address_ipv4.address[i], req->nfapi_config.p7_vnf_address_ipv4.address[i]); @@ -391,27 +425,20 @@ bool eq_error_indication(const nfapi_nr_error_indication_scf_t *unpacked_req, co void free_param_request(nfapi_nr_param_request_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_param_response(nfapi_nr_param_response_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); + + free(msg->cell_param.config_tlvs_to_report_list); - if (msg->cell_param.config_tlvs_to_report_list) { - free(msg->cell_param.config_tlvs_to_report_list); - } } void free_config_request(nfapi_nr_config_request_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); if (msg->prach_config.num_prach_fd_occasions_list) { for (int i = 0; i < msg->prach_config.num_prach_fd_occasions.value; i++) { @@ -430,10 +457,14 @@ void free_config_request(nfapi_nr_config_request_scf_t *msg) free(msg->tdd_table.max_tdd_periodicity_list); } - if (msg->pmi_list.pmi_pdu) { - free(msg->pmi_list.pmi_pdu); + for (int i = 0; i < msg->dbt_config.num_dig_beams; i++) { + free(msg->dbt_config.dig_beam_list[i].txru_list); } + free(msg->dbt_config.dig_beam_list); + + free(msg->pmi_list.pmi_pdu); + if (msg->analog_beamforming_ve.analog_beam_list) { free(msg->analog_beamforming_ve.analog_beam_list); } @@ -441,60 +472,40 @@ void free_config_request(nfapi_nr_config_request_scf_t *msg) void free_config_response(nfapi_nr_config_response_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); - if (msg->invalid_tlvs_list) { - free(msg->invalid_tlvs_list); - } + free(msg->invalid_tlvs_list); - if (msg->invalid_tlvs_configured_in_idle_list) { - free(msg->invalid_tlvs_configured_in_idle_list); - } + free(msg->invalid_tlvs_configured_in_idle_list); - if (msg->invalid_tlvs_configured_in_running_list) { - free(msg->invalid_tlvs_configured_in_running_list); - } + free(msg->invalid_tlvs_configured_in_running_list); - if (msg->missing_tlvs_list) { - free(msg->missing_tlvs_list); - } + free(msg->missing_tlvs_list); } void free_start_request(nfapi_nr_start_request_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_start_response(nfapi_nr_start_response_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_stop_request(nfapi_nr_stop_request_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_stop_indication(nfapi_nr_stop_indication_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_error_indication(nfapi_nr_error_indication_scf_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void copy_param_request(const nfapi_nr_param_request_scf_t *src, nfapi_nr_param_request_scf_t *dst) @@ -810,6 +821,39 @@ void copy_config_request(const nfapi_nr_config_request_scf_t *src, nfapi_nr_conf COPY_TLV(dst->measurement_config.rssi_measurement, src->measurement_config.rssi_measurement); + dst->dbt_config.num_dig_beams = src->dbt_config.num_dig_beams; + dst->dbt_config.num_txrus = src->dbt_config.num_txrus; + dst->dbt_config.dig_beam_list = calloc(dst->dbt_config.num_dig_beams, sizeof(*dst->dbt_config.dig_beam_list)); + for (int i = 0; i < dst->dbt_config.num_dig_beams; i++) { + nfapi_nr_dig_beam_t *dst_dig_beam = &dst->dbt_config.dig_beam_list[i]; + const nfapi_nr_dig_beam_t *src_dig_beam = &src->dbt_config.dig_beam_list[i]; + dst_dig_beam->beam_idx = src_dig_beam->beam_idx; + dst_dig_beam->txru_list = calloc(dst->dbt_config.num_txrus , sizeof(*dst_dig_beam->txru_list )); + for (int k = 0; k < dst->dbt_config.num_txrus; ++k) { + nfapi_nr_txru_t *dst_tx_ru = &dst_dig_beam->txru_list[k]; + const nfapi_nr_txru_t *src_tx_ru = &src_dig_beam->txru_list[k]; + dst_tx_ru->dig_beam_weight_Re = src_tx_ru->dig_beam_weight_Re; + dst_tx_ru->dig_beam_weight_Im = src_tx_ru->dig_beam_weight_Im; + } + } + + dst->pmi_list.num_pm_idx = src->pmi_list.num_pm_idx; + if (dst->pmi_list.num_pm_idx > 0) { + dst->pmi_list.pmi_pdu = calloc(dst->pmi_list.num_pm_idx , sizeof(*dst->pmi_list.pmi_pdu)); + for (int i = 0; i < dst->pmi_list.num_pm_idx; i++) { + nfapi_nr_pm_pdu_t * dst_pmi_pdu = &dst->pmi_list.pmi_pdu[i]; + const nfapi_nr_pm_pdu_t * src_pmi_pdu = &src->pmi_list.pmi_pdu[i]; + dst_pmi_pdu->pm_idx = src_pmi_pdu->pm_idx; + dst_pmi_pdu->numLayers = src_pmi_pdu->numLayers; + dst_pmi_pdu->num_ant_ports = src_pmi_pdu->num_ant_ports; + for (int j = 0; j < dst_pmi_pdu->numLayers; ++j) { + for (int k = 0; k < dst_pmi_pdu->num_ant_ports; ++k) { + dst_pmi_pdu->weights[j][k] = src_pmi_pdu->weights[j][k]; + } + } + } + } + COPY_TL(dst->nfapi_config.p7_vnf_address_ipv4.tl, src->nfapi_config.p7_vnf_address_ipv4.tl); memcpy(dst->nfapi_config.p7_vnf_address_ipv4.address, src->nfapi_config.p7_vnf_address_ipv4.address, @@ -986,22 +1030,382 @@ void dump_param_request(const nfapi_nr_param_request_scf_t *msg) void dump_param_response(const nfapi_nr_param_response_scf_t *msg) { int depth = 0; - dump_p5_message_header(&msg->header,depth); + dump_p5_message_header(&msg->header, depth); depth++; INDENTED_PRINTF("Error Code = 0x%02x\n", msg->error_code); INDENTED_PRINTF("Number of TLVs = 0x%02x\n", msg->num_tlv); /* dump all TLVs from each table */ + /* Cell Param */ + const nfapi_nr_cell_param_t *cell_param = &msg->cell_param; + depth++; + INDENTED_TLV_PRINT("Release Capability", cell_param->release_capability); + INDENTED_TLV_PRINT("PHY State", cell_param->phy_state); + INDENTED_TLV_PRINT("Skip Blank Dl Config", cell_param->skip_blank_dl_config); + INDENTED_TLV_PRINT("Skip Blank UL Config", cell_param->skip_blank_ul_config); + INDENTED_TLV_PRINT("NumConfigTLVsToReport", cell_param->num_config_tlvs_to_report); + depth++; + for (int i = 0; i < cell_param->num_config_tlvs_to_report.value; i++) { + const nfapi_uint8_tlv_t *reportedTLV = &cell_param->config_tlvs_to_report_list[i]; + INDENTED_PRINTF("(0x%04x) Reported CONFIG TLV #%d = 0x%02x\n", reportedTLV->tl.tag, i + 1, reportedTLV->value); + } + depth--; + /* Carrier Param */ + const nfapi_nr_carrier_param_t *carrier_param = &msg->carrier_param; + INDENTED_TLV_PRINT("Cyclic Prefix", carrier_param->cyclic_prefix); + INDENTED_TLV_PRINT("Supported SCS DL", carrier_param->supported_subcarrier_spacings_dl); + INDENTED_TLV_PRINT("Supported BW DL", carrier_param->supported_bandwidth_dl); + INDENTED_TLV_PRINT("Supported SCS UL", carrier_param->supported_subcarrier_spacings_ul); + INDENTED_TLV_PRINT("Supported BW UL", carrier_param->supported_bandwidth_ul); + /* PDCCH Param */ + const nfapi_nr_pdcch_param_t *pdcch_param = &msg->pdcch_param; + INDENTED_TLV_PRINT("CCE Mapping Type", pdcch_param->cce_mapping_type); + INDENTED_TLV_PRINT("CSet Outside First 3 OFDM Symbols of Slot", pdcch_param->coreset_outside_first_3_of_ofdm_syms_of_slot); + INDENTED_TLV_PRINT("Precoder Granularity Coreset", pdcch_param->coreset_precoder_granularity_coreset); + INDENTED_TLV_PRINT("PDCCH Mu MIMO", pdcch_param->pdcch_mu_mimo); + INDENTED_TLV_PRINT("PDCCH Precoder Cycling", pdcch_param->pdcch_precoder_cycling); + INDENTED_TLV_PRINT("Max PDCCH per Slot", pdcch_param->max_pdcch_per_slot); + /* PUCHH Params */ + const nfapi_nr_pucch_param_t *pucch_param = &msg->pucch_param; + INDENTED_TLV_PRINT("PUCCH Formats", pucch_param->pucch_formats); + INDENTED_TLV_PRINT("Max PUCCH per Slot", pucch_param->max_pucchs_per_slot); + /* PDSCH Params */ + const nfapi_nr_pdsch_param_t *pdsch_param = &msg->pdsch_param; + INDENTED_TLV_PRINT("PDSCH Mapping Type", pdsch_param->pdsch_mapping_type); + INDENTED_TLV_PRINT("PDSCH Allocation Types", pdsch_param->pdsch_allocation_types); + INDENTED_TLV_PRINT("PDSCH VRB to PRB Mapping", pdsch_param->pdsch_vrb_to_prb_mapping); + INDENTED_TLV_PRINT("PDSCH CBG", pdsch_param->pdsch_cbg); + INDENTED_TLV_PRINT("PDSCH DMRS Config Types", pdsch_param->pdsch_dmrs_config_types); + INDENTED_TLV_PRINT("PDSCH DMRS Max Length", pdsch_param->pdsch_dmrs_max_length); + INDENTED_TLV_PRINT("PDSCH DMRS Additional Position", pdsch_param->pdsch_dmrs_additional_pos); + INDENTED_TLV_PRINT("Max PDSCH TBs per Slot", pdsch_param->max_pdsch_tbs_per_slot); + INDENTED_TLV_PRINT("Max number MIMO Layers PDSCH", pdsch_param->max_number_mimo_layers_pdsch); + INDENTED_TLV_PRINT("Supported Max Modulation Order DL", pdsch_param->supported_max_modulation_order_dl); + INDENTED_TLV_PRINT("Max Mu MIMO Users DL", pdsch_param->max_mu_mimo_users_dl); + INDENTED_TLV_PRINT("PDSCH Data in DMRS Symbols", pdsch_param->pdsch_data_in_dmrs_symbols); + INDENTED_TLV_PRINT("Preemption Support", pdsch_param->premption_support); + INDENTED_TLV_PRINT("PDSCH Non Slot Support", pdsch_param->pdsch_non_slot_support); + /* PUSCH Params */ + const nfapi_nr_pusch_param_t *pusch_param = &msg->pusch_param; + INDENTED_TLV_PRINT("UCI Mux ULSCH in PUSCH", pusch_param->uci_mux_ulsch_in_pusch); + INDENTED_TLV_PRINT("UCI Only PUSCH", pusch_param->uci_only_pusch); + INDENTED_TLV_PRINT("PUSCH Frequency Hopping", pusch_param->pusch_frequency_hopping); + INDENTED_TLV_PRINT("PUSCH DMRS Config Types", pusch_param->pusch_dmrs_config_types); + INDENTED_TLV_PRINT("PUSCH DMRS Max Len", pusch_param->pusch_dmrs_max_len); + INDENTED_TLV_PRINT("PUSCH DMRS Additional Pos", pusch_param->pusch_dmrs_additional_pos); + INDENTED_TLV_PRINT("PUSCH CBG", pusch_param->pusch_cbg); + INDENTED_TLV_PRINT("PUSCH Mapping Type", pusch_param->pusch_mapping_type); + INDENTED_TLV_PRINT("PUSCH Allocation Types", pusch_param->pusch_allocation_types); + INDENTED_TLV_PRINT("PUSCH VRB to PRB Mapping", pusch_param->pusch_vrb_to_prb_mapping); + INDENTED_TLV_PRINT("PUSCH Max PTRS Ports", pusch_param->pusch_max_ptrs_ports); + INDENTED_TLV_PRINT("Max PUSCH TBs per Slot", pusch_param->max_pduschs_tbs_per_slot); + INDENTED_TLV_PRINT("Max Number MIMO Layers non CB PUSCH", pusch_param->max_number_mimo_layers_non_cb_pusch); + INDENTED_TLV_PRINT("Supported Modulation Order UL", pusch_param->supported_modulation_order_ul); + INDENTED_TLV_PRINT("Max MU MIMO Users UL", pusch_param->max_mu_mimo_users_ul); + INDENTED_TLV_PRINT("DTFS OFDM Support", pusch_param->dfts_ofdm_support); + INDENTED_TLV_PRINT("PUSCH Aggregation Factor", pusch_param->pusch_aggregation_factor); + /* PRACH Params */ + const nfapi_nr_prach_param_t *prach_param = &msg->prach_param; + INDENTED_TLV_PRINT("PRACH Long Formats", prach_param->prach_long_formats); + INDENTED_TLV_PRINT("PRACH Short Formats", prach_param->prach_short_formats); + INDENTED_TLV_PRINT("PRACH Restricted Sets", prach_param->prach_restricted_sets); + INDENTED_TLV_PRINT("Max PRACH Occasions in a Slot", prach_param->max_prach_fd_occasions_in_a_slot); + /* Measurement Params */ + const nfapi_nr_measurement_param_t *measurement_param = &msg->measurement_param; + INDENTED_TLV_PRINT("RSSI Measurement Support", measurement_param->rssi_measurement_support); + /* nFAPI Config */ + const nfapi_nr_nfapi_t *nfapi_config = &msg->nfapi_config; + if (nfapi_config->p7_vnf_address_ipv4.tl.tag) { + char ip_str[INET_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 VNF Address IPv4", + "%s", + nfapi_config->p7_vnf_address_ipv4.tl.tag, + inet_ntop(AF_INET, nfapi_config->p7_vnf_address_ipv4.address, ip_str, sizeof(ip_str))); + } + if (nfapi_config->p7_vnf_address_ipv6.tl.tag) { + char addr6[INET6_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 VNF Address IPv6", + "%s", + nfapi_config->p7_vnf_address_ipv6.tl.tag, + inet_ntop(AF_INET6, nfapi_config->p7_vnf_address_ipv6.address, addr6, sizeof(addr6))); + } + INDENTED_TLV_FORMAT_PRINT("P7 VNF Port", "%d", nfapi_config->p7_vnf_port); + + if (nfapi_config->p7_pnf_address_ipv4.tl.tag) { + char ip_str[INET_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 PNF Address IPv4", + "%s", + nfapi_config->p7_pnf_address_ipv4.tl.tag, + inet_ntop(AF_INET, nfapi_config->p7_pnf_address_ipv4.address, ip_str, sizeof(ip_str))); + } + if (nfapi_config->p7_pnf_address_ipv6.tl.tag) { + char addr6[INET6_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 PNF Address IPv6", + "%s", + nfapi_config->p7_pnf_address_ipv6.tl.tag, + inet_ntop(AF_INET6, nfapi_config->p7_pnf_address_ipv6.address, addr6, sizeof(addr6))); + } + INDENTED_TLV_FORMAT_PRINT("P7 PNF Port", "%d", nfapi_config->p7_pnf_port); + INDENTED_TLV_FORMAT_PRINT("Timing Window", "%d", nfapi_config->timing_window); + INDENTED_TLV_FORMAT_PRINT("Timing Info Mode", "%d", nfapi_config->timing_info_mode); + INDENTED_TLV_FORMAT_PRINT("Timing Info Period", "%d", nfapi_config->timing_info_period); + INDENTED_TLV_FORMAT_PRINT("DL_TTI Timing Offset", "%d", nfapi_config->dl_tti_timing_offset); + INDENTED_TLV_FORMAT_PRINT("UL_TTI Timing Offset", "%d", nfapi_config->ul_tti_timing_offset); + INDENTED_TLV_FORMAT_PRINT("UL_DCI Timing Offset", "%d", nfapi_config->ul_dci_timing_offset); + INDENTED_TLV_FORMAT_PRINT("TX_DATA Timing Offset", "%d", nfapi_config->tx_data_timing_offset); depth--; } void dump_config_request(const nfapi_nr_config_request_scf_t *msg) { int depth = 0; - dump_p5_message_header(&msg->header,depth); + dump_p5_message_header(&msg->header, depth); depth++; INDENTED_PRINTF("Number of TLVs = 0x%02x\n", msg->num_tlv); /* dump all TLVs from each table */ + /* Carrier Config */ + const nfapi_nr_carrier_config_t *carrier_config = &msg->carrier_config; + INDENTED_TLV_PRINT("DL Bandwidth", carrier_config->dl_bandwidth); + INDENTED_TLV_PRINT("DL Frequency", carrier_config->dl_frequency); + INDENTED_PRINTF("(0x%04x) DL K0 = ", NFAPI_NR_CONFIG_DL_K0_TAG); + for (int i = 0; i < 5; i++) { + printf("%d ", carrier_config->dl_k0[i].value); + } + printf("\n"); + INDENTED_PRINTF("(0x%04x) DL Grid Size = ", NFAPI_NR_CONFIG_DL_GRID_SIZE_TAG); + for (int i = 0; i < 5; i++) { + printf("%d ", carrier_config->dl_grid_size[i].value); + } + printf("\n"); + INDENTED_TLV_PRINT("Num TX Antennas", carrier_config->num_tx_ant); + INDENTED_TLV_PRINT("UL Bandwidth", carrier_config->uplink_bandwidth); + INDENTED_TLV_PRINT("UL Frequency", carrier_config->uplink_frequency); + INDENTED_PRINTF("(0x%04x) UL K0 = ", NFAPI_NR_CONFIG_UL_K0_TAG); + for (int i = 0; i < 5; i++) { + printf("%d ", carrier_config->ul_k0[i].value); + } + printf("\n"); + INDENTED_PRINTF("(0x%04x) UL Grid Size = ", NFAPI_NR_CONFIG_UL_GRID_SIZE_TAG); + for (int i = 0; i < 5; i++) { + printf("%d ", carrier_config->ul_grid_size[i].value); + } + printf("\n"); + INDENTED_TLV_PRINT("Num RX Antennas", carrier_config->num_rx_ant); + INDENTED_TLV_PRINT("Frequency Shift 7p5KHz", carrier_config->frequency_shift_7p5khz); + /* Cell Config */ + const nfapi_nr_cell_config_t *cell_config = &msg->cell_config; + INDENTED_TLV_PRINT("Physical Cell ID", cell_config->phy_cell_id); + INDENTED_TLV_PRINT("Frame Duplex Type", cell_config->frame_duplex_type); + /* SSB Config */ + const nfapi_nr_ssb_config_t *ssb_config = &msg->ssb_config; + INDENTED_TLV_PRINT("SSB Block Power", ssb_config->ss_pbch_power); + INDENTED_TLV_PRINT("BCH Payload", ssb_config->bch_payload); + INDENTED_TLV_PRINT("SCS Common", ssb_config->scs_common); + /* PRACH Config */ + const nfapi_nr_prach_config_t *prach_config = &msg->prach_config; + INDENTED_TLV_PRINT("PRACH Sequence Length", prach_config->prach_sequence_length); + INDENTED_TLV_PRINT("PRACH Subcarrier Spacing", prach_config->prach_sub_c_spacing); + INDENTED_TLV_PRINT("Restricted Set Config", prach_config->restricted_set_config); + INDENTED_TLV_PRINT("Num PRACH FD Occasions", prach_config->num_prach_fd_occasions); + INDENTED_TLV_PRINT("PRACH Config Index", prach_config->prach_ConfigurationIndex); + depth++; + for (int i = 0; i < prach_config->num_prach_fd_occasions.value; i++) { + const nfapi_nr_num_prach_fd_occasions_t *prach_fd_occasion = &(prach_config->num_prach_fd_occasions_list[i]); + INDENTED_TLV_PRINT("PRACH Root Sequence Index", prach_fd_occasion->prach_root_sequence_index); + INDENTED_TLV_PRINT("Num Root Sequences", prach_fd_occasion->num_root_sequences); + INDENTED_TLV_PRINT("K1", prach_fd_occasion->k1); + INDENTED_TLV_PRINT("PRACH Zero CorrelationZone Config", prach_fd_occasion->prach_zero_corr_conf); + INDENTED_TLV_PRINT("Num Unused Root Sequences", prach_fd_occasion->num_unused_root_sequences); + depth++; + for (int k = 0; k < prach_fd_occasion->num_unused_root_sequences.value; k++) { + INDENTED_TLV_PRINT("Unused Root Sequence", prach_fd_occasion->unused_root_sequences_list[k]); + } + depth--; + } depth--; + INDENTED_TLV_PRINT("SSB Per RACH", prach_config->ssb_per_rach); + INDENTED_TLV_PRINT("PRACH Multiple Carriers in a Band", prach_config->prach_multiple_carriers_in_a_band); + /* SSB Table */ + const nfapi_nr_ssb_table_t *ssb_table = &msg->ssb_table; + INDENTED_TLV_PRINT("SSB Offset PointA", ssb_table->ssb_offset_point_a); + INDENTED_TLV_PRINT("Beta PSS", ssb_table->beta_pss); + INDENTED_TLV_PRINT("SSB Period", ssb_table->ssb_period); + INDENTED_TLV_PRINT("SSB Subcarrier Offset", ssb_table->ssb_subcarrier_offset); + INDENTED_TLV_PRINT("MIB", ssb_table->MIB); + + INDENTED_PRINTF("SSB Mask:\n"); + depth++; + for (int i = 0; i < 2; i++) { + INDENTED_TLV_PRINT("SSB Mask", ssb_table->ssb_mask_list[i].ssb_mask); + } + depth--; + INDENTED_PRINTF("Beam ID:\n"); + depth++; + for (int i = 0; i < 64; i++) { + INDENTED_TLV_PRINT("Beam ID", ssb_table->ssb_beam_id_list[i].beam_id); + } + depth--; + INDENTED_TLV_PRINT("ssPBCH Multiple Carriers in a Band", ssb_table->ss_pbch_multiple_carriers_in_a_band); + INDENTED_TLV_PRINT("Multiple Cells ssPBCH in a Carrier", ssb_table->multiple_cells_ss_pbch_in_a_carrier); + /* TDD Table */ + const nfapi_nr_tdd_table_t *tdd_table = &msg->tdd_table; + if (cell_config->frame_duplex_type.value == 1 /* TDD */) { + INDENTED_TLV_PRINT("TDD Period", tdd_table->tdd_period); + const uint8_t slotsperframe[5] = {10, 20, 40, 80, 160}; + // Assuming always CP_Normal, because Cyclic prefix is not included in CONFIG.request 10.02, but is present in 10.04 + uint8_t cyclicprefix = 1; + // 3GPP 38.211 Table 4.3.2.1 & Table 4.3.2.2 + uint8_t number_of_symbols_per_slot = cyclicprefix ? 14 : 12; + INDENTED_PRINTF("Slot Config:\n"); + depth++; + for (int i = 0; i < slotsperframe[ssb_config->scs_common.value]; i++) { + for (int k = 0; k < number_of_symbols_per_slot; k++) { + const uint8_t slot_type = tdd_table->max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list[k].slot_config.value; + const char *slot_dir = slot_type == 0 ? "DL" : slot_type == 1 ? "UL" : "S"; + INDENTED_GENERIC_PRINT("(0x%04x) Slot Config", + "%d (%s)", + tdd_table->max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list[k].slot_config.tl.tag, + slot_type, + slot_dir); + } + } + depth--; + } + /* Measurement Config */ + const nfapi_nr_measurement_config_t *measurement_config = &msg->measurement_config; + INDENTED_TLV_PRINT("RSSI Measurement", measurement_config->rssi_measurement); + /* Beamforming Table */ + const nfapi_nr_dbt_pdu_t *dbt_config = &msg->dbt_config; + INDENTED_PRINTF("Digital Beam Table\n"); + depth++; + INDENTED_GENERIC_PRINT("Num Digital Beams", "%d", dbt_config->num_dig_beams); + INDENTED_GENERIC_PRINT("Num TX RUs", "%d", dbt_config->num_txrus); + depth++; + for (int i = 0; i < dbt_config->num_dig_beams; i++) { + const nfapi_nr_dig_beam_t *dig_beam = &dbt_config->dig_beam_list[i]; + INDENTED_GENERIC_PRINT("Beam IDX", "%d", dig_beam->beam_idx); + depth++; + for (int k = 0; k < dbt_config->num_txrus; k++) { + const nfapi_nr_txru_t *tx_ru = &dig_beam->txru_list[k]; + INDENTED_GENERIC_PRINT("Dig Beam Weight Real", "0x%02x", tx_ru->dig_beam_weight_Re); + INDENTED_GENERIC_PRINT("Dig Beam Weight Imaginary", "0x%02x", tx_ru->dig_beam_weight_Im); + } + depth--; + } + depth--; + depth--; + + /* Precoding Table */ + const nfapi_nr_pm_list_t *pmi_list = &msg->pmi_list; + INDENTED_PRINTF("Precoding Matrix Table\n"); + depth++; + INDENTED_GENERIC_PRINT("Num Precoding Tables", "%d", pmi_list->num_pm_idx); + depth++; + for (int i = 0; i < pmi_list->num_pm_idx; i++) { + const nfapi_nr_pm_pdu_t *pm_pdu = &pmi_list->pmi_pdu[i]; + + INDENTED_GENERIC_PRINT("Precoding Matrix IDX", "0x%02x", pm_pdu->pm_idx); + INDENTED_GENERIC_PRINT("Number of Layers", "%d", pm_pdu->numLayers); + INDENTED_GENERIC_PRINT("Number of Antenna Ports", "%d", pm_pdu->num_ant_ports); + depth++; + for (int k = 0; k < pm_pdu->numLayers; k++) { + for (int l = 0; l < pm_pdu->num_ant_ports; l++) { + const nfapi_nr_pm_weights_t *pm_weights = &pm_pdu->weights[k][l]; + INDENTED_GENERIC_PRINT("Dig Beam Weight Real", "0x%02x", pm_weights->r); + INDENTED_GENERIC_PRINT("Dig Beam Weight Imaginary", "0x%02x", pm_weights->i); + } + } + depth--; + } + depth--; + depth--; + /* nFAPI Config */ + const nfapi_nr_nfapi_t *nfapi_config = &msg->nfapi_config; + if (nfapi_config->p7_vnf_address_ipv4.tl.tag) { + char ip_str[INET_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 VNF Address IPv4", + "%s", + nfapi_config->p7_vnf_address_ipv4.tl.tag, + inet_ntop(AF_INET, nfapi_config->p7_vnf_address_ipv4.address, ip_str, sizeof(ip_str))); + } + if (nfapi_config->p7_vnf_address_ipv6.tl.tag) { + char addr6[INET6_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 VNF Address IPv6", + "%s", + nfapi_config->p7_vnf_address_ipv6.tl.tag, + inet_ntop(AF_INET6, nfapi_config->p7_vnf_address_ipv6.address, addr6, sizeof(addr6))); + } + INDENTED_TLV_FORMAT_PRINT("P7 VNF Port", "%d", nfapi_config->p7_vnf_port); + + if (nfapi_config->p7_pnf_address_ipv4.tl.tag) { + char ip_str[INET_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 PNF Address IPv4", + "%s", + nfapi_config->p7_pnf_address_ipv4.tl.tag, + inet_ntop(AF_INET, nfapi_config->p7_pnf_address_ipv4.address, ip_str, sizeof(ip_str))); + } + if (nfapi_config->p7_pnf_address_ipv6.tl.tag) { + char addr6[INET6_ADDRSTRLEN]; + INDENTED_GENERIC_PRINT("(0x%04x) P7 PNF Address IPv6", + "%s", + nfapi_config->p7_pnf_address_ipv6.tl.tag, + inet_ntop(AF_INET6, nfapi_config->p7_pnf_address_ipv6.address, addr6, sizeof(addr6))); + } + INDENTED_TLV_FORMAT_PRINT("P7 PNF Port", "%d", nfapi_config->p7_pnf_port); + INDENTED_TLV_FORMAT_PRINT("Timing Window", "%d", nfapi_config->timing_window); + INDENTED_TLV_FORMAT_PRINT("Timing Info Mode", "%d", nfapi_config->timing_info_mode); + INDENTED_TLV_FORMAT_PRINT("Timing Info Period", "%d", nfapi_config->timing_info_period); + INDENTED_TLV_FORMAT_PRINT("DL_TTI Timing Offset", "%d", nfapi_config->dl_tti_timing_offset); + INDENTED_TLV_FORMAT_PRINT("UL_TTI Timing Offset", "%d", nfapi_config->ul_tti_timing_offset); + INDENTED_TLV_FORMAT_PRINT("UL_DCI Timing Offset", "%d", nfapi_config->ul_dci_timing_offset); + INDENTED_TLV_FORMAT_PRINT("TX_DATA Timing Offset", "%d", nfapi_config->tx_data_timing_offset); + /* Beamforming VE */ + const nfapi_nr_analog_beamforming_ve_t *analog_beamforming_ve = &msg->analog_beamforming_ve; + INDENTED_TLV_FORMAT_PRINT("Num Beams per Period", "%d", analog_beamforming_ve->num_beams_period_vendor_ext); + INDENTED_TLV_PRINT("Analog Beamforming VE", analog_beamforming_ve->analog_bf_vendor_ext); + /* Vendor Extension */ + if (msg->vendor_extension) { + const nfapi_tl_t *vendor_extension = (nfapi_tl_t *)&msg->vendor_extension; + switch (vendor_extension->tag) { + case VENDOR_EXT_TLV_1_TAG: { + vendor_ext_tlv_1 *ve = (vendor_ext_tlv_1 *)vendor_extension; + INDENTED_PRINTF("(0x%04x) Vendor extension = %d 0x%02x\n", ve->tl.tag, ve->tl.length, ve->dummy); + } break; + case VENDOR_EXT_TLV_2_TAG: { + vendor_ext_tlv_2 *ve = (vendor_ext_tlv_2 *)vendor_extension; + INDENTED_PRINTF("(0x%04x) Vendor extension = %d 0x%02x\n", ve->tl.tag, ve->tl.length, ve->dummy); + } break; + default: + break; + } + } + + depth--; +} + +static void dump_generic_tlv(const nfapi_nr_generic_tlv_scf_t* tlv, int depth) +{ + INDENTED_PRINTF("TLV tag 0x%02x , Length 0x%02x , Value ", tlv->tl.tag, tlv->tl.length); + switch (tlv->tl.length) { + case UINT_8: + printf("0x%x\n", tlv->value.u8); + break; + case UINT_16: + printf("0x%02x\n", tlv->value.u16); + break; + case UINT_32: + printf("0x%04x\n", tlv->value.u32); + break; + case ARRAY_UINT_16: + for (int i = 0; i< 5 ; i++) { + printf("0x%04x ", tlv->value.array_u16[i]); + } + printf("\n"); + break; + default: + printf("unknown length %d\n", tlv->tl.length); + DevAssert(1 == 0); + break; + } } void dump_config_response(const nfapi_nr_config_response_scf_t *msg) @@ -1016,6 +1420,25 @@ void dump_config_response(const nfapi_nr_config_response_scf_t *msg) msg->num_invalid_tlvs_configured_in_running); INDENTED_PRINTF("Number of Missing TLVs = 0x%02x\n", msg->num_missing_tlvs); /* dump all TLVs from each table */ + INDENTED_PRINTF("Invalid or Unsupported TLVs (%d) :\n",msg->num_invalid_tlvs); + for (int i = 0; i < msg->num_invalid_tlvs; ++i) { + dump_generic_tlv(&msg->invalid_tlvs_list[i], depth+1); + } + + INDENTED_PRINTF("TLVs that can only be configured in IDLE (%d):\n", msg->num_invalid_tlvs_configured_in_idle); + for (int i = 0; i < msg->num_invalid_tlvs; ++i) { + dump_generic_tlv(&msg->invalid_tlvs_list[i], depth+1); + } + + INDENTED_PRINTF("TLVs that can only be configured in RUNNING (%d):\n",msg->num_invalid_tlvs_configured_in_running); + for (int i = 0; i < msg->num_invalid_tlvs; ++i) { + dump_generic_tlv(&msg->invalid_tlvs_list[i], depth+1); + } + + INDENTED_PRINTF("Missing TLVs (%d):\n",msg->num_missing_tlvs); + for (int i = 0; i < msg->num_invalid_tlvs; ++i) { + dump_generic_tlv(&msg->invalid_tlvs_list[i], depth+1); + } depth--; } @@ -1043,29 +1466,13 @@ void dump_stop_indication(const nfapi_nr_stop_indication_scf_t *msg) dump_p5_message_header(&msg->header,depth); } -static char *error_code_to_str(uint8_t error_code) +char* error_ind_code_to_str(nfapi_nr_phy_notifications_errors_e error_code) { switch (error_code) { - case NFAPI_NR_PHY_API_MSG_OK: - return "NFAPI_NR_PHY_API_MSG_OK"; - case NFAPI_NR_PHY_API_MSG_INVALID_STATE: - return "NFAPI_NR_PHY_API_MSG_INVALID_STATE"; - case NFAPI_NR_PHY_API_MSG_INVALID_CONFIG: - return "NFAPI_NR_PHY_API_MSG_INVALID_CONFIG"; - case NFAPI_NR_PHY_API_SFN_OUT_OF_SYNC: - return "NFAPI_NR_PHY_API_SFN_OUT_OF_SYNC"; - case NFAPI_NR_PHY_API_MSG_SLOR_ERR: - return "NFAPI_NR_PHY_API_MSG_SLOR_ERR"; - case NFAPI_NR_PHY_API_MSG_BCH_MISSING: - return "NFAPI_NR_PHY_API_MSG_BCH_MISSING"; - case NFAPI_NR_PHY_API_MSG_INVALID_SFN: - return "NFAPI_NR_PHY_API_MSG_INVALID_SFN"; - case NFAPI_NR_PHY_API_MSG_UL_DCI_ERR: - return "NFAPI_NR_PHY_API_MSG_UL_DCI_ERR"; - case NFAPI_NR_PHY_API_MSG_TX_ERR: - return "NFAPI_NR_PHY_API_MSG_TX_ERR"; - default: - return "Unknown Error code"; +#define X(name, value) case name: return #name; + NFAPI_PHY_ERROR_LIST +#undef X + default: return "UNKNOWN_ERROR"; } } @@ -1077,6 +1484,6 @@ void dump_error_indication(const nfapi_nr_error_indication_scf_t *msg) INDENTED_PRINTF("SFN = 0x%02x (%d)\n", msg->sfn, msg->sfn); INDENTED_PRINTF("Slot = 0x%02x (%d)\n", msg->slot, msg->slot); INDENTED_PRINTF("Message ID = 0x%02x\n", msg->message_id); - INDENTED_PRINTF("Error Code = 0x%02x (%s) \n", msg->error_code, error_code_to_str(msg->error_code)); + INDENTED_PRINTF("Error Code = 0x%02x (%s) \n", msg->error_code, error_ind_code_to_str(msg->error_code)); depth--; } diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c index 7b840fc126..aa90d3b4b9 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7.c @@ -134,7 +134,7 @@ int fapi_nr_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packed return packedMsgLen; } -int fapi_nr_p7_message_unpack(void *pMessageBuf, +bool fapi_nr_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, @@ -143,25 +143,24 @@ int fapi_nr_p7_message_unpack(void *pMessageBuf, int result = 0; nfapi_nr_p7_message_header_t *pMessageHeader = (nfapi_nr_p7_message_header_t *)pUnpackedBuf; fapi_message_header_t fapi_hdr; - uint8_t *pReadPackedMessage = pMessageBuf; - AssertFatal(pMessageBuf != NULL && pUnpackedBuf != NULL, "P7 unpack supplied pointers are null"); - uint8_t *end = (uint8_t *)pMessageBuf + messageBufLen; + AssertFatal(messageBufLen >= NFAPI_HEADER_LENGTH && unpackedBufLen >= sizeof(fapi_message_header_t), "P5 unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); - - if (fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &fapi_hdr, sizeof(fapi_message_header_t), 0) < 0) { + if (!fapi_nr_message_header_unpack(pMessageBuf, NFAPI_HEADER_LENGTH, &fapi_hdr, sizeof(fapi_message_header_t), 0)) { // failed to read the header - return -1; + return false; } + uint8_t *pReadPackedMessage = pMessageBuf + NFAPI_HEADER_LENGTH; + uint8_t *end = (uint8_t *)pMessageBuf + messageBufLen; pMessageHeader->message_length = fapi_hdr.message_length; pMessageHeader->message_id = fapi_hdr.message_id; if ((uint8_t *)(pMessageBuf + pMessageHeader->message_length) > end) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack message length is greater than the message buffer \n"); - return -1; + return false; } // look for the specific message @@ -232,9 +231,9 @@ int fapi_nr_p7_message_unpack(void *pMessageBuf, if (result == 0) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Unpack failed to unpack message\n"); - return -1; + return false; } - return 0; + return true; } static uint8_t pack_nr_tx_beamforming_pdu(const nfapi_nr_tx_precoding_and_beamforming_t *beamforming_pdu, @@ -2309,7 +2308,7 @@ uint8_t unpack_nr_srs_report_tlv_value(nfapi_srs_report_tlv_t *report_tlv, uint8 } } #else - const uint16_t last_idx = ((report_tlv->length + 3) / 4) - 1; + const int16_t last_idx = ((report_tlv->length + 3) / 4) - 1; for (int i = 0; i < last_idx; i++) { if (!pull32(ppReadPackedMsg, &report_tlv->value[i], end)) { return 0; diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c index 9939a6f535..fb645707ad 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p7_utils.c @@ -859,9 +859,7 @@ bool eq_rach_indication(const nfapi_nr_rach_indication_t *a, const nfapi_nr_rach void free_dl_tti_request(nfapi_nr_dl_tti_request_t *msg) { - if (msg->vendor_extension) { - free(msg->vendor_extension); - } + free(msg->vendor_extension); } void free_ul_tti_request(nfapi_nr_ul_tti_request_t *msg) @@ -907,9 +905,7 @@ void free_rx_data_indication(nfapi_nr_rx_data_indication_t *msg) if (msg->number_of_pdus > 0) { for (int pdu_idx = 0; pdu_idx < msg->number_of_pdus; ++pdu_idx) { nfapi_nr_rx_data_pdu_t *rx_pdu = &msg->pdu_list[pdu_idx]; - if (rx_pdu->pdu) { - free(rx_pdu->pdu); - } + free(rx_pdu->pdu); } free(msg->pdu_list); } @@ -917,99 +913,75 @@ void free_rx_data_indication(nfapi_nr_rx_data_indication_t *msg) void free_crc_indication(nfapi_nr_crc_indication_t *msg) { - if (msg->crc_list) { - for (int crc_idx = 0; crc_idx < msg->number_crcs; ++crc_idx) { - nfapi_nr_crc_t *crc = &msg->crc_list[crc_idx]; - if (crc->cb_crc_status) { - free(crc->cb_crc_status); - } - } - free(msg->crc_list); + for (int crc_idx = 0; crc_idx < msg->number_crcs; ++crc_idx) { + nfapi_nr_crc_t *crc = &msg->crc_list[crc_idx]; + free(crc->cb_crc_status); } + free(msg->crc_list); } void free_uci_indication(nfapi_nr_uci_indication_t *msg) { - if (msg->uci_list) { - for (int pdu_idx = 0; pdu_idx < msg->num_ucis; ++pdu_idx) { - nfapi_nr_uci_t *uci_pdu = &msg->uci_list[pdu_idx]; - switch (uci_pdu->pdu_type) { - case NFAPI_NR_UCI_PUSCH_PDU_TYPE: { - nfapi_nr_uci_pusch_pdu_t *pdu = &uci_pdu->pusch_pdu; - // Bit 0 not used in PUSCH PDU - // HARQ - if ((pdu->pduBitmap >> 1) & 0x01) { - if (pdu->harq.harq_payload) { - free(pdu->harq.harq_payload); - } - } - // CSI Part 1 - if ((pdu->pduBitmap >> 2) & 0x01) { - if (pdu->csi_part1.csi_part1_payload) { - free(pdu->csi_part1.csi_part1_payload); - } - } - // CSI Part 2 - if ((pdu->pduBitmap >> 3) & 0x01) { - if (pdu->csi_part2.csi_part2_payload) { - free(pdu->csi_part2.csi_part2_payload); - } - } - break; + for (int pdu_idx = 0; pdu_idx < msg->num_ucis; ++pdu_idx) { + nfapi_nr_uci_t *uci_pdu = &msg->uci_list[pdu_idx]; + switch (uci_pdu->pdu_type) { + case NFAPI_NR_UCI_PUSCH_PDU_TYPE: { + nfapi_nr_uci_pusch_pdu_t *pdu = &uci_pdu->pusch_pdu; + // Bit 0 not used in PUSCH PDU + // HARQ + if ((pdu->pduBitmap >> 1) & 0x01) { + free(pdu->harq.harq_payload); } - case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: { - // Nothing to free - break; + // CSI Part 1 + if ((pdu->pduBitmap >> 2) & 0x01) { + free(pdu->csi_part1.csi_part1_payload); } - case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: { - nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu = &uci_pdu->pucch_pdu_format_2_3_4; - // SR - if (pdu->pduBitmap & 0x01) { - if (pdu->sr.sr_payload) { - free(pdu->sr.sr_payload); - } - } - // HARQ - if ((pdu->pduBitmap >> 1) & 0x01) { - if (pdu->harq.harq_payload) { - free(pdu->harq.harq_payload); - } - } - // CSI Part 1 - if ((pdu->pduBitmap >> 2) & 0x01) { - if (pdu->csi_part1.csi_part1_payload) { - free(pdu->csi_part1.csi_part1_payload); - } - } - // CSI Part 2 - if ((pdu->pduBitmap >> 3) & 0x01) { - if (pdu->csi_part2.csi_part2_payload) { - free(pdu->csi_part2.csi_part2_payload); - } - } - break; + // CSI Part 2 + if ((pdu->pduBitmap >> 3) & 0x01) { + free(pdu->csi_part2.csi_part2_payload); } - default: - AssertFatal(1 == 0, "Unknown UCI.indication PDU Type %d\n", uci_pdu->pdu_type); - break; + break; } + case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: { + // Nothing to free + break; + } + case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: { + nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu = &uci_pdu->pucch_pdu_format_2_3_4; + // SR + if (pdu->pduBitmap & 0x01) { + free(pdu->sr.sr_payload); + } + // HARQ + if ((pdu->pduBitmap >> 1) & 0x01) { + free(pdu->harq.harq_payload); + } + // CSI Part 1 + if ((pdu->pduBitmap >> 2) & 0x01) { + free(pdu->csi_part1.csi_part1_payload); + } + // CSI Part 2 + if ((pdu->pduBitmap >> 3) & 0x01) { + free(pdu->csi_part2.csi_part2_payload); + } + break; + } + default: + AssertFatal(1 == 0, "Unknown UCI.indication PDU Type %d\n", uci_pdu->pdu_type); + break; } - free(msg->uci_list); } + free(msg->uci_list); } void free_srs_indication(nfapi_nr_srs_indication_t *msg) { - if (msg->pdu_list) { - free(msg->pdu_list); - } + free(msg->pdu_list); } void free_rach_indication(nfapi_nr_rach_indication_t *msg) { - if (msg->pdu_list) { - free(msg->pdu_list); - } + free(msg->pdu_list); } static void copy_dl_tti_beamforming(const nfapi_nr_tx_precoding_and_beamforming_t *src, @@ -2586,6 +2558,27 @@ void dump_ul_dci_request(const nfapi_nr_ul_dci_request_t *msg) } } +static void dump_tx_data_request_tlv(const nfapi_nr_tx_data_request_tlv_t *tlv, int depth) +{ + INDENTED_PRINTF("Tag = %d\n", tlv->tag); + INDENTED_PRINTF("Length = %d\n", tlv->length); + INDENTED_PRINTF("Value = "); + switch (tlv->tag) { + case 0: + for (int i = 0; i < tlv->length; i++) { + printf("0x%02x ", ((uint8_t*)tlv->value.direct)[i]); + } + break; + case 1: + printf("%p", tlv->value.ptr); + break; + default: + printf( " Unknown tag value %d",tlv->tag); + break; + } + printf("\n"); +} + void dump_tx_data_request(const nfapi_nr_tx_data_request_t *msg) { int depth = 0; @@ -2594,15 +2587,18 @@ void dump_tx_data_request(const nfapi_nr_tx_data_request_t *msg) INDENTED_PRINTF("SFN = %d\n", msg->SFN); INDENTED_PRINTF("Slot = %d\n", msg->Slot); INDENTED_PRINTF("Number of PDUs = %d\n", msg->Number_of_PDUs); + depth++; for (int i = 0; i < msg->Number_of_PDUs; i++) { - depth++; INDENTED_PRINTF("PDU #%d\n", i); const nfapi_nr_pdu_t *pdu = &msg->pdu_list[i]; INDENTED_PRINTF("PDU Length = 0x%02x\n", pdu->PDU_length); INDENTED_PRINTF("PDU Index = 0x%02x\n", pdu->PDU_index); INDENTED_PRINTF("numTLV = 0x%02x\n", pdu->num_TLV); + for (int tlv_idx = 0; tlv_idx < pdu->num_TLV; tlv_idx++) { + const nfapi_nr_tx_data_request_tlv_t *tlv = &pdu->TLVs[tlv_idx]; /* call to dump_tx_data_request_tlv */ - depth--; + dump_tx_data_request_tlv(tlv, depth + 1); + } } } @@ -2664,6 +2660,134 @@ void dump_crc_indication(const nfapi_nr_crc_indication_t *msg) } } +static void dump_harq_2_3_4(const nfapi_nr_harq_pdu_2_3_4_t *harq, int depth) +{ + INDENTED_PRINTF("HARQ CRC = %01x\n", harq->harq_crc); + INDENTED_PRINTF("HARQ Bit Length = %d\n", harq->harq_bit_len); + INDENTED_PRINTF("HARQ Payload = "); + for (int i = 0; i < harq->harq_bit_len / 8 + 1; i++) { + printf("%x ", harq->harq_payload[i]); + } + printf("\n"); +} + +static void dump_csi_part_1(const nfapi_nr_csi_part1_pdu_t *csi, int depth) +{ + INDENTED_PRINTF("CSI Part 1 CRC = %01x\n", csi->csi_part1_crc); + INDENTED_PRINTF("CSI Part 1 Bit Length = %d\n", csi->csi_part1_bit_len); + INDENTED_PRINTF("CSI Part 1 Payload = "); + for (int i = 0; i < csi->csi_part1_bit_len / 8 + 1; i++) { + printf("%x ", csi->csi_part1_payload[i]); + } + printf("\n"); +} + +static void dump_csi_part_2(const nfapi_nr_csi_part2_pdu_t *csi, int depth) +{ + INDENTED_PRINTF("CSI Part 1 CRC = %01x\n", csi->csi_part2_crc); + INDENTED_PRINTF("CSI Part 1 Bit Length = %d\n", csi->csi_part2_bit_len); + INDENTED_PRINTF("CSI Part 1 Payload = "); + for (int i = 0; i < csi->csi_part2_bit_len / 8 + 1; i++) { + printf("%x ", csi->csi_part2_payload[i]); + } + printf("\n"); +} + +static void dump_uci_PUSCH_PDU(const nfapi_nr_uci_pusch_pdu_t *pdu, int depth) +{ + INDENTED_PRINTF("PDU Bitmap = 0x%01x\n", pdu->pduBitmap); + INDENTED_PRINTF("Handle = 0x%04x\n", pdu->handle); + INDENTED_PRINTF("RNTI = 0x%02x\n", pdu->rnti); + INDENTED_PRINTF("UL_CQI = 0x%02x\n", pdu->ul_cqi); + INDENTED_PRINTF("Timing Advance = 0x%02x\n", pdu->timing_advance); + INDENTED_PRINTF("RSSI = 0x%02x\n", pdu->rssi); + // HARQ payload, CSI Part 1 and 2 are conditionally allocated + if ((pdu->pduBitmap >> 1) & 0x01) { + INDENTED_PRINTF("HARQ Information\n"); + dump_harq_2_3_4(&pdu->harq, depth + 1); + } + if ((pdu->pduBitmap >> 2) & 0x01) { + INDENTED_PRINTF("CSI Part 1\n"); + dump_csi_part_1(&pdu->csi_part1, depth + 1); + } + if ((pdu->pduBitmap >> 3) & 0x01) { + INDENTED_PRINTF("CSI Part 1\n"); + dump_csi_part_2(&pdu->csi_part2, depth + 1); + } +} + +static void dump_sr_0_1(const nfapi_nr_sr_pdu_0_1_t *sr, int depth) +{ + INDENTED_PRINTF("SR Indication = 0x%02x\n", sr->sr_indication); + INDENTED_PRINTF("SR Confidence Level = 0x%02x\n", sr->sr_confidence_level); +} + +static void dump_harq_0_1(const nfapi_nr_harq_pdu_0_1_t *harq, int depth) +{ + INDENTED_PRINTF("Num HARQ = 0x%02x\n", harq->num_harq); + INDENTED_PRINTF("HARQ Confidence Level = 0x%02x\n", harq->harq_confidence_level); + depth++; + for (int i = 0; i < harq->num_harq; i++) { + INDENTED_PRINTF("HARQ Value[%d] : 0x%02x \n", i, harq->harq_list[i].harq_value); + } +} + +static void dump_uci_PUCCH_0_1(const nfapi_nr_uci_pucch_pdu_format_0_1_t *pdu, int depth) +{ + INDENTED_PRINTF("PDU Bitmap = 0x%01x\n", pdu->pduBitmap); + INDENTED_PRINTF("Handle = 0x%04x\n", pdu->handle); + INDENTED_PRINTF("RNTI = 0x%02x\n", pdu->rnti); + INDENTED_PRINTF("PUCCH Format = 0x%02x\n", pdu->pucch_format); + INDENTED_PRINTF("UL_CQI = 0x%02x\n", pdu->ul_cqi); + INDENTED_PRINTF("Timing Advance = 0x%02x\n", pdu->timing_advance); + INDENTED_PRINTF("RSSI = 0x%02x\n", pdu->rssi); + if ((pdu->pduBitmap) & 0x01) { + INDENTED_PRINTF("SR Information\n"); + dump_sr_0_1(&pdu->sr, depth + 1); + } + if ((pdu->pduBitmap >> 1) & 0x01) { + INDENTED_PRINTF("HARQ Information\n"); + dump_harq_0_1(&pdu->harq, depth + 1); + } +} + +static void dump_sr_2_3_4(const nfapi_nr_sr_pdu_2_3_4_t *sr, int depth) +{ + INDENTED_PRINTF("SR Bit Length = %d\n", sr->sr_bit_len); + INDENTED_PRINTF("SR Payload "); + for (int i = 0; i < sr->sr_bit_len / 8 + 1; i++) { + printf("%x ", sr->sr_payload[i]); + } + printf("\n"); +} + +static void dump_uci_PUCCH_2_3_4(const nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu, int depth) +{ + INDENTED_PRINTF("PDU Bitmap = 0x%01x\n", pdu->pduBitmap); + INDENTED_PRINTF("Handle = 0x%04x\n", pdu->handle); + INDENTED_PRINTF("RNTI = 0x%02x\n", pdu->rnti); + INDENTED_PRINTF("PUCCH Format = 0x%02x\n", pdu->pucch_format); + INDENTED_PRINTF("UL_CQI = 0x%02x\n", pdu->ul_cqi); + INDENTED_PRINTF("Timing Advance = 0x%02x\n", pdu->timing_advance); + INDENTED_PRINTF("RSSI = 0x%02x\n", pdu->rssi); + // SR + if (pdu->pduBitmap & 0x01) { + dump_sr_2_3_4(&pdu->sr, depth + 1); + } + // HARQ + if ((pdu->pduBitmap >> 1) & 0x01) { + dump_harq_2_3_4(&pdu->harq, depth + 1); + } + // CSI Part 1 + if ((pdu->pduBitmap >> 2) & 0x01) { + dump_csi_part_1(&pdu->csi_part1, depth + 1); + } + // CSI Part 2 + if ((pdu->pduBitmap >> 3) & 0x01) { + dump_csi_part_2(&pdu->csi_part2, depth + 1); + } +} + void dump_uci_indication(const nfapi_nr_uci_indication_t *msg) { int depth = 0; @@ -2680,6 +2804,20 @@ void dump_uci_indication(const nfapi_nr_uci_indication_t *msg) INDENTED_PRINTF("PDUType = 0x%02x\n", uci->pdu_type); INDENTED_PRINTF("PDUSize = 0x%02x\n", uci->pdu_size); /* call to dump_uci_indication__pdu */ + switch (uci->pdu_type) { + case NFAPI_NR_UCI_PUSCH_PDU_TYPE: + dump_uci_PUSCH_PDU(&uci->pusch_pdu, depth + 1); + break; + case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: + dump_uci_PUCCH_0_1(&uci->pucch_pdu_format_0_1, depth + 1); + break; + case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: + dump_uci_PUCCH_2_3_4(&uci->pucch_pdu_format_2_3_4, depth + 1); + break; + default: + INDENTED_PRINTF("Unknown PDU type 0x%02x\n", uci->pdu_type); + break; + } depth--; } } diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h index 37b661afb9..57292ecee5 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h @@ -20,7 +20,7 @@ #define FAPI_NR_RX_PDU_TYPE_DLSCH 0x03 #define FAPI_NR_DCI_IND 0x04 #define FAPI_NR_RX_PDU_TYPE_RAR 0x05 -#define FAPI_NR_CSIRS_IND 0x06 +#define FAPI_NR_MEAS_IND 0x06 #define FAPI_NR_SIBS_MASK_SIB1 0x1 diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index 140ed130a4..dc52f1de2a 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -49,16 +49,25 @@ typedef enum { NFAPI_NR_FORMAT_0_1_AND_1_1, } nfapi_nr_dci_formats_e; +typedef enum { + NFAPI_NR_CSI_MEAS, + NFAPI_NR_SS_MEAS +} nfapi_nr_meas_type_e; typedef struct { - uint32_t rsrp; + uint32_t gNB_index; + uint16_t Nid_cell; + nfapi_nr_meas_type_e meas_type; + bool is_neighboring_cell; + int ssb_index; int rsrp_dBm; + float sinr_dB; uint8_t rank_indicator; uint16_t i1; uint8_t i2; uint8_t cqi; rlm_t radiolink_monitoring; -} fapi_nr_csirs_measurements_t; +} fapi_nr_l1_measurements_t; typedef struct { /// frequency_domain_resource; @@ -126,11 +135,8 @@ typedef struct { uint8_t ssb_length; uint16_t cell_id; uint16_t ssb_start_subcarrier; - short rsrp_dBm; long arfcn; rlm_t radiolink_monitoring; // -1 no monitoring, 0 out_of_sync, 1 in_sync - // SINR value times 10 as reporting granularity is 0.5 - float sinr_dB; } fapi_nr_ssb_pdu_t; typedef struct { @@ -145,7 +151,7 @@ typedef struct { fapi_nr_pdsch_pdu_t pdsch_pdu; fapi_nr_ssb_pdu_t ssb_pdu; fapi_nr_sib_pdu_t sib_pdu; - fapi_nr_csirs_measurements_t csirs_measurements; + fapi_nr_l1_measurements_t l1_measurements; }; } fapi_nr_rx_indication_body_t; @@ -470,9 +476,7 @@ typedef struct { uint16_t start_rb; uint16_t number_symbols; uint16_t start_symbol; - // TODO this is a workaround to make it work - // implementation is also a bunch of workarounds - uint16_t rb_offset; + uint8_t refPoint; uint16_t dlDmrsSymbPos; uint8_t dmrsConfigType; uint8_t prb_bundling_size_ind; @@ -557,16 +561,18 @@ typedef struct { } fapi_nr_ta_command_pdu; typedef struct { - // N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms) - double N_common_ta_adj; - // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) - double N_UE_TA_adj; - // drift rate of common ta in µs/s - double ntn_ta_commondrift; + int epoch_sfn; + int epoch_subframe; + // cell scheduling offset expressed in terms of 15kHz SCS long cell_specific_k_offset; + // ntn_total_time_advance_ms represents the complete round-trip-time between gNB and UE via SAT double ntn_total_time_advance_ms; + // drift rate of ntn_total_time_advance_ms in µs/s + double ntn_total_time_advance_drift; + // change rate of ntn_total_time_advance_ms drift in µs/s² + double ntn_total_time_advance_drift_variant; } fapi_nr_dl_ntn_config_command_pdu; typedef struct { diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h index f830e904e2..d146408abf 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h @@ -28,8 +28,11 @@ #define NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH 3 #define NFAPI_MAX_NUM_RF_BANDS 16 +#ifdef ENABLE_WLS +#define NFAPI_MAX_PACKED_MESSAGE_SIZE 1024*1024*2 +#else #define NFAPI_MAX_PACKED_MESSAGE_SIZE 32768 - +#endif // The following definition control the size of arrays used in the interface. // These may be changed if desired. They are used in the encoder to make sure // that the user has not specified a 'count' larger than the max array, and also @@ -115,7 +118,8 @@ typedef struct { #define NFAPI_P7_GET_MORE(_mss) ( ((_mss) & 0x8000) >> 15 ) #define NFAPI_P7_GET_SEGMENT(_mss) ( ((_mss) & 0x7F00) >> 8 ) #define NFAPI_P7_GET_SEQUENCE(_mss) ( (_mss) & 0x00FF ) -#define NFAPI_P7_SET_MSS(_more, _segm, _sequ) ( (((_more) & 0x1) << 7) | (((_segm) & 0x7) << 4) | ((_sequ) & 0xF) ) +#define NFAPI_NR_P7_SET_MSS(_more, _segm, _sequ) ( (((_more) & 0x1) << 15) | (((_segm) & 0x7F) << 8) | ((_sequ) & 0xFF) ) +#define NFAPI_P7_SET_MSS(_more, _segm, _sequ) ( (((_more) & 0x1) << 7) | (((_segm) & 0x7F) << 4) | ((_sequ) & 0xF) ) #define NFAPI_TAG_LENGTH_PACKED_LEN 4 diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h index b7e6577fa2..683de59c59 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h @@ -34,6 +34,7 @@ #define NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG 0xA002 #define NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG 0xA003 + typedef struct { uint16_t phy_id; uint16_t message_id; @@ -109,11 +110,11 @@ uint8_t pack_nr_p5_message_body(nfapi_nr_p4_p5_message_header_t *header, * \param pUnpackedBuf A pointer to the nfapi_message_header * \param unpackedBufLen The size of nfapi_message_header structure. * \param config A pointer to the nfapi configuration structure - * \return 10 ( size of the unpacked header ) on success, -1 on failure. + * \return true on success, false on failure. * * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p5 header structure pointed to by pUnpackedBuf */ -int nfapi_nr_p5_message_header_unpack(void *pMessageBuf, +bool nfapi_nr_p5_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, @@ -125,11 +126,11 @@ int nfapi_nr_p5_message_header_unpack(void *pMessageBuf, * \param pUnpackedBuf A pointer to the nfapi_message_header * \param unpackedBufLen The size of nfapi_message_header structure. * \param config A pointer to the nfapi configuration structure - * \return != -1 means success, -1 means failure. + * \return true on success, false on failure. * * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p5 message structure pointer to by pUnpackedBuf */ -int nfapi_nr_p5_message_unpack(void *pMessageBuf, +bool nfapi_nr_p5_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, @@ -153,13 +154,13 @@ int nfapi_nr_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packe * \param pUnpackedBuf A pointer to the nfapi_message_header * \param unpackedBufLen The size of nfapi_message_header structure. * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. + * \return true on success, false on failure. * * The function will decode a byte stream pointed to by pMessageBuf into a nfapi_p7_message_header structure pointer to by pUnpackedBuf */ -int nfapi_nr_p7_message_header_unpack(void *pMessageBuf, +bool nfapi_nr_p7_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, @@ -171,11 +172,11 @@ int nfapi_nr_p7_message_header_unpack(void *pMessageBuf, * \param pUnpackedBuf A pointer to the nfapi_message_header * \param unpackedBufLen The size of nfapi_message_header structure. * \param config A pointer to the nfapi configuration structure - * \return 0 means success, -1 means failure. + * \return true on success, false failure. * * The function will decode a byte stream pointed to by pMessageBuf into a nfapi p7 message structure pointer to by pUnpackedBuf */ -int nfapi_nr_p7_message_unpack(void *pMessageBuf, +bool nfapi_nr_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 0533a76c6d..754ef60e55 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -10,6 +10,7 @@ #define _NFAPI_NR_INTERFACE_SCF_H_ #include "stddef.h" +#include "common/platform_types.h" #include "nfapi_interface.h" #include "nfapi_nr_interface.h" @@ -328,6 +329,8 @@ typedef struct #define NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG 0x1028 #define NFAPI_NR_CONFIG_TDD_TABLE 0x1035 +#define NFAPI_NR_CONFIG_BEAMFORMING_TABLE_TAG 0x1043 // This tag was added in version 5 of the SCF222 standard ( Table 3-50 of SCF222.10.05 ) +#define NFAPI_NR_CONFIG_PRECODING_TABLE_V6_TAG 0x104B // This tag was added in version 6 of the SCF222 standard ( Table 3-52 of SCF222.10.06 ) //table 3-21 typedef struct @@ -445,6 +448,13 @@ typedef struct } nfapi_nr_tdd_table_t; +typedef struct { + nfapi_tl_t tl; + nfapi_nr_tdd_table_t *value; + uint8_t slots_per_frame; + uint8_t symbols_per_slot; +} nfapi_nr_tdd_table_tlv_t; + //table 3-27 typedef struct { @@ -473,12 +483,13 @@ typedef struct { nfapi_nr_dig_beam_t *dig_beam_list; } nfapi_nr_dbt_pdu_t; -// Table 3–62 Precoding matrix (PM) PDU (v.222.10.04) typedef struct { - int16_t precoder_weight_Re; - int16_t precoder_weight_Im; -} nfapi_nr_pm_weights_t; + nfapi_tl_t tl; + nfapi_nr_dbt_pdu_t value; +} nfapi_nr_dbt_tlv_ve_t; +// Table 3–62 Precoding matrix (PM) PDU (v.222.10.04) +typedef c16_t nfapi_nr_pm_weights_t; typedef struct { uint16_t pm_idx; @@ -491,7 +502,12 @@ typedef struct { typedef struct { uint16_t num_pm_idx; nfapi_nr_pm_pdu_t *pmi_pdu; -} nfapi_nr_pm_list_t; +} nfapi_nr_pm_list_t; // This corresponds to Table 3-69 of SCF222.10.06, which introduces the num_pm_idx parameter + +typedef struct { + nfapi_tl_t tl; + nfapi_nr_pm_list_t value; +} nfapi_nr_pm_tlv_ve_t; typedef struct { nfapi_uint8_tlv_t num_beams_period_vendor_ext; @@ -688,17 +704,46 @@ typedef enum { NFAPI_NR_STOP_MSG_INVALID_STATE } nfapi_nr_stop_errors_e; -//3.3.5 PHY Notifications +// 3.3.5 PHY Notifications + +#define SCF_ERROR_LIST \ + X(NFAPI_NR_PHY_API_MSG_OK, 0x0) \ + X(NFAPI_NR_PHY_API_MSG_INVALID_STATE, 0x1) \ + X(NFAPI_NR_PHY_API_MSG_INVALID_CONFIG, 0x2) \ + X(NFAPI_NR_PHY_API_SFN_OUT_OF_SYNC, 0X3) \ + X(NFAPI_NR_PHY_API_MSG_SLOR_ERR, 0X4) \ + X(NFAPI_NR_PHY_API_MSG_BCH_MISSING, 0X5) \ + X(NFAPI_NR_PHY_API_MSG_INVALID_SFN, 0X6) \ + X(NFAPI_NR_PHY_API_MSG_UL_DCI_ERR, 0X7) \ + X(NFAPI_NR_PHY_API_MSG_TX_ERR, 0X8) + +#ifdef ENABLE_AERIAL +#define AERIAL_ERROR_LIST \ + X(AERIAL_ERROR_CODE_FAPI_END, 0x32) \ + X(AERIAL_ERROR_CODE_L1_PROC_OBJ_UNAVAILABLE_ERR, 0x33) \ + X(AERIAL_ERROR_CODE_MSG_LATE_SLOT_ERR, 0x34) \ + X(AERIAL_ERROR_CODE_PARTIAL_SRS_IND_ERR, 0x35) \ + X(AERIAL_ERROR_CODE_L1_DL_CPLANE_TX_ERROR, 0x36) \ + X(AERIAL_ERROR_CODE_L1_UL_CPLANE_TX_ERROR, 0x37) \ + X(AERIAL_ERROR_CODE_L1_DL_GPU_ERROR, 0x38) \ + X(AERIAL_ERROR_CODE_L1_DL_CPU_TASK_ERROR, 0x39) \ + X(AERIAL_ERROR_CODE_L1_UL_CPU_TASK_ERROR, 0x3A) \ + X(AERIAL_ERROR_CODE_L1_P1_EXIT_ERROR, 0x3B) \ + X(AERIAL_ERROR_CODE_L1_P2_EXIT_ERROR, 0x3C) \ + X(AERIAL_ERROR_CODE_L1_DL_CH_ERROR, 0x3D) \ + X(AERIAL_ERROR_CODE_L1_UL_CH_ERROR, 0x3E) +#else +#define AERIAL_ERROR_LIST +#endif + +#define NFAPI_PHY_ERROR_LIST \ + SCF_ERROR_LIST \ + AERIAL_ERROR_LIST + typedef enum { - NFAPI_NR_PHY_API_MSG_OK =0x0, - NFAPI_NR_PHY_API_MSG_INVALID_STATE =0x1, - NFAPI_NR_PHY_API_MSG_INVALID_CONFIG =0x2, - NFAPI_NR_PHY_API_SFN_OUT_OF_SYNC =0X3, - NFAPI_NR_PHY_API_MSG_SLOR_ERR =0X4, - NFAPI_NR_PHY_API_MSG_BCH_MISSING =0X5, - NFAPI_NR_PHY_API_MSG_INVALID_SFN =0X6, - NFAPI_NR_PHY_API_MSG_UL_DCI_ERR =0X7, - NFAPI_NR_PHY_API_MSG_TX_ERR =0X8 +#define X(name, value) name = value, + NFAPI_PHY_ERROR_LIST +#undef X } nfapi_nr_phy_notifications_errors_e; typedef struct { @@ -725,31 +770,31 @@ typedef struct { // 3.4.2 -//for pdcch_pdu: +typedef struct { + // Index of the digital beam weight vector pre-stored at cell configuration. + // The vector maps this input port to output TXRUs. Value: 0->65535 + uint16_t beam_idx; +} nfapi_nr_dig_bf_interface_t; -typedef struct -{ - uint16_t beam_idx;//Index of the digital beam weight vector pre-stored at cell configuration. The vector maps this input port to output TXRUs. Value: 0->65535 - -}nfapi_nr_dig_bf_interface_t; - -typedef struct -{ - uint16_t pm_idx;//Index to precoding matrix (PM) pre-stored at cell configuration. Note: If precoding is not used this parameter should be set to 0. Value: 0->65535. - nfapi_nr_dig_bf_interface_t dig_bf_interface_list[NFAPI_MAX_NUM_BG_IF];//max dig_bf_interfaces - -}nfapi_nr_tx_precoding_and_beamforming_number_of_prgs_t; +typedef struct { + // Index to precoding matrix (PM) pre-stored at cell configuration. + // Note: If precoding is not used this parameter should be set to 0. Value: 0->65535. + uint16_t pm_idx; + nfapi_nr_dig_bf_interface_t dig_bf_interface_list[NFAPI_MAX_NUM_BG_IF]; // max dig_bf_interfaces +} nfapi_nr_tx_precoding_and_beamforming_number_of_prgs_t; //table 3-43 -typedef struct -{ - uint16_t num_prgs;//Number of PRGs spanning this allocation. Value : 1->275 - uint16_t prg_size;//Size in RBs of a precoding resource block group (PRG) – to which same precoding and digital beamforming gets applied. Value: 1->275 - //watchout: dig_bf_interfaces here, in table 3-53 it's dig_bf_interface - uint8_t dig_bf_interfaces;//Number of STD ant ports (parallel streams) feeding into the digBF Value: 0->255 - nfapi_nr_tx_precoding_and_beamforming_number_of_prgs_t prgs_list[NFAPI_MAX_NUM_PRGS];//max prg_size - -}nfapi_nr_tx_precoding_and_beamforming_t; +typedef struct { + // Number of PRGs spanning this allocation. Value : 1->275 + uint16_t num_prgs; + // Size in RBs of a precoding resource block group (PRG) to which same precoding and digital beamforming gets applied. + // Value: 1->275 + uint16_t prg_size; + // watchout: dig_bf_interfaces here, in table 3-53 it's dig_bf_interface + uint8_t dig_bf_interfaces; + // Number of STD ant ports (parallel streams) feeding into the digBF Value: 0->255 + nfapi_nr_tx_precoding_and_beamforming_number_of_prgs_t prgs_list[NFAPI_MAX_NUM_PRGS]; // max prg_size +} nfapi_nr_tx_precoding_and_beamforming_t; //table 3-37 diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c index 1aeef4b766..4516302e48 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c @@ -2325,7 +2325,7 @@ int nfapi_p5_message_header_unpack(void *pMessageBuf, return 8; } -int nfapi_nr_p5_message_header_unpack(void *pMessageBuf, +bool nfapi_nr_p5_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, @@ -2336,25 +2336,25 @@ int nfapi_nr_p5_message_header_unpack(void *pMessageBuf, if (pMessageBuf == NULL || pUnpackedBuf == NULL) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 header unpack supplied pointers are null\n"); - return -1; + return false; } uint8_t *end = pMessageBuf + messageBufLen; if (messageBufLen < NFAPI_NR_P5_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_nr_p4_p5_message_header_t)) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 header unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); - return -1; + return false; } // process the header if (!(pull16(&pReadPackedMessage, &pMessageHeader->phy_id, end) && pull16(&pReadPackedMessage, &pMessageHeader->message_id, end) && pull32(&pReadPackedMessage, &pMessageHeader->message_length, end) && pull16(&pReadPackedMessage, &pMessageHeader->spare, end))) { - return -1; + return false; } - return NFAPI_NR_P5_HEADER_LENGTH; + return true; } -int nfapi_nr_p5_message_unpack(void *pMessageBuf, +bool nfapi_nr_p5_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, @@ -2362,11 +2362,11 @@ int nfapi_nr_p5_message_unpack(void *pMessageBuf, { if (pMessageBuf == NULL || pUnpackedBuf == NULL) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 unpack supplied pointers are null\n"); - return -1; + return false; } if (messageBufLen < NFAPI_NR_P5_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_nr_p4_p5_message_header_t)) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); - return -1; + return false; } nfapi_nr_p4_p5_message_header_t *pMessageHeader = pUnpackedBuf; @@ -2374,7 +2374,7 @@ int nfapi_nr_p5_message_unpack(void *pMessageBuf, (void)memset(pUnpackedBuf, 0, unpackedBufLen); // process the header if (!nfapi_nr_p5_message_header_unpack(pMessageBuf, messageBufLen, pMessageHeader, unpackedBufLen, config)) { - return -1; + return false; } uint8_t *pReadPackedMessage = pMessageBuf + NFAPI_NR_P5_HEADER_LENGTH; uint8_t *end = (uint8_t *)pMessageBuf + messageBufLen; @@ -2382,7 +2382,7 @@ int nfapi_nr_p5_message_unpack(void *pMessageBuf, if (check_nr_unpack_length(pMessageHeader->message_id, unpackedBufLen) == 0) { // the unpack buffer is not big enough for the struct - return -1; + return false; } // look for the specific message @@ -2476,7 +2476,7 @@ int nfapi_nr_p5_message_unpack(void *pMessageBuf, break; } - return result; + return result == 1; } int nfapi_p5_message_unpack(void *pMessageBuf, diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c index b6e15e294b..e75e418500 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -5930,7 +5930,7 @@ int nfapi_p7_message_header_unpack(void *pMessageBuf, return 0; } -int nfapi_nr_p7_message_header_unpack(void *pMessageBuf, +bool nfapi_nr_p7_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, @@ -5941,14 +5941,14 @@ int nfapi_nr_p7_message_header_unpack(void *pMessageBuf, if (pMessageBuf == NULL || pUnpackedBuf == NULL) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 header unpack supplied pointers are null\n"); - return -1; + return false; } uint8_t *end = (uint8_t *)pMessageBuf + messageBufLen; if (messageBufLen < NFAPI_NR_P7_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_nr_p7_message_header_t)) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 header unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); - return -1; + return false; } // process the header if (!(pull16(&pReadPackedMessage, &pMessageHeader->phy_id, end) && pull16(&pReadPackedMessage, &pMessageHeader->message_id, end) @@ -5956,9 +5956,9 @@ int nfapi_nr_p7_message_header_unpack(void *pMessageBuf, && pull16(&pReadPackedMessage, &pMessageHeader->m_segment_sequence, end) && pull32(&pReadPackedMessage, &pMessageHeader->checksum, end) && pull32(&pReadPackedMessage, &pMessageHeader->transmit_timestamp, end))) - return -1; + return false; - return 0; + return true; } int nfapi_p7_message_unpack(void *pMessageBuf, @@ -6203,7 +6203,14 @@ int nfapi_p7_message_unpack(void *pMessageBuf, bool peek_nr_nfapi_p7_sfn_slot(void *pMessageBuf, uint32_t messageBufLen, uint16_t *SFN, uint16_t *Slot) { +#ifdef ENABLE_SOCKET + // Socket transport will always use nFAPI encoding uint8_t *pReadPackedMessage = &((uint8_t *)pMessageBuf)[NFAPI_NR_P7_HEADER_LENGTH]; +#endif +#ifdef ENABLE_WLS + // WLS transport will always use FAPI encoding + uint8_t *pReadPackedMessage = &((uint8_t *)pMessageBuf)[NFAPI_HEADER_LENGTH]; +#endif uint8_t *end = (uint8_t*)pMessageBuf + messageBufLen; if(!(pull16(&pReadPackedMessage, SFN, end) && pull16(&pReadPackedMessage, Slot, end))) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to peek SFN.Slot\n"); @@ -6213,7 +6220,7 @@ bool peek_nr_nfapi_p7_sfn_slot(void *pMessageBuf, uint32_t messageBufLen, uint16 return true; } -int nfapi_nr_p7_message_unpack(void *pMessageBuf, +bool nfapi_nr_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, @@ -6225,14 +6232,14 @@ int nfapi_nr_p7_message_unpack(void *pMessageBuf, if (pMessageBuf == NULL || pUnpackedBuf == NULL) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack supplied pointers are null\n"); - return -1; + return false; } uint8_t *end = (uint8_t *)pMessageBuf + messageBufLen; if (messageBufLen < NFAPI_NR_P7_HEADER_LENGTH || unpackedBufLen < sizeof(nfapi_nr_p7_message_header_t)) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack supplied message buffer is too small %d, %d\n", messageBufLen, unpackedBufLen); - return -1; + return false; } // process the header @@ -6242,11 +6249,11 @@ int nfapi_nr_p7_message_unpack(void *pMessageBuf, && pull32(&pReadPackedMessage, &pMessageHeader->checksum, end) && pull32(&pReadPackedMessage, &pMessageHeader->transmit_timestamp, end))) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack header failed\n"); - return -1; + return false; } if ((uint8_t *)(pMessageBuf + pMessageHeader->message_length) > end) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 unpack message length is greater than the message buffer \n"); - return -1; + return false; } /* @@ -6356,7 +6363,7 @@ int nfapi_nr_p7_message_unpack(void *pMessageBuf, if (result == 0) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack failed to pack message\n"); - return -1; + return false; } - return 0; + return true; } diff --git a/nfapi/open-nFAPI/pnf/inc/pnf.h b/nfapi/open-nFAPI/pnf/inc/pnf.h index 7275db76e1..2dc2ce9de6 100644 --- a/nfapi/open-nFAPI/pnf/inc/pnf.h +++ b/nfapi/open-nFAPI/pnf/inc/pnf.h @@ -20,9 +20,8 @@ #include "nfapi_pnf_interface.h" -#define NFAPI_MAX_PACKED_MESSAGE_SIZE 32768 -typedef struct { +struct pnf_t { nfapi_pnf_config_t _public; @@ -33,19 +32,28 @@ typedef struct { uint8_t terminate; -} pnf_t; +}; int pnf_connect(pnf_t *pnf); int pnf_message_pump(pnf_t *pnf); -int pnf_nr_message_pump(pnf_t *pnf); -int pnf_nr_pack_and_send_p5_message(pnf_t* pnf, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len); +void pnf_nr_handle_p5_message(pnf_t* pnf, void* pRecvMsg, int recvMsgLen); int pnf_pack_and_send_p5_message(pnf_t* pnf, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len); int pnf_pack_and_send_p4_message(pnf_t* pnf, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len); int pnf_send_message(pnf_t* pnf, uint8_t* msg, uint32_t msg_len, uint16_t stream_id); nfapi_pnf_phy_config_t* nfapi_pnf_phy_config_find(nfapi_pnf_config_t* config, uint16_t phy_id); +void pnf_nr_handle_pnf_param_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen); +void pnf_nr_handle_pnf_config_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen); +void pnf_nr_handle_pnf_start_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen); +void pnf_handle_pnf_stop_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen); +void pnf_nr_handle_param_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen); +void pnf_nr_handle_config_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen); +void pnf_nr_handle_start_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen); +void pnf_nr_handle_stop_request(pnf_t* pnf, void* pRecvMsg, int recvMsgLen); + + #endif // _PNF_H_ diff --git a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h index 0325c8c242..5805e07445 100644 --- a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h +++ b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h @@ -25,7 +25,6 @@ #include "nfapi_pnf_interface.h" -#define NFAPI_MAX_PACKED_MESSAGE_SIZE 32768 typedef struct { uint16_t dl_conf_ontime; @@ -82,7 +81,7 @@ typedef struct { } pnf_p7_rx_reassembly_queue_t; -typedef struct { +struct pnf_p7_t { nfapi_pnf_p7_config_t _public; @@ -139,12 +138,11 @@ typedef struct { pnf_p7_stats_t stats; pnf_p7_nr_stats_t nr_stats; -} pnf_p7_t; +}; int pnf_p7_message_pump(pnf_p7_t* pnf_p7); int pnf_nr_p7_message_pump(pnf_p7_t* pnf_p7); int pnf_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_p7_message_header_t* msg, uint32_t msg_len); -int pnf_nr_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_nr_p7_message_header_t* header, uint32_t msg_len); int pnf_p7_send_message(pnf_p7_t* pnf_p7, uint8_t* msg, uint32_t msg_len); @@ -159,8 +157,11 @@ int nfapi_pnf_p7_nr_rach_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_rach_indica pnf_p7_rx_message_t* pnf_p7_rx_reassembly_queue_add_segment(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, uint32_t rx_hr_time, uint16_t sequence_number, uint16_t segment_number, uint8_t m, uint8_t* data, uint16_t data_len); void pnf_p7_rx_reassembly_queue_remove_msg(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, pnf_p7_rx_message_t* msg); void pnf_p7_rx_reassembly_queue_remove_old_msgs(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, uint32_t rx_hr_time, uint32_t delta); - -int pnf_nr_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_nr_p7_message_header_t* header, uint32_t msg_len); - +void pnf_nr_handle_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t *pnf_p7, uint32_t rx_hr_time); +struct timespec pnf_timespec_sub(struct timespec lhs, struct timespec rhs); +uint32_t pnf_get_current_time_hr(void); +struct timespec pnf_timespec_add(struct timespec lhs, struct timespec rhs); +void pnf_p7_free(pnf_p7_t* pnf_p7, void* ptr); +void* pnf_p7_malloc(pnf_p7_t* pnf_p7, size_t size); #endif /* _PNF_P7_H_ */ diff --git a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h index 7403bd7169..957e032f69 100644 --- a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h +++ b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h @@ -31,8 +31,8 @@ extern "C" { #include #include "openair1/PHY/defs_gNB.h" - - +typedef struct pnf_t pnf_t; +typedef struct pnf_p7_t pnf_p7_t; /*! This enum is used to describe the states of the pnf */ @@ -319,8 +319,60 @@ typedef struct nfapi_pnf_config */ void (*deallocate_p4_p5_vendor_ext)(void* header); + /*! \brief Encodes an (n)FAPI P5 message to a buffer + * + * This function is called internally in send_p5_msg() + * \param pMessageBuf A pointer to a nfapi p5 message structure + * \param messageBufLen The size of the p5 message structure + * \param pPackedBuf A pointer to the buffer that the p5 message will be packed into + * \param packedBufLen The size of the buffer + * \param config A pointer to the nfapi configuration structure + * \return != 0 means success, -1 means failure. + */ + int (*pack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pPackedBuf, + uint32_t packedBufLen, + nfapi_p4_p5_codec_config_t* config); + /*! \brief Decodes a (n)FAPI P5 message + * \param pMessageBuf A pointer to an encoded P5 message + * \param messageBufLen The size of the encoded P5 message + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure. + */ + bool (*unpack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p4_p5_codec_config_t* config); + /*! \brief Decodes an (n)FAPI P5 message header + * \param pMessageBuf A pointer to an encoded P5 message header + * \param messageBufLen The size of the encoded P5 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure. + */ + bool (*hdr_unpack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p4_p5_codec_config_t* config); + + /*! \brief Sends a (N)FAPI P5 message + * + * This function internally packs the given message into a buffer by calling the previously defined pack_func() function pointer + * Then, having the message buffer populated, sends it to the VNF + * \param pnf A pointer to a pnf_t* + * \param msg A pointer to the P5 message + * \param msg_len The size of the encoded P5 message + * \return true on success, false on failure. + */ + bool (*send_p5_msg)(pnf_t* pnf, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len); } nfapi_pnf_config_t; /*! Create a pnf configuration @@ -367,7 +419,6 @@ int nfapi_pnf_config_destroy(nfapi_pnf_config_t* config); * \endcode */ int nfapi_pnf_start(nfapi_pnf_config_t* config); -int nfapi_nr_pnf_start(nfapi_pnf_config_t* config); /*! Stop the PNF library. * \param config A pointer to the pnf configuration @@ -726,8 +777,55 @@ typedef struct nfapi_pnf_p7_config */ void (*deallocate_p7_vendor_ext)(void* header); + /*! A callback to pack a P7 message + * + * This function is called internally in send_p7_msg() + * \param pMessageBuf A pointer to a nfapi p7 message structure + * \param pPackedBuf A pointer to the buffer that the p7 message will be packed into + * \param packedBufLen The size of the buffer + * \param config A pointer to the nfapi configuration structure + * \return != -1 means success, -1 means failure. + */ + int (*pack_func)(void* pMessageBuf, void* pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t* config); + /*! A callback to unpack a P7 message + * \param pMessageBuf A pointer to an encoded P7 message header + * \param messageBufLen The size of the encoded P7 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true success, false on failure. + */ + bool (*unpack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p7_codec_config_t* config); + /*! \brief Decodes a NFAPI P7 message header + * \param pMessageBuf A pointer to an encoded P5 message header + * \param messageBufLen The size of the encoded P5 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure. + */ + bool (*hdr_unpack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p7_codec_config_t* config); + + /*! \brief Sends a (N)FAPI P7 message + * + * This function internally packs the given message into a buffer by calling the previously defined pack_func() function pointer + * Then, having the message buffer populated, sends it to the VNF + * \param pnf_p7 A pointer to a pnf_p7_t struct + * \param header A pointer to the P7 message to pack & send + * \param msg_len The P7 message length + * \return true on success, false on failure. + */ + bool (*send_p7_msg)(pnf_p7_t* pnf_p7, nfapi_nr_p7_message_header_t* header, uint32_t msg_len); } nfapi_pnf_p7_config_t; /*! Create and initialise a nfapi_pnf_p7_config structure @@ -748,7 +846,7 @@ int nfapi_pnf_p7_config_destroy(nfapi_pnf_p7_config_t* config); * This function will not return until nfapi_pnf_p7_stop is called. */ int nfapi_pnf_p7_start(nfapi_pnf_p7_config_t* config); -int nfapi_nr_pnf_p7_start(nfapi_pnf_p7_config_t* config); + /*! Stop the PNF P7 library. * \param config A pointer to a PNF P7 config diff --git a/nfapi/open-nFAPI/pnf/src/pnf.c b/nfapi/open-nFAPI/pnf/src/pnf.c index 4cef8e6412..f9009e4a77 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf.c +++ b/nfapi/open-nFAPI/pnf/src/pnf.c @@ -30,6 +30,10 @@ #include "nfapi_nr_interface_scf.h" #include "pnf.h" +#include + +#include "nfapi/open-nFAPI/fapi/inc/nr_fapi.h" + # if 1 // for hard-code (remove later) #include "common/platform_types.h" #include "common/platform_constants.h" @@ -45,7 +49,9 @@ #include "NR_MIB.h" #include "openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h" - +#ifdef ENABLE_WLS +#include "wls_integration/include/wls_pnf.h" +#endif #endif #define MAX_SCTP_STREAMS 16 @@ -95,8 +101,9 @@ void pnf_nr_handle_pnf_param_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF_PARAM.request received\n"); - // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(nfapi_nr_pnf_param_request_t), &pnf->_public.codec_config) >= 0) + /// The unpack() function pointer is not called here due to the only possibility of entering being on a nFAPI message + const bool result = nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(nfapi_nr_pnf_param_request_t), &pnf->_public.codec_config); + if (result) { if(pnf->_public.state == NFAPI_PNF_IDLE) { @@ -195,20 +202,16 @@ void pnf_handle_pnf_config_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) nfapi_pnf_phy_config_delete_all(&pnf->_public); // create the phy records - if (req.pnf_phy_rf_config.tl.tag == NFAPI_PNF_PHY_RF_TAG) - { - int i = 0; - for(i = 0; i < req.pnf_phy_rf_config.number_phy_rf_config_info; ++i) - { - nfapi_pnf_phy_config_t* phy = (nfapi_pnf_phy_config_t*)malloc(sizeof(nfapi_pnf_phy_config_t)); - memset(phy, 0, sizeof(nfapi_pnf_phy_config_t)); + if (req.pnf_phy_rf_config.tl.tag == NFAPI_PNF_PHY_RF_TAG) { + for(int i = 0; i < req.pnf_phy_rf_config.number_phy_rf_config_info; ++i) { + nfapi_pnf_phy_config_t* phy = calloc_or_fail(1,sizeof(nfapi_pnf_phy_config_t)); - phy->state = NFAPI_PNF_PHY_IDLE; - phy->phy_id = req.pnf_phy_rf_config.phy_rf_config[i].phy_id; + phy->state = NFAPI_PNF_PHY_IDLE; + phy->phy_id = req.pnf_phy_rf_config.phy_rf_config[i].phy_id; - nfapi_pnf_phy_config_add(&(pnf->_public), phy); - } - } + nfapi_pnf_phy_config_add(&(pnf->_public), phy); + } + } if(pnf->_public.pnf_config_req) { @@ -251,8 +254,9 @@ void pnf_nr_handle_pnf_config_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF_CONFIG.request received\n"); - // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &pnf->_public.codec_config) >= 0) + /// The unpack() function pointer is not called here due to the only possibility of entering being on a nFAPI message + const bool result = nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &pnf->_public.codec_config); + if (result) { // ensure correct state if(pnf->_public.state != NFAPI_PNF_RUNNING) @@ -261,19 +265,13 @@ void pnf_nr_handle_pnf_config_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen nfapi_pnf_phy_config_delete_all(&pnf->_public); // create the phy records - if (req.pnf_phy_rf_config.tl.tag == NFAPI_PNF_PHY_RF_TAG) - { - int i = 0; - for(i = 0; i < req.pnf_phy_rf_config.number_phy_rf_config_info; ++i) - { - nfapi_pnf_phy_config_t* phy = (nfapi_pnf_phy_config_t*)malloc(sizeof(nfapi_pnf_phy_config_t)); - memset(phy, 0, sizeof(nfapi_pnf_phy_config_t)); - - phy->state = NFAPI_PNF_PHY_IDLE; - phy->phy_id = req.pnf_phy_rf_config.phy_rf_config[i].phy_id; - - nfapi_pnf_phy_config_add(&(pnf->_public), phy); - } + if (req.pnf_phy_rf_config.tl.tag == NFAPI_PNF_PHY_RF_TAG) { + for(int i = 0; i < req.pnf_phy_rf_config.number_phy_rf_config_info; ++i) { + nfapi_pnf_phy_config_t* phy = calloc_or_fail(1,sizeof(nfapi_pnf_phy_config_t)); + phy->state = NFAPI_PNF_PHY_IDLE; + phy->phy_id = req.pnf_phy_rf_config.phy_rf_config[i].phy_id; + nfapi_pnf_phy_config_add(&(pnf->_public), phy); + } } if(pnf->_public.pnf_nr_config_req) @@ -357,8 +355,9 @@ void pnf_nr_handle_pnf_start_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF_START.request Received\n"); - // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &pnf->_public.codec_config) >= 0) + /// The unpack() function pointer is not called here due to the only possibility of entering being on a nFAPI message + const bool result = nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &pnf->_public.codec_config); + if (result) { if(pnf->_public.state == NFAPI_PNF_CONFIGURED) { @@ -517,7 +516,8 @@ void pnf_nr_handle_param_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) NFAPI_TRACE(NFAPI_TRACE_INFO, "PARAM.request received\n"); // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + const bool result = pnf->_public.unpack_func(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config); + if (result) { if(config->state == NFAPI_PNF_RUNNING) { @@ -662,7 +662,8 @@ void pnf_nr_handle_config_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) nfapi_pnf_config_t* config = &(pnf->_public); // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + const bool result = pnf->_public.unpack_func(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config); + if (result) { if(config->state == NFAPI_PNF_RUNNING) { @@ -806,7 +807,8 @@ void pnf_nr_handle_start_request(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() START.request received state:%d\n", __FUNCTION__, config->state); // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) + const bool result = pnf->_public.unpack_func(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config); + if (result) { if(config->state == NFAPI_PNF_RUNNING) { @@ -945,7 +947,8 @@ void pnf_nr_handle_stop_request(pnf_t* pnf, void* pRecvMsg, int recvMsgLen) nfapi_pnf_config_t* config = &(pnf->_public); // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config) >= 0) { + const bool result = pnf->_public.unpack_func(pRecvMsg, recvMsgLen, &req, sizeof(req), &config->codec_config); + if (result) { if (config->state == NFAPI_PNF_RUNNING) { nfapi_pnf_phy_config_t* phy = nfapi_pnf_phy_config_find(config, req.header.phy_id); if (phy) { @@ -1525,12 +1528,8 @@ void pnf_nr_handle_p5_message(pnf_t* pnf, void* pRecvMsg, int recvMsgLen) } // unpack the message header - if (nfapi_nr_p5_message_header_unpack(pRecvMsg, - recvMsgLen, - &messageHeader, - sizeof(nfapi_nr_p4_p5_message_header_t), - &pnf->_public.codec_config) - < 0) { + const bool result = pnf->_public.hdr_unpack_func(pRecvMsg, recvMsgLen, &messageHeader, sizeof(messageHeader), &pnf->_public.codec_config); + if (!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); return; } @@ -1702,20 +1701,6 @@ void pnf_handle_p5_message(pnf_t* pnf, void *pRecvMsg, int recvMsgLen) } } -int pnf_nr_pack_and_send_p5_message(pnf_t* pnf, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len) -{ - int packed_len = - nfapi_nr_p5_message_pack(msg, msg_len, pnf->tx_message_buffer, sizeof(pnf->tx_message_buffer), &pnf->_public.codec_config); - - if (packed_len < 0) { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_nr_p5_message_pack failed (%d)\n", packed_len); - return -1; - } - - return pnf_send_message(pnf, pnf->tx_message_buffer, packed_len, 0 /*msg->stream_id*/); -} - - int pnf_pack_and_send_p5_message(pnf_t* pnf, nfapi_p4_p5_message_header_t* msg, uint32_t msg_len) { int packed_len = nfapi_p5_message_pack(msg, msg_len, @@ -1748,8 +1733,6 @@ int pnf_pack_and_send_p4_message(pnf_t* pnf, nfapi_p4_p5_message_header_t* msg, return pnf_send_message(pnf, pnf->tx_message_buffer, packed_len, 0/*msg->stream_id*/); } - - int pnf_connect(pnf_t* pnf) { struct sockaddr_in servaddr; @@ -1932,7 +1915,20 @@ int pnf_connect(pnf_t* pnf) socketConnected = 1; } - } + } else { + int error; + socklen_t len = sizeof(error); + + if (getsockopt(pnf->p5_sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno); + return -1; + } else { + // If error is zero, the socket is connected + if (error == 0) { + socketConnected = 1; + } + } + } NFAPI_TRACE(NFAPI_TRACE_NOTE, "Socket %s\n", socketConnected ? "CONNECTED" : "NOT_CONNECTED"); return socketConnected; @@ -1941,30 +1937,30 @@ int pnf_connect(pnf_t* pnf) int pnf_send_message(pnf_t* pnf, uint8_t *msg, uint32_t len, uint16_t stream) { - if (pnf->sctp) - { + if (pnf->sctp) + { #if 0 - printf("\nPNF SENDS: \n"); - for(int i=0; ip5_sock, msg, len, NULL, 0, 42/*config->sctp_stream_number*/, 0, stream/*P5_STREAM_ID*/, 0, 0) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "sctp_sendmsg failed errno: %d\n", errno); - return -1; - } - } - else - { - if (write(pnf->p5_sock, msg, len) != len) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "read failed errno: %d\n", errno); - return -1; - } - } + if (sctp_sendmsg(pnf->p5_sock, msg, len, NULL, 0, 42/*config->sctp_stream_number*/, 0, stream/*P5_STREAM_ID*/, 0, 0) < 0) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "sctp_sendmsg failed errno: %d\n", errno); + return -1; + } + } + else + { + if (write(pnf->p5_sock, msg, len) != len) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "read failed errno: %d\n", errno); + return -1; + } + } return 0; } @@ -2018,21 +2014,19 @@ int pnf_read_dispatch_message(pnf_t* pnf) // now have the size of the mesage } - if(message_size > stack_buffer_size) - { - dynamic_buffer = (uint8_t*)malloc(message_size); + if(message_size > stack_buffer_size) { + dynamic_buffer = malloc_or_fail(message_size); - if(dynamic_buffer == NULL) - { - // todo : add error mesage - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to allocate dynamic buffer for sctp_recvmsg size:%d\n", message_size); - return -1; - } + if (dynamic_buffer == NULL) { + // todo : add error mesage + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to allocate dynamic buffer for sctp_recvmsg size:%d\n", message_size); + return -1; + } - read_buffer = dynamic_buffer; - } + read_buffer = dynamic_buffer; + } - { + { int flags = 0; (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); @@ -2101,126 +2095,6 @@ int pnf_read_dispatch_message(pnf_t* pnf) } -int pnf_nr_read_dispatch_message(pnf_t* pnf) -{ - int socket_connected = 1; - - // 1. Peek the message header - // 2. If the message is larger than the stack buffer then create a dynamic buffer - // 3. Read the buffer - // 4. Handle the p5 message - - uint32_t header_buffer_size = NFAPI_NR_P5_HEADER_LENGTH; - uint8_t header_buffer[header_buffer_size]; - - uint32_t stack_buffer_size = 32; // should it be the size of then sctp_notificatoin structure - uint8_t stack_buffer[stack_buffer_size]; - - uint8_t* dynamic_buffer = 0; - - uint8_t* read_buffer = &stack_buffer[0]; - uint32_t message_size = 0; - - struct sockaddr_in addr; - socklen_t addr_len = sizeof(addr); - - struct sctp_sndrcvinfo sndrcvinfo; - (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); - - { - int flags = MSG_PEEK; - message_size = sctp_recvmsg(pnf->p5_sock, - header_buffer, - header_buffer_size, - /*(struct sockaddr*)&addr, &addr_len*/ 0, - 0, - &sndrcvinfo, - &flags); - - if (message_size == -1) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to peek sctp message size errno:%d\n", errno); - return 0; - } - - nfapi_nr_p4_p5_message_header_t header; - int unpack_result = nfapi_nr_p5_message_header_unpack(header_buffer, header_buffer_size, &header, sizeof(header), 0); - if (unpack_result < 0) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to unpack p5 message header\n"); - return 0; - } - message_size = header.message_length + header_buffer_size; - - // now have the size of the mesage - } - - if (message_size > stack_buffer_size) { - dynamic_buffer = (uint8_t*)malloc(message_size); - - if (dynamic_buffer == NULL) { - // todo : add error mesage - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to allocate dynamic buffer for sctp_recvmsg size:%d\n", message_size); - return -1; - } - - read_buffer = dynamic_buffer; - } - - { - int flags = 0; - (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); - - int recvmsg_result = - sctp_recvmsg(pnf->p5_sock, read_buffer, message_size, (struct sockaddr*)&addr, &addr_len, &sndrcvinfo, &flags); - if (recvmsg_result == -1) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "Failed to read sctp message size errno:%d\n", errno); - } else { -#if 0 - // print the received message - printf("\n MESSAGE RECEIVED: \n"); - for(int i=0; ip5_sock, - inet_ntoa(addr.sin_addr), - ntohs(addr.sin_port), - sndrcvinfo.sinfo_assoc_id, - sndrcvinfo.sinfo_stream, - ntohl(sndrcvinfo.sinfo_ppid), - message_size, - flags); - */ - - // handle now if complete message in one or more segments - if ((flags & 0x80) == 0x80) { - pnf_nr_handle_p5_message(pnf, read_buffer, message_size); - } else { - NFAPI_TRACE(NFAPI_TRACE_WARN, "sctp_recvmsg: unhandled mode with flags 0x%x\n", flags); - - // assume socket disconnected - NFAPI_TRACE(NFAPI_TRACE_WARN, "Disconnected socket\n"); - socket_connected = 0; - } - } - } - } - - if (dynamic_buffer) { - free(dynamic_buffer); - } - - return socket_connected; -} - int pnf_message_pump(pnf_t* pnf) { uint8_t socketConnected = 1; @@ -2272,67 +2146,6 @@ int pnf_message_pump(pnf_t* pnf) pnf->_public.state = NFAPI_PNF_IDLE; - // close the connection and socket - if (close(pnf->p5_sock) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "close(sctpSock) failed errno: %d\n", errno); - } - - return 0; - -} - -int pnf_nr_message_pump(pnf_t* pnf) -{ - uint8_t socketConnected = 1; - - while(socketConnected && pnf->terminate == 0) - { - fd_set rfds; - int selectRetval = 0; - - // select on a timeout and then get the message - FD_ZERO(&rfds); - FD_SET(pnf->p5_sock, &rfds); - - struct timeval timeout; - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - selectRetval = select(pnf->p5_sock+1, &rfds, NULL, NULL, &timeout); - - if(selectRetval == 0) - { - // timeout - continue; - } - else if (selectRetval == -1 && (errno == EINTR)) - { - // interrupted by signal - NFAPI_TRACE(NFAPI_TRACE_WARN, "P5 Signal Interrupt %d\n", errno); - continue; - } - else if (selectRetval == -1) - { - NFAPI_TRACE(NFAPI_TRACE_WARN, "P5 select() failed\n"); - sleep(1); - continue; - } - - if(FD_ISSET(pnf->p5_sock, &rfds)) - { - socketConnected = pnf_nr_read_dispatch_message(pnf); - } - else - { - NFAPI_TRACE(NFAPI_TRACE_WARN, "Why are we here\n"); - } - } - - // Drop back to idle if we have lost connection - pnf->_public.state = NFAPI_PNF_IDLE; - - // close the connection and socket if (close(pnf->p5_sock) < 0) { diff --git a/nfapi/open-nFAPI/pnf/src/pnf_interface.c b/nfapi/open-nFAPI/pnf/src/pnf_interface.c index a53604640c..d80ab168fa 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf_interface.c +++ b/nfapi/open-nFAPI/pnf/src/pnf_interface.c @@ -79,36 +79,6 @@ int nfapi_pnf_start(nfapi_pnf_config_t* config) return 0; } -int nfapi_nr_pnf_start(nfapi_pnf_config_t* config) -{ - // Verify that config is not null - if(config == 0) - return -1; - - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); - - pnf_t* _this = (pnf_t*)(config); - - while (_this->terminate == 0) - { - int connect_result = pnf_connect(_this); - - if(connect_result > 0) - { - pnf_nr_message_pump(_this); - } - else if(connect_result < 0) - { - return connect_result; - } - - sleep(1); - } - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() terminate=1 - EXITTING............\n", __FUNCTION__); - - return 0; -} - int nfapi_pnf_stop(nfapi_pnf_config_t* config) { // Verify that config is not null @@ -135,8 +105,8 @@ int nfapi_nr_pnf_pnf_param_resp(nfapi_pnf_config_t* config, nfapi_nr_pnf_param_r } pnf_t* _this = (pnf_t*)(config); - - return pnf_nr_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_nr_pnf_param_response_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured!"); + return config->send_p5_msg(_this, &(resp->header), sizeof(nfapi_nr_pnf_param_response_t)); } int nfapi_pnf_pnf_param_resp(nfapi_pnf_config_t* config, nfapi_pnf_param_response_t* resp) @@ -188,8 +158,8 @@ int nfapi_nr_pnf_pnf_config_resp(nfapi_pnf_config_t* config, nfapi_nr_pnf_config } pnf_t* _this = (pnf_t*)(config); - - return pnf_nr_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_nr_pnf_config_response_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured|"); + return config->send_p5_msg(_this, &(resp->header), sizeof(nfapi_nr_pnf_config_response_t)); } @@ -227,8 +197,8 @@ int nfapi_nr_pnf_pnf_start_resp(nfapi_pnf_config_t* config, nfapi_nr_pnf_start_r } pnf_t* _this = (pnf_t*)(config); - - return pnf_nr_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_nr_pnf_start_response_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured|"); + return config->send_p5_msg(_this, &(resp->header), sizeof(nfapi_nr_pnf_start_response_t)); } @@ -273,8 +243,8 @@ int nfapi_nr_pnf_param_resp(nfapi_pnf_config_t* config, nfapi_nr_param_response_ } pnf_t* _this = (pnf_t*)(config); - - return pnf_nr_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_nr_param_response_scf_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured|"); + return config->send_p5_msg(_this, &(resp->header), sizeof(nfapi_nr_param_response_scf_t)); } int nfapi_pnf_config_resp(nfapi_pnf_config_t* config, nfapi_config_response_t* resp) @@ -329,8 +299,8 @@ int nfapi_nr_pnf_config_resp(nfapi_pnf_config_t* config, nfapi_nr_config_respons NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: unknow phy id %d\n", __FUNCTION__, resp->header.phy_id); return -1; } - - return pnf_nr_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_nr_config_response_scf_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured|"); + return config->send_p5_msg(_this, &(resp->header), sizeof(nfapi_nr_config_response_scf_t)); } @@ -384,8 +354,8 @@ int nfapi_nr_pnf_start_resp(nfapi_pnf_config_t* config, nfapi_nr_start_response_ NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: unknown phy id %d\n", __FUNCTION__, resp->header.phy_id); return -1; } - - return pnf_nr_pack_and_send_p5_message(_this, &(resp->header), sizeof(nfapi_nr_start_response_scf_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured|"); + return config->send_p5_msg(_this, &(resp->header), sizeof(nfapi_nr_start_response_scf_t)); } diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7.c b/nfapi/open-nFAPI/pnf/src/pnf_p7.c index bdc1634ef5..e2b6d253d2 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf_p7.c +++ b/nfapi/open-nFAPI/pnf/src/pnf_p7.c @@ -32,7 +32,6 @@ #include "common/ran_context.h" #include -#define FAPI2_IP_DSCP 0 extern int sf_ahead; @@ -464,10 +463,10 @@ int pnf_p7_send_message(pnf_p7_t* pnf_p7, uint8_t* msg, uint32_t len) socklen_t remote_addr_len = sizeof(struct sockaddr_in); int sendto_result; - - if ((sendto_result = sendto((int)pnf_p7->p7_sock, (const char*)msg, len, 0, (const struct sockaddr*)&remote_addr, remote_addr_len)) < 0) -//if ((sendto_result = sendto((int)pnf_p7->p7_sock,"hello", 6, 0, (const struct sockaddr*)&remote_addr, remote_addr_len)) < 0) - { + + if ((sendto_result = sendto((int)pnf_p7->p7_sock, (const char*)msg, len, 0, (const struct sockaddr*)&remote_addr, remote_addr_len)) < 0) + //if ((sendto_result = sendto((int)pnf_p7->p7_sock,"hello", 6, 0, (const struct sockaddr*)&remote_addr, remote_addr_len)) < 0) + { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s %s:%d sendto(%d, %p, %d) %d failed errno: %d\n", __FUNCTION__, pnf_p7->_public.remote_p7_addr, pnf_p7->_public.remote_p7_port, (int)pnf_p7->p7_sock, (const char*)msg, len, remote_addr_len, errno); return -1; } @@ -569,87 +568,6 @@ int pnf_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_p7_message_header_t* return 0; } -int pnf_nr_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_nr_p7_message_header_t* header, uint32_t msg_len) -{ - header->m_segment_sequence = NFAPI_P7_SET_MSS(0, 0, pnf_p7->sequence_number); - - // Need to guard against different threads calling the encode function at the same time - if (pthread_mutex_lock(&(pnf_p7->pack_mutex)) != 0) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to lock mutex\n"); - return -1; - } - - uint8_t tx_buf[131072]; // four times NFAPI_MAX_PACKED_MESSAGE_SIZE as of this commit - int len = nfapi_nr_p7_message_pack(header, tx_buf, sizeof(tx_buf), &pnf_p7->_public.codec_config); - - if (len < 0) { - if (pthread_mutex_unlock(&(pnf_p7->pack_mutex)) != 0) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); - return -1; - } - - NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p7_message_pack failed with return %d\n", len); - return -1; - } - - if (len > pnf_p7->_public.segment_size) { - int msg_body_len = len - NFAPI_NR_P7_HEADER_LENGTH; - int seg_body_len = pnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; - int segment_count = (msg_body_len / (seg_body_len)) + ((msg_body_len % seg_body_len) ? 1 : 0); - - int segment = 0; - int offset = NFAPI_NR_P7_HEADER_LENGTH; - uint8_t buffer[pnf_p7->_public.segment_size]; - for (segment = 0; segment < segment_count; ++segment) { - uint8_t last = 0; - uint32_t size = pnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; - if (segment + 1 == segment_count) { - last = 1; - size = (msg_body_len) - (seg_body_len * segment); - } - - uint32_t segment_size = size + NFAPI_NR_P7_HEADER_LENGTH; - - // Update the header with the m and segement - memcpy(&buffer[0], tx_buf, NFAPI_NR_P7_HEADER_LENGTH); - - // set the segment length - buffer[4] = (segment_size & 0xFF000000) >> 24; - buffer[5] = (segment_size & 0xFF0000) >> 16; - buffer[6] = (segment_size & 0xFF00) >> 8; - buffer[7] = (segment_size & 0xFF); - - // set the m & segment number - buffer[8] = ((!last) << 7) + segment; - - memcpy(&buffer[NFAPI_NR_P7_HEADER_LENGTH], tx_buf + offset, size); - offset += size; - - if (pnf_p7->_public.checksum_enabled) { - nfapi_nr_p7_update_checksum(buffer, segment_size); - } - - pnf_p7_send_message(pnf_p7, &buffer[0], segment_size); - } - } else { - if (pnf_p7->_public.checksum_enabled) { - nfapi_nr_p7_update_checksum(tx_buf, len); - } - - // simple case that the message fits in a single segment - pnf_p7_send_message(pnf_p7, tx_buf, len); - } - - pnf_p7->sequence_number++; - - if (pthread_mutex_unlock(&(pnf_p7->pack_mutex)) != 0) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); - return -1; - } - - return 0; -} - void pnf_pack_and_send_timing_info(pnf_p7_t* pnf_p7) { nfapi_timing_info_t timing_info; @@ -707,9 +625,8 @@ void pnf_nr_pack_and_send_timing_info(pnf_p7_t* pnf_p7) timing_info.tx_data_request_earliest_arrival = 0; timing_info.ul_tti_earliest_arrival = 0; timing_info.ul_dci_earliest_arrival = 0; - - - pnf_nr_p7_pack_and_send_p7_message(pnf_p7, &(timing_info.header), sizeof(timing_info)); + AssertFatal(pnf_p7->_public.send_p7_msg, "The function pointer to pack and send P7 messages must be set"); + pnf_p7->_public.send_p7_msg(pnf_p7, &(timing_info.header), sizeof(timing_info)); pnf_p7->timing_info_ms_counter = 0; } @@ -1299,8 +1216,8 @@ void pnf_handle_dl_tti_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) frame, slot, buffer_index); - - if (nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(*req), &(pnf_p7->_public.codec_config)) != 0) + const bool result = pnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, req, sizeof(*req), &(pnf_p7->_public.codec_config)); + if (!result) NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unpack request\n"); } else { if (pnf_p7->_public.timing_info_mode_aperiodic) @@ -1432,8 +1349,8 @@ void pnf_handle_ul_tti_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) frame, slot, buffer_index); - - if (nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(*req), &(pnf_p7->_public.codec_config)) != 0) + const bool result = pnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, req, sizeof(*req), &(pnf_p7->_public.codec_config)); + if (!result) NFAPI_TRACE(NFAPI_TRACE_ERROR, "failed to unpack UL_TTI.request\n"); } else { NFAPI_TRACE(NFAPI_TRACE_NOTE, @@ -1551,8 +1468,8 @@ void pnf_handle_ul_dci_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7) frame, slot, buffer_index); - - if (nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(*req), &pnf_p7->_public.codec_config) != 0) + const bool result = pnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, req, sizeof(*req), &(pnf_p7->_public.codec_config)); + if (!result) NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unpack request\n"); } else { if (pnf_p7->_public.timing_info_mode_aperiodic) { @@ -1664,8 +1581,8 @@ void pnf_handle_tx_data_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7 frame, slot, buffer_index); - - if (nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(*req), &pnf_p7->_public.codec_config) == 0) { + const bool result = pnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, req, sizeof(*req), &(pnf_p7->_public.codec_config)); + if (result) { for (int i = 0; i < req->Number_of_PDUs; ++i) pnf_p7->nr_stats.dl.bytes += req->pdu_list[i].PDU_length; } else { @@ -2063,7 +1980,8 @@ void pnf_nr_handle_dl_node_sync(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7 } // unpack the message - if (nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &dl_node_sync, sizeof(dl_node_sync), &pnf_p7->_public.codec_config) < 0) + const bool result = pnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &dl_node_sync, sizeof(dl_node_sync), &pnf_p7->_public.codec_config); + if (!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); return; @@ -2096,8 +2014,8 @@ void pnf_nr_handle_dl_node_sync(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7 NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to unlock mutex\n"); return; } - - pnf_nr_p7_pack_and_send_p7_message(pnf_p7, &(ul_node_sync.header), sizeof(ul_node_sync)); + AssertFatal(pnf_p7->_public.send_p7_msg, "Function pointer must be configured|"); + pnf_p7->_public.send_p7_msg(pnf_p7, &(ul_node_sync.header), sizeof(ul_node_sync)); //printf("\nSSent UL Node Sync sfn:%d,slot:%d\n",pnf_p7->sfn,pnf_p7->slot); } @@ -2171,7 +2089,7 @@ void pnf_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, } } -void pnf_nr_dispatch_p7_message(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, uint32_t rx_hr_time) +void pnf_nr_handle_p7_message(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, uint32_t rx_hr_time) { nfapi_nr_p7_message_header_t header; @@ -2182,7 +2100,8 @@ void pnf_nr_dispatch_p7_message(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7 } // unpack the message header - if (nfapi_nr_p7_message_header_unpack(pRecvMsg, recvMsgLen, &header, sizeof(header), &pnf_p7->_public.codec_config) < 0) { + const bool result = pnf_p7->_public.hdr_unpack_func(pRecvMsg, recvMsgLen, &header, sizeof(header), &pnf_p7->_public.codec_config); + if (!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); return; } @@ -2325,113 +2244,6 @@ void pnf_handle_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, ui } -void pnf_nr_handle_p7_message(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, uint32_t rx_hr_time) -{ - nfapi_nr_p7_message_header_t messageHeader; - - // validate the input params - if (pRecvMsg == NULL || recvMsgLen < 4 || pnf_p7 == NULL) { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "pnf_handle_p7_message: invalid input params (%p %d %p)\n", pRecvMsg, recvMsgLen, pnf_p7); - return; - } - - // unpack the message header - if (nfapi_nr_p7_message_header_unpack(pRecvMsg, - recvMsgLen, - &messageHeader, - sizeof(nfapi_nr_p7_message_header_t), - &pnf_p7->_public.codec_config) - < 0) { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); - return; - } - - uint8_t m = NFAPI_P7_GET_MORE(messageHeader.m_segment_sequence); - uint8_t sequence_num = NFAPI_P7_GET_SEQUENCE(messageHeader.m_segment_sequence); - uint8_t segment_num = NFAPI_P7_GET_SEGMENT(messageHeader.m_segment_sequence); - - if (pnf_p7->_public.checksum_enabled) { - uint32_t checksum = nfapi_nr_p7_calculate_checksum(pRecvMsg, recvMsgLen); - if (checksum != messageHeader.checksum) { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "Checksum verification failed %d %d\n", checksum, messageHeader.checksum); - return; - } - } - - if (m == 0 && segment_num == 0) { - // we have a complete message - // ensure the message is sensible - if (recvMsgLen < 8 || pRecvMsg == NULL) { - NFAPI_TRACE(NFAPI_TRACE_WARN, "Invalid message size: %d, ignoring\n", recvMsgLen); - return; - } - - pnf_nr_dispatch_p7_message(pRecvMsg, recvMsgLen, pnf_p7, rx_hr_time); - } else { - pnf_p7_rx_message_t* rx_msg = pnf_p7_rx_reassembly_queue_add_segment(pnf_p7, - &(pnf_p7->reassembly_queue), - rx_hr_time, - sequence_num, - segment_num, - m, - pRecvMsg, - recvMsgLen); - - if (rx_msg->num_segments_received == rx_msg->num_segments_expected) { - // send the buffer on - uint16_t i = 0; - uint32_t length = 0; - for (i = 0; i < rx_msg->num_segments_expected; ++i) { - length += rx_msg->segments[i].length - (i > 0 ? NFAPI_NR_P7_HEADER_LENGTH : 0); - } - - if (pnf_p7->reassemby_buffer_size < length) { - pnf_p7_free(pnf_p7, pnf_p7->reassemby_buffer); - pnf_p7->reassemby_buffer = 0; - } - - if (pnf_p7->reassemby_buffer == 0) { - NFAPI_TRACE(NFAPI_TRACE_NOTE, "Resizing PNF_P7 Reassembly buffer %d->%d\n", pnf_p7->reassemby_buffer_size, length); - pnf_p7->reassemby_buffer = (uint8_t*)pnf_p7_malloc(pnf_p7, length); - - if (pnf_p7->reassemby_buffer == 0) { - NFAPI_TRACE(NFAPI_TRACE_NOTE, "Failed to allocate PNF_P7 reassemby buffer len:%d\n", length); - return; - } - memset(pnf_p7->reassemby_buffer, 0, length); - pnf_p7->reassemby_buffer_size = length; - } - - uint32_t offset = 0; - for (i = 0; i < rx_msg->num_segments_expected; ++i) { - if (i == 0) { - memcpy(pnf_p7->reassemby_buffer, rx_msg->segments[i].buffer, rx_msg->segments[i].length); - offset += rx_msg->segments[i].length; - } else { - memcpy(pnf_p7->reassemby_buffer + offset, - rx_msg->segments[i].buffer + NFAPI_NR_P7_HEADER_LENGTH, - rx_msg->segments[i].length - NFAPI_NR_P7_HEADER_LENGTH); - offset += rx_msg->segments[i].length - NFAPI_NR_P7_HEADER_LENGTH; - } - } - - pnf_nr_dispatch_p7_message(pnf_p7->reassemby_buffer, length, pnf_p7, rx_msg->rx_hr_time); - - // delete the structure - pnf_p7_rx_reassembly_queue_remove_msg(pnf_p7, &(pnf_p7->reassembly_queue), rx_msg); - } - } - - // The timeout used to be 1000, i.e., 1ms, which is too short. The below 10ms - // is selected to be able to encompass any "reasonable" slot ahead time for the VNF. - // Ideally, we would remove old msg (segments) if we detect packet loss - // (e.g., if the sequence numbers advances sufficiently); in the branch of - // this commit, our goal is to make the PNF work, so we content ourselves to - // just remove very old messages. - pnf_p7_rx_reassembly_queue_remove_old_msgs(pnf_p7, &(pnf_p7->reassembly_queue), rx_hr_time, 10000); -} - - void pnf_nfapi_p7_read_dispatch_message(pnf_p7_t* pnf_p7, uint32_t now_hr_time) { int recvfrom_result = 0; @@ -2501,68 +2313,6 @@ void pnf_nfapi_p7_read_dispatch_message(pnf_p7_t* pnf_p7, uint32_t now_hr_time) while(recvfrom_result > 0); } -void pnf_nr_nfapi_p7_read_dispatch_message(pnf_p7_t* pnf_p7, uint32_t now_hr_time) -{ - int recvfrom_result = 0; - struct sockaddr_in remote_addr; - socklen_t remote_addr_size = sizeof(remote_addr); - remote_addr.sin_family = 2; // hardcoded - do { - // peek the header - uint8_t header_buffer[NFAPI_NR_P7_HEADER_LENGTH]; - recvfrom_result = recvfrom(pnf_p7->p7_sock, - header_buffer, - NFAPI_NR_P7_HEADER_LENGTH, - MSG_DONTWAIT | MSG_PEEK, - (struct sockaddr*)&remote_addr, - &remote_addr_size); - if (recvfrom_result > 0) { - // get the segment size - nfapi_nr_p7_message_header_t header; - nfapi_nr_p7_message_header_unpack(header_buffer, NFAPI_NR_P7_HEADER_LENGTH, &header, 34, 0); - - // resize the buffer if we have a large segment - if (header.message_length > pnf_p7->rx_message_buffer_size) { - NFAPI_TRACE(NFAPI_TRACE_NOTE, "reallocing rx buffer %d\n", header.message_length); - pnf_p7->rx_message_buffer = realloc(pnf_p7->rx_message_buffer, header.message_length); - pnf_p7->rx_message_buffer_size = header.message_length; - } - - // read the segment - recvfrom_result = recvfrom(pnf_p7->p7_sock, - pnf_p7->rx_message_buffer, - header.message_length, - MSG_DONTWAIT, - (struct sockaddr*)&remote_addr, - &remote_addr_size); - - now_hr_time = pnf_get_current_time_hr(); // moved to here - get closer timestamp??? - - if (recvfrom_result > 0) { - pnf_nr_handle_p7_message(pnf_p7->rx_message_buffer, recvfrom_result, pnf_p7, now_hr_time); - // printf("\npnf_handle_p7_message sfn=%d,slot=%d\n",pnf_p7->sfn,pnf_p7->slot); - } - } else if (recvfrom_result == 0) { - // recv zero length message - recvfrom_result = - recvfrom(pnf_p7->p7_sock, header_buffer, 0, MSG_DONTWAIT, (struct sockaddr*)&remote_addr, &remote_addr_size); - } - - if (recvfrom_result == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // return to the select - // NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom would block :%d\n", __FUNCTION__, errno); - } else { - NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom failed errno:%d\n", __FUNCTION__, errno); - } - } - - // need to update the time as we would only use the value from the - // select - } while (recvfrom_result > 0); -} - - int pnf_p7_message_pump(pnf_p7_t* pnf_p7) { @@ -2604,7 +2354,7 @@ int pnf_p7_message_pump(pnf_p7_t* pnf_p7) } */ - int iptos_value = FAPI2_IP_DSCP << 2; + int iptos_value = 0; if (setsockopt(pnf_p7->p7_sock, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (IPPROTO_IP, IP_TOS) failed errno: %d\n", errno); @@ -2722,197 +2472,15 @@ struct timespec pnf_timespec_add(struct timespec lhs, struct timespec rhs) struct timespec pnf_timespec_sub(struct timespec lhs, struct timespec rhs) { struct timespec result; - if ((lhs.tv_nsec-rhs.tv_nsec)<0) + if ((lhs.tv_nsec-rhs.tv_nsec)<0) { result.tv_sec = lhs.tv_sec-rhs.tv_sec-1; result.tv_nsec = 1000000000+lhs.tv_nsec-rhs.tv_nsec; - } - else + } + else { result.tv_sec = lhs.tv_sec-rhs.tv_sec; result.tv_nsec = lhs.tv_nsec-rhs.tv_nsec; } return result; } - -int pnf_nr_p7_message_pump(pnf_p7_t* pnf_p7) -{ - - // initialize the mutex lock - if(pthread_mutex_init(&(pnf_p7->mutex), NULL) != 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 mutex init: %d\n", errno); - return -1; - } - - if(pthread_mutex_init(&(pnf_p7->pack_mutex), NULL) != 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 mutex init: %d\n", errno); - return -1; - } - - // create the pnf p7 socket - if ((pnf_p7->p7_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 socket errno: %d\n", errno); - return -1; - } - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 socket created (%d)...\n", pnf_p7->p7_sock); - - // configure the UDP socket options - int reuseaddr_enable = 1; - if (setsockopt(pnf_p7->p7_sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_enable, sizeof(int)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (SOL_SOCKET, SO_REUSEADDR) failed errno: %d\n", errno); - return -1; - } - -/* - int reuseport_enable = 1; - if (setsockopt(pnf_p7->p7_sock, SOL_SOCKET, SO_REUSEPORT, &reuseport_enable, sizeof(int)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (SOL_SOCKET, SO_REUSEPORT) failed errno: %d\n", errno); - return -1; - } -*/ - - int iptos_value = FAPI2_IP_DSCP << 2; - if (setsockopt(pnf_p7->p7_sock, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF P7 setsockopt (IPPROTO_IP, IP_TOS) failed errno: %d\n", errno); - return -1; - } - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(pnf_p7->_public.local_p7_port); - - if(pnf_p7->_public.local_p7_addr == 0) - { - addr.sin_addr.s_addr = INADDR_ANY; - } - else - { - //addr.sin_addr.s_addr = inet_addr(pnf_p7->_public.local_p7_addr); - if(inet_aton(pnf_p7->_public.local_p7_addr, &addr.sin_addr) == -1) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "inet_aton failed\n"); - } - } - - - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 binding %d too %s:%d\n", pnf_p7->p7_sock, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - if (bind(pnf_p7->p7_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF_P7 bind error fd:%d errno: %d\n", pnf_p7->p7_sock, errno); - return -1; - } - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 bind succeeded...\n"); - - //Initializaing timing structures needed for slot ticking - - struct timespec slot_start; - clock_gettime(CLOCK_MONOTONIC, &slot_start); - - struct timespec pselect_start; - - struct timespec slot_duration; - slot_duration.tv_sec = 0; - slot_duration.tv_nsec = 0.5e6; - - //Infinite loop - - while(pnf_p7->terminate == 0) - { - fd_set rfds; - int selectRetval = 0; - - // select on a timeout and then get the message - FD_ZERO(&rfds); - FD_SET(pnf_p7->p7_sock, &rfds); - - struct timespec timeout; - timeout.tv_sec = 100; - timeout.tv_nsec = 0; - clock_gettime(CLOCK_MONOTONIC, &pselect_start); - - //setting the timeout - - if((pselect_start.tv_sec > slot_start.tv_sec) || ((pselect_start.tv_sec == slot_start.tv_sec) && (pselect_start.tv_nsec > slot_start.tv_nsec))) - { - // overran the end of the subframe we do not want to wait - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - - //struct timespec overrun = pnf_timespec_sub(pselect_start, sf_start); - //NFAPI_TRACE(NFAPI_TRACE_INFO, "Subframe overrun detected of %d.%d running to catchup\n", overrun.tv_sec, overrun.tv_nsec); - } - else - { - // still time before the end of the subframe wait - timeout = pnf_timespec_sub(slot_start, pselect_start); - } - - selectRetval = pselect(pnf_p7->p7_sock+1, &rfds, NULL, NULL, &timeout, NULL); - - uint32_t now_hr_time = pnf_get_current_time_hr(); - - - - - if(selectRetval == 0) - { - // timeout - - //update slot start timing - slot_start = pnf_timespec_add(slot_start, slot_duration); - - //increment sfn/slot - if (++pnf_p7->slot == 20) - { - pnf_p7->slot = 0; - pnf_p7->sfn = (pnf_p7->sfn + 1) % 1024; - } - - continue; - } - else if (selectRetval == -1 && (errno == EINTR)) - { - // interrupted by signal - NFAPI_TRACE(NFAPI_TRACE_WARN, "PNF P7 Signal Interrupt %d\n", errno); - continue; - } - else if (selectRetval == -1) - { - NFAPI_TRACE(NFAPI_TRACE_WARN, "PNF P7 select() failed\n"); - sleep(1); - continue; - } - - if(FD_ISSET(pnf_p7->p7_sock, &rfds)) - - { - pnf_nr_nfapi_p7_read_dispatch_message(pnf_p7, now_hr_time); - } - } - NFAPI_TRACE(NFAPI_TRACE_ERROR, "PNF_P7 Terminating..\n"); - - // close the connection and socket - if (close(pnf_p7->p7_sock) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "close failed errno: %d\n", errno); - } - - if(pthread_mutex_destroy(&(pnf_p7->pack_mutex)) != 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "mutex destroy failed errno: %d\n", errno); - } - - if(pthread_mutex_destroy(&(pnf_p7->mutex)) != 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "mutex destroy failed errno: %d\n", errno); - } - - return 0; -} diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c index 6e5569d972..b021e67fc9 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c +++ b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c @@ -74,20 +74,7 @@ int nfapi_pnf_p7_start(nfapi_pnf_p7_config_t* config) return 0; } -int nfapi_nr_pnf_p7_start(nfapi_pnf_p7_config_t* config) -{ - // Verify that config is not null - if(config == 0) - return -1; - pnf_p7_t* _this = (pnf_p7_t*)(config); - - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); - - pnf_nr_p7_message_pump(_this); - - return 0; -} int nfapi_pnf_p7_stop(nfapi_pnf_p7_config_t* config) @@ -260,7 +247,8 @@ int nfapi_pnf_p7_nr_slot_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_slot_indica } pnf_p7_t* _this = (pnf_p7_t*)(config); - return pnf_nr_p7_pack_and_send_p7_message(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_slot_indication_scf_t)); + AssertFatal(_this->_public.send_p7_msg, "Function pointer must be configured|"); + return _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_slot_indication_scf_t)); } int nfapi_pnf_p7_nr_rx_data_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_rx_data_indication_t* ind) @@ -272,8 +260,8 @@ int nfapi_pnf_p7_nr_rx_data_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_rx_data_ } pnf_p7_t* _this = (pnf_p7_t*)(config); - - int ret = pnf_nr_p7_pack_and_send_p7_message(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_rx_data_indication_t)); + AssertFatal(_this->_public.send_p7_msg, "Function pointer must be configured|"); + int ret = _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_rx_data_indication_t)); if (ret == 0) { for (int i = 0; i < ind->number_of_pdus; ++i) _this->nr_stats.ul.bytes += ind->pdu_list[i].pdu_length; @@ -290,7 +278,8 @@ int nfapi_pnf_p7_nr_crc_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_crc_indicati } pnf_p7_t* _this = (pnf_p7_t*)(config); - return pnf_nr_p7_pack_and_send_p7_message(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_crc_indication_t)); + AssertFatal(_this->_public.send_p7_msg, "Function pointer must be configured|"); + return _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_crc_indication_t)); } int nfapi_pnf_p7_nr_srs_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_srs_indication_t* ind) @@ -302,7 +291,8 @@ int nfapi_pnf_p7_nr_srs_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_srs_indicati } pnf_p7_t* _this = (pnf_p7_t*)(config); - return pnf_nr_p7_pack_and_send_p7_message(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_srs_indication_t)); + AssertFatal(_this->_public.send_p7_msg, "Function pointer must be configured|"); + return _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_srs_indication_t)); } int nfapi_pnf_p7_nr_uci_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_uci_indication_t* ind) @@ -314,7 +304,8 @@ int nfapi_pnf_p7_nr_uci_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_uci_indicati } pnf_p7_t* _this = (pnf_p7_t*)(config); - return pnf_nr_p7_pack_and_send_p7_message(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_uci_indication_t)); + AssertFatal(_this->_public.send_p7_msg, "Function pointer must be configured|"); + return _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_uci_indication_t)); } int nfapi_pnf_p7_nr_rach_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_rach_indication_t* ind) @@ -326,5 +317,6 @@ int nfapi_pnf_p7_nr_rach_ind(nfapi_pnf_p7_config_t* config, nfapi_nr_rach_indica } pnf_p7_t* _this = (pnf_p7_t*)(config); - return pnf_nr_p7_pack_and_send_p7_message(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_rach_indication_t)); + AssertFatal(_this->_public.send_p7_msg, "Function pointer must be configured|"); + return _this->_public.send_p7_msg(_this, (nfapi_nr_p7_message_header_t*)ind, sizeof(nfapi_nr_rach_indication_t)); } diff --git a/nfapi/open-nFAPI/utils/nfapi_hex_parser.c b/nfapi/open-nFAPI/utils/nfapi_hex_parser.c index 342492ba92..a037f1221e 100644 --- a/nfapi/open-nFAPI/utils/nfapi_hex_parser.c +++ b/nfapi/open-nFAPI/utils/nfapi_hex_parser.c @@ -281,10 +281,9 @@ int main(int argc, char *argv[]) printf("\n"); AssertFatal(byte_count >= sizeof(fapi_message_header_t), "Read byte amount not enough to encode the header. Should have a minimum of %lu bytes, aborting...", sizeof(fapi_message_header_t)); uint8_t *ptr = hex_values; // Points to the first element of the array - uint8_t **msg_ptr = &ptr; // Pointer to the pointer fapi_message_header_t hdr = {.num_msg = 0, .opaque_handle = 0, .message_id = 0, .message_length = 0}; - fapi_nr_message_header_unpack(msg_ptr, NFAPI_HEADER_LENGTH, &hdr, sizeof(fapi_message_header_t), 0); + fapi_nr_message_header_unpack(ptr, NFAPI_HEADER_LENGTH, &hdr, sizeof(fapi_message_header_t), 0); printf("Decoded message %s message length 0x%02x\n", message_id_to_str(hdr.message_id), hdr.message_length); // Unpack the message diff --git a/nfapi/open-nFAPI/vnf/inc/vnf.h b/nfapi/open-nFAPI/vnf/inc/vnf.h index 26870f5523..39769314f4 100644 --- a/nfapi/open-nFAPI/vnf/inc/vnf.h +++ b/nfapi/open-nFAPI/vnf/inc/vnf.h @@ -20,7 +20,7 @@ #include "nfapi_vnf_interface.h" -typedef struct +struct vnf_t { nfapi_vnf_config_t _public; @@ -31,20 +31,22 @@ typedef struct uint8_t tx_message_buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; uint16_t next_phy_id; -} vnf_t; +}; int vnf_pack_and_send_p5_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len); -int vnf_nr_pack_and_send_p5_message(vnf_t* vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t* msg, uint16_t msg_len); int vnf_pack_and_send_p4_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len); int vnf_read_dispatch_message(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* pnf); -int vnf_nr_read_dispatch_message(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* pnf); + void nfapi_vnf_phy_info_list_add(nfapi_vnf_config_t* config, nfapi_vnf_phy_info_t* info); nfapi_vnf_phy_info_t* nfapi_vnf_phy_info_list_find(nfapi_vnf_config_t* config, uint16_t phy_id); void nfapi_vnf_pnf_list_add(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* node); nfapi_vnf_pnf_info_t* nfapi_vnf_pnf_list_find(nfapi_vnf_config_t* config, int p5_idx); + +void vnf_nr_handle_p4_p5_message(void *pRecvMsg, int recvMsgLen, int p5_idx, nfapi_vnf_config_t* config); + #endif // _VNF_H_ diff --git a/nfapi/open-nFAPI/vnf/inc/vnf_p7.h b/nfapi/open-nFAPI/vnf/inc/vnf_p7.h index 92623b41b8..7e04d69b49 100644 --- a/nfapi/open-nFAPI/vnf/inc/vnf_p7.h +++ b/nfapi/open-nFAPI/vnf/inc/vnf_p7.h @@ -19,7 +19,6 @@ #define _VNF_P7_H_ #include "nfapi_vnf_interface.h" - #define TIMEHR_SEC(_time_hr) ((uint32_t)(_time_hr) >> 20) #define TIMEHR_USEC(_time_hr) ((uint32_t)(_time_hr) & 0xFFFFF) #define TIME2TIMEHR(_time) (((uint32_t)(_time.tv_sec) & 0xFFF) << 20 | ((uint32_t)(_time.tv_usec) & 0xFFFFF)) @@ -108,7 +107,7 @@ typedef struct nfapi_vnf_p7_connection_info { } nfapi_vnf_p7_connection_info_t; -typedef struct { +struct vnf_p7_t{ nfapi_vnf_p7_config_t _public; @@ -121,7 +120,7 @@ typedef struct { uint8_t* rx_message_buffer; // would this be better put in the p7 conenction info? uint16_t rx_message_buffer_size; -} vnf_p7_t; +}; uint32_t vnf_get_current_time_hr(void); @@ -132,15 +131,20 @@ int vnf_nr_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info); int send_mac_subframe_indications(vnf_p7_t* config); int send_mac_slot_indications(vnf_p7_t* config); int vnf_p7_read_dispatch_message(vnf_p7_t* vnf_p7 ); -int vnf_nr_p7_read_dispatch_message(vnf_p7_t* vnf_p7 ); +void vnf_nr_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7); +vnf_p7_rx_message_t* vnf_p7_rx_reassembly_queue_add_segment(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, uint16_t sequence_number, uint16_t segment_number, uint8_t m, uint8_t* data, uint16_t data_len); +void* vnf_p7_malloc(vnf_p7_t* vnf_p7, size_t size); +void vnf_p7_free(vnf_p7_t* vnf_p7, void* ptr); +void vnf_p7_rx_reassembly_queue_remove_msg(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, vnf_p7_rx_message_t* msg); +void vnf_p7_rx_reassembly_queue_remove_old_msgs(vnf_p7_t* vnf_p7, vnf_p7_rx_reassembly_queue_t* queue, uint32_t delta); +uint32_t calculate_transmit_timestamp(int mu, uint16_t sfn, uint16_t slot, uint32_t slot_start_time_hr); + void vnf_p7_connection_info_list_add(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* node); nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_find(vnf_p7_t* vnf_p7, uint16_t phy_id); nfapi_vnf_p7_connection_info_t* vnf_p7_connection_info_list_delete(vnf_p7_t* vnf_p7, uint16_t phy_id); int vnf_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header); -int vnf_nr_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_nr_p7_message_header_t* header); - void vnf_p7_release_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header); void vnf_p7_release_pdu(vnf_p7_t* vnf_p7, void* pdu); diff --git a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h index 6fd7d733eb..db303b8b4a 100644 --- a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h +++ b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h @@ -30,7 +30,9 @@ extern "C" { #endif -#define NFAPI_MAX_PACKED_MESSAGE_SIZE 32768 +typedef struct vnf_t vnf_t; +typedef struct vnf_p7_t vnf_p7_t; + /*! The nfapi VNF phy configuration information */ @@ -292,7 +294,25 @@ typedef struct nfapi_vnf_config */ int (*start_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_start_response_t* resp); int (*nr_start_resp)(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_start_response_scf_t* resp); - + + /*! A callback for the ERROR.indication + * \param config A pointer to the vnf configuration + * \param p5_idx The p5 index used to indicate a particular pnf p5 connection + * \param ind A data structure for the decoded ERROR.indication This will + * have been allocated on the stack. + * \return not currently used. + * + * The ERROR.indication contains a reported error from the PNF, often signifying that a message has been sent too late + * + * + * The ind may contain pointers to dynamically allocated sub structures + * such as the vendor_extension. The dynamically allocated structure will + * be deallocated on return. If the client wishes to 'keep' the structures + * then the substructure pointers should be set to 0 and then the client should + * use the codec_config.deallocate function to release it at a future point + */ + int (*nr_error_ind)(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_error_indication_scf_t* ind); + /*! A callback for the STOP.resp * \param config A pointer to the vnf configuration * \param p5_idx The p5 index used to indicate a particular pnf p5 connection @@ -449,10 +469,60 @@ typedef struct nfapi_vnf_config */ void (*deallocate_p4_p5_vendor_ext)(void* header); + /*! \brief Encodes a (n)FAPI P5 message to a buffer + * \param pMessageBuf A pointer to a (n)fapi p5 message structure + * \param messageBufLen The size of the p5 message structure + * \param pPackedBuf A pointer to the buffer that the p5 message will be packed into + * \param packedBufLen The size of the buffer + * \param config A pointer to the nfapi configuration structure + * \return != 0 means success, -1 means failure. + */ + int (*pack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pPackedBuf, + uint32_t packedBufLen, + nfapi_p4_p5_codec_config_t* config); + /*! \brief Decodes an (n)FAPI P5 message + * \param pMessageBuf A pointer to an encoded P5 message + * \param messageBufLen The size of the encoded P5 message + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure + */ + bool (*unpack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p4_p5_codec_config_t* config); + /*! \brief Decodes an (n)FAPI P5 message header + * \param pMessageBuf A pointer to an encoded P5 message header + * \param messageBufLen The size of the encoded P5 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure + */ + bool (*hdr_unpack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p4_p5_codec_config_t* config); + + /*! \brief Sends a (n)FAPI P5 message + * + * This function internally packs the given message into a buffer by calling the previously defined pack_func() function pointer + * Then, having the message buffer populated, sends it to the PNF + * \param vnf A pointer to a vnf_t* + * \param p5_idx The index of the P5 PNF intended to receive the message + * \param msg A pointer to the P5 message + * \param msg_len The size of the encoded P5 message header + * \return true on success, false on failure + */ + bool (*send_p5_msg)(vnf_t* vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len); - } nfapi_vnf_config_t; @@ -476,7 +546,6 @@ void nfapi_vnf_config_destory(nfapi_vnf_config_t* config); * * This function will not return untill nfapi_vnf_stop is called */ -int nfapi_nr_vnf_start(nfapi_vnf_config_t* config); int nfapi_vnf_start(nfapi_vnf_config_t* config); @@ -878,7 +947,52 @@ typedef struct nfapi_vnf_p7_config */ void (*deallocate_p7_vendor_ext)(void* header); + /*! A callback to pack a P7 message +* \param pMessageBuf A pointer to a nfapi p7 message structure +* \param pPackedBuf A pointer to the buffer that the p7 message will be packed into +* \param packedBufLen The size of the buffer +* \param config A pointer to the nfapi configuration structure +* \return != -1 means success, -1 means failure. +*/ + int (*pack_func)(void* pMessageBuf, void* pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t* config); + /*! A callback to unpack a P7 message + * \param pMessageBuf A pointer to an encoded P7 message header + * \param messageBufLen The size of the encoded P7 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure + */ + bool (*unpack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p7_codec_config_t* config); + + /*! \brief Decodes an NFAPI P7 message header + * \param pMessageBuf A pointer to an encoded P5 message header + * \param messageBufLen The size of the encoded P5 message header + * \param pUnpackedBuf A pointer to the nfapi_message_header + * \param unpackedBufLen The size of nfapi_message_header structure. + * \param config A pointer to the nfapi configuration structure + * \return true on success, false on failure + */ + bool (*hdr_unpack_func)(void* pMessageBuf, + uint32_t messageBufLen, + void* pUnpackedBuf, + uint32_t unpackedBufLen, + nfapi_p7_codec_config_t* config); + + /*! \brief Sends a (n)FAPI P7 message + * + * This function internally packs the given message into a buffer by calling the previously defined pack_func() function pointer + * Then, having the message buffer populated, sends it to the PNF + * \param vnf_p7 A pointer to a vnf_p7_t struct + * \param header A pointer to the P7 message to pack & send + * \return true on success, false on failure + */ + bool (*send_p7_msg)(vnf_p7_t* vnf_p7, nfapi_nr_p7_message_header_t* header); } nfapi_vnf_p7_config_t; /*! Creates and initializes the nfapi_vnf_p7_config structure before use @@ -902,7 +1016,7 @@ void nfapi_vnf_p7_config_destory(nfapi_vnf_p7_config_t* config); * function is called. */ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config); -int nfapi_nr_vnf_p7_start(nfapi_vnf_p7_config_t* config); + /*! Stop the VNF P7 library. @@ -959,7 +1073,7 @@ int nfapi_vnf_p7_del_pnf(nfapi_vnf_p7_config_t* config, int phy_id); * may be released after this function call has returned or at a later pointer */ int nfapi_vnf_p7_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_dl_config_request_t* req); -int nfapi_vnf_p7_nr_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_nr_dl_tti_request_t* req); +bool nfapi_vnf_p7_nr_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_nr_dl_tti_request_t* req); /*! Send the UL_CONFIG.request * \param config A pointer to the vnf p7 configuration @@ -970,7 +1084,7 @@ int nfapi_vnf_p7_nr_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_nr_dl_tti * may be released after this function call has returned or at a later pointer */ int nfapi_vnf_p7_ul_config_req(nfapi_vnf_p7_config_t* config, nfapi_ul_config_request_t* req); -int nfapi_vnf_p7_ul_tti_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_tti_request_t* req); +bool nfapi_vnf_p7_ul_tti_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_tti_request_t* req); /*! Send the HI_DCI0.request * \param config A pointer to the vnf p7 configuration * \param req A data structure for the decoded HI_DCI0.request. @@ -980,7 +1094,7 @@ int nfapi_vnf_p7_ul_tti_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_tti_reque * may be released after this function call has returned or at a later pointer */ int nfapi_vnf_p7_hi_dci0_req(nfapi_vnf_p7_config_t* config, nfapi_hi_dci0_request_t* req); -int nfapi_vnf_p7_ul_dci_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_dci_request_t* req); +bool nfapi_vnf_p7_ul_dci_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_dci_request_t* req); /*! Send the TX.req * \param config A pointer to the vnf p7 configuration * \param req A data structure for the decoded HI_DCI0.request. @@ -990,7 +1104,7 @@ int nfapi_vnf_p7_ul_dci_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_dci_reque * may be released after this function call has returned or at a later pointer */ int nfapi_vnf_p7_tx_req(nfapi_vnf_p7_config_t* config, nfapi_tx_request_t* req); -int nfapi_vnf_p7_tx_data_req(nfapi_vnf_p7_config_t* config, nfapi_nr_tx_data_request_t* req); +bool nfapi_vnf_p7_tx_data_req(nfapi_vnf_p7_config_t* config, nfapi_nr_tx_data_request_t* req); /*! Send the LBT_DL_CONFIG.requst * \param config A pointer to the vnf p7 configuration * \param req A data structure for the decoded LBT_DL_CONFIG.request. diff --git a/nfapi/open-nFAPI/vnf/src/vnf.c b/nfapi/open-nFAPI/vnf/src/vnf.c index 390c4b15d9..b61d5f26ae 100644 --- a/nfapi/open-nFAPI/vnf/src/vnf.c +++ b/nfapi/open-nFAPI/vnf/src/vnf.c @@ -29,9 +29,14 @@ #include "nfapi_nr_interface_scf.h" #ifdef ENABLE_AERIAL #include "nfapi/oai_integration/aerial/fapi_nvIPC.h" -#include "nfapi/oai_integration/aerial/fapi_vnf_p5.h" #include "nr_fapi_p5.h" #endif +#ifdef ENABLE_WLS +#include +#endif // ENABLE_WLS + +#include + #include "nfapi/oai_integration/vendor_ext.h" void* vnf_malloc(nfapi_vnf_config_t* config, size_t size) @@ -117,7 +122,8 @@ void vnf_nr_handle_pnf_param_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_ nfapi_nr_pnf_param_response_t msg; // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + const bool result = config->unpack_func(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config); + if (result) { // Invoke the call back if(config->pnf_nr_param_resp) @@ -188,7 +194,8 @@ void vnf_nr_handle_pnf_config_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf nfapi_nr_pnf_config_response_t msg; // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + const bool result = config->unpack_func(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config); + if (result) { // Invoke the call back if(config->pnf_nr_config_resp) @@ -258,7 +265,8 @@ void vnf_nr_handle_pnf_start_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_ nfapi_nr_pnf_start_response_t msg; // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + const bool result = config->unpack_func(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config); + if (result) { if(config->pnf_nr_start_resp) { @@ -428,40 +436,39 @@ void vnf_nr_handle_param_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_conf nfapi_nr_param_response_scf_t msg; // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + const bool result = config->unpack_func(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config); + if (result) { - - if (msg.error_code == NFAPI_NR_PARAM_MSG_OK) - { - nfapi_vnf_phy_info_t* phy_info = nfapi_vnf_phy_info_list_find(config, msg.header.phy_id); - - if(msg.nfapi_config.p7_pnf_address_ipv4.tl.tag) - { - struct sockaddr_in sockAddr; - - (void)memcpy(&sockAddr.sin_addr.s_addr, msg.nfapi_config.p7_pnf_address_ipv4.address, NFAPI_IPV4_ADDRESS_LENGTH); - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 IPv4 address: %s\n", inet_ntoa(sockAddr.sin_addr)); - - // store address - phy_info->p7_pnf_address.sin_addr = sockAddr.sin_addr; - } - - if(msg.nfapi_config.p7_pnf_address_ipv6.tl.tag) - { - struct sockaddr_in6 sockAddr6; - char addr6[64]; - (void)memcpy(&sockAddr6.sin6_addr, msg.nfapi_config.p7_pnf_address_ipv6.address, NFAPI_IPV6_ADDRESS_LENGTH); - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 IPv6 address: %s\n", inet_ntop(AF_INET6, &sockAddr6.sin6_addr, addr6, sizeof(addr6))); - } - - if (msg.nfapi_config.p7_pnf_port.tl.tag) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 Port: %d\n", msg.nfapi_config.p7_pnf_port.value); - - // store port - phy_info->p7_pnf_address.sin_port = htons(msg.nfapi_config.p7_pnf_port.value); - } - } + if (msg.error_code == NFAPI_NR_PARAM_MSG_OK) { + nfapi_vnf_phy_info_t *phy_info = nfapi_vnf_phy_info_list_find(config, msg.header.phy_id); + if (phy_info) { + if (msg.nfapi_config.p7_pnf_address_ipv4.tl.tag) { + struct sockaddr_in sockAddr; + + (void)memcpy(&sockAddr.sin_addr.s_addr, msg.nfapi_config.p7_pnf_address_ipv4.address, NFAPI_IPV4_ADDRESS_LENGTH); + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 IPv4 address: %s\n", inet_ntoa(sockAddr.sin_addr)); + + // store address + phy_info->p7_pnf_address.sin_addr = sockAddr.sin_addr; + } + + if (msg.nfapi_config.p7_pnf_address_ipv6.tl.tag) { + struct sockaddr_in6 sockAddr6; + char addr6[64]; + (void)memcpy(&sockAddr6.sin6_addr, msg.nfapi_config.p7_pnf_address_ipv6.address, NFAPI_IPV6_ADDRESS_LENGTH); + NFAPI_TRACE(NFAPI_TRACE_INFO, + "PNF P7 IPv6 address: %s\n", + inet_ntop(AF_INET6, &sockAddr6.sin6_addr, addr6, sizeof(addr6))); + } + + if (msg.nfapi_config.p7_pnf_port.tl.tag) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF P7 Port: %d\n", msg.nfapi_config.p7_pnf_port.value); + + // store port + phy_info->p7_pnf_address.sin_port = htons(msg.nfapi_config.p7_pnf_port.value); + } + } + } if(config->nr_param_resp) { @@ -495,7 +502,8 @@ void vnf_nr_handle_config_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_con nfapi_nr_config_response_scf_t msg; // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >=0 ) + const bool result = config->unpack_func(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config); + if (result) { // check the error code: @@ -602,7 +610,8 @@ void vnf_nr_handle_start_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_conf nfapi_nr_start_response_scf_t msg; // unpack the message - if (nfapi_nr_p5_message_unpack(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config) >= 0) + const bool result = config->unpack_func(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config); + if (result) { // check the error code if (msg.error_code == NFAPI_NR_START_MSG_OK){ if(config->nr_start_resp) @@ -624,6 +633,39 @@ void vnf_nr_handle_start_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_conf } } +void vnf_nr_handle_error_indication(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) +{ + + // ensure it's valid + if (pRecvMsg == NULL || config == NULL) + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__); + } + else + { + NFAPI_TRACE(NFAPI_TRACE_INFO, "Received ERROR.indication\n"); + + nfapi_nr_error_indication_scf_t msg; + + // unpack the message + if (config->unpack_func(pRecvMsg, recvMsgLen, &msg, sizeof(msg), &config->codec_config)) + { + if (config->nr_error_ind){ + (config->nr_error_ind)(config, p5_idx, &msg); + } + } + else + { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Unpack message failed, ignoring\n", __FUNCTION__); + } + + // make sure to release any dynamic part of the message + if(msg.vendor_extension) + config->codec_config.deallocate(msg.vendor_extension); + } +} + + void vnf_handle_stop_response(void *pRecvMsg, int recvMsgLen, nfapi_vnf_config_t* config, int p5_idx) { @@ -1085,7 +1127,8 @@ void vnf_nr_handle_p4_p5_message(void *pRecvMsg, int recvMsgLen, int p5_idx, nfa } // unpack the message header - if (nfapi_nr_p5_message_header_unpack(pRecvMsg, recvMsgLen, &messageHeader, sizeof(nfapi_nr_p4_p5_message_header_t), &config->codec_config) < 0) + const bool result = config->hdr_unpack_func(pRecvMsg, recvMsgLen, &messageHeader, sizeof(nfapi_nr_p4_p5_message_header_t), &config->codec_config); + if (!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); return; @@ -1115,7 +1158,11 @@ void vnf_nr_handle_p4_p5_message(void *pRecvMsg, int recvMsgLen, int p5_idx, nfa case NFAPI_NR_PHY_MSG_TYPE_CONFIG_RESPONSE: vnf_nr_handle_config_response(pRecvMsg, recvMsgLen, config, p5_idx); - break; + break; + + case NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION: + vnf_nr_handle_error_indication(pRecvMsg, recvMsgLen, config, p5_idx); + break; case NFAPI_NR_PHY_MSG_TYPE_START_RESPONSE: vnf_nr_handle_start_response(pRecvMsg, recvMsgLen, config, p5_idx); @@ -1257,119 +1304,6 @@ void vnf_handle_p4_p5_message(void *pRecvMsg, int recvMsgLen, int p5_idx, nfapi_ } } -int vnf_nr_read_dispatch_message(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* pnf) -{ - if (1) { - int socket_connected = 1; - - // 1. Peek the message header - // 2. If the message is larger than the stack buffer then create a dynamic buffer - // 3. Read the buffer - // 4. Handle the p5 message - - uint32_t header_buffer_size = NFAPI_NR_P5_HEADER_LENGTH; - uint8_t header_buffer[header_buffer_size]; - - uint32_t stack_buffer_size = 32; // should it be the size of then sctp_notificatoin structure - uint8_t stack_buffer[stack_buffer_size]; - - uint8_t* dynamic_buffer = 0; - - uint8_t* read_buffer = &stack_buffer[0]; - uint32_t message_size = 0; - - struct sockaddr_in addr; - socklen_t addr_len = sizeof(addr); - - struct sctp_sndrcvinfo sndrcvinfo; - (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); - - { - int flags = MSG_PEEK; - message_size = - sctp_recvmsg(pnf->p5_sock, header_buffer, header_buffer_size, (struct sockaddr*)&addr, &addr_len, &sndrcvinfo, &flags); - - if (message_size == -1) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to peek sctp message size errno:%d\n", errno); - return 0; - } - - nfapi_nr_p4_p5_message_header_t header; - int unpack_result = nfapi_nr_p5_message_header_unpack(header_buffer, header_buffer_size, &header, sizeof(header), 0); - if (unpack_result < 0) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to decode message header %d\n", unpack_result); - return 0; - } - message_size = header.message_length + header_buffer_size; - - // now have the size of the mesage - } - - if (message_size > stack_buffer_size) { - dynamic_buffer = (uint8_t*)malloc(message_size); - - if (dynamic_buffer == NULL) { - // todo : add error mesage - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Failed to allocate dynamic buffer for sctp_recvmsg size:%d\n", message_size); - return -1; - } - - read_buffer = dynamic_buffer; - } - - { - int flags = 0; - (void)memset(&sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); - - int recvmsg_result = - sctp_recvmsg(pnf->p5_sock, read_buffer, message_size, (struct sockaddr*)&addr, &addr_len, &sndrcvinfo, &flags); - if (recvmsg_result == -1) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "Failed to read sctp message size errno:%d\n", errno); - } else { - if (flags & MSG_NOTIFICATION) { - NFAPI_TRACE(NFAPI_TRACE_INFO, "Notification received from %s:%u\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - - // todo - handle the events - } else { - /* - NFAPI_TRACE(NFAPI_TRACE_INFO, "Received message fd:%d from %s:%u assoc:%d on stream %d, PPID %d, length %d, flags 0x%x\n", - pnf->p5_sock, - inet_ntoa(addr.sin_addr), - ntohs(addr.sin_port), - sndrcvinfo.sinfo_assoc_id, - sndrcvinfo.sinfo_stream, - ntohl(sndrcvinfo.sinfo_ppid), - message_size, - flags); - */ - - // handle now if complete message in one or more segments - if ((flags & 0x80) == 0x80) { - // printf("\nVNF RECEIVES:\n"); - // for(int i=0; ip5_idx, config); - } else { - NFAPI_TRACE(NFAPI_TRACE_WARN, "sctp_recvmsg: unhandled mode with flags 0x%x\n", flags); - - // assume socket disconnected - NFAPI_TRACE(NFAPI_TRACE_WARN, "Disconnected socket\n"); - socket_connected = 0; - } - } - } - } - - if (dynamic_buffer) { - free(dynamic_buffer); - } - - return socket_connected; - } -} int vnf_read_dispatch_message(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* pnf) { @@ -1502,7 +1436,7 @@ int vnf_read_dispatch_message(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* } } -static int vnf_send_p5_msg(nfapi_vnf_pnf_info_t* pnf, const void *msg, int len, uint8_t stream) +static int vnf_send_p5_msg(vnf_t *vnf, nfapi_vnf_pnf_info_t *pnf, const void *msg, int len, uint8_t stream) { // printf("\n MESSAGE SENT: \n"); // for(int i=0; ip5_sock, msg, len, (struct sockaddr*)&pnf->p5_pnf_sockaddr, sizeof(pnf->p5_pnf_sockaddr),1, 0, stream, 0, 4); + ssize_t result = -1; + if (vnf->sctp) { + result = sctp_sendmsg(pnf->p5_sock, + msg, + len, + (struct sockaddr *)&pnf->p5_pnf_sockaddr, + sizeof(pnf->p5_pnf_sockaddr), + 1, + 0, + stream, + 0, + 4); + } else { + result = send(pnf->p5_sock, msg, len,0); + } if(result != len) { @@ -1530,53 +1478,6 @@ static int vnf_send_p5_msg(nfapi_vnf_pnf_info_t* pnf, const void *msg, int len, return 0; } -int vnf_nr_pack_and_send_p5_message(vnf_t* vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t* msg, uint16_t msg_len) -{ - nfapi_vnf_pnf_info_t* pnf = nfapi_vnf_pnf_list_find(&(vnf->_public), p5_idx); - - if(pnf) - { - // pack the message for transmission - int packedMessageLength = 0; - if (NFAPI_MODE == NFAPI_MODE_AERIAL) { -#ifdef ENABLE_AERIAL - // In case it is a FAPI message, create 2 messages, one with nFAPI header for OAI PNF and one with no nFAPI header for Aerial - // L1 - // create FAPI tx_buffer - uint8_t tx_messagebufferFAPI[sizeof(vnf->tx_message_buffer)]; - int packedMessageLengthFAPI = -1; - packedMessageLengthFAPI = - fapi_nr_p5_message_pack(msg, msg_len, tx_messagebufferFAPI, sizeof(tx_messagebufferFAPI), &vnf->_public.codec_config); - return aerial_send_P5_msg(tx_messagebufferFAPI, packedMessageLengthFAPI, msg); -#else - return 0; -#endif - } else { - packedMessageLength = nfapi_nr_p5_message_pack(msg, - msg_len, - vnf->tx_message_buffer, - sizeof(vnf->tx_message_buffer), - &vnf->_public.codec_config); - - if (packedMessageLength < 0) { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_nr_p5_message_pack failed with return %d\n", packedMessageLength); - return -1; - } - // printf("msg id = 0x%02x, entire message length: %d\n", msg->message_id, packedMessageLength); - // for (int i = 0; i < packedMessageLength; i++) { - // printf(" msg->msg_buf[%d] = 0x%02x\n", i, ((uint8_t *) vnf->tx_message_buffer)[i]); - // } - - return vnf_send_p5_msg(pnf, vnf->tx_message_buffer, packedMessageLength, 0); - } - } else { - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find pnf info for p5_idx:%d\n", __FUNCTION__, p5_idx); - return -1; - } - -} - - int vnf_pack_and_send_p5_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_message_header_t* msg, uint16_t msg_len) { nfapi_vnf_pnf_info_t* pnf = nfapi_vnf_pnf_list_find(&(vnf->_public), p5_idx); @@ -1592,7 +1493,7 @@ int vnf_pack_and_send_p5_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_messag return -1; } - return vnf_send_p5_msg(pnf, vnf->tx_message_buffer, packedMessageLength, 0/*msg->phy_id*/); + return vnf_send_p5_msg(vnf, pnf, vnf->tx_message_buffer, packedMessageLength, 0/*msg->phy_id*/); } else { @@ -1617,7 +1518,7 @@ int vnf_pack_and_send_p4_message(vnf_t* vnf, uint16_t p5_idx, nfapi_p4_p5_messag return -1; } - return vnf_send_p5_msg(pnf, vnf->tx_message_buffer, packedMessageLength, 0/*msg->phy_id*/); + return vnf_send_p5_msg(vnf, pnf, vnf->tx_message_buffer, packedMessageLength, 0/*msg->phy_id*/); } else { diff --git a/nfapi/open-nFAPI/vnf/src/vnf_interface.c b/nfapi/open-nFAPI/vnf/src/vnf_interface.c index 633dd18f24..111d88e8dc 100644 --- a/nfapi/open-nFAPI/vnf/src/vnf_interface.c +++ b/nfapi/open-nFAPI/vnf/src/vnf_interface.c @@ -1,12 +1,12 @@ /* * Copyright 2017 Cisco Systems, Inc. - * + * * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * + * * 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. @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "assertions.h" #include #include @@ -64,413 +65,6 @@ void nfapi_vnf_config_destory(nfapi_vnf_config_t* config) free(config); } -int nfapi_nr_vnf_start(nfapi_vnf_config_t* config) -{ - // Verify that config is not null - if(config == 0) - return -1; - - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); - - int p5ListenSock, p5Sock; - - struct sockaddr_in addr; - socklen_t addrSize; - - struct sockaddr_in6 addr6; - - struct sctp_event_subscribe events; - struct sctp_initmsg initMsg; - int noDelay; - - (void)memset(&addr, 0, sizeof(struct sockaddr_in)); - (void)memset(&addr6, 0, sizeof(struct sockaddr_in6)); - (void)memset(&events, 0, sizeof(struct sctp_event_subscribe)); - (void)memset(&initMsg, 0, sizeof(struct sctp_initmsg)); - - vnf_t* vnf = (vnf_t*)(config); - - NFAPI_TRACE(NFAPI_TRACE_INFO, "Starting P5 VNF connection on port %u\n", config->vnf_p5_port); - - /* - char * host = 0; - char * port = "4242"; - struct addrinfo hints; - bzero(&hints, sizeof(struct addrinfo)); - //hints.ai_flags=AI_PASSIVE; - //hints.ai_flags=AI_DEFAULT; - hints.ai_family=AF_UNSPEC; - //hints.ai_family=AF_INET6; - hints.ai_socktype=SOCK_STREAM; - //hints.ai_protocol=IPPROTO_SCTP - - struct addrinfo *aiHead = 0; - - - - int result = getaddrinfo(host, port, &hints, &aiHead); - NFAPI_TRACE(NFAPI_TRACE_INFO, "getaddrinfo return %d %d\n", result, errno); - - while(aiHead->ai_next != NULL) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "addr info %d (IP %d UDP %d SCTP %d)\n %d (%d)\n", - aiHead->ai_protocol, IPPROTO_IP, IPPROTO_UDP, IPPROTO_SCTP, - aiHead->ai_flags, AI_PASSIVE); - - char hostBfr[ NI_MAXHOST ]; - char servBfr[ NI_MAXSERV ]; - - getnameinfo(aiHead->ai_addr, - aiHead->ai_addrlen, - hostBfr, - sizeof( hostBfr ), - servBfr, - sizeof( servBfr ), - NI_NUMERICHOST | NI_NUMERICSERV ); - - switch(aiHead->ai_family) - { - case PF_INET: - { - struct sockaddr_in *pSadrIn = (struct sockaddr_in*) aiHead->ai_addr; - printf( - " ai_addr = sin_family: %d (AF_INET = %d, " - "AF_INET6 = %d)\n" - " sin_addr: %s\n" - " sin_port: %s\n", - pSadrIn->sin_family, - AF_INET, - AF_INET6, - hostBfr, - servBfr ); - } - break; - case PF_INET6: - { - struct sockaddr_in6 *pSadrIn6 = (struct sockaddr_in6*) aiHead->ai_addr; - fprintf( stderr, - " ai_addr = sin6_family: %d (AF_INET = %d, " - "AF_INET6 = %d) \n" - " sin6_addr: %s\n" - " sin6_port: %s\n" - " sin6_flowinfo: %d\n" - " sin6_scope_id: %d\n", - pSadrIn6->sin6_family, - AF_INET, - AF_INET6, - hostBfr, - servBfr, - pSadrIn6->sin6_flowinfo, - pSadrIn6->sin6_scope_id); - } - break; - default: - NFAPI_TRACE(NFAPI_TRACE_INFO, "Not ment to be here\n"); - break; - } - - aiHead = aiHead->ai_next; - } - */ - - { - int protocol; - int domain; - - if (vnf->sctp) - protocol = IPPROTO_SCTP; - else - protocol = IPPROTO_IP; - - if(config->vnf_ipv6) - { - domain = PF_INET6; - } - else - { - domain = AF_INET; - } - - // open the SCTP socket - if ((p5ListenSock = socket(domain, SOCK_STREAM, protocol)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P5 socket errno: %d\n", errno); - return 0; - } - NFAPI_TRACE(NFAPI_TRACE_INFO, "P5 socket created... %d\n", p5ListenSock); - } - - if (vnf->sctp) - { - // configure for MSG_NOTIFICATION - if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(struct sctp_event_subscribe)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_EVENTS) errno: %d\n", errno); - close(p5ListenSock); - return 0; - } - NFAPI_TRACE(NFAPI_TRACE_NOTE, "VNF Setting the SCTP_INITMSG\n"); - // configure the SCTP socket options - initMsg.sinit_num_ostreams = 5; //MAX_SCTP_STREAMS; // number of output streams can be greater - initMsg.sinit_max_instreams = 5; //MAX_SCTP_STREAMS; // number of output streams can be greater - if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_INITMSG) errno: %d\n", errno); - close(p5ListenSock); - return 0; - } - noDelay = 1; - if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_NODELAY, &noDelay, sizeof(noDelay)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (STCP_NODELAY) errno: %d\n", errno); - close(p5ListenSock); - return 0; - } - struct sctp_event_subscribe events; - memset( (void *)&events, 0, sizeof(events) ); - events.sctp_data_io_event = 1; - - if(setsockopt(p5ListenSock, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt errno: %d\n", errno); - close(p5ListenSock); - return -1; - } - - } - - - if(config->vnf_ipv6) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "IPV6 binding to port %d %d\n", config->vnf_p5_port, p5ListenSock); - addr6.sin6_family = AF_INET6; - addr6.sin6_port = htons(config->vnf_p5_port); - addr6.sin6_addr = in6addr_any; - - // bind to the configured address and port - if (bind(p5ListenSock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); - close(p5ListenSock); - return 0; - } - } - else if(config->vnf_ipv4) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "IPV4 binding to port %d\n", config->vnf_p5_port); - addr.sin_family = AF_INET; - addr.sin_port = htons(config->vnf_p5_port); - addr.sin_addr.s_addr = INADDR_ANY; - - // bind to the configured address and port - if (bind(p5ListenSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) - //if (sctp_bindx(p5ListenSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), SCTP_BINDX_ADD_ADDR) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); - close(p5ListenSock); - return 0; - } - } - - NFAPI_TRACE(NFAPI_TRACE_INFO, "bind succeeded..%d.\n", p5ListenSock); - - // put the socket into listen mode - if (listen(p5ListenSock, 2) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After listen errno: %d\n", errno); - close(p5ListenSock); - return 0; - } - - NFAPI_TRACE(NFAPI_TRACE_INFO, "listen succeeded...\n"); - - struct timeval tv; - fd_set read_fd_set; - - - int p5_idx = 0; - while(vnf->terminate == 0) - { - FD_ZERO(&read_fd_set); - - FD_SET(p5ListenSock, &read_fd_set); - int max_fd = p5ListenSock; - - tv.tv_sec = 5; - tv.tv_usec = 0; - - nfapi_vnf_pnf_info_t* pnf = config->pnf_list; - while(pnf != 0) - { - if(pnf->connected) - { - FD_SET(pnf->p5_sock, &read_fd_set); - if (pnf->p5_sock > max_fd) - { - max_fd = pnf->p5_sock; - } - } - - pnf = pnf->next; - } - - int select_result = select(max_fd + 1, &read_fd_set, 0, 0, &tv); - - if(select_result == -1) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "select result %d errno %d\n", select_result, errno); - close(p5ListenSock); - return 0; - } - else if(select_result) - { - if(FD_ISSET(p5ListenSock, &read_fd_set)) - { - addrSize = sizeof(struct sockaddr_in); - NFAPI_TRACE(NFAPI_TRACE_INFO, "Accepting connection from PNF...\n"); - - p5Sock = accept(p5ListenSock, (struct sockaddr *)&addr, &addrSize); - - if (p5Sock < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to accept PNF connection reason:%d\n", errno); - } - else - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF connection (fd:%d) accepted from %s:%d \n", p5Sock, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - nfapi_vnf_pnf_info_t* pnf = (nfapi_vnf_pnf_info_t*)malloc(sizeof(nfapi_vnf_pnf_info_t)); - NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf); - memset(pnf, 0, sizeof(nfapi_vnf_pnf_info_t)); - pnf->p5_sock = p5Sock; - pnf->p5_idx = p5_idx++; - pnf->p5_pnf_sockaddr = addr; - pnf->connected = 1; - - nfapi_vnf_pnf_list_add(config, pnf); - - // Inform mac that a pnf connection has been established - // todo : allow mac to 'accept' the connection. i.e. to - // reject it. - if(config->pnf_nr_connection_indication != 0) - { - (config->pnf_nr_connection_indication)(config, pnf->p5_idx); - } - - - // check the connection status - { - struct sctp_status status; - (void)memset(&status, 0, sizeof(struct sctp_status)); - socklen_t optLen = (socklen_t) sizeof(struct sctp_status); - if (getsockopt(p5Sock, IPPROTO_SCTP, SCTP_STATUS, &status, &optLen) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After getsockopt errno: %d\n", errno); - return -1; - } - else - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Association ID = %d\n", status.sstat_assoc_id); - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Receiver window size = %d\n", status.sstat_rwnd); - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF In Streams = %d\n", status.sstat_instrms); - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF Out Streams = %d\n", status.sstat_outstrms); - - } - } - } - } - else - { - uint8_t delete_pnfs = 0; - - nfapi_vnf_pnf_info_t* pnf = config->pnf_list; - while(pnf != 0) - { - if(FD_ISSET(pnf->p5_sock, &read_fd_set)) - { - if(vnf_nr_read_dispatch_message(config, pnf) == 0) - { - if(config->pnf_disconnect_indication != 0) - { - (config->pnf_disconnect_indication)(config, pnf->p5_idx); - } - - close(pnf->p5_sock); - - pnf->to_delete = 1; - delete_pnfs = 1; - } - } - - pnf = pnf->next; - } - - if(delete_pnfs) - { - nfapi_vnf_pnf_info_t* pnf = config->pnf_list; - nfapi_vnf_pnf_info_t* prev = 0; - while(pnf != 0) - { - nfapi_vnf_pnf_info_t* curr = pnf; - - if(pnf->to_delete == 1) - { - if(prev == 0) - { - config->pnf_list = pnf->next; - } - else - { - prev->next = pnf->next; - } - - pnf = pnf->next; - - free(curr); - } - else - { - prev = pnf; - pnf = pnf->next; - } - - } - - } - } - - continue; - } - else - { - // timeout - - // Should we test for socket closure here every second? - - continue; - } - } - - NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p5Sock socket's\n"); - { - nfapi_vnf_pnf_info_t* curr = config->pnf_list; - while(curr != NULL) - { - if(config->pnf_disconnect_indication) - { - (config->pnf_disconnect_indication)(config, curr->p5_idx); - } - - close(curr->p5_sock); - curr = curr->next; - } - } - - NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p5Listen socket\n"); - close(p5ListenSock); - - return 0; - -} int nfapi_vnf_start(nfapi_vnf_config_t* config) { @@ -894,8 +488,8 @@ int nfapi_nr_vnf_pnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_ return -1; vnf_t* _this = (vnf_t*)(config); - - return vnf_nr_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_param_request_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured\n"); + return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_param_request_t)); } int nfapi_vnf_pnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_param_request_t* req) @@ -914,8 +508,8 @@ int nfapi_nr_vnf_pnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr return -1; vnf_t* _this = (vnf_t*)(config); - - return vnf_nr_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_config_request_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured\n"); + return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_config_request_t)); } @@ -945,8 +539,8 @@ int nfapi_nr_vnf_pnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_ return -1; vnf_t* _this = (vnf_t*)(config); - - return vnf_nr_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_start_request_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured\n"); + return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_pnf_start_request_t)); } int nfapi_vnf_pnf_stop_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_pnf_stop_request_t* req) @@ -965,8 +559,8 @@ int nfapi_nr_vnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_para return -1; vnf_t* _this = (vnf_t*)(config); - - return vnf_nr_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_nr_param_request_scf_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured\n"); + return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_param_request_scf_t)); } int nfapi_vnf_param_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_param_request_t* req) @@ -983,9 +577,9 @@ int nfapi_nr_vnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_con { if(config == 0 || req == 0) return -1; - + AssertFatal(config->send_p5_msg, "Function pointer must be configured\n"); vnf_t* _this = (vnf_t*)(config); - +#if !defined(ENABLE_WLS) && !defined(ENABLE_AERIAL) nfapi_vnf_phy_info_t* phy = nfapi_vnf_phy_info_list_find(config, req->header.phy_id); if(phy == NULL) @@ -1006,8 +600,8 @@ int nfapi_nr_vnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_con req->nfapi_config.timing_info_period.tl.tag = NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG; req->nfapi_config.timing_info_period.value = phy->timing_info_period; req->num_tlv++; - - return vnf_nr_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_nr_config_request_scf_t)); +#endif + return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_config_request_scf_t)); } int nfapi_vnf_config_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_config_request_t* req) @@ -1057,8 +651,8 @@ int nfapi_nr_vnf_start_req(nfapi_vnf_config_t* config, int p5_idx, nfapi_nr_star return -1; vnf_t* _this = (vnf_t*)(config); - - return vnf_nr_pack_and_send_p5_message(_this, p5_idx, &req->header, sizeof(nfapi_nr_start_request_scf_t)); + AssertFatal(config->send_p5_msg, "Function pointer must be configured\n"); + return config->send_p5_msg(_this, p5_idx, &req->header, sizeof(nfapi_nr_start_request_scf_t)); } diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7.c b/nfapi/open-nFAPI/vnf/src/vnf_p7.c index 3d2975d03c..82c5ae7d1c 100644 --- a/nfapi/open-nFAPI/vnf/src/vnf_p7.c +++ b/nfapi/open-nFAPI/vnf/src/vnf_p7.c @@ -29,6 +29,9 @@ #include "nfapi/oai_integration/aerial/fapi_nvIPC.h" #endif #include "vnf_p7.h" +#ifdef ENABLE_WLS +#include +#endif #include "nr_fapi_p7_utils.h" #ifdef NDEBUG @@ -473,102 +476,6 @@ int vnf_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info, u return 0; } -int vnf_nr_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_nr_p7_message_header_t* header) -{ - - nfapi_vnf_p7_connection_info_t* p7_connection = vnf_p7_connection_info_list_find(vnf_p7, header->phy_id); - if(p7_connection) - { - int send_result = 0; - uint8_t buffer[1024*1024*3]; - - header->m_segment_sequence = NFAPI_P7_SET_MSS(0, 0, p7_connection->sequence_number); - - int len = nfapi_nr_p7_message_pack(header, buffer, sizeof(buffer), &vnf_p7->_public.codec_config); - - //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() phy_id:%d nfapi_p7_message_pack()=len=%d vnf_p7->_public.segment_size:%u\n", __FUNCTION__, header->phy_id, len, vnf_p7->_public.segment_size); - - if(len < 0) - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() failed to pack p7 message phy_id:%d\n", __FUNCTION__, header->phy_id); - return -1; - } - - if(len > vnf_p7->_public.segment_size) - { - // todo : consider replacing with the sendmmsg call - // todo : worry about blocking writes? - - // segmenting the transmit - int msg_body_len = len - NFAPI_NR_P7_HEADER_LENGTH ; - uint32_t seg_body_len = vnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH ; - int segment_count = (msg_body_len / (seg_body_len)) + ((msg_body_len % seg_body_len) ? 1 : 0); - - int segment = 0; - int offset = NFAPI_NR_P7_HEADER_LENGTH; - uint8_t tx_buffer[vnf_p7->_public.segment_size]; - NFAPI_TRACE(NFAPI_TRACE_DEBUG, "%s() MORE THAN ONE SEGMENT phy_id:%d nfapi_p7_message_pack()=len=%d vnf_p7->_public.segment_size:%u\n", __FUNCTION__, header->phy_id, len, vnf_p7->_public.segment_size); - for(segment = 0; segment < segment_count; ++segment) - { - uint8_t last = 0; - uint32_t size = vnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; - if(segment + 1 == segment_count) - { - last = 1; - size = (msg_body_len) - (seg_body_len * segment); - } - - uint32_t segment_size = size + NFAPI_NR_P7_HEADER_LENGTH; - - // Update the header with the m and segement - memcpy(&tx_buffer[0], buffer, NFAPI_NR_P7_HEADER_LENGTH); - - // set the segment length - tx_buffer[4] = (segment_size & 0xFF000000) >> 24; - tx_buffer[5] = (segment_size & 0xFF0000) >> 16; - tx_buffer[6] = (segment_size & 0xFF00) >> 8; - tx_buffer[7] = (segment_size & 0xFF); - - // set the m & segment number - tx_buffer[8] = ((!last) << 7) + segment; - - memcpy(&tx_buffer[NFAPI_NR_P7_HEADER_LENGTH], &buffer[0] + offset, size); - offset += size; - - if(vnf_p7->_public.checksum_enabled) - { - nfapi_nr_p7_update_checksum(tx_buffer, segment_size); - } - - nfapi_nr_p7_update_transmit_timestamp(buffer, calculate_transmit_timestamp(p7_connection->mu, p7_connection->sfn, p7_connection->slot, vnf_p7->slot_start_time_hr)); - - send_result = vnf_send_p7_msg(vnf_p7, p7_connection, &tx_buffer[0], segment_size); - - } - } - else - { - if(vnf_p7->_public.checksum_enabled) - { - nfapi_nr_p7_update_checksum(buffer, len); - } - - nfapi_nr_p7_update_transmit_timestamp(buffer, calculate_transmit_timestamp(p7_connection->mu, p7_connection->sfn, p7_connection->slot, vnf_p7->slot_start_time_hr)); - - // simple case that the message fits in a single segement - send_result = vnf_send_p7_msg(vnf_p7, p7_connection, &buffer[0], len); - } - - p7_connection->sequence_number++; - return send_result; - } - else - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find p7 connection info for phy_id:%d\n", __FUNCTION__, header->phy_id); - return -1; - } -} - int vnf_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_p7_message_header_t* header) { @@ -676,7 +583,8 @@ int vnf_build_send_dl_node_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t } int vnf_nr_build_send_dl_node_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info) -{ +{ + nfapi_vnf_p7_config_t* config = (nfapi_vnf_p7_config_t*)vnf_p7; nfapi_nr_dl_node_sync_t dl_node_sync; memset(&dl_node_sync, 0, sizeof(dl_node_sync)); @@ -686,7 +594,7 @@ int vnf_nr_build_send_dl_node_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_inf dl_node_sync.t1 = calculate_nr_t1(p7_info->mu, p7_info->sfn,p7_info->slot, vnf_p7->slot_start_time_hr); dl_node_sync.delta_sfn_slot = 0; - return vnf_nr_p7_pack_and_send_p7_msg(vnf_p7, &dl_node_sync.header); + return config->send_p7_msg(vnf_p7, &dl_node_sync.header); } int vnf_nr_sync(vnf_p7_t* vnf_p7, nfapi_vnf_p7_connection_info_t* p7_info) @@ -1098,10 +1006,8 @@ void vnf_nr_handle_p7_vendor_extension(void *pRecvMsg, int recvMsgLen, vnf_p7_t* NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate vendor extention structure\n", __FUNCTION__); return; } - - int unpack_result = nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, msg, msg_size, &vnf_p7->_public.codec_config); - - if(unpack_result == 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, msg, msg_size, &vnf_p7->_public.codec_config); + if(!result) { if(vnf_p7->_public.vendor_ext) vnf_p7->_public.vendor_ext(&(vnf_p7->_public), msg); @@ -1497,8 +1403,8 @@ void vnf_handle_nr_slot_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf else { nfapi_nr_slot_indication_scf_t ind = {0}; - - if(nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config); + if(!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); } @@ -1524,8 +1430,8 @@ void vnf_handle_nr_rx_data_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* else { nfapi_nr_rx_data_indication_t ind; - - if(nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config); + if(!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); } @@ -1551,8 +1457,8 @@ void vnf_handle_nr_crc_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_ else { nfapi_nr_crc_indication_t ind; - - if(nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config); + if(!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); } @@ -1578,8 +1484,8 @@ void vnf_handle_nr_srs_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_ else { nfapi_nr_srs_indication_t ind; - - if(nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config); + if(!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); } @@ -1604,8 +1510,8 @@ void vnf_handle_nr_uci_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_ else { nfapi_nr_uci_indication_t ind; - - if(nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config); + if(!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); } @@ -1631,8 +1537,8 @@ void vnf_handle_nr_rach_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf else { nfapi_nr_rach_indication_t ind; - - if(nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(ind), &vnf_p7->_public.codec_config); + if(!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__); } @@ -1661,7 +1567,8 @@ void vnf_nr_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7 } nfapi_nr_ul_node_sync_t ind; - if(nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(nfapi_nr_ul_node_sync_t), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(nfapi_nr_ul_node_sync_t), &vnf_p7->_public.codec_config); + if(!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to unpack ul_node_sync\n"); return; @@ -2096,7 +2003,8 @@ void vnf_nr_handle_timing_info(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) } nfapi_nr_timing_info_t ind; - if(nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, &ind, sizeof(nfapi_timing_info_t), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.unpack_func(pRecvMsg, recvMsgLen, &ind, sizeof(nfapi_timing_info_t), &vnf_p7->_public.codec_config); + if(!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "Failed to unpack timing_info\n"); return; @@ -2220,7 +2128,7 @@ void vnf_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) } } -void vnf_nr_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) +void vnf_nr_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) { nfapi_nr_p7_message_header_t header; @@ -2232,7 +2140,8 @@ void vnf_nr_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7 } // unpack the message header - if (nfapi_nr_p7_message_header_unpack(pRecvMsg, recvMsgLen, &header, sizeof(header), &vnf_p7->_public.codec_config) < 0) + const bool result = vnf_p7->_public.hdr_unpack_func(pRecvMsg, recvMsgLen, &header, sizeof(header), &vnf_p7->_public.codec_config); + if (!result) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); return; @@ -2417,196 +2326,6 @@ void vnf_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) } } -void vnf_nr_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7) -{ - nfapi_nr_p7_message_header_t messageHeader; - - // validate the input params - if(pRecvMsg == NULL || recvMsgLen < 4 || vnf_p7 == NULL) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_p7_message: invalid input params (%p %d %p)\n", pRecvMsg, recvMsgLen, vnf_p7); - return; - } - - // unpack the message header - if (nfapi_nr_p7_message_header_unpack(pRecvMsg, recvMsgLen, &messageHeader, sizeof(nfapi_nr_p7_message_header_t), &vnf_p7->_public.codec_config) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); - return; - } - - if(vnf_p7->_public.checksum_enabled) - { - uint32_t checksum = nfapi_nr_p7_calculate_checksum(pRecvMsg, recvMsgLen); - if(checksum != messageHeader.checksum) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "Checksum verification failed %d %d msg:%d len:%d\n", checksum, messageHeader.checksum, messageHeader.message_id, recvMsgLen); - return; - } - } - - uint8_t m = NFAPI_P7_GET_MORE(messageHeader.m_segment_sequence); - uint8_t segment_num = NFAPI_P7_GET_SEGMENT(messageHeader.m_segment_sequence); - uint8_t sequence_num = NFAPI_P7_GET_SEQUENCE(messageHeader.m_segment_sequence); - - - if(m == 0 && segment_num == 0) - { - // we have a complete message - // ensure the message is sensible - if (recvMsgLen < 8 || pRecvMsg == NULL) - { - NFAPI_TRACE(NFAPI_TRACE_WARN, "Invalid message size: %d, ignoring\n", recvMsgLen); - return; - } - - //vnf_dispatch_p7_message(&messageHeader, pRecvMsg, recvMsgLen, vnf_p7); - vnf_nr_dispatch_p7_message(pRecvMsg, recvMsgLen, vnf_p7); - } - else - { - nfapi_vnf_p7_connection_info_t* phy = vnf_p7_connection_info_list_find(vnf_p7, messageHeader.phy_id); - - if(phy) - { - vnf_p7_rx_message_t* rx_msg = vnf_p7_rx_reassembly_queue_add_segment(vnf_p7, &(phy->reassembly_queue), sequence_num, segment_num, m, pRecvMsg, recvMsgLen); - - if(rx_msg->num_segments_received == rx_msg->num_segments_expected) - { - // send the buffer on - uint16_t i = 0; - uint16_t length = 0; - for(i = 0; i < rx_msg->num_segments_expected; ++i) - { - length += rx_msg->segments[i].length - (i > 0 ? NFAPI_NR_P7_HEADER_LENGTH : 0); - } - - if(phy->reassembly_buffer_size < length) - { - vnf_p7_free(vnf_p7, phy->reassembly_buffer); - phy->reassembly_buffer = 0; - } - - if(phy->reassembly_buffer == 0) - { - NFAPI_TRACE(NFAPI_TRACE_NOTE, "Resizing VNF_P7 Reassembly buffer %d->%d\n", phy->reassembly_buffer_size, length); - phy->reassembly_buffer = (uint8_t*)vnf_p7_malloc(vnf_p7, length); - - if(phy->reassembly_buffer == 0) - { - NFAPI_TRACE(NFAPI_TRACE_NOTE, "Failed to allocate VNF_P7 reassemby buffer len:%d\n", length); - return; - } - memset(phy->reassembly_buffer, 0, length); - phy->reassembly_buffer_size = length; - } - - uint16_t offset = 0; - for(i = 0; i < rx_msg->num_segments_expected; ++i) - { - if(i == 0) - { - memcpy(phy->reassembly_buffer, rx_msg->segments[i].buffer, rx_msg->segments[i].length); - offset += rx_msg->segments[i].length; - } - else - { - memcpy(phy->reassembly_buffer + offset, rx_msg->segments[i].buffer + NFAPI_NR_P7_HEADER_LENGTH, rx_msg->segments[i].length - NFAPI_NR_P7_HEADER_LENGTH); - offset += rx_msg->segments[i].length - NFAPI_NR_P7_HEADER_LENGTH; - } - } - - - //pnf_dispatch_p7_message(pnf_p7->reassemby_buffer, length, pnf_p7, rx_msg->rx_hr_time); - vnf_nr_dispatch_p7_message(phy->reassembly_buffer, length , vnf_p7); - - - // delete the structure - vnf_p7_rx_reassembly_queue_remove_msg(vnf_p7, &(phy->reassembly_queue), rx_msg); - } - - // see corresponding comment in pnf_nr_handle_p7_message() [same commit] - vnf_p7_rx_reassembly_queue_remove_old_msgs(vnf_p7, &(phy->reassembly_queue), 10000); - } - else - { - - NFAPI_TRACE(NFAPI_TRACE_INFO, "Unknown phy id %d\n", messageHeader.phy_id); - } - } -} - -int vnf_nr_p7_read_dispatch_message(vnf_p7_t* vnf_p7) -{ - int recvfrom_result = 0; - struct sockaddr_in remote_addr; - socklen_t remote_addr_size = sizeof(remote_addr); - - do - { - // peek the header - uint8_t header_buffer[NFAPI_NR_P7_HEADER_LENGTH]; - recvfrom_result = recvfrom(vnf_p7->socket, header_buffer, NFAPI_NR_P7_HEADER_LENGTH, MSG_DONTWAIT | MSG_PEEK, (struct sockaddr*)&remote_addr, &remote_addr_size); - - if(recvfrom_result > 0) - { - // get the segment size - nfapi_nr_p7_message_header_t header; - if(nfapi_nr_p7_message_header_unpack(header_buffer, NFAPI_NR_P7_HEADER_LENGTH, &header, sizeof(header), 0) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unpack message header failed, ignoring\n"); - return -1; - } - - // resize the buffer if we have a large segment - if(header.message_length > vnf_p7->rx_message_buffer_size) - { - NFAPI_TRACE(NFAPI_TRACE_NOTE, "reallocing rx buffer %d\n", header.message_length); - vnf_p7->rx_message_buffer = realloc(vnf_p7->rx_message_buffer, header.message_length); - vnf_p7->rx_message_buffer_size = header.message_length; - } - - // read the segment - recvfrom_result = recvfrom(vnf_p7->socket, vnf_p7->rx_message_buffer, header.message_length, MSG_WAITALL | MSG_TRUNC, (struct sockaddr*)&remote_addr, &remote_addr_size); - NFAPI_TRACE(NFAPI_TRACE_DEBUG, "recvfrom_result = %d from %s():%d\n", recvfrom_result, __FUNCTION__, __LINE__); - - // todo : how to handle incomplete readfroms, need some sort of buffer/select - - if (recvfrom_result > 0) - { - if (recvfrom_result != header.message_length) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "(%d) Received unexpected number of bytes. %d != %d", - __LINE__, recvfrom_result, header.message_length); - break; - } - NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Calling vnf_nr_handle_p7_message from %d\n", __LINE__); - vnf_nr_handle_p7_message(vnf_p7->rx_message_buffer, recvfrom_result, vnf_p7); - return 0; - } - else - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "recvfrom failed %d %d\n", recvfrom_result, errno); - } - } - - if(recvfrom_result == -1) - { - if(errno == EAGAIN || errno == EWOULDBLOCK) - { - // return to the select - //NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom would block :%d\n", __FUNCTION__, errno); - } - else - { - NFAPI_TRACE(NFAPI_TRACE_WARN, "%s recvfrom failed errno:%d\n", __FUNCTION__, errno); - } - } - } - while(recvfrom_result > 0); - - return 0; -} int vnf_p7_read_dispatch_message(vnf_p7_t* vnf_p7) { @@ -2652,7 +2371,7 @@ int vnf_p7_read_dispatch_message(vnf_p7_t* vnf_p7) __LINE__, recvfrom_result, header.message_length); break; } - NFAPI_TRACE(NFAPI_TRACE_INFO, "Calling vnf_nr_handle_p7_message from %d\n", __LINE__); + NFAPI_TRACE(NFAPI_TRACE_INFO, "Calling vnf_nr_reassemble_p7_message from %d\n", __LINE__); vnf_handle_p7_message(vnf_p7->rx_message_buffer, recvfrom_result, vnf_p7); return 0; } diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c b/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c index d3160f4e30..225b0b7d8c 100644 --- a/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c +++ b/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c @@ -30,7 +30,7 @@ #include "common/ran_context.h" #include "openair1/PHY/defs_gNB.h" -#define FAPI2_IP_DSCP 0 + extern RAN_CONTEXT_t RC; @@ -96,115 +96,6 @@ struct timespec timespec_sub(struct timespec lhs, struct timespec rhs) // monitor the p7 endpoints and the timing loop and // send indications to mac -int nfapi_nr_vnf_p7_start(nfapi_vnf_p7_config_t* config) -{ - if(config == 0) - return -1; - - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); - - vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; - - // Create p7 receive udp port - // todo : this needs updating for Ipv6 - - NFAPI_TRACE(NFAPI_TRACE_INFO, "Initialising VNF P7 port:%u\n", config->port); - - // open the UDP socket - if ((vnf_p7->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After P7 socket errno: %d\n", errno); - return -1; - } - - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 socket created...\n"); - - // configure the UDP socket options - int iptos_value = FAPI2_IP_DSCP << 2; - if (setsockopt(vnf_p7->socket, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (IP_TOS) errno: %d\n", errno); - return -1; - } - - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 setsockopt succeeded...\n"); - - // Create the address structure - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(config->port); - addr.sin_addr.s_addr = INADDR_ANY; - - // bind to the configured port - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 binding too %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); - if (bind(vnf_p7->socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) - //if (sctp_bindx(config->socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), 0) < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "After bind errno: %d\n", errno); - return -1; - } - - NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 bind succeeded...\n"); - - - //struct timespec original_pselect_timeout; - struct timespec pselect_timeout; - pselect_timeout.tv_sec = 100; - pselect_timeout.tv_nsec = 0; - - struct timespec ref_time; - clock_gettime(CLOCK_MONOTONIC, &ref_time); - while(vnf_p7->terminate == 0) - { - fd_set rfds; - int maxSock = 0; - FD_ZERO(&rfds); - int selectRetval = 0; - - // Add the p7 socket - FD_SET(vnf_p7->socket, &rfds); - maxSock = vnf_p7->socket; - - selectRetval = pselect(maxSock+1, &rfds, NULL, NULL, &pselect_timeout, NULL); - - if(selectRetval == 0) - { - // pselect timed out, continue - } - else if(selectRetval > 0) - { - // have a p7 message - if(FD_ISSET(vnf_p7->socket, &rfds)) - { - vnf_nr_p7_read_dispatch_message(vnf_p7); - } - } - else - { - // pselect error - if(selectRetval == -1 && errno == EINTR) - { - // a sigal was received. - } - else - { - //NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%d.%d orginal:%d.%d last_ms:%ld ms:%ld\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, last_millisecond, millisecond); - // should we exit now? - if (selectRetval == -1 && errno == 22) // invalid argument??? not sure about timeout duration - { - usleep(100000); - } - } - } - } - NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p7 socket\n"); - close(vnf_p7->socket); - - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() returning\n", __FUNCTION__); - - return 0; -} int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) @@ -231,7 +122,7 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config) NFAPI_TRACE(NFAPI_TRACE_INFO, "VNF P7 socket created...\n"); // configure the UDP socket options - int iptos_value = FAPI2_IP_DSCP << 2; + int iptos_value = 0; if (setsockopt(vnf_p7->socket, IPPROTO_IP, IP_TOS, &iptos_value, sizeof(iptos_value)) < 0) { NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (IP_TOS) errno: %d\n", errno); @@ -559,12 +450,12 @@ int nfapi_vnf_p7_add_pnf(nfapi_vnf_p7_config_t* config, const char* pnf_p7_addr, node->slot = 0; node->min_sync_cycle_count = 8; node->mu = mu; - +#ifndef ENABLE_AERIAL // save the remote endpoint information node->remote_addr.sin_family = AF_INET; node->remote_addr.sin_port = pnf_p7_port;//htons(pnf_p7_port); node->remote_addr.sin_addr.s_addr = inet_addr(pnf_p7_addr); - +#endif vnf_p7_connection_info_list_add(vnf_p7, node); return 0; @@ -600,7 +491,7 @@ int nfapi_vnf_p7_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_dl_config_re return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header); } -int nfapi_vnf_p7_nr_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_nr_dl_tti_request_t* req) +bool nfapi_vnf_p7_nr_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_nr_dl_tti_request_t* req) { //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(config:%p req:%p)\n", __FUNCTION__, config, req); @@ -608,15 +499,17 @@ int nfapi_vnf_p7_nr_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_nr_dl_tti return -1; vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; - return vnf_nr_p7_pack_and_send_p7_msg(vnf_p7, &req->header); + AssertFatal(config->send_p7_msg, "Function pointer must be configured|"); + return config->send_p7_msg(vnf_p7, &req->header); } -int nfapi_vnf_p7_ul_tti_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_tti_request_t* req) +bool nfapi_vnf_p7_ul_tti_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_tti_request_t* req) { if(config == 0 || req == 0) return -1; vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; - return vnf_nr_p7_pack_and_send_p7_msg(vnf_p7, &req->header); + AssertFatal(config->send_p7_msg, "Function pointer must be configured|"); + return config->send_p7_msg(vnf_p7, &req->header); } int nfapi_vnf_p7_ul_config_req(nfapi_vnf_p7_config_t* config, nfapi_ul_config_request_t* req) @@ -627,13 +520,14 @@ int nfapi_vnf_p7_ul_config_req(nfapi_vnf_p7_config_t* config, nfapi_ul_config_re vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header); } -int nfapi_vnf_p7_ul_dci_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_dci_request_t* req) +bool nfapi_vnf_p7_ul_dci_req(nfapi_vnf_p7_config_t* config, nfapi_nr_ul_dci_request_t* req) { if(config == 0 || req == 0) return -1; vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; - return vnf_nr_p7_pack_and_send_p7_msg(vnf_p7, &req->header); + AssertFatal(config->send_p7_msg, "Function pointer must be configured|"); + return config->send_p7_msg(vnf_p7, &req->header); } int nfapi_vnf_p7_hi_dci0_req(nfapi_vnf_p7_config_t* config, nfapi_hi_dci0_request_t* req) { @@ -643,13 +537,14 @@ int nfapi_vnf_p7_hi_dci0_req(nfapi_vnf_p7_config_t* config, nfapi_hi_dci0_reques vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header); } -int nfapi_vnf_p7_tx_data_req(nfapi_vnf_p7_config_t* config, nfapi_nr_tx_data_request_t* req) +bool nfapi_vnf_p7_tx_data_req(nfapi_vnf_p7_config_t* config, nfapi_nr_tx_data_request_t* req) { if(config == 0 || req == 0) return -1; vnf_p7_t* vnf_p7 = (vnf_p7_t*)config; - return vnf_nr_p7_pack_and_send_p7_msg(vnf_p7, &req->header); + AssertFatal(config->send_p7_msg, "Function pointer must be configured|"); + return config->send_p7_msg(vnf_p7, &req->header); } int nfapi_vnf_p7_tx_req(nfapi_vnf_p7_config_t* config, nfapi_tx_request_t* req) { diff --git a/nfapi/tests/p5/nr_fapi_config_request_test.c b/nfapi/tests/p5/nr_fapi_config_request_test.c index 93ff5b5f3a..5a80a89f3d 100644 --- a/nfapi/tests/p5/nr_fapi_config_request_test.c +++ b/nfapi/tests/p5/nr_fapi_config_request_test.c @@ -206,6 +206,47 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap FILL_TLV(nfapi_resp->measurement_config.rssi_measurement, NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, rand8()); nfapi_resp->num_tlv++; + uint16_t nb_beams = rand16_range(1, 15); + uint16_t nb_tx = rand16_range(1, 15); + nfapi_resp->dbt_config.num_dig_beams = nb_beams; + if (nfapi_resp->dbt_config.num_dig_beams > 0) { + nfapi_resp->dbt_config.num_txrus = nb_tx; + nfapi_resp->dbt_config.dig_beam_list = calloc(nb_beams , sizeof(*nfapi_resp->dbt_config.dig_beam_list)); + for (int i = 0; i < nb_beams; i++) { + nfapi_nr_dig_beam_t *beam = &nfapi_resp->dbt_config.dig_beam_list[i]; + beam->beam_idx = i; + beam->txru_list = calloc(nb_tx , sizeof(*beam->txru_list)); + for (int j = 0; j < nb_tx; j++) { + nfapi_nr_txru_t *txru = &beam->txru_list[j]; + txru->dig_beam_weight_Re = rand16_range(1, 0xffff); + txru->dig_beam_weight_Im = rand16_range(1, 0xffff); + } + } + nfapi_resp->num_tlv++; + } + + nfapi_nr_pm_list_t *pm_list = &nfapi_resp->pmi_list; + const uint16_t num_layers = rand16_range(1, 4); + const uint16_t num_ant_ports = rand16_range(1, 4); + pm_list->num_pm_idx = rand16_range(1, 4); + if (nfapi_resp->pmi_list.num_pm_idx > 0) { + pm_list->pmi_pdu = calloc(pm_list->num_pm_idx, sizeof(*pm_list->pmi_pdu)); + for (int i = 0; i < pm_list->num_pm_idx; i++) { + nfapi_nr_pm_pdu_t *pmi_pdu = &pm_list->pmi_pdu[i]; + pmi_pdu->pm_idx = i+1; + pmi_pdu->numLayers = num_layers; + pmi_pdu->num_ant_ports = num_ant_ports; + for (int j = 0; j < num_layers; j++) { + for (int k = 0; k < num_ant_ports; k++) { + nfapi_nr_pm_weights_t* pm_weight = &pmi_pdu->weights[j][k]; + pm_weight->r = (int16_t)rand16_range(1, 0xffff); + pm_weight->i = (int16_t)rand16_range(1, 0xffff); + } + } + } + nfapi_resp->num_tlv++; + } + nfapi_resp->nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; for (int i = 0; i < NFAPI_IPV4_ADDRESS_LENGTH; ++i) { nfapi_resp->nfapi_config.p7_vnf_address_ipv4.address[i] = rand8(); @@ -221,6 +262,21 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap FILL_TLV(nfapi_resp->nfapi_config.p7_vnf_port, NFAPI_NR_NFAPI_P7_VNF_PORT_TAG, rand16()); nfapi_resp->num_tlv++; + nfapi_resp->nfapi_config.p7_pnf_address_ipv4.tl.tag = NFAPI_NR_NFAPI_P7_PNF_ADDRESS_IPV4_TAG; + for (int i = 0; i < NFAPI_IPV4_ADDRESS_LENGTH; ++i) { + nfapi_resp->nfapi_config.p7_pnf_address_ipv4.address[i] = rand8(); + } + nfapi_resp->num_tlv++; + + nfapi_resp->nfapi_config.p7_pnf_address_ipv6.tl.tag = NFAPI_NR_NFAPI_P7_PNF_ADDRESS_IPV6_TAG; + for (int i = 0; i < NFAPI_IPV6_ADDRESS_LENGTH; ++i) { + nfapi_resp->nfapi_config.p7_pnf_address_ipv6.address[i] = rand8(); + } + nfapi_resp->num_tlv++; + + FILL_TLV(nfapi_resp->nfapi_config.p7_pnf_port, NFAPI_NR_NFAPI_P7_PNF_PORT_TAG, rand16()); + nfapi_resp->num_tlv++; + FILL_TLV(nfapi_resp->nfapi_config.timing_window, NFAPI_NR_NFAPI_TIMING_WINDOW_TAG, rand8()); nfapi_resp->num_tlv++; @@ -278,7 +334,7 @@ static void test_pack_unpack(nfapi_nr_config_request_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p5/nr_fapi_config_response_test.c b/nfapi/tests/p5/nr_fapi_config_response_test.c index bc44b4b6fd..36a6389c0c 100644 --- a/nfapi/tests/p5/nr_fapi_config_response_test.c +++ b/nfapi/tests/p5/nr_fapi_config_response_test.c @@ -92,7 +92,7 @@ void test_pack_unpack(nfapi_nr_config_response_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p5/nr_fapi_error_indication_test.c b/nfapi/tests/p5/nr_fapi_error_indication_test.c index 85ef17b536..772b9bccea 100644 --- a/nfapi/tests/p5/nr_fapi_error_indication_test.c +++ b/nfapi/tests/p5/nr_fapi_error_indication_test.c @@ -40,7 +40,7 @@ void test_pack_unpack(nfapi_nr_error_indication_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p5/nr_fapi_param_request_test.c b/nfapi/tests/p5/nr_fapi_param_request_test.c index d42717eaeb..0af3fd9633 100644 --- a/nfapi/tests/p5/nr_fapi_param_request_test.c +++ b/nfapi/tests/p5/nr_fapi_param_request_test.c @@ -41,7 +41,7 @@ void test_pack_unpack(nfapi_nr_param_request_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p5/nr_fapi_param_response_test.c b/nfapi/tests/p5/nr_fapi_param_response_test.c index 1ba14c1655..e94e805bcb 100644 --- a/nfapi/tests/p5/nr_fapi_param_response_test.c +++ b/nfapi/tests/p5/nr_fapi_param_response_test.c @@ -233,7 +233,7 @@ void test_pack_unpack(nfapi_nr_param_response_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p5/nr_fapi_start_request_test.c b/nfapi/tests/p5/nr_fapi_start_request_test.c index 9a36528db6..d908fbe023 100644 --- a/nfapi/tests/p5/nr_fapi_start_request_test.c +++ b/nfapi/tests/p5/nr_fapi_start_request_test.c @@ -41,7 +41,7 @@ void test_pack_unpack(nfapi_nr_start_request_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p5/nr_fapi_start_response_test.c b/nfapi/tests/p5/nr_fapi_start_response_test.c index bb3a096734..9d9423de83 100644 --- a/nfapi/tests/p5/nr_fapi_start_response_test.c +++ b/nfapi/tests/p5/nr_fapi_start_response_test.c @@ -41,7 +41,7 @@ void test_pack_unpack(nfapi_nr_start_response_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p5/nr_fapi_stop_indication_test.c b/nfapi/tests/p5/nr_fapi_stop_indication_test.c index 4b5d9d4319..e4205d982c 100644 --- a/nfapi/tests/p5/nr_fapi_stop_indication_test.c +++ b/nfapi/tests/p5/nr_fapi_stop_indication_test.c @@ -41,7 +41,7 @@ void test_pack_unpack(nfapi_nr_stop_indication_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p5/nr_fapi_stop_request_test.c b/nfapi/tests/p5/nr_fapi_stop_request_test.c index 74e5ea31ff..3536ad2272 100644 --- a/nfapi/tests/p5/nr_fapi_stop_request_test.c +++ b/nfapi/tests/p5/nr_fapi_stop_request_test.c @@ -41,7 +41,7 @@ void test_pack_unpack(nfapi_nr_stop_request_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_crc_indication_test.c b/nfapi/tests/p7/nr_fapi_crc_indication_test.c index 472959b0d6..71bb8eca1b 100644 --- a/nfapi/tests/p7/nr_fapi_crc_indication_test.c +++ b/nfapi/tests/p7/nr_fapi_crc_indication_test.c @@ -72,7 +72,7 @@ static void test_pack_unpack(nfapi_nr_crc_indication_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_dl_tti_request_test.c b/nfapi/tests/p7/nr_fapi_dl_tti_request_test.c index 2cc95260f0..599a3b85a5 100644 --- a/nfapi/tests/p7/nr_fapi_dl_tti_request_test.c +++ b/nfapi/tests/p7/nr_fapi_dl_tti_request_test.c @@ -241,7 +241,7 @@ static void test_pack_unpack(nfapi_nr_dl_tti_request_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_rach_indication_test.c b/nfapi/tests/p7/nr_fapi_rach_indication_test.c index fd4a0fac32..83f569a7d1 100644 --- a/nfapi/tests/p7/nr_fapi_rach_indication_test.c +++ b/nfapi/tests/p7/nr_fapi_rach_indication_test.c @@ -71,7 +71,7 @@ static void test_pack_unpack(nfapi_nr_rach_indication_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_rx_data_indication_test.c b/nfapi/tests/p7/nr_fapi_rx_data_indication_test.c index 2f382cf797..18445a0ee2 100644 --- a/nfapi/tests/p7/nr_fapi_rx_data_indication_test.c +++ b/nfapi/tests/p7/nr_fapi_rx_data_indication_test.c @@ -69,7 +69,7 @@ static void test_pack_unpack(nfapi_nr_rx_data_indication_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_slot_indication_test.c b/nfapi/tests/p7/nr_fapi_slot_indication_test.c index 96c030479c..414b52332f 100644 --- a/nfapi/tests/p7/nr_fapi_slot_indication_test.c +++ b/nfapi/tests/p7/nr_fapi_slot_indication_test.c @@ -47,7 +47,7 @@ static void test_pack_unpack(nfapi_nr_slot_indication_scf_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_srs_indication_test.c b/nfapi/tests/p7/nr_fapi_srs_indication_test.c index 1271606b77..363aa43962 100644 --- a/nfapi/tests/p7/nr_fapi_srs_indication_test.c +++ b/nfapi/tests/p7/nr_fapi_srs_indication_test.c @@ -78,7 +78,7 @@ static void test_pack_unpack(nfapi_nr_srs_indication_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_tx_data_request_test.c b/nfapi/tests/p7/nr_fapi_tx_data_request_test.c index e67b5bf3ca..660c514b9c 100644 --- a/nfapi/tests/p7/nr_fapi_tx_data_request_test.c +++ b/nfapi/tests/p7/nr_fapi_tx_data_request_test.c @@ -132,7 +132,7 @@ static void test_pack_unpack(nfapi_nr_tx_data_request_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_uci_indication_test.c b/nfapi/tests/p7/nr_fapi_uci_indication_test.c index 9e2dcda6be..53f8469325 100644 --- a/nfapi/tests/p7/nr_fapi_uci_indication_test.c +++ b/nfapi/tests/p7/nr_fapi_uci_indication_test.c @@ -199,7 +199,7 @@ static void test_pack_unpack(nfapi_nr_uci_indication_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_ul_dci_request_test.c b/nfapi/tests/p7/nr_fapi_ul_dci_request_test.c index b1bc910da8..709c1c9db9 100644 --- a/nfapi/tests/p7/nr_fapi_ul_dci_request_test.c +++ b/nfapi/tests/p7/nr_fapi_ul_dci_request_test.c @@ -103,7 +103,7 @@ static void test_pack_unpack(nfapi_nr_ul_dci_request_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/nfapi/tests/p7/nr_fapi_ul_tti_request_test.c b/nfapi/tests/p7/nr_fapi_ul_tti_request_test.c index 4f65cbfc9e..f7087c92ef 100644 --- a/nfapi/tests/p7/nr_fapi_ul_tti_request_test.c +++ b/nfapi/tests/p7/nr_fapi_ul_tti_request_test.c @@ -422,7 +422,7 @@ static void test_pack_unpack(nfapi_nr_ul_tti_request_t *req) header_buffer[idx] = msg_buf[idx]; } uint8_t *pReadPackedMessage = header_buffer; - int unpack_header_result = fapi_nr_message_header_unpack(&pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); + int unpack_header_result = fapi_nr_p7_message_header_unpack(pReadPackedMessage, NFAPI_HEADER_LENGTH, &header, sizeof(header), 0); DevAssert(unpack_header_result >= 0); DevAssert(header.message_id == req->header.message_id); DevAssert(header.message_length == req->header.message_length); diff --git a/openair1/CMakeLists.txt b/openair1/CMakeLists.txt index 1ce6debaf1..123d723342 100644 --- a/openair1/CMakeLists.txt +++ b/openair1/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(PHY) +add_subdirectory(SIMULATION) diff --git a/openair1/PHY/CMakeLists.txt b/openair1/PHY/CMakeLists.txt index 2d74e9aedc..83e7dc0530 100644 --- a/openair1/PHY/CMakeLists.txt +++ b/openair1/PHY/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(nr_phy_common) add_subdirectory(TOOLS) add_subdirectory(NR_TRANSPORT) add_subdirectory(CODING) +add_subdirectory(MODULATION) diff --git a/openair1/PHY/CODING/3gpplte.c b/openair1/PHY/CODING/3gpplte.c index 49740487ac..d3aec284da 100644 --- a/openair1/PHY/CODING/3gpplte.c +++ b/openair1/PHY/CODING/3gpplte.c @@ -30,6 +30,7 @@ #include #include #include "PHY/CODING/coding_defs.h" +#include "common/utils/utils.h" //#define DEBUG_TURBO_ENCODER 1 @@ -450,7 +451,7 @@ t_interleaver_codebook *f1f2mat; short *il_tb; __attribute__((constructor)) static void init_interleaver(void) { int totSize=0; - f1f2mat=(t_interleaver_codebook*) malloc(sizeof(*f1f2mat) * sizeof(f1f2) / sizeof(*f1f2)); + f1f2mat = malloc_or_fail(sizeof(*f1f2mat) * sizeof(f1f2) / sizeof(*f1f2)); for (int i=0; i < sizeof(f1f2)/sizeof(*f1f2) ; i++) { f1f2mat[i].nb_bits=f1f2[i].nb_bits; f1f2mat[i].f1=f1f2[i].f1; @@ -458,7 +459,7 @@ __attribute__((constructor)) static void init_interleaver(void) { f1f2mat[i].beg_index=totSize; totSize+=f1f2mat[i].nb_bits; } - il_tb=(short*)malloc(sizeof(*il_tb)*totSize); + il_tb = malloc_or_fail(sizeof(*il_tb) * totSize); int idx=0; for (int i=0; i < sizeof(f1f2)/sizeof(*f1f2) ; i++) for (uint64_t j=0; j> 4), simde_mm_extract_epi8(beta_ptr[0], 0), simde_mm_extract_epi8(beta_ptr[0], 1), @@ -1403,7 +1403,7 @@ void compute_beta(llr_t *alpha,llr_t *beta,llr_t *m_11,llr_t *m_10,unsigned shor simde_mm_extract_epi8(beta_ptr[0], 13), simde_mm_extract_epi8(beta_ptr[0], 14), simde_mm_extract_epi8(beta_ptr[0], 15)); - printf("beta1 %u: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", + printf("beta1 %d: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", (frame_length >> 4), simde_mm_extract_epi8(beta_ptr[1], 0), simde_mm_extract_epi8(beta_ptr[1], 1), @@ -1421,7 +1421,7 @@ void compute_beta(llr_t *alpha,llr_t *beta,llr_t *m_11,llr_t *m_10,unsigned shor simde_mm_extract_epi8(beta_ptr[1], 13), simde_mm_extract_epi8(beta_ptr[1], 14), simde_mm_extract_epi8(beta_ptr[1], 15)); - printf("beta2 %u: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", + printf("beta2 %d: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", (frame_length >> 4), simde_mm_extract_epi8(beta_ptr[2], 0), simde_mm_extract_epi8(beta_ptr[2], 1), @@ -1439,7 +1439,7 @@ void compute_beta(llr_t *alpha,llr_t *beta,llr_t *m_11,llr_t *m_10,unsigned shor simde_mm_extract_epi8(beta_ptr[2], 13), simde_mm_extract_epi8(beta_ptr[2], 14), simde_mm_extract_epi8(beta_ptr[2], 15)); - printf("beta3 %u: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", + printf("beta3 %d: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", (frame_length >> 4), simde_mm_extract_epi8(beta_ptr[3], 0), simde_mm_extract_epi8(beta_ptr[3], 1), @@ -1457,7 +1457,7 @@ void compute_beta(llr_t *alpha,llr_t *beta,llr_t *m_11,llr_t *m_10,unsigned shor simde_mm_extract_epi8(beta_ptr[3], 13), simde_mm_extract_epi8(beta_ptr[3], 14), simde_mm_extract_epi8(beta_ptr[3], 15)); - printf("beta4 %u: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", + printf("beta4 %d: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", (frame_length >> 4), simde_mm_extract_epi8(beta_ptr[4], 0), simde_mm_extract_epi8(beta_ptr[4], 1), @@ -1475,7 +1475,7 @@ void compute_beta(llr_t *alpha,llr_t *beta,llr_t *m_11,llr_t *m_10,unsigned shor simde_mm_extract_epi8(beta_ptr[4], 13), simde_mm_extract_epi8(beta_ptr[4], 14), simde_mm_extract_epi8(beta_ptr[4], 15)); - printf("beta5 %u: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", + printf("beta5 %d: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", (frame_length >> 4), simde_mm_extract_epi8(beta_ptr[5], 0), simde_mm_extract_epi8(beta_ptr[5], 1), @@ -1493,7 +1493,7 @@ void compute_beta(llr_t *alpha,llr_t *beta,llr_t *m_11,llr_t *m_10,unsigned shor simde_mm_extract_epi8(beta_ptr[5], 13), simde_mm_extract_epi8(beta_ptr[5], 14), simde_mm_extract_epi8(beta_ptr[5], 15)); - printf("beta6 %u: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", + printf("beta6 %d: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", (frame_length >> 4), simde_mm_extract_epi8(beta_ptr[6], 0), simde_mm_extract_epi8(beta_ptr[6], 1), @@ -1511,7 +1511,7 @@ void compute_beta(llr_t *alpha,llr_t *beta,llr_t *m_11,llr_t *m_10,unsigned shor simde_mm_extract_epi8(beta_ptr[6], 13), simde_mm_extract_epi8(beta_ptr[6], 14), simde_mm_extract_epi8(beta_ptr[6], 15)); - printf("beta7 %u: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", + printf("beta7 %d: %03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d,%03d\n", (frame_length >> 4), simde_mm_extract_epi8(beta_ptr[7], 0), simde_mm_extract_epi8(beta_ptr[7], 1), diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c index 12cbe867a4..5a80f04a21 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_16bit.c @@ -997,7 +997,7 @@ uint8_t phy_threegpplte_turbo_decoder16(int16_t *y, #elif defined(__arm__) || defined(__aarch64__) int16x8_t *yp128; // int16x8_t tmp128[(n+8)>>3]; - int16x8_t tmp, zeros=vdupq_n_s16(0); + int16x8_t tmp = {}, zeros = {}; const uint16_t __attribute__ ((aligned (16))) _Powers[8]= { 1, 2, 4, 8, 16, 32, 64, 128}; uint16x8_t Powers= vld1q_u16(_Powers); diff --git a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c index 0180bed149..63ec8ade8e 100644 --- a/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c +++ b/openair1/PHY/CODING/3gpplte_turbo_decoder_sse_8bit.c @@ -930,7 +930,7 @@ uint8_t phy_threegpplte_turbo_decoder8(int16_t *y, #elif defined(__arm__) || defined(__aarch64__) int8x16_t *yp128; int8x16_t tmp128[(n+8)>>3]; - int8x16_t tmp, zeros=vdupq_n_s8(0); + int8x16_t tmp = {}, zeros = {}; const uint8_t __attribute__ ((aligned (16))) _Powers[16]= { 1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128 }; // Set the powers of 2 (do it once for all, if applicable) diff --git a/openair1/PHY/CODING/CMakeLists.txt b/openair1/PHY/CODING/CMakeLists.txt index e31857a4d5..f696c71213 100644 --- a/openair1/PHY/CODING/CMakeLists.txt +++ b/openair1/PHY/CODING/CMakeLists.txt @@ -7,7 +7,6 @@ add_library(coding MODULE 3gpplte_turbo_decoder.c ) set_target_properties(coding PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -#ensure that the T header files are generated before targets depending on them target_link_libraries(coding PRIVATE log_headers) add_library(ldpc_orig MODULE @@ -32,19 +31,6 @@ add_dependencies(nr_ulschsim ldpc ldpc_orig) add_dependencies(nr_dlsim ldpc ldpc_orig) add_dependencies(nr_dlschsim ldpc ldpc_orig) -add_custom_target(nrLDPC_decoder_kernels_CL - COMMAND gcc nrLDPC_decoder/nrLDPC_decoder_CL.c -dD -DNRLDPC_KERNEL_SOURCE -E -o ${CMAKE_CURRENT_BINARY_DIR}/nrLDPC_decoder_kernels_CL.clc - SOURCES nrLDPC_decoder/nrLDPC_decoder_CL.c - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -) -add_library(ldpc_cl MODULE - nrLDPC_decoder/nrLDPC_decoder_CL.c - nrLDPC_encoder/ldpc_encoder_optim8segmulti.c -) -set_target_properties(ldpc_cl PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(ldpc_cl PRIVATE ldpc_segment OpenCL) -add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL) - ############################################## # Base CUDA setting ############################################## @@ -81,7 +67,4 @@ if (ENABLE_LDPC_CUDA) endif() add_subdirectory(nrLDPC_coding) - -if(ENABLE_PHYSIM_TESTS) - add_subdirectory(tests) -endif() +add_subdirectory(nrLDPC_decoder) diff --git a/openair1/PHY/CODING/DOC/LDPCImplementation.md b/openair1/PHY/CODING/DOC/LDPCImplementation.md index 325b208a64..0e4a630f4b 100644 --- a/openair1/PHY/CODING/DOC/LDPCImplementation.md +++ b/openair1/PHY/CODING/DOC/LDPCImplementation.md @@ -1,6 +1,10 @@ # LDPC coding implementation +This document gives an overview of the different LDPC coding implementations (functional or not) available with Open Air Interface. + +[[_TOC_]] + The LDPC encoder and decoder are implemented in a shared library, dynamically loaded at run-time using the [oai shared library loader](file://../../../../common/utils/DOC/loader.md). -Two types of library are available with two different interfaces. There are libraries implementing the encoder and decoder of code segments and libraries implementing the encoder and decoder of slots. +Two types of library are available with two different interfaces. There are libraries implementing the encoder and decoder of slots and libraries implementing the encoder and decoder of code segments. ## LDPC slot coding The interface of the library is defined in [nrLDPC_coding_interface.h](file://../nrLDPC_coding/nrLDPC_coding_interface.h). @@ -17,46 +21,31 @@ loading default `libldpc.so`: ``` ./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 -....................... -[CONFIG] loader.ldpc.shlibversion set to default value "" -[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (2 to default value) -shlib_path libldpc.so -[LOADER] library libldpc.so successfully loaded -........................ ``` `libldpc.so` has its decoder implemented in [nrLDPC_coding_segment_decoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c).\ Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c). -loading `libldpc_t2.so` instead of `libldpc.so`: +loading `libldpc_aal.so` instead of `libldpc.so`: -`make ldpc_t2` +`make ldpc_aal` -This command creates the `libldpc_t2.so` shared library. +This command creates the `libldpc_aal.so` shared library. ``` -Building C object CMakeFiles/ldpc_t2.dir/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c.o -Linking C shared module libldpc_t2.so +Building C object CMakeFiles/ldpc_aal.dir/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c.o +Linking C shared module libldpc_aal.so ``` -At runtime, to successfully use the T2 board, you need to install vendor specific drivers and tools.\ -Please refer to the dedicated documentation at [LDPC_T2_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_T2_OFFLOAD_SETUP.md). +At runtime, to successfully use LDPC accelerators (e.g., Xilinx T2/Intel ACCs), you will need to install the corresponding drivers and tools. +Please refer to the dedicated documentation at [LDPC_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_OFFLOAD_SETUP.md). -`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _t2 --nrLDPC_coding_t2.dpdk_dev 01:00.0 --nrLDPC_coding_t2.dpdk_core_list 0-1` - -``` - -....................... -[CONFIG] loader.ldpc.shlibversion set to default value "" -[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value) -[CONFIG] shlibversion set to _t2 from command line -[CONFIG] loader.ldpc 1 options set from command line -shlib_path libldpc_t2.so -[LOADER] library libldpc_t2.so successfully loaded -........................ +<<<<<<< HEAD +``` +./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev 01:00.0 --nrLDPC_coding_aal.dpdk_core_list 0-1 ``` -`libldpc_t2.so` has its decoder and its encoder implemented in [nrLDPC_coding_t2.c](file://../nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c). +`libldpc_aal.so` has its decoder and its encoder implemented in [nrLDPC_coding_aal.c](file://../nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c). loading `libldpc_xdma.so` instead of `libldpc.so`: @@ -72,18 +61,9 @@ ninja ldpc_xdma At runtime, to successfully use the xdma, you need to install vendor specific drivers and tools.\ Please refer to the dedicated documentation at [LDPC_XDMA_OFFLOAD_SETUP.md](file://../../../../doc/LDPC_XDMA_OFFLOAD_SETUP.md). -`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2` - -``` -....................... -[CONFIG] loader.ldpc.shlibversion set to default value "" -[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value) -[CONFIG] shlibversion set to _xdma from command line -[CONFIG] loader.ldpc 1 options set from command line -shlib_path libldpc_xdma.so -[LOADER] library libldpc_xdma.so successfully loaded -........................ -``` +``` +./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _xdma --nrLDPC_coding_xdma.num_threads_prepare 2 +``` `libldpc_xdma.so` has its decoder implemented in [nrLDPC_coding_xdma.c](file://../nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c).\ Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c). @@ -103,16 +83,17 @@ Libraries implementing the slotwise LDPC coding must be named `libldpc<_version> `libldpc.so` is completed. -`libldpc_t2.so` is completed. +`libldpc_aal.so` is completed. `libldpc_xdma.so` is completed. ## LDPC segment coding -The interface of the library is defined in [nrLDPC_defs.h](file://../nrLDPC_defs.h). -The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time. +The interface of the library is defined in [nrLDPC_defs.h](file://../nrLDPC_defs.h) as typedefs of the functions of the interface. +The name of the functions implementing these typedefs can be found in [nrLDPC_extern.h](file://../nrLDPC_extern.h). LDPC segment coding libraries are not loaded directly by OAI but are statically linked in libraries implementing the LDPC slot coding interface using an adaptation layer between the slot coding interface and the segment coding interface. -This way, these libraries can be loaded to implement the slot coding interface as well as the segment coding interface in `ldpctest`. +This way, these libraries can be loaded to implement the slot coding interface as well as the segment coding interface in `ldpctest`. +`ldpctest` therefore loads directly the segment coding interface with the loader implemented in [nrLDPC_load.c](file://../nrLDPC_load.c) as function `load_nrLDPClib`. ### Selecting the LDPC library at run time @@ -124,111 +105,6 @@ loading `libldpc_orig.so` instead of `libldpc.so`: ``` ./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --loader.ldpc.shlibversion _orig -....................... -[CONFIG] loader.ldpc.shlibversion set to default value "" -[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value) -[CONFIG] shlibversion set to _orig from command line -[CONFIG] loader.ldpc 1 options set from command line -[LOADER] library libldpc_orig.so successfully loaded -........................ -``` - -loading `libldpc_cl.so` instead of `libldpc.so`: - -`make ldpc_cl` - -This command creates the `libldpc_cl.so` shared library. To perform this build successfully, only the OpenCL header `(/usr/include/CL/opencl.h)` and library `(/usr/lib/x86_64-linux-gnu/libOpenCL.so)`are required, they implement OpenCL API support which is not hardware dependent. - -``` -Scanning dependencies of target nrLDPC_decoder_kernels_CL -Built target nrLDPC_decoder_kernels_CL -Scanning dependencies of target ldpc_cl -Building C object CMakeFiles/ldpc_cl.dir/usr/local/oai/oai-develop/openairinterface5g/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c.o -In file included from /usr/include/CL/cl.h:32, - from /usr/include/CL/opencl.h:38, - from /usr/local/oai/oai-develop/openairinterface5g/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c:49: -/usr/include/CL/cl_version.h:34:9: note: #pragma message: cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 220 (OpenCL 2.2) - #pragma message("cl_version.h: CL_TARGET_OPENCL_VERSION is not defined. Defaulting to 220 (OpenCL 2.2)") - ^~~~~~~ - -Building C object CMakeFiles/ldpc_cl.dir/usr/local/oai/oai-develop/openairinterface5g/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encoder_optim8segmulti.c.o -Linking C shared module libldpc_cl.so -Built target ldpc_cl - -``` - -At runtime, to successfully use hardware acceleration via OpenCL, you need to install vendor specific packages which deliver the required drivers and tools to make use of their GPU (Nvidia, Intel...) , fpga (Xilinx, Intel) or CPU (Intel, AMD, ARM...) through OpenCL. - -`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _cl` - -``` ------------------------------------------------- -[LOADER] library libldpc_cl.so successfully loaded -[HW] Platform 0, OpenCL profile FULL_PROFILE -[HW] Platform 0, OpenCL version OpenCL 2.1 LINUX -[HW] Device 0 is available -[HW] Device 0, type 2 = 0x00000002: cpu -[HW] Device 0, number of Compute Units: 8 -[HW] Device 0, max Work Items dimension: 3 -[HW] Device 0, max Work Items size for dimension: 0 8192 -[HW] Device 0, max Work Items size for dimension: 1 8192 -[HW] Device 0, max Work Items size for dimension: 2 8192 -[New Thread 0x7fffcc258700 (LWP 3945123)] -[New Thread 0x7fffc3e57700 (LWP 3945124)] -[New Thread 0x7fffcbe57700 (LWP 3945125)] -[New Thread 0x7fffcba56700 (LWP 3945126)] -[New Thread 0x7fffcb254700 (LWP 3945128)] -[New Thread 0x7fffcb655700 (LWP 3945127)] -[New Thread 0x7fffcae53700 (LWP 3945129)] -[HW] Platform 1, OpenCL profile FULL_PROFILE -[HW] Platform 1, OpenCL version OpenCL 2.0 beignet 1.3 -[New Thread 0x7fffc965a700 (LWP 3945130)] -[Thread 0x7fffc965a700 (LWP 3945130) exited] -[HW] Device 0 is available -[HW] Device 0, type 4 = 0x00000004: gpu -[HW] Device 0, number of Compute Units: 20 -[HW] Device 0, max Work Items dimension: 3 -[HW] Device 0, max Work Items size for dimension: 0 512 -[HW] Device 0, max Work Items size for dimension: 1 512 -[HW] Device 0, max Work Items size for dimension: 2 512 ------------------------------------------------------------------ -``` - -`./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim -O libconfig:/usr/local/oai/conf/nrue_sim.conf:dbgl5 --loader.ldpc.shlibversion _cl --log_config.hw_log_level info` - -``` -............................................................ -[CONFIG] segment_shlibversion set to _cl from command line -[CONFIG] loader.ldpc 1 options set from command line -[LOADER] library libldpc_cl.so successfully loaded -[HW] Platform 0, OpenCL profile FULL_PROFILE -[HW] Platform 0, OpenCL version OpenCL 2.1 LINUX -[HW] Device 0 is available -[HW] Device 0, type 2 = 0x00000002: cpu -[HW] Device 0, number of Compute Units: 8 -[HW] Device 0, max Work Items dimension: 3 -[HW] Device 0, max Work Items size for dimension: 0 8192 -[HW] Device 0, max Work Items size for dimension: 1 8192 -[HW] Device 0, max Work Items size for dimension: 2 8192 -[New Thread 0x7fffecccc700 (LWP 3945413)] -[New Thread 0x7fffec8cb700 (LWP 3945415)] -[New Thread 0x7fffec4ca700 (LWP 3945414)] -[New Thread 0x7fffdf7fd700 (LWP 3945417)] -[New Thread 0x7fffdfbfe700 (LWP 3945418)] -[New Thread 0x7fffdffff700 (LWP 3945416)] -[New Thread 0x7fffd73fc700 (LWP 3945419)] -[HW] Platform 1, OpenCL profile FULL_PROFILE -[HW] Platform 1, OpenCL version OpenCL 2.0 beignet 1.3 -[New Thread 0x7fffde105700 (LWP 3945420)] -[Thread 0x7fffde105700 (LWP 3945420) exited] -[HW] Device 0 is available -[HW] Device 0, type 4 = 0x00000004: gpu -[HW] Device 0, number of Compute Units: 20 -[HW] Device 0, max Work Items dimension: 3 -[HW] Device 0, max Work Items size for dimension: 0 512 -[HW] Device 0, max Work Items size for dimension: 1 512 -[HW] Device 0, max Work Items size for dimension: 2 512 ------------------------------------------------------------- ``` A mechanism to select ldpc implementation is also available in the `ldpctest` phy simulator via the `-v` option, which can be used to specify the version of the ldpc shared library to be used. @@ -239,74 +115,16 @@ Loading libldpc_cuda.so, the cuda implementation of the ldpc decoder: ``` $ ./ldpctest -v _cuda -ldpctest -v _cuda -Initializing random number generator, seed 0 -block length 8448: -n_trials 1: -SNR0 -2.000000: -[CONFIG] get parameters from cmdline , debug flags: 0x00400000 -[CONFIG] log_config: 2/3 parameters successfully set -[CONFIG] log_config: 53/53 parameters successfully set -[CONFIG] log_config: 53/53 parameters successfully set -[CONFIG] log_config: 16/16 parameters successfully set -[CONFIG] log_config: 16/16 parameters successfully set -log init done -[CONFIG] loader: 2/2 parameters successfully set -[CONFIG] loader.ldpc: 2/2 parameters successfully set -[LOADER] library libldpc_cuda.so successfully loaded -................................... ``` - -Loading libldpc_cl.so, the opencl implementation of the ldpc decoder: - -`make ldpc_cl` - - -``` -$ ./ldpctest -v _cl -Initializing random number generator, seed 0 -block length 8448: -n_trials 1: -SNR0 -2.000000: -[CONFIG] get parameters from cmdline , debug flags: 0x00400000 -[CONFIG] log_config: 2/3 parameters successfully set -[CONFIG] log_config: 53/53 parameters successfully set -[CONFIG] log_config: 53/53 parameters successfully set -[CONFIG] log_config: 16/16 parameters successfully set -[CONFIG] log_config: 16/16 parameters successfully set -log init done -[CONFIG] loader: 2/2 parameters successfully set -[CONFIG] loader.ldpc: 1/2 parameters successfully set -[LOADER] library libldpc_cl.so successfully loaded -[HW] Platform 0, OpenCL profile FULL_PROFILE -[HW] Platform 0, OpenCL version OpenCL 2.1 LINUX -[HW] Device 0 is available -[HW] Device 0, type 2 = 0x00000002: cpu -[HW] Device 0, number of Compute Units: 8 -[HW] Device 0, max Work Items dimension: 3 -[HW] Device 0, max Work Items size for dimension: 0 8192 -[HW] Device 0, max Work Items size for dimension: 1 8192 -[HW] Device 0, max Work Items size for dimension: 2 8192 -[HW] Platform 1, OpenCL profile FULL_PROFILE -[HW] Platform 1, OpenCL version OpenCL 2.0 beignet 1.3 -[HW] Device 0 is available -[HW] Device 0, type 4 = 0x00000004: gpu -[HW] Device 0, number of Compute Units: 20 -[HW] Device 0, max Work Items dimension: 3 -[HW] Device 0, max Work Items size for dimension: 0 512 -[HW] Device 0, max Work Items size for dimension: 1 512 -[HW] Device 0, max Work Items size for dimension: 2 512 -................................ -``` - - - ### LDPC libraries -Libraries implementing the LDPC algorithms must be named `libldpc<_version>.so`, they must implement three functions: `nrLDPC_initcall` `nrLDPC_decod` and `nrLDPC_encod`. The prototypes for these functions is defined in [nrLDPC_defs.h](file://nrLDPC_defs.h). +The prototypes for the functions of the interface are defined in [nrLDPC_defs.h](file://nrLDPC_defs.h) as typedefs. +Libraries implementing the LDPC algorithms must be named `libldpc<_version>.so`, they must implement four functions with the names and types: +* `LDPCinit` implementing type `LDPC_initfunc_t *` +* `LDPCshutdown` implementing type `LDPC_shutdownfunc_t *` +* `LDPCdecoder` implementing type `LDPC_decoderfunc_t *` +* `LDPCencoder` implementing type `LDPC_encoderfunc_t *` -`libldpc_cuda.so`has been tested with the `ldpctest` executable, usage from the softmodem's has to be tested. - -`libldpc_cl.so`is under development. +`libldpc_cuda.so` has been tested with the `ldpctest` executable, usage from the softmodem's has to be tested. [oai Wikis home](https://gitlab.eurecom.fr/oai/openairinterface5g/wikis/home) diff --git a/openair1/PHY/CODING/TESTBENCH/ldpctest.c b/openair1/PHY/CODING/TESTBENCH/ldpctest.c index 0e0493dcc6..97b39beaf8 100644 --- a/openair1/PHY/CODING/TESTBENCH/ldpctest.c +++ b/openair1/PHY/CODING/TESTBENCH/ldpctest.c @@ -352,9 +352,6 @@ one_measurement_t test_ldpc(short max_iterations, set_abort(&dec_abort, false); n_iter = ldpc_toCompare.LDPCdecoder(&decParams[j], - 0, - 0, - 0, (int8_t *)channel_output_fixed[j], (int8_t *)estimated_output[j], &decoder_profiler, diff --git a/openair1/PHY/CODING/coding_defs.h b/openair1/PHY/CODING/coding_defs.h index 3c91892d8c..d6e1b780f7 100644 --- a/openair1/PHY/CODING/coding_defs.h +++ b/openair1/PHY/CODING/coding_defs.h @@ -28,7 +28,7 @@ #define __CODING_DEFS__H__ #include -#include +#include #define CRC24_A 0 #define CRC24_B 1 @@ -455,8 +455,5 @@ int32_t nr_segmentation(unsigned char *input_buffer, */ int nr_get_R_ldpc_decoder(int rvidx, int E, int BG, int Z, int *llrLen, int round); -decoder_if_t phy_threegpplte_turbo_decoder; -decoder_if_t phy_threegpplte_turbo_decoder8; -decoder_if_t phy_threegpplte_turbo_decoder16; /** @} */ #endif diff --git a/openair1/PHY/CODING/nrLDPC_coding/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/CMakeLists.txt index e60ca479bb..356aa5f2a0 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/CMakeLists.txt @@ -1,3 +1,3 @@ add_subdirectory(nrLDPC_coding_segment) add_subdirectory(nrLDPC_coding_xdma) -add_subdirectory(nrLDPC_coding_t2) +add_subdirectory(nrLDPC_coding_aal) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/CMakeLists.txt new file mode 100644 index 0000000000..1bad804fba --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/CMakeLists.txt @@ -0,0 +1,36 @@ +########################################################## +# LDPC offload library - O-RAN AAL/DPDK BBDEV +########################################################## + +add_boolean_option(ENABLE_LDPC_AAL OFF "Build support for LDPC Offload using O-RAN AAL library" OFF) + +if (ENABLE_LDPC_AAL) + pkg_check_modules(LIBDPDK_AAL REQUIRED libdpdk>=20.11.9) + + find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_AAL_LIBRARY_DIRS}) + if (PMD_T2) + message(STATUS "found poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)") + else() + if (LIBDPDK_AAL_VERSION VERSION_LESS "22.11") + message(FATAL_ERROR "for non-T2 BBDEV PMDs, we support the Intel ACC100 and ACC200 (VRB1), using DPDK 22.11 or later.") + endif() + endif() + + add_library(ldpc_aal MODULE nrLDPC_coding_aal.c) + + set_target_properties(ldpc_aal PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") + set_target_properties(ldpc_aal PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + target_include_directories(ldpc_aal PRIVATE ${LIBDPDK_AAL_INCLUDE_DIRS}) + target_link_libraries(ldpc_aal PRIVATE ldpc_gen_HEADERS ${LIBDPDK_AAL_LDFLAGS}) + if (PMD_T2) + target_link_libraries(ldpc_aal PRIVATE ${PMD_T2}) + endif() + + add_dependencies(nr-softmodem ldpc_aal) + add_dependencies(nr-uesoftmodem ldpc_aal) + add_dependencies(nr_ulsim ldpc_aal) + add_dependencies(nr_ulschsim ldpc_aal) + add_dependencies(nr_dlsim ldpc_aal) + add_dependencies(nr_dlschsim ldpc_aal) + +endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/README.md b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/README.md new file mode 100644 index 0000000000..140fff5f1e --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/README.md @@ -0,0 +1,143 @@ +This document highlights some of the key aspects of the implementation for O-RAN AAL/DPDK BBDEV; for user documentation, please consult the [setup guide](../../../../../doc/LDPC_OFFLOAD_SETUP.md) instead. + +## Overview + +The current implementation supports the following BBDEV devices and respective DPDK versions: +- Xilinx T2 on DPDK20.11+ +- Intel ACC100* on DPDK22.11+ +- Intel ACC200 (VRB1) on DPDK22.11+ + +> Important notes: +> - For the Intel ACC100, for DPDK22.11 and DPDK23.11, users are required to [patch](https://github.com/DPDK/dpdk/commit/fdde63a1dfc129d0a510a831aa98253b36a2a1cd) the ACC100's driver. +> - If you intend to use this implementation in an FHI7.2 setup, only the F-release and beyond is supported. + +## Implementation Details + +Below, we highlight some of the important details in this implementation. + +### HARQ + +To maintain the HARQ buffers in the LDPC decoding process, the BBDEV either uses its internal memory (not visible to DPDK), or using external memory (i.e., DDR) managed by OAI. +For the Xilinx T2 and Intel ACC100, they use the internal memory while the Intel ACC200 uses the DDR memory. + +If internal memory is supported by the device, we will set `RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE` and `RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE`. + +The following two fields are important for HARQ: `harq_combined_input` and `harq_combined_output`. + +For the first transmission, there is no HARQ input. +Thus, the flag `RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE` is not set. +However, there will be a HARQ output, so we set the flag `RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE`. +We also set the corresponding fields for `harq_combined_output`. + +For the second transmission (or subsequent retransmissions), we need to provide a HARQ input at the same time, there will also be a HARQ output. +Therefore, both fields, `harq_combined_input` and `harq_combined_output` must be set accordingly. + +As HARQ requires the output of the previous transmission/ HARQ round as its input, we need to maintain a separate variable to hold the previous round's information. +To do so, we define `harq_buffers` (which is a pointer to an array of size `num_harq_codeblock` allocated in the heap later) in the `active_device` struct (see the following) in our implementation. +```C +struct active_device { + ... + uint32_t num_harq_codeblock; + /* Persistent data structure to keep track of HARQ-related information */ + // Note: This is used to store/keep track of the combined output information across iterations + struct rte_bbdev_op_data *harq_buffers; + ... +} active_dev; +``` + + +In the following, we elaborate on how the HARQ-related fields are set. + +#### Internal Memory + +When using the internal memory, we need to specify the *offset* of the hardware's memory where we want to store the HARQ combined output, and read from it accordingly later. + +In the current implementation, we use a fixed offset of 32K, i.e., this means that each block is 32K. + +An index is derived from a unique HARQ PID assigned by OAI, modulo `active_dev.num_harq_codeblock` (which is configurable by the user through `nrLDPC_coding_t2.num_harq_codeblock`). +Using that index, we then derived the corresponding offset in the memory (i.e., `harq_combined_offset`). + +```C +... + +// Calculate offset in the HARQ combined buffers +// Unique segment offset +uint32_t segment_offset = (nrLDPC_slot_decoding_parameters->TBs[h].harq_unique_pid * NR_LDPC_MAX_NUM_CB) + i; +// Prune to avoid shooting above maximum id +uint32_t pruned_segment_offset = segment_offset % active_dev.num_harq_codeblock; +// Segment offset to byte offset +uint32_t harq_combined_offset = pruned_segment_offset * LDPC_MAX_CB_SIZE; + +... +``` + +This `harq_combined_offset` is then set for `harq_combined_input.offset` and `harq_combined_output.offset` to tell BBDEV where to read/write the HARQ buffers. + +Especially for the Intel ACCs, when providing the HARQ input, the `harq_combined_input.length` must be provided. +To do so, we maintain the length of previous round's output using `harq_buffers` by copying it in `retrieve_ldpc_dec_op`. + +#### External Memory + +Different from the Xilinx T2 and Intel ACC100, the Intel ACC200 uses DDR memory to maintain the HARQ buffers which is managed by OAI. + +In short, we use `harq_buffers` from the `active_device` struct, which have been initialzed with corresponding DPDK mempools for BBDEV to read/write the HARQ input/outputs. + +For indexing, we use the `pruned_segment_offset`, which is derived from the unique HARQ PID assigned by OAI, modulo `active_dev.num_harq_codeblock` (which is configurable by the user through `nrLDPC_coding_t2.num_harq_codeblock`). + +`harq_combined_input.offset` and `harq_combined_output.offset` is always set to 0 in our implementation. +Instead, we provide BBDEV the pointers to our allocated mempool regions through `harq_combined_input.data` and `harq_combined_output.data`. + +In `retrieve_ldpc_dec_op`, we perform a `rte_memcpy` to copy the HARQ combined outputs to `harq_buffers`, along with other necessary metadata information to prepare for subsequent HARQ rounds. +Similar to the Intel ACC100, when providing the HARQ input, the `harq_combined_input.length` must be provided. + +### LLR Scaling + +The LLR output from OAI's demodulation block is in 16 bits. +However, accelerators typically assume that the LLR inputs are scaled down using fixed-point arithmetic, e.g., 8 bits. + +For the Xilinx T2, saturation is performed. +However, our tests have shown that this implementation did not work well for the Intel ACCs. + +To that end, we perform LLR scaling differently for the Intel ACCs. +Through the function `llr_scaling`, we look at the min and max LLR values, perform scaling and subsequently saturation accordingly. + +The fixed-point representations supported by the hardware is defined by the `llr_size` and `llr_decimal`. +For example, if `llr_size=8`, and `llr_decimal=1`, it means that we use a S8.1 representation (1 fractional bit), the min and max values are -64 to 63.5. + +> *Limitation:* +> We observe that in certain configurations, such as when using 2 MIMO layers, the LLR (Log-Likelihood Ratio) outputs exhibit a much wider dynamic range (e.g., from -10,000 to 10,000) compared to the typical sub-1,000 range seen in most other cases. +> This suggests potential inconsistencies in the LLR values generated by the demodulator. +> We believe that the decoding performance, when compared to the CPU implementation under the same number of LDPC decoding iterations, could be improved by refining the LLR scaling approach or revisiting the LLR generation process during demodulation. +> This remains an area of active investigation. +> +> *Workaround:* +> As a temporary measure, increasing the number of LDPC decoding iterations—e.g., to 150—has shown to yield a decoding success rate comparable to that of the CPU implementation. +> This comes at a negligible increase in decoding time based on our current evaluation. + +### Special Case(s) + +#### TB mode + +For the T2, only CB mode is supported. + +For the Intel ACCs, while we also use CB mode mostly, there is a special case that must be handled properly as specified by the BBDEV documentations: +``` +... The case when one CB belongs to TB and is being enqueued individually to BBDEV, this case is considered as a special case of partial TB where its number of CBs is 1. Therefore, it requires to get processed in TB-mode. ... +``` + +In such a case, we perform a check on whether there is only one TB, AND if the TB has only one CB. +If so, this has to be handled separately by using TB mode. + +### Future Work(s) + +#### TB mode + +The current channel coding interface assumes LDPC encoding and decoding are performed on a per-code block basis. +However, to fully leverage Transport Block (TB) mode as supported in BBDEV, which can improve efficiency, the L1 implementation surrounding channel coding needs to be refactored. +This remains an area for future investigation. + +#### CRC24A/CRC16 + +CRC24A/CRC16 is supported by the BBDEV device (i.e., Intel ACC200). +However, we do not make use of them and rely on OAI's existing CRC functions. +To use of BBDEV's CRC24A/CRC16 capability will be looked into in future MRs. diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c similarity index 56% rename from openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c rename to openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c index 04ad571de0..31ca0b387b 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.c @@ -2,13 +2,8 @@ * Copyright(c) 2017 Intel Corporation */ -/*! \file PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.c - * \note: based on testbbdev test_bbdev_perf.c functions. Harq buffer offset added. - * \mbuf and mempool allocated at the init step, LDPC parameters updated from OAI. - */ - -#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" -#include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h" +#include "../nrLDPC_coding_interface.h" +#include "nrLDPC_coding_aal.h" #include "PHY/sse_intrin.h" #include #define NR_LDPC_ENABLE_PARITY_CHECK @@ -19,6 +14,7 @@ #include #include #include +#include #include @@ -47,16 +43,21 @@ #define TIME_OUT_POLL 1e8 /* Headroom for filler LLRs insertion in HARQ buffer */ #define FILLER_HEADROOM 1024 -/* Number of segments that could be stored in HARQ combined buffers */ -#define HARQ_CODEBLOCK_ID_MAX (16 << 5) pthread_mutex_t encode_mutex; pthread_mutex_t decode_mutex; -/* Represents tested active devices */ +/* we assume one active baseband device only */ struct active_device { const char *driver_name; uint8_t dev_id; + struct rte_bbdev_info info; + bool is_t2; + uint32_t num_harq_codeblock; + /* Persistent data structure to keep track of HARQ-related information */ + // Note: This is used to store/keep track of the combined output information across iterations + struct rte_bbdev_op_data *harq_buffers; + bool support_internal_harq_memory; int dec_queue; int enc_queue; uint16_t queue_ids[MAX_QUEUES]; @@ -65,13 +66,15 @@ struct active_device { struct rte_mempool *bbdev_enc_op_pool; struct rte_mempool *in_mbuf_pool; struct rte_mempool *hard_out_mbuf_pool; -} active_devs[RTE_BBDEV_MAX_DEVS]; -static int nb_active_devs; + struct rte_mempool *harq_in_mbuf_pool; + struct rte_mempool *harq_out_mbuf_pool; +} active_dev; /* Data buffers used by BBDEV ops */ struct data_buffers { struct rte_bbdev_op_data *inputs; struct rte_bbdev_op_data *hard_outputs; + struct rte_bbdev_op_data *harq_outputs; }; /* Operation parameters specific for given test case */ @@ -93,26 +96,34 @@ struct thread_params { struct rte_mempool *bbdev_op_pool; }; -static uint16_t nb_segments_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { +static uint16_t nb_segments_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) +{ uint16_t nb_segments = 0; for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { - nb_segments+=nrLDPC_slot_decoding_parameters->TBs[h].C; + nb_segments += nrLDPC_slot_decoding_parameters->TBs[h].C; } return nb_segments; } -static uint16_t nb_segments_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) { +static uint16_t nb_segments_encoding(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +{ uint16_t nb_segments = 0; for (int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) { - nb_segments+=nrLDPC_slot_encoding_parameters->TBs[h].C; + nb_segments += nrLDPC_slot_encoding_parameters->TBs[h].C; } return nb_segments; } +/* Read flag value 0/1 from bitmap */ +// DPDK BBDEV copy +static inline bool check_bit(uint32_t bitmap, uint32_t bitmask) +{ + return bitmap & bitmask; +} + /* calculates optimal mempool size not smaller than the val */ // DPDK BBDEV copy -static unsigned int -optimal_mempool_size(unsigned int val) +static unsigned int optimal_mempool_size(unsigned int val) { return rte_align32pow2(val + 1) - 1; } @@ -131,17 +142,16 @@ static int create_mempools(struct active_device *ad, int socket_id, uint16_t num OPS_POOL_SIZE_MIN)); /* Decoder ops mempool */ - ad->bbdev_dec_op_pool = rte_bbdev_op_pool_create("bbdev_op_pool_dec", RTE_BBDEV_OP_LDPC_DEC, - /* Encoder ops mempool */ ops_pool_size, OPS_CACHE_SIZE, socket_id); - ad->bbdev_enc_op_pool = rte_bbdev_op_pool_create("bbdev_op_pool_enc", RTE_BBDEV_OP_LDPC_ENC, - ops_pool_size, OPS_CACHE_SIZE, socket_id); + ad->bbdev_dec_op_pool = rte_bbdev_op_pool_create("bbdev_op_pool_dec", + RTE_BBDEV_OP_LDPC_DEC, + /* Encoder ops mempool */ ops_pool_size, + OPS_CACHE_SIZE, + socket_id); + ad->bbdev_enc_op_pool = + rte_bbdev_op_pool_create("bbdev_op_pool_enc", RTE_BBDEV_OP_LDPC_ENC, ops_pool_size, OPS_CACHE_SIZE, socket_id); if ((ad->bbdev_dec_op_pool == NULL) || (ad->bbdev_enc_op_pool == NULL)) - AssertFatal(1 == 0, - "ERROR Failed to create %u items ops pool for dev %u on socket %d.", - ops_pool_size, - ad->dev_id, - socket_id); + AssertFatal(1 == 0, "ERROR Failed to create %u items ops pool for dev %u on socket %d.", ops_pool_size, ad->dev_id, socket_id); /* Inputs */ mbuf_pool_size = optimal_mempool_size(ops_pool_size * nb_segments); @@ -149,9 +159,9 @@ static int create_mempools(struct active_device *ad, int socket_id, uint16_t num ad->in_mbuf_pool = rte_pktmbuf_pool_create("in_mbuf_pool", mbuf_pool_size, 0, 0, data_room_size, socket_id); AssertFatal(ad->in_mbuf_pool != NULL, "ERROR Failed to create %u items input pktmbuf pool for dev %u on socket %d.", - mbuf_pool_size, - ad->dev_id, - socket_id); + mbuf_pool_size, + ad->dev_id, + socket_id); /* Hard outputs */ data_room_size = RTE_MAX(out_buff_sz + RTE_PKTMBUF_HEADROOM + FILLER_HEADROOM, (unsigned int)RTE_MBUF_DEFAULT_BUF_SIZE); @@ -161,6 +171,27 @@ static int create_mempools(struct active_device *ad, int socket_id, uint16_t num mbuf_pool_size, ad->dev_id, socket_id); + + /* HARQ outputs */ + data_room_size = LDPC_MAX_CB_SIZE; + ad->harq_out_mbuf_pool = rte_pktmbuf_pool_create("harq_out_mbuf_pool", mbuf_pool_size, 0, 0, data_room_size, socket_id); + AssertFatal(ad->harq_out_mbuf_pool != NULL, + "ERROR Failed to create %u items harq output pktmbuf pool for dev %u on socket %d.", + mbuf_pool_size, + ad->dev_id, + socket_id); + + /* HARQ inputs */ + // Note: This is used as our harq buffer to store the combined outputs across iterations + data_room_size = LDPC_MAX_CB_SIZE; + ad->harq_in_mbuf_pool = + rte_pktmbuf_pool_create("harq_in_mbuf_pool", active_dev.num_harq_codeblock, 0, 0, data_room_size, socket_id); + AssertFatal(ad->harq_in_mbuf_pool != NULL, + "ERROR Failed to create %u items harq input pktmbuf pool for dev %u on socket %d.", + active_dev.num_harq_codeblock, + ad->dev_id, + socket_id); + return 0; } @@ -237,52 +268,130 @@ const char *ldpcdec_flag_bitmask[] = { "RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_FILLERS", }; -// based on DPDK BBDEV add_bbdev_dev -static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info) +void debug_dev_capabilities(uint8_t dev_id, struct rte_bbdev_info *info) { - int ret; - struct active_device *ad = &active_devs[nb_active_devs]; - unsigned int nb_queues; - nb_queues = RTE_MIN(rte_lcore_count(), info->drv.max_num_queues); - nb_queues = RTE_MIN(nb_queues, (unsigned int)MAX_QUEUES); - /* Display for debug the capabilities of the card */ for (int i = 0; info->drv.capabilities[i].type != RTE_BBDEV_OP_NONE; i++) { - printf("device: %d, capability[%d]=%s\n", dev_id, i, rte_bbdev_op_type_str(info->drv.capabilities[i].type)); + LOG_D(NR_PHY, "device: %d, capability[%d]=%s\n", dev_id, i, rte_bbdev_op_type_str(info->drv.capabilities[i].type)); if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_ENC) { const struct rte_bbdev_op_cap_ldpc_enc cap = info->drv.capabilities[i].cap.ldpc_enc; - printf(" buffers: src = %d, dst = %d\n capabilites: ", cap.num_buffers_src, cap.num_buffers_dst); + LOG_D(NR_PHY, " buffers: src = %d, dst = %d\n capabilites: ", cap.num_buffers_src, cap.num_buffers_dst); for (int j = 0; j < sizeof(cap.capability_flags) * 8; j++) if (cap.capability_flags & (1ULL << j)) - printf("%s ", ldpcenc_flag_bitmask[j]); - printf("\n"); + LOG_D(NR_PHY, "%s ", ldpcenc_flag_bitmask[j]); + LOG_D(NR_PHY, "\n"); } if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_DEC) { const struct rte_bbdev_op_cap_ldpc_dec cap = info->drv.capabilities[i].cap.ldpc_dec; - printf(" buffers: src = %d, hard out = %d, soft_out %d, llr size %d, llr decimals %d \n capabilities: ", - cap.num_buffers_src, - cap.num_buffers_hard_out, - cap.num_buffers_soft_out, - cap.llr_size, - cap.llr_decimals); + LOG_D(NR_PHY, + " buffers: src = %d, hard out = %d, soft_out %d, llr size %d, llr decimals %d \n capabilities: ", + cap.num_buffers_src, + cap.num_buffers_hard_out, + cap.num_buffers_soft_out, + cap.llr_size, + cap.llr_decimals); for (int j = 0; j < sizeof(cap.capability_flags) * 8; j++) if (cap.capability_flags & (1ULL << j)) - printf("%s ", ldpcdec_flag_bitmask[j]); - printf("\n"); + LOG_D(NR_PHY, "%s ", ldpcdec_flag_bitmask[j]); + LOG_D(NR_PHY, "\n"); } } +} - /* setup device */ - ret = rte_bbdev_setup_queues(dev_id, nb_queues, info->socket_id); - if (ret < 0) { - printf("rte_bbdev_setup_queues(%u, %u, %d) ret %i\n", dev_id, nb_queues, info->socket_id, ret); - return -1; +void check_required_dev_capabilities(struct rte_bbdev_info *info) +{ + // check ldpc enc/ dec support + bool ldpc_enc = false; + bool ldpc_dec = false; + for (int i = 0; info->drv.capabilities[i].type != RTE_BBDEV_OP_NONE; i++) { + if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_ENC) { + ldpc_enc = true; + } + if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_DEC) { + ldpc_dec = true; + } } + AssertFatal(ldpc_enc, "ERROR: bbdev device does not support LDPC encoding\n"); + AssertFatal(ldpc_dec, "ERROR: bbdev device does not support LDPC decoding\n"); + + for (int i = 0; info->drv.capabilities[i].type != RTE_BBDEV_OP_NONE; i++) { + if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_ENC) { + // check encoding capabilities + bool rate_match = check_bit(info->drv.capabilities[i].cap.ldpc_enc.capability_flags, RTE_BBDEV_LDPC_RATE_MATCH); + AssertFatal(rate_match, "ERROR: bbdev device does not support LDPC encoding with rate matching\n"); + } + if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_DEC) { + // check decoding capabilities + bool iter_stop = check_bit(info->drv.capabilities[i].cap.ldpc_dec.capability_flags, RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE); + AssertFatal(iter_stop, "ERROR: bbdev device does not support LDPC decoding with iteration stop\n"); + + bool crc_24b_drop = check_bit(info->drv.capabilities[i].cap.ldpc_dec.capability_flags, RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP); + AssertFatal(crc_24b_drop, "ERROR: bbdev device does not support LDPC decoding with CRC-24B drop\n"); + + bool crc_24b_check = check_bit(info->drv.capabilities[i].cap.ldpc_dec.capability_flags, RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK); + AssertFatal(crc_24b_check, "ERROR: bbdev device does not support LDPC decoding with CRC-24B check\n"); + } + } +} + +bool check_internal_harq_memory_capabilities(struct rte_bbdev_info *info) +{ + for (int i = 0; info->drv.capabilities[i].type != RTE_BBDEV_OP_NONE; i++) { + if (info->drv.capabilities[i].type == RTE_BBDEV_OP_LDPC_DEC) { + bool harq_in = + check_bit(info->drv.capabilities[i].cap.ldpc_dec.capability_flags, RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE); + bool harq_out = + check_bit(info->drv.capabilities[i].cap.ldpc_dec.capability_flags, RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE); + bool internal_harq_memory_support = harq_in & harq_out; + if (internal_harq_memory_support) { + LOG_I(NR_PHY, "bbdev device supports internal HARQ memory\n"); + } + return internal_harq_memory_support; + } + } + return false; +} + +// based on DPDK BBDEV add_bbdev_dev +static int add_dev(uint8_t dev_id, bool is_t2, uint32_t num_harq_codeblock) +{ + int ret; + unsigned int nb_queues; + + // retrieve device capabilities + rte_bbdev_info_get(dev_id, &active_dev.info); + LOG_I(NR_PHY, "using bbdev %d: %s\n", dev_id, active_dev.info.dev_name); + + active_dev.driver_name = active_dev.info.drv.driver_name; + active_dev.dev_id = dev_id; + + nb_queues = RTE_MIN(rte_lcore_count(), active_dev.info.drv.max_num_queues); + nb_queues = RTE_MIN(nb_queues, (unsigned int)MAX_QUEUES); + + // debug device capabilities + debug_dev_capabilities(dev_id, &active_dev.info); + + // check required device capabilities + check_required_dev_capabilities(&active_dev.info); + + // check internal harq memory capabilities + active_dev.support_internal_harq_memory = check_internal_harq_memory_capabilities(&active_dev.info); + + // setup harq buffers + active_dev.num_harq_codeblock = num_harq_codeblock; + active_dev.harq_buffers = malloc(sizeof(struct rte_bbdev_op_data) * active_dev.num_harq_codeblock); + + // is device T2? + active_dev.is_t2 = is_t2; + + // device setup + ret = rte_bbdev_setup_queues(dev_id, nb_queues, active_dev.info.socket_id); + AssertFatal(ret == 0, "rte_bbdev_setup_queues(%u, %u, %d) ret %i\n", dev_id, nb_queues, active_dev.info.socket_id, ret); /* setup device queues */ struct rte_bbdev_queue_conf qconf = { - .socket = info->socket_id, - .queue_size = info->drv.default_queue_conf.queue_size, + .socket = active_dev.info.socket_id, + .queue_size = active_dev.info.drv.default_queue_conf.queue_size, }; // Search a queue linked to HW capability ldpc decoding @@ -291,10 +400,10 @@ static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info) for (queue_id = 0; queue_id < nb_queues; ++queue_id) { ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf); if (ret == 0) { - printf("Found LDCP encoding queue (id=%u) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id); + LOG_I(NR_PHY, "Found LDPC encoding queue (id=%u) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id); qconf.priority++; - ad->enc_queue = queue_id; - ad->queue_ids[queue_id] = queue_id; + active_dev.enc_queue = queue_id; + active_dev.queue_ids[queue_id] = queue_id; break; } } @@ -305,15 +414,30 @@ static int add_dev(uint8_t dev_id, struct rte_bbdev_info *info) for (queue_id++; queue_id < nb_queues; ++queue_id) { ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf); if (ret == 0) { - printf("Found LDCP decoding queue (id=%u) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id); + LOG_I(NR_PHY, "Found LDPC decoding queue (id=%u) at prio%u on dev%u\n", queue_id, qconf.priority, dev_id); qconf.priority++; - ad->dec_queue = queue_id; - ad->queue_ids[queue_id] = queue_id; + active_dev.dec_queue = queue_id; + active_dev.queue_ids[queue_id] = queue_id; break; } } AssertFatal(queue_id != nb_queues, "ERROR Failed to configure encoding queues on dev %u", dev_id); - ad->nb_queues = 2; + active_dev.nb_queues = 2; + return 0; +} + +static int init_op_data_objs_harq(struct rte_bbdev_op_data *bufs, struct rte_mempool *mbuf_pool) +{ + for (int i = 0; i < active_dev.num_harq_codeblock; i++) { + struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool); + AssertFatal(m_head != NULL, + "Not enough mbufs in HARQ mbuf pool (needed %u, available %u)", + active_dev.num_harq_codeblock, + mbuf_pool->size); + bufs[i].data = m_head; + bufs[i].offset = 0; + bufs[i].length = 0; + } return 0; } @@ -337,7 +461,7 @@ static int init_op_data_objs_dec(struct rte_bbdev_op_data *bufs, op_type, nb_segments_decoding(nrLDPC_slot_decoding_parameters), mbuf_pool->size); - + if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) { printf("Warning: Larger input size than DPDK mbuf %u\n", data_len); large_input = true; @@ -393,7 +517,7 @@ static int init_op_data_objs_enc(struct rte_bbdev_op_data *bufs, op_type, nb_segments_encoding(nrLDPC_slot_encoding_parameters), mbuf_pool->size); - + if (data_len > RTE_BBDEV_LDPC_E_MAX_MBUF) { printf("Warning: Larger input size than DPDK mbuf %u\n", data_len); large_input = true; @@ -430,7 +554,6 @@ static int init_op_data_objs_enc(struct rte_bbdev_op_data *bufs, return 0; } - // DPDK BBEV copy static int allocate_buffers_on_socket(struct rte_bbdev_op_data **buffers, const int len, const int socket) { @@ -457,53 +580,89 @@ static void free_mempools(struct active_device *ad) rte_mempool_free(ad->bbdev_enc_op_pool); rte_mempool_free(ad->in_mbuf_pool); rte_mempool_free(ad->hard_out_mbuf_pool); + rte_mempool_free(ad->harq_in_mbuf_pool); + rte_mempool_free(ad->harq_out_mbuf_pool); } // based on DPDK BBDEV copy_reference_ldpc_dec_op -static void -set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, - struct rte_bbdev_op_data *inputs, - struct rte_bbdev_op_data *outputs, - nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) +static void set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, + struct rte_bbdev_op_data *inputs, + struct rte_bbdev_op_data *outputs, + struct rte_bbdev_op_data *harq_outputs, + nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { int j = 0; + // The T2 only supports CB mode, and does not TB mode special case handling. + bool special_case_tb_mode = !active_dev.is_t2 && (nrLDPC_slot_decoding_parameters->nb_TBs == 1) + && (nb_segments_decoding(nrLDPC_slot_decoding_parameters) == 1); for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { for (int i = 0; i < nrLDPC_slot_decoding_parameters->TBs[h].C; ++i) { - ops[j]->ldpc_dec.cb_params.e = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E; ops[j]->ldpc_dec.basegraph = nrLDPC_slot_decoding_parameters->TBs[h].BG; ops[j]->ldpc_dec.z_c = nrLDPC_slot_decoding_parameters->TBs[h].Z; ops[j]->ldpc_dec.q_m = nrLDPC_slot_decoding_parameters->TBs[h].Qm; ops[j]->ldpc_dec.n_filler = nrLDPC_slot_decoding_parameters->TBs[h].F; - ops[j]->ldpc_dec.n_cb = (nrLDPC_slot_decoding_parameters->TBs[h].BG == 1) ? (66 * nrLDPC_slot_decoding_parameters->TBs[h].Z) : (50 * nrLDPC_slot_decoding_parameters->TBs[h].Z); + ops[j]->ldpc_dec.n_cb = (nrLDPC_slot_decoding_parameters->TBs[h].BG == 1) ? (66 * nrLDPC_slot_decoding_parameters->TBs[h].Z) + : (50 * nrLDPC_slot_decoding_parameters->TBs[h].Z); ops[j]->ldpc_dec.iter_max = nrLDPC_slot_decoding_parameters->TBs[h].max_ldpc_iterations; ops[j]->ldpc_dec.rv_index = nrLDPC_slot_decoding_parameters->TBs[h].rv_index; - ops[j]->ldpc_dec.op_flags = RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE | - RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE | - RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE | - RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE; + ops[j]->ldpc_dec.op_flags = RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE | RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE; if (*nrLDPC_slot_decoding_parameters->TBs[h].segments[i].d_to_be_cleared) { *nrLDPC_slot_decoding_parameters->TBs[h].segments[i].d_to_be_cleared = false; - *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = 0; + if (active_dev.is_t2) + *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = 0; } else { ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_HQ_COMBINE_IN_ENABLE; + if (active_dev.support_internal_harq_memory) { + ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_IN_ENABLE; + ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE; + } } - if (nrLDPC_slot_decoding_parameters->TBs[h].C > 1) { - ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP; - ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK; - } - ops[j]->ldpc_dec.code_block_mode = 1; + if (!active_dev.is_t2) + *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = 0; + + if (!special_case_tb_mode) { + ops[j]->ldpc_dec.code_block_mode = 1; + ops[j]->ldpc_dec.cb_params.e = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E; + if (nrLDPC_slot_decoding_parameters->TBs[h].C > 1) { + ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_DROP; + ops[j]->ldpc_dec.op_flags |= RTE_BBDEV_LDPC_CRC_TYPE_24B_CHECK; + } + } else { + /** + * This is a special case when #TB = 1 and #CB = 1 + * In this case, we must use TB mode + * Quoted from: https://doc.dpdk.org/guides-23.11/prog_guide/bbdev.html#bbdev-ldpc-decode-operation + * The case when one CB belongs to TB and is being enqueued individually to BBDEV, this case is considered as a + * special case of partial TB where its number of CBs is 1. Therefore, it requires to get processed in TB-mode. + */ + ops[j]->ldpc_dec.code_block_mode = 0; + ops[j]->ldpc_dec.tb_params.c = 1; + ops[j]->ldpc_dec.tb_params.r = 0; + ops[j]->ldpc_dec.tb_params.cab = 1; + ops[j]->ldpc_dec.tb_params.ea = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E; + ops[j]->ldpc_dec.tb_params.eb = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].E; + } // Calculate offset in the HARQ combined buffers // Unique segment offset uint32_t segment_offset = (nrLDPC_slot_decoding_parameters->TBs[h].harq_unique_pid * NR_LDPC_MAX_NUM_CB) + i; // Prune to avoid shooting above maximum id - uint32_t pruned_segment_offset = segment_offset % HARQ_CODEBLOCK_ID_MAX; + uint32_t pruned_segment_offset = segment_offset % active_dev.num_harq_codeblock; // Segment offset to byte offset uint32_t harq_combined_offset = pruned_segment_offset * LDPC_MAX_CB_SIZE; - ops[j]->ldpc_dec.harq_combined_input.offset = harq_combined_offset; - ops[j]->ldpc_dec.harq_combined_output.offset = harq_combined_offset; - + if (active_dev.support_internal_harq_memory) { + // retrieve corresponding HARQ output information from previous iteration, especially the length + ops[j]->ldpc_dec.harq_combined_input = active_dev.harq_buffers[pruned_segment_offset]; + // Note: When using INTERNAL_HARQ memory, the "offset" is used to point to a particular address + // within the BBDEV's onboard memory, and the address should be multiples of 32K. + harq_outputs[j].offset = harq_combined_offset; + ops[j]->ldpc_dec.harq_combined_output = harq_outputs[j]; + } else { + // retrieve corresponding HARQ buffers from previous iteration + ops[j]->ldpc_dec.harq_combined_input = active_dev.harq_buffers[pruned_segment_offset]; + ops[j]->ldpc_dec.harq_combined_output = harq_outputs[j]; + } ops[j]->ldpc_dec.hard_output = outputs[j]; ops[j]->ldpc_dec.input = inputs[j]; ++j; @@ -512,28 +671,47 @@ set_ldpc_dec_op(struct rte_bbdev_dec_op **ops, } // based on DPDK BBDEV copy_reference_ldpc_enc_op -static void -set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, - struct rte_bbdev_op_data *inputs, - struct rte_bbdev_op_data *outputs, - nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +static void set_ldpc_enc_op(struct rte_bbdev_enc_op **ops, + struct rte_bbdev_op_data *inputs, + struct rte_bbdev_op_data *outputs, + nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) { int j = 0; + // The T2 only supports CB mode, and does not TB mode special case handling. + bool special_case_tb_mode = !active_dev.is_t2 && (nrLDPC_slot_encoding_parameters->nb_TBs == 1) + && (nb_segments_encoding(nrLDPC_slot_encoding_parameters) == 1); for (int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) { for (int i = 0; i < nrLDPC_slot_encoding_parameters->TBs[h].C; ++i) { - ops[j]->ldpc_enc.cb_params.e = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].E; ops[j]->ldpc_enc.basegraph = nrLDPC_slot_encoding_parameters->TBs[h].BG; ops[j]->ldpc_enc.z_c = nrLDPC_slot_encoding_parameters->TBs[h].Z; ops[j]->ldpc_enc.q_m = nrLDPC_slot_encoding_parameters->TBs[h].Qm; ops[j]->ldpc_enc.n_filler = nrLDPC_slot_encoding_parameters->TBs[h].F; - ops[j]->ldpc_enc.n_cb = (nrLDPC_slot_encoding_parameters->TBs[h].BG == 1) ? (66 * nrLDPC_slot_encoding_parameters->TBs[h].Z) : (50 * nrLDPC_slot_encoding_parameters->TBs[h].Z); + ops[j]->ldpc_enc.n_cb = (nrLDPC_slot_encoding_parameters->TBs[h].BG == 1) ? (66 * nrLDPC_slot_encoding_parameters->TBs[h].Z) + : (50 * nrLDPC_slot_encoding_parameters->TBs[h].Z); if (nrLDPC_slot_encoding_parameters->TBs[h].tbslbrm != 0) { uint32_t Nref = 3 * nrLDPC_slot_encoding_parameters->TBs[h].tbslbrm / (2 * nrLDPC_slot_encoding_parameters->TBs[h].C); ops[j]->ldpc_enc.n_cb = min(ops[j]->ldpc_enc.n_cb, Nref); } ops[j]->ldpc_enc.rv_index = nrLDPC_slot_encoding_parameters->TBs[h].rv_index; ops[j]->ldpc_enc.op_flags = RTE_BBDEV_LDPC_RATE_MATCH; - ops[j]->ldpc_enc.code_block_mode = 1; + if (!special_case_tb_mode) { + ops[j]->ldpc_enc.code_block_mode = 1; + ops[j]->ldpc_enc.cb_params.e = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].E; + } else { + /** + * This is a special case when #TB = 1 and #CB = 1 + * In this case, we must use TB mode + * Quoted from: https://doc.dpdk.org/guides-23.11/prog_guide/bbdev.html#bbdev-ldpc-decode-operation + * The case when one CB belongs to TB and is being enqueued individually to BBDEV, this case is considered as a + * special case of partial TB where its number of CBs is 1. Therefore, it requires to get processed in TB-mode. + */ + ops[j]->ldpc_enc.code_block_mode = 0; + ops[j]->ldpc_enc.tb_params.c = 1; + ops[j]->ldpc_enc.tb_params.r = 0; + ops[j]->ldpc_enc.tb_params.cab = 1; + ops[j]->ldpc_enc.tb_params.ea = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].E; + ops[j]->ldpc_enc.tb_params.eb = nrLDPC_slot_encoding_parameters->TBs[h].segments[i].E; + } ops[j]->ldpc_enc.output = outputs[j]; ops[j]->ldpc_enc.input = inputs[j]; ++j; @@ -551,19 +729,30 @@ static int retrieve_ldpc_dec_op(struct rte_bbdev_dec_op **ops, nrLDPC_slot_decod uint16_t data_len = rte_pktmbuf_data_len(m) - hard_output->offset; uint8_t *data = rte_pktmbuf_mtod_offset(m, uint8_t *, hard_output->offset); memcpy(nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c, data, data_len); + + uint32_t segment_offset = (nrLDPC_slot_decoding_parameters->TBs[h].harq_unique_pid * NR_LDPC_MAX_NUM_CB) + i; + uint32_t pruned_segment_offset = segment_offset % active_dev.num_harq_codeblock; + struct rte_bbdev_op_data *harq_output = &ops[j]->ldpc_dec.harq_combined_output; + if (!active_dev.support_internal_harq_memory) { + struct rte_mbuf *m_src = harq_output->data; + uint8_t *data_src = rte_pktmbuf_mtod_offset(m_src, uint8_t *, 0); + struct rte_mbuf *m_dst = active_dev.harq_buffers[pruned_segment_offset].data; + uint8_t *data_dst = rte_pktmbuf_mtod_offset(m_dst, uint8_t *, 0); + rte_memcpy(data_dst, data_src, harq_output->length); + } + active_dev.harq_buffers[pruned_segment_offset].offset = harq_output->offset; + active_dev.harq_buffers[pruned_segment_offset].length = harq_output->length; ++j; } } return 0; } -static int -retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, - nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) +static int retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_encoding_parameters) { uint8_t *p_out = NULL; int j = 0; - for (int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h){ + for (int h = 0; h < nrLDPC_slot_encoding_parameters->nb_TBs; ++h) { int E_sum = 0; int bit_offset = 0; int byte_offset = 0; @@ -606,8 +795,7 @@ retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, } // based on DPDK BBDEV throughput_pmd_lcore_ldpc_dec -static int -pmd_lcore_ldpc_dec(void *arg) +static int pmd_lcore_ldpc_dec(void *arg) { struct thread_params *tp = arg; nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters = tp->nrLDPC_slot_decoding_parameters; @@ -620,15 +808,16 @@ pmd_lcore_ldpc_dec(void *arg) AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); - struct rte_bbdev_info info; - rte_bbdev_info_get(tp->dev_id, &info); - while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) rte_pause(); int ret = rte_bbdev_dec_op_alloc_bulk(tp->bbdev_op_pool, ops_enq, num_segments); AssertFatal(ret == 0, "Allocation failed for %d ops", num_segments); - set_ldpc_dec_op(ops_enq, bufs->inputs, bufs->hard_outputs, nrLDPC_slot_decoding_parameters); + set_ldpc_dec_op(ops_enq, bufs->inputs, bufs->hard_outputs, bufs->harq_outputs, nrLDPC_slot_decoding_parameters); + + // Start timer + // We report timing only once in (0,0) since the timers are merged at the end + start_meas(&nrLDPC_slot_decoding_parameters->TBs[0].segments[0].ts_ldpc_decode); uint16_t enq = 0, deq = 0; while (enq < num_segments) { @@ -643,6 +832,10 @@ pmd_lcore_ldpc_dec(void *arg) DevAssert(time_out <= TIME_OUT_POLL); } + // Stop timer + // We report timing only once in (0,0) since the timers are merged at the end + stop_meas(&nrLDPC_slot_decoding_parameters->TBs[0].segments[0].ts_ldpc_decode); + if (deq == enq) { ret = retrieve_ldpc_dec_op(ops_deq, nrLDPC_slot_decoding_parameters); AssertFatal(ret == 0, "LDPC offload decoder failed!"); @@ -656,24 +849,19 @@ pmd_lcore_ldpc_dec(void *arg) // Check if CRC is available otherwise rely on ops_enq[j]->status to detect decoding success // CRC is NOT available if the CRC type is 24_B which is when C is greater than 1 - if (nrLDPC_slot_decoding_parameters->TBs[h].C > 1) { - *status = (ops_enq[j]->status == 0); - } else { - uint8_t *decoded_bytes = nrLDPC_slot_decoding_parameters->TBs[h].segments[i].c; uint8_t crc_type = crcType(nrLDPC_slot_decoding_parameters->TBs[h].C, nrLDPC_slot_decoding_parameters->TBs[h].A); uint32_t len_with_crc = lenWithCrc(nrLDPC_slot_decoding_parameters->TBs[h].C, nrLDPC_slot_decoding_parameters->TBs[h].A); *status = check_crc(decoded_bytes, len_with_crc, crc_type); - } if (*status) { - *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments + 1; + *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments = + *nrLDPC_slot_decoding_parameters->TBs[h].processedSegments + 1; } - ++j; } } @@ -698,9 +886,6 @@ static int pmd_lcore_ldpc_enc(void *arg) AssertFatal((num_segments < MAX_BURST), "BURST_SIZE should be <= %u", MAX_BURST); - struct rte_bbdev_info info; - rte_bbdev_info_get(tp->dev_id, &info); - while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) rte_pause(); @@ -763,7 +948,8 @@ int start_pmd_dec(struct active_device *ad, t_params[0].nrLDPC_slot_decoding_parameters = nrLDPC_slot_decoding_parameters; used_cores++; // For now, we never enter here, we don't use the DPDK thread pool - RTE_LCORE_FOREACH_WORKER(lcore_id) { + RTE_LCORE_FOREACH_WORKER(lcore_id) + { if (used_cores >= num_lcores) break; t_params[used_cores].dev_id = ad->dev_id; @@ -807,7 +993,8 @@ int32_t start_pmd_enc(struct active_device *ad, t_params[0].nrLDPC_slot_encoding_parameters = nrLDPC_slot_encoding_parameters; used_cores++; // For now, we never enter here, we don't use the DPDK thread pool - RTE_LCORE_FOREACH_WORKER(lcore_id) { + RTE_LCORE_FOREACH_WORKER(lcore_id) + { if (used_cores >= num_lcores) break; t_params[used_cores].dev_id = ad->dev_id; @@ -828,46 +1015,125 @@ int32_t start_pmd_enc(struct active_device *ad, struct test_op_params *op_params = NULL; +static int normalize_dpdk_dev(const char *input, char *output, size_t out_len) +{ + regex_t regex_full, regex_short; + int reti; + + // patterns + const char *pattern_full = "^[0]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\\.[0-7]$"; + const char *pattern_short = "^[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\\.[0-7]$"; + regcomp(®ex_full, pattern_full, REG_EXTENDED); + regcomp(®ex_short, pattern_short, REG_EXTENDED); + + // check full format + reti = regexec(®ex_full, input, 0, NULL, 0); + if (reti == 0) { + // already in full format + strncpy(output, input, out_len - 1); + output[out_len - 1] = '\0'; + } else { + // check short format + reti = regexec(®ex_short, input, 0, NULL, 0); + if (reti == 0) { + // convert to full format + snprintf(output, out_len, "0000:%s", input); + } else { + // invalid format + regfree(®ex_full); + regfree(®ex_short); + return -1; + } + } + regfree(®ex_full); + regfree(®ex_short); + return 0; +} + // OAI CODE int32_t nrLDPC_coding_init() { pthread_mutex_init(&encode_mutex, NULL); pthread_mutex_init(&decode_mutex, NULL); + int ret; - int dev_id = 0; - struct rte_bbdev_info info; - struct active_device *ad = active_devs; - char *dpdk_dev = NULL; //PCI address of the card - char *dpdk_core_list = NULL; // cores used by DPDK for T2 + int dev_id = -1; + + char *dpdk_dev = NULL; // PCI address of the card + char *dpdk_core_list = NULL; // cores used by DPDK for bbdev char *dpdk_file_prefix = NULL; + char *vfio_vf_token = NULL; // vfio token for the bbdev card + uint32_t num_harq_codeblock = 0; // size of the HARQ buffer in terms of the number of 32K blocks + uint32_t is_t2 = 0; paramdef_t LoaderParams[] = { - {"dpdk_dev", NULL, 0, .strptr = &dpdk_dev, .defstrval = NULL, TYPE_STRING, 0, NULL}, - {"dpdk_core_list", NULL, 0, .strptr = &dpdk_core_list, .defstrval = NULL, TYPE_STRING, 0, NULL}, - {"dpdk_file_prefix", NULL, 0, .strptr = &dpdk_file_prefix, .defstrval = "b6", TYPE_STRING, 0, NULL} + {"dpdk_dev", NULL, 0, .strptr = &dpdk_dev, .defstrval = NULL, TYPE_STRING, 0, NULL}, + {"dpdk_core_list", NULL, 0, .strptr = &dpdk_core_list, .defstrval = NULL, TYPE_STRING, 0, NULL}, + {"dpdk_file_prefix", NULL, 0, .strptr = &dpdk_file_prefix, .defstrval = "b6", TYPE_STRING, 0, NULL}, + {"vfio_vf_token", NULL, 0, .strptr = &vfio_vf_token, .defstrval = NULL, TYPE_STRING, 0, NULL}, + {"num_harq_codeblock", NULL, 0, .uptr = &num_harq_codeblock, .defintval = 512, TYPE_UINT32, 0, NULL}, + {"is_t2", NULL, 0, .uptr = &is_t2, .defintval = 0, TYPE_UINT8, 0, NULL}, }; - config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_t2"); - AssertFatal(dpdk_dev!=NULL, "nrLDPC_coding_t2.dpdk_dev was not provided"); - AssertFatal(dpdk_core_list!=NULL, "nrLDPC_coding_t2.dpdk_core_list was not provided"); - char *argv_re[] = {"bbdev", "-a", dpdk_dev, "-l", dpdk_core_list, "--file-prefix", dpdk_file_prefix, "--"}; - // EAL initialization, if already initialized (init in xran lib) try to probe DPDK device - ret = rte_eal_init(sizeofArray(argv_re), argv_re); - if (ret < 0) { - printf("EAL initialization failed, probing DPDK device %s\n", dpdk_dev); - if (rte_dev_probe(dpdk_dev) != 0) { - LOG_E(PHY, "T2 card %s not found\n", dpdk_dev); + config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_aal"); + if (dpdk_dev == NULL) + LOG_E(NR_PHY, + "could not find mandatory --nrLDPC_coding_aal.dpdk_dev. If you used --nrLDPC_coding_t2.*, please rename all options to " + "--nrLDPC_coding_aal.*\n"); + AssertFatal(dpdk_dev != NULL, "nrLDPC_coding_aal.dpdk_dev was not provided"); + + char dpdk_dev_full[32]; + if (normalize_dpdk_dev(dpdk_dev, dpdk_dev_full, sizeof(dpdk_dev_full)) != 0) { + LOG_E(NR_PHY, "invalid DPDK device format: %s\n", dpdk_dev); + return -1; + } + + // Detect if EAL was initialized by probing the device + LOG_I(NR_PHY, "Probing DPDK device %s to know if EAL is initialized. This may generate EAL error messages\n", dpdk_dev_full); + if (rte_dev_probe(dpdk_dev_full) != 0) { + LOG_I(NR_PHY, "Probing DPDK device %s failed, initializing EAL before continuing\n", dpdk_dev_full); + // EAL was not initialized yet + // We initialize EAL + AssertFatal(dpdk_core_list != NULL, "nrLDPC_coding_aal.dpdk_core_list was not provided"); + + int argc = 7; + char *argv[11] = + {"bbdev", "-l", dpdk_core_list, "-a", dpdk_dev_full, "--file-prefix", dpdk_file_prefix, "--", "--", "--", "--"}; + if (vfio_vf_token != NULL) { + argc += 2; + argv[7] = "--vfio-vf-token"; + argv[8] = vfio_vf_token; + } + ret = rte_eal_init(argc, argv); + if (ret < 0) { + LOG_E(NR_PHY, "EAL initialization failed\n"); return (-1); } + } else { + // EAL was already initialized + LOG_I(NR_PHY, "Probing DPDK device %s succeeded, skipping EAL initialization\n", dpdk_dev_full); } - // Use only device 0 - first detected device - rte_bbdev_info_get(0, &info); - // Set number of queues based on number of initialized cores (-l option) and driver - // capabilities - AssertFatal(add_dev(dev_id, &info)== 0, "Failed to setup bbdev"); + uint16_t nb_bbdevs = rte_bbdev_count(); + AssertFatal(nb_bbdevs > 0, "no bbdev found"); + + // find the baseband device that matches the dpdk_dev specified in the configurations + struct rte_bbdev_info info; + LOG_I(NR_PHY, "detected %u bbdev.\n", nb_bbdevs); + for (uint16_t device_id = 0; device_id < nb_bbdevs; device_id++) { + rte_bbdev_info_get(device_id, &info); + // check if info matches the dpdk_dev that we are looking for + if (strcmp(info.dev_name, dpdk_dev_full) == 0) { + LOG_I(NR_PHY, "bbdev %s found.\n", info.dev_name); + dev_id = device_id; + break; + } + } + AssertFatal(dev_id != -1, "bbdev %s not found.", dpdk_dev_full); + + AssertFatal(add_dev(dev_id, is_t2, num_harq_codeblock) == 0, "Failed to setup bbdev"); AssertFatal(rte_bbdev_stats_reset(dev_id) == 0, "Failed to reset stats of bbdev %u", dev_id); AssertFatal(rte_bbdev_start(dev_id) == 0, "Failed to start bbdev %u", dev_id); - //the previous calls have populated this global variable (beurk) - // One more global to remove, not thread safe global op_params + // the previous calls have populated this global variable (beurk) + // One more global to remove, not thread safe global op_params op_params = rte_zmalloc(NULL, sizeof(struct test_op_params), RTE_CACHE_LINE_SIZE); AssertFatal(op_params != NULL, "Failed to alloc %zuB for op_params", @@ -877,34 +1143,120 @@ int32_t nrLDPC_coding_init() int out_max_sz = 8448; // max code block size (for BG1), 22 * 384 int in_max_sz = LDPC_MAX_CB_SIZE; // max number of encoded bits (for BG2 and MCS0) int num_queues = 1; - int f_ret = create_mempools(ad, socket_id, num_queues, out_max_sz, in_max_sz); + int f_ret = create_mempools(&active_dev, socket_id, num_queues, out_max_sz, in_max_sz); if (f_ret != 0) { printf("Couldn't create mempools"); return -1; } + + // initialize persistent data structure to keep track of HARQ-related information + init_op_data_objs_harq(active_dev.harq_buffers, active_dev.harq_in_mbuf_pool); + op_params->num_lcores = 1; return 0; } int32_t nrLDPC_coding_shutdown() { - struct active_device *ad = active_devs; int dev_id = 0; struct rte_bbdev_stats stats; - free_mempools(ad); + free(active_dev.harq_buffers); + free_mempools(&active_dev); rte_free(op_params); rte_bbdev_stats_get(dev_id, &stats); rte_bbdev_stop(dev_id); rte_bbdev_close(dev_id); - memset(active_devs, 0, sizeof(active_devs)); - nb_active_devs = 0; + memset(&active_dev, 0, sizeof(active_dev)); return 0; } +static void +llr_scaling(int16_t *llr, int llr_len, uint8_t *llr_scaled, int8_t llr_size, int8_t llr_decimal, int8_t nb_layers, int8_t Qm) +{ + const int16_t llr_max = (1 << (llr_size - 1)) - 1; + const int16_t llr_min = -llr_max; + + // Step 1: Find the max absolute LLR + int16_t max_abs = 1; // prevent divide-by-zero + // SCALAR IMPLEMENTATION + // for (int i = 0; i < llr_len; i++) { + // int16_t abs_val = abs(llr[i]); + // if (abs_val > max_abs) max_abs = abs_val; + // } + // VECTORIZED IMPLEMENTATION + simde__m128i max_vec = simde_mm_set1_epi16(1); + for (int i = 0; i < llr_len; i += 8) { + simde__m128i llr_vec = simde_mm_loadu_si128((simde__m128i *)&llr[i]); + simde__m128i abs_vec = simde_mm_abs_epi16(llr_vec); + max_vec = simde_mm_max_epi16(max_vec, abs_vec); + } + // reduce max_vec to single max_abs + int16_t temp[8]; + simde_mm_storeu_si128((simde__m128i *)temp, max_vec); + for (int i = 0; i < 8; i++) { + if (temp[i] > max_abs) + max_abs = temp[i]; + } + + // Step 2: Compute dynamic scale factor + float fixed_point_range = (float)llr_max / (1 << llr_decimal); + float scale = fixed_point_range / (float)max_abs; + if (max_abs < fixed_point_range) { + scale = 1.0f; + } + + // Step 3: Scale and saturate + // SCALAR IMPLEMENTATION + // for (int i = 0; i < llr_len; i++) { + // float scaled = (float)llr[i] * scale; // map into fixed-point domain + // scaled = (int8_t)roundf(scaled * (1 << llr_decimal)); + // // Clamp to [-128, 127] + // if (scaled > llr_max) llr_scaled[i] = llr_max; + // else if (scaled < llr_min) llr_scaled[i] = llr_min; + // } + // VECTORIZED IMPLEMENTATION + simde__m128 scale_vec = simde_mm_set1_ps(scale); + simde__m128i llr_max_vec = simde_mm_set1_epi16(llr_max); + simde__m128i llr_min_vec = simde_mm_set1_epi16(llr_min); + simde__m128i decimal_shift = simde_mm_set1_epi16(1 << llr_decimal); + for (int i = 0; i < llr_len; i += 8) { + // load LLR values + simde__m128i llr_vec = simde_mm_loadu_si128((simde__m128i *)&llr[i]); + + // convert to float for scaling + simde__m128i llr_lo = simde_mm_cvtepi16_epi32(llr_vec); + simde__m128i llr_hi = simde_mm_cvtepi16_epi32(simde_mm_srli_si128(llr_vec, 8)); + simde__m128 float_lo = simde_mm_cvtepi32_ps(llr_lo); + simde__m128 float_hi = simde_mm_cvtepi32_ps(llr_hi); + + // scale + float_lo = simde_mm_mul_ps(float_lo, scale_vec); + float_hi = simde_mm_mul_ps(float_hi, scale_vec); + + // convert back to int16 with saturation + llr_lo = simde_mm_cvtps_epi32(float_lo); + llr_hi = simde_mm_cvtps_epi32(float_hi); + simde__m128i scaled_vec = simde_mm_packs_epi32(llr_lo, llr_hi); + + scaled_vec = simde_mm_mullo_epi16(scaled_vec, decimal_shift); + + // clamp to [llr_min, llr_max] + scaled_vec = simde_mm_min_epi16(scaled_vec, llr_max_vec); + scaled_vec = simde_mm_max_epi16(scaled_vec, llr_min_vec); + + // Pack to int8 and store + simde__m128i result = simde_mm_packs_epi16(scaled_vec, simde_mm_setzero_si128()); + simde_mm_storeu_si128((simde__m128i *)&llr_scaled[i], result); + } +} + int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_decoding_parameters) { pthread_mutex_lock(&decode_mutex); + int ret; + int socket_id = active_dev.info.socket_id; + const uint16_t num_segments = nb_segments_decoding(nrLDPC_slot_decoding_parameters); /* It is not unlikely that l_ol becomes big enough to overflow the stack @@ -913,26 +1265,38 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec */ uint8_t l_ol[num_segments * LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); - // hardcoded we use first device - struct active_device *ad = active_devs; - struct rte_bbdev_info info; - int ret; - rte_bbdev_info_get(ad->dev_id, &info); - int socket_id = GET_SOCKET(info.socket_id); // fill_queue_buffers -> init_op_data_objs - struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {ad->in_mbuf_pool, ad->hard_out_mbuf_pool}; + struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {active_dev.in_mbuf_pool, + active_dev.hard_out_mbuf_pool, + active_dev.harq_out_mbuf_pool}; struct data_buffers data_buffers; - struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&data_buffers.inputs, &data_buffers.hard_outputs}; - + struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&data_buffers.inputs, + &data_buffers.hard_outputs, + &data_buffers.harq_outputs}; + int8_t llr_size = (active_dev.info.drv.capabilities)[RTE_BBDEV_OP_LDPC_DEC].cap.ldpc_dec.llr_size; + int8_t llr_decimal = (active_dev.info.drv.capabilities)[RTE_BBDEV_OP_LDPC_DEC].cap.ldpc_dec.llr_decimals; int offset = 0; for (int h = 0; h < nrLDPC_slot_decoding_parameters->nb_TBs; ++h) { for (int r = 0; r < nrLDPC_slot_decoding_parameters->TBs[h].C; r++) { - uint16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); - memcpy(z_ol, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].llr, nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E * sizeof(uint16_t)); - simde__m128i *pv_ol128 = (simde__m128i *)z_ol; - simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset]; - for (int i = 0, j = 0; j < ((nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E + 15) >> 4); i += 2, j++) { - pl_ol128[j] = simde_mm_packs_epi16(pv_ol128[i], pv_ol128[i + 1]); + if (active_dev.is_t2) { + // For the T2, we simply saturate the LLRs. + uint16_t z_ol[LDPC_MAX_CB_SIZE] __attribute__((aligned(16))); + memcpy(z_ol, + nrLDPC_slot_decoding_parameters->TBs[h].segments[r].llr, + nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E * sizeof(uint16_t)); + simde__m128i *pv_ol128 = (simde__m128i *)z_ol; + simde__m128i *pl_ol128 = (simde__m128i *)&l_ol[offset]; + for (int i = 0, j = 0; j < ((nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E + 15) >> 4); i += 2, j++) { + pl_ol128[j] = simde_mm_packs_epi16(pv_ol128[i], pv_ol128[i + 1]); + } + } else { + llr_scaling(nrLDPC_slot_decoding_parameters->TBs[h].segments[r].llr, + nrLDPC_slot_decoding_parameters->TBs[h].segments[r].E, + &l_ol[offset], + llr_size, + llr_decimal, + nrLDPC_slot_decoding_parameters->TBs[h].nb_layers, + nrLDPC_slot_decoding_parameters->TBs[h].Qm); } offset += LDPC_MAX_CB_SIZE; } @@ -946,13 +1310,13 @@ int32_t nrLDPC_coding_decoder(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_dec nrLDPC_slot_decoding_parameters, mbuf_pools[type], type, - info.drv.min_alignment); + active_dev.info.drv.min_alignment); AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); } - ret = start_pmd_dec(ad, op_params, &data_buffers, nrLDPC_slot_decoding_parameters); + ret = start_pmd_dec(&active_dev, op_params, &data_buffers, nrLDPC_slot_decoding_parameters); if (ret < 0) { - LOG_E(PHY, "Couldn't start pmd dec\n"); + LOG_E(NR_PHY, "Couldn't start pmd dec\n"); } for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { @@ -973,27 +1337,28 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc const uint16_t num_segments = nb_segments_encoding(nrLDPC_slot_encoding_parameters); - // hardcoded to use the first found board - struct active_device *ad = active_devs; int ret; - struct rte_bbdev_info info; - rte_bbdev_info_get(ad->dev_id, &info); - int socket_id = GET_SOCKET(info.socket_id); - // fill_queue_buffers -> init_op_data_objs - struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {ad->in_mbuf_pool, ad->hard_out_mbuf_pool}; - struct data_buffers data_buffers; - struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {&data_buffers.inputs, &data_buffers.hard_outputs}; + int socket_id = active_dev.info.socket_id; - for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { + // fill_queue_buffers -> init_op_data_objs + struct rte_mempool *mbuf_pools[2] = {active_dev.in_mbuf_pool, active_dev.hard_out_mbuf_pool}; + struct data_buffers data_buffers; + struct rte_bbdev_op_data **queue_ops[2] = {&data_buffers.inputs, &data_buffers.hard_outputs}; + + for (enum op_data_type type = DATA_INPUT; type < 2; ++type) { ret = allocate_buffers_on_socket(queue_ops[type], num_segments * sizeof(struct rte_bbdev_op_data), socket_id); AssertFatal(ret == 0, "Couldn't allocate memory for rte_bbdev_op_data structs"); - ret = init_op_data_objs_enc(*queue_ops[type], nrLDPC_slot_encoding_parameters, mbuf_pools[type], type, info.drv.min_alignment); + ret = init_op_data_objs_enc(*queue_ops[type], + nrLDPC_slot_encoding_parameters, + mbuf_pools[type], + type, + active_dev.info.drv.min_alignment); AssertFatal(ret == 0, "Couldn't init rte_bbdev_op_data structs"); } - ret = start_pmd_enc(ad, op_params, &data_buffers, nrLDPC_slot_encoding_parameters); + ret = start_pmd_enc(&active_dev, op_params, &data_buffers, nrLDPC_slot_encoding_parameters); - for (enum op_data_type type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) { + for (enum op_data_type type = DATA_INPUT; type < 2; ++type) { for (int segment = 0; segment < num_segments; ++segment) rte_pktmbuf_free((*queue_ops[type])[segment].data); rte_free(*queue_ops[type]); @@ -1002,4 +1367,3 @@ int32_t nrLDPC_coding_encoder(nrLDPC_slot_encoding_parameters_t *nrLDPC_slot_enc pthread_mutex_unlock(&encode_mutex); return ret; } - diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.h similarity index 79% rename from openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h rename to openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.h index 642ac8f55a..0337202b9b 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/nrLDPC_coding_t2.h +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_aal/nrLDPC_coding_aal.h @@ -2,8 +2,8 @@ * Copyright(c) 2017 Intel Corporation */ -#ifndef _MAIN_H_ -#define _MAIN_H_ +#ifndef __NRLDPC_CODING_T2_H__ +#define __NRLDPC_CODING_T2_H__ #include #include @@ -17,6 +17,7 @@ enum op_data_type { DATA_INPUT = 0, DATA_HARD_OUTPUT, + DATA_HARQ_OUTPUT, DATA_NUM_TYPES, }; diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt index f96a2cfaca..8c2811e3a1 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt @@ -3,8 +3,4 @@ add_library(ldpc_segment OBJECT nrLDPC_coding_segment_decoder.c nrLDPC_coding_segment_encoder.c ) - -#ensure that the T header files are generated before targets depending on them -if (${T_TRACER}) - add_dependencies(ldpc_segment generate_T) -endif (${T_TRACER}) +target_link_libraries(ldpc_segment PUBLIC log_headers) diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c index c7bb47c581..3fece46ac8 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c @@ -215,8 +215,7 @@ static void nr_process_decode_segment(void *arg) ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////// pl =====> llrProcBuf ////////////////////////////////// - int decodeIterations = - LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode); + int decodeIterations = LDPCdecoder(p_decoderParms, l, llrProcBuf, p_procTime, rdata->abort_decode); if (decodeIterations < p_decoderParms->numMaxIter) { memcpy(rdata->c, llrProcBuf, K >> 3); diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt deleted file mode 100644 index f64384568a..0000000000 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_t2/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -########################################################## - -# LDPC offload library - AMD T2 Accelerator Card -########################################################## - -add_boolean_option(ENABLE_LDPC_T2 OFF "Build support for LDPC Offload to T2 library" OFF) - -if (ENABLE_LDPC_T2) - - pkg_check_modules(LIBDPDK_T2 REQUIRED libdpdk>=20.11.9) - - find_library(PMD_T2 NAMES rte_baseband_accl_ldpc HINTS ${LIBDPDK_T2_LIBRARY_DIRS}) - if (NOT PMD_T2) - message(FATAL_ERROR "could not find poll-mode driver for AccelerComm T2 LDPC Offload (rte_baseband_accl_ldpc.so)") - endif() - - message(STATUS "T2 build: use ${PMD_T2}") - add_library(ldpc_t2 MODULE nrLDPC_coding_t2.c) - - set_target_properties(ldpc_t2 PROPERTIES COMPILE_FLAGS "-DALLOW_EXPERIMENTAL_API") - set_target_properties(ldpc_t2 PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) - target_link_libraries(ldpc_t2 PRIVATE ldpc_gen_HEADERS ${LIBDPDK_T2_LDFLAGS} ${PMD_T2}) - - add_dependencies(nr-softmodem ldpc_t2) - add_dependencies(nr-uesoftmodem ldpc_t2) - add_dependencies(nr_ulsim ldpc_t2) - add_dependencies(nr_ulschsim ldpc_t2) - add_dependencies(nr_dlsim ldpc_t2) - add_dependencies(nr_dlschsim ldpc_t2) - -endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt index 0325858389..0d8f5571cd 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt @@ -16,12 +16,7 @@ if (ENABLE_LDPC_XDMA) ) target_include_directories(ldpc_xdma PRIVATE ../nrLDPC_coding_segment) - #ensure that the T header files are generated before targets depending on them - if (${T_TRACER}) - add_dependencies(ldpc_xdma generate_T) - endif (${T_TRACER}) - - target_link_libraries(ldpc_xdma PRIVATE ldpc_gen_HEADERS) + target_link_libraries(ldpc_xdma PRIVATE ldpc_gen_HEADERS log_headers) set_target_properties(ldpc_xdma PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_dependencies(nr-softmodem ldpc_xdma) diff --git a/openair1/PHY/CODING/nrLDPC_decoder/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_decoder/CMakeLists.txt new file mode 100644 index 0000000000..1734260e68 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_decoder/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(nrLDPC_tools) diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c index e2ed7fce10..d3b9a58da1 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c @@ -170,9 +170,6 @@ int32_t LDPCshutdown() } int32_t LDPCdecoder(t_nrLDPC_dec_params* p_decParams, - uint8_t harq_pid, - uint8_t ulsch_id, - uint8_t C, int8_t* p_llr, int8_t* p_out, t_nrLDPC_time_stats* p_profiler, diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c deleted file mode 100644 index 1766c0f072..0000000000 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c +++ /dev/null @@ -1,465 +0,0 @@ -/* - * 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.0 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - /*! \file nrLDPC_decoder_CL.c -* \brief ldpc decoder, openCL implementaion -* \author Francois TABURET -* \date 2021 -* \version 1.0 -* \note initial implem - translation of cuda version -*/ - - -#define MAX_ITERATION 2 -#define MC 1 - -#define MAX_OCLDEV 10 -#define MAX_OCLRUNTIME 5 - -typedef struct{ - char x; - char y; - short value; -} h_element; - -#ifdef NRLDPC_KERNEL_SOURCE -#include "nrLDPC_decoder_kernels_CL.c" -#else -/* uses HW component id for log messages ( --log_config.hw_log_level ) */ -#include -#include -#include -#include -#include "openair1/PHY/CODING/nrLDPC_extern.h" -#include "assertions.h" -#include "common/utils/LOG/log.h" - -#define CLSETKERNELARG(A,B,C,D) \ -rt=clSetKernelArg(A,B,C,D) ;\ -AssertFatal(rt == CL_SUCCESS, "Error %d setting kernel argument index %d\n" , (int)rt, B); - -#include "../nrLDPC_decoder_LYC/bgs/BG1_compact_in_C.h" - -typedef struct{ - cl_uint max_CU; - cl_uint max_WID; - size_t *max_WIS; -} ocldev_t; - -typedef struct { - cl_kernel cnp_kernel_1st; - cl_kernel cnp_kernel; - cl_kernel vnp_kernel_normal; - cl_kernel pack_decoded_bit; -} oclkernels_t; - -typedef struct{ - cl_uint num_devices; - cl_device_id devices[MAX_OCLDEV]; - ocldev_t ocldev[MAX_OCLDEV]; - cl_context context; - cl_program program; - cl_mem dev_h_compact1; - cl_mem dev_h_compact2; - cl_mem dev_const_llr; - cl_mem dev_llr; - cl_mem dev_dt; - cl_mem dev_tmp; - oclkernels_t kernels[MAX_OCLDEV]; - cl_command_queue queue[MAX_OCLDEV]; -} oclruntime_t; - -typedef struct{ - oclruntime_t runtime[MAX_OCLRUNTIME]; -} ocl_t; - - - -ocl_t ocl; - - -void set_compact_BG(int Zc,short BG){ - cl_uint rt; - int row,col; - if(BG == 1){ - row = 46; - col = 68; - } - else{ - row = 42; - col = 52; - } - int compact_row = 30; - int compact_col = 19; - if(BG==2){compact_row = 10, compact_col = 23;} - int memorySize_h_compact1 = row * compact_col * sizeof(h_element); - int memorySize_h_compact2 = compact_row * col * sizeof(h_element); - int lift_index = 0; - short lift_set[][9] = { - {2,4,8,16,32,64,128,256}, - {3,6,12,24,48,96,192,384}, - {5,10,20,40,80,160,320}, - {7,14,28,56,112,224}, - {9,18,36,72,144,288}, - {11,22,44,88,176,352}, - {13,26,52,104,208}, - {15,30,60,120,240}, - {0} - }; - - for(int i = 0; lift_set[i][0] != 0; i++){ - for(int j = 0; lift_set[i][j] != 0; j++){ - if(Zc == lift_set[i][j]){ - lift_index = i; - break; - } - } - } - printf("\nZc = %d BG = %d\n",Zc,BG); - ocl.runtime[0].dev_h_compact1 = clCreateBuffer(ocl.runtime[0].context, CL_MEM_READ_ONLY|CL_MEM_HOST_WRITE_ONLY, memorySize_h_compact1, NULL, (cl_int *)&rt); - AssertFatal(rt == CL_SUCCESS, "Error %d creating buffer dev_h_compact1 for platform %i \n" , (int)rt, 0); - ocl.runtime[0].dev_h_compact2 = clCreateBuffer(ocl.runtime[0].context, CL_MEM_READ_ONLY|CL_MEM_HOST_WRITE_ONLY, memorySize_h_compact2, NULL, (cl_int *)&rt); - AssertFatal(rt == CL_SUCCESS, "Error %d creating buffer dev_h_compact2 for platform %i \n" , (int)rt, 0); - h_element *h1; - h_element *h2; - switch(lift_index){ - case 0: - h1 = host_h_compact1_I0; - h2 = host_h_compact2_I0; - break; - case 1: - h1 = host_h_compact1_I1; - h2 = host_h_compact2_I1; - break; - case 2: - h1 = host_h_compact1_I2; - h2 = host_h_compact2_I2; - break; - case 3: - h1 = host_h_compact1_I3; - h2 = host_h_compact2_I3; - break; - case 4: - h1 = host_h_compact1_I4; - h2 = host_h_compact2_I4; - break; - case 5: - h1 = host_h_compact1_I5; - h2 = host_h_compact2_I5; - break; - case 6: - h1 = host_h_compact1_I6; - h2 = host_h_compact2_I6; - break; - case 7: - h1 = host_h_compact1_I7; - h2 = host_h_compact2_I7; - break; - default: - AssertFatal(0, "Invalid lift_index value %i\n" , lift_index); - break; - } - rt = clEnqueueWriteBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_h_compact1, CL_TRUE, 0,memorySize_h_compact1, h1, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d moving h_compact1 memory to pltf %i dev %i\n" , (int)rt, 0,0); - rt = clEnqueueWriteBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_h_compact2, CL_TRUE, 0,memorySize_h_compact2, h2, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d moving h_compact2 memory to pltf %i dev %i\n" , (int)rt, 0,0); - // return 0; -} -void cl_error_callback(const char* errinfo, const void* private_info, size_t cb, void* user_data) { - oclruntime_t *runtime = (oclruntime_t *)user_data; - LOG_E(HW,"OpenCL accelerator error %s\n", errinfo ); -} - -char *clutil_getstrdev(int intdev) { - static char retstring[255]=""; - char *retptr=retstring; - retptr+=sprintf(retptr,"0x%08x: ",(uint32_t)intdev); - if (intdev & CL_DEVICE_TYPE_CPU) - retptr+=sprintf(retptr,"%s","cpu "); - if (intdev & CL_DEVICE_TYPE_GPU) - retptr+=sprintf(retptr,"%s","gpu "); - if (intdev & CL_DEVICE_TYPE_ACCELERATOR) - retptr+=sprintf(retptr,"%s","acc "); - return retstring; -} - -void get_CompilErr(cl_program program, int pltf) { - - // Determine the size of the log - size_t log_size; - for(int i=0; i0 , "clGetPlatformIDs: no cl compatible platform found\n"); - for (int i=0 ; i<(int)num_platforms_found ; i++) { - char stringval[255]; - rt = clGetPlatformInfo(platforms[i],CL_PLATFORM_PROFILE, sizeof(stringval),stringval,NULL); - AssertFatal(rt == CL_SUCCESS, "clGetPlatformInfo PROFILE error %d\n" , (int)rt); - LOG_I(HW,"Platform %i, OpenCL profile %s\n", i,stringval ); - rt = clGetPlatformInfo(platforms[i],CL_PLATFORM_VERSION, sizeof(stringval),stringval,NULL); - AssertFatal(rt == CL_SUCCESS, "clGetPlatformInfo VERSION error %d\n" , (int)rt); - LOG_I(HW,"Platform %i, OpenCL version %s\n", i,stringval ); - rt = clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_ALL, sizeof(ocl.runtime[i].devices)/sizeof(cl_device_id),ocl.runtime[i].devices,&(ocl.runtime[i].num_devices)); - AssertFatal(rt == CL_SUCCESS, "clGetDeviceIDs error %d\n" , (int)rt); - int devok=0; - for (int j=0; j0) { - ocl.runtime[i].context = clCreateContext(NULL, ocl.runtime[i].num_devices, ocl.runtime[i].devices, cl_error_callback, &(ocl.runtime[i]), (cl_int *)&rt); - AssertFatal(rt == CL_SUCCESS, "Error %d creating context for platform %i\n" , (int)rt, i); - for(int dev=0; dev0, "No openCL device available to accelerate ldpc\n"); - return 0; -} - -int32_t LDPCshutdown() -{ - return 0; -} - -int32_t LDPCinit() -{ - // init_LLR_DMA(p_decParams, p_llr, p_out); - return 0; -} - -int32_t LDPCdecoder(t_nrLDPC_dec_params *p_decParams, - uint8_t harq_pid, - uint8_t ulsch_id, - uint8_t C, - int8_t *p_llr, - int8_t *p_out, - t_nrLDPC_time_stats *time_decoder, - decode_abort_t *ab) -{ - uint16_t Zc = p_decParams->Z; - uint8_t BG = p_decParams->BG; -// uint8_t numMaxIter = p_decParams->numMaxIter; - int block_length = p_decParams->Kprime; -// e_nrLDPC_outMode outMode = p_decParams->outMode; - uint8_t row,col; - if(BG == 1){ - row = 46; - col = 68; - } - else{ - row = 42; - col = 52; - } - -// alloc memory -// unsigned char *hard_decision = (unsigned char*)p_out; -// gpu - int memorySize_llr = col * Zc * sizeof(char) * MC; -// cudaCheck( cudaMemcpyToSymbol(dev_const_llr, p_llr, memorySize_llr_cuda) ); -// cudaCheck( cudaMemcpyToSymbol(dev_llr, p_llr, memorySize_llr_cuda) ); - set_compact_BG(p_decParams->Z, p_decParams->BG); - - int rt = - clEnqueueWriteBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_const_llr, CL_TRUE, 0, memorySize_llr, p_llr, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d moving p_llr data to read only memory in pltf %i dev %i\n" , (int)rt, 0,0); - rt = clEnqueueWriteBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_llr, CL_TRUE, 0, - memorySize_llr, p_llr, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d moving p_llr data to read-write memory in pltf %i dev %i\n" , (int)rt, 0,0); -// Define CUDA kernel dimension -// int blockSizeX = Zc; -// dim3 dimGridKernel1(row, MC, 1); // dim of the thread blocks -// dim3 dimBlockKernel1(blockSizeX, 1, 1); - -// dim3 dimGridKernel2(col, MC, 1); -// dim3 dimBlockKernel2(blockSizeX, 1, 1); -// cudaDeviceSynchronize(); - -// lauch kernel - size_t global_item_sizek0[2] = {row*Zc,MC}; // Process the entire lists - size_t global_item_sizek1[2] = {col*Zc,MC}; // Process the entire lists - size_t local_item_sizek[2] = {128,1}; // Divide work items into groups of 128 - - for(int ii = 0; ii < MAX_ITERATION; ii++){ - // first kernel - if(ii == 0){ -// ldpc_cnp_kernel_1st_iter -// <<>> -// ( BG, row, col, Zc); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 0, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_llr)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 1, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_dt)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 2, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_h_compact1)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 3, sizeof(int), (void *)&(BG)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 4, sizeof(int), (void *)&(row)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 5, sizeof(int), (void *)&(col)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel_1st, 6, sizeof(int), (void *)&(Zc)); - rt = clEnqueueNDRangeKernel(ocl.runtime[0].queue[0], ocl.runtime[0].kernels[0].cnp_kernel_1st, 2, NULL, - global_item_sizek0, local_item_sizek, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d enqueing cnp_kernel_1st \n" , (int)rt); - }else{ -// ldpc_cnp_kernel -// <<>> -// ( BG, row, col, Zc); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 0, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_llr)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 1, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_dt)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 2, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_h_compact1)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 3, sizeof(int), (void *)&(BG)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 4, sizeof(int), (void *)&(row)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 5, sizeof(int), (void *)&(col)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].cnp_kernel, 6, sizeof(int), (void *)&(Zc)); - rt = clEnqueueNDRangeKernel(ocl.runtime[0].queue[0], ocl.runtime[0].kernels[0].cnp_kernel, 2, NULL, - global_item_sizek0, local_item_sizek, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d enqueing cnp_kernel\n" , (int)rt); - } - // second kernel -// ldpc_vnp_kernel_normal -// <<>> -// // (dev_llr, dev_const_llr,BG, row, col, Zc); -// (BG, row, col, Zc); - CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 0, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_llr)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 1, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_dt)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 2, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_const_llr)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 3, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_h_compact2)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 4, sizeof(int), (void *)&(BG)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 5, sizeof(int), (void *)&(row)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 6, sizeof(int), (void *)&(col)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].vnp_kernel_normal, 7, sizeof(int), (void *)&(Zc)); - rt = clEnqueueNDRangeKernel(ocl.runtime[0].queue[0], ocl.runtime[0].kernels[0].vnp_kernel_normal, 2, NULL, - global_item_sizek1, local_item_sizek, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d enqueing vnp_kernel_normal \n" , (int)rt); - } - -// int pack = (block_length/128)+1; -// dim3 pack_block(pack, MC, 1); -// pack_decoded_bit<<>>( col, Zc); - CLSETKERNELARG(ocl.runtime[0].kernels[0].pack_decoded_bit, 0, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_llr)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].pack_decoded_bit, 1, sizeof(cl_mem), (void *)&(ocl.runtime[0].dev_tmp)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].pack_decoded_bit, 2, sizeof(int), (void *)&(col)); - CLSETKERNELARG(ocl.runtime[0].kernels[0].pack_decoded_bit, 3, sizeof(int), (void *)&(Zc)); - - // Execute the OpenCL kernel on the list - size_t global_item_size[2] = {block_length,MC}; // Process the entire lists - size_t local_item_size[2] = {128,1}; // Divide work items into groups of 128 - rt = clEnqueueNDRangeKernel(ocl.runtime[0].queue[0], ocl.runtime[0].kernels[0].pack_decoded_bit, 2, NULL, - global_item_size, local_item_size, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d enqueing pack_decoded_bit \n" , (int)rt); -// cudaCheck( cudaMemcpyFromSymbol((void*)hard_decision, (const void*)dev_tmp, (block_length/8)*sizeof(unsigned char)) ); -// cudaDeviceSynchronize(); - - rt = clEnqueueReadBuffer(ocl.runtime[0].queue[0], ocl.runtime[0].dev_tmp, CL_TRUE, 0, - (block_length/8)*sizeof(unsigned char) , p_llr, 0, NULL, NULL); - AssertFatal(rt == CL_SUCCESS, "Error %d moving p_llr data to pltf %i dev %i\n" , (int)rt, 0,0); - return MAX_ITERATION; - -} -#endif //NRLDPC_KERNEL_SOURCE diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.c deleted file mode 100644 index 42b25e41c0..0000000000 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_kernels_CL.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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.0 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file PHY/CODING/nrLDPC_decoder_kernels_CL.cl -* \brief kernel functions for ldpc decoder accelerated via openCL -* \author Francois TABURET -* \date 2021 -* \version 1.0 -* \company Nokia BellLabs France -* \email: francois.taburet@nokia-bell-labs.com -* \note initial implem - translation of cuda version -* \warning -*/ - - -//__global char dev_dt [46*68*384]; -//__local char *dev_t; -//__global char dev_llr[68*384]; -//__global unsigned char dev_tmp[68*384]; - - -#define INT32_MAX 2147483647 - -//__constant h_element dev_h_compact1[46*19] = {}; // used in kernel 1 -//__constant h_element dev_h_compact2[68*30] = {}; // used in kernel 2 - -// __device__ __constantant__ h_element dev_h_compact1[46*19]; // used in kernel 1 -// __device__ __constantant__ h_element dev_h_compact2[68*30]; // used in kernel 2 - -// row and col element count -__constant char h_ele_row_bg1_count[46] = { - 19, 19, 19, 19, 3, 8, 9, 7, 10, 9, - 7, 8, 7, 6, 7, 7, 6, 6, 6, 6, - 6, 6, 5, 5, 6, 5, 5, 4, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, - 4, 5, 4, 5, 5, 4}; -__constant char h_ele_col_bg1_count[68] = { - 30, 28, 7, 11, 9, 4, 8, 12, 8, 7, - 12, 10, 12, 11, 10, 7, 10, 10, 13, 7, - 8, 11, 12, 5, 6, 6, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1}; -__constant char h_ele_row_bg2_count[42] = { - 8, 10, 8, 10, 4, 6, 6, 6, 4, 5, - 5, 5, 4, 5, 5, 4, 5, 5, 4, 4, - 4, 4, 3, 4, 4, 3, 5, 3, 4, 3, - 5, 3, 4, 4, 4, 4, 4, 3, 4, 4, - 4, 4}; -__constant char h_ele_col_bg2_count[52] = { - 22, 23, 10, 5, 5, 14, 7, 13, 6, 8, - 9, 16, 9, 12, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1}; - - - -// Kernel 1 -__kernel void ldpc_cnp_kernel_1st_iter( __global char * dev_llr, __global char * dev_dt, __local h_element *dev_h_compact1, int BG, int row, int col, int Zc) -{ -// int iMCW = blockIdx.y; // codeword id -// int iBlkRow = blockIdx.x; // block row in h_base -// int iSubRow = threadIdx.x; // row index in sub_block of h_base -// if(blockIdx.x == 0 && threadIdx.x == 1) printf("cnp %d\n", threadIdx.x); - int iMCW = get_group_id(1); // codeword id - int iBlkRow = get_group_id(0); // block row in h_base - int iBlkCol; // block col in h_base - int iSubRow = get_local_id(0);; // row index in sub_block of h_base - int iCol; // overall col index in h_base - int offsetR; - int shift_t; - -// For 2-min algorithm. - int Q_sign = 0; - int sq; - int Q, Q_abs; - int R_temp; - - int sign = 1; - int rmin1 = INT32_MAX; - int rmin2 = INT32_MAX; - char idx_min = 0; - - h_element h_element_t; - int s = (BG==1)? h_ele_row_bg1_count[iBlkRow]:h_ele_row_bg2_count[iBlkRow]; - offsetR = (iMCW * row*col*Zc) + iBlkRow * Zc + iSubRow; // row*col*Zc = size of dev_dt -// if(blockIdx.x == 0 && threadIdx.x == 1) printf("s: %d, offset %d\n", s, offsetR); -// The 1st recursion - for(int i = 0; i < s; i++) // loop through all the ZxZ sub-blocks in a row - { - h_element_t = dev_h_compact1[i*row+iBlkRow]; // compact_col == row - - iBlkCol = h_element_t.y; - shift_t = h_element_t.value; - - shift_t = (iSubRow + shift_t) % Zc; - iCol = (iMCW * col*Zc) + iBlkCol * Zc + shift_t; // col*Zc = size of llr - Q = dev_llr[iCol]; - Q_abs = (Q>0)? Q : -Q; - sq = Q < 0; -// if(blockIdx.x == 0 && threadIdx.x == 1) printf("i %d, icol %d, Q: %d\n", i, iCol, Q); - // quick version - sign = sign * (1 - sq * 2); - Q_sign |= sq << i; - - if (Q_abs < rmin1){ - rmin2 = rmin1; - rmin1 = Q_abs; - idx_min = i; - } else if (Q_abs < rmin2){ - rmin2 = Q_abs; - } - } - -// if(blockIdx.x == 0 && threadIdx.x == 1)printf("min1 %d, min2 %d, min1_idx %d\n", rmin1, rmin2, idx_min); - -// The 2nd recursion - for(int i = 0; i < s; i++){ - // v0: Best performance so far. 0.75f is the value of alpha. - sq = 1 - 2 * ((Q_sign >> i) & 0x01); - R_temp = 0.75f * sign * sq * (i != idx_min ? rmin1 : rmin2); - // write results to global memory - h_element_t = dev_h_compact1[i*row+iBlkRow]; - int addr_temp = offsetR + h_element_t.y * row * Zc; - dev_dt[addr_temp] = R_temp; -// if(blockIdx.x == 0 && threadIdx.x == 1)printf("R_temp %d, temp_addr %d\n", R_temp, addr_temp); - } -} - -// Kernel_1 -__kernel void ldpc_cnp_kernel( __global char * dev_llr, __global char * dev_dt, __local h_element *dev_h_compact1, int BG, int row, int col, int Zc) -{ -// if(blockIdx.x == 0 && threadIdx.x == 1) printf("cnp\n"); -// int iMCW = blockIdx.y; -// int iBlkRow = blockIdx.x; // block row in h_base // block col in h_base -// int iSubRow = threadIdx.x; // row index in sub_block of h_base - int iMCW = get_group_id(1); - int iBlkRow = get_group_id(0); // block row in h_base - int iBlkCol; // block col in h_base - int iSubRow = get_local_id(0);; // row index in sub_block of h_base - int iCol; // overall col index in h_base - int offsetR; - int shift_t; - -// For 2-min algorithm. - int Q_sign = 0; - int sq; - int Q, Q_abs; - int R_temp; - - int sign = 1; - int rmin1 = INT32_MAX; - int rmin2 = INT32_MAX; - char idx_min = 0; - - h_element h_element_t; - int s = (BG==1)? h_ele_row_bg1_count[iBlkRow]: h_ele_row_bg2_count[iBlkRow]; - offsetR = (iMCW *row*col*Zc) + iBlkRow * Zc + iSubRow; // row * col * Zc = size of dev_dt -// if(blockIdx.x == 0 && threadIdx.x == 1) printf("s: %d, offset %d\n", s, offsetR); -// The 1st recursion - for(int i = 0; i < s; i++) // loop through all the ZxZ sub-blocks in a row - { - h_element_t = dev_h_compact1[i*row+iBlkRow]; - - iBlkCol = h_element_t.y; - shift_t = h_element_t.value; - shift_t = (iSubRow + shift_t) % Zc; - iCol = iBlkCol * Zc + shift_t; - - R_temp = dev_dt[offsetR + iBlkCol * row * Zc]; - - Q = dev_llr[iMCW * (col*Zc) + iCol] - R_temp; - Q_abs = (Q>0)? Q : -Q; -// if(blockIdx.x == 0 && threadIdx.x == 1) printf("i %d, icol %d, Q: %d\n", i, iCol, Q); - sq = Q < 0; - sign = sign * (1 - sq * 2); - Q_sign |= sq << i; - - if (Q_abs < rmin1){ - rmin2 = rmin1; - rmin1 = Q_abs; - idx_min = i; - } else if (Q_abs < rmin2){ - rmin2 = Q_abs; - } - - } - -// if(blockIdx.x == 0 && threadIdx.x == 1)printf("min1 %d, min2 %d, min1_idx %d\n", rmin1, rmin2, idx_min); - -// The 2nd recursion - for(int i = 0; i < s; i ++){ - sq = 1 - 2 * ((Q_sign >> i) & 0x01); - R_temp = 0.75f * sign * sq * (i != idx_min ? rmin1 : rmin2); - - - // write results to global memory - h_element_t = dev_h_compact1[i*row+iBlkRow]; - int addr_temp = h_element_t.y * row * Zc + offsetR; - dev_dt[addr_temp] = R_temp; -// if(blockIdx.x == 0 && threadIdx.x == 1)printf("R_temp %d, temp_addr %d\n", R_temp, addr_temp); - } -} - -// Kernel 2: VNP processing -__kernel void -ldpc_vnp_kernel_normal(__global char * dev_llr, __global char * dev_dt, __global char * dev_const_llr, __local h_element *dev_h_compact2, int BG, int row, int col, int Zc) -{ -// int iMCW = blockIdx.y; -// int iBlkCol = blockIdx.x; -// int iSubCol = threadIdx.x; - int iMCW = get_group_id(1); - int iBlkCol = get_group_id(0); - int iBlkRow; - int iSubCol = get_local_id(0); - int iRow; - int iCol; - - int shift_t, sf; - int APP; - - h_element h_element_t; - - // update all the llr values - iCol = iBlkCol * Zc + iSubCol; - APP = dev_const_llr[iMCW *col*Zc + iCol]; - int offsetDt = iMCW *row*col*Zc + iBlkCol * row * Zc; - int s = (BG==1)? h_ele_col_bg1_count[iBlkCol]:h_ele_col_bg2_count[iBlkCol]; - - for(int i = 0; i < s; i++) - { - h_element_t = dev_h_compact2[i*col+iBlkCol]; - - shift_t = h_element_t.value%Zc; - iBlkRow = h_element_t.x; - - sf = iSubCol - shift_t; - sf = (sf + Zc) % Zc; - - iRow = iBlkRow * Zc + sf; - APP = APP + dev_dt[offsetDt + iRow]; - } - if(APP > SCHAR_MAX) APP = SCHAR_MAX; - if(APP < SCHAR_MIN) APP = SCHAR_MIN; - // write back to device global memory - dev_llr[iMCW *col*Zc + iCol] = APP; -} - - -__kernel void pack_decoded_bit(__global unsigned char * dev_llr, __global unsigned char * dev_tmp, int col, int Zc) -{ -// int iMCW = blockIdx.y; -// int btid = threadIdx.x; - unsigned char tmp[128]; - int iMCW = get_group_id(1); - int btid = get_local_id(0); - int tid = iMCW * col*Zc + get_group_id(0)*128 + btid; - tmp[btid] = 0; - - if(dev_llr[tid] < 0){ - tmp[btid] = 1 << (7-(btid&7)); - } -// __syncthreads(); - - if(btid < 16){ - dev_tmp[iMCW * col*Zc + get_group_id(0)*16+btid] = 0; - for(int i = 0; i < 8; i++){ - dev_tmp[iMCW * col*Zc + get_group_id(0)*16+btid] += tmp[btid*8+i]; - } - } -} diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt index 26ef39408f..4b8dfcb446 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_tools/CMakeLists.txt @@ -1,7 +1,7 @@ -add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/generator_bnProc ldpc/generator_bnProc) -add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/generator_bnProc_avx512 ldpc/generator_bnProc_avx512) -add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/generator_cnProc ldpc/generator_cnProc) -add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/generator_cnProc_avx512 ldpc/generator_cnProc_avx512) +add_subdirectory(generator_bnProc ldpc/generator_bnProc) +add_subdirectory(generator_bnProc_avx512 ldpc/generator_bnProc_avx512) +add_subdirectory(generator_cnProc ldpc/generator_cnProc) +add_subdirectory(generator_cnProc_avx512 ldpc/generator_cnProc_avx512) # custom target to build all generators add_custom_target(ldpc_generators) diff --git a/openair1/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu b/openair1/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu index aa85716947..961fa36579 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu +++ b/openair1/PHY/CODING/nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu @@ -32,10 +32,13 @@ #include "bgs/BG2_I6" #include "bgs/BG2_I7" #define MAX_ITERATION 2 -#define MC 1 +#define MC 1 typedef void decode_abort_t; -#define cudaCheck(ans) { cudaAssert((ans), __FILE__, __LINE__); } +#define cudaCheck(ans) \ + { \ + cudaAssert((ans), __FILE__, __LINE__); \ + } inline void cudaAssert(cudaError_t code, const char *file, int line) { if (code != cudaSuccess) { @@ -44,23 +47,23 @@ inline void cudaAssert(cudaError_t code, const char *file, int line) } } -typedef struct{ +typedef struct { char x; char y; short value; } h_element; #include "bgs/BG1_compact_in_C.h" -__device__ char dev_const_llr[68*384]; -__device__ char dev_dt [46*68*384]; -__device__ char dev_llr[68*384]; -__device__ unsigned char dev_tmp[68*384]; +__device__ char dev_const_llr[68 * 384]; +__device__ char dev_dt[46 * 68 * 384]; +__device__ char dev_llr[68 * 384]; +__device__ unsigned char dev_tmp[68 * 384]; -h_element h_compact1 [46*23] = {}; -h_element h_compact2 [68*30] = {}; +h_element h_compact1[46 * 23] = {}; +h_element h_compact2[68 * 30] = {}; -__device__ h_element dev_h_compact1[46*23]; // used in kernel 1 -__device__ h_element dev_h_compact2[68*30]; // used in kernel 2 +__device__ h_element dev_h_compact1[46 * 23]; // used in kernel 1 +__device__ h_element dev_h_compact2[68 * 30]; // used in kernel 2 // __device__ __constant__ h_element dev_h_compact1[46*23]; // used in kernel 1 // __device__ __constant__ h_element dev_h_compact2[68*30]; // used in kernel 2 @@ -82,13 +85,13 @@ __global__ void warmup() // warm up gpu for time measurement } -extern "C" -void warmup_for_GPU(){ +extern "C" void warmup_for_GPU() +{ warmup<<<20, 1024>>>(); } -extern "C" -void set_compact_BG(int Zc,short BG){ +extern "C" void set_compact_BG(int Zc, short BG) +{ int row, col; if (BG == 1) { row = 46; @@ -162,7 +165,6 @@ void set_compact_BG(int Zc,short BG){ // return 0; } - // Kernel 1 __global__ void ldpc_cnp_kernel_1st_iter(/*char * dev_llr,*/ int BG, int row, int col, int Zc) { @@ -303,8 +305,7 @@ __global__ void ldpc_cnp_kernel(/*char * dev_llr, char * dev_dt,*/ int BG, int r } // Kernel 2: VNP processing -__global__ void -ldpc_vnp_kernel_normal(/*char * dev_llr, char * dev_dt, char * dev_const_llr,*/ int BG, int row, int col, int Zc) +__global__ void ldpc_vnp_kernel_normal(/*char * dev_llr, char * dev_dt, char * dev_const_llr,*/ int BG, int row, int col, int Zc) { int iMCW = blockIdx.y; int iBlkCol = blockIdx.x; @@ -344,7 +345,6 @@ ldpc_vnp_kernel_normal(/*char * dev_llr, char * dev_dt, char * dev_const_llr,*/ dev_llr[iMCW * col * Zc + iCol] = APP; } - __global__ void pack_decoded_bit(/*char *dev, unsigned char *host,*/ int col, int Zc) { __shared__ unsigned char tmp[128]; @@ -440,8 +440,8 @@ void read_BG(int BG, int *h, int row, int col) */ } -extern "C" -void init_LLR_DMA(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out){ +extern "C" void init_LLR_DMA(t_nrLDPC_dec_params *p_decParams, int8_t *p_llr, int8_t *p_out) +{ uint16_t Zc = p_decParams->Z; uint8_t BG = p_decParams->BG; uint8_t col; @@ -456,11 +456,11 @@ void init_LLR_DMA(t_nrLDPC_dec_params* p_decParams, int8_t* p_llr, int8_t* p_out cudaDeviceSynchronize(); } -using namespace std ; +using namespace std; /* from here: entry points in decoder shared lib */ -extern "C" -int ldpc_autoinit(void) { // called by the library loader +extern "C" int ldpc_autoinit(void) +{ // called by the library loader /*int devices = 0; cudaError_t err = cudaGetDeviceCount(&devices); @@ -493,7 +493,7 @@ int ldpc_autoinit(void) { // called by the library loader } */ warmup_for_GPU(); - return 0; + return 0; } extern "C" int32_t LDPCinit() @@ -505,14 +505,11 @@ extern "C" void LDPCshutdown() { } -extern "C" int32_t LDPCdecoder(t_nrLDPC_dec_params *p_decParams, - uint8_t harq_pid, - uint8_t ulsch_id, - uint8_t C, - int8_t *p_llr, - int8_t *p_out, - t_nrLDPC_time_stats *, - decode_abort_t *ab) +extern "C" int32_t LDPCdecoder(t_nrLDPC_dec_params *p_decParams, + int8_t *p_llr, + int8_t *p_out, + t_nrLDPC_time_stats *, + decode_abort_t *ab) { set_compact_BG(p_decParams->Z, p_decParams->BG); init_LLR_DMA(p_decParams, p_llr, p_out); @@ -529,7 +526,7 @@ extern "C" int32_t LDPCdecoder(t_nrLDPC_dec_params *p_decParams, } // alloc memory - unsigned char* hard_decision = (unsigned char*)p_out; + unsigned char *hard_decision = (unsigned char *)p_out; // gpu int memorySize_llr_cuda = col * Zc * sizeof(char) * MC; cudaCheck(cudaMemcpyToSymbol(dev_const_llr, p_llr, memorySize_llr_cuda)); @@ -563,7 +560,7 @@ extern "C" int32_t LDPCdecoder(t_nrLDPC_dec_params *p_decParams, dim3 pack_block(pack, MC, 1); pack_decoded_bit<<>>(/*dev_llr,*/ /*dev_tmp,*/ col, Zc); - cudaCheck(cudaMemcpyFromSymbol((void*)hard_decision, (const void*)dev_tmp, (block_length / 8) * sizeof(unsigned char))); + cudaCheck(cudaMemcpyFromSymbol((void *)hard_decision, (const void *)dev_tmp, (block_length / 8) * sizeof(unsigned char))); cudaDeviceSynchronize(); return MAX_ITERATION; diff --git a/openair1/PHY/CODING/nrLDPC_defs.h b/openair1/PHY/CODING/nrLDPC_defs.h index 2298400078..9abb048d83 100644 --- a/openair1/PHY/CODING/nrLDPC_defs.h +++ b/openair1/PHY/CODING/nrLDPC_defs.h @@ -29,7 +29,7 @@ \brief LDPC encoder parameter structure \var n_segments number of segments in the transport block \var first_seg index of the first segment of the subset to encode - within the transport block + within the transport block \var gen_code flag to generate parity check code 0 -> encoding 1 -> generate parity check code with AVX2 @@ -52,8 +52,8 @@ */ typedef struct { unsigned int n_segments; // optim8seg - unsigned int first_seg; // optim8segmulti - unsigned char gen_code; //orig + unsigned int first_seg; // optim8segmulti + unsigned char gen_code; // orig time_stats_t *tinput; time_stats_t *tprep; time_stats_t *tparity; @@ -75,22 +75,20 @@ typedef struct { typedef int32_t(LDPC_initfunc_t)(void); typedef int32_t(LDPC_shutdownfunc_t)(void); + // decoder interface /** \brief LDPC decoder API type definition \param p_decParams LDPC decoder parameters \param p_llr Input LLRs \param p_llrOut Output vector - \param p_profiler LDPC profiler statistics + \param time_stats time statistics + \param ab structure shared between tasks to stop all the tasks if one fails */ - typedef int32_t(LDPC_decoderfunc_t)(t_nrLDPC_dec_params *p_decParams, - uint8_t harq_pid, - uint8_t ulsch_id, - uint8_t C, int8_t *p_llr, int8_t *p_out, - t_nrLDPC_time_stats *, + t_nrLDPC_time_stats *time_stats, decode_abort_t *ab); typedef int32_t(LDPC_encoderfunc_t)(uint8_t **, uint8_t *, encoder_implemparams_t *); diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_alignr_byte_128.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_alignr_byte_128.c new file mode 100644 index 0000000000..493a33c735 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_alignr_byte_128.c @@ -0,0 +1,153 @@ +#ifndef __AVX2__ +#include "PHY/sse_intrin.h" +// generated code for Zc=384, byte encoding +static inline void ldpc384_byte(uint8_t *c,uint8_t *d) { + simde__m128i *csimd=(simde__m128i *)c,*dsimd=(simde__m128i *)d; + + simde__m128i *c2,*d2; + + int i2; + for (i2=0; i2<24; i2++) { + c2=&csimd[i2]; + d2=&dsimd[i2]; + +//row: 0 + d2[0]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[20],c2[19],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[5],c2[4],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[13],c2[12],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[18],c2[17],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[50],c2[49],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[100],c2[99],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[101],c2[100],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[117],c2[116],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[168],c2[167],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[149],c2[148],9),simde_mm_xor_si128(c2[144],simde_mm_xor_si128(c2[210],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[213],c2[212],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[252],c2[251],5),simde_mm_xor_si128(c2[249],simde_mm_xor_si128(c2[256],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[302],c2[301],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[299],c2[298],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[353],c2[352],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],11),simde_mm_xor_si128(c2[394],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[452],c2[451],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[436],c2[435],15),simde_mm_xor_si128(c2[498],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[535],c2[534],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[547],c2[546],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[548],c2[547],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[598],c2[597],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[647],c2[646],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[637],c2[636],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[646],c2[645],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[727],c2[726],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[724],c2[723],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[775],c2[774],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[791],c2[790],2),simde_mm_xor_si128(c2[787],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[824],c2[823],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[825],c2[824],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[880],c2[879],2),simde_mm_xor_si128(c2[879],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[881],c2[880],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[924],c2[923],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[933],c2[932],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[925],c2[924],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[981],c2[980],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[961],c2[960],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[963],c2[962],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1030],c2[1029],10),simde_mm_xor_si128(c2[1015],simde_mm_alignr_epi8(c2[1031],c2[1030],5))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 1 + d2[24]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[20],c2[19],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[20],c2[19],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[5],c2[4],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[13],c2[12],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[18],c2[17],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[50],c2[49],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[50],c2[49],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[100],c2[99],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[100],c2[99],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[101],c2[100],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[117],c2[116],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[168],c2[167],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[168],c2[167],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[149],c2[148],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[145],c2[144],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[211],c2[210],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[213],c2[212],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[252],c2[251],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[252],c2[251],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[250],c2[249],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[257],c2[256],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[302],c2[301],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[302],c2[301],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[299],c2[298],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[353],c2[352],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[395],c2[394],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[452],c2[451],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[452],c2[451],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],3),simde_mm_xor_si128(c2[436],simde_mm_xor_si128(c2[498],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[535],c2[534],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[535],c2[534],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[547],c2[546],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[548],c2[547],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[598],c2[597],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[647],c2[646],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[647],c2[646],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[637],c2[636],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[646],c2[645],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[727],c2[726],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[724],c2[723],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[775],c2[774],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[775],c2[774],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[791],c2[790],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[788],c2[787],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[824],c2[823],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[825],c2[824],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[880],c2[879],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[880],c2[879],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[880],c2[879],1),simde_mm_xor_si128(c2[881],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[924],c2[923],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[924],c2[923],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[933],c2[932],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[925],c2[924],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[981],c2[980],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[981],c2[980],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[961],c2[960],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[963],c2[962],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1030],c2[1029],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1030],c2[1029],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1016],c2[1015],1),simde_mm_alignr_epi8(c2[1031],c2[1030],6)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 2 + d2[48]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[20],c2[19],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[5],c2[4],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[13],c2[12],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[13],c2[12],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[18],c2[17],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[18],c2[17],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[50],c2[49],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[100],c2[99],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[101],c2[100],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[117],c2[116],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[117],c2[116],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[168],c2[167],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[149],c2[148],10),simde_mm_xor_si128(c2[144],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[145],c2[144],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[211],c2[210],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[213],c2[212],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[213],c2[212],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[252],c2[251],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[250],c2[249],1),simde_mm_xor_si128(c2[256],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[257],c2[256],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[302],c2[301],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[299],c2[298],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[299],c2[298],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[353],c2[352],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[353],c2[352],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],12),simde_mm_xor_si128(c2[394],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[395],c2[394],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[452],c2[451],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[436],c2[435],15),simde_mm_xor_si128(c2[436],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[535],c2[534],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[547],c2[546],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[548],c2[547],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[548],c2[547],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[598],c2[597],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[647],c2[646],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[637],c2[636],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[637],c2[636],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[646],c2[645],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[646],c2[645],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[727],c2[726],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[724],c2[723],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[724],c2[723],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[775],c2[774],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[791],c2[790],3),simde_mm_xor_si128(c2[787],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[788],c2[787],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[824],c2[823],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[825],c2[824],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[825],c2[824],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[880],c2[879],3),simde_mm_xor_si128(c2[879],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[880],c2[879],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[881],c2[880],15),simde_mm_xor_si128(c2[881],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[924],c2[923],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[933],c2[932],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[925],c2[924],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[925],c2[924],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[981],c2[980],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[961],c2[960],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[961],c2[960],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[963],c2[962],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[963],c2[962],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1030],c2[1029],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1016],c2[1015],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1031],c2[1030],5),simde_mm_alignr_epi8(c2[1031],c2[1030],6))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 3 + d2[72]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[20],c2[19],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[5],c2[4],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[13],c2[12],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[18],c2[17],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[18],c2[17],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[50],c2[49],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[100],c2[99],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[101],c2[100],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[117],c2[116],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[168],c2[167],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[149],c2[148],10),simde_mm_xor_si128(c2[144],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[145],c2[144],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[211],c2[210],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[213],c2[212],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[252],c2[251],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[250],c2[249],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[257],c2[256],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[302],c2[301],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[299],c2[298],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[353],c2[352],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[395],c2[394],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[452],c2[451],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],3),simde_mm_xor_si128(c2[436],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[535],c2[534],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[547],c2[546],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[548],c2[547],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[548],c2[547],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[598],c2[597],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[647],c2[646],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[637],c2[636],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[646],c2[645],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[646],c2[645],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[686],c2[685],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[727],c2[726],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[724],c2[723],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[775],c2[774],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[791],c2[790],3),simde_mm_xor_si128(c2[787],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[788],c2[787],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[824],c2[823],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[825],c2[824],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[880],c2[879],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[880],c2[879],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[881],c2[880],15),simde_mm_xor_si128(c2[881],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[924],c2[923],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[933],c2[932],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[925],c2[924],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[981],c2[980],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[961],c2[960],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[963],c2[962],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[963],c2[962],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1030],c2[1029],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1016],c2[1015],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1031],c2[1030],5),simde_mm_alignr_epi8(c2[1031],c2[1030],6)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 4 + d2[96]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[21],c2[20],12),simde_mm_alignr_epi8(c2[60],c2[59],5)); + +//row: 5 + d2[120]=simde_mm_xor_si128(c2[5],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[15],c2[14],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[4],c2[3],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[13],c2[12],3),simde_mm_xor_si128(c2[59],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[50],c2[49],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[49],c2[48],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[109],c2[108],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[111],c2[110],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[103],c2[102],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[153],c2[152],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[159],c2[158],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[154],c2[153],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[152],c2[151],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[196],c2[195],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[199],c2[198],9),simde_mm_xor_si128(c2[195],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[262],c2[261],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[259],c2[258],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[242],c2[241],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[312],c2[311],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[308],c2[307],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[311],c2[310],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[343],c2[342],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[339],c2[338],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[356],c2[355],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[391],c2[390],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[404],c2[403],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[398],c2[397],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[438],c2[437],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[453],c2[452],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[446],c2[445],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[484],c2[483],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[498],c2[497],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[545],c2[544],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[533],c2[532],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[533],c2[532],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[587],c2[586],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[584],c2[583],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[577],c2[576],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[587],c2[586],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[633],c2[632],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[647],c2[646],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[632],c2[631],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[696],c2[695],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[688],c2[687],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[696],c2[695],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[744],c2[743],4),simde_mm_xor_si128(c2[736],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[785],c2[784],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[776],c2[775],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[773],c2[772],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[784],c2[783],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[833],c2[832],15),simde_mm_xor_si128(c2[834],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[821],c2[820],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[865],c2[864],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[865],c2[864],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[867],c2[866],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[934],c2[933],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[919],c2[918],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[935],c2[934],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[967],c2[966],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[971],c2[970],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[973],c2[972],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1016],c2[1015],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1025],c2[1024],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1017],c2[1016],2),simde_mm_alignr_epi8(c2[1012],c2[1011],3))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 6 + d2[144]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[18],c2[17],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[305],c2[304],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[550],c2[549],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[832],c2[831],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[866],c2[865],2),simde_mm_alignr_epi8(c2[975],c2[974],1)))))))); + +//row: 7 + d2[168]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1],c2[0],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[52],c2[51],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[212],c2[211],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[403],c2[402],2),simde_mm_alignr_epi8(c2[680],c2[679],2)))))); + +//row: 8 + d2[192]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[24],c2[23],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[6],c2[5],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[9],c2[8],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[16],c2[15],7),simde_mm_xor_si128(c2[17],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[24],c2[23],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[24],c2[23],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[22],c2[21],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[4],c2[3],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[4],c2[3],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[20],c2[19],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[60],c2[59],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[68],c2[67],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[51],c2[50],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[51],c2[50],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[58],c2[57],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[65],c2[64],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[65],c2[64],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[60],c2[59],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[104],c2[103],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[110],c2[109],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[105],c2[104],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[112],c2[111],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[97],c2[96],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[104],c2[103],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[104],c2[103],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[148],c2[147],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[154],c2[153],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[153],c2[152],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[160],c2[159],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[149],c2[148],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[155],c2[154],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[155],c2[154],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[155],c2[154],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[215],c2[214],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[197],c2[196],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[193],c2[192],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[200],c2[199],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[200],c2[199],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[214],c2[213],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[196],c2[195],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[196],c2[195],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[256],c2[255],8),simde_mm_xor_si128(c2[262],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[254],c2[253],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[260],c2[259],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[261],c2[260],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[243],c2[242],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[243],c2[242],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[306],c2[305],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[289],c2[288],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[303],c2[302],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[309],c2[308],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[309],c2[308],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[305],c2[304],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[312],c2[311],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[312],c2[311],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[337],c2[336],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[344],c2[343],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[340],c2[339],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[340],c2[339],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[350],c2[349],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[385],c2[384],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[392],c2[391],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[399],c2[398],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[392],c2[391],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[399],c2[398],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[399],c2[398],3),simde_mm_xor_si128(c2[432],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[439],c2[438],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[448],c2[447],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[454],c2[453],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[441],c2[440],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[447],c2[446],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[447],c2[446],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[503],c2[502],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[485],c2[484],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[493],c2[492],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[493],c2[492],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],15),simde_mm_xor_si128(c2[539],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[546],c2[545],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[551],c2[550],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[534],c2[533],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[552],c2[551],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[534],c2[533],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[534],c2[533],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[582],c2[581],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[588],c2[587],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[585],c2[584],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[595],c2[594],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[627],c2[626],8),simde_mm_xor_si128(c2[633],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[641],c2[640],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[648],c2[647],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[648],c2[647],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[626],c2[625],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[632],c2[631],15),simde_mm_xor_si128(c2[632],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[690],c2[689],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[673],c2[672],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[682],c2[681],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[689],c2[688],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[689],c2[688],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[690],c2[689],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[696],c2[695],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[696],c2[695],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[738],c2[737],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[721],c2[720],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[731],c2[730],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[737],c2[736],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[728],c2[727],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],15),simde_mm_xor_si128(c2[734],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[779],c2[778],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[786],c2[785],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[771],c2[770],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[777],c2[776],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[792],c2[791],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[771],c2[770],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[828],c2[827],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[834],c2[833],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[829],c2[828],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[839],c2[838],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[822],c2[821],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[822],c2[821],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[884],c2[883],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[866],c2[865],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[884],c2[883],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[866],c2[865],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[866],c2[865],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[886],c2[885],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[868],c2[867],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[868],c2[867],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[928],c2[927],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[934],c2[933],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[913],c2[912],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[920],c2[919],6),simde_mm_xor_si128(c2[929],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[936],c2[935],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[936],c2[935],8),simde_mm_xor_si128(c2[926],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[961],c2[960],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[968],c2[967],5),simde_mm_xor_si128(c2[965],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[972],c2[971],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[972],c2[971],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[967],c2[966],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[974],c2[973],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[974],c2[973],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1010],c2[1009],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1017],c2[1016],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1020],c2[1019],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1026],c2[1025],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1011],c2[1010],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1017],c2[1016],15),simde_mm_xor_si128(c2[1017],c2[1031])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 9 + d2[216]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[63],c2[62],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[501],c2[500],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[537],c2[536],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[628],c2[627],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[868],c2[867],15),simde_mm_alignr_epi8(c2[966],c2[965],2)))))))); + +//row: 10 + d2[240]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[55],c2[54],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[118],c2[117],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[343],c2[342],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[408],c2[407],15),simde_mm_alignr_epi8(c2[695],c2[694],2)))))); + +//row: 11 + d2[264]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[17],c2[16],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[3],c2[2],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[3],c2[2],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[2],c2[1],10),simde_mm_xor_si128(c2[12],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[21],c2[20],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[15],c2[14],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1],c2[0],8),simde_mm_xor_si128(c2[3],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[71],c2[70],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[61],c2[60],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[71],c2[70],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[51],c2[50],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[61],c2[60],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[55],c2[54],6),simde_mm_xor_si128(c2[96],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[107],c2[106],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[107],c2[106],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[98],c2[97],10),simde_mm_xor_si128(c2[108],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[114],c2[113],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[100],c2[99],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[164],c2[163],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[151],c2[150],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[151],c2[150],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[146],c2[145],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[156],c2[155],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[165],c2[164],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[152],c2[151],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[207],c2[206],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[194],c2[193],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],10),simde_mm_xor_si128(c2[196],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[207],c2[206],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[193],c2[192],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[249],c2[248],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[259],c2[258],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[259],c2[258],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[246],c2[245],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[257],c2[256],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[253],c2[252],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[264],c2[263],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[299],c2[298],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[309],c2[308],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[309],c2[308],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[295],c2[294],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[306],c2[305],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[298],c2[297],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[308],c2[307],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[354],c2[353],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[340],c2[339],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[350],c2[349],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[360],c2[359],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[343],c2[342],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[353],c2[352],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[402],c2[401],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[391],c2[390],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[402],c2[401],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[385],c2[384],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[395],c2[394],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[449],c2[448],11),simde_mm_xor_si128(c2[435],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[436],c2[435],1),simde_mm_xor_si128(c2[440],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[451],c2[450],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[433],c2[432],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[495],c2[494],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[482],c2[481],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[482],c2[481],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[485],c2[484],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[496],c2[495],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[486],c2[485],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[496],c2[495],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[532],c2[531],11),simde_mm_xor_si128(c2[542],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[543],c2[542],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[544],c2[543],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[530],c2[529],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[544],c2[543],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[531],c2[530],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[598],c2[597],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[585],c2[584],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[585],c2[584],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[595],c2[594],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[581],c2[580],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[588],c2[587],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[598],c2[597],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[577],c2[576],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[644],c2[643],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[634],c2[633],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[644],c2[643],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[643],c2[642],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[629],c2[628],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[683],c2[682],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[693],c2[692],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[675],c2[674],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[685],c2[684],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[683],c2[682],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[693],c2[692],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[731],c2[730],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[741],c2[740],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[741],c2[740],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[724],c2[723],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[721],c2[720],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[731],c2[730],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[772],c2[771],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[782],c2[781],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[782],c2[781],14),simde_mm_xor_si128(c2[787],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[784],c2[783],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[771],c2[770],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[771],c2[770],15),simde_mm_xor_si128(c2[820],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[831],c2[830],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[822],c2[821],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[832],c2[831],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[832],c2[831],10),simde_mm_xor_si128(c2[818],simde_mm_xor_si128(c2[876],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[887],c2[886],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[887],c2[886],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[876],c2[875],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[887],c2[886],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[878],c2[877],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[865],c2[864],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[921],c2[920],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[931],c2[930],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[931],c2[930],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[930],c2[929],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[916],c2[915],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[922],c2[921],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[933],c2[932],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[978],c2[977],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[964],c2[963],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[964],c2[963],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[982],c2[981],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[969],c2[968],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[984],c2[983],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[970],c2[969],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1027],c2[1026],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1013],c2[1012],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1013],c2[1012],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1012],c2[1011],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1023],c2[1022],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1028],c2[1027],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1014],c2[1013],9),simde_mm_alignr_epi8(c2[1020],c2[1019],12)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 12 + d2[288]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[5],c2[4],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[60],c2[59],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[491],c2[490],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[543],c2[542],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[628],c2[627],2),simde_mm_alignr_epi8(c2[869],c2[868],10)))))); + +//row: 13 + d2[312]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[19],c2[18],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[19],c2[18],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[4],c2[3],15),simde_mm_xor_si128(c2[12],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[17],c2[16],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[20],c2[19],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[49],c2[48],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[49],c2[48],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[63],c2[62],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[53],c2[52],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[99],c2[98],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[99],c2[98],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[100],c2[99],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[116],c2[115],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[167],c2[166],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[167],c2[166],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[148],c2[147],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[168],c2[167],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[156],c2[155],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[210],c2[209],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[212],c2[211],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[209],c2[208],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[251],c2[250],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[251],c2[250],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[249],c2[248],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[256],c2[255],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[298],c2[297],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[300],c2[299],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[356],c2[355],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[352],c2[351],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[345],c2[344],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[353],c2[352],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[404],c2[403],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[394],c2[393],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[387],c2[386],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[451],c2[450],15),simde_mm_xor_si128(c2[451],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[443],c2[442],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[436],c2[435],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[498],c2[497],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[498],c2[497],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[488],c2[487],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[488],c2[487],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[534],c2[533],15),simde_mm_xor_si128(c2[534],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[546],c2[545],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[547],c2[546],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[577],c2[576],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[577],c2[576],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[597],c2[596],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[590],c2[589],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[646],c2[645],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[646],c2[645],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[636],c2[635],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[645],c2[644],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[685],c2[684],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[677],c2[676],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[685],c2[684],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[733],c2[732],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[733],c2[732],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[726],c2[725],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[723],c2[722],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[790],c2[789],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[787],c2[786],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[823],c2[822],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[824],c2[823],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[834],c2[833],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[879],c2[878],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[879],c2[878],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[879],c2[878],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[881],c2[880],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[923],c2[922],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[923],c2[922],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[932],c2[931],14),simde_mm_xor_si128(c2[924],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[980],c2[979],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[980],c2[979],13),simde_mm_xor_si128(c2[960],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[962],c2[961],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[968],c2[967],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1029],c2[1028],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1029],c2[1028],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1015],c2[1014],3),simde_mm_alignr_epi8(c2[1030],c2[1029],8)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 14 + d2[336]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[9],c2[8],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[592],c2[591],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[729],c2[728],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[838],c2[837],11),simde_mm_alignr_epi8(c2[1009],c2[1008],12)))))); + +//row: 15 + d2[360]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[13],c2[12],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[22],c2[21],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[6],c2[5],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[11],c2[10],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[11],c2[10],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[16],c2[15],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[67],c2[66],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[71],c2[70],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[71],c2[70],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[49],c2[48],2),simde_mm_xor_si128(c2[116],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[118],c2[117],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[110],c2[109],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[160],c2[159],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[166],c2[165],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[161],c2[160],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[161],c2[160],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[203],c2[202],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[206],c2[205],10),simde_mm_xor_si128(c2[202],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[203],c2[202],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[245],c2[244],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[242],c2[241],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[249],c2[248],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[295],c2[294],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[291],c2[290],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[294],c2[293],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[294],c2[293],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[350],c2[349],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[339],c2[338],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[339],c2[338],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[398],c2[397],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[387],c2[386],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[445],c2[444],11),simde_mm_xor_si128(c2[436],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[453],c2[452],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[491],c2[490],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[482],c2[481],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[482],c2[481],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[494],c2[493],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[552],c2[551],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[594],c2[593],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[584],c2[583],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[584],c2[583],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[640],c2[639],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[639],c2[638],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[639],c2[638],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[644],c2[643],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[679],c2[678],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[695],c2[694],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[679],c2[678],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[679],c2[678],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[727],c2[726],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[744],c2[743],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[741],c2[740],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[792],c2[791],8),simde_mm_xor_si128(c2[783],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[780],c2[779],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[780],c2[779],14),simde_mm_xor_si128(c2[816],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[818],c2[817],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[828],c2[827],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[828],c2[827],10),simde_mm_xor_si128(c2[872],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[874],c2[873],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[874],c2[873],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[868],c2[867],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[917],c2[916],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[926],c2[925],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[918],c2[917],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[974],c2[973],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[978],c2[977],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[980],c2[979],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[980],c2[979],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1023],c2[1022],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1032],c2[1031],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1024],c2[1023],2),simde_mm_alignr_epi8(c2[1024],c2[1023],3))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 16 + d2[384]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[9],c2[8],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[17],c2[16],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[21],c2[20],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[53],c2[52],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[68],c2[67],3),simde_mm_xor_si128(c2[57],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[49],c2[48],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[103],c2[102],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[105],c2[104],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[97],c2[96],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[147],c2[146],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[153],c2[152],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[148],c2[147],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[166],c2[165],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[214],c2[213],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[193],c2[192],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[213],c2[212],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[255],c2[254],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[253],c2[252],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[260],c2[259],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[306],c2[305],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[302],c2[301],10),simde_mm_xor_si128(c2[304],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[337],c2[336],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[350],c2[349],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[385],c2[384],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[398],c2[397],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[392],c2[391],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[456],c2[455],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[447],c2[446],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[440],c2[439],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[502],c2[501],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[492],c2[491],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[492],c2[491],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[539],c2[538],6),simde_mm_xor_si128(c2[550],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[551],c2[550],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[532],c2[531],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[581],c2[580],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[577],c2[576],15),simde_mm_xor_si128(c2[594],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[626],c2[625],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[641],c2[640],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[625],c2[624],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[690],c2[689],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[682],c2[681],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[689],c2[688],13),simde_mm_xor_si128(c2[737],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[730],c2[729],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[727],c2[726],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[779],c2[778],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[770],c2[769],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[791],c2[790],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[827],c2[826],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[828],c2[827],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[839],c2[838],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[883],c2[882],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[883],c2[882],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[885],c2[884],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[927],c2[926],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[913],c2[912],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[929],c2[928],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[961],c2[960],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[965],c2[964],6),simde_mm_xor_si128(c2[966],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[979],c2[978],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1010],c2[1009],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1019],c2[1018],9),simde_mm_alignr_epi8(c2[1010],c2[1009],14))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 17 + d2[408]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[17],c2[16],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[691],c2[690],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[839],c2[838],6),simde_mm_alignr_epi8(c2[1032],c2[1031],7))))); + +//row: 18 + d2[432]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[587],c2[586],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[642],c2[641],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[873],c2[872],4),simde_mm_alignr_epi8(c2[913],c2[912],4))))); + +//row: 19 + d2[456]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[62],c2[61],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[358],c2[357],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[400],c2[399],2),simde_mm_alignr_epi8(c2[493],c2[492],5))))); + +//row: 20 + d2[480]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[9],c2[8],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[17],c2[16],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[21],c2[20],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[12],c2[11],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[53],c2[52],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[68],c2[67],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[58],c2[57],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[103],c2[102],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[105],c2[104],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[97],c2[96],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[147],c2[146],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[153],c2[152],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[148],c2[147],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[157],c2[156],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[214],c2[213],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[193],c2[192],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[213],c2[212],14),simde_mm_xor_si128(c2[255],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[253],c2[252],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[260],c2[259],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[306],c2[305],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[302],c2[301],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[305],c2[304],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[337],c2[336],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[350],c2[349],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[385],c2[384],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[398],c2[397],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[392],c2[391],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[456],c2[455],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[447],c2[446],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[440],c2[439],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[449],c2[448],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[502],c2[501],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[492],c2[491],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[492],c2[491],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[539],c2[538],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[551],c2[550],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[551],c2[550],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[550],c2[549],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[581],c2[580],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[578],c2[577],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[595],c2[594],2),simde_mm_xor_si128(c2[626],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[641],c2[640],3),simde_mm_xor_si128(c2[625],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[690],c2[689],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[682],c2[681],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[689],c2[688],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[738],c2[737],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[730],c2[729],14),simde_mm_xor_si128(c2[727],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[779],c2[778],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[770],c2[769],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[791],c2[790],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[827],c2[826],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[828],c2[827],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[839],c2[838],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[883],c2[882],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[883],c2[882],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[885],c2[884],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[927],c2[926],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[913],c2[912],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[929],c2[928],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[961],c2[960],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[965],c2[964],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[967],c2[966],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1010],c2[1009],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1019],c2[1018],11),c2[1010])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 21 + d2[504]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[61],c2[60],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[247],c2[246],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[789],c2[788],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[974],c2[973],5),simde_mm_alignr_epi8(c2[1015],c2[1014],1))))); + +//row: 22 + d2[528]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[2],c2[1],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[577],c2[576],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[639],c2[638],9),simde_mm_alignr_epi8(c2[818],c2[817],6)))); + +//row: 23 + d2[552]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[50],c2[49],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[102],c2[101],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[484],c2[483],13),simde_mm_alignr_epi8(c2[866],c2[865],11)))); + +//row: 24 + d2[576]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[20],c2[19],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[4],c2[3],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[8],c2[7],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[19],c2[18],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[55],c2[54],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[69],c2[68],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[114],c2[113],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[116],c2[115],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[108],c2[107],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[158],c2[157],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[164],c2[163],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[159],c2[158],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[154],c2[153],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[201],c2[200],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[204],c2[203],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[200],c2[199],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[207],c2[206],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[242],c2[241],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[264],c2[263],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[247],c2[246],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[293],c2[292],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[289],c2[288],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[292],c2[291],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[348],c2[347],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[344],c2[343],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[337],c2[336],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[396],c2[395],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[385],c2[384],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[403],c2[402],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[443],c2[442],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[434],c2[433],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[451],c2[450],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[489],c2[488],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[503],c2[502],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[503],c2[502],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[550],c2[549],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[538],c2[537],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[538],c2[537],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[550],c2[549],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[592],c2[591],11),simde_mm_xor_si128(c2[588],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[582],c2[581],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[637],c2[636],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[628],c2[627],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[636],c2[635],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[677],c2[676],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[693],c2[692],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[676],c2[675],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[725],c2[724],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[741],c2[740],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[738],c2[737],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[790],c2[789],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[781],c2[780],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[778],c2[777],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[838],c2[837],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[839],c2[838],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[826],c2[825],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[870],c2[869],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[870],c2[869],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[914],c2[913],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[924],c2[923],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[916],c2[915],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[972],c2[971],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[976],c2[975],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[978],c2[977],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1021],c2[1020],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1030],c2[1029],10),simde_mm_alignr_epi8(c2[1021],c2[1020],15))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 25 + d2[600]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[53],c2[52],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[290],c2[289],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[360],c2[359],15),simde_mm_alignr_epi8(c2[692],c2[691],8)))); + +//row: 26 + d2[624]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[5],c2[4],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[102],c2[101],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[197],c2[196],12),simde_mm_alignr_epi8(c2[729],c2[728],8)))); + +//row: 27 + d2[648]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[61],c2[60],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[301],c2[300],2),simde_mm_alignr_epi8(c2[391],c2[390],5))); + +//row: 28 + d2[672]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[14],c2[13],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[194],c2[193],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[928],c2[927],4),simde_mm_alignr_epi8(c2[1026],c2[1025],2)))); + +//row: 29 + d2[696]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1],c2[0],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[18],c2[17],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[55],c2[54],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[69],c2[68],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[59],c2[58],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[59],c2[58],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[105],c2[104],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[106],c2[105],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[98],c2[97],7),simde_mm_xor_si128(c2[148],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[154],c2[153],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[149],c2[148],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[149],c2[148],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[215],c2[214],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[194],c2[193],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[215],c2[214],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[215],c2[214],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[257],c2[256],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[254],c2[253],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[261],c2[260],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[307],c2[306],7),simde_mm_xor_si128(c2[303],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[306],c2[305],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[306],c2[305],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[338],c2[337],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[358],c2[357],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[351],c2[350],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[351],c2[350],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[386],c2[385],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[399],c2[398],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[393],c2[392],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[393],c2[392],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[433],c2[432],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[449],c2[448],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[441],c2[440],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[503],c2[502],15),simde_mm_xor_si128(c2[493],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[494],c2[493],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[494],c2[493],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[552],c2[551],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[552],c2[551],15),simde_mm_xor_si128(c2[528],simde_mm_xor_si128(c2[582],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[579],c2[578],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[596],c2[595],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[596],c2[595],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[628],c2[627],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[642],c2[641],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[627],c2[626],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[627],c2[626],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[691],c2[690],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[683],c2[682],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[691],c2[690],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[691],c2[690],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[673],c2[672],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[739],c2[738],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[732],c2[731],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[729],c2[728],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[780],c2[779],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[772],c2[771],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[792],c2[791],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[792],c2[791],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[829],c2[828],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[830],c2[829],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[840],c2[839],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[840],c2[839],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[885],c2[884],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[884],c2[883],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[886],c2[885],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[886],c2[885],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[874],c2[873],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[929],c2[928],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[914],c2[913],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[930],c2[929],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[962],c2[961],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[966],c2[965],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[968],c2[967],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[968],c2[967],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1011],c2[1010],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1020],c2[1019],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1012],c2[1011],3),simde_mm_alignr_epi8(c2[1012],c2[1011],4))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 30 + d2[720]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1],c2[0],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[11],c2[10],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[19],c2[18],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[19],c2[18],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[55],c2[54],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[70],c2[69],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[70],c2[69],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[60],c2[59],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[60],c2[59],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[105],c2[104],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[107],c2[106],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[99],c2[98],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[99],c2[98],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[149],c2[148],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[155],c2[154],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[150],c2[149],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[150],c2[149],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[216],c2[215],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[195],c2[194],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[195],c2[194],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[215],c2[214],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[215],c2[214],14),simde_mm_xor_si128(c2[257],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[255],c2[254],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[262],c2[261],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[262],c2[261],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[308],c2[307],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[304],c2[303],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[304],c2[303],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[307],c2[306],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[307],c2[306],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[339],c2[338],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[359],c2[358],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[359],c2[358],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[352],c2[351],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[352],c2[351],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[387],c2[386],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[400],c2[399],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[400],c2[399],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[394],c2[393],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[394],c2[393],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[434],c2[433],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[449],c2[448],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[442],c2[441],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[442],c2[441],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[504],c2[503],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[494],c2[493],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[494],c2[493],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[494],c2[493],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[494],c2[493],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[495],c2[494],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[541],c2[540],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[529],c2[528],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[529],c2[528],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[529],c2[528],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[583],c2[582],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[580],c2[579],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[597],c2[596],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[597],c2[596],2),simde_mm_xor_si128(c2[628],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[643],c2[642],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[643],c2[642],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[627],c2[626],15),simde_mm_xor_si128(c2[627],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[641],c2[640],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[692],c2[691],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[684],c2[683],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[684],c2[683],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[691],c2[690],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[691],c2[690],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[740],c2[739],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[732],c2[731],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[729],c2[728],15),simde_mm_xor_si128(c2[729],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[781],c2[780],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[772],c2[771],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[769],c2[768],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[769],c2[768],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[829],c2[828],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[830],c2[829],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[830],c2[829],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[817],c2[816],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[817],c2[816],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[885],c2[884],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[885],c2[884],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[885],c2[884],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[887],c2[886],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[887],c2[886],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[929],c2[928],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[915],c2[914],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[931],c2[930],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[931],c2[930],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[963],c2[962],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[967],c2[966],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[967],c2[966],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[969],c2[968],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[969],c2[968],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1012],c2[1011],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1021],c2[1020],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1012],c2[1011],15),c2[1012]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 31 + d2[744]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[12],c2[11],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[12],c2[11],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[21],c2[20],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[21],c2[20],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[5],c2[4],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[5],c2[4],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[66],c2[65],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[66],c2[65],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[56],c2[55],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[56],c2[55],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[70],c2[69],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[70],c2[69],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[70],c2[69],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[55],c2[54],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[116],c2[115],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[116],c2[115],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[117],c2[116],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[117],c2[116],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[109],c2[108],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[109],c2[108],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[160],c2[159],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[160],c2[159],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[165],c2[164],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[165],c2[164],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[161],c2[160],2),simde_mm_xor_si128(c2[160],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[161],c2[160],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[203],c2[202],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[203],c2[202],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[205],c2[204],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[205],c2[204],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[202],c2[201],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[202],c2[201],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[202],c2[201],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[244],c2[243],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[244],c2[243],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[242],c2[241],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[242],c2[241],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[249],c2[248],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[249],c2[248],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[294],c2[293],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[294],c2[293],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[291],c2[290],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[291],c2[290],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[293],c2[292],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[293],c2[292],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[293],c2[292],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[349],c2[348],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[349],c2[348],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[345],c2[344],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[345],c2[344],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[338],c2[337],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[338],c2[337],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[338],c2[337],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[350],c2[349],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[397],c2[396],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[397],c2[396],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[387],c2[386],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[387],c2[386],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[404],c2[403],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[404],c2[403],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[404],c2[403],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[436],c2[435],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[436],c2[435],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[453],c2[452],1),simde_mm_xor_si128(c2[452],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[491],c2[490],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[491],c2[490],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[551],c2[550],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[551],c2[550],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[539],c2[538],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[539],c2[538],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[594],c2[593],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[594],c2[593],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[590],c2[589],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[590],c2[589],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[583],c2[582],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[583],c2[582],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[583],c2[582],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[639],c2[638],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[639],c2[638],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[629],c2[628],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[629],c2[628],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[638],c2[637],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[638],c2[637],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[638],c2[637],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[694],c2[693],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[694],c2[693],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[726],c2[725],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[726],c2[725],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[743],c2[742],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[743],c2[742],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[740],c2[739],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[740],c2[739],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[791],c2[790],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[791],c2[790],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[783],c2[782],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[783],c2[782],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[780],c2[779],2),simde_mm_xor_si128(c2[779],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[780],c2[779],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[840],c2[839],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[840],c2[839],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[817],c2[816],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[817],c2[816],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[827],c2[826],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[827],c2[826],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[827],c2[826],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[874],c2[873],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[873],c2[872],15),simde_mm_xor_si128(c2[873],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[916],c2[915],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[916],c2[915],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[925],c2[924],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[925],c2[924],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[917],c2[916],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[917],c2[916],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[973],c2[972],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[973],c2[972],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[977],c2[976],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[977],c2[976],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[979],c2[978],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[979],c2[978],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[979],c2[978],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1022],c2[1021],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1022],c2[1021],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1032],c2[1031],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1032],c2[1031],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1023],c2[1022],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1023],c2[1022],5),simde_mm_alignr_epi8(c2[1023],c2[1022],6))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 32 + d2[768]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[14],c2[13],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[23],c2[22],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[7],c2[6],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[7],c2[6],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[12],c2[11],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[12],c2[11],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[7],c2[6],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[68],c2[67],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[58],c2[57],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[58],c2[57],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[72],c2[71],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[72],c2[71],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[118],c2[117],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[119],c2[118],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[111],c2[110],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[111],c2[110],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[162],c2[161],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[167],c2[166],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[162],c2[161],15),simde_mm_xor_si128(c2[162],simde_mm_xor_si128(c2[204],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[207],c2[206],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[207],c2[206],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[204],c2[203],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[204],c2[203],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[246],c2[245],5),simde_mm_xor_si128(c2[243],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[250],c2[249],15),simde_mm_xor_si128(c2[250],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[296],c2[295],8),simde_mm_xor_si128(c2[292],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[293],c2[292],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[295],c2[294],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[295],c2[294],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[351],c2[350],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[347],c2[346],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[347],c2[346],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[340],c2[339],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[340],c2[339],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[399],c2[398],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],15),simde_mm_xor_si128(c2[388],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[406],c2[405],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[406],c2[405],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[446],c2[445],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[438],c2[437],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[454],c2[453],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[454],c2[453],15),simde_mm_xor_si128(c2[492],simde_mm_xor_si128(c2[482],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[483],c2[482],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[483],c2[482],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[483],c2[482],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[529],c2[528],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[541],c2[540],7),simde_mm_xor_si128(c2[541],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[542],c2[541],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[596],c2[595],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[592],c2[591],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[585],c2[584],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[585],c2[584],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[589],c2[588],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[641],c2[640],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[631],c2[630],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[631],c2[630],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[640],c2[639],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[640],c2[639],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[680],c2[679],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[696],c2[695],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[696],c2[695],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[680],c2[679],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[680],c2[679],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[683],c2[682],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[728],c2[727],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[721],c2[720],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[742],c2[741],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[742],c2[741],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[769],c2[768],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[785],c2[784],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[781],c2[780],15),simde_mm_xor_si128(c2[781],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[818],c2[817],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[819],c2[818],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[819],c2[818],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[829],c2[828],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[829],c2[828],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[874],c2[873],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[873],c2[872],15),simde_mm_xor_si128(c2[873],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[875],c2[874],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[875],c2[874],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[918],c2[917],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[927],c2[926],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[919],c2[918],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[919],c2[918],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[975],c2[974],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[979],c2[978],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[979],c2[978],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[981],c2[980],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[981],c2[980],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1024],c2[1023],10),simde_mm_xor_si128(c2[1009],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1025],c2[1024],4),simde_mm_alignr_epi8(c2[1025],c2[1024],5)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 33 + d2[792]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[69],c2[68],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[97],c2[96],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[551],c2[550],9),simde_mm_alignr_epi8(c2[1015],c2[1014],9)))); + +//row: 34 + d2[816]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[15],c2[14],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[733],c2[732],10),simde_mm_alignr_epi8(c2[836],c2[835],8)))); + +//row: 35 + d2[840]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[12],c2[11],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[22],c2[21],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[6],c2[5],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[10],c2[9],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[66],c2[65],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[71],c2[70],1),simde_mm_xor_si128(c2[68],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[116],c2[115],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[118],c2[117],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[110],c2[109],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[160],c2[159],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[166],c2[165],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[161],c2[160],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[203],c2[202],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[206],c2[205],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[202],c2[201],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[244],c2[243],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[242],c2[241],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[249],c2[248],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[295],c2[294],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[291],c2[290],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[294],c2[293],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[309],c2[308],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[350],c2[349],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[339],c2[338],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[398],c2[397],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[387],c2[386],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[445],c2[444],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[436],c2[435],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[453],c2[452],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[491],c2[490],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[481],c2[480],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[552],c2[551],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[594],c2[593],11),simde_mm_xor_si128(c2[590],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[584],c2[583],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[577],c2[576],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[639],c2[638],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[638],c2[637],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[679],c2[678],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[695],c2[694],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[678],c2[677],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[727],c2[726],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[743],c2[742],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[740],c2[739],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[792],c2[791],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[783],c2[782],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[780],c2[779],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[840],c2[839],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[817],c2[816],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[828],c2[827],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[874],c2[873],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[916],c2[915],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[926],c2[925],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[918],c2[917],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[974],c2[973],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[978],c2[977],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[980],c2[979],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1023],c2[1022],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1032],c2[1031],10),simde_mm_alignr_epi8(c2[1023],c2[1022],15)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 36 + d2[864]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[14],c2[13],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[692],c2[691],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[739],c2[738],9),simde_mm_alignr_epi8(c2[866],c2[865],5)))); + +//row: 37 + d2[888]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[3],c2[2],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[3],c2[2],7),simde_mm_xor_si128(c2[12],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[21],c2[20],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1],c2[0],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[71],c2[70],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[61],c2[60],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[65],c2[64],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[107],c2[106],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[107],c2[106],6),simde_mm_xor_si128(c2[108],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[100],c2[99],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[151],c2[150],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[151],c2[150],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[156],c2[155],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[152],c2[151],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[194],c2[193],4),simde_mm_xor_si128(c2[196],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[193],c2[192],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[259],c2[258],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[259],c2[258],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[257],c2[256],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[264],c2[263],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[309],c2[308],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[309],c2[308],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[306],c2[305],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[308],c2[307],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[340],c2[339],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[360],c2[359],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[353],c2[352],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[402],c2[401],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[395],c2[394],12),simde_mm_xor_si128(c2[435],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[436],c2[435],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[451],c2[450],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[482],c2[481],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[482],c2[481],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[496],c2[495],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[496],c2[495],8),simde_mm_xor_si128(c2[542],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[543],c2[542],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[530],c2[529],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[531],c2[530],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[585],c2[584],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[585],c2[584],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[581],c2[580],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[598],c2[597],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[644],c2[643],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[629],c2[628],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[693],c2[692],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[685],c2[684],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[693],c2[692],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[741],c2[740],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[741],c2[740],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[731],c2[730],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[782],c2[781],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[782],c2[781],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[771],c2[770],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[831],c2[830],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[832],c2[831],7),simde_mm_xor_si128(c2[818],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[887],c2[886],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[887],c2[886],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[887],c2[886],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[865],c2[864],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[931],c2[930],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[931],c2[930],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[916],c2[915],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[933],c2[932],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[964],c2[963],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[964],c2[963],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[969],c2[968],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[970],c2[969],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1013],c2[1012],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1013],c2[1012],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1023],c2[1022],4),simde_mm_alignr_epi8(c2[1014],c2[1013],9)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 38 + d2[912]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[12],c2[11],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[444],c2[443],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],1),simde_mm_alignr_epi8(c2[590],c2[589],6)))); + +//row: 39 + d2[936]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[65],c2[64],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[150],c2[149],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[358],c2[357],10),simde_mm_alignr_epi8(c2[931],c2[930],9)))); + +//row: 40 + d2[960]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[11],c2[10],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[387],c2[386],5),simde_mm_alignr_epi8(c2[836],c2[835],8))); + +//row: 41 + d2[984]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[52],c2[51],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[164],c2[163],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[441],c2[440],11),c2[882]))); + +//row: 42 + d2[1008]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[9],c2[8],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[19],c2[18],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[3],c2[2],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[3],c2[2],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[7],c2[6],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[7],c2[6],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[8],c2[7],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[63],c2[62],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[54],c2[53],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[68],c2[67],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[68],c2[67],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[113],c2[112],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[115],c2[114],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[107],c2[106],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[107],c2[106],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[157],c2[156],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[163],c2[162],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[158],c2[157],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[158],c2[157],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[200],c2[199],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[203],c2[202],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[203],c2[202],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[199],c2[198],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[199],c2[198],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[193],c2[192],14),simde_mm_xor_si128(c2[241],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[263],c2[262],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[246],c2[245],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[246],c2[245],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[292],c2[291],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[312],c2[311],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[312],c2[311],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[291],c2[290],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[291],c2[290],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[347],c2[346],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[343],c2[342],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[343],c2[342],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[360],c2[359],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[360],c2[359],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[395],c2[394],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[408],c2[407],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[408],c2[407],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[402],c2[401],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[402],c2[401],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[442],c2[441],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[433],c2[432],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[450],c2[449],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[450],c2[449],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[488],c2[487],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[502],c2[501],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[502],c2[501],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[502],c2[501],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[502],c2[501],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[549],c2[548],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[537],c2[536],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[537],c2[536],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[537],c2[536],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[588],c2[587],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[581],c2[580],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[581],c2[580],2),simde_mm_xor_si128(c2[636],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[627],c2[626],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[627],c2[626],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[635],c2[634],15),simde_mm_xor_si128(c2[635],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[676],c2[675],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[692],c2[691],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[692],c2[691],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[675],c2[674],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[675],c2[674],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[724],c2[723],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[740],c2[739],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[737],c2[736],15),simde_mm_xor_si128(c2[737],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[789],c2[788],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[780],c2[779],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[777],c2[776],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[777],c2[776],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[837],c2[836],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[838],c2[837],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[838],c2[837],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[825],c2[824],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[825],c2[824],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[869],c2[868],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[869],c2[868],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[869],c2[868],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[871],c2[870],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[871],c2[870],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[913],c2[912],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[923],c2[922],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[915],c2[914],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[915],c2[914],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[971],c2[970],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[975],c2[974],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[975],c2[974],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[977],c2[976],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[977],c2[976],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1020],c2[1019],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1029],c2[1028],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1020],c2[1019],15),c2[1020])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 43 + d2[1032]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[6],c2[5],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[16],c2[15],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[24],c2[23],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[4],c2[3],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[4],c2[3],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[60],c2[59],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[51],c2[50],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[64],c2[63],15),simde_mm_xor_si128(c2[64],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[56],c2[55],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[110],c2[109],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[112],c2[111],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[104],c2[103],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[154],c2[153],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[160],c2[159],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[155],c2[154],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[155],c2[154],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[197],c2[196],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[200],c2[199],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[196],c2[195],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[196],c2[195],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[262],c2[261],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[260],c2[259],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[243],c2[242],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[289],c2[288],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[309],c2[308],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[311],c2[310],15),simde_mm_xor_si128(c2[311],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[344],c2[343],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[340],c2[339],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[357],c2[356],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[392],c2[391],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],9),simde_mm_xor_si128(c2[398],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[399],c2[398],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[439],c2[438],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[454],c2[453],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[447],c2[446],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[485],c2[484],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[499],c2[498],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[546],c2[545],6),simde_mm_xor_si128(c2[533],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[534],c2[533],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[534],c2[533],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[588],c2[587],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[584],c2[583],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[577],c2[576],15),simde_mm_xor_si128(c2[577],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[633],c2[632],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[648],c2[647],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[632],c2[631],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[632],c2[631],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[673],c2[672],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[689],c2[688],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[696],c2[695],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[696],c2[695],13),simde_mm_xor_si128(c2[720],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[737],c2[736],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[734],c2[733],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[786],c2[785],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[777],c2[776],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[774],c2[773],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[777],c2[776],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[834],c2[833],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[835],c2[834],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[822],c2[821],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[822],c2[821],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[866],c2[865],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[866],c2[865],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[868],c2[867],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[868],c2[867],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[872],c2[871],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[934],c2[933],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[920],c2[919],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[936],c2[935],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[968],c2[967],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[972],c2[971],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[973],c2[972],15),simde_mm_xor_si128(c2[973],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1017],c2[1016],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1026],c2[1025],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1017],c2[1016],13),simde_mm_alignr_epi8(c2[1017],c2[1016],14))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 44 + d2[1056]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[13],c2[12],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[22],c2[21],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[6],c2[5],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[11],c2[10],6),simde_mm_xor_si128(c2[5],simde_mm_xor_si128(simde_mm_alignr_epi8(c2[67],c2[66],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[71],c2[70],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[117],c2[116],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[118],c2[117],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[110],c2[109],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[161],c2[160],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[166],c2[165],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[162],c2[161],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[204],c2[203],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[206],c2[205],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[203],c2[202],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[245],c2[244],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[243],c2[242],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[250],c2[249],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[295],c2[294],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[292],c2[291],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[294],c2[293],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[350],c2[349],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[346],c2[345],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[339],c2[338],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[341],c2[340],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[398],c2[397],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[388],c2[387],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[405],c2[404],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[445],c2[444],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[437],c2[436],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[454],c2[453],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[443],c2[442],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[492],c2[491],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[482],c2[481],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[482],c2[481],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[552],c2[551],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[540],c2[539],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[541],c2[540],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[595],c2[594],3),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[591],c2[590],8),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[584],c2[583],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[640],c2[639],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[630],c2[629],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[639],c2[638],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[679],c2[678],11),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[695],c2[694],10),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[679],c2[678],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[727],c2[726],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[744],c2[743],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[741],c2[740],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[792],c2[791],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[784],c2[783],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[781],c2[780],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[817],c2[816],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[818],c2[817],5),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[828],c2[827],14),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[873],c2[872],4),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[873],c2[872],2),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[875],c2[874],1),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[917],c2[916],6),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[926],c2[925],13),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[918],c2[917],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[974],c2[973],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[978],c2[977],15),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[980],c2[979],9),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1023],c2[1022],12),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[1009],c2[1008],2),simde_mm_alignr_epi8(c2[1024],c2[1023],7)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 45 + d2[1080]=simde_mm_xor_si128(simde_mm_alignr_epi8(c2[57],c2[56],7),simde_mm_xor_si128(simde_mm_alignr_epi8(c2[298],c2[297],5),simde_mm_alignr_epi8(c2[481],c2[480],15))); + } +} +#endif diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_simd512_alignr_byte.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_simd512_alignr_byte.c new file mode 100644 index 0000000000..96b83f4e28 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_simd512_alignr_byte.c @@ -0,0 +1,151 @@ +#include "PHY/sse_intrin.h" +// generated code for Zc=384, byte encoding +static inline void ldpc384_byte(uint8_t *c,uint8_t *d) { + __m512i *csimd=(__m512i *)c,*dsimd=(__m512i *)d; + + __m512i *c2,*d2; + + int i2; + for (i2=0; i2<6; i2++) { + c2=&csimd[i2]; + d2=&dsimd[i2]; + +//row: 0 + d2[0]=_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],9),_mm512_xor_si512(c2[36],_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],16),_mm512_xor_si512(c2[64],_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],48),_mm512_alignr_epi8(c2[258],c2[257],37))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 1 + d2[6]=_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],51),_mm512_xor_si512(c2[109],_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],49),_mm512_alignr_epi8(c2[258],c2[257],38)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 2 + d2[12]=_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],10),_mm512_xor_si512(c2[36],_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],17),_mm512_xor_si512(c2[64],_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],63),_mm512_xor_si512(c2[109],_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],37),_mm512_alignr_epi8(c2[258],c2[257],38))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 3 + d2[18]=_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],10),_mm512_xor_si512(c2[36],_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],51),_mm512_xor_si512(c2[109],_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],37),_mm512_alignr_epi8(c2[258],c2[257],38)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 4 + d2[24]=_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],12),_mm512_alignr_epi8(c2[15],c2[14],53)); + +//row: 5 + d2[30]=_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[98],c2[97],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[110],c2[109],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[159],c2[158],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],52),_mm512_xor_si512(c2[184],_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[257],c2[256],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],2),_mm512_alignr_epi8(c2[253],c2[252],51))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 6 + d2[36]=_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],18),_mm512_alignr_epi8(c2[244],c2[243],33)))))))); + +//row: 7 + d2[42]=_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],34),_mm512_alignr_epi8(c2[170],c2[169],50)))))); + +//row: 8 + d2[48]=_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[98],c2[97],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[98],c2[97],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],35),_mm512_xor_si512(c2[108],_mm512_xor_si512(_mm512_alignr_epi8(c2[110],c2[109],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[122],c2[121],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[159],c2[158],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],63),_mm512_xor_si512(c2[158],_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[169],c2[168],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[257],c2[256],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],16),_mm512_alignr_epi8(c2[258],c2[257],48))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 9 + d2[54]=_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],63),_mm512_alignr_epi8(c2[242],c2[241],18)))))))); + +//row: 10 + d2[60]=_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],63),_mm512_alignr_epi8(c2[174],c2[173],34)))))); + +//row: 11 + d2[66]=_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],26),_mm512_xor_si512(c2[3],_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],38),_mm512_xor_si512(c2[24],_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],26),_mm512_xor_si512(c2[27],_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],26),_mm512_xor_si512(c2[49],_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[62],c2[61],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[98],c2[97],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],49),_mm512_xor_si512(c2[110],_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[122],c2[121],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[122],c2[121],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[159],c2[158],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[169],c2[168],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],47),_mm512_xor_si512(c2[205],_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],32),_mm512_xor_si512(c2[219],_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[257],c2[256],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[257],c2[256],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],25),_mm512_alignr_epi8(c2[255],c2[254],60)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 12 + d2[72]=_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],50),_mm512_alignr_epi8(c2[218],c2[217],10)))))); + +//row: 13 + d2[78]=_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],63),_mm512_xor_si512(c2[3],_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[53],c2[52],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[122],c2[121],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[122],c2[121],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[159],c2[158],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[220],c2[219],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],62),_mm512_xor_si512(c2[231],_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],61),_mm512_xor_si512(c2[240],_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],35),_mm512_alignr_epi8(c2[258],c2[257],24)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 14 + d2[84]=_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],27),_mm512_alignr_epi8(c2[253],c2[252],12)))))); + +//row: 15 + d2[90]=_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],2),_mm512_xor_si512(c2[29],_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[62],c2[61],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],11),_mm512_xor_si512(c2[109],_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],62),_mm512_xor_si512(c2[204],_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],58),_mm512_xor_si512(c2[218],_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],50),_mm512_alignr_epi8(c2[256],c2[255],51))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 16 + d2[96]=_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],26),_mm512_xor_si512(c2[76],_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[98],c2[97],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[110],c2[109],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],41),_mm512_alignr_epi8(c2[253],c2[252],30))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 17 + d2[102]=_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],38),_mm512_alignr_epi8(c2[258],c2[257],55))))); + +//row: 18 + d2[108]=_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],4),_mm512_alignr_epi8(c2[229],c2[228],4))))); + +//row: 19 + d2[114]=_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],50),_mm512_alignr_epi8(c2[124],c2[123],5))))); + +//row: 20 + d2[120]=_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[37],c2[36],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[98],c2[97],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[110],c2[109],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],43),_mm512_alignr_epi8(c2[253],c2[252],32))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 21 + d2[126]=_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[62],c2[61],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],21),_mm512_alignr_epi8(c2[254],c2[253],33))))); + +//row: 22 + d2[132]=_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],41),_mm512_alignr_epi8(c2[205],c2[204],22)))); + +//row: 23 + d2[138]=_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],61),_mm512_alignr_epi8(c2[217],c2[216],27)))); + +//row: 24 + d2[144]=_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[62],c2[61],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],59),_mm512_xor_si512(c2[147],_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[159],c2[158],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[169],c2[168],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],26),_mm512_alignr_epi8(c2[256],c2[255],15))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 25 + d2[150]=_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],63),_mm512_alignr_epi8(c2[173],c2[172],56)))); + +//row: 26 + d2[156]=_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],12),_mm512_alignr_epi8(c2[183],c2[182],8)))); + +//row: 27 + d2[162]=_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],2),_mm512_alignr_epi8(c2[98],c2[97],37))); + +//row: 28 + d2[168]=_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],52),_mm512_alignr_epi8(c2[257],c2[256],18)))); + +//row: 29 + d2[174]=_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],23),_mm512_xor_si512(c2[37],_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],63),_mm512_xor_si512(c2[132],_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[169],c2[168],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[221],c2[220],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],51),_mm512_alignr_epi8(c2[253],c2[252],52))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 30 + d2[180]=_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[54],c2[53],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[64],c2[63],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[76],c2[75],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],2),_mm512_xor_si512(c2[157],_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],63),c2[253]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 31 + d2[186]=_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],2),_mm512_xor_si512(c2[40],_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],1),_mm512_xor_si512(c2[113],_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],37),_mm512_alignr_epi8(c2[256],c2[255],38))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 32 + d2[192]=_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],32),_mm512_xor_si512(c2[51],_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[62],c2[61],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],56),_mm512_xor_si512(c2[73],_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],63),_mm512_xor_si512(c2[97],_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[110],c2[109],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],31),_mm512_xor_si512(c2[123],_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[171],c2[170],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[246],c2[245],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[257],c2[256],4),_mm512_alignr_epi8(c2[257],c2[256],5)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 33 + d2[198]=_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],41),_mm512_alignr_epi8(c2[254],c2[253],41)))); + +//row: 34 + d2[204]=_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],10),_mm512_alignr_epi8(c2[209],c2[208],56)))); + +//row: 35 + d2[210]=_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],33),_mm512_xor_si512(c2[17],_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],58),_mm512_alignr_epi8(c2[256],c2[255],47)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 36 + d2[216]=_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],41),_mm512_alignr_epi8(c2[217],c2[216],21)))); + +//row: 37 + d2[222]=_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],39),_mm512_xor_si512(c2[3],_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],38),_mm512_xor_si512(c2[27],_mm512_xor_si512(_mm512_alignr_epi8(c2[25],c2[24],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],20),_mm512_xor_si512(c2[49],_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[77],c2[76],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[89],c2[88],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[124],c2[123],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[133],c2[132],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[150],c2[149],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[161],c2[160],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[172],c2[171],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],23),_mm512_xor_si512(_mm512_alignr_epi8(c2[183],c2[182],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[193],c2[192],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[208],c2[207],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[222],c2[221],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[233],c2[232],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[241],c2[240],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[254],c2[253],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],36),_mm512_alignr_epi8(c2[254],c2[253],25)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 38 + d2[228]=_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],33),_mm512_alignr_epi8(c2[148],c2[147],22)))); + +//row: 39 + d2[234]=_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[38],c2[37],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],26),_mm512_alignr_epi8(c2[233],c2[232],41)))); + +//row: 40 + d2[240]=_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],37),_mm512_alignr_epi8(c2[209],c2[208],56))); + +//row: 41 + d2[246]=_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],11),_mm512_alignr_epi8(c2[221],c2[220],32)))); + +//row: 42 + d2[252]=_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[5],c2[4],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[29],c2[28],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[27],c2[26],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],36),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[62],c2[61],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[62],c2[61],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[99],c2[98],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[101],c2[100],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[109],c2[108],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[113],c2[112],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[122],c2[121],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[126],c2[125],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],8),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],2),_mm512_xor_si512(c2[159],_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[157],c2[156],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[159],c2[158],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[159],c2[158],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[169],c2[168],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[169],c2[168],46),_mm512_xor_si512(_mm512_alignr_epi8(c2[169],c2[168],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[181],c2[180],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[210],c2[209],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],13),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[231],c2[230],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[229],c2[228],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[258],c2[257],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],63),c2[255])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 43 + d2[258]=_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[1],c2[0],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[13],c2[12],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[16],c2[15],63),_mm512_xor_si512(c2[16],_mm512_xor_si512(_mm512_alignr_epi8(c2[14],c2[13],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[26],c2[25],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[40],c2[39],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[39],c2[38],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[50],c2[49],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],59),_mm512_xor_si512(_mm512_alignr_epi8(c2[49],c2[48],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[66],c2[65],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[65],c2[64],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],47),_mm512_xor_si512(_mm512_alignr_epi8(c2[78],c2[77],48),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[90],c2[89],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[98],c2[97],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],32),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[110],c2[109],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[122],c2[121],9),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[125],c2[124],45),_mm512_xor_si512(_mm512_alignr_epi8(c2[137],c2[136],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[134],c2[133],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[147],c2[146],58),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[145],c2[144],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[159],c2[158],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[162],c2[161],49),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],61),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[169],c2[168],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[173],c2[172],1),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],61),_mm512_xor_si512(c2[180],_mm512_xor_si512(_mm512_alignr_epi8(c2[185],c2[184],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[184],c2[183],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[197],c2[196],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],11),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],24),_mm512_xor_si512(_mm512_alignr_epi8(c2[194],c2[193],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[195],c2[194],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[209],c2[208],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],20),_mm512_xor_si512(_mm512_alignr_epi8(c2[206],c2[205],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[217],c2[216],56),_mm512_xor_si512(_mm512_alignr_epi8(c2[218],c2[217],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[234],c2[233],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[242],c2[241],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[243],c2[242],54),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[257],c2[256],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[255],c2[254],13),_mm512_alignr_epi8(c2[255],c2[254],14))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 44 + d2[264]=_mm512_xor_si512(_mm512_alignr_epi8(c2[4],c2[3],5),_mm512_xor_si512(_mm512_alignr_epi8(c2[6],c2[5],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[3],c2[2],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[2],c2[1],16),_mm512_xor_si512(_mm512_alignr_epi8(c2[17],c2[16],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],12),_mm512_xor_si512(_mm512_alignr_epi8(c2[18],c2[17],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[30],c2[29],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[28],c2[27],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[42],c2[41],27),_mm512_xor_si512(_mm512_alignr_epi8(c2[41],c2[40],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[52],c2[51],30),_mm512_xor_si512(_mm512_alignr_epi8(c2[51],c2[50],37),_mm512_xor_si512(_mm512_alignr_epi8(c2[62],c2[61],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[61],c2[60],34),_mm512_xor_si512(_mm512_alignr_epi8(c2[63],c2[62],18),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[73],c2[72],51),_mm512_xor_si512(_mm512_alignr_epi8(c2[74],c2[73],25),_mm512_xor_si512(_mm512_alignr_epi8(c2[88],c2[87],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[87],c2[86],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[85],c2[84],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[86],c2[85],14),_mm512_xor_si512(_mm512_alignr_epi8(c2[100],c2[99],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[97],c2[96],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[102],c2[101],10),_mm512_xor_si512(_mm512_alignr_epi8(c2[112],c2[111],15),_mm512_xor_si512(_mm512_alignr_epi8(c2[110],c2[109],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[114],c2[113],17),_mm512_xor_si512(_mm512_alignr_epi8(c2[111],c2[110],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[123],c2[122],50),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],19),_mm512_xor_si512(_mm512_alignr_epi8(c2[121],c2[120],22),_mm512_xor_si512(_mm512_alignr_epi8(c2[138],c2[137],63),_mm512_xor_si512(_mm512_alignr_epi8(c2[135],c2[134],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[136],c2[135],3),_mm512_xor_si512(_mm512_alignr_epi8(c2[149],c2[148],35),_mm512_xor_si512(_mm512_alignr_epi8(c2[148],c2[147],40),_mm512_xor_si512(_mm512_alignr_epi8(c2[146],c2[145],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],55),_mm512_xor_si512(_mm512_alignr_epi8(c2[158],c2[157],26),_mm512_xor_si512(_mm512_alignr_epi8(c2[160],c2[159],39),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],43),_mm512_xor_si512(_mm512_alignr_epi8(c2[174],c2[173],42),_mm512_xor_si512(_mm512_alignr_epi8(c2[170],c2[169],38),_mm512_xor_si512(_mm512_alignr_epi8(c2[182],c2[181],41),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],53),_mm512_xor_si512(_mm512_alignr_epi8(c2[186],c2[185],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[198],c2[197],60),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],52),_mm512_xor_si512(_mm512_alignr_epi8(c2[196],c2[195],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[205],c2[204],21),_mm512_xor_si512(_mm512_alignr_epi8(c2[207],c2[206],62),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],4),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],2),_mm512_xor_si512(_mm512_alignr_epi8(c2[219],c2[218],33),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],6),_mm512_xor_si512(_mm512_alignr_epi8(c2[232],c2[231],29),_mm512_xor_si512(_mm512_alignr_epi8(c2[230],c2[229],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[244],c2[243],28),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],31),_mm512_xor_si512(_mm512_alignr_epi8(c2[245],c2[244],57),_mm512_xor_si512(_mm512_alignr_epi8(c2[256],c2[255],44),_mm512_xor_si512(_mm512_alignr_epi8(c2[253],c2[252],2),_mm512_alignr_epi8(c2[256],c2[255],55)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 45 + d2[270]=_mm512_xor_si512(_mm512_alignr_epi8(c2[15],c2[14],7),_mm512_xor_si512(_mm512_alignr_epi8(c2[75],c2[74],21),_mm512_alignr_epi8(c2[121],c2[120],15))); + } +} diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_simd512_permutex_byte.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_simd512_permutex_byte.c new file mode 100644 index 0000000000..d0649a1e88 --- /dev/null +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc384_simd512_permutex_byte.c @@ -0,0 +1,218 @@ +#include "PHY/sse_intrin.h" +// generated code for Zc=384, byte encoding + const uint8_t abshift_bytes[64][64] __attribute__((aligned(64)))= { +{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63}, +{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64}, +{2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65}, +{3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66}, +{4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67}, +{5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68}, +{6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69}, +{7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70}, +{8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71}, +{9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72}, +{10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73}, +{11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74}, +{12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75}, +{13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76}, +{14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77}, +{15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78}, +{16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79}, +{17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80}, +{18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81}, +{19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82}, +{20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83}, +{21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84}, +{22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85}, +{23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86}, +{24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87}, +{25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88}, +{26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89}, +{27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90}, +{28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91}, +{29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92}, +{30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93}, +{31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94}, +{32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95}, +{33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96}, +{34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97}, +{35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98}, +{36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99}, +{37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100}, +{38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101}, +{39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102}, +{40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103}, +{41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104}, +{42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105}, +{43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106}, +{44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107}, +{45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108}, +{46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109}, +{47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110}, +{48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111}, +{49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112}, +{50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113}, +{51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114}, +{52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115}, +{53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116}, +{54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117}, +{55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118}, +{56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119}, +{57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120}, +{58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121}, +{59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122}, +{60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123}, +{61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124}, +{62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125}, +{63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126}}; +#define abshift_get(r) (*(const __m512i *) abshift_bytes[r]) + +static void ldpc384_byte(uint8_t *c,uint8_t *d) { + __m512i *csimd=(__m512i *)c,*dsimd=(__m512i *)d; + + __m512i *c2,*d2; + + int i2; + for (i2=0; i2<6; i2++) { + c2=&csimd[i2]; + d2=&dsimd[i2]; + +//row: 0 + d2[0]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(51),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(12),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(13),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(20),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(19),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(58),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(23),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(50),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(12),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(8),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(49),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(9),c2[38]),_mm512_xor_si512(c2[36],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(32),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(12),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(19),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(53),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(16),c2[63]),_mm512_xor_si512(c2[64],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(24),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(33),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(7),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(11),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(11),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(25),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(11),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(32),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(56),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(61),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(50),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(63),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(32),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(1),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(4),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(45),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(39),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(49),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(17),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(22),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(39),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(37),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(8),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(21),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(25),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(24),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(20),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(23),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(35),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(53),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(42),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(34),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(48),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(50),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(3),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(44),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(50),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(48),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(15),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(52),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(11),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(13),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(10),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(13),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(39),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(26),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(48),c2[254]),_mm512_permutex2var_epi8(c2[257],abshift_get(37),c2[258]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 1 + d2[6]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(51),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(52),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(13),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(14),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(21),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(19),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(20),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(59),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(24),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(50),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(51),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(13),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(9),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(49),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(50),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(10),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(1),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(33),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(13),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(20),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(53),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(54),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(17),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(1),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(24),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(25),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(34),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(8),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(12),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(12),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(26),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(12),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(33),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(57),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(61),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(62),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(51),c2[111]),_mm512_xor_si512(c2[109],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(32),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(33),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(2),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(5),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(45),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(46),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(40),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(50),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(17),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(18),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(23),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(40),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(37),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(38),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(9),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(22),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(26),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(25),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(21),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(23),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(24),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(36),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(54),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(42),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(43),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(35),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(49),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(51),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(4),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(45),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(50),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(51),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(49),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(16),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(52),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(53),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(12),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(14),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(10),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(11),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(14),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(40),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(26),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(27),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(49),c2[254]),_mm512_permutex2var_epi8(c2[257],abshift_get(38),c2[258])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 2 + d2[12]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(52),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(13),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(13),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(14),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(20),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(21),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(20),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(58),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(59),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(23),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(24),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(51),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(13),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(8),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(9),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(50),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(10),c2[38]),_mm512_xor_si512(c2[36],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(1),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(33),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(12),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(13),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(19),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(20),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(54),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(17),c2[63]),_mm512_xor_si512(c2[64],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(1),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(25),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(33),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(34),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(7),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(8),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(12),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(11),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(12),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(25),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(26),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(12),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(32),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(33),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(56),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(57),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(62),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(51),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(63),c2[109]),_mm512_xor_si512(c2[109],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(33),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(1),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(2),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(4),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(5),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(46),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(40),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(49),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(50),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(18),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(23),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(39),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(40),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(38),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(8),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(9),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(21),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(22),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(26),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(24),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(25),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(20),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(21),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(24),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(36),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(53),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(54),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(43),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(35),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(48),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(49),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(51),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(3),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(4),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(44),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(45),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(51),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(48),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(49),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(15),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(16),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(53),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(12),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(13),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(14),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(11),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(13),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(14),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(39),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(40),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(27),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(49),c2[254]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(37),c2[258]),_mm512_permutex2var_epi8(c2[257],abshift_get(38),c2[258]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 3 + d2[18]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(52),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(13),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(14),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(20),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(21),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(20),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(59),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(23),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(24),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(51),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(13),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(9),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(50),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(10),c2[38]),_mm512_xor_si512(c2[36],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(1),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(33),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(13),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(19),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(20),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(54),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(17),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(1),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(25),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(34),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(7),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(8),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(12),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(12),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(25),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(26),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(12),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(33),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(56),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(57),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(62),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(51),c2[111]),_mm512_xor_si512(c2[109],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(33),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(2),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(4),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(5),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(46),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(40),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(49),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(50),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(18),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(23),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(39),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(40),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(38),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(9),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(21),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(22),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(26),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(25),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(20),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(21),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(24),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(36),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(54),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(43),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(35),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(48),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(49),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(51),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(4),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(44),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(45),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(51),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(49),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(15),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(16),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(53),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(12),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(14),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(11),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(14),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(39),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(40),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(27),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(49),c2[254]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(37),c2[258]),_mm512_permutex2var_epi8(c2[257],abshift_get(38),c2[258])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 4 + d2[24]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(12),c2[6]),_mm512_permutex2var_epi8(c2[14],abshift_get(53),c2[15])); + +//row: 5 + d2[30]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(16),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(41),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(42),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(49),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(3),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(48),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(23),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(52),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(14),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(15),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(41),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(37),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(14),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(38),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(29),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(51),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(61),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(41),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(48),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(18),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(45),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(29),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(53),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(62),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(36),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(40),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(40),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(54),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[97],abshift_get(40),c2[98]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(61),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(21),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[109],abshift_get(26),c2[110]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(15),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(28),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(61),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(30),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(33),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(10),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(4),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(14),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(46),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(51),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(4),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(38),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[158],abshift_get(2),c2[159]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(37),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(50),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(54),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(53),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(49),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(52),c2[186]),_mm512_xor_si512(c2[184],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(18),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(7),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(63),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(13),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(49),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(15),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(32),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(9),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(15),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(13),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(44),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(17),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(40),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(42),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(39),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(42),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(4),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(55),c2[254]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[256],abshift_get(13),c2[257]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(2),c2[255]),_mm512_permutex2var_epi8(c2[252],abshift_get(51),c2[253]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 6 + d2[36]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(22),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(1),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(1),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(31),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(28),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(61),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(18),c2[217]),_mm512_permutex2var_epi8(c2[243],abshift_get(33),c2[244])))))))); + +//row: 7 + d2[42]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(9),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(62),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(60),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(13),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(34),c2[101]),_mm512_permutex2var_epi8(c2[169],abshift_get(50),c2[170])))))); + +//row: 8 + d2[48]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(54),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(30),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(15),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(55),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(16),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(55),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(56),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(23),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(62),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(63),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(51),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(22),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(62),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(61),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(36),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(37),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(26),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(1),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(2),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(51),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(53),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(29),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(15),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(55),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(11),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(50),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(51),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(52),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(28),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(12),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(52),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(3),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(42),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(43),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(37),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(35),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(11),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(15),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(54),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(55),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(22),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(61),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(62),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(56),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(32),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(19),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(59),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(3),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(42),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(43),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(27),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(3),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(36),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(11),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(12),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(10),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(49),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(50),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(14),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(54),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(14),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(53),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(54),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(28),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(3),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(4),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(14),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[97],abshift_get(54),c2[98]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(35),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(10),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(11),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[97],abshift_get(59),c2[98]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(34),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(35),c2[100]),_mm512_xor_si512(c2[108],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[109],abshift_get(40),c2[110]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(53),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(29),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(2),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(41),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(42),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(35),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[121],abshift_get(11),c2[122]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(4),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(43),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(44),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(7),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(46),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(47),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(48),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(24),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(42),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(18),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(52),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(27),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(28),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(20),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(60),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(25),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(1),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(42),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(17),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(18),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(18),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(40),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[158],abshift_get(16),c2[159]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(11),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(50),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(51),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(24),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(63),c2[158]),_mm512_xor_si512(c2[158],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(28),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[168],abshift_get(4),c2[169]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(27),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(2),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(3),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(23),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(62),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(63),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(26),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(2),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(38),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(14),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(56),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(31),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(32),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(45),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(21),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(37),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(13),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(51),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(26),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(27),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(39),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(53),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(29),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(6),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(45),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(46),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(47),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(22),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(23),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(53),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(29),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(51),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(26),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(27),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(18),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(57),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(58),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(55),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(31),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(14),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(54),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(16),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(55),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(56),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(32),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(13),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(53),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(16),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(55),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(56),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(42),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(17),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(18),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(29),c2[253]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(5),c2[255]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(51),c2[255]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[256],abshift_get(27),c2[257]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(40),c2[253]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(15),c2[255]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(16),c2[255]),_mm512_permutex2var_epi8(c2[257],abshift_get(48),c2[258]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 9 + d2[54]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(46),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(40),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(1),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(5),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(57),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(47),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(63),c2[217]),_mm512_permutex2var_epi8(c2[241],abshift_get(18),c2[242])))))))); + +//row: 10 + d2[60]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(37),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(19),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(18),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(47),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(63),c2[102]),_mm512_permutex2var_epi8(c2[173],abshift_get(34),c2[174])))))); + +//row: 11 + d2[66]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(1),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(38),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(39),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(26),c2[1]),_mm512_xor_si512(c2[3],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(27),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(1),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(34),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(8),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(48),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(33),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(6),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(7),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(8),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(46),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(37),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(11),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(38),c2[14]),_mm512_xor_si512(c2[24],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(37),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(38),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(26),c2[25]),_mm512_xor_si512(c2[27],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(22),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(60),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(63),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(36),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(37),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(23),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(61),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(14),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(52),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(46),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(20),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(26),c2[53]),_mm512_xor_si512(c2[49],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(33),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(7),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(3),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(40),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(41),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[61],abshift_get(30),c2[62]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(4),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(14),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(52),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(38),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(11),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(12),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(47),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(21),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(21),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(59),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(25),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(63),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(25),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(63),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(39),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(13),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(25),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(63),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[97],abshift_get(46),c2[98]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(20),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(6),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(44),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(11),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(48),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(49),c2[109]),_mm512_xor_si512(c2[110],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(38),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(13),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(51),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(46),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(19),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(20),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[121],abshift_get(15),c2[122]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(53),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[121],abshift_get(18),c2[122]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(56),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(59),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(32),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(33),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(53),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(27),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(63),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(37),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(31),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(4),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(5),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(36),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(10),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(53),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(27),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(8),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(51),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(24),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(25),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[158],abshift_get(22),c2[159]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(60),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(35),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(9),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(39),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(13),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[168],abshift_get(38),c2[169]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(12),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(34),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(8),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(37),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(10),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(11),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(49),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(23),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(3),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(41),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(56),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(29),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(30),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(48),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(22),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(62),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(36),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(47),c2[193]),_mm512_xor_si512(c2[205],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(38),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(17),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(55),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(58),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(32),c2[205]),_mm512_xor_si512(c2[219],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(37),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(38),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(62),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(36),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(29),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(3),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(2),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(39),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(40),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(25),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(63),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(27),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(1),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(24),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(61),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(62),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(27),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(1),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(53),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(27),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[256],abshift_get(40),c2[257]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(13),c2[254]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(14),c2[254]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(62),c2[253]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(36),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[256],abshift_get(51),c2[257]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(25),c2[254]),_mm512_permutex2var_epi8(c2[254],abshift_get(60),c2[255])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 12 + d2[72]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(13),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(58),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(46),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(40),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(50),c2[157]),_mm512_permutex2var_epi8(c2[217],abshift_get(10),c2[218])))))); + +//row: 13 + d2[78]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(37),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(38),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(63),c2[1]),_mm512_xor_si512(c2[3],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(7),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(57),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(5),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(6),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(45),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(10),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(36),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(37),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(63),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(59),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(35),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(36),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(60),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(51),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(49),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(19),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(63),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[52],abshift_get(6),c2[53]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(39),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(40),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(3),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(51),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(10),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(11),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(20),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(58),c2[75]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(62),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(62),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(12),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(10),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(62),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(19),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(43),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(47),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(48),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(37),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(50),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(18),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(19),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[121],abshift_get(52),c2[122]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[121],abshift_get(55),c2[122]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(31),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(32),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(26),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(36),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(3),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(4),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(9),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(26),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(23),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(24),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[158],abshift_get(59),c2[159]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(8),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(12),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(11),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(7),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(9),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(10),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(22),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(40),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(28),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(29),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(21),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(35),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(37),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(54),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(31),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(36),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(37),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[219],abshift_get(35),c2[220]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(2),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(38),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(39),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(62),c2[233]),_mm512_xor_si512(c2[231],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(60),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(61),c2[245]),_mm512_xor_si512(c2[240],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(26),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(51),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(12),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(13),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(35),c2[254]),_mm512_permutex2var_epi8(c2[257],abshift_get(24),c2[258])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 14 + d2[84]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(14),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(56),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(9),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(25),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(27),c2[210]),_mm512_permutex2var_epi8(c2[252],abshift_get(12),c2[253])))))); + +//row: 15 + d2[90]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(1),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(26),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(27),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(33),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(34),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(49),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(33),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(8),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(36),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(37),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(2),c2[13]),_mm512_xor_si512(c2[29],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(26),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(22),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(63),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(23),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(13),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(14),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(46),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(26),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(32),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(33),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[61],abshift_get(3),c2[62]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(30),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(14),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(38),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(47),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(20),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(21),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(25),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(25),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(38),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(39),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(25),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(46),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(5),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(6),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(11),c2[112]),_mm512_xor_si512(c2[109],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(13),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(46),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(15),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(17),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(18),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(18),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(59),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(53),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(62),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(63),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(31),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(36),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(52),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(53),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(51),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(22),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(34),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(35),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(62),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(39),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(38),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(33),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(34),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(37),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(49),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(3),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(56),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(48),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(61),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(62),c2[195]),_mm512_xor_si512(c2[204],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(17),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(57),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(58),c2[207]),_mm512_xor_si512(c2[218],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(62),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(28),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(29),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(55),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(2),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(25),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(27),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(24),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(27),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(52),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(53),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(40),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(62),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(50),c2[256]),_mm512_permutex2var_epi8(c2[255],abshift_get(51),c2[256]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 16 + d2[96]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(44),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(5),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(6),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(13),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(12),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(51),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(16),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(13),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(43),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(5),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(1),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(42),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(2),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(57),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(18),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(25),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(5),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(12),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(46),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(9),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(57),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(17),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(26),c2[76]),_mm512_xor_si512(c2[76],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(4),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(4),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(18),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(4),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(25),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[97],abshift_get(49),c2[98]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(54),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(43),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[109],abshift_get(56),c2[110]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(25),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(58),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(61),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(38),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(32),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(42),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(57),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(10),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(15),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(32),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(30),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(1),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(14),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(18),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(17),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(13),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(16),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(28),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(46),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(35),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(27),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(41),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(43),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(60),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(37),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(43),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(41),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(8),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(45),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(4),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(6),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(3),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(6),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(32),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(33),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(19),c2[253]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(41),c2[255]),_mm512_permutex2var_epi8(c2[252],abshift_get(30),c2[253]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 17 + d2[102]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(4),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(47),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(17),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(38),c2[210]),_mm512_permutex2var_epi8(c2[257],abshift_get(55),c2[258]))))); + +//row: 18 + d2[108]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(2),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(35),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(24),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(4),c2[219]),_mm512_permutex2var_epi8(c2[228],abshift_get(4),c2[229]))))); + +//row: 19 + d2[114]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(17),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(21),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(24),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(50),c2[100]),_mm512_permutex2var_epi8(c2[123],abshift_get(5),c2[124]))))); + +//row: 20 + d2[120]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(46),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(7),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(8),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(15),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(59),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(14),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(53),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(18),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(45),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(7),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(3),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(44),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(4),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[36],abshift_get(59),c2[37]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(14),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(27),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(7),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(14),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(48),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(11),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(59),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(19),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(28),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(2),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(6),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(6),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(20),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(6),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(27),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[97],abshift_get(51),c2[98]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(56),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(45),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[109],abshift_get(58),c2[110]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(8),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(27),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(60),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(63),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(40),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(34),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(44),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(21),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(12),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(17),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(34),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(32),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(3),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(16),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(20),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(19),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(15),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(18),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(30),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(48),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(37),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(29),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(43),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(45),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(62),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(39),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(45),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(43),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(10),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(47),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(6),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(8),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(5),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(8),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(34),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(21),c2[253]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(43),c2[255]),_mm512_permutex2var_epi8(c2[252],abshift_get(32),c2[253]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 21 + d2[126]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(13),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[61],abshift_get(38),c2[62]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(8),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(21),c2[244]),_mm512_permutex2var_epi8(c2[253],abshift_get(33),c2[254]))))); + +//row: 22 + d2[132]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(30),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(11),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(41),c2[160]),_mm512_permutex2var_epi8(c2[204],abshift_get(22),c2[205])))); + +//row: 23 + d2[138]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(24),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(25),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(61),c2[121]),_mm512_permutex2var_epi8(c2[216],abshift_get(27),c2[217])))); + +//row: 24 + d2[144]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(29),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(54),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(55),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(62),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(42),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(61),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(36),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(1),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(28),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(54),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(50),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(27),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(51),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(42),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(30),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(10),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(54),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(61),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(43),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(31),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(58),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[61],abshift_get(42),c2[62]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(2),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(11),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(49),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(53),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(53),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(3),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(53),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(10),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(34),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(39),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(28),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(41),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(10),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(43),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(46),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(23),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(17),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(27),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(19),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(59),c2[148]),_mm512_xor_si512(c2[147],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(17),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(15),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(50),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[158],abshift_get(63),c2[159]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(3),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(2),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[168],abshift_get(62),c2[169]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(1),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(13),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(31),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(20),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(12),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(26),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(28),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(45),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(22),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(28),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(26),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(57),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(30),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(53),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(55),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(52),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(55),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(17),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(4),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(26),c2[258]),_mm512_permutex2var_epi8(c2[255],abshift_get(15),c2[256]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 25 + d2[150]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(8),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(17),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(63),c2[90]),_mm512_permutex2var_epi8(c2[172],abshift_get(56),c2[173])))); + +//row: 26 + d2[156]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(7),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(17),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(12),c2[50]),_mm512_permutex2var_epi8(c2[182],abshift_get(8),c2[183])))); + +//row: 27 + d2[162]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(2),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(2),c2[76]),_mm512_permutex2var_epi8(c2[97],abshift_get(37),c2[98]))); + +//row: 28 + d2[168]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(30),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(19),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(52),c2[232]),_mm512_permutex2var_epi8(c2[256],abshift_get(18),c2[257])))); + +//row: 29 + d2[174]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(2),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(27),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(28),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(34),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(35),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(34),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(9),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(37),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(38),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(60),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(1),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(27),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(23),c2[25]),_mm512_xor_si512(c2[37],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(24),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(14),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(15),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(47),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(27),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(33),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(34),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(4),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(31),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(15),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(39),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(48),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(21),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(22),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(26),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(26),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(39),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(40),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(26),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(47),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(6),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(7),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(12),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(1),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(14),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(47),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(16),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(18),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(19),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(60),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(54),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(63),c2[138]),_mm512_xor_si512(c2[132],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(32),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(37),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(53),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(54),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(52),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(23),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(35),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(36),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(40),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(39),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(34),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(35),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[168],abshift_get(5),c2[169]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(38),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(50),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(4),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(57),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(49),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(62),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(63),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(1),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(18),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(58),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(59),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(1),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[220],abshift_get(63),c2[221]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(29),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(30),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(19),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(3),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(26),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(28),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(25),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(28),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(53),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(54),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(41),c2[253]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(63),c2[255]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(51),c2[253]),_mm512_permutex2var_epi8(c2[252],abshift_get(52),c2[253]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 30 + d2[180]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(14),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(39),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(39),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(40),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(46),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(47),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(31),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(46),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(20),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(21),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(49),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(50),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(13),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(39),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(34),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(35),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(12),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(36),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(26),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(27),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(59),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(38),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(39),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(45),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[53],abshift_get(46),c2[54]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(16),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[63],abshift_get(43),c2[64]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(26),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(27),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(51),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(59),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[75],abshift_get(60),c2[76]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(33),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(34),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(38),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(37),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(38),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(51),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(52),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(38),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(58),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(59),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(18),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(19),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(24),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(13),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(25),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(26),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(59),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(27),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(28),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(30),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(31),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(37),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(8),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(2),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(11),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(12),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(44),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(49),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(1),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(2),c2[150]),_mm512_xor_si512(c2[157],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(34),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(35),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(47),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(48),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(4),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(52),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(50),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(51),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(46),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(47),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(50),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(62),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(15),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(16),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(5),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(61),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(10),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(11),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(13),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(29),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(30),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(6),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(7),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(13),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(10),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(11),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(41),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(42),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(15),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(38),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(39),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(40),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(37),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(39),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(40),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(1),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(2),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(53),c2[253]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(11),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(63),c2[253]),c2[253]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 31 + d2[186]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(53),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(52),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(14),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(13),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(15),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(14),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(22),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(20),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(21),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(21),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(20),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(60),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(59),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(25),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(23),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(24),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(36),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(52),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(51),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(14),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(13),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(10),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(9),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(51),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(50),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(11),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(10),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(2),c2[41]),_mm512_xor_si512(c2[40],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(1),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(34),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(33),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(14),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(13),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(21),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(19),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(20),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(55),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(54),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(18),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(17),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(2),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(1),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(26),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(25),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(35),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(34),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(9),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(7),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(8),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(13),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(12),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(13),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(12),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(27),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(25),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(26),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(23),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(13),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(12),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(34),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(33),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(58),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(56),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(57),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(63),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(62),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(52),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(51),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(1),c2[114]),_mm512_xor_si512(c2[113],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(34),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(33),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(3),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(2),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(6),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(4),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(5),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(47),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(46),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(41),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(40),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(51),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(49),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(50),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(19),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(18),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(24),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(23),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(41),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(39),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(40),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(39),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(38),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(10),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(9),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(23),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(21),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(22),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(27),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(26),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(26),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(25),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(22),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(20),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(21),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(25),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(24),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(37),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(36),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(55),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(54),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(44),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(43),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(36),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(35),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(50),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(48),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(49),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(52),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(51),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(5),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(4),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(46),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(44),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(45),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(52),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(51),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(50),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(49),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(17),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(15),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(16),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(54),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(53),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(13),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(12),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(15),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(14),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(12),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(11),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(15),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(14),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(41),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(39),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(40),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(28),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(27),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(50),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(49),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(39),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(37),c2[256]),_mm512_permutex2var_epi8(c2[255],abshift_get(38),c2[256]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 32 + d2[192]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(19),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(44),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(44),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(45),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(51),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(52),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(38),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(51),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(25),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(26),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(54),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(55),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(18),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(44),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(39),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(40),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(17),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(41),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(31),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(32),c2[41]),_mm512_xor_si512(c2[51],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(43),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(44),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(50),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(51),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[61],abshift_get(21),c2[62]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(48),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(31),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(32),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(56),c2[74]),_mm512_xor_si512(c2[73],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(1),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(38),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(39),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(43),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(42),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(43),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(56),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(57),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(43),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(63),c2[97]),_mm512_xor_si512(c2[97],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(23),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(24),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(29),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[109],abshift_get(18),c2[110]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(30),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(31),c2[114]),_mm512_xor_si512(c2[123],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(32),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(33),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(35),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(36),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(13),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(7),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(16),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(17),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(49),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(54),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(6),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(7),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(9),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(5),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(39),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(40),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(52),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(53),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(57),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(55),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(56),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(51),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(52),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[170],abshift_get(47),c2[171]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(55),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(3),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(20),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(21),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(10),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(2),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(15),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(16),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(18),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(34),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(35),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(11),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(12),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(18),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(15),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(16),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(46),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(47),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(20),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(43),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(44),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(45),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(42),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(44),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(45),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(6),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[245],abshift_get(7),c2[246]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(58),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(16),c2[253]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[256],abshift_get(4),c2[257]),_mm512_permutex2var_epi8(c2[256],abshift_get(5),c2[257])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 33 + d2[198]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(3),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(8),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(41),c2[138]),_mm512_permutex2var_epi8(c2[253],abshift_get(41),c2[254])))); + +//row: 34 + d2[204]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(38),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(20),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(10),c2[184]),_mm512_permutex2var_epi8(c2[208],abshift_get(56),c2[209])))); + +//row: 35 + d2[210]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(61),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(22),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(23),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(30),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(29),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(4),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(33),c2[18]),_mm512_xor_si512(c2[17],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(60),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(22),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(18),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(59),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(19),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(10),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(42),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(22),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(29),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(63),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(26),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(10),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(34),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(43),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(17),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(15),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(21),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(21),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(35),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(21),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(42),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(2),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(7),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(60),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(9),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(42),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(11),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(14),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(55),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(49),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(59),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(27),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(32),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(49),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(2),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(47),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(18),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(31),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(35),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(34),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(30),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(33),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(45),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(63),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(52),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(44),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(58),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(60),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(13),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(54),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(60),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(58),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(25),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(62),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(21),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(23),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(20),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(23),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(49),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(36),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(58),c2[258]),_mm512_permutex2var_epi8(c2[255],abshift_get(47),c2[256])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 36 + d2[216]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(18),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(57),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(41),c2[185]),_mm512_permutex2var_epi8(c2[216],abshift_get(21),c2[217])))); + +//row: 37 + d2[222]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(38),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(39),c2[1]),_mm512_xor_si512(c2[3],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(1),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(8),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(6),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(7),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(46),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(11),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(13),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(37),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(38),c2[27]),_mm512_xor_si512(c2[27],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[24],abshift_get(60),c2[25]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(36),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(37),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(61),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(52),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(20),c2[49]),_mm512_xor_si512(c2[49],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(7),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(40),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(41),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(4),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(52),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(11),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(12),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(21),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[76],abshift_get(59),c2[77]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(63),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(63),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[88],abshift_get(13),c2[89]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(63),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(20),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(44),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(48),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(49),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(38),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(51),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(19),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(20),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(53),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[123],abshift_get(56),c2[124]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(32),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(33),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(27),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[132],abshift_get(37),c2[133]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(4),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(5),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(10),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[149],abshift_get(27),c2[150]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(24),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(25),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[160],abshift_get(60),c2[161]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(9),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(18),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(13),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[171],abshift_get(12),c2[172]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(8),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(10),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(11),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(23),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[182],abshift_get(41),c2[183]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(29),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(30),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(22),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[192],abshift_get(36),c2[193]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(38),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[207],abshift_get(55),c2[208]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(32),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(37),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(38),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[221],abshift_get(36),c2[222]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(3),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(39),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[232],abshift_get(40),c2[233]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(63),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(1),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(61),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[240],abshift_get(62),c2[241]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(1),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(27),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(13),c2[254]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[253],abshift_get(14),c2[254]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(36),c2[256]),_mm512_permutex2var_epi8(c2[253],abshift_get(25),c2[254])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 38 + d2[228]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(57),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(49),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(33),c2[125]),_mm512_permutex2var_epi8(c2[147],abshift_get(22),c2[148])))); + +//row: 39 + d2[234]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(2),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[37],abshift_get(29),c2[38]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(26),c2[90]),_mm512_permutex2var_epi8(c2[232],abshift_get(41),c2[233])))); + +//row: 40 + d2[240]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(47),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(37),c2[97]),_mm512_permutex2var_epi8(c2[208],abshift_get(56),c2[209]))); + +//row: 41 + d2[246]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(52),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(58),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(11),c2[111]),_mm512_permutex2var_epi8(c2[220],abshift_get(32),c2[221])))); + +//row: 42 + d2[252]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(14),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[4],abshift_get(39),c2[5]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(39),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(40),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(46),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(47),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(49),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(46),c2[16]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(20),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(21),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(49),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(50),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(13),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[28],abshift_get(39),c2[29]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(34),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[26],abshift_get(35),c2[27]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(12),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(36),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(26),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(27),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(59),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(38),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(39),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(45),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(46),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(14),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(16),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(43),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[61],abshift_get(26),c2[62]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[61],abshift_get(27),c2[62]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(51),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(59),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(60),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(33),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(34),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(38),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(37),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(38),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(51),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(52),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[98],abshift_get(38),c2[99]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(58),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(59),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(18),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[100],abshift_get(19),c2[101]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(24),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[108],abshift_get(13),c2[109]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(25),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[112],abshift_get(26),c2[113]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[121],abshift_get(59),c2[122]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(27),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(28),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(30),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[125],abshift_get(31),c2[126]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(8),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(2),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(11),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(12),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(44),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(49),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(1),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(2),c2[146]),_mm512_xor_si512(c2[159],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(34),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[156],abshift_get(35),c2[157]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[158],abshift_get(47),c2[159]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[158],abshift_get(48),c2[159]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[168],abshift_get(52),c2[169]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(50),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(51),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[168],abshift_get(46),c2[169]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[168],abshift_get(47),c2[169]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[180],abshift_get(50),c2[181]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(62),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(15),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(16),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(5),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(61),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(10),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(11),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(13),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(29),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[209],abshift_get(30),c2[210]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(6),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(7),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(13),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(10),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(11),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(41),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(42),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(15),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[230],abshift_get(38),c2[231]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(39),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[228],abshift_get(40),c2[229]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(37),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(39),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(40),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(1),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(2),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(53),c2[255]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[257],abshift_get(11),c2[258]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(63),c2[255]),c2[255])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 43 + d2[258]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(28),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(53),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(54),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(60),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[0],abshift_get(61),c2[1]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(60),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[12],abshift_get(35),c2[13]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[15],abshift_get(63),c2[16]),_mm512_xor_si512(c2[16],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[13],abshift_get(49),c2[14]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(27),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(53),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[25],abshift_get(49),c2[26]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(26),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[39],abshift_get(50),c2[40]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(40),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[38],abshift_get(41),c2[39]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(9),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[49],abshift_get(53),c2[50]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(59),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[48],abshift_get(60),c2[49]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[65],abshift_get(30),c2[66]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[64],abshift_get(57),c2[65]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(41),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(1),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(10),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(47),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[77],abshift_get(48),c2[78]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(52),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(52),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(1),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[89],abshift_get(2),c2[90]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[97],abshift_get(52),c2[98]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(9),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(32),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(33),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[109],abshift_get(38),c2[110]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(27),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(40),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[121],abshift_get(9),c2[122]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(42),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(44),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[124],abshift_get(45),c2[125]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[136],abshift_get(22),c2[137]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(16),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(25),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[133],abshift_get(26),c2[134]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[146],abshift_get(58),c2[147]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(63),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(15),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[144],abshift_get(16),c2[145]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[158],abshift_get(14),c2[159]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[161],abshift_get(49),c2[162]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(61),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(62),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[168],abshift_get(2),c2[169]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[172],abshift_get(1),c2[173]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(60),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(61),c2[174]),_mm512_xor_si512(c2[180],_mm512_xor_si512(_mm512_permutex2var_epi8(c2[184],abshift_get(12),c2[185]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[183],abshift_get(30),c2[184]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[196],abshift_get(19),c2[197]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(11),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(24),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[193],abshift_get(25),c2[194]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[194],abshift_get(4),c2[195]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(27),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[208],abshift_get(44),c2[209]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(20),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[205],abshift_get(21),c2[206]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(27),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(25),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(55),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[216],abshift_get(56),c2[217]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[217],abshift_get(50),c2[218]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(29),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(52),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[233],abshift_get(54),c2[234]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[241],abshift_get(51),c2[242]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[242],abshift_get(54),c2[243]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(15),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(16),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(3),c2[255]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[256],abshift_get(25),c2[257]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[254],abshift_get(13),c2[255]),_mm512_permutex2var_epi8(c2[254],abshift_get(14),c2[255]))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 44 + d2[264]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[3],abshift_get(5),c2[4]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[5],abshift_get(30),c2[6]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(31),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[2],abshift_get(38),c2[3]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[1],abshift_get(16),c2[2]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[16],abshift_get(37),c2[17]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(12),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[17],abshift_get(41),c2[18]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(4),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[29],abshift_get(30),c2[30]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[27],abshift_get(26),c2[28]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(3),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[41],abshift_get(27),c2[42]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[40],abshift_get(18),c2[41]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(50),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[51],abshift_get(30),c2[52]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[50],abshift_get(37),c2[51]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[61],abshift_get(7),c2[62]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[60],abshift_get(34),c2[61]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[62],abshift_get(18),c2[63]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(42),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[72],abshift_get(51),c2[73]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[73],abshift_get(25),c2[74]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[87],abshift_get(29),c2[88]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[86],abshift_get(29),c2[87]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[84],abshift_get(43),c2[85]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[85],abshift_get(14),c2[86]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[99],abshift_get(29),c2[100]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[96],abshift_get(50),c2[97]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[101],abshift_get(10),c2[102]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[111],abshift_get(15),c2[112]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[109],abshift_get(4),c2[110]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[113],abshift_get(17),c2[114]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[110],abshift_get(35),c2[111]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[122],abshift_get(50),c2[123]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(19),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[120],abshift_get(22),c2[121]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[137],abshift_get(63),c2[138]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[134],abshift_get(57),c2[135]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[135],abshift_get(3),c2[136]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[148],abshift_get(35),c2[149]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[147],abshift_get(40),c2[148]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[145],abshift_get(57),c2[146]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(55),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[157],abshift_get(26),c2[158]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[159],abshift_get(39),c2[160]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(43),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[173],abshift_get(42),c2[174]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[169],abshift_get(38),c2[170]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[181],abshift_get(41),c2[182]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(53),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[185],abshift_get(7),c2[186]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[197],abshift_get(60),c2[198]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(52),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[195],abshift_get(2),c2[196]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(4),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[204],abshift_get(21),c2[205]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[206],abshift_get(62),c2[207]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(4),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(2),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[218],abshift_get(33),c2[219]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(6),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[231],abshift_get(29),c2[232]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[229],abshift_get(31),c2[230]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[243],abshift_get(28),c2[244]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(31),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[244],abshift_get(57),c2[245]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[255],abshift_get(44),c2[256]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[252],abshift_get(2),c2[253]),_mm512_permutex2var_epi8(c2[255],abshift_get(55),c2[256])))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))); + +//row: 45 + d2[270]=_mm512_xor_si512(_mm512_permutex2var_epi8(c2[14],abshift_get(7),c2[15]),_mm512_xor_si512(_mm512_permutex2var_epi8(c2[74],abshift_get(21),c2[75]),_mm512_permutex2var_epi8(c2[120],abshift_get(15),c2[121]))); + } +} diff --git a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c index 94eb0a4d92..70bc03b953 100644 --- a/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c +++ b/openair1/PHY/CODING/nrLDPC_encoder/ldpc_encode_parity_check.c @@ -36,13 +36,27 @@ #include "assertions.h" #include "common/utils/LOG/log.h" - +#define USE_PERMUTEX +#ifdef __aarch64__ +#define USE_ALIGNR +#endif #ifdef __AVX512F__ +#if defined(__AVX512VBMI__) && defined(USE_PERMUTEX) +// For AVX512 machines, use an AVX512 version of the encoder for Zc=384 only for now. This is used almost exclusively for +// high-throughput cases. The version with "permutex2var" instruction uses less memory (i.e. 1/64th of the memory to store the +// input), but uses more reads instead of creating 64 shifts of the input with memcpy +#include "ldpc384_simd512_permutex_byte.c" +#else #include "ldpc384_simd512_byte.c" +#endif #else #include "ldpc384_byte.c" #endif +#ifdef USE_ALIGNR +#include "ldpc384_alignr_byte_128.c" +#else #include "ldpc384_byte_128.c" +#endif #include "ldpc352_byte.c" #include "ldpc352_byte_128.c" #include "ldpc320_byte.c" @@ -96,8 +110,13 @@ static void encode_parity_check_part_optim(uint8_t *cc, uint8_t *d, short BG,sho memcpy(&c[2 * i1 * Zc], &cc[i1 * Zc], Zc * sizeof(unsigned char)); memcpy(&c[(2 * i1 + 1) * Zc], &cc[i1 * Zc], Zc * sizeof(unsigned char)); } - for (int i1 = 1; i1 < simd_size; i1++) { - memcpy(&c[(2 * ncols * Zc * i1)], &c[i1], (2 * ncols * Zc * sizeof(unsigned char)) - i1); +#if (defined(USE_PERMUTEX) && defined(__AVX512VBMI__)) || defined(USE_ALIGNR) + if (Zc < 384 || BG == 2) +#endif + { + for (int i1 = 1; i1 < simd_size; i1++) { + memcpy(&c[(2 * ncols * Zc * i1)], &c[i1], (2 * ncols * Zc * sizeof(unsigned char)) - i1); + } } if (BG == 1) { switch (Zc) { diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_crc_byte.c b/openair1/PHY/CODING/nrPolar_tools/nr_crc_byte.c index 1908aa654c..2bc3c8b517 100644 --- a/openair1/PHY/CODING/nrPolar_tools/nr_crc_byte.c +++ b/openair1/PHY/CODING/nrPolar_tools/nr_crc_byte.c @@ -20,6 +20,7 @@ */ #include "PHY/CODING/nrPolar_tools/nr_polar_defs.h" +#include "common/utils/utils.h" // ----- Old implementation ---- const uint8_t **crc24c_generator_matrix(uint16_t payloadSizeBits) @@ -30,7 +31,7 @@ const uint8_t **crc24c_generator_matrix(uint16_t payloadSizeBits) uint8_t temp1[crcPolynomialSize], temp2[crcPolynomialSize]; uint8_t **crc_generator_matrix = - malloc(payloadSizeBits * sizeof(uint8_t *) + payloadSizeBits * crcPolynomialSize * sizeof(uint8_t)); + malloc_or_fail(payloadSizeBits * sizeof(uint8_t *) + payloadSizeBits * crcPolynomialSize * sizeof(uint8_t)); if (crc_generator_matrix) for (int i = 0; i < payloadSizeBits; i++) crc_generator_matrix[i] = ((uint8_t *)&crc_generator_matrix[payloadSizeBits]) + i * crcPolynomialSize; diff --git a/openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h b/openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h index 803854c23b..519f23175c 100644 --- a/openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h +++ b/openair1/PHY/CODING/nrPolar_tools/nr_polar_defs.h @@ -38,11 +38,13 @@ #include #include #include +#include #include "PHY/CODING/nrPolar_tools/nr_polar_dci_defs.h" #include "PHY/CODING/nrPolar_tools/nr_polar_uci_defs.h" #include "PHY/CODING/nrPolar_tools/nr_polar_pbch_defs.h" #include "PHY/CODING/coding_defs.h" +#include "PHY/sse_intrin.h" // #include "SIMULATION/TOOLS/sim.h" #define NR_POLAR_DECODER_LISTSIZE 8 // uint8_t diff --git a/openair1/PHY/CODING/nrSmallBlock/encodeSmallBlock.c b/openair1/PHY/CODING/nrSmallBlock/encodeSmallBlock.c index 3078243c8f..a3a5863542 100644 --- a/openair1/PHY/CODING/nrSmallBlock/encodeSmallBlock.c +++ b/openair1/PHY/CODING/nrSmallBlock/encodeSmallBlock.c @@ -31,11 +31,14 @@ */ #include "PHY/CODING/nrSmallBlock/nr_small_block_defs.h" +#include "common/utils/assertions.h" //input = [0 ... 0 c_K-1 ... c_2 c_1 c_0] //output = [d_31 d_30 ... d_2 d_1 d_0] uint32_t encodeSmallBlock(int in, int len) { + AssertFatal(len >= 3, "encodeSmallBlock only supports input lengths A >= 3, got A=%d", len); + uint32_t out = 0; for (int i = 0; i < len; i++) if ((in & (1 << i)) > 0) diff --git a/openair1/PHY/CODING/tests/CMakeLists.txt b/openair1/PHY/CODING/tests/CMakeLists.txt deleted file mode 100644 index 8d7fac20d7..0000000000 --- a/openair1/PHY/CODING/tests/CMakeLists.txt +++ /dev/null @@ -1,263 +0,0 @@ -# Define a macro to add tests for different physical simulators -macro(add_physim_test test_gen test_exec test_description test_label) - # catch all the arguments past the last expected arqument and store them in the options_list - set(options_list ${ARGN}) - set(test_name physim.${test_gen}.${test_exec}.${test_description}) - add_test( - NAME ${test_name} - COMMAND ${test_exec} ${options_list} - COMMAND_EXPAND_LISTS - ) - set_tests_properties(${test_name} PROPERTIES - LABELS "${test_exec}: ${test_label};${test_exec}" - ENVIRONMENT "LD_LIBRARY_PATH=." - ) - add_dependencies(tests ${test_exec}) -endmacro() - -#################################################################################### -###### dlsim unit test ###### -#################################################################################### - -add_physim_test(4g dlsim basic.test1 "10 MHz, R2.FDD (MCS 5), EVA5, -1dB" -m=5 -g=F -s=-1 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -z=2 -Tperf=60) -add_physim_test(4g dlsim basic.test2 "1.4 MHz, R4.FDD (MCS 4), EVA5, 0dB (70%)" -m=4 -g=F -s=0 -w=1.0 -f=.2 -n=1500 -B=6 -c=4 -z=2 -Tperf=60) -add_physim_test(4g dlsim basic.test3 "10 MHz, R3.FDD (MCS 15), EVA5, 6.7dB (70%)" -m=15 -g=F -s=6.7 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -z=2 -Tperf=60) -add_physim_test(4g dlsim basic.test4 "5 MHz, R3-1.FDD (MCS 15), EVA5, 6.7dB (70%)" -m=15 -g=F -s=6.7 -w=1.0 -f=.2 -n=1500 -B=25 -c=2 -z=2 -Tperf=60) -add_physim_test(4g dlsim basic.test5 "10 MHz, R3-1.FDD (MCS 15), EVA5, 6.7dB (30%)" -m=15 -g=G -s=1.4 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -z=2 -Tperf=25) -add_physim_test(4g dlsim basic.test6 "5 MHz, R3-1.FDD (MCS 15), ETU70, 1.4 dB (30%)" -m=15 -g=G -s=1.4 -w=1.0 -f=.2 -n=1500 -B=25 -c=2 -z=2 -Tperf=25) -add_physim_test(4g dlsim basic.test7 "5 MHz, R6.FDD (MCS 25), EVA5, 17.4 dB (70%)" -m=25 -g=F -s=17.4 -w=1.0 -f=.2 -n=1500 -B=25 -c=3 -z=2 -Tperf=60) -add_physim_test(4g dlsim basic.test8 "5 MHz, R6-1.FDD (MCS 24,18 PRB), EVA5, 17.5dB (70%)" -m=25 -g=F -s=17.5 -w=1.0 -f=.2 -n=1500 -B=25 -c=3 -z=2 -r=1022 -Tperf=60) -add_physim_test(4g dlsim basic.test9 "10 MHz, R7.FDD (MCS 25), EVA5, 17.7dB (70%)" -m=26 -g=F -s=17.7 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -z=2 -Tperf=60) -add_physim_test(4g dlsim 100rb.tm2.test1 "20 MHz, R.9 FDD (MCS 26), EVA5, 17.6dB (70%)" -m=26 -g=F -s=17.6 -w=1.0 -f=.2 -n=1500 -B=100 -c=2 -z=2 -Tperf=60) -add_physim_test(4g dlsim 100rb.tm2.test2 "20 MHz, R.9-2 FDD (MCS 26, 17PRB), EVA5, 17.3dB (70%)" -m=26 -g=F -s=17.3 -w=1.0 -f=.2 -n=1500 -B=100 -c=2 -z=2 -r=1600 -Tperf=60) -add_physim_test(4g dlsim 100rb.tm2.test3 "20 MHz, R.9-1 FDD (MCS 26, 83 PRB), EVA5, 16.6dB (70%)" -m=26 -g=F -s=16.6 -w=1.0 -f=.2 -n=1500 -B=100 -c=2 -z=2 -r=1899 -Tperf=60) -add_physim_test(4g dlsim 100rb.tm2.test4 "10 MHz, R.11 FDD (MCS 14), EVA5, 6.8 dB (70%)" -m=14 -g=F -s=6.8 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -x=2 -y=2 -z=2 -Tperf=60) -add_physim_test(4g dlsim 100rb.tm2.test5 "5 MHz, R.11-2 FDD (MCS 13), EVA5, 5.9 dB (70%)" -m=13 -g=F -s=5.9 -w=1.0 -f=.2 -n=1500 -B=25 -c=3 -x=2 -y=2 -z=2 -Tperf=60) - -#################################################################################### -###### ulsim unit test ###### -#################################################################################### - -add_physim_test(4g ulsim test1 "5 MHz, FDD (MCS 5), AWGN, 6dB" -BnbRBs=25 -mcs=5 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=6 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) -add_physim_test(4g ulsim test2 "5 MHz, FDD (MCS 16), AWGN , 12dB (70%)" -BnbRBs=25 -mcs=16 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=12 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) -add_physim_test(4g ulsim test3 "10 MHz, R3.FDD (MCS 5), AWGN, 6dB (70%)" -BnbRBs=50 -mcs=5 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=6 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) -add_physim_test(4g ulsim test4 "10 MHz, R3-1.FDD (MCS 16), AWGN, 12dB (70%)" -BnbRBs=50 -mcs=16 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=12 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) -add_physim_test(4g ulsim test5 "20 MHz, FDD (MCS 5), AWGN, 6dB (70%)" -BnbRBs=100 -mcs=5 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=6 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) -add_physim_test(4g ulsim test6 "20 MHz, FDD (MCS 16), AWGN, 12 dB (70%)" -BnbRBs=100 -mcs=16 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=12 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) - -#################################################################################### -###### ldpctest unit test ###### -#################################################################################### - -add_physim_test(5g ldpctest test1 "block length = 3872, BG1" -l3872 -s10 -n300) -add_physim_test(5g ldpctest test2 "block length = 4224, BG1" -l4224 -s10 -n300) -add_physim_test(5g ldpctest test3 "block length = 4576, BG1" -l4576 -s10 -n300) -add_physim_test(5g ldpctest test4 "block length = 4928, BG1" -l4928 -s10 -n300) -add_physim_test(5g ldpctest test5 "block length = 5280, BG1" -l5280 -s10 -n300) -add_physim_test(5g ldpctest test6 "block length = 5632, BG1" -l5632 -s10 -n300) -add_physim_test(5g ldpctest test7 "block length = 6336, BG1" -l6336 -s10 -n300) -add_physim_test(5g ldpctest test8 "block length = 7040, BG1" -l7040 -s10 -n300) -add_physim_test(5g ldpctest test9 "block length = 7744, BG1" -l7744 -s10 -n300) -add_physim_test(5g ldpctest test10 "block length = 8448, BG1" -l8448 -s10 -n300) -add_physim_test(5g ldpctest test11 "block length = 1, BG2" -l1 -s10 -n300) -add_physim_test(5g ldpctest test12 "block length = 100, BG2" -l100 -s10 -n300) -add_physim_test(5g ldpctest test13 "block length = 193, BG2" -l193 -s10 -n300) -add_physim_test(5g ldpctest test14 "block length = 500, BG2" -l500 -s10 -n300) -add_physim_test(5g ldpctest test15 "block length = 561, BG2" -l561 -s10 -n300) -add_physim_test(5g ldpctest test16 "block length = 600, BG2" -l600 -s10 -n300) -add_physim_test(5g ldpctest test17 "block length = 641, BG2" -l641 -s10 -n300) -add_physim_test(5g ldpctest test18 "block length = 2000, BG1" -l2000 -s10 -n300) -add_physim_test(5g ldpctest test19 "block length = 3000, BG1" -l3000 -s10 -n300) -add_physim_test(5g ldpctest test20 "block length = 3840, BG1" -l3840 -s10 -n300) - -#################################################################################### -###### polartest unit test ###### -#################################################################################### - -add_physim_test(5g polartest test1 "PBCH polar test" -q -s-10 -f0) -add_physim_test(5g polartest test2 "DCI polar test" -q -s-10 -f0 -m1) -add_physim_test(5g polartest test3 "UCI polar test,6-bit CRC" -q -s-2 -f2 -m2 -k12) -add_physim_test(5g polartest test4 "UCI polar test,11-bit CRC" -q -s-2 -f2 -m2 -k20) - -#################################################################################### -###### nr_pbchsim unit test ###### -#################################################################################### - -add_physim_test(5g nr_pbchsim 106rb.test1 "PBCH-only, 106 PRB, NID 2" -s-11 -S-8 -n30 -R106 -N2) -add_physim_test(5g nr_pbchsim 106rb.test2 "PBCH and synchronization, 106PBR" -s-11 -S-8 -n30 -o8000 -I -R106) -add_physim_test(5g nr_pbchsim 106rb.test3 "PBCH and synchronization, 106PBR, SSB SC OFFSET 6" -s-11 -S-8 -n30 -R106 -c6) -add_physim_test(5g nr_pbchsim 217rb.test1 "PBCH-only, 217 PRB" -s-10 -S-8 -n30 -R217) -add_physim_test(5g nr_pbchsim 217rb.test2 "PBCH and synchronization, 217 RPB" -s-10 -S-8 -n30 -o8000 -I -R217) -add_physim_test(5g nr_pbchsim 273rb.test1 "PBCH-only, 273 PRB" -s-10 -S-8 -n30 -R273) -add_physim_test(5g nr_pbchsim 273rb.test2 "PBCH and synchronization, 273 PRB" -s-10 -S-8 -n30 -o8000 -I -R273) -add_physim_test(5g nr_pbchsim otherSCS.test1 "PBCH-only, 15Khz, 5Mhz" -s-10 -S-8 -n30 -m0 -R25) -add_physim_test(5g nr_pbchsim otherSCS.test2 "PBCH-only, 120Khz, 50Mhz" -s-10 -S-8 -n30 -m3 -R32) - -#################################################################################### -###### nr_dlsim unit test ###### -#################################################################################### - -add_physim_test(5g nr_dlsim basic.test1 "106 PRB" -n300 -R106 -b106 -s5) -add_physim_test(5g nr_dlsim basic.test2 "217 PRB" -n300 -R217 -b217 -s5) -add_physim_test(5g nr_dlsim basic.test3 "273 PRB" -n300 -R273 -b273 -s5) -add_physim_test(5g nr_dlsim basic.test4 "HARQ test 25% TP 4 rounds" -n300 -s1 -S2 -t25) -add_physim_test(5g nr_dlsim basic.test5 "HARQ test 33% TP 3 rounds" -n300 -s1 -S2 -t33) -add_physim_test(5g nr_dlsim basic.test6 "HARQ test 50% TP 2 rounds" -n300 -s5 -S7 -t50) -add_physim_test(5g nr_dlsim basic.test7 "25 PRBs, 15 kHz SCS" -n300 -m0 -e0 -R25 -b25 -i 2 1 0) -add_physim_test(5g nr_dlsim basic.test8 "32 PRBs, 120 kHz SCS" -n300 -s5 -m3 -R32 -b32) -add_physim_test(5g nr_dlsim offset.test1 "106 PRB 25 PDSCH-Offset" -n300 -R106 -a25 -s5) -add_physim_test(5g nr_dlsim offset.test2 "106 PRB 51 PDSCH-Offset" -n300 -R106 -a51 -s5) -add_physim_test(5g nr_dlsim offset.test3 "217 PRB 100 PDSCH-PRBs" -n300 -R217 -b100 -s5) -add_physim_test(5g nr_dlsim offset.test4 "217 PRB 80 PDSCH-Offset" -n300 -R217 -a80 -s5) -add_physim_test(5g nr_dlsim offset.test5 "217 PRB 100 PDSCH-PRBs 110 PDSCH-Offset" -n300 -R217 -a110 -s5 -b100) -add_physim_test(5g nr_dlsim mcs.mimo.test1 "106 PRBs 50 PDSCH-PRBs MCS Index 27" -n300 -e27 -s30) -add_physim_test(5g nr_dlsim mcs.mimo.test2 "106 PRBs 50 PDSCH-PRBs MCS Index 16" -n300 -e16 -s11 -S13) -add_physim_test(5g nr_dlsim mcs.mimo.test3 "106 MCS-TABLE 256 QAM MCS Index 26" -n300 -q1 -e26 -s30) -add_physim_test(5g nr_dlsim mcs.mimo.test4 "MCS 0, low SNR performance" -n300 -e0 -t95 -S-1.0 -i 2 1 0) -add_physim_test(5g nr_dlsim mcs.mimo.test5 "4x4 MIMO, 1 Layer" -n30 -s20 -U 3 0 0 2 -gA -x1 -y4 -z4) -add_physim_test(5g nr_dlsim mcs.mimo.test6 "4x4 MIMO, 2 Layers" -n30 -s20 -U 3 0 0 2 -gA -x2 -y4 -z4) -add_physim_test(5g nr_dlsim mcs.mimo.test7 "4x4 MIMO, 4 Layers" -n30 -s20 -U 3 0 0 2 -x4 -y4 -z4) -add_physim_test(5g nr_dlsim dmrs.ptrs.test1 "3 PTRS, 8 Interpolated Symbols" -n300 -s5 -T 2 2 2) -add_physim_test(5g nr_dlsim dmrs.ptrs.test2 "6 PTRS, 5 Interpolated Symbols" -n300 -s5 -T 2 1 2) -add_physim_test(5g nr_dlsim dmrs.ptrs.test3 "11 PTRS, 0 Interpolated Symbols" -n300 -s5 -T 2 0 4) -add_physim_test(5g nr_dlsim dmrs.ptrs.test4 "Mapping type A, 2 DMRS Symbols" -n300 -s5 -S7 -U 2 0 1) -add_physim_test(5g nr_dlsim dmrs.ptrs.test5 "Mapping type A, 3 DMRS Symbols" -n300 -s5 -S7 -U 2 0 2) -add_physim_test(5g nr_dlsim dmrs.ptrs.test6 "Mapping type B, 4 DMRS Symbols" -n300 -s5 -S7 -U 2 1 3) - -#################################################################################### -###### nr_dlschsim unit test ###### -#################################################################################### - -add_physim_test(5g nr_dlschsim test1 "106 PRBs" -R 106 -m9 -s13 -n300) -add_physim_test(5g nr_dlschsim test2 "217 PRBs" -R 217 -m15 -s15 -n300) -add_physim_test(5g nr_dlschsim test3 "273 PRBs" -R 273 -m19 -s20 -n300) - -#################################################################################### -###### smallblocktest unit test ###### -#################################################################################### - -add_physim_test(5g smallblocktest test1 "3 bits" -l 3 -s -4 -d 1 -i 10000) -add_physim_test(5g smallblocktest test2 "6 bits" -l 6 -s -4 -d 1 -i 10000) -add_physim_test(5g smallblocktest test3 "7 bits" -l 7 -s -4 -d 1 -i 10000) -add_physim_test(5g smallblocktest test4 "11 bits" -l 11 -s -4 -d 1 -i 10000) - -#################################################################################### -###### nr_ulschsim unit test ###### -#################################################################################### - -add_physim_test(5g nr_ulschsim test1 "106 PRBs" -R 106 -m9 -s13 -n300) -add_physim_test(5g nr_ulschsim test2 "217 PRBs" -R 217 -m15 -s15 -n300) -add_physim_test(5g nr_ulschsim test3 "273 PRBs" -R 273 -m19 -s20 -n300) -add_physim_test(5g nr_ulschsim test4 "106 PRBs 4-layer MIMO" -R 106 -m9 -s13 -n300 -y4 -z4 -W4) - -#################################################################################### -###### nr_pucchsim unit test ###### -#################################################################################### - -add_physim_test(5g nr_pucchsim test1 "Format 0 1-bit ACK miss 106 PRB" -R 106 -i 1 -P 0 -b 1 -s-2 -n3000) -add_physim_test(5g nr_pucchsim test2 "Format 0 2-bit ACK miss 106 PRB" -R 106 -i 1 -P 0 -b 2 -s-2 -n3000) -add_physim_test(5g nr_pucchsim test3 "Format 0 2-bit ACK miss, 1-bit SR 106 PRB" -R 106 -i 1 -P 0 -b 2 -s-2 -c -n3000) -add_physim_test(5g nr_pucchsim test4 "Format 2 3-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 3 -s0 -n3000) -add_physim_test(5g nr_pucchsim test5 "Format 2 4-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 4 -s0 -n3000) -add_physim_test(5g nr_pucchsim test6 "Format 2 5-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 5 -s1 -n3000) -add_physim_test(5g nr_pucchsim test7 "Format 2 6-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 6 -s2 -n3000) -add_physim_test(5g nr_pucchsim test8 "Format 2 7-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 7 -s3 -n3000) -add_physim_test(5g nr_pucchsim test9 "Format 2 8-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 8 -s4 -n3000) -add_physim_test(5g nr_pucchsim test10 "Format 2 9-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 9 -s5 -n3000) -add_physim_test(5g nr_pucchsim test11 "Format 2 10-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 10 -s6 -n3000) -add_physim_test(5g nr_pucchsim test12 "Format 2 11-bit 2/106 PRB" -R 106 -i 1 -P 2 -b 11 -s6 -n3000) -add_physim_test(5g nr_pucchsim test13 "Format 2 12-bit 4/106 PRB" -R 106 -i 1 -P 2 -q4 -b 12 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test14 "Format 2 19-bit 4/106 PRB" -R 106 -i 1 -P 2 -q4 -b 19 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test15 "Format 2 12-bit 8/106 PRB" -R 106 -i 1 -P 2 -q8 -b 12 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test16 "Format 2 19-bit 8/106 PRB" -R 106 -i 1 -P 2 -q8 -b 19 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test17 "Format 2 32-bit 8/106 PRB" -R 106 -i 1 -P 2 -q8 -b 32 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test18 "Format 2 32-bit 16/106 PRB" -R 106 -i 1 -P 2 -q16 -b 32 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test19 "Format 2 64-bit 16/106 PRB" -R 106 -i 1 -P 2 -q16 -b 64 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test20 "Format 0 1-bit Ack miss 273 PRB" -R 273 -z8 -i 1 -P 0 -b 1 -s-2 -n3000) -add_physim_test(5g nr_pucchsim test21 "Format 0 2-bit Ack miss 273 PRB" -R 273 -z8 -i 1 -P 0 -b 2 -s-2 -n3000) -add_physim_test(5g nr_pucchsim test22 "Format 0 2-bit Ack miss+SR 273 PRB" -R 273 -z8 -i 1 -P 0 -b 2 -s-2 -c -n3000) -add_physim_test(5g nr_pucchsim test23 "Format 2 4-bit 2/273 PRB" -R 273 -z8 -i 1 -P 2 -b 4 -s-8 -S0 -n3000) -add_physim_test(5g nr_pucchsim test24 "Format 2 7-bit 2/273 PRB" -R 273 -z8 -i 1 -P 2 -b 7 -s3 -n3000) -add_physim_test(5g nr_pucchsim test25 "Format 2 11-bit 2/273 PRB" -R 273 -z8 -i 1 -P 2 -b 11 -s6 -n3000) -add_physim_test(5g nr_pucchsim test26 "Format 2 12-bit 8/273 PRB" -R 273 -z8 -i 1 -P 2 -q8 -b 12 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test27 "Format 2 19-bit 8/273 PRB" -R 273 -z8 -i 1 -P 2 -q8 -b 19 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test28 "Format 2 64-bit 16/273 PRB" -R 273 -z8 -i 1 -P 2 -q16 -b 64 -s-3 -n3000) -add_physim_test(5g nr_pucchsim test29 "Format 2 64-bit 16/273 PRB Delay 2us" -R 273 -z8 -i 1 -P 2 -q16 -b 64 -s0 -S7 -d 2 -n3000) - -#################################################################################### -###### nr_ulsim unit test ###### -#################################################################################### - -add_physim_test(5g nr_ulsim misc.test1 "MCS 9 106 PRBs" -n300 -m9 -r106 -s5) -add_physim_test(5g nr_ulsim misc.test2 "MCS 16 50 PRBs" -n300 -m16 -s10) -add_physim_test(5g nr_ulsim misc.test3 "MCS 28 50 PRBs" -n300 -m28 -s20) -add_physim_test(5g nr_ulsim misc.test4 "MCS 27 50 PRBs 256QAM" -n300 -m27 -s25 -q1) -add_physim_test(5g nr_ulsim misc.test5 "MCS 9 217 PRBs" -n300 -m9 -R217 -r217 -s5) -add_physim_test(5g nr_ulsim misc.test6 "MCS 9 273 PRBs" -n300 -m9 -R273 -r273 -s5) -add_physim_test(5g nr_ulsim misc.test7 "PUSCH Type A, 2 DMRS Symbols" -n300 -s5 -U 0,1,1,1) -add_physim_test(5g nr_ulsim misc.test8 "PUSCH Type A, 3 DMRS, 4 PTRS, 5 Interpolated Symbols" -n300 -s5 -T 1,2 -U 0,2,1,1) -add_physim_test(5g nr_ulsim misc.test9 "PUSCH Type B, 3 DMRS, 2 PTRS, 7 Interpolated Symbols" -n300 -s5 -T 2,2 -U 1,2,1,1) -add_physim_test(5g nr_ulsim misc.test10 "PUSCH Type B, 3 DMRS, 2 PTRS, 3 Interpolated Symbols" -n300 -s5 -a4 -b8 -T 1,2 -U 1,3,1,1) -add_physim_test(5g nr_ulsim misc.test11 "25 PRBs, 15 kHz SCS" -n300 -u0 -m0 -R25 -r25 -i 1,0) -add_physim_test(5g nr_ulsim misc.test12 "32 PRBs, 120 kHz SCS" -n300 -s5 -r32 -R32 -u3) -add_physim_test(5g nr_ulsim misc.test13 "MCS 0, low SNR performance" -n300 -m0 -S -0.6 -i 1,0) -add_physim_test(5g nr_ulsim misc.test14 "MCS 28, 106 PRBs, Time shift 8" -n300 -m28 -R106 -r106 -t90 -s24 -S24 -d 8) -add_physim_test(5g nr_ulsim misc.test15 "SRS, SNR 40 dB" -n300 -s40 -E 1) -add_physim_test(5g nr_ulsim sc-fdma.test1 "SC-FDMA, 50 PRBs" -n300 -s5 -Z) -add_physim_test(5g nr_ulsim sc-fdma.test2 "SC-FDMA, 75 PRBs" -n300 -s5 -Z -r75) -add_physim_test(5g nr_ulsim sc-fdma.test3 "SC-FDMA, 216 PRBs" -n150 -s5 -Z -r216 -R217) -add_physim_test(5g nr_ulsim sc-fdma.test4 "SC-FDMA, 273 PRBs" -n150 -s5 -Z -r270 -R273) -add_physim_test(5g nr_ulsim sc-fdma.test5 "SC-FDMA, 3 DMRS" -n300 -s5 -Z -U 0,2,1,2) -add_physim_test(5g nr_ulsim mimo.test1 "MCS 19 50 PRBs 2 RX_Antenna" -n300 -m19 -s10 -S15 -z2) -add_physim_test(5g nr_ulsim mimo.test2 "MCS 9 106 PRBs MIMO 2 layers" -n300 -m9 -r106 -s8 -W2 -y2 -z2) -add_physim_test(5g nr_ulsim mimo.test3 "MCS 10 106 PRBs MIMO 2 layers" -n300 -m10 -r106 -s12 -W2 -y2 -z2) -add_physim_test(5g nr_ulsim mimo.test4 "MCS 19 106 PRBs MIMO 2 layers" -n300 -m19 -r106 -s22 -W2 -y2 -z2) -add_physim_test(5g nr_ulsim mimo.test5 "MCS 9 106 PRBs MIMO 4 layers" -n300 -m9 -r106 -s10 -W4 -y4 -z4) -add_physim_test(5g nr_ulsim 3gpp.test1 "3GPP G-FR1-A5-13, PUSCH Type A, 40 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 0,1,1,2 -z2 -s12.4 -S12.4) -add_physim_test(5g nr_ulsim 3gpp.test2 "3GPP G-FR1-A5-13, PUSCH Type A, 40 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 0,1,1,2 -z4 -s8.5 -S8.5) -add_physim_test(5g nr_ulsim 3gpp.test3 "3GPP G-FR1-A5-13, PUSCH Type A, 40 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 0,1,1,2 -z8 -s5.4 -S5.4) -add_physim_test(5g nr_ulsim 3gpp.test4 "3GPP G-FR1-A5-8, PUSCH Type B, 5 MHz BW, 15 kHz SCS, 2 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R25 -r25 -U 1,1,1,2 -z2 -s12.5 -S12.5) -add_physim_test(5g nr_ulsim 3gpp.test5 "3GPP G-FR1-A5-8, PUSCH Type B, 5 MHz BW, 15 kHz SCS, 4 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R25 -r25 -U 1,1,1,2 -z4 -s8.9 -S8.9) -add_physim_test(5g nr_ulsim 3gpp.test6 "3GPP G-FR1-A5-8, PUSCH Type B, 5 MHz BW, 15 kHz SCS, 8 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R25 -r25 -U 1,1,1,2 -z8 -s5.7 -S5.7) -add_physim_test(5g nr_ulsim 3gpp.test7 "3GPP G-FR1-A5-9, PUSCH Type B, 10 MHz BW, 15 kHz SCS, 2 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R52 -r52 -U 1,1,1,2 -z2 -s12.6 -S12.6) -add_physim_test(5g nr_ulsim 3gpp.test8 "3GPP G-FR1-A5-9, PUSCH Type B, 10 MHz BW, 15 kHz SCS, 4 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R52 -r52 -U 1,1,1,2 -z4 -s8.9 -S8.9) -add_physim_test(5g nr_ulsim 3gpp.test9 "3GPP G-FR1-A5-9, PUSCH Type B, 10 MHz BW, 15 kHz SCS, 8 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R52 -r52 -U 1,1,1,2 -z8 -s5.8 -S5.8) -add_physim_test(5g nr_ulsim 3gpp.test10 "3GPP G-FR1-A5-10, PUSCH Type B, 20 MHz BW, 15 kHz SCS, 2 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R106 -r106 -U 1,1,1,2 -z2 -s12.3 -S12.3) -add_physim_test(5g nr_ulsim 3gpp.test11 "3GPP G-FR1-A5-10, PUSCH Type B, 20 MHz BW, 15 kHz SCS, 4 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R106 -r106 -U 1,1,1,2 -z4 -s8.8 -S8.8) -add_physim_test(5g nr_ulsim 3gpp.test12 "3GPP G-FR1-A5-10, PUSCH Type B, 20 MHz BW, 15 kHz SCS, 8 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R106 -r106 -U 1,1,1,2 -z8 -s5.7 -S5.7) -add_physim_test(5g nr_ulsim 3gpp.test13 "3GPP G-FR1-A5-11, PUSCH Type B, 10 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R24 -r24 -U 1,1,1,2 -z2 -s12.5 -S12.5) -add_physim_test(5g nr_ulsim 3gpp.test14 "3GPP G-FR1-A5-11, PUSCH Type B, 10 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R24 -r24 -U 1,1,1,2 -z4 -s8.6 -S8.6) -add_physim_test(5g nr_ulsim 3gpp.test15 "3GPP G-FR1-A5-11, PUSCH Type B, 10 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R24 -r24 -U 1,1,1,2 -z8 -s5.6 -S5.6) -add_physim_test(5g nr_ulsim 3gpp.test16 "3GPP G-FR1-A5-12, PUSCH Type B, 20 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R51 -r51 -U 1,1,1,2 -z2 -s12.5 -S12.5) -add_physim_test(5g nr_ulsim 3gpp.test17 "3GPP G-FR1-A5-12, PUSCH Type B, 20 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R51 -r51 -U 1,1,1,2 -z4 -s8.6 -S8.6) -add_physim_test(5g nr_ulsim 3gpp.test18 "3GPP G-FR1-A5-12, PUSCH Type B, 20 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R51 -r51 -U 1,1,1,2 -z8 -s5.6 -S5.6) -add_physim_test(5g nr_ulsim 3gpp.test19 "3GPP G-FR1-A5-13, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 1,1,1,2 -z2 -s12.5 -S12.5) -add_physim_test(5g nr_ulsim 3gpp.test20 "3GPP G-FR1-A5-13, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 1,1,1,2 -z4 -s8.7 -S8.7) -add_physim_test(5g nr_ulsim 3gpp.test21 "3GPP G-FR1-A5-13, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 1,1,1,2 -z8 -s5.5 -S5.5) -add_physim_test(5g nr_ulsim 3gpp.test22 "3GPP G-FR1-A5-14, PUSCH Type B, 100 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R273 -r273 -U 1,1,1,2 -z2 -s13.1 -S13.1) -add_physim_test(5g nr_ulsim 3gpp.test23 "3GPP G-FR1-A5-14, PUSCH Type B, 100 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R273 -r273 -U 1,1,1,2 -z4 -s9.2 -S9.2) -add_physim_test(5g nr_ulsim 3gpp.test24 "3GPP G-FR1-A5-14, PUSCH Type B, 100 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" -n300 -b14 -I8 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R273 -r273 -U 1,1,1,2 -z8 -s5.9 -S5.9) -add_physim_test(5g nr_ulsim 3gpp.test25 "3GPP G-FR1-A3-27, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test, 2 layers" -n300 -b14 -I15 -i 0,1 -g B,l -t70 -u 1 -m2 -R106 -r106 -U 1,1,1,2 -W2 -y2 -z2 -s1.7 -S1.7) -add_physim_test(5g nr_ulsim 3gpp.test26 "3GPP G-FR1-A3-27, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test, 2 layers" -n300 -b14 -I15 -i 0,1 -g B,l -t70 -u 1 -m2 -R106 -r106 -U 1,1,1,2 -W2 -y2 -z4 -s-2.1 -S-2.1) -add_physim_test(5g nr_ulsim 3gpp.test27 "3GPP G-FR1-A4-27, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test, 2 layers" -n300 -b14 -I15 -i 0,1 -g C,l -t70 -u 1 -m16 -R106 -r106 -U 1,1,1,2 -W2 -y2 -z2 -s18.7 -S18.7) -add_physim_test(5g nr_ulsim 3gpp.test28 "3GPP G-FR1-A4-27, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test, 2 layers" -n300 -b14 -I15 -i 0,1 -g C,l -t70 -u 1 -m16 -R106 -r106 -U 1,1,1,2 -W2 -y2 -z4 -s11.2 -S11.2) - -#################################################################################### -###### nr_prachsim unit test ###### -#################################################################################### - -add_physim_test(5g nr_prachsim test1 "30kHz SCS, 106 PRBs, Prach format A2" -a -s -30 -n 300 -p 63 -R 106) -add_physim_test(5g nr_prachsim test2 "30kHz SCS, 217 PRBs, Prach format A2" -a -s -30 -n 300 -p 63 -R 217) -add_physim_test(5g nr_prachsim test3 "30kHz SCS, 273 PRBs, Prach format A2" -a -s -30 -n 300 -p 63 -R 273) -add_physim_test(5g nr_prachsim test4 "30kHz SCS, 106 PRBs, Prach format 0" -a -s -30 -n 300 -p 63 -R 106 -c 4) -add_physim_test(5g nr_prachsim test5 "120kHz SCS, 32 PRBs, Prach format A2" -a -s -30 -n 300 -p 32 -R 32 -m 3 -c52) -add_physim_test(5g nr_prachsim test6 "120kHz SCS, 66 PRBs, Prach format A2" -a -s -30 -n 300 -p 32 -R 66 -m 3 -c52) -add_physim_test(5g nr_prachsim test7 "120kHz SCS, 66 PRBs, High Speed Enabled" -a -s -30 -n 300 -R 66 -m 3 -c52 -H) -add_physim_test(5g nr_prachsim test8 "15kHz SCS, 25 PRBs" -a -s -30 -n 300 -p 99 -R 25 -m 0) - -#################################################################################### -###### nr_psbchsim unit test ###### -#################################################################################### - -add_physim_test(5g nr_psbchsim test1 "SLSS Search" -I) -add_physim_test(5g nr_psbchsim test2 "PSBCH TxRx" -n 30) diff --git a/openair1/PHY/INIT/lte_param_init.c b/openair1/PHY/INIT/lte_param_init.c index 5b661d7c2d..81177a63cb 100644 --- a/openair1/PHY/INIT/lte_param_init.c +++ b/openair1/PHY/INIT/lte_param_init.c @@ -63,9 +63,9 @@ void lte_param_init(PHY_VARS_eNB **eNBp, PHY_VARS_UE *UE; RU_t *ru; printf("Start lte_param_init\n"); - *eNBp = malloc(sizeof(PHY_VARS_eNB)); - *UEp = malloc(sizeof(PHY_VARS_UE)); - *rup = malloc(sizeof(RU_t)); + *eNBp = malloc_or_fail(sizeof(PHY_VARS_eNB)); + *UEp = malloc_or_fail(sizeof(PHY_VARS_UE)); + *rup = malloc_or_fail(sizeof(RU_t)); eNB = *eNBp; UE = *UEp; ru = *rup; diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index ca453b6e65..60bc63dac4 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -42,6 +42,7 @@ #include "SCHED_NR/fapi_nr_l1.h" #include "PHY/NR_REFSIG/ul_ref_seq_nr.h" #include +#include "nfapi/open-nFAPI/fapi/inc/nr_fapi_p5_utils.h" int l1_north_init_gNB() { @@ -109,6 +110,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) common_vars->analog_bf = cfg->analog_beamforming_ve.analog_bf_vendor_ext.value; LOG_I(PHY, "L1 configured with%s analog beamforming\n", common_vars->analog_bf ? "" : "out"); if (common_vars->analog_bf) { + // True only if nrmac->beam_info.beam_mode == FAPI_ANALOG_BEAM, thus analog_beamforming=2 common_vars->num_beams_period = cfg->analog_beamforming_ve.num_beams_period_vendor_ext.value; LOG_I(PHY, "Max number of concurrent beams: %d\n", common_vars->num_beams_period); } else @@ -129,7 +131,6 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) crcTableInit(); init_byte2m128i(); - init_byte2bit16(); init_pucch2_luts(); nr_init_fde(); // Init array for frequency equalization of transform precoding of PUSCH @@ -363,7 +364,7 @@ void nr_phy_config_request(NR_PHY_Config_t *phy_config) NR_DL_FRAME_PARMS *fp = &RC.gNB[Mod_id]->frame_parms; nfapi_nr_config_request_scf_t *gNB_config = &RC.gNB[Mod_id]->gNB_config; - memcpy((void*)gNB_config,phy_config->cfg,sizeof(*phy_config->cfg)); + copy_config_request(phy_config->cfg, gNB_config); uint64_t dl_bw_khz = (12*gNB_config->carrier_config.dl_grid_size[gNB_config->ssb_config.scs_common.value].value)*(15<ssb_config.scs_common.value); fp->dl_CarrierFreq = ((dl_bw_khz>>1) + gNB_config->carrier_config.dl_frequency.value)*1000 ; diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index b167cebc26..e617b08172 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -484,7 +484,6 @@ void clean_UE_harq(PHY_VARS_NR_UE *UE) } for (int harq_pid = 0; harq_pid < NR_MAX_ULSCH_HARQ_PROCESSES; harq_pid++) { NR_UL_UE_HARQ_t *ul_harq_process = &UE->ul_harq_processes[harq_pid]; - ul_harq_process->tx_status = NEW_TRANSMISSION_HARQ; ul_harq_process->round = 0; } } @@ -519,17 +518,6 @@ static void sl_generate_psbch_dmrs_qpsk_sequences(PHY_VARS_NR_UE *UE, struct com idx = (((sl_dmrs_sequence[(m << 1) >> 5]) >> ((m << 1) & 0x1f)) & 3); modulated_dmrs_sym[m].r = mod_table[idx].r; modulated_dmrs_sym[m].i = mod_table[idx].i; - -#ifdef SL_DEBUG_INIT_DATA - printf("m:%d gold seq: %d b0-b1: %d-%d DMRS Symbols: %d %d\n", - m, - sl_dmrs_sequence[(m << 1) >> 5], - (((sl_dmrs_sequence[(m << 1) >> 5]) >> ((m << 1) & 0x1f)) & 1), - (((sl_dmrs_sequence[((m << 1) + 1) >> 5]) >> (((m << 1) + 1) & 0x1f)) & 1), - modulated_dmrs_sym[m].r, - modulated_dmrs_sym[m].i); - printf("idx:%d, qpsk_table.r:%d, qpsk_table.i:%d\n", idx, mod_table[idx].r, mod_table[idx].i); -#endif } #ifdef SL_DUMP_INIT_SAMPLES diff --git a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c index 591c589b49..b7ad400ff1 100644 --- a/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c +++ b/openair1/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c @@ -526,11 +526,7 @@ int32_t lte_srs_channel_estimation(LTE_DL_FRAME_PARMS *frame_parms, //if ((1<<(sub_frame_number%T_SFC))&transmission_offset_tdd[Ssrs]) { - if (generate_srs(frame_parms, - soundingrs_ul_config_dedicated, - &srs_vars->srs[eNB_id], - 0x7FFF, - subframe)==-1) { + if (generate_srs(frame_parms, soundingrs_ul_config_dedicated, &srs_vars->srs[eNB_id], INT16_MAX, subframe) == -1) { LOG_E(PHY,"lte_srs_channel_estimation: Error in generate_srs\n"); return(-1); } diff --git a/openair1/PHY/LTE_TRANSPORT/dci.c b/openair1/PHY/LTE_TRANSPORT/dci.c index d2ad87f717..c1f54fa9c3 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci.c +++ b/openair1/PHY/LTE_TRANSPORT/dci.c @@ -418,7 +418,10 @@ uint8_t generate_dci_top(uint8_t num_pdcch_symbols, // if REG is allocated to PHICH, skip it if (check_phich_reg(frame_parms,kprime,lprime,mi) == 1) { #ifdef DEBUG_DCI_ENCODING - printf("generate_dci: skipping REG %d (kprime %u, lprime %u)\n",(lprime==0)?(kprime/6) : (kprime>>2),kprime,lprime); + printf("generate_dci: skipping REG %u (kprime %u, lprime %u)\n", + (lprime == 0) ? (kprime / 6) : (kprime >> 2), + kprime, + lprime); #endif } else { // Copy REG to TX buffer diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c index 9c92503186..4e0a2163e3 100644 --- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c +++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c @@ -1993,6 +1993,7 @@ int get_narrowband_index(int N_RB_UL,int rb) { default: AssertFatal(1==0,"Impossible N_RB_UL %d\n",N_RB_UL); + return 0; break; } } @@ -2128,6 +2129,7 @@ int get_first_rb_in_narrowband(int N_RB_UL, default: AssertFatal(1==0,"Impossible N_RB_UL %d\n",N_RB_UL); + return 0; break; } } diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c index 8bdceceed8..5626f0a9df 100644 --- a/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c +++ b/openair1/PHY/LTE_TRANSPORT/dlsch_scrambling.c @@ -202,7 +202,7 @@ void dlsch_unscrambling(LTE_DL_FRAME_PARMS *frame_parms, for (i=0; i<(1+(G>>5)); i++) { for (j=0; j<32; j++,k++) { #ifdef DEBUG_SCRAMBLING - printf("unscrambling %d : %d xor %d =",k,llr[k],(s>>j)&1); + printf("unscrambling %d : %d xor %u =", k, llr[k], (s >> j) & 1); #endif llr[k] = ((2*((s>>j)&1))-1)*llr[k]; #ifdef DEBUG_SCRAMBLING diff --git a/openair1/PHY/LTE_TRANSPORT/edci.c b/openair1/PHY/LTE_TRANSPORT/edci.c index 8370b35b49..977dbd9ca7 100644 --- a/openair1/PHY/LTE_TRANSPORT/edci.c +++ b/openair1/PHY/LTE_TRANSPORT/edci.c @@ -262,7 +262,6 @@ void generate_mdci_top(PHY_VARS_eNB *eNB, int frame, int subframe, int16_t amp, mDCI_ALLOC_t *mdci; int coded_bits; LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; - int i; int gain_lin_QPSK; uint16_t *mpdcchtab; uint32_t x1 = 0, x2 = 0, s = 0; @@ -277,7 +276,7 @@ void generate_mdci_top(PHY_VARS_eNB *eNB, int frame, int subframe, int16_t amp, int *w; LOG_D(PHY, "generate_mdci_top: num_dci %d\n", mpdcch->num_dci); - for (i = 0; i < mpdcch->num_dci; i++) { + for (int i = 0; i < mpdcch->num_dci; i++) { mdci = &mpdcch->mdci_alloc[i]; AssertFatal(fp->frame_type == FDD, "TDD is not yet supported for MPDCCH\n"); AssertFatal(fp->Ncp == NORMAL, "Extended Prefix not yet supported for MPDCCH\n"); @@ -358,14 +357,14 @@ void generate_mdci_top(PHY_VARS_eNB *eNB, int frame, int subframe, int16_t amp, if (re_offset > fp->ofdm_symbol_size) re_offset -= (fp->ofdm_symbol_size - 1); - int32_t *txF = &txdataF[0][symbol_offset+re_offset]; - int32_t yIQ; + c16_t *txF = (c16_t *)&txdataF[0][symbol_offset + re_offset]; + c16_t yIQ; - for (i = 0; i < (coded_bits >> 1); i++) { + for (int i = 0; i < (coded_bits >> 1); i++) { // QPSK modulation to yIQ - ((int16_t *) & yIQ)[0] = (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK; + yIQ.r = *e_ptr == 1 ? -gain_lin_QPSK : gain_lin_QPSK; e_ptr++; - ((int16_t *) & yIQ)[1] = (*e_ptr == 1) ? -gain_lin_QPSK : gain_lin_QPSK; + yIQ.i = *e_ptr == 1 ? -gain_lin_QPSK : gain_lin_QPSK; e_ptr++; txF[mpdcchtab[i]] = yIQ; /* @@ -406,7 +405,7 @@ void generate_mdci_top(PHY_VARS_eNB *eNB, int frame, int subframe, int16_t amp, int last_prb = (mdci->narrowband*6) + nb_i0 + 5; int soffset[4] = {5,6,12,13}; - for (int lprime=0,i=0; lprime<4; lprime++) { + for (int lprime=0,ii=0; lprime<4; lprime++) { for (int nprb=0; nprb<110; nprb++) { if (nprbN_RB_DL) { re_offset = fp->first_carrier_offset + (12 * nprb); @@ -414,11 +413,11 @@ void generate_mdci_top(PHY_VARS_eNB *eNB, int frame, int subframe, int16_t amp, if (re_offset > fp->ofdm_symbol_size) re_offset -= (fp->ofdm_symbol_size - 1); - txF = &txdataF[0][symbol_offset + re_offset + fp->ofdm_symbol_size*soffset[lprime]]; + txF = (c16_t *)&txdataF[0][symbol_offset + re_offset + fp->ofdm_symbol_size * soffset[lprime]]; } - for (int mprime=0; mprime<3; mprime++,i+=2) { - if ((i & 0x1f) == 0) { + for (int mprime=0; mprime<3; mprime++,ii+=2) { + if ((ii & 0x1f) == 0) { s = lte_gold_generic(&x1, &x2, reset); reset = 0; } @@ -426,8 +425,8 @@ void generate_mdci_top(PHY_VARS_eNB *eNB, int frame, int subframe, int16_t amp, // select PRBs corresponding to narrowband if ((nprb>= first_prb) && (nprb<= last_prb)) { - ((int16_t *) & yIQ)[0] = (((s >> (i & 0x1f)) & 1) == 1) ? -gain_lin_QPSK : gain_lin_QPSK; - ((int16_t *) & yIQ)[1] = (((s >> ((i + 1) & 0x1f)) & 1) == 1) ? -gain_lin_QPSK : gain_lin_QPSK; + yIQ.r = (s >> (ii & 0x1f)) & 1 ? -gain_lin_QPSK : gain_lin_QPSK; + yIQ.i = (s >> ((ii + 1) & 0x1f)) & 1 ? -gain_lin_QPSK : gain_lin_QPSK; AssertFatal(mdci->transmission_type==1,"transmission_type %d!=1, handle this ...\n",mdci->transmission_type); if (mdci->transmission_type==1) { // same thing on both 107 and 109 @@ -435,9 +434,9 @@ void generate_mdci_top(PHY_VARS_eNB *eNB, int frame, int subframe, int16_t amp, txF[1+(5*mprime)] = yIQ; } else { // put on selected antenna port with w sequence if (((mprime+nprb)&1) == 0) - txF[off+(5*mprime)] = yIQ*w[lprime]; + txF[off + (5 * mprime)] = (c16_t){yIQ.r * w[lprime], yIQ.i * w[lprime]}; else - txF[off+(5*mprime)] = yIQ*w[3-lprime]; + txF[off + (5 * mprime)] = (c16_t){yIQ.r * w[3 - lprime], yIQ.i * w[3 - lprime]}; } /* diff --git a/openair1/PHY/LTE_TRANSPORT/phich_common.c b/openair1/PHY/LTE_TRANSPORT/phich_common.c index 302229b88d..48209274fc 100644 --- a/openair1/PHY/LTE_TRANSPORT/phich_common.c +++ b/openair1/PHY/LTE_TRANSPORT/phich_common.c @@ -390,7 +390,11 @@ void generate_phich_reg_mapping(LTE_DL_FRAME_PARMS *frame_parms) { frame_parms->phich_reg[1+(mprime<<1)][1] = ((frame_parms->Nid_cell*n1/n0) + mprime + (n1/3))%n1; frame_parms->phich_reg[1+(mprime<<1)][2] = ((frame_parms->Nid_cell*n2/n0) + mprime + (2*n2/3))%n2; //#ifdef DEBUG_PHICH - printf("phich_reg :%u => %d,%d,%d\n",mprime<<1,frame_parms->phich_reg[mprime<<1][0],frame_parms->phich_reg[mprime][1],frame_parms->phich_reg[mprime][2]); + printf("phich_reg :%d => %d,%d,%d\n", + mprime << 1, + frame_parms->phich_reg[mprime << 1][0], + frame_parms->phich_reg[mprime][1], + frame_parms->phich_reg[mprime][2]); printf("phich_reg :%d => %d,%d,%d\n",1+(mprime<<1),frame_parms->phich_reg[1+(mprime<<1)][0],frame_parms->phich_reg[1+(mprime<<1)][1],frame_parms->phich_reg[1+(mprime<<1)][2]); //#endif } diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index e220549045..6cb2de68d2 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -69,8 +69,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, uint32_t preamble_shift2; uint16_t preamble_index0=0,n_shift_ra=0,n_shift_ra_bar; uint16_t d_start=0; - uint16_t numshift=0; - uint16_t *prach_root_sequence_map; + uint16_t numshift = 0; uint8_t not_found; int k=0; uint16_t u; @@ -221,7 +220,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, if (eNB) start_meas(&eNB->rx_prach); - prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4; + const uint16_t *prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4; // PDP is oversampled, e.g. 1024 sample instead of 839 // Adapt the NCS (zero-correlation zones) with oversampling factor e.g. 1024/839 NCS2 = (N_ZC==839) ? ((NCS<<10)/839) : ((NCS<<8)/139); @@ -347,20 +346,31 @@ void rx_prach0(PHY_VARS_eNB *eNB, } } - if ((eNB==NULL) && ru->function == NGFI_RRU_IF4p5) { - /// **** send_IF4 of rxsigF to RAU **** /// - if (br_flag == 1) - send_IF4p5(ru, frame_prach, subframe, IF4p5_PRACH+1+ce_level); - else - send_IF4p5(ru, frame_prach, subframe, IF4p5_PRACH); - - return; - } else if (eNB!=NULL) { - if (LOG_DEBUGFLAG(DEBUG_PRACH)) { - int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0],840)); - - if ((en > 10)&&(br_flag==1)) LOG_I(PHY,"PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n",br_flag,ce_level,n_ra_prb,k,frame_prach,subframe,en); + if (!eNB) { + if (ru->function == NGFI_RRU_IF4p5) { + /// **** send_IF4 of rxsigF to RAU **** /// + if (br_flag == 1) + send_IF4p5(ru, frame_prach, subframe, IF4p5_PRACH + 1 + ce_level); + else + send_IF4p5(ru, frame_prach, subframe, IF4p5_PRACH); + } else { + LOG_E(PHY, "inconsistent case\n"); } + return; + } + + if (LOG_DEBUGFLAG(DEBUG_PRACH)) { + int en = dB_fixed(signal_energy((int32_t *)&rxsigF[0][0], 840)); + if ((en > 10) && (br_flag == 1)) + LOG_I(PHY, + "PRACH (br_flag %d,ce_level %d, n_ra_prb %d, k %d): Frame %d, Subframe %d => %d dB\n", + br_flag, + ce_level, + n_ra_prb, + k, + frame_prach, + subframe, + en); } // in case of RAU and prach received rx_thread wakes up prach @@ -495,7 +505,7 @@ void rx_prach0(PHY_VARS_eNB *eNB, new_dft = 0; if (br_flag == 1) { - Xu=(c16_t *)eNB->X_u_br[ce_level][preamble_offset-first_nonzero_root_idx]; + Xu = eNB->X_u_br[ce_level][preamble_offset - first_nonzero_root_idx]; prach_ifft = prach_ifftp[prach_ifft_cnt++]; if (eNB->prach_vars_br.repetition_number[ce_level]==1) memset(prach_ifft,0,((N_ZC==839)?2048:256)*sizeof(int32_t)); diff --git a/openair1/PHY/LTE_TRANSPORT/prach_common.c b/openair1/PHY/LTE_TRANSPORT/prach_common.c index 2d9ef9d712..6dfa1cdec6 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach_common.c +++ b/openair1/PHY/LTE_TRANSPORT/prach_common.c @@ -35,12 +35,13 @@ #include "PHY/phy_extern_ue.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "common/utils/lte/prach_utils.h" +#include "openair1/PHY/LTE_TRANSPORT/prach_extern.h" const uint16_t NCS_unrestricted[16] = {0, 13, 15, 18, 22, 26, 32, 38, 46, 59, 76, 93, 119, 167, 279, 419}; const uint16_t NCS_restricted[15] = {15, 18, 22, 26, 32, 38, 46, 55, 68, 82, 100, 128, 158, 202, 237}; // high-speed case const uint16_t NCS_4[7] = {2, 4, 6, 8, 10, 12, 15}; -int16_t ru[2*839]; // quantized roots of unity +c16_t root_unit[839]; // quantized roots of unity static uint32_t ZC_inv[839]; // multiplicative inverse for roots u uint16_t du[838]; @@ -303,8 +304,9 @@ const uint16_t prach_root_sequence_map4[138] = { 57, 82, 58, 81, 59, 80, 60, 79, 61, 78, 62, 77, 63, 76, 64, 75, 65, 74, 66, 73, 67, 72, 68, 71, 69, 70}; void dump_prach_config(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe) { - FILE *fd; - fd = fopen("prach_config.txt","w"); + FILE *fd = fopen("prach_config.txt", "w"); + if (!fd) + return; fprintf(fd,"prach_config: subframe = %d\n",subframe); fprintf(fd,"prach_config: N_RB_UL = %d\n",frame_parms->N_RB_UL); fprintf(fd,"prach_config: frame_type = %s\n",(frame_parms->frame_type==1) ? "TDD":"FDD"); @@ -367,13 +369,13 @@ int is_prach_subframe(LTE_DL_FRAME_PARMS *frame_parms, uint32_t frame, uint8_t s return(prach_mask); } - void compute_prach_seq(uint16_t rootSequenceIndex, uint8_t prach_ConfigIndex, uint8_t zeroCorrelationZoneConfig, uint8_t highSpeedFlag, frame_type_t frame_type, - uint32_t X_u[64][839]) { + c16_t X_u[64][839]) +{ // Compute DFT of x_u => X_u[k] = x_u(inv(u)*k)^* X_u[k] = exp(j\pi u*inv(u)*k*(inv(u)*k+1)/N_ZC) unsigned int k,inv_u,i,NCS=0,num_preambles; int N_ZC; @@ -495,7 +497,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex, for (k=0; kulsch_stats; st < eNB->ulsch_stats + sizeofArray(eNB->ulsch_stats); st++) if (st->rnti > 0 && st->round_trials[0] > 100) { for (int aa = 0; aa < eNB->frame_parms.nb_antennas_rx; aa++) diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c index d8d3008be7..9f850cf2b9 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c @@ -124,7 +124,7 @@ static int errorRB(int rb, char * table, int line) { return 0; } -#define rbAllocCheck(RBalL, TabLe) (RBalL) > sizeof(TabLe)/sizeof(*TabLe) ? errorRB(RBalL, #TabLe, __LINE__) : TabLe[RBalL] +#define rbAllocCheck(RBalL, TabLe) (RBalL) >= sizeof(TabLe) / sizeof(*TabLe) ? errorRB(RBalL, #TabLe, __LINE__) : TabLe[RBalL] void extract_dci1A_info(uint8_t N_RB_DL, frame_type_t frame_type, void *dci_pdu, DCI_INFO_EXTRACTED_t *pdci_info_extarcted) { uint8_t harq_pid=0; @@ -941,17 +941,17 @@ void extract_dci2A_info(uint8_t N_RB_DL, frame_type_t frame_type, uint8_t nb_ant pdci_info_extarcted->tpmi = tpmi; } -int check_dci_format1_1a_coherency(DCI_format_t dci_format, - uint8_t N_RB_DL, - uint16_t rnti, - uint16_t tc_rnti, - uint16_t si_rnti, - uint16_t ra_rnti, - uint16_t p_rnti, - uint32_t frame, - uint8_t subframe, - DCI_INFO_EXTRACTED_t *pdci_info_extarcted, - LTE_DL_UE_HARQ_t *pdlsch0_harq) +static int check_dci_format1_1a_coherency(DCI_format_t dci_format, + uint8_t N_RB_DL, + uint16_t rnti, + uint16_t tc_rnti, + uint16_t si_rnti, + uint16_t ra_rnti, + uint16_t p_rnti, + uint32_t frame, + uint8_t subframe, + DCI_INFO_EXTRACTED_t *pdci_info_extarcted, + LTE_DL_UE_HARQ_t *pdlsch0_harq) { uint8_t harq_pid = pdci_info_extarcted->harq_pid; uint32_t rballoc = pdci_info_extarcted->rballoc; @@ -982,34 +982,39 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, // I- check dci content minimum coherency if( ((rnti==si_rnti) || (rnti==p_rnti) || (rnti==ra_rnti)) && harq_pid > 0) { - return(0); + LOG_I(PHY, "bad system or random access rnti %x id, harq %d \n", rnti, harq_pid); + return (0); } if(harq_pid>=8) { - // LOG_I(PHY,"bad harq id \n"); - return(0); + LOG_I(PHY, "bad harq id %d\n", harq_pid); + return (0); } if(dci_format == format1 && ((rnti==si_rnti) || (rnti==p_rnti) || (rnti==ra_rnti)) ) { - // LOG_I(PHY,"bad dci format \n"); - return(0); + LOG_I(PHY, "bad dci format 1 with system rnti %x\n", rnti); + return (0); } if( mcs1 > 28) { + if (!pdlsch0_harq) { + LOG_E(PHY, "pointer to pdlsch0_harq is NULL\n"); + return 0; + } if(pdlsch0_harq->round == 0) { - // LOG_I(PHY,"bad dci mcs + round \n"); - return(0); + LOG_I(PHY, "bad dci mcs %d + round %d\n", mcs1, pdlsch0_harq->round); + return (0); } if((rnti==si_rnti) || (rnti==p_rnti) || (rnti==ra_rnti)) { - // LOG_I(PHY,"bad dci mcs + rnti \n"); - return(0); + LOG_I(PHY, "bad dci mcs %d + rnti %x\n", mcs1, rnti); + return (0); } } @@ -1065,47 +1070,47 @@ int check_dci_format1_1a_coherency(DCI_format_t dci_format, } } - - else if (dci_format == format1) - { - NPRB = conv_nprb(rah, rballoc, N_RB_DL); + else if (dci_format == format1) { + NPRB = conv_nprb(rah, rballoc, N_RB_DL); } - if(dci_format == format1A && rballoc > RIV_max) { - // LOG_I(PHY,"bad dci rballoc rballoc %d RIV_max %lld \n",rballoc, RIV_max); - // DCI false detection - return(0); + LOG_I(PHY, "bad dci rballoc rballoc %d RIV_max %lld \n", rballoc, RIV_max); + // DCI false detection + return (0); } if(NPRB == 0) { // DCI false detection - // LOG_I(PHY,"bad NPRB = 0 \n"); + LOG_I(PHY, "bad dci NPRB = 0 \n"); return(0); } // this a retransmission + if (!pdlsch0_harq) { + LOG_E(PHY, "pointer to pdlsch0_harq is NULL\n"); + return 0; + } if(pdlsch0_harq->round>0) { // compare old TBS to new TBS if((mcs1<29) && (pdlsch0_harq->TBS != TBStable[get_I_TBS(mcs1)][NPRB-1])) { - // this is an eNB issue - // retransmisison but old and new TBS are different !!! - // work around, consider it as a new transmission - LOG_E(PHY, - "Format1A Retransmission but TBS are different: consider it as new transmission !!!, round %d, mcs 1 %d, NPRB %d \n", - pdlsch0_harq->round, - mcs1, - NPRB); - pdlsch0_harq->round = 0; - //return(0); // ?? to cross check - return(0); // ?? to cross check + // this is an eNB issue + // retransmisison but old and new TBS are different !!! + // we have missed DCIs, consider it as a new transmission + LOG_W(PHY, + "dci format1A Retransmission but TBS are different: consider it as new transmission !!!, round %d, mcs 1 %d, NPRB " + "%d \n", + pdlsch0_harq->round, + mcs1, + NPRB); + pdlsch0_harq->round = 0; + return (0); } } - return(1); } @@ -1148,14 +1153,15 @@ int check_dci_format1c_coherency(uint8_t N_RB_DL, if(rballoc > RIV_max) { - // DCI false detection - return(0); + LOG_I(PHY, "bad dci format 1c rballoc rballoc %d RIV_max %u \n", rballoc, RIV_max); // DCI false detection + return (0); } if(NPRB == 0) { - // DCI false detection - return(0); + LOG_I(PHY, "bad dci format 1c NPRB = 0 \n"); + // DCI false detection + return (0); } return(1); @@ -1204,53 +1210,44 @@ int check_dci_format2_2a_coherency(DCI_format_t dci_format, #endif // I- check dci content minimum coherency - if(harq_pid>=8) - { - // LOG_I(PHY,"bad harq pid\n"); + if (harq_pid >= 8) { + LOG_I(PHY, "bad dci foramt2 harq pid %d\n", harq_pid); return(0); } - if( (rnti==si_rnti) || (rnti==p_rnti) || (rnti==ra_rnti) ) - { - // LOG_I(PHY,"bad rnti\n"); - return(0); + if ((rnti == si_rnti) || (rnti == p_rnti) || (rnti == ra_rnti)) { + LOG_I(PHY, "bad dci format 2 rnti %x\n", rnti); + return (0); } - - if( mcs1 > 28) - { - if(pdlsch0_harq->round == 0) - { - // LOG_I(PHY,"bad mcs1\n"); - return(0); - } + if (!pdlsch0_harq) { + LOG_E(PHY, "pointer to pdlsch0_harq is NULL\n"); + return 0; + } + if ((mcs1 > 28) && !pdlsch0_harq->round) { + LOG_I(PHY, "bad mcs1 %d while round is %d\n", mcs1, pdlsch0_harq->round); + return (0); } - if( mcs2 > 28) - { - if(pdlsch1_harq->round == 0) - { - // LOG_I(PHY,"bad mcs2\n"); - return(0); - } + if (!pdlsch1_harq) { + LOG_E(PHY, "pointer to pdlsch0_harq is NULL\n"); + return 0; + } + if ((mcs2 > 28) && !pdlsch1_harq->round) { + LOG_I(PHY, "bad mcs2 %d while round is %d\n", mcs2, pdlsch0_harq->round); + return (0); } - - if((pdlsch0_harq->round == 0) && (rv1 > 0) && (mcs1 != 0)) - { - // DCI false detection - // LOG_I(PHY,"bad rv1\n"); + if ((pdlsch0_harq->round == 0) && (rv1 > 0) && (mcs1 != 0)) { + LOG_I(PHY, "bad mcs2 %d while round is %d and rv1 %d and mcs1 %d\n", mcs2, pdlsch0_harq->round, rv1, mcs1); return(0); } - if((pdlsch1_harq->round == 0) && (rv2 > 0) && (mcs2 != 0)) - { - // DCI false detection - // LOG_I(PHY,"bad rv2\n"); + if ((pdlsch1_harq->round == 0) && (rv2 > 0) && (mcs2 != 0)) { + LOG_I(PHY, "bad mcs2 %d while round is %d and rv2 %d \n", mcs2, pdlsch0_harq->round, rv2); return(0); } - switch (N_RB_DL) { case 6: if (rah == 0) @@ -1307,14 +1304,14 @@ int check_dci_format2_2a_coherency(DCI_format_t dci_format, if( (rballoc > RIV_max) && (rah == 1) ) { // DCI false detection - // LOG_I(PHY,"bad rballoc %d RIV_max %lld\n", rballoc, RIV_max); + LOG_I(PHY, "bad rballoc %d RIV_max %lld\n", rballoc, RIV_max); return(0); } if(NPRB == 0) { // DCI false detection - // LOG_I(PHY,"bad NPRB\n"); + LOG_I(PHY, "dci format 2 bad NPRB %d\n", NPRB); return(0); } @@ -1627,8 +1624,13 @@ void prepare_dl_decoding_format1_1A(DCI_format_t dci_format, { if(mcs1 < 29) { - pdlsch0_harq->TBS = TBStable[get_I_TBS(mcs1)][NPRB4TBS-1]; - pdlsch0_harq->Qm = get_Qm(mcs1); + int tbs = get_I_TBS(mcs1); + if (NPRB4TBS > 110 || tbs >= TBStable_rowCnt) { + LOG_E(PHY, "NPRB4TBS %d out of array\n", NPRB4TBS); + pdlsch0_harq->TBS = 0; + } else + pdlsch0_harq->TBS = TBStable[tbs][NPRB4TBS - 1]; + pdlsch0_harq->Qm = get_Qm(mcs1); } } @@ -2304,11 +2306,8 @@ int generate_ue_dlsch_params_from_dci(int frame, p_rnti,frame,subframe, &dci_info_extarcted, dlsch0_harq); - if(status == 0) - { - printf("bad DCI 1A !!! \n"); - return(-1); - } + if (status == 0) // log of error is done + return (-1); // dci is correct ==> update internal structure and prepare dl decoding #ifdef DEBUG_DCI @@ -2412,12 +2411,8 @@ int generate_ue_dlsch_params_from_dci(int frame, p_rnti,frame,subframe, &dci_info_extarcted, dlsch0_harq); - if(status == 0) - { - printf("bad DCI 1 !!! \n"); - return(-1); - } - + if (status == 0) // log of error is done + return (-1); // dci is correct ==> update internal structure and prepare dl decoding #ifdef DEBUG_DCI @@ -3528,8 +3523,14 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, if (rballoc > RIV_max) { - LOG_E(PHY,"frame %d, subframe %d, rnti %x, format %d: FATAL ERROR: generate_ue_ulsch_params_from_dci, rb_alloc[%d] > RIV_max[%d]\n", - proc->frame_rx, subframe, rnti, dci_format,rballoc,RIV_max); + LOG_W(PHY, + "frame %d, subframe %d, rnti %x, format %d, generate_ue_ulsch_params_from_dci impossible rb_alloc[%d] > RIV_max[%d]\n", + proc->frame_rx, + subframe, + rnti, + dci_format, + rballoc, + RIV_max); LOG_E(PHY,"Wrong DCI0 detection, do not transmit PUSCH for HARQID: %d\n",harq_pid); ulsch->harq_processes[harq_pid]->subframe_scheduling_flag = 0; return(-1); @@ -4965,7 +4966,8 @@ double sinr_eff_cqi_calc(PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe) } } - s_dB[count] = 10*log10(abs_channel/2) - meas->n0_power_avg_dB; + if (abs_channel > 0) + s_dB[count] = 10 * log10(abs_channel / 2.0) - meas->n0_power_avg_dB; } break; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dci_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/dci_ue.c index 5dba6257df..24c32729aa 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dci_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dci_ue.c @@ -1381,12 +1381,6 @@ void dci_decoding(uint8_t DCI_LENGTH, //debug_printf("Done DCI Viterbi \n"); } - -static uint8_t dci_decoded_output[RX_NB_TH][(MAX_DCI_SIZE_BITS+64)/8]; - - - - int get_nCCE_offset_l1(int *CCE_table, const unsigned char L, const int nCCE, @@ -1593,19 +1587,19 @@ void dci_decoding_procedure0(LTE_UE_PDCCH **pdcch_vars, switch (L2) { case 1: - CCEmap_mask = (1<<(CCEind&0x1f)); + CCEmap_mask = (1U << (CCEind & 0x1f)); break; case 2: - CCEmap_mask = (3<<(CCEind&0x1f)); + CCEmap_mask = (3U << (CCEind & 0x1f)); break; case 4: - CCEmap_mask = (0xf<<(CCEind&0x1f)); + CCEmap_mask = (0xfU << (CCEind & 0x1f)); break; case 8: - CCEmap_mask = (0xff<<(CCEind&0x1f)); + CCEmap_mask = (0xffU << (CCEind & 0x1f)); break; default: @@ -1625,25 +1619,14 @@ void dci_decoding_procedure0(LTE_UE_PDCCH **pdcch_vars, else LOG_D(PHY,"[DCI search nPdcch %d - ue spec %x] Attempting candidate %d Aggregation Level %d DCI length %d at CCE %d/%d (CCEmap %x,CCEmap_cand %x) format %d\n", pdcch_vars[eNB_id]->num_pdcch_symbols,pdcch_vars[eNB_id]->crnti,m,L2,sizeof_bits,CCEind,nCCE,*CCEmap,CCEmap_mask,format_c); - - dci_decoding(sizeof_bits, - L, - &pdcch_vars[eNB_id]->e_rx[CCEind*72], - &dci_decoded_output[current_thread_id][0]); - /* - for (i=0;i<3+(sizeof_bits>>3);i++) - printf("dci_decoded_output[%d][%d] => %x\n",current_thread_id,i,dci_decoded_output[current_thread_id][i]); - */ - - crc = (crc16(&dci_decoded_output[current_thread_id][0],sizeof_bits)>>16) ^ extract_crc(&dci_decoded_output[current_thread_id][0],sizeof_bits); + uint8_t dci_decoded_output[(MAX_DCI_SIZE_BITS + 64) / 8] = {}; + dci_decoding(sizeof_bits, L, &pdcch_vars[eNB_id]->e_rx[CCEind * 72], dci_decoded_output); + crc = (crc16(dci_decoded_output, sizeof_bits) >> 16) ^ extract_crc(dci_decoded_output, sizeof_bits); #ifdef DEBUG_DCI_DECODING printf("crc =>%x\n",crc); #endif - - if (((L>1) && ((crc == si_rnti)|| - (crc == p_rnti)|| - (crc == ra_rnti)/*||(crc == 0xfff9)*/))|| - (crc == pdcch_vars[eNB_id]->crnti)) { + uint8_t *ptr = dci_decoded_output; + if ((do_common && (L > 1) && (crc == si_rnti || crc == p_rnti || crc == ra_rnti)) || (crc == pdcch_vars[eNB_id]->crnti)) { dci_alloc[*dci_cnt].dci_length = sizeof_bits; dci_alloc[*dci_cnt].rnti = crc; dci_alloc[*dci_cnt].L = L; @@ -1651,30 +1634,19 @@ void dci_decoding_procedure0(LTE_UE_PDCCH **pdcch_vars, //printf("DCI FOUND !!! crc =>%x, sizeof_bits %d, sizeof_bytes %d \n",crc, sizeof_bits, sizeof_bytes); if (sizeof_bytes<=4) { - dci_alloc[*dci_cnt].dci_pdu[3] = dci_decoded_output[current_thread_id][0]; - dci_alloc[*dci_cnt].dci_pdu[2] = dci_decoded_output[current_thread_id][1]; - dci_alloc[*dci_cnt].dci_pdu[1] = dci_decoded_output[current_thread_id][2]; - dci_alloc[*dci_cnt].dci_pdu[0] = dci_decoded_output[current_thread_id][3]; -#ifdef DEBUG_DCI_DECODING - printf("DCI => %x,%x,%x,%x\n",dci_decoded_output[current_thread_id][0], - dci_decoded_output[current_thread_id][1], - dci_decoded_output[current_thread_id][2], - dci_decoded_output[current_thread_id][3]); -#endif + dci_alloc[*dci_cnt].dci_pdu[3] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[2] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[1] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[0] = *ptr++; } else { - dci_alloc[*dci_cnt].dci_pdu[7] = dci_decoded_output[current_thread_id][0]; - dci_alloc[*dci_cnt].dci_pdu[6] = dci_decoded_output[current_thread_id][1]; - dci_alloc[*dci_cnt].dci_pdu[5] = dci_decoded_output[current_thread_id][2]; - dci_alloc[*dci_cnt].dci_pdu[4] = dci_decoded_output[current_thread_id][3]; - dci_alloc[*dci_cnt].dci_pdu[3] = dci_decoded_output[current_thread_id][4]; - dci_alloc[*dci_cnt].dci_pdu[2] = dci_decoded_output[current_thread_id][5]; - dci_alloc[*dci_cnt].dci_pdu[1] = dci_decoded_output[current_thread_id][6]; - dci_alloc[*dci_cnt].dci_pdu[0] = dci_decoded_output[current_thread_id][7]; -#ifdef DEBUG_DCI_DECODING - printf("DCI => %x,%x,%x,%x,%x,%x,%x,%x\n", - dci_decoded_output[current_thread_id][0],dci_decoded_output[current_thread_id][1],dci_decoded_output[current_thread_id][2],dci_decoded_output[current_thread_id][3], - dci_decoded_output[current_thread_id][4],dci_decoded_output[current_thread_id][5],dci_decoded_output[current_thread_id][6],dci_decoded_output[current_thread_id][7]); -#endif + dci_alloc[*dci_cnt].dci_pdu[7] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[6] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[5] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[4] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[3] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[2] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[1] = *ptr++; + dci_alloc[*dci_cnt].dci_pdu[0] = *ptr++; } if (crc==si_rnti /*|| crc==0xfff9*/) { @@ -1689,8 +1661,7 @@ void dci_decoding_procedure0(LTE_UE_PDCCH **pdcch_vars, pdcch_vars[eNB_id]->nCCE[subframe]=CCEind; *dci_cnt = *dci_cnt+1; } else if (crc==pdcch_vars[eNB_id]->crnti) { - - if ((mode&UL_DCI)&&(format_c == format0)&&((dci_decoded_output[current_thread_id][0]&0x80)==0)) {// check if pdu is format 0 or 1A + if ((mode & UL_DCI) && (format_c == format0) && ((dci_decoded_output[0] & 0x80) == 0)) { // check if pdu is format 0 or 1A if (*format0_found == 0) { dci_alloc[*dci_cnt].format = format0; *format0_found = 1; @@ -1772,8 +1743,7 @@ uint16_t dci_CRNTI_decoding_procedure(PHY_VARS_UE *ue, int16_t eNB_id, uint8_t subframe) { - - uint8_t dci_cnt=0,old_dci_cnt=0; + uint8_t dci_cnt = 0; uint32_t CCEmap0=0,CCEmap1=0,CCEmap2=0; LTE_UE_PDCCH **pdcch_vars = ue->pdcch_vars[ue->current_thread_id[subframe]]; LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; @@ -1879,8 +1849,7 @@ uint16_t dci_CRNTI_decoding_procedure(PHY_VARS_UE *ue, &CCEmap1, &CCEmap2); - if ((CCEmap0==0xffff)|| - ((format0_found==1)&&(format_c_found==1))) + if ((CCEmap0 == 0xffff) || ((format0_found == 1) && (format_c_found == 1))) return(dci_cnt); if (DCIFormat == format1) @@ -1892,7 +1861,7 @@ uint16_t dci_CRNTI_decoding_procedure(PHY_VARS_UE *ue, //printf("[DCI search] Format 1/1A aggregation 1\n"); - old_dci_cnt=dci_cnt; + int old_dci_cnt = dci_cnt; dci_decoding_procedure0(pdcch_vars,0,mode,subframe, dci_alloc, eNB_id, @@ -1916,15 +1885,12 @@ uint16_t dci_CRNTI_decoding_procedure(PHY_VARS_UE *ue, &CCEmap1, &CCEmap2); - if ((CCEmap0==0xffff) || - (format_c_found==1)) + if ((CCEmap0 == 0xffff) || (format_c_found == 1)) return(dci_cnt); if (dci_cnt>old_dci_cnt) return(dci_cnt); - //printf("Crnti 1 decoding frame param agregation %d DCI %d \n",agregationLevel,DCIFormat); - } else if (DCIFormat == format1A) { diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c index ac045480da..9aa520c585 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_demodulation.c @@ -2867,16 +2867,16 @@ void float_to_chan_est(int32_t **dl_ch_estimates_ext, for (aarx=0; aarx=1) - imag = 0x7FFF; + imag = INT16_MAX; else imag = cimag(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])*32768; if (creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])<-1) - real = 0x8000; + real = -INT16_MAX; else if (creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])>=1) - real = 0x7FFF; + real = INT16_MAX; else real = creal(dl_ch_estimates_ext_f[aatx*n_rx + aarx][re])*32768; @@ -2910,16 +2910,16 @@ void float_to_rxdataF(int32_t **rxdataF_ext, for (aarx=0; aarx=1) - imag = 0x7FFF; + imag = INT16_MAX; else imag = cimag(rxdataF_f[aarx][re])*32768; if (creal(rxdataF_f[aarx][re])<-1) - real = 0x8000; + real = -INT16_MAX; else if (creal(rxdataF_f[aarx][re])>=1) - real = 0x7FFF; + real = INT16_MAX; else real = creal(rxdataF_f[aarx][re])*32768; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c index fd1b2a3e9a..bcab4cd8dd 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation.c @@ -38,12 +38,9 @@ #include "transport_proto_ue.h" #include "PHY/sse_intrin.h" -//#define DEBUG_LLR_SIC - -const int16_t zeros[8] __attribute__((aligned(16))) = {0, 0, 0, 0, 0, 0, 0, 0}; -const int16_t ones[8] __attribute__((aligned(16))) = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; +// #define DEBUG_LLR_SIC //============================================================================================== -// Auxiliary Makros +// Auxiliary Makros // calculates psi_a = psi_r*a_r + psi_i*a_i #define prodsum_psi_a_epi16(psi_r, a_r, psi_i, a_i, psi_a) \ @@ -54,18 +51,18 @@ const int16_t ones[8] __attribute__((aligned(16))) = {0xffff, 0xffff, 0xffff, 0x simde__m128i psi_a = simde_mm_adds_epi16(tmp_result, tmp_result2); // calculate interference magnitude -#define interference_abs_epi16(psi, int_ch_mag, int_mag, c1, c2) \ - tmp_result = simde_mm_cmplt_epi16(psi, int_ch_mag); \ - tmp_result2 = simde_mm_xor_si128(tmp_result, (*(simde__m128i *)&ones[0])); \ - tmp_result = simde_mm_and_si128(tmp_result, c1); \ - tmp_result2 = simde_mm_and_si128(tmp_result2, c2); \ +#define interference_abs_epi16(psi, int_ch_mag, int_mag, c1, c2) \ + tmp_result = simde_mm_cmplt_epi16(psi, int_ch_mag); \ + tmp_result2 = simde_mm_xor_si128(tmp_result, ones); \ + tmp_result = simde_mm_and_si128(tmp_result, c1); \ + tmp_result2 = simde_mm_and_si128(tmp_result2, c2); \ simde__m128i int_mag = simde_mm_or_si128(tmp_result, tmp_result2); // calculate interference magnitude // tmp_result = ones in shorts corr. to interval 2<=x<=4, tmp_result2 interval < 2, tmp_result3 interval 46 #define interference_abs_64qam_epi16(psi, int_ch_mag, int_two_ch_mag, int_three_ch_mag, a, c1, c3, c5, c7) \ tmp_result = simde_mm_cmplt_epi16(psi, int_two_ch_mag); \ - tmp_result3 = simde_mm_xor_si128(tmp_result, (*(simde__m128i *)&ones[0])); \ + tmp_result3 = simde_mm_xor_si128(tmp_result, ones); \ tmp_result2 = simde_mm_cmplt_epi16(psi, int_ch_mag); \ tmp_result = simde_mm_xor_si128(tmp_result, tmp_result2); \ tmp_result4 = simde_mm_cmpgt_epi16(psi, int_three_ch_mag); \ @@ -1123,6 +1120,8 @@ void qpsk_qam16(int16_t *stream0_in, oai_mm_separate_real_imag_parts(&ch_mag_int, NULL, xmm2, xmm3); simde__m128i tmp_result, tmp_result2; + //generate a const of all ff in case the compiler doesn't optimize it inside the loop + const simde__m128i ones = allones128(); // calculate optimal interference amplitudes interference_abs_epi16(psi_r_p1_p1 , ch_mag_int, a_r_p1_p1 , ONE_OVER_SQRT_10_Q15, THREE_OVER_SQRT_10); interference_abs_epi16(psi_i_p1_p1 , ch_mag_int, a_i_p1_p1 , ONE_OVER_SQRT_10_Q15, THREE_OVER_SQRT_10); @@ -1351,6 +1350,8 @@ void qpsk_qam64(short *stream0_in, two_ch_mag_int_with_sigma2 = ch_mag_int; // *4 three_ch_mag_int_with_sigma2 = simde_mm_adds_epi16(ch_mag_int_with_sigma2, two_ch_mag_int_with_sigma2); // *6 simde__m128i tmp_result, tmp_result2, tmp_result3, tmp_result4; + //generate a const of all ff in case the compiler doesn't optimize it inside the loop + const simde__m128i ones = allones128(); interference_abs_64qam_epi16(psi_r_p1_p1, ch_mag_int_with_sigma2, two_ch_mag_int_with_sigma2, three_ch_mag_int_with_sigma2, a_r_p1_p1, ONE_OVER_SQRT_2_42, THREE_OVER_SQRT_2_42, FIVE_OVER_SQRT_2_42, SEVEN_OVER_SQRT_2_42); interference_abs_64qam_epi16(psi_i_p1_p1, ch_mag_int_with_sigma2, two_ch_mag_int_with_sigma2, three_ch_mag_int_with_sigma2, a_i_p1_p1, ONE_OVER_SQRT_2_42, THREE_OVER_SQRT_2_42, FIVE_OVER_SQRT_2_42, @@ -2081,6 +2082,8 @@ void qam16_qam16(short *stream0_in, simde__m128i y0_p_3_3 = simde_mm_adds_epi16(y0r_three_over_sqrt10, y0i_three_over_sqrt10); simde__m128i y0_m_3_3 = simde_mm_subs_epi16(y0r_three_over_sqrt10, y0i_three_over_sqrt10); simde__m128i tmp_result, tmp_result2; + //generate a const of all ff in case the compiler doesn't optimize it inside the loop + const simde__m128i ones = allones128(); // Compute optimal interfering symbol magnitude interference_abs_epi16(psi_r_p1_p1 ,ch_mag_int,a_r_p1_p1,ONE_OVER_SQRT_10_Q15, THREE_OVER_SQRT_10); interference_abs_epi16(psi_i_p1_p1 ,ch_mag_int,a_i_p1_p1,ONE_OVER_SQRT_10_Q15, THREE_OVER_SQRT_10); @@ -2597,6 +2600,8 @@ void qam16_qam64(int16_t *stream0_in, ch_mag_int_with_sigma2 = simde_mm_srai_epi16(ch_mag_int, 1); // *2 two_ch_mag_int_with_sigma2 = ch_mag_int; // *4 simde__m128i tmp_result, tmp_result2, tmp_result3, tmp_result4; + //generate a const of all ff in case the compiler doesn't optimize it inside the loop + const simde__m128i ones = allones128(); three_ch_mag_int_with_sigma2 = simde_mm_adds_epi16(ch_mag_int_with_sigma2, two_ch_mag_int_with_sigma2); // *6 interference_abs_64qam_epi16(psi_r_p1_p1 ,ch_mag_int_with_sigma2, two_ch_mag_int_with_sigma2, three_ch_mag_int_with_sigma2, a_r_p1_p1,ONE_OVER_SQRT_2_42, THREE_OVER_SQRT_2_42,FIVE_OVER_SQRT_2_42, @@ -4927,6 +4932,8 @@ void qam64_qam16(short *stream0_in, simde__m128i y0_m_7_5 = simde_mm_subs_epi16(y0r_seven_over_sqrt_21, y0i_five_over_sqrt_21); simde__m128i y0_m_7_7 = simde_mm_subs_epi16(y0r_seven_over_sqrt_21, y0i_seven_over_sqrt_21); simde__m128i tmp_result, tmp_result2; + //generate a const of all ff in case the compiler doesn't optimize it inside the loop + const simde__m128i ones = allones128(); interference_abs_epi16(psi_r_p7_p7, ch_mag_int, a_r_p7_p7, ONE_OVER_SQRT_10_Q15, THREE_OVER_SQRT_10); interference_abs_epi16(psi_r_p7_p5, ch_mag_int, a_r_p7_p5, ONE_OVER_SQRT_10_Q15, THREE_OVER_SQRT_10); interference_abs_epi16(psi_r_p7_p3, ch_mag_int, a_r_p7_p3, ONE_OVER_SQRT_10_Q15, THREE_OVER_SQRT_10); @@ -6425,6 +6432,8 @@ void qam64_qam64(short *stream0_in, two_ch_mag_int_with_sigma2 = ch_mag_int; // *4 three_ch_mag_int_with_sigma2 = simde_mm_adds_epi16(ch_mag_int_with_sigma2, two_ch_mag_int_with_sigma2); // *6 simde__m128i tmp_result, tmp_result2, tmp_result3, tmp_result4; + //generate a const of all ff in case the compiler doesn't optimize it inside the loop + const simde__m128i ones = allones128(); interference_abs_64qam_epi16(psi_r_p7_p7, ch_mag_int_with_sigma2, two_ch_mag_int_with_sigma2, three_ch_mag_int_with_sigma2, a_r_p7_p7, ONE_OVER_SQRT_2_42, THREE_OVER_SQRT_2_42, FIVE_OVER_SQRT_2_42, SEVEN_OVER_SQRT_2_42); interference_abs_64qam_epi16(psi_r_p7_p5, ch_mag_int_with_sigma2, two_ch_mag_int_with_sigma2, three_ch_mag_int_with_sigma2, a_r_p7_p5, ONE_OVER_SQRT_2_42, THREE_OVER_SQRT_2_42, FIVE_OVER_SQRT_2_42, diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation_avx2.c b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation_avx2.c index 0877b2ba7e..a4f641896b 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation_avx2.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dlsch_llr_computation_avx2.c @@ -37,40 +37,21 @@ #if defined(__x86_64__) - static const int16_t ones256[16] __attribute__((aligned(32))) = {0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff, - 0xffff}; - - - // Auxiliary Makros - + // Auxiliary Macros // calculate interference magnitude #define interference_abs_epi16(psi, int_ch_mag, int_mag, c1, c2) \ - tmp_result = simde_mm256_cmpgt_epi16(int_ch_mag, psi); \ - tmp_result2 = simde_mm256_xor_si256(tmp_result, (*(simde__m256i *)&ones256[0])); \ - tmp_result = simde_mm256_and_si256(tmp_result, c1); \ - tmp_result2 = simde_mm256_and_si256(tmp_result2, c2); \ - const simde__m256i int_mag = simde_mm256_or_si256(tmp_result, tmp_result2); + tmp_result = simde_mm256_cmpgt_epi16(int_ch_mag, psi); \ + tmp_result2 = simde_mm256_xor_si256(tmp_result, ff256); \ + tmp_result = simde_mm256_and_si256(tmp_result, c1); \ + tmp_result2 = simde_mm256_and_si256(tmp_result2, c2); \ + const simde__m256i int_mag = simde_mm256_or_si256(tmp_result, tmp_result2); // calculate interference magnitude // tmp_result = ones in shorts corr. to interval 2<=x<=4, tmp_result2 interval < 2, tmp_result3 interval 46 #define interference_abs_64qam_epi16(psi, int_ch_mag, int_two_ch_mag, int_three_ch_mag, a, c1, c3, c5, c7) \ tmp_result = simde_mm256_cmpgt_epi16(int_two_ch_mag, psi); \ - tmp_result3 = simde_mm256_xor_si256(tmp_result, (*(simde__m256i *)&ones256[0])); \ + tmp_result3 = simde_mm256_xor_si256(tmp_result, ff256); \ tmp_result2 = simde_mm256_cmpgt_epi16(int_ch_mag, psi); \ tmp_result = simde_mm256_xor_si256(tmp_result, tmp_result2); \ tmp_result4 = simde_mm256_cmpgt_epi16(psi, int_three_ch_mag); \ @@ -195,7 +176,8 @@ void qam64_qam16_avx2(short *stream0_in, int i,j; uint32_t len256 = (length)>>3; - + //generate a const of all ff in case the compiler doesn't optimize it inside the loop + const simde__m256i ff256 = allones256(); for (i=0; i>3; + //generate a const of all ff in case the compiler doesn't optimize it inside the loop + const simde__m256i ff256 = allones256(); for (i=0; iframe_parms; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c b/openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c index 2b8a725787..e4a34eb376 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/initial_sync.c @@ -482,13 +482,6 @@ int initial_sync(PHY_VARS_UE *ue, runmode_t mode) { LOG_I(PHY, "[UE%d] In synch, rx_offset %d samples\n",ue->Mod_id, ue->rx_offset); if (ue->UE_scan_carrier == 0) { -#if UE_AUTOTEST_TRACE - LOG_I(PHY,"[UE %d] AUTOTEST Cell Sync : frame = %d, rx_offset %d, freq_offset %d \n", - ue->Mod_id, - ue->proc.proc_rxtx[0].frame_rx, - ue->rx_offset, - ue->common_vars.freq_offset ); -#endif // send sync status to higher layers later when timing offset converge to target timing generate_pcfich_reg_mapping(frame_parms); generate_phich_reg_mapping(frame_parms); diff --git a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c index 9ac775c4be..998b95d0d3 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/linear_preprocessing_rec.c @@ -22,7 +22,7 @@ data storage. */ #include #include //#define DEBUG_PREPROC - +#include "common/utils/utils.h" void transpose (int N, float complex *A, float complex *Result) { @@ -43,14 +43,14 @@ void transpose (int N, float complex *A, float complex *Result) int ldb = col_opB; if (transb == CblasNoTrans) { - B = (float complex*)calloc(ldb*col_opB,sizeof(float complex)); + B = calloc_or_fail(ldb * col_opB, sizeof(float complex)); col_B= col_opB; } else { - B = (float complex*)calloc(ldb*col_opA, sizeof(float complex)); + B = calloc_or_fail(ldb * col_opA, sizeof(float complex)); col_B = col_opA; } - float complex* C = (float complex*)malloc(ldc*col_opB*sizeof(float complex)); + float complex* C = malloc_or_fail(ldc * col_opB * sizeof(float complex)); for (i=0; i>2)*sizeof(float complex)); - float complex *H1_re = malloc(n_rx*(n_tx>>2)*sizeof(float complex)); - float complex *R_corr_col_n_0_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *R_corr_col_n_1_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *U_0_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *U_1_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *U_0_herm_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *U_1_herm_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *D_0_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *D_1_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *W_Wh_0_re = malloc(n_rx*n_tx*sizeof(float complex)); - float complex *W_Wh_1_re = malloc(n_rx*n_tx*sizeof(float complex)); + float complex *H0_re = malloc_or_fail(n_rx*(n_tx>>2)*sizeof(float complex)); + float complex *H1_re = malloc_or_fail(n_rx*(n_tx>>2)*sizeof(float complex)); + float complex *R_corr_col_n_0_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *R_corr_col_n_1_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *U_0_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *U_1_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *U_0_herm_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *U_1_herm_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *D_0_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *D_1_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *W_Wh_0_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); + float complex *W_Wh_1_re = malloc_or_fail(n_rx*n_tx*sizeof(float complex)); for (aatx=0; aatxframe_parms.prach_config_common.prach_ConfigInfo.prach_ConfigIndex, ue->frame_parms.prach_config_common.prach_ConfigInfo.prach_FreqOffset, tdd_mapindex, Nf); - prach_root_sequence_map = (prach_fmt<4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4; + const uint16_t *prach_root_sequence_map = (prach_fmt < 4) ? prach_root_sequence_map0_3 : prach_root_sequence_map4; /* // this code is not part of get_prach_prb_offset if (frame_type == TDD) { // TDD @@ -215,20 +210,6 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 #endif // nsymb = (frame_parms->Ncp==0) ? 14:12; // subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*subframe*nsymb; - k = (12*n_ra_prb) - 6*ue->frame_parms.N_RB_UL; - - if (k<0) - k+=ue->frame_parms.ofdm_symbol_size; - - k*=12; - k+=13; - Xu = (int16_t *)ue->X_u[preamble_offset-first_nonzero_root_idx]; - /* - k+=(12*ue->frame_parms.first_carrier_offset); - if (k>(12*ue->frame_parms.ofdm_symbol_size)) - k-=(12*ue->frame_parms.ofdm_symbol_size); - */ - k*=2; switch (ue->frame_parms.N_RB_UL) { case 6: @@ -259,20 +240,26 @@ int32_t generate_prach( PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, uint1 break; } + { + int k = (12 * n_ra_prb) - 6 * ue->frame_parms.N_RB_UL; - for (offset=0,offset2=0; offset= N_ZC) - offset2 -= N_ZC; + if (k < 0) + k += ue->frame_parms.ofdm_symbol_size; - Xu_re = (((int32_t)Xu[offset<<1]*amp)>>15); - Xu_im = (((int32_t)Xu[1+(offset<<1)]*amp)>>15); - prachF[k++]= ((Xu_re*ru[offset2<<1]) - (Xu_im*ru[1+(offset2<<1)]))>>15; - prachF[k++]= ((Xu_im*ru[offset2<<1]) + (Xu_re*ru[1+(offset2<<1)]))>>15; + k *= 12; + k += 13; + c16_t *Xu_ue = ue->X_u[preamble_offset - first_nonzero_root_idx]; + c16_t *complex_prachF = (c16_t *)prachF; + for (int offset = 0, offset2 = 0; offset < N_ZC; offset++, offset2 += preamble_shift) { + if (offset2 >= N_ZC) + offset2 -= N_ZC; + c16_t Xu = c16mulRealShift(*Xu_ue++, amp, 15); + complex_prachF[k++] = c16mulShift(Xu, root_unit[offset2], 15); - if (k==(12*2*ue->frame_parms.ofdm_symbol_size)) - k=0; + if (k == 12 * ue->frame_parms.ofdm_symbol_size) + k = 0; + } } - switch (prach_fmt) { case 0: Ncp = 3168; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/pucch_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/pucch_ue.c index 8db7549b36..d6361f4606 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/pucch_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/pucch_ue.c @@ -384,7 +384,7 @@ void generate_pucch2x(int32_t **txdataF, int i,j; uint32_t B=0; - uint8_t btilde[20]; + uint8_t btilde[20] = {0}; int16_t d[22]; uint8_t deltaPUCCH_Shift = fp->pucch_config_common.deltaPUCCH_Shift; uint8_t NRB2 = fp->pucch_config_common.nRB_CQI; diff --git a/openair1/PHY/LTE_UE_TRANSPORT/rar_tools_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/rar_tools_ue.c index ad513a424e..778b9ecfa0 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/rar_tools_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/rar_tools_ue.c @@ -105,7 +105,7 @@ int generate_ue_ulsch_params_from_rar(PHY_VARS_UE *ue, cqireq=rar[3]&1; if (rballoc>RIV_max) { - LOG_D(PHY,"rar_tools.c: ERROR: rb_alloc (%x) > RIV_max\n",rballoc); + LOG_W(PHY,"rar_tools.c: ERROR: rb_alloc (%x) > RIV_max\n",rballoc); return(-1); } diff --git a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h index 9aab56e52a..06bf87fc74 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h +++ b/openair1/PHY/LTE_UE_TRANSPORT/transport_proto_ue.h @@ -1649,8 +1649,7 @@ void compute_prach_seq(uint16_t rootSequenceIndex, uint8_t zeroCorrelationZoneConfig, uint8_t highSpeedFlag, frame_type_t frame_type, - uint32_t X_u[64][839]); - + c16_t X_u[64][839]); void init_prach_tables(int N_ZC); diff --git a/openair1/PHY/MODULATION/CMakeLists.txt b/openair1/PHY/MODULATION/CMakeLists.txt new file mode 100644 index 0000000000..dc1a5e0301 --- /dev/null +++ b/openair1/PHY/MODULATION/CMakeLists.txt @@ -0,0 +1,3 @@ +if (ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index 994c0798c2..eb4dc50bc9 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -119,49 +119,33 @@ const char nr_W_4l_4p[5][4][4] = { void nr_modulation(const uint32_t *in, uint32_t length, uint16_t mod_order, int16_t *out) { - uint16_t mask = ((1 << mod_order) - 1); - int32_t *nr_mod_table32; + const uint16_t mask = ((1 << mod_order) - 1); int32_t *out32 = (int32_t *)out; const uint8_t *in_bytes = (const uint8_t *)in; const uint64_t *in64 = (const uint64_t *)in; int64_t *out64 = (int64_t *)out; uint32_t i = 0; -#if defined(__SSE2__) - simde__m128i *nr_mod_table128; - simde__m128i *out128; -#endif - LOG_D(PHY, "nr_modulation: length %d, mod_order %d\n", length, mod_order); switch (mod_order) { -#if defined(__SSE2__) - case 2: - nr_mod_table128 = (simde__m128i *)nr_qpsk_byte_mod_table; - out128 = (simde__m128i *)out; + case 2: { + simde__m128i *nr_mod_table128 = (simde__m128i *)nr_qpsk_byte_mod_table; + simde__m128i *out128 = (simde__m128i *)out; for (i = 0; i < length / 8; i++) out128[i] = nr_mod_table128[in_bytes[i]]; // the bits that are left out i = i * 8 / 2; - nr_mod_table32 = (int32_t *)nr_qpsk_mod_table; + int32_t *nr_mod_table32 = (int32_t *)nr_qpsk_mod_table; while (i < length / 2) { const int idx = ((in_bytes[(i * 2) / 8] >> ((i * 2) & 0x7)) & mask); out32[i] = nr_mod_table32[idx]; i++; } + } return; -#else - case 2: - nr_mod_table32 = (int32_t *)nr_qpsk_mod_table; - for (i = 0; i < length / mod_order; i++) { - const int idx = ((in[i * 2 / 32] >> ((i * 2) & 0x1f)) & mask); - out32[i] = nr_mod_table32[idx]; - } - return; -#endif case 4: - out64 = (int64_t *)out; for (i = 0; i < length / 8; i++) out64[i] = nr_16qam_byte_mod_table[in_bytes[i]]; // the bits that are left out @@ -234,10 +218,11 @@ void nr_modulation(const uint32_t *in, uint32_t length, uint16_t mod_order, int1 } return; - case 8: - nr_mod_table32 = (int32_t *)nr_256qam_mod_table; + case 8: { + int32_t *nr_mod_table32 = (int32_t *)nr_256qam_mod_table; for (i = 0; i < length / 8; i++) out32[i] = nr_mod_table32[in_bytes[i]]; + } return; default: @@ -310,7 +295,7 @@ void nr_layer_mapping(int nbCodes, c16_t *tx0 = tx_layers[0]; c16_t *tx1 = tx_layers[1]; c16_t *tx2 = tx_layers[2]; -#if defined(__AVX512BW__) +#if defined(__AVX512F) && defined(__AVX512VBMI__) simde__m512i perm3_0 = simde_mm512_set_epi32(13 + 16, 10 + 16, 7 + 16, @@ -414,7 +399,7 @@ void nr_layer_mapping(int nbCodes, } #ifdef DEBUG_LAYER_MAPPING - printf("\nsymb %d/%d\n", i << 3, n_symbs); + printf("\nsymb %d/%u\n", i << 3, n_symbs); printf(" layer 0:\t"); for (int j = 0; j < 8 * 6; j += 6) { printf("%d %d ", ((int16_t *)&mod[i << 3])[j], ((int16_t *)&mod[i << 3])[j + 1]); @@ -448,7 +433,7 @@ void nr_layer_mapping(int nbCodes, c16_t *tx1 = tx_layers[1]; c16_t *tx2 = tx_layers[2]; c16_t *tx3 = tx_layers[3]; -#if defined(__AVX512BW__) +#if defined(__AVX512VBMI__) simde__m512i perm4 = simde_mm512_set_epi32(15, 11, 7, 3, 14, 10, 6, 2, 13, 9, 5, 1, 12, 8, 4, 0); for (; i < (n_symbs & ~15); i += 16) { simde__m512i e = simde_mm512_permutexvar_epi32(perm4, *(simde__m512i *)(mod + i)); @@ -725,13 +710,104 @@ c16_t nr_layer_precoder_cm(int n_layers, { c16_t precodatatx_F = {0}; for (int al = 0; al < n_layers; al++) { - nfapi_nr_pm_weights_t *w = &pmi_pdu->weights[al][ap]; - c16_t prec_weight = {.r = w->precoder_weight_Re, .i = w->precoder_weight_Im}; + c16_t prec_weight = pmi_pdu->weights[al][ap]; precodatatx_F = c16maddShift(datatx_F_precoding[al][offset], prec_weight, precodatatx_F, 15); } return precodatatx_F; } +#if defined(__AVX512F__) && defined(__AVX512BW__) + +static inline __attribute__((always_inline)) __m512i cmac0_prec512(__m512i x, __m512i w_c, __m512i w_s) { + + // Multiplication and shift + const __m512i reals = + _mm512_srai_epi32(_mm512_madd_epi16(x, w_c), 15); // (int32_t) .r = (x.r * w.r - x.i * w.i) >> 15 + const __m512i imags = + _mm512_slli_epi32(_mm512_madd_epi16(x, w_s), 1); // (int32_t) .i = (x.r * w.i + x.i * w.r) << 1, since higher 16 bit of each 32 bit is taken by blend_epi16 + + // Re-arrange to match c16_t format + return _mm512_mask_blend_epi16(0xAAAAAAAA,reals, imags); + +} +static inline __attribute__((always_inline)) __m512i cmac_prec512(__m512i y, __m512i x, __m512i w_c, __m512i w_s) { + const __m512i produ = cmac0_prec512(x, w_c, w_s); + // Accumulate the product + return _mm512_adds_epi16(y, produ); +} +#endif +#ifdef __AVX2__ +static inline __attribute__((always_inline)) __m256i cmac0_prec256(__m256i x, __m256i w_c, __m256i w_s) { + + // Multiplication and shift + const __m256i reals = + _mm256_srai_epi32(_mm256_madd_epi16(x, w_c), 15); // (int32_t) .r = (x.r * w.r - x.i * w.i) >> 15 + const __m256i imags = + _mm256_slli_epi32(_mm256_madd_epi16(x, w_s), 1); // (int32_t) .i = (x.r * w.i + x.i * w.r) << 1, since higher 16 bit of each 32 bit is taken by blend_epi16 + + // Re-arrange to match c16_t format + return _mm256_blend_epi16(reals, imags,0xAA); + +} +static inline __attribute__((always_inline)) __m256i cmac_prec256(__m256i y, __m256i x, __m256i w_c, __m256i w_s) { + const __m256i produ = cmac0_prec256(x, w_c, w_s); + // Accumulate the product + return _mm256_adds_epi16(y, produ); +} +#endif +#ifdef __aarch64__ +static inline __attribute__((always_inline)) int16x8_t cmac0_prec128(int16x8_t x, int16x8_t wr, int16x8_t wi) { + // + int16x8_t xr = vuzp1q_s16(x, x); // even lanes + int16x8_t xi = vuzp2q_s16(x, x); // odd lanes + // real = ar*br - ai*bi (Q15 scaling via high-half doubling muls) + int16x8_t real = vqdmulhq_s16(xr, wr); // ≈ round((2*xr*wr)/2^16) + real = vqrdmlshq_s16(real, xi, wi); // real -= round((2*xi*wi)/2^16) + // + // imag = ar*bi + ai*br + int16x8_t imag = vqdmulhq_s16(xr, wi); + imag = vqrdmlahq_s16(imag, xi, wr); // imag += round((2*xi*wr)/2^16) + // + // Re-interleave [real, imag] + int16x8x2_t produ = vzipq_s16(real, imag); + return produ.val[0]; +} +static inline __attribute__((always_inline)) int16x8_t cmac_prec128(int16x8_t y, int16x8_t x, int16x8_t wr, int16x8_t wi) { + int16x8_t produ = cmac0_prec128(x, wr, wi); + return vaddq_s16(y, produ); +} +#else +static inline __attribute__((always_inline)) simde__m128i cmac0_prec128(simde__m128i x, simde__m128i w_c, simde__m128i w_s) +{ + // Multiplication and shift + const simde__m128i reals = simde_mm_srai_epi32(simde_mm_madd_epi16(x, w_c), 15); // (int32_t) .r = (x.r * w.r - x.i * w.i) >> 15 + const simde__m128i imags = simde_mm_slli_epi32( + simde_mm_madd_epi16(x, w_s), + 1); // (int32_t) .i = (x.r * w.i + x.i * w.r) << 1, since higher 16 bit of each 32 bit is taken by blend_epi16 + + /* Re-arrange to match c16_t format + bit index: 0 | 16 | 32 | 48 | 64 | 80 | 96 | 112 + reals = {R0.r[15..30] | R0.r[31] (0)*15 | R1.r[15..30] | R1.r[31] (0)*15 | R2.r[15..30] | R2.r[31] (0)*15 | R3.r[15..30] + | R3.r[31] (0)*15} imags = {0 R0.i[0..14]| R0.i[15..30] | 0 R1.i[0..14]| R1.i[15..30] | 0 R2.i[0..14]| R2.i[15..30] + | 0 R3.i[0..14]| R3.i[15..30] } 16b from {reals | imags | reals | imags | reals | imags | reals + | imags } produ = {R0.r[15..30] | R0.i[15..30] | R1.r[15..30] | R1.i[15..30] | R2.r[15..30] | R2.i[15..30] | + R3.r[15..30] | R3.i[15..30] } + */ + return simde_mm_blend_epi16(reals, imags, 0xAA); +} +static inline __attribute__((always_inline)) __m128i cmac_prec128(__m128i y, __m128i x, __m128i w_c, __m128i w_s) +{ + const __m128i produ = cmac0_prec128(x, w_c, w_s); + // Accumulate the product + return simde_mm_adds_epi16(y, produ); +} +#endif + +#define load_consts(Type, Instruct, Rank) \ + const Type w_c##Rank = Instruct(c16toI32(c16conj(pmi_pdu->weights[Rank][ant]))); \ + const Type w_s##Rank = Instruct(c16toI32(c16swap(pmi_pdu->weights[Rank][ant]))); \ + const Type *in##Rank = (Type *)(txdataF_res_mapped[Rank] + sc_offset + (out-beginning)); + void nr_layer_precoder_simd(const int n_layers, const int symSz, const c16_t txdataF_res_mapped[n_layers][symSz], @@ -741,114 +817,264 @@ void nr_layer_precoder_simd(const int n_layers, const int re_cnt, c16_t *txdataF_precoded) { - uint32_t sc = sc_offset; - c16_t prec_weight = {0}; // For x86, use 256 SIMD for every 8 RE and 128 SIMD for last 4 RE // For aarch64, use 128 SIMD for every 4 RE + AssertFatal(n_layers > 0 && n_layers <= 4, "Shouldn't get here, n_layers %d\n", n_layers); - // 256 SIMD: Do 8 RE in one iteration, 3 iterations for 2 RB -#ifdef __AVX2__ - const uint32_t re_cnt_align8 = re_cnt & ~7; - for (; sc < sc_offset + (re_cnt_align8); sc += sizeof(simde__m256i) / sizeof(prec_weight)) { - // Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8) - simde__m256i y = simde_mm256_set1_epi16(0); // Y = W[0]*X[0] + W[1]*X[1] + ... + W[nrOfLayers-1]*X[nrOfLayers-1] - for (int nl = 0; nl < n_layers; nl++) { - prec_weight.r = pmi_pdu->weights[nl][ant].precoder_weight_Re; - prec_weight.i = pmi_pdu->weights[nl][ant].precoder_weight_Im; - - const simde__m256i x = simde_mm256_loadu_si256(&txdataF_res_mapped[nl][sc]); - - // Rearrange precoding matrix weight to match complex multiplication and broadcast it to match SIMD size - const simde__m256i w_c = simde_mm256_set1_epi32(c16toI32(c16conj(prec_weight))); // broadcast conjugate of w - const simde__m256i w_s = simde_mm256_set1_epi32(c16toI32(c16swap(prec_weight))); // broadcast swapped real and img of w - - // Multiplication and shift - const simde__m256i reals = - simde_mm256_srai_epi32(simde_mm256_madd_epi16(x, w_c), 15); // (int32_t) .r = (x.r * w.r - x.i * w.i) >> 15 - const simde__m256i imags = simde_mm256_slli_epi32( - simde_mm256_madd_epi16(x, w_s), - 1); // (int32_t) .i = (x.r * w.i + x.i * w.r) << 1, since higher 16 bit of each 32 bit is taken by blend_epi16 - - // Re-arrange to match c16_t format - const simde__m256i produ = simde_mm256_blend_epi16(reals, imags, 0xAA); - - // Accumulate the product - y = simde_mm256_adds_epi16(y, produ); + // 512/256 SIMD: Do 16/8 RE in one iteration, 3 iterations for 2 RB + c16_t *beginning = txdataF_precoded + sc_offset; + c16_t *out=beginning; +#if defined(__AVX512F__) && defined(__AVX512BW__) + { + c16_t *end = out + (re_cnt & ~15); + load_consts(__m512i, _mm512_set1_epi32, 0); + if (n_layers == 1) { + for (; out < end; out += sizeof(__m512i) / sizeof(*out)) { + const __m512i x = _mm512_loadu_si512(in0++); + // Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8) + __m512i y = cmac0_prec512(x, w_c0, w_s0); + _mm512_storeu_si512(out, y); + } + } else if (n_layers == 2) { + load_consts(__m512i, _mm512_set1_epi32, 1); + for (; out < end; out += sizeof(__m512i) / sizeof(*out)) { + const __m512i x = _mm512_loadu_si512(in0++); + const __m512i x1 = _mm512_loadu_si512(in1++); + // Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8) + __m512i y = cmac0_prec512(x, w_c0, w_s0); + y = cmac_prec512(y, x1, w_c1, w_s1); + _mm512_storeu_si512(out, y); + } + } else if (n_layers == 3) { + load_consts(__m512i, _mm512_set1_epi32, 1); + load_consts(__m512i, _mm512_set1_epi32, 2); + for (; out < end; out += sizeof(__m512i) / sizeof(*out)) { + const __m512i x = _mm512_loadu_si512(in0++); + const __m512i x1 = _mm512_loadu_si512(in1++); + const __m512i x2 = _mm512_loadu_si512(in2++); + // Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8) + __m512i y = cmac0_prec512(x, w_c0, w_s0); + y = cmac_prec512(y, x1, w_c1, w_s1); + y = cmac_prec512(y, x2, w_c2, w_s2); + _mm512_storeu_si512(out, y); + } + } else if (n_layers == 4) { + load_consts(__m512i, _mm512_set1_epi32, 1); + load_consts(__m512i, _mm512_set1_epi32, 2); + load_consts(__m512i, _mm512_set1_epi32, 3); + for (; out < end; out += sizeof(__m512i) / sizeof(*out)) { + const __m512i x = _mm512_loadu_si512(in0++); + const __m512i x1 = _mm512_loadu_si512(in1++); + const __m512i x2 = _mm512_loadu_si512(in2++); + const __m512i x3 = _mm512_loadu_si512(in3++); + // Matrix multiplication for 4 elements of the result (sizeof(simde__m256i) / sizeof(*prec_matrix) = 8) + __m512i y = cmac0_prec512(x, w_c0, w_s0); + y = cmac_prec512(y, x1, w_c1, w_s1); + y = cmac_prec512(y, x2, w_c2, w_s2); + y = cmac_prec512(y, x3, w_c3, w_s3); + _mm512_storeu_si512(out, y); + } } - // Store the result to txdataF - simde_mm256_storeu_si256(&txdataF_precoded[sc], y); } #endif - - // 128 SIMD: Do 4 RE in one iteration, 3 iterations for 1 RB - const uint32_t re_cnt_align4 = re_cnt & ~3; - for (; sc < sc_offset + re_cnt_align4; sc += sizeof(simde__m128i) / sizeof(prec_weight)) { +#ifdef __AVX2__ + { + c16_t *end = beginning + (re_cnt & ~7); + load_consts(simde__m256i, simde_mm256_set1_epi32, 0); + if (n_layers == 1) { + for (; out < end; out += sizeof(simde__m256i) / sizeof(*out)) { + const simde__m256i x0 = simde_mm256_loadu_si256(in0++); + // Accumulate the product + simde__m256i y = cmac0_prec256(x0, w_c0, w_s0); + // Store the result to txdataF + simde_mm256_storeu_si256(out, y); + } + } else if (n_layers == 2) { + load_consts(simde__m256i, simde_mm256_set1_epi32, 1); + for (; out < end; out += sizeof(simde__m256i) / sizeof(*out)) { + const simde__m256i x0 = simde_mm256_loadu_si256(in0++); + const simde__m256i x1 = simde_mm256_loadu_si256(in1++); + // Accumulate the product + simde__m256i y = cmac0_prec256(x0, w_c0, w_s0); + y = cmac_prec256(y, x1, w_c1, w_s1); + // Store the result to txdataF + simde_mm256_storeu_si256(out, y); + } + } else if (n_layers == 3) { + load_consts(simde__m256i, simde_mm256_set1_epi32, 1); + load_consts(simde__m256i, simde_mm256_set1_epi32, 2); + for (; out < end; out += sizeof(simde__m256i) / sizeof(*out)) { + const simde__m256i x0 = simde_mm256_loadu_si256(in0++); + const simde__m256i x1 = simde_mm256_loadu_si256(in1++); + const simde__m256i x2 = simde_mm256_loadu_si256(in2++); + simde__m256i y = cmac0_prec256(x0, w_c0, w_s0); + y = cmac_prec256(y, x1, w_c1, w_s1); + y = cmac_prec256(y, x2, w_c2, w_s2); + // Store the result to txdataF + simde_mm256_storeu_si256(out, y); + } + } else if (n_layers == 4) { + load_consts(simde__m256i, simde_mm256_set1_epi32, 1); + load_consts(simde__m256i, simde_mm256_set1_epi32, 2); + load_consts(simde__m256i, simde_mm256_set1_epi32, 3); + for (; out < end; out += sizeof(simde__m256i) / sizeof(*out)) { + const simde__m256i x0 = simde_mm256_loadu_si256(in0++); + const simde__m256i x1 = simde_mm256_loadu_si256(in1++); + const simde__m256i x2 = simde_mm256_loadu_si256(in2++); + const simde__m256i x3 = simde_mm256_loadu_si256(in3++); + simde__m256i y = cmac0_prec256(x0, w_c0, w_s0); + y = cmac_prec256(y, x1, w_c1, w_s1); + y = cmac_prec256(y, x2, w_c2, w_s2); + y = cmac_prec256(y, x3, w_c3, w_s3); + // Store the result to txdataF + simde_mm256_storeu_si256(out, y); + } + } + } +#endif + c16_t *end = beginning + (re_cnt & ~3); #ifdef DEBUG_DLSCH_PRECODING_PRINT_WITH_TRIVIAL // Get result with trivial solution, TODO: To be removed + // 128 SIMD: Do 4 RE in one iteration, 3 iterations for 1 RB + for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) { c16_t y_triv[4]; for (int i = 0; i < 4; i++) y_triv[i] = nr_layer_precoder_cm(n_layers, symSz, txdataF_res_mapped, ant, pmi_pdu, sc + i); - memcpy(&txdataF_precoded[sc], y_triv, sizeof(y_triv)); -#endif - - // Matrix multiplication for 4 elements of the result (sizeof(simde__m128i) / sizeof(c16_t) = 4) - simde__m128i y = simde_mm_set1_epi16(0); // Y = W[0]*X[0] + W[1]*X[1] + ... + W[nrOfLayers-1]*X[nrOfLayers-1] - for (int nl = 0; nl < n_layers; nl++) { - prec_weight.r = pmi_pdu->weights[nl][ant].precoder_weight_Re; - prec_weight.i = pmi_pdu->weights[nl][ant].precoder_weight_Im; - - const simde__m128i x = simde_mm_loadu_si128(&txdataF_res_mapped[nl][sc]); - - // Rearrange precoding matrix weight to match complex multiplication and broadcast it to match SIMD size - const simde__m128i w_c = simde_mm_set1_epi32(c16toI32(c16conj(prec_weight))); // broadcast conjugate of w - const simde__m128i w_s = simde_mm_set1_epi32(c16toI32(c16swap(prec_weight))); // broadcast swapped real and img of w - - // Multiplication and shift - const simde__m128i reals = - simde_mm_srai_epi32(simde_mm_madd_epi16(x, w_c), 15); // (int32_t) .r = (x.r * w.r - x.i * w.i) >> 15 - const simde__m128i imags = simde_mm_slli_epi32( - simde_mm_madd_epi16(x, w_s), - 1); // (int32_t) .i = (x.r * w.i + x.i * w.r) << 1, since higher 16 bit of each 32 bit is taken by blend_epi16 - - /* Re-arrange to match c16_t format - bit index: 0 | 16 | 32 | 48 | 64 | 80 | 96 | 112 - reals = {R0.r[15..30] | R0.r[31] (0)*15 | R1.r[15..30] | R1.r[31] (0)*15 | R2.r[15..30] | R2.r[31] (0)*15 | R3.r[15..30] - | R3.r[31] (0)*15} imags = {0 R0.i[0..14]| R0.i[15..30] | 0 R1.i[0..14]| R1.i[15..30] | 0 R2.i[0..14]| R2.i[15..30] - | 0 R3.i[0..14]| R3.i[15..30] } 16b from {reals | imags | reals | imags | reals | imags | reals - | imags } produ = {R0.r[15..30] | R0.i[15..30] | R1.r[15..30] | R1.i[15..30] | R2.r[15..30] | R2.i[15..30] | - R3.r[15..30] | R3.i[15..30] } - */ - const simde__m128i produ = simde_mm_blend_epi16(reals, imags, 0xAA); - - // Accumulate the product - y = simde_mm_adds_epi16(y, produ); - } - // Store the result to txdataF - simde_mm_storeu_si128(&txdataF_precoded[sc], y); - -#ifdef DEBUG_DLSCH_PRECODING_PRINT_WITH_TRIVIAL // Print simd and trivial result, TODO: To be removed - c16_t *y_simd = (c16_t *)&y; - printf("debug_to_be_removed re_cnt=%d, sc=%u, y_simd=(%+4d,%+4d), (%+4d,%+4d), (%+4d,%+4d), (%+4d,%+4d)\n", - re_cnt, - sc, - y_simd[0].r, - y_simd[0].i, - y_simd[1].r, - y_simd[1].i, - y_simd[2].r, - y_simd[2].i, - y_simd[3].r, - y_simd[3].i); - printf("debug_to_be_removed re_cnt=%d, sc=%u, y_triv=(%+4d,%+4d), (%+4d,%+4d), (%+4d,%+4d), (%+4d,%+4d)\n", - re_cnt, - sc, - y_triv[0].r, - y_triv[0].i, - y_triv[1].r, - y_triv[1].i, - y_triv[2].r, - y_triv[2].i, - y_triv[3].r, - y_triv[3].i); -#endif + memcpy(out, y_triv, sizeof(y_triv)); } +#endif +#ifdef __aarch64__ + load_consts(int16x8_t, vdupq_n_s16, 0); + if (n_layers == 1) { + for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) { + const int16x8_t x0 = vld1q_s16((const int16_t *)in0++); + // Accumulate the product + int16x8_t y = cmac0_prec128(x0, w_c0, w_s0); + // Store the result to txdataF + *(int16x8_t *)out = y; + } + } + if (n_layers == 2) { + load_consts(int16x8_t, vdupq_n_s16, 1); + for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) { + const int16x8_t x0 = vld1q_s16((const int16_t *)in0++); + const int16x8_t x1 = vld1q_s16((const int16_t *)in1++); + // Accumulate the product + int16x8_t y = cmac0_prec128(x0, w_c0, w_s0); + y = cmac_prec128(y, x1, w_c1, w_s1); + // Store the result to txdataF + *(int16x8_t *)out = y; + } + } + if (n_layers == 3) { + load_consts(int16x8_t, vdupq_n_s16, 1); + load_consts(int16x8_t, vdupq_n_s16, 2); + for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) { + const int16x8_t x0 = vld1q_s16((const int16_t *)in0++); + const int16x8_t x1 = vld1q_s16((const int16_t *)in1++); + const int16x8_t x2 = vld1q_s16((const int16_t *)in2++); + // Accumulate the product + int16x8_t y = cmac0_prec128(x0, w_c0, w_s0); + ; + y = cmac_prec128(y, x1, w_c1, w_s1); + y = cmac_prec128(y, x2, w_c2, w_s2); + // Store the result to txdataF + *(int16x8_t *)out = y; + } + } + if (n_layers == 4) { + load_consts(int16x8_t, vdupq_n_s16, 1); + load_consts(int16x8_t, vdupq_n_s16, 2); + load_consts(int16x8_t, vdupq_n_s16, 3); + for (; out < end; out += sizeof(int16x8_t) / sizeof(*out)) { + const int16x8_t x0 = vld1q_s16((const int16_t *)in0++); + const int16x8_t x1 = vld1q_s16((const int16_t *)in1++); + const int16x8_t x2 = vld1q_s16((const int16_t *)in2++); + const int16x8_t x3 = vld1q_s16((const int16_t *)in3++); + // Accumulate the product + int16x8_t y = cmac0_prec128(x0, w_c0, w_s0); + ; + y = cmac_prec128(y, x1, w_c1, w_s1); + y = cmac_prec128(y, x2, w_c2, w_s2); + y = cmac_prec128(y, x3, w_c3, w_s3); + // Store the result to txdataF + *(int16x8_t *)out = y; + } + } +#else + load_consts(simde__m128i, simde_mm_set1_epi32, 0); + if (n_layers == 1) { + for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) { + const simde__m128i x0 = simde_mm_loadu_si128(in0++); + // Accumulate the product + simde__m128i y = cmac0_prec128(x0, w_c0, w_s0); + // Store the result to txdataF + simde_mm_storeu_si128(out, y); + } + } else if (n_layers == 2) { + load_consts(simde__m128i, simde_mm_set1_epi32, 1); + for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) { + const simde__m128i x0 = simde_mm_loadu_si128(in0++); + const simde__m128i x1 = simde_mm_loadu_si128(in1++); + // Accumulate the product + simde__m128i y = cmac0_prec128(x0, w_c0, w_s0); + y = cmac_prec128(y, x1, w_c1, w_s1); + // Store the result to txdataF + simde_mm_storeu_si128(out, y); + } + } else if (n_layers == 3) { + load_consts(simde__m128i, simde_mm_set1_epi32, 1); + load_consts(simde__m128i, simde_mm_set1_epi32, 2); + for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) { + const simde__m128i x0 = simde_mm_loadu_si128(in0++); + const simde__m128i x1 = simde_mm_loadu_si128(in1++); + const simde__m128i x2 = simde_mm_loadu_si128(in2++); + simde__m128i y = cmac0_prec128(x0, w_c0, w_s0); + y = cmac_prec128(y, x1, w_c1, w_s1); + y = cmac_prec128(y, x2, w_c2, w_s2); + // Store the result to txdataF + simde_mm_storeu_si128(out, y); + } + } else if (n_layers == 4) { + load_consts(simde__m128i, simde_mm_set1_epi32, 1); + load_consts(simde__m128i, simde_mm_set1_epi32, 2); + load_consts(simde__m128i, simde_mm_set1_epi32, 3); + for (; out < end; out += sizeof(simde__m128i) / sizeof(*out)) { + const simde__m128i x0 = simde_mm_loadu_si128(in0++); + const simde__m128i x1 = simde_mm_loadu_si128(in1++); + const simde__m128i x2 = simde_mm_loadu_si128(in2++); + const simde__m128i x3 = simde_mm_loadu_si128(in3++); + simde__m128i y = cmac0_prec128(x0, w_c0, w_s0); + y = cmac_prec128(y, x1, w_c1, w_s1); + y = cmac_prec128(y, x2, w_c2, w_s2); + y = cmac_prec128(y, x3, w_c3, w_s3); + // Store the result to txdataF + simde_mm_storeu_si128(out, y); + } + } +#endif +#ifdef DEBUG_DLSCH_PRECODING_PRINT_WITH_TRIVIAL // Print simd and trivial result, TODO: To be removed + c16_t *y_simd = (c16_t *)&y; + printf("debug_to_be_removed re_cnt=%d, sc=%u, y_simd=(%+4d,%+4d), (%+4d,%+4d), (%+4d,%+4d), (%+4d,%+4d)\n", + re_cnt, + sc, + y_simd[0].r, + y_simd[0].i, + y_simd[1].r, + y_simd[1].i, + y_simd[2].r, + y_simd[2].i, + y_simd[3].r, + y_simd[3].i); + printf("debug_to_be_removed re_cnt=%d, sc=%u, y_triv=(%+4d,%+4d), (%+4d,%+4d), (%+4d,%+4d), (%+4d,%+4d)\n", + re_cnt, + sc, + y_triv[0].r, + y_triv[0].i, + y_triv[1].r, + y_triv[1].i, + y_triv[2].r, + y_triv[2].i, + y_triv[3].r, + y_triv[3].i); +#endif } diff --git a/openair1/PHY/MODULATION/nr_modulation.h b/openair1/PHY/MODULATION/nr_modulation.h index 6977628187..64886a2809 100644 --- a/openair1/PHY/MODULATION/nr_modulation.h +++ b/openair1/PHY/MODULATION/nr_modulation.h @@ -25,7 +25,6 @@ #include #include "PHY/defs_nr_common.h" #include "PHY/defs_gNB.h" -#include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h" #define DMRS_MOD_ORDER 2 /*Precoding matices: W[pmi][antenna_port][layer]*/ diff --git a/openair1/PHY/MODULATION/tests/CMakeLists.txt b/openair1/PHY/MODULATION/tests/CMakeLists.txt new file mode 100644 index 0000000000..426181698d --- /dev/null +++ b/openair1/PHY/MODULATION/tests/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test_nr_modulation test_nr_modulation.cpp) +target_link_libraries(test_nr_modulation PRIVATE PHY_NR GTest::gtest minimal_lib) +add_dependencies(tests test_nr_modulation) +add_test(NAME test_nr_modulation + COMMAND ./test_nr_modulation) diff --git a/openair1/PHY/MODULATION/tests/test_nr_modulation.cpp b/openair1/PHY/MODULATION/tests/test_nr_modulation.cpp new file mode 100644 index 0000000000..04d32514a0 --- /dev/null +++ b/openair1/PHY/MODULATION/tests/test_nr_modulation.cpp @@ -0,0 +1,214 @@ +/* + * 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 + */ + +// Initial unit test for nr_layer_precoder_simd_[cm, simd] functions +// Issue: gNB: SIMD Precoding Bug in nr_layer_precoder_simd for PMI = 4 +// https://gitlab.eurecom.fr/oai/openairinterface5g/-/issues/955 + +#include "gtest/gtest.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "openair1/PHY/TOOLS/tools_defs.h" // c16_t +#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h" // nfapi_nr_pm_pdu_t +#include "nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h" // fapi_nr_dl_config_dci_dl_pdu_rel15_t + +//#include "openair1/PHY/MODULATION/nr_modulation.h" // nr_layer_precoder_simd_[cm, simd] + +// Forward declare the function but hide the Variable-Length Array (VLA) feature from C not available in C++ +c16_t nr_layer_precoder_cm(int n_layers, + int symbol_size, + c16_t (*dataF_in)[/*symbol_size*/], // c16_t dataF_in[n_layers][symbol_size] + int ant, + nfapi_nr_pm_pdu_t *pmi_pdu, + int offset); + +// Forward declare the function but hide the Variable-Length Array (VLA) feature from C not available in C++ +void nr_layer_precoder_simd(int n_layers, + int symbol_size, + const c16_t (*dataF_in)[/*symbol_size*/], // c16_t dataF_in[n_layers][symbol_size] + int ant, + const nfapi_nr_pm_pdu_t *pmi_pdu, + int offset, + int re_cnt, + c16_t *dataF_out); + +#ifdef __cplusplus +} +#endif + +TEST(NrLayerPrecoderTest, Basic) +{ + constexpr int n_layers = 2; + constexpr int symbol_size = 24; + constexpr int n_ants = 2; + constexpr int ant = 1; + constexpr int re_cnt = 24; + + // Initialize the 2D input data buffer + std::vector buffer_in(n_layers * symbol_size); + std::vector buffer_out(n_layers * symbol_size); + + for (int i = 0; i < n_layers * symbol_size; ++i) { + buffer_in[i] = {static_cast(i + 1), static_cast(-i - 1)}; + } + for (int i = 0; i < n_ants * symbol_size; ++i) { + buffer_out[i] = {static_cast(0), static_cast(0)}; + } + + // Cast flat buffer to the required 2D Variable-Length Array (VLA) style pointer + c16_t(*dataF_in)[symbol_size] = reinterpret_cast(buffer_in.data()); + c16_t(*dataF_out)[symbol_size] = reinterpret_cast(buffer_out.data()); + + // Create and populate the pmi_pdu structure + nfapi_nr_pm_pdu_t pmi_pdu = {0}; + for (int layer = 0; layer < n_layers; ++layer) { + pmi_pdu.weights[layer][ant] = (c16_t){-SHRT_MAX, 0}; + } + + // Call the C function + for (int symbol = 0; symbol < re_cnt; symbol++) + dataF_out[ant][symbol] = nr_layer_precoder_cm(n_layers, symbol_size, dataF_in, ant, &pmi_pdu, symbol); + + // You can calculate the expected value manually or test rough correctness + for (int symbol = 0; symbol < re_cnt; symbol++) { + int result_real = -26 - (symbol<<1); + int result_imag = -24 - (symbol<<1); + + EXPECT_EQ(dataF_out[ant][symbol].r, result_real) + << " at [" << ant << "][" << symbol << "] got real part: " << dataF_out[ant][symbol].r; + EXPECT_EQ(dataF_out[ant][symbol].i, -result_imag) + << " at [" << ant << "][" << symbol << "] got imag part: " << dataF_out[ant][symbol].i; + } +} + +TEST(NrLayerPrecoderTest, SIMD) +{ + constexpr int n_layers = 2; + constexpr int symbol_size = 24; + constexpr int n_ants = 2; + constexpr int ant = 1; + constexpr int re_cnt = 24; + + // Initialize the 2D input data buffer + std::vector buffer_in(n_layers * symbol_size); + std::vector buffer_out(n_layers * symbol_size); + + for (int i = 0; i < n_layers * symbol_size; ++i) { + buffer_in[i] = {static_cast(i + 1), static_cast(-i - 1)}; + } + for (int i = 0; i < n_ants * symbol_size; ++i) { + buffer_out[i] = {static_cast(0), static_cast(0)}; + } + + // Cast flat buffer to the required 2D Variable-Length Array (VLA) style pointer + c16_t(*dataF_in)[symbol_size] = reinterpret_cast(buffer_in.data()); + c16_t(*dataF_out)[symbol_size] = reinterpret_cast(buffer_out.data()); + + // Create and populate the pmi_pdu structure + nfapi_nr_pm_pdu_t pmi_pdu = {0}; + for (int layer = 0; layer < n_layers; ++layer) { + pmi_pdu.weights[layer][ant] = (c16_t){-SHRT_MAX, 0}; + } + + // Call the C function + nr_layer_precoder_simd(n_layers, symbol_size, dataF_in, ant, &pmi_pdu, 0, re_cnt, dataF_out[ant]); + + // You can calculate the expected value manually or test rough correctness + for (int symbol = 0; symbol < re_cnt; symbol++) { + int result_real = -26 - (symbol<<1); + int result_imag = -24 - (symbol<<1); + + EXPECT_EQ(dataF_out[ant][symbol].r, result_real) + << " at [" << ant << "][" << symbol << "] got real part: " << dataF_out[ant][symbol].r; + EXPECT_EQ(dataF_out[ant][symbol].i, -result_imag) + << " at [" << ant << "][" << symbol << "] got imag part: " << dataF_out[ant][symbol].i; + } +} + +TEST(NrLayerPrecoderTest, Compare_CM_SIMD) +{ + constexpr int n_layers = 1; + constexpr int symbol_size = 24; + constexpr int n_ants = 2; + constexpr int re_cnt = 24; + + // Initialize the 2D input data buffer + std::vector buffer_in(n_layers * symbol_size); + std::vector buffer_out_cm(n_ants * symbol_size); + std::vector buffer_out_simd(n_ants * symbol_size); + + for (int i = 0; i < n_layers * symbol_size; ++i) { + buffer_in[i] = {static_cast((rand() % (2 * SHRT_MAX + 1)) - SHRT_MAX), static_cast((rand() % (2 * SHRT_MAX + 1)) - SHRT_MAX)}; + } + for (int i = 0; i < n_ants * symbol_size; ++i) { + buffer_out_cm[i] = {static_cast(0), static_cast(0)}; + buffer_out_simd[i] = {static_cast(0), static_cast(0)}; + } + + // Cast flat buffer to the required 2D Variable-Length Array (VLA) style pointer + c16_t(*dataF_in)[symbol_size] = reinterpret_cast(buffer_in.data()); + c16_t(*dataF_out_cm)[symbol_size] = reinterpret_cast(buffer_out_cm.data()); + c16_t(*dataF_out_simd)[symbol_size] = reinterpret_cast(buffer_out_simd.data()); + + // Create and populate the pmi_pdu structure + nfapi_nr_pm_pdu_t pmi_pdu = {0}; + pmi_pdu.pm_idx = 4; + for (int layer = 0; layer < n_layers; ++layer) { + // Could not use convert_precoder_weight() as complex.h could not be used in googletest + // Use the logic in convert_precoder_weight() + // precoder [−1,−j] + pmi_pdu.weights[layer][0] = (c16_t){-SHRT_MAX, 0}; + pmi_pdu.weights[layer][1] = (c16_t){0, -SHRT_MAX}; + } + + // Get the results for all the antenna + for (int ant = 0; ant < n_ants; ant++) { + + // Call the C function + for (int symbol = 0; symbol < re_cnt; symbol++) + dataF_out_cm[ant][symbol] = nr_layer_precoder_cm(n_layers, symbol_size, dataF_in, ant, &pmi_pdu, symbol); + + // Call the C function + nr_layer_precoder_simd(n_layers, symbol_size, dataF_in, ant, &pmi_pdu, 0, re_cnt, dataF_out_simd[ant]); + + // Compare the result from both C function + for (int symbol = 0; symbol < re_cnt; symbol++) { + EXPECT_EQ(dataF_out_cm[ant][symbol].r, dataF_out_simd[ant][symbol].r) + << " at [" << ant << "][" << symbol << "] got real part: " << dataF_out_cm[ant][symbol].r << " result " << dataF_out_simd[ant][symbol].r; + EXPECT_EQ(dataF_out_cm[ant][symbol].i, dataF_out_simd[ant][symbol].i) + << " at [" << ant << "][" << symbol << "] got imag part: " << dataF_out_cm[ant][symbol].i << " result " << dataF_out_simd[ant][symbol].i; + } + } +} + +int main(int argc, char **argv) +{ + // Initialize random seed + srand(time(0)); + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/openair1/PHY/NR_ESTIMATION/nr_freq_equalization.c b/openair1/PHY/NR_ESTIMATION/nr_freq_equalization.c index c593c04cc5..8f12f100c2 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_freq_equalization.c +++ b/openair1/PHY/NR_ESTIMATION/nr_freq_equalization.c @@ -34,13 +34,13 @@ void nr_init_fde() nr_inv_ch[i] = simde_mm_set1_epi16(4096/i); } -void nr_freq_equalization (NR_DL_FRAME_PARMS *frame_parms, - int32_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - uint8_t symbol, - uint16_t Msc_RS, - uint8_t Qm) +void nr_freq_equalization(NR_DL_FRAME_PARMS *frame_parms, + c16_t *rxdataF_comp, + c16_t *ul_ch_mag, + c16_t *ul_ch_magb, + uint8_t symbol, + uint16_t Msc_RS, + uint8_t Qm) { simde__m128i *rxdataF_comp128 = (simde__m128i *)rxdataF_comp; simde__m128i *ul_ch_mag128 = (simde__m128i *)ul_ch_mag; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 728e59e510..93d7feebe0 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -28,7 +28,6 @@ #include "PHY/NR_REFSIG/dmrs_nr.h" #include "PHY/NR_REFSIG/ptrs_nr.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" -#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h" #include "PHY/NR_UE_ESTIMATION/filt16a_32.h" #include "PHY/NR_TRANSPORT/nr_sch_dmrs.h" #include "PHY/NR_REFSIG/ul_ref_seq_nr.h" @@ -64,6 +63,8 @@ typedef struct puschAntennaProc_s { c16_t ***rxdataF; task_ans_t *ans; scopeData_t *scope; + c16_t *pusch_ch_est_dmrs_pos_slot_mem; + int dmrs_symbol_start_idx; } puschAntennaProc_t; __attribute__((always_inline)) inline c16_t c32x16cumulVectVectWithSteps(c16_t *in1, @@ -149,6 +150,9 @@ static void nr_pusch_antenna_processing(void *arg) int re_offset = k0; LOG_D(PHY, "PUSCH estimation DMRS type 1, Freq-domain interpolation"); int pilot_cnt = 0; +#if T_TRACER + int ch_est_cnt = 0; // To trace channel coefficients +#endif for (int n = 0; n < 3 * nb_rb_pusch; n++) { // LS estimation @@ -165,6 +169,17 @@ static void nr_pusch_antenna_processing(void *arg) for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) { ul_ls_est[k] = ch16; } +//------------------Write channel parameters to Memory for data recording ------------------// +#if T_TRACER + if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS)) { + // Trace channel coefficients + c16_t *pusch_ch_est_dmrs_pos_slot_mem = rdata->pusch_ch_est_dmrs_pos_slot_mem; + int dmrs_symbol_start_idx = rdata->dmrs_symbol_start_idx; + pusch_ch_est_dmrs_pos_slot_mem[dmrs_symbol_start_idx + delta + ch_est_cnt] = ch16; // 0, 2, 4, 6, 8, location of REs + pusch_ch_est_dmrs_pos_slot_mem[dmrs_symbol_start_idx + delta + ch_est_cnt + 2] = ch16; // 0, 2, 4, 6, 8, location of REs + } + ch_est_cnt += 4; +#endif pilot_cnt += 2; } c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); @@ -459,7 +474,9 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, unsigned short bwp_start_subcarrier, nfapi_nr_pusch_pdu_t *pusch_pdu, int *max_ch, - uint32_t *nvar) + uint32_t *nvar, + c16_t *pusch_dmrs_slot_mem, + c16_t *pusch_ch_est_dmrs_pos_slot_mem) { c16_t pilot[3280] __attribute__((aligned(32))); @@ -481,8 +498,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, pusch_pdu->scid, Ns, symbol); - pusch_dmrs_type_t dmrs_type = pusch_pdu->dmrs_config_type == NFAPI_NR_DMRS_TYPE1 ? pusch_dmrs_type1 : pusch_dmrs_type2; - float beta_dmrs_pusch = get_beta_dmrs_pusch(pusch_pdu->num_dmrs_cdm_grps_no_data, dmrs_type); + float beta_dmrs_pusch = get_beta_dmrs(pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dmrs_config_type == pusch_dmrs_type2); int16_t dmrs_scaling = (1 / beta_dmrs_pusch) * (1 << 14); nr_pusch_dmrs_rx(gNB, Ns, @@ -519,6 +535,20 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, LOG_I(PHY, "In %s: %d + j*(%d)\n", __FUNCTION__, pilot[i].r, pilot[i].i); } +#endif + + //------------------Write DMRS to Memory for Data Recording ------------------// + int dmrs_symbol_start_idx = symbol * pusch_pdu->nrOfLayers * nb_rb_pusch * NR_NB_SC_PER_RB + nl * nb_rb_pusch * NR_NB_SC_PER_RB; +#if T_TRACER + if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS)) { + // used by T-Tracer to trace DMRS slot grid + int dmrs_delta = 0; // intialize it to zero currently, derive it later from above functions + for (int i = 0; i < (6 * nb_rb_pusch); i++) { + // the generated DMRs is a complex conjugate of mod table, so flip the sign of imag. part + pusch_dmrs_slot_mem[dmrs_symbol_start_idx + dmrs_delta + i * 2].r = pilot[i].r; // 0, 2, 4, 6, 8, location of REs + pusch_dmrs_slot_mem[dmrs_symbol_start_idx + dmrs_delta + i * 2].i = -pilot[i].i; // 0, 2, 4, 6, 8, location of REs + } + } #endif int nest_count = 0; @@ -573,6 +603,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, rdata->rxdataF = gNB->common_vars.rxdataF; rdata->scope = gNB->scopeData; rdata->ans = &ans; + rdata->pusch_ch_est_dmrs_pos_slot_mem = pusch_ch_est_dmrs_pos_slot_mem; + rdata->dmrs_symbol_start_idx = dmrs_symbol_start_idx; // Call the nr_pusch_antenna_processing function if (job_id == num_jobs - 1) { // Run the last job inline @@ -745,11 +777,12 @@ int nr_srs_channel_estimation( const nr_srs_info_t *nr_srs_info, const c16_t **srs_generated_signal, c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports] [gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], c16_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size], c16_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size], - int8_t *snr_per_rb, + int16_t *snr_per_rb, int8_t *snr) { #ifdef SRS_DEBUG @@ -769,16 +802,6 @@ int nr_srs_channel_estimation( } c16_t srs_ls_estimated_channel[frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)]; - uint32_t noise_power_per_rb[srs_pdu->bwp_size]; - - const uint32_t arr_len = frame_parms->nb_antennas_rx * N_ap * M_sc_b_SRS; - - c16_t ch[arr_len]; - memset(ch, 0, arr_len * sizeof(c16_t)); - - c16_t noise[arr_len]; - memset(noise, 0, arr_len * sizeof(c16_t)); - uint8_t mem_offset = ((16 - ((intptr_t)&srs_estimated_channel_freq[0][0][subcarrier_offset + nr_srs_info->k_0_p[0][0]])) & 0xF) >> 2; // >> 2 <=> /sizeof(int32_t) @@ -799,7 +822,7 @@ int nr_srs_channel_estimation( #endif uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier > frame_parms->ofdm_symbol_size) { + if (subcarrier >= frame_parms->ofdm_symbol_size) { subcarrier -= frame_parms->ofdm_symbol_size; } @@ -811,19 +834,12 @@ int nr_srs_channel_estimation( uint16_t subcarrier_cdm = subcarrier; for (int cdm_idx = 0; cdm_idx < fd_cdm; cdm_idx++) { - int16_t generated_real = srs_generated_signal[p_index][subcarrier_cdm].r; - int16_t generated_imag = srs_generated_signal[p_index][subcarrier_cdm].i; - - int16_t received_real = srs_received_signal[ant][subcarrier_cdm].r; - int16_t received_imag = srs_received_signal[ant][subcarrier_cdm].i; - - // We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the generated_real and - // generated_imag. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 + c16_t generated_srs = srs_generated_signal[p_index][subcarrier_cdm]; + c16_t received_srs = srs_received_signal[ant][subcarrier_cdm]; + // We know that nr_srs_info->srs_generated_signal_bits bits are enough to represent the real and imaginary parts of + // generated_srs. So we only need a nr_srs_info->srs_generated_signal_bits shift to ensure that the result fits into 16 // bits. - ls_estimated.r += (int16_t)(((int32_t)generated_real * received_real + (int32_t)generated_imag * received_imag) - >> nr_srs_info->srs_generated_signal_bits); - ls_estimated.i += (int16_t)(((int32_t)generated_real * received_imag - (int32_t)generated_imag * received_real) - >> nr_srs_info->srs_generated_signal_bits); + ls_estimated = c16maddConjShift(generated_srs, received_srs, ls_estimated, nr_srs_info->srs_generated_signal_bits); // Subcarrier increment subcarrier_cdm += K_TC; @@ -902,7 +918,7 @@ int nr_srs_channel_estimation( // Subcarrier increment subcarrier += K_TC; if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier = subcarrier - frame_parms->ofdm_symbol_size; + subcarrier -= frame_parms->ofdm_symbol_size; } } // for (int k = 0; k < M_sc_b_SRS; k++) @@ -911,25 +927,9 @@ int nr_srs_channel_estimation( &srs_est[mem_offset], (frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)) * sizeof(c16_t)); - // Compute noise - subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier > frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; - } - uint16_t base_idx = ant * N_ap * M_sc_b_SRS + p_index * M_sc_b_SRS; - for (int k = 0; k < M_sc_b_SRS; k++) { - ch[base_idx + k] = srs_estimated_channel_freq[ant][p_index][subcarrier]; - noise[base_idx + k].r = abs(srs_ls_estimated_channel[subcarrier].r - ch[base_idx + k].r); - noise[base_idx + k].i = abs(srs_ls_estimated_channel[subcarrier].i - ch[base_idx + k].i); - subcarrier += K_TC; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier = subcarrier - frame_parms->ofdm_symbol_size; - } - } - #ifdef SRS_DEBUG subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; - if (subcarrier > frame_parms->ofdm_symbol_size) { + if (subcarrier >= frame_parms->ofdm_symbol_size) { subcarrier -= frame_parms->ofdm_symbol_size; } @@ -951,13 +951,13 @@ int nr_srs_channel_estimation( srs_ls_estimated_channel[subcarrier].i, srs_estimated_channel_freq[ant][p_index][subcarrier].r, srs_estimated_channel_freq[ant][p_index][subcarrier].i, - noise[base_idx + (k / K_TC)].r, - noise[base_idx + (k / K_TC)].i); + srs_received_noise[ant][subcarrier].r, + srs_received_noise[ant][subcarrier].i); // Subcarrier increment subcarrier++; if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier = subcarrier - frame_parms->ofdm_symbol_size; + subcarrier -= frame_parms->ofdm_symbol_size; } } #endif @@ -978,61 +978,71 @@ int nr_srs_channel_estimation( } // for (int p_index = 0; p_index < N_ap; p_index++) } // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) - // Compute signal power - uint32_t signal_power = max(signal_energy_nodc(ch, arr_len), 1); - -#ifdef SRS_DEBUG - LOG_I(NR_PHY, "signal_power = %u\n", signal_power); -#endif - + // Compute wideband SNR + int tot_subcarriers = m_SRS_b * NR_NB_SC_PER_RB; + uint32_t signal_power = 0; + uint32_t noise_power = 0; + for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { + for (int p_index = 0; p_index < N_ap; p_index++) { + uint16_t subcarrier0 = subcarrier_offset + nr_srs_info->k_0_p[p_index][0]; + if (subcarrier0 >= frame_parms->ofdm_symbol_size) { + subcarrier0 -= frame_parms->ofdm_symbol_size; + } + if (subcarrier0 + tot_subcarriers < frame_parms->ofdm_symbol_size) { + signal_power += signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][subcarrier0], tot_subcarriers); + if (p_index == 0) + noise_power += signal_energy_nodc(&srs_received_noise[ant][subcarrier0], tot_subcarriers); + } else { + int size1 = frame_parms->ofdm_symbol_size - subcarrier0; + int size2 = tot_subcarriers - size1; + uint64_t signal_power_p1 = signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][subcarrier0], size1) * size1; + uint64_t signal_power_p2 = signal_energy_nodc(&srs_estimated_channel_freq[ant][p_index][0], size2) * size2; + signal_power += (signal_power_p1 + signal_power_p2) / tot_subcarriers; + if (p_index == 0) { + uint64_t noise_power_p1 = signal_energy_nodc(&srs_received_noise[ant][subcarrier0], size1) * size1; + uint64_t noise_power_p2 = signal_energy_nodc(&srs_received_noise[ant][0], size2) * size2; + noise_power += (noise_power_p1 + noise_power_p2) / tot_subcarriers; + } + } + } + } + signal_power = max(signal_power / (frame_parms->nb_antennas_rx * N_ap), 1); + noise_power = max(noise_power / (frame_parms->nb_antennas_rx), 1); if (signal_power == 0) { LOG_W(NR_PHY, "Received SRS signal power is 0\n"); return -1; } - - // Compute noise power - const uint8_t srs_symbols_per_rb = srs_pdu->comb_size == 0 ? 6 : 3; - const uint8_t n_noise_est = frame_parms->nb_antennas_rx * N_ap * srs_symbols_per_rb; - uint64_t sum_re = 0; - uint64_t sum_re2 = 0; - uint64_t sum_im = 0; - uint64_t sum_im2 = 0; - - for (int rb = 0; rb < m_SRS_b; rb++) { - sum_re = 0; - sum_re2 = 0; - sum_im = 0; - sum_im2 = 0; - - for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { - for (int p_index = 0; p_index < N_ap; p_index++) { - uint16_t base_idx = ant * N_ap * M_sc_b_SRS + p_index * M_sc_b_SRS + rb * srs_symbols_per_rb; - for (int srs_symb = 0; srs_symb < srs_symbols_per_rb; srs_symb++) { - sum_re = sum_re + noise[base_idx + srs_symb].r; - sum_re2 = sum_re2 + noise[base_idx + srs_symb].r * noise[base_idx + srs_symb].r; - sum_im = sum_im + noise[base_idx + srs_symb].i; - sum_im2 = sum_im2 + noise[base_idx + srs_symb].i * noise[base_idx + srs_symb].i; - } // for (int srs_symb = 0; srs_symb < srs_symbols_per_rb; srs_symb++) - } // for (int p_index = 0; p_index < N_ap; p_index++) - } // for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) - - noise_power_per_rb[rb] = max(sum_re2 / n_noise_est - (sum_re / n_noise_est) * (sum_re / n_noise_est) + sum_im2 / n_noise_est - - (sum_im / n_noise_est) * (sum_im / n_noise_est), - 1); - snr_per_rb[rb] = dB_fixed(signal_power) - dB_fixed(noise_power_per_rb[rb]); - -#ifdef SRS_DEBUG - LOG_I(NR_PHY, "noise_power_per_rb[%i] = %i, snr_per_rb[%i] = %i dB\n", rb, noise_power_per_rb[rb], rb, snr_per_rb[rb]); -#endif - - } // for (int rb = 0; rb < m_SRS_b; rb++) - - const uint32_t noise_power = max(signal_energy_nodc(noise, arr_len), 1); - *snr = dB_fixed(signal_power) - dB_fixed(noise_power); + // Compute SNR per RB + uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[0][0]; + for (int rb = 0; rb < m_SRS_b; rb++) { + if (subcarrier >= frame_parms->ofdm_symbol_size) { + subcarrier -= frame_parms->ofdm_symbol_size; + } + uint32_t noise_power_per_rb = 0; + for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { + if (subcarrier + NR_NB_SC_PER_RB < frame_parms->ofdm_symbol_size) { + noise_power_per_rb += signal_energy_nodc(&srs_received_noise[ant][subcarrier], NR_NB_SC_PER_RB); + } else { + int size1 = frame_parms->ofdm_symbol_size - subcarrier; + int size2 = NR_NB_SC_PER_RB - size1; + uint32_t noise_power_per_rb1 = signal_energy_nodc(&srs_received_noise[ant][subcarrier], size1) * size1; + uint32_t noise_power_per_rb2 = signal_energy_nodc(&srs_received_noise[ant][0], size2) * size2; + noise_power_per_rb += (noise_power_per_rb1 + noise_power_per_rb2) / NR_NB_SC_PER_RB; + } + } + noise_power_per_rb = max(noise_power_per_rb / (frame_parms->nb_antennas_rx), 1); + snr_per_rb[rb] = dB_fixed(signal_power) - dB_fixed(noise_power_per_rb); + subcarrier += NR_NB_SC_PER_RB; + #ifdef SRS_DEBUG - LOG_I(NR_PHY, "noise_power = %u, SNR = %i dB\n", noise_power, *snr); + LOG_I(NR_PHY, "[RB %3i] noise_power_per_rb = %i, snr_per_rb = %i dB\n", rb, noise_power_per_rb, snr_per_rb[rb]); +#endif + } + +#ifdef SRS_DEBUG + LOG_I(NR_PHY, "signal_power = %i dB, noise_power = %i dB, SNR = %i dB\n", dB_fixed(signal_power), dB_fixed(noise_power), *snr); #endif return 0; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 483e1ea090..04377db1b8 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -51,7 +51,9 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, unsigned short bwp_start_subcarrier, nfapi_nr_pusch_pdu_t *pusch_pdu, int *max_ch, - uint32_t *nvar); + uint32_t *nvar, + c16_t *pusch_dmrs_slot_mem, + c16_t *pusch_ch_est_dmrs_pos_slot_mem); void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB); @@ -82,17 +84,18 @@ int nr_srs_channel_estimation( const nr_srs_info_t *nr_srs_info, const c16_t **srs_generated_signal, c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports] [gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], c16_t srs_estimated_channel_time[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size], c16_t srs_estimated_channel_time_shifted[][1 << srs_pdu->num_ant_ports][gNB->frame_parms.ofdm_symbol_size], - int8_t *snr_per_rb, + int16_t *snr_per_rb, int8_t *snr); void nr_freq_equalization(NR_DL_FRAME_PARMS *frame_parms, - int *rxdataF_comp, - int *ul_ch_mag, - int *ul_ch_mag_b, + c16_t *rxdataF_comp, + c16_t *ul_ch_mag, + c16_t *ul_ch_mag_b, unsigned char symbol, unsigned short Msc_RS, unsigned char Qm); diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.c b/openair1/PHY/NR_REFSIG/dmrs_nr.c index 4d5ed0fe63..7dba224cdb 100644 --- a/openair1/PHY/NR_REFSIG/dmrs_nr.c +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.c @@ -306,15 +306,9 @@ int8_t get_next_dmrs_symbol_in_slot(uint16_t ul_dmrs_symb_pos, uint8_t counter, return -1; } - -/* return the total number of dmrs symbol in a slot */ -uint8_t get_dmrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t nb_symb, uint8_t start) +int8_t get_num_dmrs_re_per_rb(const uint8_t dmrs_type, const uint8_t num_cdm_grp_no_data) { - uint8_t tmp = 0; - for (int i = start; i < start + nb_symb; i++) { - tmp += (l_prime_mask >> i) & 0x01; - } - return tmp; + return (dmrs_type == NFAPI_NR_DMRS_TYPE1 ? 6 * num_cdm_grp_no_data : 4 * num_cdm_grp_no_data); } /* return the position of valid dmrs symbol in a slot for channel compensation */ @@ -351,7 +345,7 @@ void nr_chest_time_domain_avg(NR_DL_FRAME_PARMS *frame_parms, simde__m128i *ul_ch128_1; int16_t *ul_ch16_0; int total_symbols = start_symbol + num_symbols; - int num_dmrs_symb = get_dmrs_symbols_in_slot(dmrs_bitmap, total_symbols, start_symbol); + int num_dmrs_symb = count_bits64_with_mask(dmrs_bitmap, start_symbol, total_symbols); int first_dmrs_symb = get_next_dmrs_symbol_in_slot(dmrs_bitmap, start_symbol, total_symbols); AssertFatal(first_dmrs_symb > -1, "No DMRS symbol present in this slot\n"); for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { diff --git a/openair1/PHY/NR_REFSIG/dmrs_nr.h b/openair1/PHY/NR_REFSIG/dmrs_nr.h index 001aae4150..5f17478874 100644 --- a/openair1/PHY/NR_REFSIG/dmrs_nr.h +++ b/openair1/PHY/NR_REFSIG/dmrs_nr.h @@ -63,7 +63,6 @@ uint8_t allowed_xlsch_re_in_dmrs_symbol(uint16_t k, void nr_gen_ref_conj_symbols(const uint32_t *in, uint32_t length, int16_t *output, int mod_order); int8_t get_next_dmrs_symbol_in_slot(uint16_t ul_dmrs_symb_pos, uint8_t counter, uint8_t end_symbol); -uint8_t get_dmrs_symbols_in_slot(uint16_t l_prime_mask, uint16_t nb_symb, uint8_t start); int8_t get_valid_dmrs_idx_for_channel_est(uint16_t dmrs_symb_pos, uint8_t counter); void nr_chest_time_domain_avg(NR_DL_FRAME_PARMS *frame_parms, int32_t **ch_estimates, @@ -72,6 +71,8 @@ void nr_chest_time_domain_avg(NR_DL_FRAME_PARMS *frame_parms, uint16_t dmrs_bitmap, uint16_t num_rbs); +int8_t get_num_dmrs_re_per_rb(const uint8_t dmrs_type, const uint8_t num_cdm_grp_no_data); + static inline uint8_t is_dmrs_symbol(uint8_t l, uint16_t dmrsSymbMask) { DevAssert(l < 32); diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index e929fc5f3e..7fd703ea30 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -117,7 +117,8 @@ int nr_pdsch_dmrs_rx(const PHY_VARS_NR_UE *ue, unsigned short p, unsigned char lp, unsigned short nb_pdsch_rb, - uint8_t config_type) + uint8_t config_type, + int16_t dmrs_scaling) { typedef int array_of_w[2]; const array_of_w *wf = (config_type == NFAPI_NR_DMRS_TYPE1) ? wf1 : wf2; @@ -131,6 +132,7 @@ int nr_pdsch_dmrs_rx(const PHY_VARS_NR_UE *ue, for (int i = 0; i < nb_pdsch_rb * ((config_type == NFAPI_NR_DMRS_TYPE1) ? 6 : 4); i++) { int w = (wf[p - 1000][i & 1]) * (wt[p - 1000][lp]); output[i] = get_modulated(nr_gold_pdsch, i, w == 1); + output[i] = c16mulRealShift(output[i], dmrs_scaling, 14); #ifdef DEBUG_PDSCH printf("nr_pdsch_dmrs_rx dmrs config type %d port %d nb_pdsch_rb %d\n", config_type, p, nb_pdsch_rb); diff --git a/openair1/PHY/NR_REFSIG/nr_gen_mod_table.c b/openair1/PHY/NR_REFSIG/nr_gen_mod_table.c index 76a89f670b..732d531db4 100644 --- a/openair1/PHY/NR_REFSIG/nr_gen_mod_table.c +++ b/openair1/PHY/NR_REFSIG/nr_gen_mod_table.c @@ -22,15 +22,11 @@ #include "nr_refsig.h" #include "nr_mod_table.h" c16_t nr_qpsk_mod_table[4]; - +simde__m128i nr_qpsk_byte_mod_table[256]; int32_t nr_16qam_mod_table[16]; -simde__m128i nr_qpsk_byte_mod_table[2048]; - -int64_t nr_16qam_byte_mod_table[1024]; - +int64_t nr_16qam_byte_mod_table[256]; int64_t nr_64qam_mod_table[4096]; - -int32_t nr_256qam_mod_table[512]; +int32_t nr_256qam_mod_table[256]; void nr_generate_modulation_table() { float sqrt2 = 0.70711; diff --git a/openair1/PHY/NR_REFSIG/nr_mod_table.h b/openair1/PHY/NR_REFSIG/nr_mod_table.h index 517d86b762..81969d9a40 100644 --- a/openair1/PHY/NR_REFSIG/nr_mod_table.h +++ b/openair1/PHY/NR_REFSIG/nr_mod_table.h @@ -29,15 +29,12 @@ #define NR_MOD_TABLE_QAM256_OFFSET 87 extern c16_t nr_qpsk_mod_table[4]; +extern simde__m128i nr_qpsk_byte_mod_table[256]; extern int32_t nr_16qam_mod_table[16]; -#if defined(__SSE2__) -extern simde__m128i nr_qpsk_byte_mod_table[2048]; -#endif - -extern int64_t nr_16qam_byte_mod_table[1024]; +extern int64_t nr_16qam_byte_mod_table[256]; extern int64_t nr_64qam_mod_table[4096]; -extern int32_t nr_256qam_mod_table[512]; +extern int32_t nr_256qam_mod_table[256]; #endif diff --git a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h index 7df105d05c..1d2d4b87ae 100644 --- a/openair1/PHY/NR_REFSIG/refsig_defs_ue.h +++ b/openair1/PHY/NR_REFSIG/refsig_defs_ue.h @@ -49,7 +49,8 @@ int nr_pdsch_dmrs_rx(const PHY_VARS_NR_UE *ue, unsigned short p, unsigned char lp, unsigned short nb_pdsch_rb, - uint8_t config_type); + uint8_t config_type, + int16_t dmrs_scaling); void sl_generate_pss(SL_NR_UE_INIT_PARAMS_t *sl_init_params, uint8_t n_sl_id2, uint16_t scaling); void sl_generate_pss_ifft_samples(sl_nr_ue_phy_params_t *sl_ue_params, SL_NR_UE_INIT_PARAMS_t *sl_init_params); diff --git a/openair1/PHY/NR_REFSIG/ss_pbch_nr.h b/openair1/PHY/NR_REFSIG/ss_pbch_nr.h index 0929d483cd..e3b9b0e8ed 100644 --- a/openair1/PHY/NR_REFSIG/ss_pbch_nr.h +++ b/openair1/PHY/NR_REFSIG/ss_pbch_nr.h @@ -78,7 +78,6 @@ #define NR_N_SYMBOLS_SSB (4) #define IQ_SIZE sizeof(c16_t) /* I and Q are alternatively stored into buffers */ -#define N_SYMB_SLOT (14) /* SS/PBCH parameters : see from TS 38.211 table 7.4.3.1-1: Resources within an SS/PBCH block for PSS... */ #define DMRS_PBCH_PER_RB (N_SC_RB >> 4) /* at 0+v, 4+v, 8+v for a resource block with v = NcellID modulo 4 */ diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index bea9cb63c5..0548c8fc10 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -220,15 +220,6 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB, } else { // DCI payload txdataF[l * frame_parms->ofdm_symbol_size + k] = c16mulRealShift(mod_dci[dci_idx], amp, 15); -#ifdef DEBUG_DCI - LOG_I(NR_PHY_DCI, - "PDCCH: l %d position %d => (%d,%d)\n", - l, - k, - txdataF[l * frame_parms->ofdm_symbol_size + k].r, - txdataF[l * frame_parms->ofdm_symbol_size + k].i; -#endif - dci_idx++; } diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 58d11413f4..535c68f419 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -470,12 +470,14 @@ static inline void do_txdataF(c16_t **txdataF, // get pmi info const int pmi = (pb->prg_size > 0) ? (pb->prgs_list[(int)rb / pb->prg_size].pm_idx) : 0; const int pmi2 = (rb < (rel15->rbSize - 1) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 1) / pb->prg_size].pm_idx) : -1; + const int pmi3 = (rb < (rel15->rbSize - 2) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 2) / pb->prg_size].pm_idx) : -1; + const int pmi4 = (rb < (rel15->rbSize - 3) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 3) / pb->prg_size].pm_idx) : -1; // If pmi of next RB and pmi of current RB are the same, we do 2 RB in a row // if pmi differs, or current rb is the end (rel15->rbSize - 1), than we do 1 RB in a row - const int rb_step = pmi == pmi2 ? 2 : 1; + int rb_step0 = pmi == pmi2 ? 2 : 1; + const int rb_step = rb_step0==2 && pmi3==pmi && pmi4==pmi ? 4 : rb_step0; const int re_cnt = NR_NB_SC_PER_RB * rb_step; - if (pmi == 0) { // unitary Precoding if (subCarrier + re_cnt <= symbol_sz) { // RB does not cross DC if (ant < rel15->nrOfLayers) @@ -643,6 +645,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC #endif } + start_meas(&gNB->dlsch_pdsch_generation_stats); /// Resource mapping // Non interleaved VRB to PRB mapping uint16_t start_sc = frame_parms->first_carrier_offset + (rel15->rbStart + rel15->BWPStart) * NR_NB_SC_PER_RB; @@ -664,6 +667,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC c16_t mod_dmrs[(n_dmrs+63)&~63] __attribute__((aligned(64))); unsigned int re_beginning_of_symbol = 0; + start_meas(&gNB->dlsch_layer_mapping_stats); int layerSz2 = (layerSz + 63) & ~63; c16_t tx_layers[rel15->nrOfLayers][layerSz2] __attribute__((aligned(64))); memset(tx_layers, 0, sizeof(tx_layers)); @@ -676,7 +680,6 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC // pmi = prgs_list[rbidx/prg_size].pm_idx, rbidx =0,...,rbSize-1 // The Precoding matrix: // The Codebook Type I - start_meas(&gNB->dlsch_precoding_stats); nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming; // beam number in multi-beam scenario (concurrent beams) int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); @@ -689,9 +692,10 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC bitmap); c16_t **txdataF = gNB->common_vars.txdataF[beam_nb]; - + stop_meas(&gNB->dlsch_layer_mapping_stats); // Loop Over OFDM symbols: for (int l_symbol = rel15->StartSymbolIndex; l_symbol < rel15->StartSymbolIndex + rel15->NrOfSymbols; l_symbol++) { + start_meas(&gNB->dlsch_resource_mapping_stats); int l_prime = 0; // single symbol layer 0 int l_overline = get_l0(rel15->dlDmrsSymbPos); @@ -758,13 +762,14 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC re_beginning_of_symbol += layer_sz; stop_meas(&gNB->dlsch_resource_mapping_stats); + start_meas(&gNB->dlsch_precoding_stats); for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) { const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz + txdataF_offset; do_txdataF(txdataF, symbol_sz, txdataF_precoding, gNB, rel15, ant, start_sc, txdataF_offset_per_symbol); } + stop_meas(&gNB->dlsch_precoding_stats); } - - stop_meas(&gNB->dlsch_precoding_stats); + stop_meas(&gNB->dlsch_pdsch_generation_stats); /* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits) * should remain a multiple of 8 * 64 with enough offset to fit each dlsch */ diff --git a/openair1/PHY/NR_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_TRANSPORT/nr_pbch.c index 64d07723bd..c5edd4cfde 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_pbch.c @@ -65,16 +65,6 @@ void nr_generate_pbch_dmrs(uint32_t *gold_pbch_dmrs, for (int m=0; m>5])>>((m<<1)&0x1f))&3); mod_dmrs[m] = nr_qpsk_mod_table[idx]; -#ifdef DEBUG_PBCH_DMRS - printf("m %d idx %d gold seq %u b0-b1 %d-%d mod_dmrs %d %d\n", - m, - idx, - gold_pbch_dmrs[(m << 1) >> 5], - (((gold_pbch_dmrs[(m << 1) >> 5]) >> ((m << 1) & 0x1f)) & 1), - (((gold_pbch_dmrs[((m << 1) + 1) >> 5]) >> (((m << 1) + 1) & 0x1f)) & 1), - mod_dmrs[m].r, - mod_dmrs[m].i); -#endif } /// Resource mapping @@ -165,9 +155,6 @@ static void nr_pbch_encoded_scrambling(uint32_t *pbch_e, #ifdef DEBUG_PBCH_ENCODING printf("Scrambling params: nushift %d M %d length %d offset %d\n", nushift, M, length, info.offset); #endif -#ifdef DEBUG_PBCH_ENCODING - printf("s: %04x\t", s); -#endif for (int i = 0; i < length; ++i) { if (((i + info.offset) & 0x1f) == 0) @@ -189,9 +176,6 @@ static uint32_t nr_pbch_scrambling(uint32_t pbch_a_interleaved, uint32_t *s = gold_cache(Nid, info.len); #ifdef DEBUG_PBCH_ENCODING printf("Scrambling params: nushift %d M %d length %d offset %d\n", nushift, M, length, info.offset); -#endif -#ifdef DEBUG_PBCH_ENCODING - printf("s: %04x\t", s); #endif int goldIdx = info.goldIdx; for (int i = 0; i < length; ++i) { @@ -280,9 +264,6 @@ void nr_generate_pbch(PHY_VARS_gNB *gNB, uint8_t *interleaver = gNB->nr_pbch_interleaver; for (int i = 0; i < NR_POLAR_PBCH_PAYLOAD_BITS; i++) { pbch_a_interleaved |= ((pbch_a >> i) & 1) << (*(interleaver + i)); -#ifdef DEBUG_PBCH_ENCODING - printf("i %d out 0x%08x ilv %d (in>>i)&1) %d\n", i, pbch_a_interleaved, *(interleaver+i), (pbch_a >> i) & 1); -#endif } #ifdef DEBUG_PBCH_ENCODING diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index db49237a9e..a7769dc84d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -159,63 +159,6 @@ void nr_ulsch_qam64_qam64(c16_t *stream0_in, c16_t *rho01, uint32_t length); -/** \brief This function generates log-likelihood ratios (decoder input) for single-stream QPSK received waveforms. - @param rxdataF_comp Compensated channel output - @param ulsch_llr llr output - @param nb_re number of REs for this allocation - @param symbol OFDM symbol index in sub-frame -*/ -void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol); - - -/** \brief This function generates log-likelihood ratios (decoder input) for single-stream 16 QAM received waveforms. - @param rxdataF_comp Compensated channel output - @param ul_ch_mag uplink channel magnitude multiplied by the 1st amplitude threshold in QAM 16 - @param ulsch_llr llr output - @param nb_re number of RBs for this allocation - @param symbol OFDM symbol index in sub-frame -*/ -void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, - int32_t **ul_ch_mag, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol); - -/** \brief This function generates log-likelihood ratios (decoder input) for single-stream 64 QAM received waveforms. - @param rxdataF_comp Compensated channel output - @param ul_ch_mag uplink channel magnitude multiplied by the 1st amplitude threshold in QAM 64 - @param ul_ch_magb uplink channel magnitude multiplied by the 2bd amplitude threshold in QAM 64 - @param ulsch_llr llr output - @param nb_re number of REs for this allocation - @param symbol OFDM symbol index in sub-frame -*/ -void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, - int32_t **ul_ch_mag, - int32_t **ul_ch_magb, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol); - -/** \brief This function generates log-likelihood ratios (decoder input) for single-stream 256 QAM received waveforms. - @param rxdataF_comp Compensated channel output - @param ul_ch_mag uplink channel magnitude multiplied by the 1st amplitude threshold in QAM 256 - @param ul_ch_magb uplink channel magnitude multiplied by the 2bd amplitude threshold in QAM 256 - @param ul_ch_magc uplink channel magnitude multiplied by the 3rd amplitude threshold in QAM 256 - @param ulsch_llr llr output - @param nb_re number of REs for this allocation - @param symbol OFDM symbol index in sub-frame -*/ -void nr_ulsch_256qam_llr(int32_t *rxdataF_comp, - int32_t **ul_ch_mag, - int32_t **ul_ch_magb, - int32_t **ul_ch_magc, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol); - /** \brief This function computes the log-likelihood ratios for 4, 16, and 64 QAM @param rxdataF_comp Compensated channel output @param ul_ch_mag uplink channel magnitude multiplied by the 1st amplitude threshold in QAM 64 @@ -226,13 +169,13 @@ void nr_ulsch_256qam_llr(int32_t *rxdataF_comp, @param mod_order modulation order */ void nr_ulsch_compute_llr(int32_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - int32_t *ul_ch_magc, - int16_t *ulsch_llr, + c16_t *ul_ch_mag, + c16_t *ul_ch_magb, + c16_t *ul_ch_magc, + int16_t *ulsch_llr, uint32_t nb_re, - uint8_t symbol, - uint8_t mod_order); + uint8_t symbol, + uint8_t mod_order); void reset_active_stats(PHY_VARS_gNB *gNB, int frame); void reset_active_ulsch(PHY_VARS_gNB *gNB, int frame); @@ -299,7 +242,8 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, slot_t slot, nfapi_nr_srs_pdu_t *srs_pdu, nr_srs_info_t *nr_srs_info, - c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)]); + c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)]); void init_prach_list(PHY_VARS_gNB *gNB); void init_prach_ru_list(RU_t *ru); diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 667c7146b0..239b6f2f29 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -305,6 +305,10 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, LOG_D(PHY, "ULSCH %d in error\n", ULSCH_id); } offset += ((harq_process->K >> 3) - (harq_process->F >> 3) - ((harq_process->C > 1) ? 3 : 0)); + + merge_meas(&phy_vars_gNB->ts_deinterleave, &nrLDPC_segment_decoding_parameters.ts_deinterleave); + merge_meas(&phy_vars_gNB->ts_rate_unmatch, &nrLDPC_segment_decoding_parameters.ts_rate_unmatch); + merge_meas(&phy_vars_gNB->ts_ldpc_decode, &nrLDPC_segment_decoding_parameters.ts_ldpc_decode); } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 1729c8c8c4..28f3e2cc67 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -7,12 +7,23 @@ #include "PHY/NR_REFSIG/ptrs_nr.h" #include "PHY/NR_ESTIMATION/nr_ul_estimation.h" #include "PHY/defs_nr_common.h" +#include "PHY/nr_phy_common/inc/nr_phy_common.h" #include "common/utils/nr/nr_common.h" #include #include "PHY/sse_intrin.h" +#include "T.h" +#include +#include "PHY/log_tools.h" #define INVALID_VALUE 255 +#if T_TRACER +static void copy_c16_data_to_slot_memory(c16_t *src, c16_t *dst_slot, int nb_re_pusch, int symbol) +{ + memcpy(&dst_slot[nb_re_pusch * symbol], src, nb_re_pusch * sizeof(c16_t)); +} +#endif + void nr_idft(int32_t *z, uint32_t Msc_PUSCH) { @@ -148,42 +159,6 @@ static void nr_ulsch_extract_rbs(c16_t* const rxdataF, } } -static void nr_ulsch_scale_channel(int size_est, - int ul_ch_estimates_ext[][size_est], - NR_DL_FRAME_PARMS *frame_parms, - uint8_t symbol, - uint8_t is_dmrs_symbol, - uint32_t len, - uint8_t nrOfLayers, - unsigned short nb_rb, - int shift_ch_ext) -{ - // Determine scaling amplitude based the symbol - int b = 3; - short ch_amp = 1024 * 8; - if (shift_ch_ext > 3) { - b = 0; - ch_amp >>= (shift_ch_ext - 3); - if (ch_amp == 0) { - ch_amp = 1; - } - } else { - b -= shift_ch_ext; - } - simde__m128i ch_amp128 = simde_mm_set1_epi16(ch_amp); // Q3.13 - LOG_D(PHY, "Scaling PUSCH Chest in OFDM symbol %d by %d, pilots %d nb_rb %d NCP %d symbol %d\n", symbol, ch_amp, is_dmrs_symbol, nb_rb, frame_parms->Ncp, symbol); - - for (int aatx = 0; aatx < nrOfLayers; aatx++) { - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - simde__m128i *ul_ch128 = (simde__m128i *)&ul_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * len]; - for (int i = 0; i < len >> 2; i++) { - ul_ch128[i] = simde_mm_mulhi_epi16(ul_ch128[i], ch_amp128); - ul_ch128[i] = simde_mm_slli_epi16(ul_ch128[i], b); - } - } - } -} - static int get_nb_re_pusch (NR_DL_FRAME_PARMS *frame_parms, nfapi_nr_pusch_pdu_t *rel15_ul,int symbol) { uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; @@ -200,47 +175,22 @@ static int get_nb_re_pusch (NR_DL_FRAME_PARMS *frame_parms, nfapi_nr_pusch_pdu_t } else return(rel15_ul->rb_size * NR_NB_SC_PER_RB); } -// compute average channel_level on each (TX,RX) antenna pair -static void nr_ulsch_channel_level(int size_est, - int ul_ch_estimates_ext[][size_est], - NR_DL_FRAME_PARMS *frame_parms, - int32_t *avg, - uint8_t symbol, - uint32_t len, - uint8_t nrOfLayers) -{ - int16_t x = factor2(len); - int16_t y = (len)>>x; - - for (int aatx = 0; aatx < nrOfLayers; aatx++) { - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - - simde__m128i *ul_ch128 = (simde__m128i *)&ul_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * len]; - - //compute average level - avg[aatx * frame_parms->nb_antennas_rx + aarx] = simde_mm_average(ul_ch128, len, x, y); - //LOG_D(PHY, "Channel level: %d\n", avg[aatx * frame_parms->nb_antennas_rx + aarx]); - } - } - -} - -static void nr_ulsch_channel_compensation(c16_t *rxFext, - c16_t *chFext, - c16_t *ul_ch_maga, - c16_t *ul_ch_magb, - c16_t *ul_ch_magc, +static void nr_ulsch_channel_compensation(uint32_t buffer_length, + int nb_rx_ant, + c16_t rxFext[][buffer_length], + c16_t chFext[][nb_rx_ant][buffer_length], + c16_t ul_ch_maga[][buffer_length], + c16_t ul_ch_magb[][buffer_length], + c16_t ul_ch_magc[][buffer_length], int32_t **rxComp, - c16_t *rho, - NR_DL_FRAME_PARMS *frame_parms, - nfapi_nr_pusch_pdu_t* rel15_ul, + int nb_layers, + c16_t rho[][nb_layers][buffer_length], + nfapi_nr_pusch_pdu_t *rel15_ul, uint32_t symbol, - uint32_t buffer_length, uint32_t output_shift) { int mod_order = rel15_ul->qam_mod_order; int nrOfLayers = rel15_ul->nrOfLayers; - int nb_rx_ant = frame_parms->nb_antennas_rx; simde__m256i QAM_ampa_256 = simde_mm256_setzero_si256(); simde__m256i QAM_ampb_256 = simde_mm256_setzero_si256(); @@ -263,13 +213,13 @@ static void nr_ulsch_channel_compensation(c16_t *rxFext, } for (int aatx = 0; aatx < nrOfLayers; aatx++) { - simde__m256i *rxComp_256 = (simde__m256i*)&rxComp[aatx * nb_rx_ant][symbol * buffer_length]; - simde__m256i *rxF_ch_maga_256 = (simde__m256i*)&ul_ch_maga[aatx * buffer_length]; - simde__m256i *rxF_ch_magb_256 = (simde__m256i*)&ul_ch_magb[aatx * buffer_length]; - simde__m256i *rxF_ch_magc_256 = (simde__m256i*)&ul_ch_magc[aatx * buffer_length]; + simde__m256i *rxComp_256 = (simde__m256i *)&rxComp[aatx * nb_rx_ant][symbol * buffer_length]; + simde__m256i *rxF_ch_maga_256 = (simde__m256i *)ul_ch_maga[aatx]; + simde__m256i *rxF_ch_magb_256 = (simde__m256i *)ul_ch_magb[aatx]; + simde__m256i *rxF_ch_magc_256 = (simde__m256i *)ul_ch_magc[aatx]; for (int aarx = 0; aarx < nb_rx_ant; aarx++) { - simde__m256i *rxF_256 = (simde__m256i*) &rxFext[aarx * buffer_length]; - simde__m256i *chF_256 = (simde__m256i*) &chFext[(aatx * nb_rx_ant + aarx) * buffer_length]; + simde__m256i *rxF_256 = (simde__m256i *)rxFext[aarx]; + simde__m256i *chF_256 = (simde__m256i *)chFext[aatx][aarx]; for (int i = 0; i < buffer_length >> 3; i++) { @@ -292,11 +242,11 @@ static void nr_ulsch_channel_compensation(c16_t *rxFext, rxF_ch_magc_256[i] = simde_mm256_add_epi16(rxF_ch_magc_256[i], simde_mm256_mulhrs_epi16(mag, QAM_ampc_256)); } } - if (rho != NULL) { + if (nb_layers > 1) { for (int atx = 0; atx < nrOfLayers; atx++) { - simde__m256i *rho_256 = (simde__m256i * )&rho[(aatx * nrOfLayers + atx) * buffer_length]; - simde__m256i *chF_256 = (simde__m256i *)&chFext[(aatx * nb_rx_ant + aarx) * buffer_length]; - simde__m256i *chF2_256 = (simde__m256i *)&chFext[ (atx * nb_rx_ant + aarx) * buffer_length]; + simde__m256i *rho_256 = (simde__m256i *)rho[aatx][atx]; + simde__m256i *chF_256 = (simde__m256i *)chFext[aatx][aarx]; + simde__m256i *chF2_256 = (simde__m256i *)chFext[atx][aarx]; for (int i = 0; i < buffer_length >> 3; i++) { rho_256[i] = simde_mm256_adds_epi16(rho_256[i], oai_mm256_cpx_mult_conj(chF_256[i], chF2_256[i], output_shift)); } @@ -523,25 +473,20 @@ static void nr_ulsch_construct_HhH_elements(c16_t *conjch00_ch00, } // MMSE Rx function: nr_ulsch_mmse_2layers() -static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, - int **rxdataF_comp, - int **ul_ch_mag, - int **ul_ch_magb, - int **ul_ch_magc, - int nb_layer, - int nb_rx_ant, +static uint8_t nr_ulsch_mmse_2layers(int **rxdataF_comp, uint32_t buffer_length, - c16_t ul_ch_estimates_ext[nb_layer][nb_rx_ant][buffer_length], + int nb_rx_ant, + c16_t ul_ch_mag[][buffer_length], + c16_t ul_ch_magb[][buffer_length], + c16_t ul_ch_magc[][buffer_length], + c16_t ul_ch_estimates_ext[][nb_rx_ant][buffer_length], unsigned short nb_rb, - unsigned char n_rx, unsigned char mod_order, int shift, unsigned char symbol, int length, uint32_t noise_var) { - c16_t *ch00, *ch01, *ch10, *ch11; - c16_t *ch20, *ch30, *ch21, *ch31; uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); /* we need at least alignment to 16 bytes, let's put 32 to be sure @@ -570,7 +515,9 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, c16_t af_mf_11[12 * nb_rb] __attribute__((aligned(32))); uint32_t determ_fin[12*nb_rb] __attribute__((aligned(32))); - switch (n_rx) { + c16_t *ch00, *ch01, *ch10, *ch11; + c16_t *ch20, *ch30, *ch21, *ch31; + switch (nb_rx_ant) { case 2:// ch00 = ul_ch_estimates_ext[0][0]; ch01 = ul_ch_estimates_ext[1][0]; @@ -606,7 +553,7 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, * */ - if (n_rx>=2){ + if (nb_rx_ant >= 2) { // (1/2^log2_maxh)*conj_H_00xH_00: (1/(64*2))conjH_00*H_00*2^15 nr_ulsch_conjch0_mult_ch1(ch00, ch00, @@ -656,7 +603,7 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, nb_rb_0, shift); } - if (n_rx==4){ + if (nb_rx_ant == 4) { // (1/2^log2_maxh)*conj_H_20xH_20: (1/(64*2*16))conjH_20*H_20*2^15 nr_ulsch_conjch0_mult_ch1(ch20, ch20, @@ -732,7 +679,7 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, nb_rb_0, symbol); } - if (n_rx==2){ + if (nb_rx_ant == 2) { nr_ulsch_construct_HhH_elements(conjch00_ch00, conjch01_ch01, conjch11_ch11, @@ -805,7 +752,7 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, simde__m128i *after_mf_d_128 = (simde__m128i *)af_mf_11; simde__m128i *rxdataF_comp128_0 = (simde__m128i *)&rxdataF_comp[0][symbol * buffer_length]; - simde__m128i *rxdataF_comp128_1 = (simde__m128i *)&rxdataF_comp[n_rx][symbol * buffer_length]; + simde__m128i *rxdataF_comp128_1 = (simde__m128i *)&rxdataF_comp[nb_rx_ant][symbol * buffer_length]; if (mod_order > 2) { if (mod_order == 4) { @@ -821,12 +768,12 @@ static uint8_t nr_ulsch_mmse_2layers(NR_DL_FRAME_PARMS *frame_parms, QAM_amp128b = simde_mm_set1_epi16(QAM256_n2); QAM_amp128c = simde_mm_set1_epi16(QAM256_n3); } - ul_ch_mag128_0 = (simde__m128i *) &ul_ch_mag[0]; + ul_ch_mag128_0 = (simde__m128i *)&ul_ch_mag[0]; ul_ch_mag128b_0 = (simde__m128i *)&ul_ch_magb[0]; ul_ch_mag128c_0 = (simde__m128i *)&ul_ch_magc[0]; - ul_ch_mag128_1 = (simde__m128i *) &((int *)ul_ch_mag)[1 * buffer_length]; - ul_ch_mag128b_1 = (simde__m128i *)&((int *)ul_ch_magb)[1 * buffer_length]; - ul_ch_mag128c_1 = (simde__m128i *)&((int *)ul_ch_magc)[1 * buffer_length]; + ul_ch_mag128_1 = (simde__m128i *)&ul_ch_mag[1]; + ul_ch_mag128b_1 = (simde__m128i *)&ul_ch_magb[1]; + ul_ch_mag128c_1 = (simde__m128i *)&ul_ch_magc[1]; } for (int rb = 0; rb < 3 * nb_rb_0; rb++) { @@ -928,7 +875,9 @@ static void inner_rx(PHY_VARS_gNB *gNB, int length, int symbol, int output_shift, - uint32_t nvar) + uint32_t nvar, + c16_t *rxFext_slot, + c16_t *chFext_slot) { int nb_layer = rel15_ul->nrOfLayers; int nb_rx_ant = frame_parms->nb_antennas_rx; @@ -959,6 +908,16 @@ static void inner_rx(PHY_VARS_gNB *gNB, dmrs_symbol_flag, rel15_ul, frame_parms); +#if T_TRACER + int nb_re_pusch = NR_NB_SC_PER_RB * rel15_ul->rb_size; + // Assume assume Tx and Rx = 1 + if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ)) { + copy_c16_data_to_slot_memory(rxFext[aarx], rxFext_slot, nb_re_pusch, symbol); + } + if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL)) { + copy_c16_data_to_slot_memory(chFext[aatx][aarx], chFext_slot, nb_re_pusch, symbol); + } +#endif } } c16_t rho[nb_layer][nb_layer][buffer_length] __attribute__((aligned(32))); @@ -973,28 +932,29 @@ static void inner_rx(PHY_VARS_gNB *gNB, for (int i = 0; i < nb_layer; i++) memset(&pusch_vars->rxdataF_comp[i*nb_rx_ant][symbol * buffer_length], 0, sizeof(int32_t) * buffer_length); - nr_ulsch_channel_compensation((c16_t*)rxFext, - (c16_t*)chFext, - (c16_t*)rxF_ch_maga, - (c16_t*)rxF_ch_magb, - (c16_t*)rxF_ch_magc, + nr_ulsch_channel_compensation(buffer_length, + nb_rx_ant, + rxFext, + chFext, + rxF_ch_maga, + rxF_ch_magb, + rxF_ch_magc, pusch_vars->rxdataF_comp, - (nb_layer == 1) ? NULL : (c16_t*)rho, - frame_parms, + nb_layer, + rho, rel15_ul, symbol, - buffer_length, output_shift); if (nb_layer == 1 && rel15_ul->transform_precoding == transformPrecoder_enabled && rel15_ul->qam_mod_order <= 6) { if (rel15_ul->qam_mod_order > 2) nr_freq_equalization(frame_parms, - &pusch_vars->rxdataF_comp[0][symbol * buffer_length], - (int *)rxF_ch_maga, - (int *)rxF_ch_magb, - symbol, - pusch_vars->ul_valid_re_per_slot[symbol], - rel15_ul->qam_mod_order); + (c16_t *)&pusch_vars->rxdataF_comp[0][symbol * buffer_length], + rxF_ch_maga[0], + rxF_ch_magb[0], + symbol, + pusch_vars->ul_valid_re_per_slot[symbol], + rel15_ul->qam_mod_order); nr_idft(&pusch_vars->rxdataF_comp[0][symbol * buffer_length], pusch_vars->ul_valid_re_per_slot[symbol]); } if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { @@ -1024,17 +984,14 @@ static void inner_rx(PHY_VARS_gNB *gNB, rel15_ul->qam_mod_order); } else { - nr_ulsch_mmse_2layers(frame_parms, - (int32_t **)pusch_vars->rxdataF_comp, - (int **)rxF_ch_maga, - (int **)rxF_ch_magb, - (int **)rxF_ch_magc, - nb_layer, - nb_rx_ant, + nr_ulsch_mmse_2layers((int32_t **)pusch_vars->rxdataF_comp, buffer_length, + nb_rx_ant, + rxF_ch_maga, + rxF_ch_magb, + rxF_ch_magc, chFext, rel15_ul->rb_size, - frame_parms->nb_antennas_rx, rel15_ul->qam_mod_order, pusch_vars->log2_maxh, symbol, @@ -1045,9 +1002,9 @@ static void inner_rx(PHY_VARS_gNB *gNB, if (nb_layer != 2 || rel15_ul->qam_mod_order > 6) for (int aatx = 0; aatx < nb_layer; aatx++) nr_ulsch_compute_llr((int32_t *)&pusch_vars->rxdataF_comp[aatx * nb_rx_ant][symbol * buffer_length], - (int32_t *)rxF_ch_maga[aatx], - (int32_t *)rxF_ch_magb[aatx], - (int32_t *)rxF_ch_magc[aatx], + rxF_ch_maga[aatx], + rxF_ch_magb[aatx], + rxF_ch_magc[aatx], llr[aatx], pusch_vars->ul_valid_re_per_slot[symbol], symbol, @@ -1067,6 +1024,8 @@ typedef struct puschSymbolProc_s { uint32_t nvar; int beam_nb; task_ans_t *ans; + c16_t *pusch_ch_est_dmrs_interpl_slot_mem; + c16_t *rxFext_slot_mem; } puschSymbolProc_t; static void nr_pusch_symbol_processing(void *arg) @@ -1102,7 +1061,9 @@ static void nr_pusch_symbol_processing(void *arg) gNB->pusch_vars[ulsch_id].ul_valid_re_per_slot[symbol], symbol, gNB->pusch_vars[ulsch_id].log2_maxh, - rdata->nvar); + rdata->nvar, + rdata->rxFext_slot_mem, + rdata->pusch_ch_est_dmrs_interpl_slot_mem); int nb_re_pusch = gNB->pusch_vars[ulsch_id].ul_valid_re_per_slot[symbol]; // layer de-mapping @@ -1165,6 +1126,38 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, LOG_D(PHY,"pusch %d.%d : bwp_start_subcarrier %d, rb_start %d, first_carrier_offset %d\n", frame,slot,bwp_start_subcarrier, rel15_ul->rb_start, frame_parms->first_carrier_offset); LOG_D(PHY,"pusch %d.%d : ul_dmrs_symb_pos %x\n",frame,slot,rel15_ul->ul_dmrs_symb_pos); + // Memories to store data for data recording + int buffer_length_slot = rel15_ul->rb_size * NR_NB_SC_PER_RB * 14; // 14 OFDM Symbols per slot + int nb_rx_ant = frame_parms->nb_antennas_rx; + int nb_layer = rel15_ul->nrOfLayers; + + // Initialize memory for DMRS signals + c16_t pusch_dmrs_slot_mem[nb_layer * buffer_length_slot] __attribute__((aligned(32))); + // Initialize memory for channel estimates based on DMRS positions + c16_t pusch_ch_est_dmrs_pos_slot_mem[buffer_length_slot * nb_layer * nb_rx_ant] __attribute__((aligned(32))); + // memory to store slot grid with channel coefficients based on DMRS positions after interpolation + c16_t pusch_ch_est_dmrs_interpl_slot_mem[buffer_length_slot * nb_layer * nb_rx_ant] __attribute__((aligned(32))); + // memory to store extracted data including PUSCH + DMRS + c16_t rxFext_slot_mem[nb_rx_ant * buffer_length_slot] __attribute__((aligned(32))); + +#if T_TRACER + // Initialize memory for DMRS signals + if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS)) + memset(pusch_dmrs_slot_mem, 0, sizeof(c16_t) * nb_layer * buffer_length_slot); + + // Initialize memory for channel estimates based on DMRS positions + if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS)) + memset(pusch_ch_est_dmrs_pos_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_layer * nb_rx_ant); + + // memory to store slot grid with channel coefficients based on DMRS positions after interpolation + if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL)) + memset(pusch_ch_est_dmrs_interpl_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_layer * nb_rx_ant); + + // memory to store extracted data including PUSCH + DMRS + if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ)) + memset(rxFext_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_rx_ant); +#endif + //---------------------------------------------------------- //------------------- Channel estimation ------------------- //---------------------------------------------------------- @@ -1190,7 +1183,9 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, bwp_start_subcarrier, rel15_ul, &max_ch, - &nvar_tmp); + &nvar_tmp, + pusch_dmrs_slot_mem, + pusch_ch_est_dmrs_pos_slot_mem); nvar += nvar_tmp; } // measure the SNR from the channel estimation @@ -1339,31 +1334,29 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, rel15_ul, frame_parms); - int avgs = 0; - int avg[frame_parms->nb_antennas_rx*rel15_ul->nrOfLayers]; uint8_t shift_ch_ext = rel15_ul->nrOfLayers > 1 ? log2_approx(max_ch >> 11) : 0; //---------------------------------------------------------- //--------------------- Channel Scaling -------------------- //---------------------------------------------------------- - nr_ulsch_scale_channel(size_est, - ul_ch_estimates_ext, - frame_parms, - meas_symbol, - (rel15_ul->ul_dmrs_symb_pos >> meas_symbol) & 0x01, - nb_re_pusch, - rel15_ul->nrOfLayers, - rel15_ul->rb_size, - shift_ch_ext); - - nr_ulsch_channel_level(size_est, - ul_ch_estimates_ext, - frame_parms, - avg, - meas_symbol, // index of the start symbol - nb_re_pusch, // number of the re in pusch - rel15_ul->nrOfLayers); + nr_scale_channel(size_est, + ul_ch_estimates_ext, + meas_symbol, + nb_re_pusch, + rel15_ul->nrOfLayers, + frame_parms->nb_antennas_rx, + shift_ch_ext); + int avg[frame_parms->nb_antennas_rx*rel15_ul->nrOfLayers]; + nr_channel_level(meas_symbol, + size_est, + (c16_t (*)[size_est])ul_ch_estimates_ext, + frame_parms->nb_antennas_rx, + rel15_ul->nrOfLayers, + avg, + nb_re_pusch); + + int avgs = 0; for (int nl = 0; nl < rel15_ul->nrOfLayers; nl++) for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) avgs = cmax(avgs, avg[nl * frame_parms->nb_antennas_rx + aarx]); @@ -1417,6 +1410,8 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, rdata->scramblingSequence = scramblingSequence; rdata->nvar = nvar; rdata->beam_nb = beam_nb; + rdata->rxFext_slot_mem = rxFext_slot_mem; + rdata->pusch_ch_est_dmrs_interpl_slot_mem = pusch_ch_est_dmrs_interpl_slot_mem; if (rel15_ul->pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) { nr_pusch_symbol_processing(rdata); @@ -1431,6 +1426,191 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, } } // symbol loop +#if T_TRACER + // Get Time Stamp for T-tracer messages + char trace_time_stamp_str[30]; + get_time_stamp_usec(trace_time_stamp_str); + // trace_time_stamp_str = 8 bytes timestamp = YYYYMMDD + // + 9 bytes timestamp = HHMMSSMMM + // Not Ready for MIMO + int dmrs_port = get_dmrs_port(0, rel15_ul->dmrs_ports); + if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS)) { + // Log GNB_PHY_UL_FD_DMRS using T-Tracer if activated + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : + // int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data + T(T_GNB_PHY_UL_FD_DMRS, + T_INT((int)frame), + T_INT((int)slot), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)), + T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure + T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2) + T_INT((int)rel15_ul->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz) + T_INT((int)rel15_ul->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended) + T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot + T_INT((int)frame_parms->Nid_cell), + T_INT((int)rel15_ul->rnti), + T_INT((int)rel15_ul->rb_size), + T_INT((int)rel15_ul->rb_start), + T_INT((int)rel15_ul->start_symbol_index), // start_ofdm_symbol + T_INT((int)rel15_ul->nr_of_symbols), // num_ofdm_symbols + T_INT((int)rel15_ul->qam_mod_order), // modulation + T_INT((int)rel15_ul->mcs_index), // mcs + T_INT((int)rel15_ul->mcs_table), // mcs_table_index + T_INT((int)rel15_ul->nrOfLayers), // num_layer + T_INT((int)rel15_ul->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1 + T_INT((int)rel15_ul->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1 + T_INT((int)rel15_ul->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions + T_INT((int)number_dmrs_symbols), + // dmrs_start_ofdm_symbol + // dmrs_duration_num_ofdm_symbols + // dmrs_num_add_positions + T_INT((int)dmrs_port), // dmrs_antenna_port + T_INT((int)rel15_ul->scid), // dmrs_nscid + T_INT((int)frame_parms->nb_antennas_rx), // rx antenna + T_INT(0), // number_of_bits + T_BUFFER((c16_t *)(&(pusch_dmrs_slot_mem[0])), rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4)); + } + + if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS)) { + // Log GNB_PHY_UL_FD_CHAN_EST_DMRS_POS using T-Tracer if activated + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : + // int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data + T(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS, + T_INT((int)frame), + T_INT((int)slot), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)), + T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure + T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2) + T_INT((int)rel15_ul->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz) + T_INT((int)rel15_ul->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended) + T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot + T_INT((int)frame_parms->Nid_cell), + T_INT((int)rel15_ul->rnti), + T_INT((int)rel15_ul->rb_size), + T_INT((int)rel15_ul->rb_start), + T_INT((int)rel15_ul->start_symbol_index), // start_ofdm_symbol + T_INT((int)rel15_ul->nr_of_symbols), // num_ofdm_symbols + T_INT((int)rel15_ul->qam_mod_order), // modulation + T_INT((int)rel15_ul->mcs_index), // mcs + T_INT((int)rel15_ul->mcs_table), // mcs_table_index + T_INT((int)rel15_ul->nrOfLayers), // num_layer + T_INT((int)rel15_ul->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1 + T_INT((int)rel15_ul->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1 + T_INT((int)rel15_ul->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions + T_INT((int)number_dmrs_symbols), + // dmrs_start_ofdm_symbol + // dmrs_duration_num_ofdm_symbols + // dmrs_num_add_positions + T_INT((int)dmrs_port), // dmrs_antenna_port + T_INT((int)rel15_ul->scid), // dmrs_nscid + T_INT((int)frame_parms->nb_antennas_rx), // rx antenna + T_INT(0), // number_of_bits + T_BUFFER((c16_t *)(&(pusch_ch_est_dmrs_pos_slot_mem[0])), rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4)); + } + + if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ)) { + // Log GNB_PHY_UL_FD_PUSCH_IQ using T-Tracer if activated + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : + // int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data + + T(T_GNB_PHY_UL_FD_PUSCH_IQ, + T_INT((int)frame), + T_INT((int)slot), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)), + T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure + T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2) + T_INT((int)rel15_ul->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz) + T_INT((int)rel15_ul->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended) + T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot + T_INT((int)frame_parms->Nid_cell), + T_INT((int)rel15_ul->rnti), + T_INT((int)rel15_ul->rb_size), + T_INT((int)rel15_ul->rb_start), + T_INT((int)rel15_ul->start_symbol_index), // start_ofdm_symbol + T_INT((int)rel15_ul->nr_of_symbols), // num_ofdm_symbols + T_INT((int)rel15_ul->qam_mod_order), // modulation + T_INT((int)rel15_ul->mcs_index), // mcs + T_INT((int)rel15_ul->mcs_table), // mcs_table_index + T_INT((int)rel15_ul->nrOfLayers), // num_layer + T_INT((int)rel15_ul->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1 + T_INT((int)rel15_ul->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1 + T_INT((int)rel15_ul->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions + T_INT((int)number_dmrs_symbols), + // dmrs_start_ofdm_symbol + // dmrs_duration_num_ofdm_symbols + // dmrs_num_add_positions + T_INT((int)dmrs_port), // dmrs_antenna_port + T_INT((int)rel15_ul->scid), // dmrs_nscid + T_INT((int)frame_parms->nb_antennas_rx), // rx antenna + T_INT(0), // number_of_bits + T_BUFFER((c16_t *)(&(rxFext_slot_mem[0])), + rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * frame_parms->nb_antennas_rx * 4)); + } + if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL)) { + // Log pusch_ch_est_dmrs_interpl_slot_mem using T-Tracer if activated + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : + // int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data + + T(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL, + T_INT((int)frame), + T_INT((int)slot), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)), + T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure + T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2) + T_INT((int)rel15_ul->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz) + T_INT((int)rel15_ul->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended) + T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot + T_INT((int)frame_parms->Nid_cell), + T_INT((int)rel15_ul->rnti), + T_INT((int)rel15_ul->rb_size), + T_INT((int)rel15_ul->rb_start), + T_INT((int)rel15_ul->start_symbol_index), // start_ofdm_symbol + T_INT((int)rel15_ul->nr_of_symbols), // num_ofdm_symbols + T_INT((int)rel15_ul->qam_mod_order), // modulation + T_INT((int)rel15_ul->mcs_index), // mcs + T_INT((int)rel15_ul->mcs_table), // mcs_table_index + T_INT((int)rel15_ul->nrOfLayers), // num_layer + T_INT((int)rel15_ul->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1 + T_INT((int)rel15_ul->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1 + T_INT((int)rel15_ul->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions + T_INT((int)number_dmrs_symbols), + // dmrs_start_ofdm_symbol + // dmrs_duration_num_ofdm_symbols + // dmrs_num_add_positions + T_INT((int)dmrs_port), // dmrs_antenna_port + T_INT((int)rel15_ul->scid), // dmrs_nscid + T_INT((int)frame_parms->nb_antennas_rx), // rx antenna + T_INT(0), // number_of_bits + T_BUFFER( + (c16_t *)pusch_ch_est_dmrs_interpl_slot_mem, + rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * frame_parms->nb_antennas_rx * rel15_ul->nrOfLayers * 4)); + } +#endif + join_task_ans(&ans); stop_meas(&gNB->rx_pusch_symbol_processing_stats); diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c index d6a5f78beb..3f4660744d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c @@ -39,13 +39,13 @@ #endif void nr_ulsch_compute_llr(int32_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - int32_t *ul_ch_magc, + c16_t *ul_ch_mag, + c16_t *ul_ch_magb, + c16_t *ul_ch_magc, int16_t *ulsch_llr, uint32_t nb_re, - uint8_t symbol, - uint8_t mod_order) + uint8_t symbol, + uint8_t mod_order) { switch(mod_order) { case 2: @@ -390,12 +390,7 @@ void nr_ulsch_qpsk_qpsk(c16_t *stream0_in, c16_t *stream1_in, int16_t *stream0_o #endif } - - #ifdef USE_128BIT - -static const int16_t ones[8] __attribute__((aligned(16))) = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; - // calculate interference magnitude // tmp_result = ones in shorts corr. to interval 2<=x<=4, tmp_result2 interval < 2, tmp_result3 interval 46 @@ -409,7 +404,7 @@ static inline simde__m128i interference_abs_64qam_epi16(simde__m128i psi, simde__m128i c7) { simde__m128i tmp_result = simde_mm_cmpgt_epi16(int_two_ch_mag, psi); - simde__m128i tmp_result3 = simde_mm_xor_si128(tmp_result, (*(simde__m128i *)&ones[0])); + simde__m128i tmp_result3 = simde_mm_xor_si128(tmp_result, allones128()); simde__m128i tmp_result2 = simde_mm_cmpgt_epi16(int_ch_mag, psi); tmp_result = simde_mm_xor_si128(tmp_result, tmp_result2); simde__m128i tmp_result4 = simde_mm_cmpgt_epi16(psi, int_three_ch_mag); @@ -437,7 +432,7 @@ static inline simde__m128i prodsum_psi_a_epi16(simde__m128i psi_r, simde__m128i static inline simde__m128i interference_abs_epi16(simde__m128i psi, simde__m128i int_ch_mag, simde__m128i c1, simde__m128i c2) { simde__m128i tmp_result = simde_mm_cmplt_epi16(psi, int_ch_mag); - simde__m128i tmp_result2 = simde_mm_xor_si128(tmp_result, (*(simde__m128i *)&ones[0])); + simde__m128i tmp_result2 = simde_mm_xor_si128(tmp_result,allones128()); tmp_result = simde_mm_and_si128(tmp_result, c1); tmp_result2 = simde_mm_and_si128(tmp_result2, c2); return simde_mm_or_si128(tmp_result, tmp_result2); @@ -492,9 +487,6 @@ static inline simde__m128i max_epi16(simde__m128i m0, simde__m128i m1, simde__m1 #else -static const int16_t ones256[16] __attribute__((aligned(32))) = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; - // calculate interference magnitude // tmp_result = ones in shorts corr. to interval 2<=x<=4, tmp_result2 interval < 2, tmp_result3 interval 46 @@ -508,7 +500,7 @@ static inline simde__m256i interference_abs_64qam_epi16_256(simde__m256i psi, simde__m256i c7) { simde__m256i tmp_result = simde_mm256_cmpgt_epi16(int_two_ch_mag, psi); - simde__m256i tmp_result3 = simde_mm256_xor_si256(tmp_result, (*(simde__m256i *)&ones256[0])); + simde__m256i tmp_result3 = simde_mm256_xor_si256(tmp_result, allones256()); simde__m256i tmp_result2 = simde_mm256_cmpgt_epi16(int_ch_mag, psi); tmp_result = simde_mm256_xor_si256(tmp_result, tmp_result2); simde__m256i tmp_result4 = simde_mm256_cmpgt_epi16(psi, int_three_ch_mag); @@ -536,7 +528,7 @@ static inline simde__m256i prodsum_psi_a_epi16_256(simde__m256i psi_r, simde__m2 static inline simde__m256i interference_abs_epi16_256(simde__m256i psi, simde__m256i int_ch_mag, simde__m256i c1, simde__m256i c2) { simde__m256i tmp_result = simde_mm256_cmpgt_epi16(int_ch_mag, psi); - simde__m256i tmp_result2 = simde_mm256_xor_si256(tmp_result, (*(simde__m256i *)&ones256[0])); + simde__m256i tmp_result2 = simde_mm256_xor_si256(tmp_result, allones256()); tmp_result = simde_mm256_and_si256(tmp_result, c1); tmp_result2 = simde_mm256_and_si256(tmp_result2, c2); return simde_mm256_or_si256(tmp_result, tmp_result2); diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index a9639ce0d7..ddf16a0541 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -41,7 +41,6 @@ #include "PHY/defs_nr_common.h" #include "PHY/defs_gNB.h" #include "PHY/sse_intrin.h" -#include "PHY/NR_UE_TRANSPORT/pucch_nr.h" #include "PHY/CODING/nrSmallBlock/nr_small_block_defs.h" #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index c8b6d99c30..3da018bf84 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -36,7 +36,6 @@ #include "PHY/defs_gNB.h" #include "PHY/defs_RU.h" #include "PHY/CODING/nrSmallBlock/nr_small_block_defs.h" -#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h" #include "common/utils/LOG/log.h" #include "SCHED_NR/sched_nr.h" #include "nfapi/oai_integration/vendor_ext.h" @@ -80,59 +79,67 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, slot_t slot, nfapi_nr_srs_pdu_t *srs_pdu, nr_srs_info_t *nr_srs_info, - c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)]) + c16_t srs_received_signal[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)], + c16_t srs_received_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)]) { const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; const uint16_t n_symbols = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot; // number of symbols until this slot - const uint8_t l0 = srs_pdu->time_start_position; // starting symbol in this slot + const uint8_t l0 = srs_pdu->time_start_position; // starting symbol in this slot const uint64_t symbol_offset = (n_symbols + l0) * frame_parms->ofdm_symbol_size; - const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*NR_NB_SC_PER_RB; + const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start * NR_NB_SC_PER_RB; - const uint8_t N_ap = 1<num_ant_ports; + const uint8_t N_ap = 1 << srs_pdu->num_ant_ports; const uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; const uint8_t K_TC = 2 << srs_pdu->comb_size; const uint16_t M_sc_b_SRS = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index) * NR_NB_SC_PER_RB / K_TC; - c16_t *rx_signal; bool no_srs_signal = true; for (int ant = 0; ant < frame_parms->nb_antennas_rx; ant++) { memset(srs_received_signal[ant], 0, frame_parms->ofdm_symbol_size * sizeof(c16_t)); - rx_signal = &rxdataF[ant][symbol_offset]; + memset(srs_received_noise[ant], 0, frame_parms->ofdm_symbol_size * sizeof(c16_t)); + c16_t *rx_signal = &rxdataF[ant][symbol_offset]; for (int p_index = 0; p_index < N_ap; p_index++) { - #ifdef SRS_DEBUG - LOG_I(NR_PHY,"===== UE port %d --> gNB Rx antenna %i =====\n", p_index, ant); + LOG_I(NR_PHY, "===== UE port %d --> gNB Rx antenna %i =====\n", p_index, ant); #endif for (int l_line = 0; l_line < N_symb_SRS; l_line++) { - #ifdef SRS_DEBUG - LOG_I(NR_PHY,":::::::: OFDM symbol %d ::::::::\n", l0+l_line); + LOG_I(NR_PHY, ":::::::: OFDM symbol %d ::::::::\n", l0 + l_line); #endif uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[p_index][l_line]; - if (subcarrier>frame_parms->ofdm_symbol_size) { + if (subcarrier >= frame_parms->ofdm_symbol_size) { subcarrier -= frame_parms->ofdm_symbol_size; } - uint16_t l_line_offset = l_line*frame_parms->ofdm_symbol_size; + uint16_t l_line_offset = l_line * frame_parms->ofdm_symbol_size; for (int k = 0; k < M_sc_b_SRS; k++) { - - srs_received_signal[ant][l_line_offset+subcarrier] = rx_signal[l_line_offset+subcarrier]; - + // Subcarriers with SRS symbols + srs_received_signal[ant][l_line_offset + subcarrier] = rx_signal[l_line_offset + subcarrier]; if (rx_signal[l_line_offset + subcarrier].r || rx_signal[l_line_offset + subcarrier].i) { no_srs_signal = false; } + // Subcarriers without SRS symbols and only noise + srs_received_noise[ant][l_line_offset + subcarrier] = rx_signal[l_line_offset + subcarrier + 1]; + for (int n = 1; n < K_TC; n++) { + uint16_t subcarrier_n = subcarrier + n; + if (subcarrier_n >= frame_parms->ofdm_symbol_size) { + subcarrier_n -= frame_parms->ofdm_symbol_size; + } + srs_received_noise[ant][l_line_offset + subcarrier_n] = rx_signal[l_line_offset + subcarrier_n]; + } + #ifdef SRS_DEBUG - int subcarrier_log = subcarrier-subcarrier_offset; - if(subcarrier_log < 0) { + int subcarrier_log = subcarrier - subcarrier_offset; + if (subcarrier_log < 0) { subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size; } - if(subcarrier_log%12 == 0) { - LOG_I(NR_PHY,"------------ %d ------------\n", subcarrier_log/12); + if (subcarrier_log % 12 == 0) { + LOG_I(NR_PHY, "------------ %d ------------\n", subcarrier_log / 12); } LOG_I(NR_PHY, "(%i) \t%i\t%i\n", @@ -144,7 +151,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, // Subcarrier increment subcarrier += K_TC; if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier=subcarrier-frame_parms->ofdm_symbol_size; + subcarrier -= frame_parms->ofdm_symbol_size; } } // for (int k = 0; k < M_sc_b_SRS; k++) diff --git a/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp b/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp index bd0c95d2ae..f07aa8e552 100644 --- a/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp +++ b/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp @@ -48,12 +48,11 @@ void exit_function(const char *file, const char *function, const int line, const #include "openair1/PHY/TOOLS/phy_test_tools.hpp" #include -int16_t saturating_sub(int16_t a, int16_t b) +int16_t saturating_sub(int a, int b) { - int32_t result = (int32_t)a - (int32_t)b; - - if (result < INT16_MIN) { - return INT16_MIN; + int result = a - abs(b); + if (result < -INT16_MAX) { + return -INT16_MAX; } else if (result > INT16_MAX) { return INT16_MAX; } else { @@ -71,8 +70,8 @@ void nr_16qam_llr_ref(c16_t *rxdataF_comp, int32_t *ch_mag, int16_t *llr, uint32 int16_t mag_imag = ch_mag_i16[2 * i + 1]; llr[4 * i] = real; llr[4 * i + 1] = imag; - llr[4 * i + 2] = saturating_sub(mag_real, std::abs(real)); - llr[4 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + llr[4 * i + 2] = saturating_sub(mag_real, real); + llr[4 * i + 3] = saturating_sub(mag_imag, imag); } } @@ -91,12 +90,12 @@ void nr_64qam_llr_ref(c16_t *rxdataF_comp, int16_t mag_imag = ch_mag_i16[2 * i + 1]; llr[6 * i] = real; llr[6 * i + 1] = imag; - llr[6 * i + 2] = saturating_sub(mag_real, std::abs(real)); - llr[6 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + llr[6 * i + 2] = saturating_sub(mag_real, real); + llr[6 * i + 3] = saturating_sub(mag_imag, imag); int16_t mag_realb = ch_magb_i16[2 * i]; int16_t mag_imagb = ch_magb_i16[2 * i + 1]; - llr[6 * i + 4] = saturating_sub(mag_realb, std::abs(llr[6 * i + 2])); - llr[6 * i + 5] = saturating_sub(mag_imagb, std::abs(llr[6 * i + 3])); + llr[6 * i + 4] = saturating_sub(mag_realb, llr[6 * i + 2]); + llr[6 * i + 5] = saturating_sub(mag_imagb, llr[6 * i + 3]); } } @@ -117,16 +116,16 @@ void nr_256qam_llr_ref(c16_t *rxdataF_comp, int16_t mag_imag = ch_mag_i16[2 * i + 1]; llr[8 * i] = real; llr[8 * i + 1] = imag; - llr[8 * i + 2] = saturating_sub(mag_real, std::abs(real)); - llr[8 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + llr[8 * i + 2] = saturating_sub(mag_real, real); + llr[8 * i + 3] = saturating_sub(mag_imag, imag); int16_t magb_real = ch_magb_i16[2 * i]; int16_t magb_imag = ch_magb_i16[2 * i + 1]; - llr[8 * i + 4] = saturating_sub(magb_real, std::abs(llr[8 * i + 2])); - llr[8 * i + 5] = saturating_sub(magb_imag, std::abs(llr[8 * i + 3])); + llr[8 * i + 4] = saturating_sub(magb_real, llr[8 * i + 2]); + llr[8 * i + 5] = saturating_sub(magb_imag, llr[8 * i + 3]); int16_t magc_real = ch_magc_i16[2 * i]; int16_t magc_imag = ch_magc_i16[2 * i + 1]; - llr[8 * i + 6] = saturating_sub(magc_real, std::abs(llr[8 * i + 4])); - llr[8 * i + 7] = saturating_sub(magc_imag, std::abs(llr[8 * i + 5])); + llr[8 * i + 6] = saturating_sub(magc_real, llr[8 * i + 4]); + llr[8 * i + 7] = saturating_sub(magc_imag, llr[8 * i + 5]); } } @@ -136,23 +135,21 @@ void test_function_16_qam(AlignedVector512 nb_res) uint32_t nb_re = nb_res[i]; auto rf_data = generate_random_c16(nb_re); auto magnitude_data = generate_random_uint16(nb_re * 2); - AlignedVector512 llr_ref; - llr_ref.resize(nb_re); + AlignedVector512 llr_ref; + llr_ref.resize(nb_re * 4); std::fill(llr_ref.begin(), llr_ref.end(), 0); nr_16qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int16_t *)llr_ref.data(), nb_re); - AlignedVector512 llr; - llr.resize(nb_re); + AlignedVector512 llr; + llr.resize(nb_re * 4); std::fill(llr.begin(), llr.end(), 0); nr_16qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int16_t *)llr.data(), nb_re); int num_errors = 0; - for (auto i = 0U; i < nb_re; i++) { - EXPECT_EQ(llr_ref[i], llr[i]) - << "Mismatch 16qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i; - if (llr_ref[i] != llr[i]) { - num_errors++; - } + for (auto i = 0U; i < llr_ref.size(); i++) { + EXPECT_LE(llr_ref[i] - llr[i] ? (llr_ref[i] - llr[i]) / (float)llr[i] : 0, 0.001) + << "Mismatch 16qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i + << "total err: " << ++num_errors; } EXPECT_EQ(num_errors, 0) << " Errors during testing 16qam llr " << num_errors << " nb res " << nb_re; } @@ -165,8 +162,8 @@ void test_function_64_qam(AlignedVector512 nb_res) auto rf_data = generate_random_c16(nb_re); auto magnitude_data = generate_random_uint16(nb_re * 2); auto magnitude_b_data = generate_random_uint16(nb_re * 2); - AlignedVector512 llr_ref; - llr_ref.resize(nb_re * 3); + AlignedVector512 llr_ref; + llr_ref.resize(nb_re * 6); std::fill(llr_ref.begin(), llr_ref.end(), 0); nr_64qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), @@ -174,8 +171,8 @@ void test_function_64_qam(AlignedVector512 nb_res) (int16_t *)llr_ref.data(), nb_re); - AlignedVector512 llr; - llr.resize(nb_re * 3); + AlignedVector512 llr; + llr.resize(nb_re * 6); std::fill(llr.begin(), llr.end(), 0); nr_64qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), @@ -184,12 +181,10 @@ void test_function_64_qam(AlignedVector512 nb_res) nb_re); int num_errors = 0; - for (auto i = 0U; i < nb_re * 3; i++) { - EXPECT_EQ(llr_ref[i], llr[i]) - << "Mismatch 64qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i; - if (llr_ref[i] != llr[i]) { - num_errors++; - } + for (auto i = 0U; i < llr.size(); i++) { + EXPECT_LE(llr_ref[i] - llr[i] ? (llr_ref[i] - llr[i]) / (float)llr[i] : 0, 0.001) + << "Mismatch 64qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i + << "total err: " << ++num_errors; } EXPECT_EQ(num_errors, 0) << " Errors during testing 64qam llr " << num_errors << " nb res " << nb_re; } @@ -203,8 +198,8 @@ void test_function_256_qam(AlignedVector512 nb_res) auto magnitude_data = generate_random_uint16(nb_re * 2); auto magnitude_b_data = generate_random_uint16(nb_re * 2); auto magnitude_c_data = generate_random_uint16(nb_re * 2); - AlignedVector512 llr_ref; - llr_ref.resize(nb_re * 4); + AlignedVector512 llr_ref; + llr_ref.resize(nb_re * 8); std::fill(llr_ref.begin(), llr_ref.end(), 0); nr_256qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), @@ -213,8 +208,8 @@ void test_function_256_qam(AlignedVector512 nb_res) (int16_t *)llr_ref.data(), nb_re); - AlignedVector512 llr; - llr.resize(nb_re * 4); + AlignedVector512 llr; + llr.resize(nb_re * 8); std::fill(llr.begin(), llr.end(), 0); nr_256qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), @@ -224,12 +219,10 @@ void test_function_256_qam(AlignedVector512 nb_res) nb_re); int num_errors = 0; - for (auto i = 0U; i < nb_re * 4; i++) { - EXPECT_EQ(llr_ref[i], llr[i]) - << "Mismatch 256qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i; - if (llr_ref[i] != llr[i]) { - num_errors++; - } + for (auto i = 0U; i < llr.size(); i++) { + EXPECT_LE(llr_ref[i] - llr[i] ? (llr_ref[i] - llr[i]) / (float)llr[i] : 0, 0.001) + << "Mismatch 256qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i + << "total err: " << ++num_errors; } EXPECT_EQ(num_errors, 0) << " Errors during testing 256qam llr " << num_errors << " nb res " << nb_re; } @@ -401,11 +394,9 @@ TEST(test_llr, check_2_res_256_qam) int num_errors = 0; for (auto i = 0U; i < 2 * 8; i++) { - EXPECT_EQ(llr_ref[i], llr[i]) - << "Mismatch 256qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i; - if (llr_ref[i] != llr[i]) { - num_errors++; - } + EXPECT_LE(llr_ref[i] - llr[i] ? (llr_ref[i] - llr[i]) / (float)llr[i] : 0, 0.001) + << "Mismatch 256qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i + << "total err: " << ++num_errors; } EXPECT_EQ(num_errors, 0) << " Errors during testing 256qam llr " << num_errors << " nb res " << 2; } diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index 0e186a3bc3..296606a426 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -19,6 +19,7 @@ * contact@openairinterface.org */ +#include "nr_common.h" #include #include "SCHED_NR_UE/defs.h" #include "nr_estimation.h" @@ -448,12 +449,15 @@ int nr_prs_channel_estimation(uint8_t gNB_id, peak_estimator(&chT_interpol[rxAnt][0], NR_PRS_IDFT_OVERSAMP_FACTOR * frame_params->ofdm_symbol_size, &prs_toa, &ch_pwr, mean_val); // adjusting the rx_gains for channel peak power - ch_pwr_dbm = 10 * log10(ch_pwr) + 30 - SQ15_SQUARED_NORM_FACTOR_DB - ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(frame_params->ofdm_symbol_size); + ch_pwr_dbm = 10 * log10(ch_pwr) + 30 - SQ15_SQUARED_NORM_FACTOR_DB + - ((int)ue->openair0_cfg[0].rx_gain[0] - (int)ue->openair0_cfg[0].rx_gain_offset[0]) + - dB_fixed(frame_params->ofdm_symbol_size); - prs_meas[rxAnt]->rsrp_dBm = - 10 * log10(prs_meas[rxAnt]->rsrp) + 30 - SQ15_SQUARED_NORM_FACTOR_DB - ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(ue->frame_parms.ofdm_symbol_size); + prs_meas[rxAnt]->rsrp_dBm = 10 * log10(prs_meas[rxAnt]->rsrp) + 30 - SQ15_SQUARED_NORM_FACTOR_DB + - ((int)ue->openair0_cfg[0].rx_gain[0] - (int)ue->openair0_cfg[0].rx_gain_offset[0]) + - dB_fixed(ue->frame_parms.ofdm_symbol_size); - //prs measurements + // prs measurements prs_meas[rxAnt]->gNB_id = gNB_id; prs_meas[rxAnt]->sfn = proc->frame_rx; prs_meas[rxAnt]->slot = proc->nr_slot_rx; @@ -938,51 +942,57 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, c16_t *pil, c16_t *dl_ch, unsigned short bwp_start_subcarrier, - unsigned short nb_rb_pdsch, + int rb_offset, + int nb_rb_pdsch, + const uint8_t bitmap[36], delay_t *delay, uint32_t *nvar) { c16_t *dl_ch0 = dl_ch; int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; - c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); memset(dl_ls_est, 0, sizeof(dl_ls_est)); - - int nest_count = 0; - uint64_t noise_amp2 = 0; - - for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt += 2) { - c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); + int idx = 0; + for (int rb = rb_offset; rb < rb_offset + nb_rb_pdsch; rb++) { + bool allocated_rb = (bitmap[rb / 8] >> (rb % 8)) & 0x01; + if (allocated_rb) { + for (int pilot_cnt = 0; pilot_cnt < 6; pilot_cnt += 2) { + c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); #endif - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); + pil++; + re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; + c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); #endif - c16_t ch = c16addShift(ch_l, ch_r, 1); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) { - dl_ls_est[k] = ch; + c16_t ch = c16addShift(ch_l, ch_r, 1); + pil++; + re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; + for (int k = 0; k < 4; k++) { + dl_ls_est[idx] = ch; + idx++; + } + } + } else { + pil += 6; + re_offset = (re_offset + 12) % frame_parms->ofdm_symbol_size; } } - c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); nr_est_delay(frame_parms->ofdm_symbol_size, dl_ls_est, ch_estimates_time, delay); int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP); c16_t *dl_delay_table = frame_parms->delay_table[delay_idx]; - for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) { + for (int pilot_cnt = 0; pilot_cnt < idx >> 1; pilot_cnt++) { int k = pilot_cnt << 1; c16_t ch = c16mulShift(dl_ls_est[k], dl_delay_table[k], 8); if (pilot_cnt == 0) { // Treat first pilot c16multaddVectRealComplex(filt16_ul_p0, &ch, dl_ch, 16); } else if (pilot_cnt == 1 || pilot_cnt == 2) { c16multaddVectRealComplex(filt16_ul_p1p2, &ch, dl_ch, 16); - } else if (pilot_cnt == 6 * nb_rb_pdsch - 1) { // Treat last pilot + } else if (pilot_cnt == (idx >> 1) - 1) { // Treat last pilot c16multaddVectRealComplex(filt16_ul_last, &ch, dl_ch, 16); } else { // Treat middle pilots c16multaddVectRealComplex(filt16_ul_middle, &ch, dl_ch, 16); @@ -994,9 +1004,11 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, // Revert delay dl_ch = dl_ch0; + int nest_count = 0; + uint64_t noise_amp2 = 0; int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); c16_t *dl_inv_delay_table = frame_parms->delay_table[inv_delay_idx]; - for (int k = 0; k < 12 * nb_rb_pdsch; k++) { + for (int k = 0; k < idx; k++) { dl_ch[k] = c16mulShift(dl_ch[k], dl_inv_delay_table[k], 8); noise_amp2 += c16amp2(c16sub(dl_ls_est[k], dl_ch[k])); nest_count++; @@ -1096,51 +1108,58 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, c16_t *pil, c16_t *dl_ch, unsigned short bwp_start_subcarrier, - unsigned short nb_rb_pdsch, + int rb_offset, + int nb_rb_pdsch, + const uint8_t bitmap[36], delay_t *delay, uint32_t *nvar) { int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size; c16_t *dl_ch0 = dl_ch; - c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); memset(dl_ls_est, 0, sizeof(dl_ls_est)); - - int nest_count = 0; - uint64_t noise_amp2 = 0; - - for (int pilot_cnt = 0; pilot_cnt < 4 * nb_rb_pdsch; pilot_cnt += 2) { - c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); + int idx = 0; + for (int rb = rb_offset; rb < rb_offset + nb_rb_pdsch; rb++) { + bool allocated_rb = (bitmap[rb / 8] >> (rb % 8)) & 0x01; + if (allocated_rb) { + for (int pilot_cnt = 0; pilot_cnt < 4; pilot_cnt += 2) { + c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); #endif - pil++; - re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size; - c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); + pil++; + re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size; + c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); #endif - c16_t ch = c16addShift(ch_l, ch_r, 1); - for (int k = 3 * pilot_cnt; k < (3 * pilot_cnt) + 6; k++) { - dl_ls_est[k] = ch; + c16_t ch = c16addShift(ch_l, ch_r, 1); + pil++; + re_offset = (re_offset + 5) % frame_parms->ofdm_symbol_size; + for (int k = 0; k < 6; k++) { + dl_ls_est[idx] = ch; + idx++; + } + } + } else { + pil += 4; + re_offset = (re_offset + 12) % frame_parms->ofdm_symbol_size; } - pil++; - re_offset = (re_offset + 5) % frame_parms->ofdm_symbol_size; } c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); nr_est_delay(frame_parms->ofdm_symbol_size, dl_ls_est, ch_estimates_time, delay); int delay_idx = get_delay_idx(delay->est_delay, MAX_DELAY_COMP); c16_t *dl_delay_table = frame_parms->delay_table[delay_idx]; - - for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) { - int k = (pilot_cnt / 3) * 6; + // kept the same as before but unclear why would it be nb_rb_pdsch / 2 and not / 3 + for (int pilot_cnt = 0; pilot_cnt < idx >> 1; pilot_cnt++) { + int k = pilot_cnt << 1; c16_t ch = c16mulShift(dl_ls_est[k], dl_delay_table[k], 8); if (pilot_cnt == 0) { // Treat first pilot c16multaddVectRealComplex(filt16_ul_p0, &ch, dl_ch, 16); } else if (pilot_cnt == 1 || pilot_cnt == 2) { c16multaddVectRealComplex(filt16_ul_p1p2, &ch, dl_ch, 16); - } else if (pilot_cnt == 6 * nb_rb_pdsch - 1) { // Treat last pilot + } else if (pilot_cnt == (idx >> 1) - 1) { // Treat last pilot c16multaddVectRealComplex(filt16_ul_last, &ch, dl_ch, 16); } else { // Treat middle pilots c16multaddVectRealComplex(filt16_ul_middle, &ch, dl_ch, 16); @@ -1152,9 +1171,11 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, // Revert delay dl_ch = dl_ch0; + int nest_count = 0; + uint64_t noise_amp2 = 0; int inv_delay_idx = get_delay_idx(-delay->est_delay, MAX_DELAY_COMP); c16_t *dl_inv_delay_table = frame_parms->delay_table[inv_delay_idx]; - for (int k = 0; k < 12 * nb_rb_pdsch; k++) { + for (int k = 0; k < idx; k++) { dl_ch[k] = c16mulShift(dl_ch[k], dl_inv_delay_table[k], 8); noise_amp2 += c16amp2(c16sub(dl_ls_est[k], dl_ch[k])); nest_count++; @@ -1249,29 +1270,25 @@ void NFAPI_NR_DMRS_TYPE2_average_prb(NR_DL_FRAME_PARMS *frame_parms, #endif } -int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - int nl, - unsigned short p, - unsigned char symbol, - unsigned char nscid, - unsigned short scrambling_id, - unsigned short BWPStart, - uint8_t config_type, - uint16_t rb_offset, - unsigned short bwp_start_subcarrier, - unsigned short nb_rb_pdsch, - uint32_t pdsch_est_size, - int32_t dl_ch_estimates[][pdsch_est_size], - int rxdataFsize, - c16_t rxdataF[][rxdataFsize], - uint32_t *nvar) +void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + const fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch, + const freq_alloc_bitmap_t *freq_alloc, + int nl, + unsigned short p, + unsigned char symbol, + uint32_t pdsch_est_size, + int32_t dl_ch_estimates[][pdsch_est_size], + int rxdataFsize, + c16_t rxdataF[][rxdataFsize], + uint32_t *nvar) { // int gNB_id = proc->gNB_id; int slot = proc->nr_slot_rx; NR_DL_FRAME_PARMS *fp = &ue->frame_parms; const int ch_offset = fp->ofdm_symbol_size * symbol; const int symbol_offset = fp->ofdm_symbol_size * symbol; + int bwp_start_subcarrier = fp->first_carrier_offset + (dlsch->BWPStart + freq_alloc->start[0]) * 12; #ifdef DEBUG_PDSCH printf( @@ -1287,12 +1304,16 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, #endif // generate pilot for gNB port number 1000+p + int config_type = dlsch->dmrsConfigType; + int rb_offset = freq_alloc->start[0] + (dlsch->refPoint ? 0 : dlsch->BWPStart); + int nb_rb_pdsch = freq_alloc->end[freq_alloc->num_blocks - 1] - freq_alloc->start[0] + 1; int8_t delta = get_delta(p, config_type); - c16_t pilot[3280] __attribute__((aligned(16))); // Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS - const uint32_t *gold = nr_gold_pdsch(fp->N_RB_DL, fp->symbols_per_slot, scrambling_id, nscid, slot, symbol); - nr_pdsch_dmrs_rx(ue, slot, gold, pilot, 1000 + p, 0, nb_rb_pdsch + rb_offset, config_type); + float beta_dmrs_pdsch = get_beta_dmrs(dlsch->n_dmrs_cdm_groups, config_type == NFAPI_NR_DMRS_TYPE2); + int16_t dmrs_scaling = (int16_t)((1 / beta_dmrs_pdsch) * (1 << 14)); + const uint32_t *gold = nr_gold_pdsch(fp->N_RB_DL, fp->symbols_per_slot, dlsch->dlDmrsScramblingId, dlsch->nscid, slot, symbol); + nr_pdsch_dmrs_rx(ue, slot, gold, pilot, 1000 + p, 0, nb_rb_pdsch + rb_offset, config_type, dmrs_scaling); delay_t delay = {0}; @@ -1308,12 +1329,14 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, memset(dl_ch, 0, sizeof(*dl_ch) * fp->ofdm_symbol_size); if (config_type == NFAPI_NR_DMRS_TYPE1 && ue->chest_freq == 0) { - NFAPI_NR_DMRS_TYPE1_linear_interp(&ue->frame_parms, + NFAPI_NR_DMRS_TYPE1_linear_interp(fp, rxF, &pilot[6 * rb_offset], dl_ch, bwp_start_subcarrier, + freq_alloc->start[0], nb_rb_pdsch, + freq_alloc->bitmap, &delay, nvar); @@ -1323,14 +1346,18 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, &pilot[4 * rb_offset], dl_ch, bwp_start_subcarrier, + freq_alloc->start[0], nb_rb_pdsch, + freq_alloc->bitmap, &delay, nvar); } else if (config_type == NFAPI_NR_DMRS_TYPE1) { + AssertFatal(dlsch->resource_alloc == 1, "PRB average in channel estimation not supported for type0 DLSCH\n"); NFAPI_NR_DMRS_TYPE1_average_prb(fp, rxF, &pilot[6 * rb_offset], dl_ch, bwp_start_subcarrier, nb_rb_pdsch); } else { + AssertFatal(dlsch->resource_alloc == 1, "PRB average in channel estimation not supported for type0 DLSCH\n"); NFAPI_NR_DMRS_TYPE2_average_prb(fp, rxF, &pilot[4 * rb_offset], dl_ch, bwp_start_subcarrier, nb_rb_pdsch); } @@ -1344,7 +1371,6 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, } #endif } - return 0; } /******************************************************************* @@ -1362,7 +1388,6 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, * uint8_t : gNB_id, * uint8_t : nr_slot_rx, * unsigned char : symbol, - * uint32_t : nb_re_pdsch, * uint16_t : rnti * RX_type_t : rx_type * RETURN : Nothing @@ -1385,7 +1410,6 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t nr_slot_rx, unsigned char symbol, - uint32_t nb_re_pdsch, uint16_t rnti, NR_UE_DLSCH_t dlsch[2]) { diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index da6fd31eb5..66339e25a2 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -78,23 +78,18 @@ int nr_pbch_channel_estimation(const NR_DL_FRAME_PARMS *fp, bool sidelink, uint Nid); -int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - int nl, - unsigned short p, - unsigned char symbol, - unsigned char nscid, - unsigned short scrambling_id, - unsigned short BWPStart, - uint8_t config_type, - uint16_t rb_offset, - unsigned short bwp_start_subcarrier, - unsigned short nb_rb_pdsch, - uint32_t pdsch_est_size, - int32_t dl_ch_estimates[][pdsch_est_size], - int rxdataFsize, - c16_t rxdataF[][rxdataFsize], - uint32_t *nvar); +void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + const fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch, + const freq_alloc_bitmap_t *freq_alloc, + int nl, + unsigned short p, + unsigned char symbol, + uint32_t pdsch_est_size, + int32_t dl_ch_estimates[][pdsch_est_size], + int rxdataFsize, + c16_t rxdataF[][rxdataFsize], + uint32_t *nvar); int nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms, PHY_VARS_NR_UE *ue, @@ -107,7 +102,7 @@ int nr_adjust_synch_ue(NR_DL_FRAME_PARMS *frame_parms, void nr_ue_measurements(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, - NR_UE_DLSCH_t *dlsch, + int number_rbs, uint32_t pdsch_est_size, int32_t dl_ch_estimates[][pdsch_est_size]); @@ -142,15 +137,13 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t nr_slot_rx, unsigned char symbol, - uint32_t nb_re_pdsch, uint16_t rnti, NR_UE_DLSCH_t dlsch[2]); -float_t get_nr_RSRP(module_id_t Mod_id,uint8_t CC_id,uint8_t gNB_index); - int nr_sl_psbch_rsrp_measurements(sl_nr_ue_phy_params_t *sl_phy_params, NR_DL_FRAME_PARMS *fp, c16_t rxdataF[][fp->samples_per_slot_wCP], - bool use_SSS); + bool use_SSS, + openair0_config_t *openair0_cfg); /** @}*/ #endif diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index b6aeba7f76..36b8d8a673 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -37,46 +37,18 @@ #include "PHY/phy_extern_nr_ue.h" #include "common/utils/LOG/log.h" #include "PHY/sse_intrin.h" +#include "SCHED_NR_UE/defs.h" -//#define k1 1000 -#define k1 ((long long int) 1000) -#define k2 ((long long int) (1024-k1)) +#define K1 ((long long int) 512) +#define K2 ((long long int) (1024-K1)) //#define DEBUG_MEAS_RRC //#define DEBUG_MEAS_UE //#define DEBUG_RANK_EST -uint32_t get_nr_rx_total_gain_dB (module_id_t Mod_id,uint8_t CC_id) -{ - - PHY_VARS_NR_UE *ue = PHY_vars_UE_g[Mod_id][CC_id]; - - if (ue) - return ue->rx_total_gain_dB; - - return 0xFFFFFFFF; -} - - -float_t get_nr_RSRP(module_id_t Mod_id,uint8_t CC_id,uint8_t gNB_index) -{ - - AssertFatal(PHY_vars_UE_g!=NULL,"PHY_vars_UE_g is null\n"); - AssertFatal(PHY_vars_UE_g[Mod_id]!=NULL,"PHY_vars_UE_g[%d] is null\n",Mod_id); - AssertFatal(PHY_vars_UE_g[Mod_id][CC_id]!=NULL,"PHY_vars_UE_g[%d][%d] is null\n",Mod_id,CC_id); - - PHY_VARS_NR_UE *ue = PHY_vars_UE_g[Mod_id][CC_id]; - - if (ue) - return (10*log10(ue->measurements.rsrp[gNB_index])- - get_nr_rx_total_gain_dB(Mod_id,0) - - 10*log10(20*12)); - return -140.0; -} - void nr_ue_measurements(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, - NR_UE_DLSCH_t *dlsch, + int number_rbs, uint32_t pdsch_est_size, int32_t dl_ch_estimates[][pdsch_est_size]) { @@ -84,8 +56,6 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, int aarx, aatx, gNB_id = 0; NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; int ch_offset = frame_parms->ofdm_symbol_size*2; - int N_RB_DL = dlsch->dlsch_config.number_rbs; - ue->measurements.nb_antennas_rx = frame_parms->nb_antennas_rx; allocCast3D(rx_spatial_power, @@ -113,7 +83,7 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, ue->measurements.rx_power[gNB_id][aarx] = 0; for (aatx = 0; aatx < frame_parms->nb_antenna_ports_gNB; aatx++){ - const int z=signal_energy_nodc((c16_t*)&dl_ch_estimates[gNB_id][ch_offset], N_RB_DL * NR_NB_SC_PER_RB); + const int z = signal_energy_nodc((c16_t*)&dl_ch_estimates[gNB_id][ch_offset], number_rbs * NR_NB_SC_PER_RB); rx_spatial_power[gNB_id][aatx][aarx] = z; if (rx_spatial_power[gNB_id][aatx][aarx] < 0) @@ -136,11 +106,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, if (ue->init_averaging == 0) { for (gNB_id = 0; gNB_id < ue->n_connected_gNB; gNB_id++) - ue->measurements.rx_power_avg[gNB_id] = (int)(((k1*((long long int)(ue->measurements.rx_power_avg[gNB_id]))) + (k2*((long long int)(ue->measurements.rx_power_tot[gNB_id])))) >> 10); + ue->measurements.rx_power_avg[gNB_id] = (int)((K1 * ue->measurements.rx_power_avg[gNB_id] + K2 * ue->measurements.rx_power_tot[gNB_id]) >> 10); - ue->measurements.n0_power_avg = (int)(((k1*((long long int) (ue->measurements.n0_power_avg))) + (k2*((long long int) (ue->measurements.n0_power_tot))))>>10); + ue->measurements.n0_power_avg = (int)((K1 * ue->measurements.n0_power_avg + K2 * ue->measurements.n0_power_tot) >> 10); - LOG_D(PHY, "Noise Power Computation: k1 %lld k2 %lld n0 avg %u n0 tot %u\n", k1, k2, ue->measurements.n0_power_avg, ue->measurements.n0_power_tot); + LOG_D(PHY, "Noise Power Computation: K1 %lld K2 %lld n0 avg %u n0 tot %u\n", K1, K2, ue->measurements.n0_power_avg, ue->measurements.n0_power_tot); } else { @@ -157,7 +127,9 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, ue->measurements.rx_power_avg_dB[gNB_id] = dB_fixed( ue->measurements.rx_power_avg[gNB_id]); ue->measurements.wideband_cqi_tot[gNB_id] = ue->measurements.rx_power_tot_dB[gNB_id] - ue->measurements.n0_power_tot_dB; ue->measurements.wideband_cqi_avg[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] - dB_fixed(ue->measurements.n0_power_avg); - ue->measurements.rx_rssi_dBm[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] + 30 - SQ15_SQUARED_NORM_FACTOR_DB - ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(ue->frame_parms.ofdm_symbol_size); + ue->measurements.rx_rssi_dBm[gNB_id] = ue->measurements.rx_power_avg_dB[gNB_id] + 30 - SQ15_SQUARED_NORM_FACTOR_DB + - ((int)ue->openair0_cfg[0].rx_gain[0] - (int)ue->openair0_cfg[0].rx_gain_offset[0]) + - dB_fixed(ue->frame_parms.ofdm_symbol_size); LOG_D(PHY, "[gNB %d] Slot %d, RSSI %d dB (%d dBm/RE), WBandCQI %d dB, rxPwrAvg %d, n0PwrAvg %d\n", gNB_id, @@ -235,7 +207,7 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier); float rsrp_db_per_re = 10 * log10(rsrp_avg); - openair0_config_t *cfg0 = &openair0_cfg[0]; + openair0_config_t *cfg0 = &ue->openair0_cfg[0]; ue->measurements.ssb_rsrp_dBm[ssb_index] = rsrp_db_per_re + 30 - SQ15_SQUARED_NORM_FACTOR_DB - ((int)cfg0->rx_gain[0] - (int)cfg0->rx_gain_offset[0]) @@ -253,6 +225,24 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, ue->measurements.ssb_rsrp_dBm[ssb_index], rsrp_db_per_re, ue->measurements.ssb_sinr_dB[ssb_index]); + + // Send SS measurements to MAC + if (!ue->if_inst || !ue->if_inst->dl_indication) + return; + + fapi_nr_l1_measurements_t l1_measurements = { + .gNB_index = proc->gNB_id, + .meas_type = NFAPI_NR_SS_MEAS, + .Nid_cell = ue->frame_parms.Nid_cell, + .rsrp_dBm = ue->measurements.ssb_rsrp_dBm[ssb_index], + .ssb_index = ssb_index, + .is_neighboring_cell = false, + }; + nr_downlink_indication_t dl_indication = {0}; + fapi_nr_rx_indication_t rx_ind = {0}; + nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL); + nr_fill_rx_indication(&rx_ind, FAPI_NR_MEAS_IND, ue, NULL, NULL, 1, proc, &l1_measurements, NULL); + ue->if_inst->dl_indication(&dl_indication); } // This function computes the received noise power @@ -271,8 +261,8 @@ void nr_ue_rrc_measurements(PHY_VARS_NR_UE *ue, const uint8_t k_length = 8; uint8_t l_sss = (ue->symbol_offset + 2) % ue->frame_parms.symbols_per_slot; unsigned int ssb_offset = ue->frame_parms.first_carrier_offset + ue->frame_parms.ssb_start_subcarrier; - double rx_gain = openair0_cfg[0].rx_gain[0]; - double rx_gain_offset = openair0_cfg[0].rx_gain_offset[0]; + double rx_gain = ue->openair0_cfg[0].rx_gain[0]; + double rx_gain_offset = ue->openair0_cfg[0].rx_gain_offset[0]; ue->measurements.n0_power_tot = 0; @@ -344,7 +334,8 @@ void nr_ue_rrc_measurements(PHY_VARS_NR_UE *ue, int nr_sl_psbch_rsrp_measurements(sl_nr_ue_phy_params_t *sl_phy_params, NR_DL_FRAME_PARMS *fp, c16_t rxdataF[][fp->samples_per_slot_wCP], - bool use_SSS) + bool use_SSS, + openair0_config_t *openair0_cfg) { SL_NR_UE_PSBCH_t *psbch_rx = &sl_phy_params->psbch; uint8_t numsym = (fp->Ncp) ? SL_NR_NUM_SYMBOLS_SSB_EXT_CP : SL_NR_NUM_SYMBOLS_SSB_NORMAL_CP; diff --git a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c index 33ba3e0829..c28830e4d7 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/csi_rx.c @@ -238,7 +238,7 @@ static int nr_get_csi_rs_signal(const PHY_VARS_NR_UE *ue, *rsrp = rsrp_sum/meas_count; *rsrp_dBm = dB_fixed(*rsrp) + 30 - SQ15_SQUARED_NORM_FACTOR_DB - - ((int)openair0_cfg[0].rx_gain[0] - (int)openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(ue->frame_parms.ofdm_symbol_size); + - ((int)ue->openair0_cfg[0].rx_gain[0] - (int)ue->openair0_cfg[0].rx_gain_offset[0]) - dB_fixed(ue->frame_parms.ofdm_symbol_size); #ifdef NR_CSIRS_DEBUG LOG_I(NR_PHY, "RSRP = %i (%i dBm)\n", *rsrp, *rsrp_dBm); @@ -592,7 +592,33 @@ int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue, // The first column is applicable if the UE is reporting a Rank = 1, whereas the second column is applicable if the // UE is reporting a Rank = 2. - if(N_ports == 1 || interference_plus_noise_power == 0) { + if (interference_plus_noise_power == 0) { + return 0; + } + + if (N_ports == 1) { + // SISO case: SINR = E[|h|^2] / noise_power. No PMI to estimate. + int64_t signal_power = 0; + int count = 0; + + for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb + csirs_config_pdu->nr_of_rbs); rb++) { + if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) { + continue; + } + uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; + uint16_t k_offset = k + mem_offset; + + const c16_t h = csi_rs_estimated_channel_freq[0][0][k_offset]; + signal_power += (int64_t)h.r * h.r + (int64_t)h.i * h.i; + count++; + } + + if (count > 0) { + const int64_t avg_signal_power = signal_power / count; + const uint32_t sinr = avg_signal_power / interference_plus_noise_power; + *precoded_sinr_dB = dB_fixed(sinr); + } + return 0; } @@ -756,6 +782,8 @@ static void nr_csi_im_power_estimation(const PHY_VARS_NR_UE *ue, LOG_I(NR_PHY, "(ant_rx %i, sc %i) real %i, imag %i\n", ant_rx, sc, rx_signal[sc].r, rx_signal[sc].i); #endif + if (sc == 0) // skip DC for noise power estimation + continue; sum_re += rx_signal[sc].r; sum_im += rx_signal[sc].i; sum2_re += rx_signal[sc].r * rx_signal[sc].r; @@ -951,18 +979,24 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue, } // Send CSI measurements to MAC - fapi_nr_csirs_measurements_t csirs_measurements; - csirs_measurements.rsrp = rsrp; - csirs_measurements.rsrp_dBm = rsrp_dBm; - csirs_measurements.rank_indicator = rank_indicator; - csirs_measurements.i1 = *i1; - csirs_measurements.i2 = *i2; - csirs_measurements.cqi = cqi; - csirs_measurements.radiolink_monitoring = RLM_no_monitoring; // TODO do be activated in case of RLM based on CSI-RS + if (!ue->if_inst || !ue->if_inst->dl_indication) + return; + + fapi_nr_l1_measurements_t l1_measurements = { + .gNB_index = proc->gNB_id, + .meas_type = NFAPI_NR_CSI_MEAS, + .Nid_cell = frame_parms->Nid_cell, + .is_neighboring_cell = false, + .rsrp_dBm = rsrp_dBm, + .rank_indicator = rank_indicator, + .i1 = *i1, + .i2 = *i2, + .cqi = cqi, + .radiolink_monitoring = RLM_no_monitoring, // TODO do be activated in case of RLM based on CSI-RS + }; nr_downlink_indication_t dl_indication; fapi_nr_rx_indication_t rx_ind = {0}; nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL); - nr_fill_rx_indication(&rx_ind, FAPI_NR_CSIRS_IND, ue, NULL, NULL, 1, proc, (void *)&csirs_measurements, NULL); - if (ue->if_inst && ue->if_inst->dl_indication) - ue->if_inst->dl_indication(&dl_indication); + nr_fill_rx_indication(&rx_ind, FAPI_NR_MEAS_IND, ue, NULL, NULL, 1, proc, (void *)&l1_measurements, NULL); + ue->if_inst->dl_indication(&dl_indication); } diff --git a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c index a027b042ca..43b27e3932 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/dci_nr.c @@ -36,6 +36,7 @@ #include "PHY/CODING/nrPolar_tools/nr_polar_dci_defs.h" #include "PHY/phy_extern.h" #include "PHY/CODING/coding_extern.h" +#include "PHY/nr_phy_common/inc/nr_phy_common.h" #include "PHY/sse_intrin.h" #include "common/utils/nr/nr_common.h" #include @@ -44,9 +45,7 @@ #include "assertions.h" #include "T.h" -//#define DEBUG_DCI_DECODING 1 - -//#define NR_PDCCH_DCI_DEBUG // activates NR_PDCCH_DCI_DEBUG logs +// #define NR_PDCCH_DCI_DEBUG // activates NR_PDCCH_DCI_DEBUG logs #ifdef NR_PDCCH_DCI_DEBUG #define LOG_DDD(a, ...) printf("<-NR_PDCCH_DCI_DEBUG (%s)-> " a, __func__, ##__VA_ARGS__ ) #define LOG_DSYMB(b) \ @@ -63,20 +62,19 @@ #define LOG_DDD(a...) #define LOG_DSYMB(a...) #endif + #define NR_NBR_CORESET_ACT_BWP 3 // The number of CoreSets per BWP is limited to 3 (including initial CORESET: ControlResourceId 0) #define NR_NBR_SEARCHSPACE_ACT_BWP \ 10 // The number of SearSpaces per BWP is limited to 10 (including initial SEARCHSPACE: SearchSpaceId 0) -#ifdef LOG_I -#undef LOG_I -#define LOG_I(A, B...) printf(B) -#endif +#define RE_PER_RB 12 +// after removing the 3 DMRS RE, the RB contains 9 RE with PDCCH +#define RE_PER_RB_OUT_DMRS 9 -static void nr_pdcch_demapping_deinterleaving(c16_t *llr, +static void nr_pdcch_demapping_deinterleaving(uint32_t coreset_nbr_rb, + c16_t llr[][coreset_nbr_rb * RE_PER_RB_OUT_DMRS], c16_t *e_rx, uint8_t coreset_time_dur, - uint8_t start_symbol, - uint32_t coreset_nbr_rb, uint8_t reg_bundle_size_L, uint8_t coreset_interleaver_size_R, uint8_t n_shift, @@ -170,15 +168,14 @@ static void nr_pdcch_demapping_deinterleaving(c16_t *llr, } int rb_count = 0; - const int data_sc = 9; // 9 sub-carriers with data per PRB for (int c_id = 0; c_id < number_of_candidates; c_id++) { - for (int symbol_idx = start_symbol; symbol_idx < start_symbol + coreset_time_dur; symbol_idx++) { + for (int symbol_idx = 0; symbol_idx < coreset_time_dur; symbol_idx++) { for (int cce_count = 0; cce_count < L[c_id]; cce_count++) { for (int k = 0; k < NR_NB_REG_PER_CCE / reg_bundle_size_L; k++) { // loop over REG bundles int f = f_bundle_j_list_ord[c_id][k + NR_NB_REG_PER_CCE * cce_count / reg_bundle_size_L]; - c16_t *in = llr + (f * B_rb + symbol_idx * coreset_nbr_rb) * data_sc; + c16_t *in = llr[symbol_idx] + f * B_rb * RE_PER_RB_OUT_DMRS; // loop over the RBs of the bundle - memcpy(e_rx + data_sc * rb_count, in, B_rb * data_sc * sizeof(*e_rx)); + memcpy(e_rx + RE_PER_RB_OUT_DMRS * rb_count, in, B_rb * RE_PER_RB_OUT_DMRS * sizeof(*e_rx)); rb_count += B_rb; } } @@ -186,67 +183,33 @@ static void nr_pdcch_demapping_deinterleaving(c16_t *llr, } } -static void nr_pdcch_llr(NR_DL_FRAME_PARMS *frame_parms, - int32_t rx_size, - c16_t rxdataF_comp[][rx_size], - c16_t *pdcch_llr, - uint8_t symbol, - uint32_t coreset_nbr_rb) +static void nr_pdcch_llr(uint32_t sz, c16_t *rxF, c16_t *llr) { - c16_t *rxF = &rxdataF_comp[0][(symbol * coreset_nbr_rb * 12)]; - c16_t *pdcch_llrp = &pdcch_llr[symbol * coreset_nbr_rb * 9]; - - if (!pdcch_llrp) { - LOG_E(NR_PHY_DCI, "pdcch_qpsk_llr: llr is null, symbol %d\n", symbol); - return; - } - - LOG_DDD("llr logs: pdcch qpsk llr for symbol %d (pos %d), llr offset %ld\n",symbol,(symbol*frame_parms->N_RB_DL*12),pdcch_llrp-pdcch_llr); - - for (int i = 0; i < coreset_nbr_rb * 9; i++) { + for (int i = 0; i < sz; i++) { // We clip the signal c16_t res; res.r = min(rxF->r, 31); res.r = max(-32, res.r); res.i = min(rxF->i, 31); res.i = max(-32, res.i); - *pdcch_llrp = res; - LOG_DDD("llr logs: rb=%d i=%d *rxF:%d => *pdcch_llrp:%d\n",i/18,i,*rxF,*pdcch_llrp); + *llr++ = res; + LOG_DDD("llr logs: rb=%d i=%d rxF:%d,%d => pdcch_llr:%d,%d\n", i / 18, i, rxF->r, rxF->i, llr->r, llr->i); rxF++; - pdcch_llrp++; - } -} - -//compute average channel_level on each (TX,RX) antenna pair -void nr_pdcch_channel_level(int32_t rx_size, - c16_t dl_ch_estimates_ext[][rx_size], - NR_DL_FRAME_PARMS *frame_parms, - int32_t *avg, - int symbol, - int nb_rb) -{ - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - - simde__m128i *dl_ch128 = (simde__m128i *)&dl_ch_estimates_ext[aarx][symbol * nb_rb * 12]; - - //compute average level - avg[aarx] = simde_mm_average(dl_ch128, nb_rb * 12, 0, nb_rb * 12); - //LOG_DDD("Channel level : %d\n", avg[aarx]); } } // This function will extract the mapped DM-RS PDCCH REs as per 38.211 Section 7.4.1.3.2 (Mapping to physical resources) static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz, + uint32_t coreset_nbr_rb, c16_t rxdataF[][rxdataF_sz], int32_t est_size, c16_t dl_ch_estimates[][est_size], - int32_t rx_size, - c16_t rxdataF_ext[][rx_size], - c16_t dl_ch_estimates_ext[][rx_size], + int arraySz, + c16_t rxdataF_ext[][arraySz], + c16_t dl_ch_estimates_ext[][arraySz], int symbol, NR_DL_FRAME_PARMS *frame_parms, uint8_t *coreset_freq_dom, - uint32_t coreset_nbr_rb, uint32_t n_BWP_start) { /* @@ -260,19 +223,13 @@ static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz, * */ -#define NBR_RE_PER_RB_WITH_DMRS 12 - // after removing the 3 DMRS RE, the RB contains 9 RE with PDCCH -#define NBR_RE_PER_RB_WITHOUT_DMRS 9 for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { const c16_t *dl_ch0 = dl_ch_estimates[aarx] + frame_parms->ofdm_symbol_size * symbol; c16_t *rxFbase = rxdataF[aarx] + frame_parms->ofdm_symbol_size * symbol; LOG_DDD("dl_ch0 = &dl_ch_estimates[aarx = (%d)][0]\n", aarx); - const int offset = symbol * coreset_nbr_rb * NBR_RE_PER_RB_WITH_DMRS; - c16_t *dl_ch0_ext = &dl_ch_estimates_ext[aarx][offset]; - LOG_DDD("dl_ch0_ext = &dl_ch_estimates_ext[aarx = (%d)][symbol * (frame_parms->N_RB_DL * 9) = (%d)]\n", aarx, offset); - c16_t *rxF_ext = &rxdataF_ext[aarx][offset]; - LOG_DDD("rxF_ext = &rxdataF_ext[aarx = (%d)][symbol * (frame_parms->N_RB_DL * 9) = (%d)]\n", aarx, offset); + c16_t *dl_ch0_ext = dl_ch_estimates_ext[aarx]; + c16_t *rxF_ext = rxdataF_ext[aarx]; /* * The following for loop handles treatment of PDCCH contained in table rxdataF (in frequency domain) @@ -297,140 +254,67 @@ static void nr_pdcch_extract_rbs_single(uint32_t rxdataF_sz, int c_rb_by6 = c_rb / 6; // skip zeros in frequency domain bitmap - while ((coreset_freq_dom[c_rb_by6 >> 3] & (1 << (7 - (c_rb_by6 & 7)))) == 0) { + while ((coreset_freq_dom[c_rb_by6 / 8] & (1 << (7 - (c_rb_by6 & 7)))) == 0) { c_rb += 6; c_rb_by6 = c_rb / 6; } - - // first we set initial conditions for pointer to rxdataF depending on the situation of the first RB within the CORESET - // (c_rb = n_BWP_start) - if ((frame_parms->N_RB_DL & 1) == 1 && (c_rb + n_BWP_start) == (frame_parms->N_RB_DL >> 1)) { - // treatment of RB containing the DC - // if odd number RBs in system bandwidth and first RB to be treated is higher than middle system bandwidth (around DC) - // we have to treat the RB in two parts: first part from i=0 to 5, the data is at the end of rxdataF (pointing at the - // end of the table) - c16_t *rxF = rxFbase + frame_parms->first_carrier_offset + 12 * (c_rb + n_BWP_start); - - int i = 0, j = 0; - for (; i < 6; i++) { // treating first part of the RB note that i=5 would correspond to DC. We treat it in NR - if ((i != 1) && (i != 5)) { - dl_ch0_ext[j] = dl_ch0[i]; - rxF_ext[j] = rxF[i]; - LOG_DSYMB(""); - j++; - } else { - LOG_DSYMB("\t\t <==> DM-RS PDCCH, this is a pilot symbol\n"); - } - } - - // then we point at the begining of the symbol part of rxdataF do process second part of RB - for (; i < 12; i++) { - if ((i != 9)) { - dl_ch0_ext[j] = dl_ch0[i]; - rxF_ext[j] = rxFbase[i - 6]; - LOG_DSYMB(""); - j++; - } else { - LOG_DSYMB("\t\t <==> DM-RS PDCCH, this is a pilot symbol\n"); - } - } - - } else { // treatment of any RB that does not contain the DC - c16_t *rxF=NULL; - if ((frame_parms->N_RB_DL & 1) == 0) { - if ((c_rb + n_BWP_start) < (frame_parms->N_RB_DL >> 1)) - // if RB to be treated is lower than middle system bandwidth then rxdataF pointed - // at (offset + c_br + symbol * ofdm_symbol_size): even case - rxF = rxFbase + (frame_parms->first_carrier_offset + 12 * c_rb) + n_BWP_start * 12; - else - // number of RBs is even and c_rb is higher than half system bandwidth (we don't skip DC) - // if these conditions are true the pointer has to be situated at the 1st part of the rxdataF - // we point at the 1st part of the rxdataF in symbol - rxF = rxFbase + 12 * (c_rb + n_BWP_start - (frame_parms->N_RB_DL >> 1)); - } else { - if ((c_rb + n_BWP_start) < (frame_parms->N_RB_DL >> 1)) - // if RB to be treated is lower than middle system bandwidth then rxdataF pointed - // at (offset + c_br + symbol * ofdm_symbol_size): odd case - rxF = rxFbase + frame_parms->first_carrier_offset + 12 * (c_rb + n_BWP_start); - else if ((c_rb + n_BWP_start) > (frame_parms->N_RB_DL >> 1)) - // number of RBs is odd and c_rb is higher than half system bandwidth + 1 - // if these conditions are true the pointer has to be situated at the 1st part of - // the rxdataF just after the first IQ symbols of the RB containing DC - // we point at the 1st part of the rxdataF in symbol - rxF = rxFbase + 12 * (c_rb + n_BWP_start - (frame_parms->N_RB_DL >> 1)) - 6; - } - AssertFatal(rxF, "bug"); - int j = 0; - - for (int i = 0; i < 12; i++) { - if ((i != 1) && (i != 5) && (i != 9)) { - rxF_ext[j] = rxF[i]; - dl_ch0_ext[j] = dl_ch0[i]; - LOG_DSYMB(""); - j++; - } else { - LOG_DSYMB("\t\t <==> DM-RS PDCCH, this is a pilot symbol\n"); - } - } + c16_t *rxF = NULL; + if ((frame_parms->N_RB_DL & 1) == 0) { + if ((c_rb + n_BWP_start) < frame_parms->N_RB_DL / 2) + // if RB to be treated is lower than middle system bandwidth then rxdataF pointed + // at (offset + c_br + symbol * ofdm_symbol_size): even case + rxF = rxFbase + frame_parms->first_carrier_offset + RE_PER_RB * (c_rb + n_BWP_start); + else + // number of RBs is even and c_rb is higher than half system bandwidth (we don't skip DC) + // if these conditions are true the pointer has to be situated at the 1st part of the rxdataF + // we point at the 1st part of the rxdataF in symbol + rxF = rxFbase + RE_PER_RB * (c_rb + n_BWP_start - frame_parms->N_RB_DL / 2); + } else { + if ((c_rb + n_BWP_start) <= frame_parms->N_RB_DL / 2) + // if RB to be treated is lower than middle system bandwidth then rxdataF pointed + // at (offset + c_br + symbol * ofdm_symbol_size): odd case + rxF = rxFbase + frame_parms->first_carrier_offset + RE_PER_RB * (c_rb + n_BWP_start); + else + // number of RBs is odd and c_rb is higher than half system bandwidth + 1 + // if these conditions are true the pointer has to be situated at the 1st part of + // the rxdataF just after the first IQ symbols of the RB containing DC + // we point at the 1st part of the rxdataF in symbol + rxF = rxFbase + RE_PER_RB * (c_rb + n_BWP_start - frame_parms->N_RB_DL / 2) - 6; } - dl_ch0_ext += NBR_RE_PER_RB_WITHOUT_DMRS; - rxF_ext += NBR_RE_PER_RB_WITHOUT_DMRS; - dl_ch0 += 12; + const int valid_re[RE_PER_RB_OUT_DMRS] = {0, 2, 3, 4, 6, 7, 8, 10, 11}; + for (int i = 0; i < sizeofArray(valid_re); i++) { + *rxF_ext++ = rxF[valid_re[i]]; + *dl_ch0_ext++ = dl_ch0[valid_re[i]]; + } + dl_ch0 += RE_PER_RB; } } } -#define print_shorts(s,x) printf("%s %d,%d,%d,%d,%d,%d,%d,%d\n",s,(x)[0],(x)[1],(x)[2],(x)[3],(x)[4],(x)[5],(x)[6],(x)[7]) - -void nr_pdcch_channel_compensation(int32_t rx_size, - c16_t rxdataF_ext[][rx_size], - c16_t dl_ch_estimates_ext[][rx_size], - c16_t rxdataF_comp[][rx_size], - int32_t **rho, - NR_DL_FRAME_PARMS *frame_parms, - uint8_t symbol, - uint8_t output_shift, - uint32_t coreset_nbr_rb) +static void nr_pdcch_channel_compensation(int arraySz, + c16_t rxdataF_ext[][arraySz], + c16_t dl_ch_estimates_ext[][arraySz], + c16_t rxdataF_comp[][arraySz], + int antRx, + uint8_t output_shift) { - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - simde__m128i *dl_ch128 = (simde__m128i *)&dl_ch_estimates_ext[aarx][symbol * coreset_nbr_rb * 12]; - simde__m128i *rxdataF128 = (simde__m128i *)&rxdataF_ext[aarx][symbol * coreset_nbr_rb * 12]; - simde__m128i *rxdataF_comp128 = (simde__m128i *)&rxdataF_comp[aarx][symbol * coreset_nbr_rb * 12]; - //printf("ch compensation dl_ch ext addr %p \n", &dl_ch_estimates_ext[(aatx<<1)+aarx][symbol*20*12]); - //printf("rxdataf ext addr %p symbol %d\n", &rxdataF_ext[aarx][symbol*20*12], symbol); - //printf("rxdataf_comp addr %p\n",&rxdataF_comp[(aatx<<1)+aarx][symbol*20*12]); - - // multiply by conjugated channel - mult_cpx_conj_vector((c16_t *)dl_ch128, (c16_t *)rxdataF128, (c16_t *)rxdataF_comp128, 12 * coreset_nbr_rb, output_shift); - - for (int rb = 0; rb < 12 * coreset_nbr_rb; rb++) { - LOG_DDD("rxdataF128[%d]=(%d,%d) X dlch[%d]=(%d,%d) rxdataF_comp128[%d]=(%d,%d)\n", - rb, - ((c16_t *)rxdataF128)[rb].r, - ((c16_t *)rxdataF128)[rb].i, - rb, - ((c16_t *)dl_ch128)[rb].r, - ((c16_t *)dl_ch128)[rb].i, - rb, - ((c16_t *)rxdataF_comp128)[rb].r, - ((c16_t *)rxdataF_comp128)[rb].i); - - } + for (int aarx = 0; aarx < antRx; aarx++) { + // multiply by conjugated channel, this function require size in _m128i, else it doesn't process all samples + mult_cpx_conj_vector(dl_ch_estimates_ext[aarx], rxdataF_ext[aarx], rxdataF_comp[aarx], arraySz, output_shift); } } -static void nr_pdcch_detection_mrc(NR_DL_FRAME_PARMS *frame_parms, int32_t rx_size, c16_t rxdataF_comp[][rx_size], int symbol) +static void nr_pdcch_detection_mrc(int sz, c16_t rxdataF_comp[][sz]) { - if (frame_parms->nb_antennas_rx>1) { - const int sz = frame_parms->N_RB_DL * 12; - - simde__m128i *rxdataF_comp128_0 = (simde__m128i *)&rxdataF_comp[0][symbol * sz]; - simde__m128i *rxdataF_comp128_1 = (simde__m128i *)&rxdataF_comp[1][symbol * sz]; + LOG_D(NR_PHY_DCI, "we enter nr_pdcch_detection_mrc (hard coded 2 antennas)\n"); + c16_t *rx0 = rxdataF_comp[0]; + c16_t *rx1 = rxdataF_comp[1]; - // MRC on each re of rb - for (int i = 0; i < sz >> 2; i++) { - rxdataF_comp128_0[i] = simde_mm_adds_epi16(simde_mm_srai_epi16(rxdataF_comp128_0[i], 1), simde_mm_srai_epi16(rxdataF_comp128_1[i], 1)); - } + // MRC on each re of rb + // input always aligned and accepting tail padding to process all actual samples + for (int i = 0; i < sz; i += 4) { + *(simde__m128i *)(rx0 + i) = + simde_mm_adds_epi16(simde_mm_srai_epi16(*(simde__m128i *)(rx0 + i), 1), simde_mm_srai_epi16(*(simde__m128i *)(rx1 + i), 1)); } } @@ -444,112 +328,76 @@ void nr_rx_pdcch(PHY_VARS_NR_UE *ue, { NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; - uint8_t log2_maxh, aarx; - int32_t avgs; - int32_t avgP[4]; int n_rb,rb_offset; get_coreset_rballoc(rel15->coreset.frequency_domain_resource,&n_rb,&rb_offset); + const int antRx = frame_parms->nb_antennas_rx; - // Pointers to extracted PDCCH symbols in frequency-domain. - int32_t rx_size = ((4 * frame_parms->N_RB_DL * 12 + 31) >> 5) << 5; - __attribute__((aligned(32))) c16_t rxdataF_ext[frame_parms->nb_antennas_rx][rx_size]; - __attribute__((aligned(32))) c16_t rxdataF_comp[frame_parms->nb_antennas_rx][rx_size]; - __attribute__((aligned(32))) c16_t pdcch_dl_ch_estimates_ext[frame_parms->nb_antennas_rx][rx_size]; - - memset(rxdataF_comp, 0, sizeof(rxdataF_comp)); - - // Pointer to llrs, 4-bit resolution. - int32_t llr_size = 4 * n_rb * 9; - c16_t llr[llr_size]; - - memset(llr, 0, sizeof(llr)); + // Pointer to llrs + const int symb_size = n_rb * RE_PER_RB_OUT_DMRS; + c16_t llr[rel15->coreset.duration][symb_size]; LOG_D(NR_PHY_DCI, "pdcch coreset: freq %x, n_rb %d, rb_offset %d\n", rel15->coreset.frequency_domain_resource[0], n_rb, rb_offset); - for (int s=rel15->coreset.StartSymbolIndex; s<(rel15->coreset.StartSymbolIndex+rel15->coreset.duration); s++) { + for (int s = 0; s < rel15->coreset.duration; s++) { LOG_D(NR_PHY_DCI, "in nr_pdcch_extract_rbs_single(rxdataF -> rxdataF_ext || dl_ch_estimates -> dl_ch_estimates_ext)\n"); - + const int arraySz = ceil_mod(symb_size, 32); + __attribute__((aligned(32))) c16_t rxdataF_ext[antRx][arraySz]; + __attribute__((aligned(32))) c16_t pdcch_dl_ch_estimates_ext[antRx][arraySz]; nr_pdcch_extract_rbs_single(ue->frame_parms.samples_per_slot_wCP, + n_rb, rxdataF, pdcch_est_size, pdcch_dl_ch_estimates, - rx_size, + arraySz, rxdataF_ext, pdcch_dl_ch_estimates_ext, - s, + rel15->coreset.StartSymbolIndex + s, frame_parms, rel15->coreset.frequency_domain_resource, - n_rb, rel15->BWPStart); - LOG_D(NR_PHY_DCI, - "we enter nr_pdcch_channel_level(avgP=%d) => compute channel level based on ofdm symbol 0, " - "pdcch_vars[eNB_id]->dl_ch_estimates_ext\n", - *avgP); - LOG_D(NR_PHY_DCI, "in nr_pdcch_channel_level(dl_ch_estimates_ext -> dl_ch_estimates_ext)\n"); + LOG_D(NR_PHY_DCI, "in channel level function (dl_ch_estimates_ext -> dl_ch_estimates_ext)\n"); // compute channel level based on ofdm symbol 0 - nr_pdcch_channel_level(rx_size, - pdcch_dl_ch_estimates_ext, - frame_parms, - avgP, - s, - n_rb); - avgs = 0; - - for (aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) - avgs = cmax(avgs, avgP[aarx]); - - log2_maxh = (log2_approx(avgs) / 2) + 5; //+frame_parms->nb_antennas_rx; + int avg[antRx]; + nr_channel_level(0, arraySz, pdcch_dl_ch_estimates_ext, antRx, 1, avg, n_rb); + int avgs = avg[0]; + for (int i = 1; i < antRx; i++) + avgs = cmax(avgs, avg[i]); + uint8_t log2_maxh = (log2_approx(avgs) / 2) + 5; //+antRx; #ifdef UE_DEBUG_TRACE LOG_D(NR_PHY_DCI, "slot %d: pdcch log2_maxh = %d (%d,%d)\n", proc->nr_slot_rx, log2_maxh, avgP[0], avgs); #endif #if T_TRACER - T(T_UE_PHY_PDCCH_ENERGY, T_INT(0), T_INT(0), T_INT(proc->frame_rx % 1024), T_INT(proc->nr_slot_rx), T_INT(avgP[0]), T_INT(avgP[1]), T_INT(avgP[2]), T_INT(avgP[3])); + T(T_UE_PHY_PDCCH_ENERGY, T_INT(0), T_INT(0), T_INT(proc->frame_rx % 1024), T_INT(proc->nr_slot_rx), T_INT(avgs)); #endif LOG_D(NR_PHY_DCI, "we enter nr_pdcch_channel_compensation(log2_maxh=%d)\n", log2_maxh); LOG_D(NR_PHY_DCI, "in nr_pdcch_channel_compensation(rxdataF_ext x dl_ch_estimates_ext -> rxdataF_comp)\n"); // compute LLRs for ofdm symbol 0 only - nr_pdcch_channel_compensation(rx_size, rxdataF_ext, + __attribute__((aligned(32))) c16_t rxdataF_comp[antRx][arraySz]; + nr_pdcch_channel_compensation(arraySz, + rxdataF_ext, pdcch_dl_ch_estimates_ext, rxdataF_comp, - NULL, - frame_parms, - s, - log2_maxh, - n_rb); // log2_maxh+I0_shift + antRx, + log2_maxh); // log2_maxh+I0_shift - UEscopeCopy(ue, pdcchRxdataF_comp, rxdataF_comp, sizeof(struct complex16), frame_parms->nb_antennas_rx, rx_size, 0); + UEscopeCopy(ue, pdcchRxdataF_comp, rxdataF_comp, sizeof(struct complex16), antRx, symb_size, 0); - if (frame_parms->nb_antennas_rx > 1) { - LOG_D(NR_PHY_DCI, "we enter nr_pdcch_detection_mrc(frame_parms->nb_antennas_rx=%d)\n", frame_parms->nb_antennas_rx); - nr_pdcch_detection_mrc(frame_parms, rx_size, rxdataF_comp,s); - } + if (antRx > 1) + nr_pdcch_detection_mrc(arraySz, rxdataF_comp); - LOG_D(NR_PHY_DCI, "we enter nr_pdcch_llr(for symbol %d), pdcch_vars[eNB_id]->rxdataF_comp ---> pdcch_vars[eNB_id]->llr \n", s); - LOG_D(NR_PHY_DCI, "in nr_pdcch_llr(rxdataF_comp -> llr)\n"); - nr_pdcch_llr(frame_parms, - rx_size, - rxdataF_comp, - llr, - s, - n_rb); - - UEscopeCopy(ue, pdcchLlr, llr, sizeof(c16_t), 1, llr_size, 0); - -#ifdef DEBUG_DCI_DECODING - printf("demapping: slot %u, mi %d\n",slot,get_mi(frame_parms,slot)); -#endif + nr_pdcch_llr(symb_size, rxdataF_comp[0], llr[s]); } + UEscopeCopy(ue, pdcchLlr, llr, sizeof(c16_t), 1, rel15->coreset.duration * symb_size, 0); - nr_pdcch_demapping_deinterleaving(llr, + nr_pdcch_demapping_deinterleaving(n_rb, + llr, pdcch_e_rx, rel15->coreset.duration, - rel15->coreset.StartSymbolIndex, - n_rb, rel15->coreset.RegBundleSize, rel15->coreset.InterleaverSize, rel15->coreset.ShiftIndex, @@ -668,6 +516,6 @@ void nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, rel15->dci_format_options[k]); } } - e_rx_cand_idx += 9 * L * 6; // e_rx index for next candidate (L CCEs, 6 REGs per CCE and 9 REs per REG ) + e_rx_cand_idx += RE_PER_RB_OUT_DMRS * L * 6; // e_rx index for next candidate (L CCEs, 6 REGs per CCE and 9 REs per REG ) } } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index d266d443e9..5e677b542b 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -80,11 +80,11 @@ unsigned char offset_mumimo_llr_drange[29][3]={{8,8,8},{7,7,7},{7,7,7},{7,7,7},{ /* compute the MMSE up to 4x4 matrices */ static void nr_dlsch_mmse(uint32_t rx_size_symbol, unsigned char n_rx, - unsigned char n_tx, // number of layer + unsigned char nl, // number of layer int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], - int32_t dl_ch_mag[][n_rx][rx_size_symbol], - int32_t dl_ch_magb[][n_rx][rx_size_symbol], - int32_t dl_ch_magr[][n_rx][rx_size_symbol], + c16_t dl_ch_mag[][n_rx][rx_size_symbol], + c16_t dl_ch_magb[][n_rx][rx_size_symbol], + c16_t dl_ch_magr[][n_rx][rx_size_symbol], int32_t dl_ch_estimates_ext[][rx_size_symbol], unsigned short nb_rb, unsigned char mod_order, @@ -109,9 +109,9 @@ static void nr_dlsch_llr(uint32_t rx_size_symbol, uint sz, int16_t layer_llr[][sz], int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], - int32_t dl_ch_mag[rx_size_symbol], - int32_t dl_ch_magb[rx_size_symbol], - int32_t dl_ch_magr[rx_size_symbol], + c16_t dl_ch_mag[rx_size_symbol], + c16_t dl_ch_magb[rx_size_symbol], + c16_t dl_ch_magr[rx_size_symbol], NR_DL_UE_HARQ_t *dlsch0_harq, NR_DL_UE_HARQ_t *dlsch1_harq, unsigned char symbol, @@ -141,11 +141,11 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz, unsigned char symbol, uint8_t pilots, uint8_t config_type, - unsigned short start_rb, - unsigned short nb_rb_pdsch, + int startBWP, + const freq_alloc_bitmap_t *freq_alloc, uint8_t n_dmrs_cdm_groups, uint8_t Nl, - NR_DL_FRAME_PARMS *frame_parms, + NR_DL_FRAME_PARMS *fp, uint16_t dlDmrsSymbPos, uint32_t csi_res_bitmap, int chest_time_type); @@ -178,9 +178,9 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol, int nbRx, c16_t rxdataF_ext[][rx_size_symbol], int32_t dl_ch_estimates_ext[][rx_size_symbol], - int32_t dl_ch_mag[][nbRx][rx_size_symbol], - int32_t dl_ch_magb[][nbRx][rx_size_symbol], - int32_t dl_ch_magr[][nbRx][rx_size_symbol], + c16_t dl_ch_mag[][nbRx][rx_size_symbol], + c16_t dl_ch_magb[][nbRx][rx_size_symbol], + c16_t dl_ch_magr[][nbRx][rx_size_symbol], int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], int ***rho, NR_DL_FRAME_PARMS *frame_parms, @@ -193,37 +193,14 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol, unsigned char output_shift, PHY_NR_MEASUREMENTS *measurements); -/** \brief This function computes the average channel level over all allocated RBs and antennas (TX/RX) in order to compute output shift for compensated signal - @param dl_ch_estimates_ext Channel estimates in allocated RBs - @param frame_parms Pointer to frame descriptor - @param avg Pointer to average signal strength - @param pilots_flag Flag to indicate pilots in symbol - @param nb_rb Number of allocated RBs -*/ -static void nr_dlsch_channel_level(uint32_t rx_size_symbol, - int32_t dl_ch_estimates_ext[][rx_size_symbol], - uint8_t n_rx, - uint8_t n_tx, - int32_t avg[MAX_ANT][MAX_ANT], - uint32_t len); - -void nr_dlsch_scale_channel(uint32_t rx_size_symbol, - int32_t dl_ch_estimates_ext[][rx_size_symbol], - NR_DL_FRAME_PARMS *frame_parms, - uint8_t n_tx, - uint8_t n_rx, - uint8_t symbol, - uint8_t pilots, - uint32_t len, - unsigned short nb_rb); static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, - short n_tx, + short nl, short n_rx, int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], int ***rho, - int32_t dl_ch_mag[][n_rx][rx_size_symbol], - int32_t dl_ch_magb[][n_rx][rx_size_symbol], - int32_t dl_ch_magr[][n_rx][rx_size_symbol], + c16_t dl_ch_mag[][n_rx][rx_size_symbol], + c16_t dl_ch_magb[][n_rx][rx_size_symbol], + c16_t dl_ch_magr[][n_rx][rx_size_symbol], unsigned char symbol, int length); @@ -307,11 +284,14 @@ static uint32_t build_csi_overlap_bitmap(fapi_nr_dl_config_dlsch_pdu_rel15_t *dl int nr_rx_pdsch(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, NR_UE_DLSCH_t dlsch[2], + const freq_alloc_bitmap_t *freq_alloc, unsigned char symbol, bool first_symbol_flag, unsigned char harq_pid, uint32_t pdsch_est_size, int32_t dl_ch_estimates[][pdsch_est_size], + int layer_llr_size, + int16_t layer_llr[][layer_llr_size], int16_t *llr[2], uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT], c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP], @@ -326,21 +306,22 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, uint32_t nvar, pdsch_scope_req_t *scope_req) { + NR_DL_FRAME_PARMS *fp = &ue->frame_parms; const int nl = dlsch[0].Nl; - const int matrixSz = ue->frame_parms.nb_antennas_rx * nl; + const int n_rx = fp->nb_antennas_rx; + const int matrixSz = n_rx * nl; __attribute__((aligned(32))) int32_t dl_ch_estimates_ext[matrixSz][rx_size_symbol]; memset(dl_ch_estimates_ext, 0, sizeof(dl_ch_estimates_ext)); - __attribute__((aligned(32))) int32_t dl_ch_mag[nl][ue->frame_parms.nb_antennas_rx][rx_size_symbol]; + __attribute__((aligned(32))) c16_t dl_ch_mag[nl][n_rx][rx_size_symbol]; memset(dl_ch_mag, 0, sizeof(dl_ch_mag)); - __attribute__((aligned(32))) int32_t dl_ch_magb[nl][nbRx][rx_size_symbol]; + __attribute__((aligned(32))) c16_t dl_ch_magb[nl][nbRx][rx_size_symbol]; memset(dl_ch_magb, 0, sizeof(dl_ch_magb)); - __attribute__((aligned(32))) int32_t dl_ch_magr[nl][nbRx][rx_size_symbol]; + __attribute__((aligned(32))) c16_t dl_ch_magr[nl][nbRx][rx_size_symbol]; memset(dl_ch_magr, 0, sizeof(dl_ch_magr)); NR_UE_COMMON *common_vars = &ue->common_vars; - NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; PHY_NR_MEASUREMENTS *measurements = &ue->measurements; const int frame = proc->frame_rx; const int nr_slot_rx = proc->nr_slot_rx; @@ -359,7 +340,14 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, if (dlsch0_harq && dlsch1_harq){ - LOG_D(PHY,"AbsSubframe %d.%d / Sym %d harq_pid %d, harq status %d.%d \n", frame, nr_slot_rx, symbol, harq_pid, dlsch0_harq->status, dlsch1_harq->status); + LOG_D(PHY, + "AbsSubframe %d.%d / Sym %d harq_pid %d, harq status %d.%d \n", + frame, + nr_slot_rx, + symbol, + harq_pid, + dlsch0_harq->status, + dlsch1_harq->status); if ((dlsch0_harq->status == ACTIVE) && (dlsch1_harq->status == ACTIVE)){ codeword_TB0 = dlsch0_harq->codeword; // SV: where is this set? revisit for DL MIMO. @@ -405,13 +393,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, DEBUG_HARQ("[DEMOD] cw for TB0 = %d, cw for TB1 = %d\n", codeword_TB0, codeword_TB1); fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config = &dlsch[0].dlsch_config; - int start_rb = dlsch_config->start_rb; - int nb_rb_pdsch = dlsch_config->number_rbs; - DevAssert(dlsch0_harq); if (gNB_id > 2) { - LOG_E(PHY, "In %s: Illegal gNB_id %d\n", __FUNCTION__, gNB_id); + LOG_E(PHY, "Illegal gNB_id %d\n", gNB_id); return(-1); } @@ -420,12 +405,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, return(-1); } - if (!frame_parms) { - LOG_E(PHY, "dlsch_demodulation.c: Null frame_parms\n"); - return(-1); - } - - if(symbol > ue->frame_parms.symbols_per_slot >> 1) + if(symbol > fp->symbols_per_slot >> 1) slot = 1; uint8_t pilots = (dlsch_config->dlDmrsSymbPos >> symbol) & 1; @@ -433,9 +413,8 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, //---------------------------------------------------------- //--------------------- RBs extraction --------------------- //---------------------------------------------------------- - const int n_rx = frame_parms->nb_antennas_rx; const bool meas_enabled = cpumeas(CPUMEAS_GETSTATE); - + int nb_rb_pdsch = freq_alloc->num_rbs; { start_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS); __attribute__((aligned(32))) c16_t rxdataF_ext[nbRx][rx_size_symbol]; @@ -445,7 +424,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, LOG_D(PHY, "%d.%d symbol %d csi overlap bitmap %d\n", frame, nr_slot_rx, symbol, csi_res_bitmap); - nr_dlsch_extract_rbs(ue->frame_parms.samples_per_slot_wCP, + nr_dlsch_extract_rbs(fp->samples_per_slot_wCP, rxdataF, rx_size_symbol, pdsch_est_size, @@ -455,17 +434,17 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, symbol, pilots, config_type, - start_rb + dlsch_config->BWPStart, - nb_rb_pdsch, + dlsch_config->BWPStart, + freq_alloc, dlsch_config->n_dmrs_cdm_groups, nl, - frame_parms, + fp, dlsch_config->dlDmrsSymbPos, csi_res_bitmap, ue->chest_time); stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS); if (scope_req->copy_chanest_to_scope) { - size_t size = sizeof(c16_t) * dlsch_config->number_rbs * NR_NB_SC_PER_RB; + size_t size = sizeof(c16_t) * nb_rb_pdsch * NR_NB_SC_PER_RB; int copy_index = symbol - dlsch_config->start_symbol; int offset = copy_index * size; UEscopeCopyUnsafe(ue, pdschChanEstimates, dl_ch_estimates_ext[0], size, offset, copy_index); @@ -480,14 +459,36 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, ue->phy_cpu_stats.cpu_time_stats[DLSCH_EXTRACT_RBS_STATS].p_time / (cpuf * 1000.0)); } if (ue->phy_sim_pdsch_rxdataF_ext) - for (unsigned char aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - int offset = ((void *)rxdataF_ext[aarx] - (void *)rxdataF_ext) + symbol * rx_size_symbol; - memcpy(ue->phy_sim_pdsch_rxdataF_ext + offset, rxdataF_ext, rx_size_symbol * sizeof(c16_t)); - } + memcpy(ue->phy_sim_pdsch_rxdataF_ext + symbol * sizeof(rxdataF_ext), rxdataF_ext, sizeof(rxdataF_ext)); nb_re_pdsch = (pilots == 1) ? ((config_type == NFAPI_NR_DMRS_TYPE1) ? nb_rb_pdsch * (12 - 6 * dlsch_config->n_dmrs_cdm_groups) : nb_rb_pdsch * (12 - 4 * dlsch_config->n_dmrs_cdm_groups)) : (nb_rb_pdsch * 12); + // Subtract CSI-RS REs from PDSCH RE count + if (csi_res_bitmap != 0) { + uint32_t csi_re_count = 0; + uint32_t csi_res_even = csi_res_bitmap & 0xfff; + uint32_t csi_res_odd = (csi_res_bitmap >> 16) & 0xfff; + int start = freq_alloc->start[0] + dlsch_config->BWPStart; + int end = freq_alloc->end[freq_alloc->num_blocks - 1] + 1; + for (int rb = start; rb < end; rb++) { + if ((freq_alloc->bitmap[rb / 8] >> (rb % 8)) & 0x01) { + uint32_t rb_csi_pattern = (rb % 2 == 0) ? csi_res_even : csi_res_odd; + csi_re_count += __builtin_popcount(rb_csi_pattern); + } + } + nb_re_pdsch = (nb_re_pdsch > csi_re_count) ? (nb_re_pdsch - csi_re_count) : 0; + if (csi_re_count > 0) { + LOG_D(NR_PHY, + "[CSI OVERLAP] Frame/Slot %d.%d Symbol %d: CSI-RS overlapping PDSCH - %d CSI-RS REs skipped, %d data REs extracted\n", + frame, + nr_slot_rx, + symbol, + csi_re_count, + nb_re_pdsch); + } + } + if (scope_req->copy_rxdataF_to_scope) { size_t size = sizeof(c16_t) * nb_re_pdsch; int copy_index = symbol - dlsch_config->start_symbol; @@ -498,7 +499,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, //--------------------- Channel Scaling -------------------- //---------------------------------------------------------- start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS); - nr_dlsch_scale_channel(rx_size_symbol, dl_ch_estimates_ext, frame_parms, nl, n_rx, symbol, pilots, nb_re_pdsch, nb_rb_pdsch); + nr_scale_channel(rx_size_symbol, dl_ch_estimates_ext, 0, nb_re_pdsch, nl, n_rx, 0); stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_SCALE_STATS); if (meas_enabled) { LOG_D(PHY, @@ -515,25 +516,25 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, //---------------------------------------------------------- start_meas_nr_ue_phy(ue, DLSCH_CHANNEL_LEVEL_STATS); if (first_symbol_flag) { - int32_t avg[MAX_ANT][MAX_ANT] = {}; + int32_t avg[nl * n_rx]; if (nb_re_pdsch) - nr_dlsch_channel_level(rx_size_symbol, dl_ch_estimates_ext, frame_parms->nb_antennas_rx, nl, avg, nb_re_pdsch); + nr_channel_level(0, rx_size_symbol, (c16_t (*)[rx_size_symbol])dl_ch_estimates_ext, n_rx, nl, avg, nb_re_pdsch); else LOG_E(NR_PHY, "Average channel level is 0: nb_rb_pdsch = %d, nb_re_pdsch = %d\n", nb_rb_pdsch, nb_re_pdsch); int avgs = 0; int32_t median[MAX_ANT][MAX_ANT]; - for (int aatx = 0; aatx < nl; aatx++) + for (int l = 0; l < nl; l++) for (int aarx = 0; aarx < n_rx; aarx++) { - avgs = cmax(avgs, avg[aatx][aarx]); - LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, aatx, avg[aatx][aarx]); + avgs = cmax(avgs, avg[l * n_rx + aarx]); + LOG_D(PHY, "nb_rb %d avg_%d_%d Power per SC is %d\n", nb_rb_pdsch, aarx, l, avg[l * n_rx + aarx]); LOG_D(PHY, "avgs Power per SC is %d\n", avgs); - median[aatx][aarx] = avg[aatx][aarx]; + median[l][aarx] = avg[l * n_rx + aarx]; } if (nl > 1) { nr_dlsch_channel_level_median(rx_size_symbol, dl_ch_estimates_ext, median, nl, n_rx, nb_re_pdsch); - for (int aatx = 0; aatx < nl; aatx++) { + for (int l = 0; l < nl; l++) { for (int aarx = 0; aarx < n_rx; aarx++) { - avgs = cmax(avgs, median[aatx][aarx]); + avgs = cmax(avgs, median[l][aarx]); } } } @@ -569,7 +570,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, dl_ch_magr, rxdataF_comp, NULL, - frame_parms, + fp, nl, symbol, nb_re_pdsch, @@ -594,10 +595,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, char filename[50]; snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); - write_output(filename, "rxdataF0", &rxdataF[0][symbol * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1); + write_output(filename, "rxdataF0", &rxdataF[0][symbol * fp->ofdm_symbol_size], fp->ofdm_symbol_size, 1, 1); snprintf(filename, 50, "dl_ch_estimates0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); - write_output(filename, "dl_ch_estimates0", &dl_ch_estimates[0][symbol * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1); + write_output(filename, "dl_ch_estimates0", &dl_ch_estimates[0][symbol * fp->ofdm_symbol_size], fp->ofdm_symbol_size, 1, 1); snprintf(filename, 50, "rxdataF_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); write_output(filename, "rxdataF_ext0", &rxdataF_ext[0][0], rx_size_symbol, 1, 1); @@ -673,58 +674,38 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, ptrs_re_per_slot, rx_size_symbol, rxdataF_comp, - frame_parms, + fp, dlsch0_harq, dlsch1_harq, gNB_id, nr_slot_rx, symbol, - (nb_rb_pdsch * 12), dlsch[0].rnti, dlsch); dl_valid_re[symbol] -= ptrs_re_per_slot[0][symbol]; } + start_meas_nr_ue_phy(ue, DLSCH_LLR_STATS); + nr_dlsch_llr(rx_size_symbol, + nbRx, + layer_llr_size, + layer_llr, + rxdataF_comp, + dl_ch_mag[0][0], + dl_ch_magb[0][0], + dl_ch_magr[0][0], + dlsch0_harq, + dlsch1_harq, + symbol, + dl_valid_re[symbol], + dlsch, + llr_offset[symbol]); + if (symbol < startSymbIdx + nbSymb - 1) // up to the penultimate symbol + llr_offset[symbol + 1] = dl_valid_re[symbol] * dlsch_config->qamModOrder + llr_offset[symbol]; + stop_meas_nr_ue_phy(ue, DLSCH_LLR_STATS); /* at last symbol in a slot calculate LLR's for whole slot */ - if(symbol == (startSymbIdx + nbSymb - 1)) { - const uint32_t rx_llr_layer_size = (G + dlsch[0].Nl - 1) / dlsch[0].Nl; - - if (dlsch[0].Nl == 0 || rx_llr_layer_size == 0 || rx_llr_layer_size > 10 * 1000 * 1000) { - LOG_E(PHY, "rx_llr_layer_size %d, G %d, Nl, %d, discarding this pdsch\n", rx_llr_layer_size, G, dlsch[0].Nl); - return -1; - } - - int16_t layer_llr[dlsch[0].Nl][rx_llr_layer_size]; - for(int i = startSymbIdx; i < startSymbIdx + nbSymb; i++) { - /* Calculate LLR's for each symbol */ - start_meas_nr_ue_phy(ue, DLSCH_LLR_STATS); - nr_dlsch_llr(rx_size_symbol, - nbRx, - rx_llr_layer_size, - layer_llr, - rxdataF_comp, - dl_ch_mag[0][0], - dl_ch_magb[0][0], - dl_ch_magr[0][0], - dlsch0_harq, - dlsch1_harq, - i, - dl_valid_re[i], - dlsch, - llr_offset[i]); - if (i < startSymbIdx + nbSymb - 1) // up to the penultimate symbol - llr_offset[i + 1] = dl_valid_re[i] * dlsch_config->qamModOrder + llr_offset[i]; - stop_meas_nr_ue_phy(ue, DLSCH_LLR_STATS); - } - + if (symbol == (startSymbIdx + nbSymb - 1)) { start_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING); - nr_dlsch_layer_demapping(llr, - dlsch[0].Nl, - dlsch_config->qamModOrder, - G, - codeword_TB0, - codeword_TB1, - rx_llr_layer_size, - layer_llr); + nr_dlsch_layer_demapping(llr, dlsch[0].Nl, dlsch_config->qamModOrder, G, codeword_TB0, codeword_TB1, layer_llr_size, layer_llr); stop_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING); /* for (int i=0; i < 2; i++){ @@ -769,69 +750,26 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, T_INT(frame % 1024), T_INT(nr_slot_rx), T_INT(nb_rb_pdsch), - T_INT(frame_parms->N_RB_UL), - T_INT(frame_parms->symbols_per_slot), - T_BUFFER(&rxdataF_comp[gNB_id][0], 2 * /* ulsch[UE_id]->harq_processes[harq_pid]->nb_rb */ frame_parms->N_RB_UL * 12 * 2)); + T_INT(fp->N_RB_UL), + T_INT(fp->symbols_per_slot), + T_BUFFER(&rxdataF_comp[gNB_id][0], 2 * /* ulsch[UE_id]->harq_processes[harq_pid]->nb_rb */ fp->N_RB_UL * 12 * 2)); #endif if (ue->phy_sim_pdsch_rxdataF_comp) for (int a = 0; a < nbRx; a++) { - int offset = (void *)rxdataF_comp[0][a] - (void *)rxdataF_comp[0] + symbol * rx_size_symbol * sizeof(c16_t); - memcpy(ue->phy_sim_pdsch_rxdataF_comp + offset, rxdataF_comp[0][a] + symbol * rx_size_symbol, sizeof(c16_t) * rx_size_symbol); + for (int l = 0; l < nl; l++) { + int offset = (void *)rxdataF_comp[l][a] - (void *)rxdataF_comp[0] + symbol * rx_size_symbol * sizeof(c16_t); + memcpy(ue->phy_sim_pdsch_rxdataF_comp + offset, + rxdataF_comp[l][a] + symbol * rx_size_symbol, + sizeof(c16_t) * rx_size_symbol); + } memcpy((c16_t *)ue->phy_sim_pdsch_dl_ch_estimates + pdsch_est_size * a, dl_ch_estimates, pdsch_est_size * sizeof(c16_t)); } if (ue->phy_sim_pdsch_dl_ch_estimates_ext) - memcpy((c16_t *)ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * rx_size_symbol, + memcpy(ue->phy_sim_pdsch_dl_ch_estimates_ext + symbol * sizeof(dl_ch_estimates_ext), dl_ch_estimates_ext, sizeof(dl_ch_estimates_ext)); - return (0); -} - -void nr_dlsch_deinterleaving(uint8_t symbol, - uint8_t start_symbol, - uint16_t L, - uint16_t *llr, - uint16_t *llr_deint, - uint16_t nb_rb_pdsch) -{ - - uint32_t bundle_idx, N_bundle, R, C, r,c; - int32_t m,k; - uint8_t nb_re; - - R=2; - N_bundle = nb_rb_pdsch/L; - C=N_bundle/R; - - uint32_t bundle_deint[N_bundle]; - memset(bundle_deint, 0 , sizeof(bundle_deint)); - - printf("N_bundle %u L %d nb_rb_pdsch %d\n",N_bundle, L,nb_rb_pdsch); - - if (symbol==start_symbol) - nb_re = 6; - else - nb_re = 12; - - - AssertFatal(llr!=NULL,"nr_dlsch_deinterleaving: FATAL llr is Null\n"); - - - for (c =0; c< C; c++){ - for (r=0; r 2) { // get channel amplitude if not QPSK - mmtmpD0 = simde_mm_madd_epi16(dl_ch128[0], dl_ch128[0]); + simde__m128i mmtmpD0 = simde_mm_madd_epi16(dl_ch128[0], dl_ch128[0]); mmtmpD0 = simde_mm_srai_epi32(mmtmpD0, output_shift); - mmtmpD1 = simde_mm_madd_epi16(dl_ch128[1], dl_ch128[1]); + simde__m128i mmtmpD1 = simde_mm_madd_epi16(dl_ch128[1], dl_ch128[1]); mmtmpD1 = simde_mm_srai_epi32(mmtmpD1, output_shift); mmtmpD0 = simde_mm_packs_epi32(mmtmpD0, mmtmpD1); //|H[0]|^2 |H[1]|^2 |H[2]|^2 |H[3]|^2 |H[4]|^2 |H[5]|^2 |H[6]|^2 |H[7]|^2 @@ -974,91 +912,6 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol, } } -void nr_dlsch_scale_channel(uint32_t rx_size_symbol, - int32_t dl_ch_estimates_ext[][rx_size_symbol], - NR_DL_FRAME_PARMS *frame_parms, - uint8_t n_tx, - uint8_t n_rx, - uint8_t symbol, - uint8_t pilots, - uint32_t len, - unsigned short nb_rb) - -{ - - - short rb, ch_amp; - unsigned char aatx,aarx; - simde__m128i *dl_ch128, ch_amp128; - - uint32_t nb_rb_0 = len/12 + ((len%12)?1:0); - - // Determine scaling amplitude based the symbol - - ch_amp = 1024*8; //((pilots) ? (dlsch_ue[0]->sqrt_rho_b) : (dlsch_ue[0]->sqrt_rho_a)); - - LOG_D(PHY,"Scaling PDSCH Chest in OFDM symbol %d by %d, pilots %d nb_rb %d NCP %d symbol %d\n",symbol,ch_amp,pilots,nb_rb,frame_parms->Ncp,symbol); - // printf("Scaling PDSCH Chest in OFDM symbol %d by %d\n",symbol_mod,ch_amp); - - ch_amp128 = simde_mm_set1_epi16(ch_amp); // Q3.13 - - for (aatx=0; aatx> x; - - uint32_t nb_rb_0 = len / NR_NB_SC_PER_RB + ((len % NR_NB_SC_PER_RB) ? 1 : 0); - LOG_D(NR_PHY, "nb_rb_0 %d len %d = %d * 2^(%d)\n", nb_rb_0, len, y, x); - - for (int aatx = 0; aatx < n_tx; aatx++) { - for (int aarx = 0; aarx < n_rx; aarx++) { - - simde__m128i *dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[(aatx * n_rx) + aarx]; - - //compute average level - avg[aatx][aarx] = simde_mm_average(dl_ch128, nb_rb_0 * 12, x, y); - //LOG_D(PHY, "Channel level: %d\n", avg[aatx][aarx]); - } - } -} - static void nr_dlsch_channel_level_median(uint32_t rx_size_symbol, int32_t dl_ch_estimates_ext[][rx_size_symbol], int32_t median[MAX_ANT][MAX_ANT], @@ -1107,28 +960,31 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz, unsigned char symbol, uint8_t pilots, uint8_t config_type, - unsigned short start_rb, - unsigned short nb_rb_pdsch, + int startBWP, + const freq_alloc_bitmap_t *freq_alloc, uint8_t n_dmrs_cdm_groups, uint8_t Nl, - NR_DL_FRAME_PARMS *frame_parms, + NR_DL_FRAME_PARMS *fp, uint16_t dlDmrsSymbPos, uint32_t csi_res_bitmap, int chest_time_type) { if (config_type == NFAPI_NR_DMRS_TYPE1) - AssertFatal(n_dmrs_cdm_groups == 1 || n_dmrs_cdm_groups == 2, "n_dmrs_cdm_groups %d is illegal\n",n_dmrs_cdm_groups); + AssertFatal(n_dmrs_cdm_groups == 1 || n_dmrs_cdm_groups == 2, "n_dmrs_cdm_groups %d is illegal\n", n_dmrs_cdm_groups); else AssertFatal(n_dmrs_cdm_groups == 1 || n_dmrs_cdm_groups == 2 || n_dmrs_cdm_groups == 3, "n_dmrs_cdm_groups %d is illegal\n",n_dmrs_cdm_groups); - uint32_t dmrs_rb_bitmap = 0xfff; // all REs taken by dmrs - if (config_type == NFAPI_NR_DMRS_TYPE1 && n_dmrs_cdm_groups == 1) - dmrs_rb_bitmap = 0x555; // alternating REs starting from 0 - if (config_type == NFAPI_NR_DMRS_TYPE2 && n_dmrs_cdm_groups == 1) - dmrs_rb_bitmap = 0xc3; // REs 0,1 and 6,7 - if (config_type == NFAPI_NR_DMRS_TYPE2 && n_dmrs_cdm_groups == 2) - dmrs_rb_bitmap = 0x3cf; // REs 0,1,2,3 and 6,7,8,9 + uint32_t dmrs_rb_bitmap = 0; + if (pilots) { + dmrs_rb_bitmap = 0xfff; // all REs taken by dmrs + if (config_type == NFAPI_NR_DMRS_TYPE1 && n_dmrs_cdm_groups == 1) + dmrs_rb_bitmap = 0x555; // alternating REs starting from 0 + if (config_type == NFAPI_NR_DMRS_TYPE2 && n_dmrs_cdm_groups == 1) + dmrs_rb_bitmap = 0xc3; // REs 0,1 and 6,7 + if (config_type == NFAPI_NR_DMRS_TYPE2 && n_dmrs_cdm_groups == 2) + dmrs_rb_bitmap = 0x3cf; // REs 0,1,2,3 and 6,7,8,9 + } // csi_res_bitmap LS 16 bits for even RBs, MS 16 bits for odd RBs uint32_t csi_res_even = csi_res_bitmap & 0xfff; @@ -1137,69 +993,68 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz, AssertFatal((dmrs_rb_bitmap & csi_res_odd) == 0, "DMRS RE overlapping with CSI RE, it shouldn't happen\n"); uint32_t dmrs_csi_overlap_even = csi_res_even + dmrs_rb_bitmap; uint32_t dmrs_csi_overlap_odd = csi_res_odd + dmrs_rb_bitmap; - - const unsigned short start_re = (frame_parms->first_carrier_offset + start_rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size; int8_t validDmrsEst; - if (chest_time_type == 0) - validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlDmrsSymbPos,symbol); + validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlDmrsSymbPos, symbol); else - validDmrsEst = get_next_dmrs_symbol_in_slot(dlDmrsSymbPos,0,14); // get first dmrs symbol index + validDmrsEst = get_next_dmrs_symbol_in_slot(dlDmrsSymbPos, 0, 14); // get first dmrs symbol index - for (unsigned char aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { - c16_t *rxF_ext = rxdataF_ext[aarx]; - c16_t *rxF = &rxdataF[aarx][symbol * frame_parms->ofdm_symbol_size]; - - for (unsigned char l = 0; l < Nl; l++) { - - int32_t *dl_ch0 = &dl_ch_estimates[(l * frame_parms->nb_antennas_rx) + aarx][validDmrsEst * frame_parms->ofdm_symbol_size]; - int32_t *dl_ch0_ext = dl_ch_estimates_ext[(l * frame_parms->nb_antennas_rx) + aarx]; - - if (pilots == 0 && csi_res_bitmap == 0) { // data symbol only - if (l == 0) { - if (start_re + nb_rb_pdsch * NR_NB_SC_PER_RB <= frame_parms->ofdm_symbol_size) { - memcpy(rxF_ext, &rxF[start_re], nb_rb_pdsch * NR_NB_SC_PER_RB * sizeof(int32_t)); - } else { - int neg_length = frame_parms->ofdm_symbol_size - start_re; - int pos_length = nb_rb_pdsch * NR_NB_SC_PER_RB - neg_length; - memcpy(rxF_ext, &rxF[start_re], neg_length * sizeof(int32_t)); - memcpy(&rxF_ext[neg_length], rxF, pos_length * sizeof(int32_t)); - } - } - memcpy(dl_ch0_ext, dl_ch0, nb_rb_pdsch * NR_NB_SC_PER_RB * sizeof(int32_t)); - } - else { - int j = 0; - int k = start_re; - for (int rb = 0; rb < nb_rb_pdsch; rb++) { - uint32_t overlap_map = rb % 2 ? dmrs_csi_overlap_odd : dmrs_csi_overlap_even; - for (int re = 0; re < 12; re++) { - if (((overlap_map >> re) & 0x01) == 0) { - // DATA RE - if (l == 0) - rxF_ext[j] = rxF[k]; - dl_ch0_ext[j] = dl_ch0[re]; - j++; + for (int b = 0; b < freq_alloc->num_blocks; b++) { + int start_rb = freq_alloc->start[b] + startBWP; + int nb_rb = freq_alloc->end[b] - freq_alloc->start[b] + 1; + const int start_re = (fp->first_carrier_offset + start_rb * NR_NB_SC_PER_RB) % fp->ofdm_symbol_size; + for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) { + c16_t *rxF_ext = rxdataF_ext[aarx]; + c16_t *rxF = &rxdataF[aarx][symbol * fp->ofdm_symbol_size]; + for (int l = 0; l < Nl; l++) { + int32_t *dl_ch0 = &dl_ch_estimates[(l * fp->nb_antennas_rx) + aarx][validDmrsEst * fp->ofdm_symbol_size]; + int32_t *dl_ch0_ext = dl_ch_estimates_ext[(l * fp->nb_antennas_rx) + aarx]; + if (pilots == 0 && csi_res_bitmap == 0) { // data symbol only + if (l == 0) { + if (start_re + nb_rb * NR_NB_SC_PER_RB <= fp->ofdm_symbol_size) { + memcpy(rxF_ext, &rxF[start_re], nb_rb * NR_NB_SC_PER_RB * sizeof(int32_t)); + } else { + int neg_length = fp->ofdm_symbol_size - start_re; + int pos_length = nb_rb * NR_NB_SC_PER_RB - neg_length; + memcpy(rxF_ext, &rxF[start_re], neg_length * sizeof(int32_t)); + memcpy(&rxF_ext[neg_length], rxF, pos_length * sizeof(int32_t)); } - k++; - if (k >= frame_parms->ofdm_symbol_size) - k -= frame_parms->ofdm_symbol_size; } - dl_ch0 += 12; + memcpy(dl_ch0_ext, dl_ch0, nb_rb * NR_NB_SC_PER_RB * sizeof(int32_t)); + } else { + int j = 0; + int k = start_re; + for (int rb = start_rb; rb < start_rb + nb_rb; rb++) { + uint32_t overlap_map = rb % 2 ? dmrs_csi_overlap_odd : dmrs_csi_overlap_even; + for (int re = 0; re < NR_NB_SC_PER_RB; re++) { + if (((overlap_map >> re) & 0x01) == 0) { + // DATA RE + if (l == 0) + rxF_ext[j] = rxF[k]; + dl_ch0_ext[j] = dl_ch0[re]; + j++; + } + k++; + if (k >= fp->ofdm_symbol_size) + k -= fp->ofdm_symbol_size; + } + dl_ch0 += 12; + } } } } } } + static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, short nl, short n_rx, int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], int ***rho, - int32_t dl_ch_mag[][n_rx][rx_size_symbol], - int32_t dl_ch_magb[][n_rx][rx_size_symbol], - int32_t dl_ch_magr[][n_rx][rx_size_symbol], + c16_t dl_ch_mag[][n_rx][rx_size_symbol], + c16_t dl_ch_magb[][n_rx][rx_size_symbol], + c16_t dl_ch_magr[][n_rx][rx_size_symbol], unsigned char symbol, int length) { @@ -1270,13 +1125,8 @@ void nr_a_sum_b(c16_t *input_x, c16_t *input_y, unsigned short nb_rb) } /* Zero Forcing Rx function: nr_element_sign() - * Compute b=sign*a - * - * */ -static inline void nr_element_sign(c16_t *a, // a - c16_t *b, // b - unsigned short nb_rb, - int32_t sign) + * Compute b=sign*a */ +static inline void nr_element_sign(c16_t *a, c16_t *b, unsigned short nb_rb, int32_t sign) { const int16_t nr_sign[8] __attribute__((aligned(16))) = {-1, -1, -1, -1, -1, -1, -1, -1}; simde__m128i *a_128,*b_128; @@ -1530,9 +1380,9 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, unsigned char n_rx, unsigned char nl, // number of layer int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], - int32_t dl_ch_mag[][n_rx][rx_size_symbol], - int32_t dl_ch_magb[][n_rx][rx_size_symbol], - int32_t dl_ch_magr[][n_rx][rx_size_symbol], + c16_t dl_ch_mag[][n_rx][rx_size_symbol], + c16_t dl_ch_magb[][n_rx][rx_size_symbol], + c16_t dl_ch_magr[][n_rx][rx_size_symbol], int32_t dl_ch_estimates_ext[][rx_size_symbol], unsigned short nb_rb, unsigned char mod_order, @@ -1541,7 +1391,7 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, int length, uint32_t noise_var) { - uint32_t nb_rb_0 = length / 12 + ((length % 12) ? 1 : 0); + uint32_t nb_rb_0 = (length + 11) / 12; c16_t determ_fin[12 * nb_rb_0] __attribute__((aligned(32))); ///Allocate H^*H matrix elements and sub elements @@ -1598,7 +1448,7 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, determ_fin, // determin nb_rb_0, fp_flag, // fixed point flag - shift - (fp_flag == 1 ? 2 : 0)); // the out put is Q15 + shift - (fp_flag == 1 ? 1 : 0)); // the out put is Q15 // multiply Matrix inversion pf H_h_H by the rx signal vector c16_t outtemp[12 * nb_rb_0] __attribute__((aligned(32))); @@ -1616,7 +1466,7 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, (c16_t *)(rxdataF_comp[ctx][0] + symbol * rx_size_symbol), outtemp, sizeofArray(outtemp), - shift - (fp_flag == 1 ? 2 : 0)); + shift - (fp_flag == 1 ? 1 : 0)); nr_a_sum_b(rxdataF_zforcing[rtx], outtemp, nb_rb_0); // a = a + b } #ifdef DEBUG_DLSCH_DEMOD @@ -1667,13 +1517,9 @@ static void nr_dlsch_mmse(uint32_t rx_size_symbol, dl_ch_mag128b_0[0] = mmtmpD2; dl_ch_mag128r_0[0] = mmtmpD2; - dl_ch_mag128_0[0] = simde_mm_mulhi_epi16(dl_ch_mag128_0[0],QAM_amp128); - dl_ch_mag128_0[0] = simde_mm_slli_epi16(dl_ch_mag128_0[0],1); - - dl_ch_mag128b_0[0] = simde_mm_mulhi_epi16(dl_ch_mag128b_0[0],QAM_amp128b); - dl_ch_mag128b_0[0] = simde_mm_slli_epi16(dl_ch_mag128b_0[0],1); - dl_ch_mag128r_0[0] = simde_mm_mulhi_epi16(dl_ch_mag128r_0[0],QAM_amp128r); - dl_ch_mag128r_0[0] = simde_mm_slli_epi16(dl_ch_mag128r_0[0],1); + dl_ch_mag128_0[0] = simde_mm_mulhrs_epi16(dl_ch_mag128_0[0], QAM_amp128); + dl_ch_mag128b_0[0] = simde_mm_mulhrs_epi16(dl_ch_mag128b_0[0],QAM_amp128b); + dl_ch_mag128r_0[0] = simde_mm_mulhrs_epi16(dl_ch_mag128r_0[0],QAM_amp128r); determ_fin_128 += 1; dl_ch_mag128_0 += 1; @@ -1727,9 +1573,9 @@ static void nr_dlsch_llr(uint32_t rx_size_symbol, uint sz, int16_t layer_llr[][sz], int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], - int32_t dl_ch_mag[rx_size_symbol], - int32_t dl_ch_magb[rx_size_symbol], - int32_t dl_ch_magr[rx_size_symbol], + c16_t dl_ch_mag[rx_size_symbol], + c16_t dl_ch_magb[rx_size_symbol], + c16_t dl_ch_magr[rx_size_symbol], NR_DL_UE_HARQ_t *dlsch0_harq, NR_DL_UE_HARQ_t *dlsch1_harq, unsigned char symbol, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index 422e8d6484..da70fd50e8 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -147,7 +147,7 @@ static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc, 1, 1); } - LOG_I(PHY, "Initial sync: pbch decoded sucessfully, ssb index %d\n", *ssb_index); + LOG_A(PHY, "Initial sync: pbch decoded sucessfully, ssb index %d\n", *ssb_index); return true; } } @@ -311,7 +311,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, fp->dl_CarrierFreq, fp->N_RB_DL, numGscn); - + DevAssert(numGscn); task_ans_t ans; init_task_ans(&ans, numGscn); nr_ue_ssb_scan_t ssb_info[numGscn]; @@ -342,39 +342,38 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, } // Collect the scan results - nr_ue_ssb_scan_t res = {0}; - if (numGscn > 0) { - join_task_ans(&ans); - for (int i = 0; i < numGscn; i++) { - nr_ue_ssb_scan_t *ssbInfo = &ssb_info[i]; - if (ssbInfo->syncRes.cell_detected) { - LOG_I(NR_PHY, - "Cell Detected with GSCN: %d, SSB SC offset: %d, SSB Ref: %lf, PSS Corr peak: %d dB, PSS Corr Average: %d\n", - ssbInfo->gscnInfo.gscn, - ssbInfo->gscnInfo.ssbFirstSC, - ssbInfo->gscnInfo.ssRef, - ssbInfo->pssCorrPeakPower, - ssbInfo->pssCorrAvgPower); - if (!res.syncRes.cell_detected) { // take the first cell detected - res = *ssbInfo; - } - } - for (int ant = 0; ant < fp->nb_antennas_rx; ant++) { - free(ssbInfo->rxdata[ant]); - } - free(ssbInfo->rxdata); + nr_ue_ssb_scan_t *res = NULL; + join_task_ans(&ans); + for (int i = 0; i < numGscn; i++) { + nr_ue_ssb_scan_t *ssbInfo = &ssb_info[i]; + if (ssbInfo->syncRes.cell_detected) { + LOG_I(NR_PHY, + "Cell Detected with GSCN: %d, SSB SC offset: %d, SSB Ref: %lf, PSS Corr peak: %d dB, PSS Corr Average: %d\n", + ssbInfo->gscnInfo.gscn, + ssbInfo->gscnInfo.ssbFirstSC, + ssbInfo->gscnInfo.ssRef, + ssbInfo->pssCorrPeakPower, + ssbInfo->pssCorrAvgPower); + // take the first cell detected + if (!res) + res = ssbInfo; } + for (int ant = 0; ant < fp->nb_antennas_rx; ant++) { + free(ssbInfo->rxdata[ant]); + } + free(ssbInfo->rxdata); + ssbInfo->rxdata = NULL; } // Set globals based on detected cell - if (res.syncRes.cell_detected) { - fp->Nid_cell = res.nidCell; - fp->ssb_start_subcarrier = res.gscnInfo.ssbFirstSC; - fp->half_frame_bit = res.halfFrameBit; - fp->ssb_index = res.ssbIndex; - ue->symbol_offset = res.symbolOffset; - ue->common_vars.freq_offset = res.freqOffset; - ue->adjust_rxgain = res.adjust_rxgain; + if (res) { + fp->Nid_cell = res->nidCell; + fp->ssb_start_subcarrier = res->gscnInfo.ssbFirstSC; + fp->half_frame_bit = res->halfFrameBit; + fp->ssb_index = res->ssbIndex; + ue->symbol_offset = res->symbolOffset; + ue->common_vars.freq_offset = res->freqOffset; + ue->adjust_rxgain = res->adjust_rxgain; } // In initial sync, we indicate PBCH to MAC after the scan is complete. @@ -389,7 +388,7 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, NULL, number_pdus, proc, - res.syncRes.cell_detected ? (void *)&res.pbchResult : NULL, + res ? (void *)&res->pbchResult : NULL, NULL); if (ue->if_inst && ue->if_inst->dl_indication) @@ -398,73 +397,76 @@ nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc, LOG_D(PHY, "nr_initial sync ue RB_DL %d\n", fp->N_RB_DL); - if (res.syncRes.cell_detected) { + if (res) { // digital compensation of FFO for SSB symbols - if (res.freqOffset && ue->UE_fo_compensation) { + if (res->freqOffset && ue->UE_fo_compensation) { // In SA we need to perform frequency offset correction until the end of buffer because we need to decode SIB1 // and we do not know yet in which slot it goes. - compensate_freq_offset(ue->common_vars.rxdata, fp, res.freqOffset, res.syncRes.frame_id); + compensate_freq_offset(ue->common_vars.rxdata, fp, res->freqOffset, res->syncRes.frame_id); } // sync at symbol ue->symbol_offset // computing the offset wrt the beginning of the frame int mu = fp->numerology_index; // number of symbols with different prefix length // every 7*(1<symbolOffset / (7 * (1 << mu))) + 1; const int sync_pos_frame = n_symb_prefix0 * (fp->ofdm_symbol_size + fp->nb_prefix_samples0) - + (res.symbolOffset - n_symb_prefix0) * (fp->ofdm_symbol_size + fp->nb_prefix_samples); + + (res->symbolOffset - n_symb_prefix0) * (fp->ofdm_symbol_size + fp->nb_prefix_samples); // for a correct computation of frame number to sync with the one decoded at MIB we need to take into account in which of // the n_frames we got sync - ue->init_sync_frame = n_frames - 1 - res.syncRes.frame_id; + ue->init_sync_frame = n_frames - 1 - res->syncRes.frame_id; // we also need to take into account the shift by samples_per_frame in case the if is true - if (res.ssbOffset < sync_pos_frame) { - res.syncRes.rx_offset = fp->samples_per_frame - sync_pos_frame + res.ssbOffset; + if (res->ssbOffset < sync_pos_frame) { + res->syncRes.rx_offset = fp->samples_per_frame - sync_pos_frame + res->ssbOffset; ue->init_sync_frame += 1; } else - res.syncRes.rx_offset = res.ssbOffset - sync_pos_frame; + res->syncRes.rx_offset = res->ssbOffset - sync_pos_frame; } - 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); - } else { + if (res) { + 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); + } else { #ifdef DEBUG_INITIAL_SYNC 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, fp->Nid_cell,fp->frame_type); #endif - } + } // gain control - if (!res.syncRes.cell_detected) { // we are not synched, so we cannot use rssi measurement (which is based on channel estimates) - int rx_power = 0; + if (!res) { // we are not synched, so we cannot use rssi measurement (which is based on channel estimates) + int rx_power = 0; - // do a measurement on the best guess of the PSS - // for (aarx=0; aarxnb_antennas_rx; aarx++) - // rx_power += signal_energy(&ue->common_vars.rxdata[aarx][sync_pos2], - // frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples); + // do a measurement on the best guess of the PSS + // for (aarx=0; aarxnb_antennas_rx; aarx++) + // rx_power += signal_energy(&ue->common_vars.rxdata[aarx][sync_pos2], + // frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples); - /* - // do a measurement on the full frame - for (aarx=0; aarxnb_antennas_rx; aarx++) - rx_power += signal_energy(&ue->common_vars.rxdata[aarx][0], - frame_parms->samples_per_subframe*10); - */ + /* + // do a measurement on the full frame + for (aarx=0; aarxnb_antennas_rx; aarx++) + rx_power += signal_energy(&ue->common_vars.rxdata[aarx][0], + frame_parms->samples_per_subframe*10); + */ - // we might add a low-pass filter here later - ue->measurements.rx_power_avg[0] = rx_power / fp->nb_antennas_rx; + // we might add a low-pass filter here later + ue->measurements.rx_power_avg[0] = rx_power / fp->nb_antennas_rx; - ue->measurements.rx_power_avg_dB[0] = dB_fixed(ue->measurements.rx_power_avg[0]); + 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 failed : Estimated power: %d dB\n", ue->Mod_id, ue->measurements.rx_power_avg_dB[0]); #endif - } else { - LOG_A(PHY, "Initial sync successful, PCI: %d\n",fp->Nid_cell); - } + } else { + 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); - return res.syncRes; + if (res) + return res->syncRes; + else + return (nr_initial_sync_t){.cell_detected = false}; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c index 2568a54a37..f9047aedd0 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync_sl.c @@ -78,19 +78,6 @@ static int sl_nr_pss_correlation(PHY_VARS_NR_UE *UE, int frame_index) const c64_t r64 = {.r = result.r, .i = result.i}; psss_corr_value += squaredMod(r64); - -#ifdef SL_DEBUG - pss_corr_debug_values[pss_index][n] = psss_corr_value; - printf("frame:%d n:%d, pss_index:%d, pss_for_correlation[pss_index][0]:%x, rxdata[n]:%x\n", - frame_index, - n, - pss_index, - pss_for_correlation[pss_index][0], - rxdata[ar][n + frame_index * sl_fp->samples_per_frame]); - printf("result %lld, pss_corr_values[%d][%d]:%ld\n", result, pss_index, n, pss_corr_debug_values[pss_index][n]); - printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)pss_corr_debug_values[pss_index][n]); - printf("peak_value:%ld, peak_position:%d, pss_source:%d\n", peak_value, peak_position, pss_source); -#endif } // calculate the absolute value of sync_corr[n] @@ -99,10 +86,6 @@ static int sl_nr_pss_correlation(PHY_VARS_NR_UE *UE, int frame_index) peak_value = psss_corr_value; peak_position = n; pss_source = pss_index; - -#ifdef SL_DEBUG - printf("pss_index %d: n %6u peak_value %15llu\n", pss_index, n, (unsigned long long)psss_corr_value); -#endif } } } @@ -518,7 +501,7 @@ nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc, sync_params->DFN, sync_params->slot_offset); - UE->adjust_rxgain = nr_sl_psbch_rsrp_measurements(sl_ue, frame_parms, rxdataF, false); + UE->adjust_rxgain = nr_sl_psbch_rsrp_measurements(sl_ue, frame_parms, rxdataF, false, UE->openair0_cfg); UE->init_sync_frame = sync_params->remaining_frames; result.rx_offset = sync_params->rx_offset; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c index 298de612ee..00130b3642 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c @@ -38,6 +38,7 @@ #include #include #include "openair1/PHY/NR_REFSIG/nr_refsig_common.h" +#include "PHY/nr_phy_common/inc/nr_phy_common.h" #include "instrumentation.h" //#define DEBUG_PBCH //#define DEBUG_PBCH_ENCODING @@ -201,31 +202,6 @@ static uint16_t nr_pbch_extract(uint32_t rxdataF_sz, return(0); } -//__m128i avg128; - -//compute average channel_level on each (TX,RX) antenna pair -int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL], - const NR_DL_FRAME_PARMS *frame_parms, - int nb_re) -{ - int32_t avg2 = 0; - - for (int aarx=0; aarxnb_antennas_rx; aarx++) { - - simde__m128i *dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[aarx]; - - //compute average level - int32_t avg1 = simde_mm_average(dl_ch128, nb_re, 0, nb_re); - - if (avg1>avg2) - avg2 = avg1; - - //LOG_I(PHY,"Channel level : %d, %d\n",avg1, avg2); - } - - return(avg2); -} - void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL], struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL], int nb_re, @@ -287,11 +263,7 @@ void nr_pbch_unscrambling(int16_t *demod_pbch_e, *pbch_a_interleaved ^= ((unscrambling_mask >> i) & 1) ? ((pbch_a_prime >> i) & 1) << i : (((pbch_a_prime >> i) & 1) ^ ((seq[idxGold] >> ((k + offset) & 0x1f)) & 1)) << i; - k += (!((unscrambling_mask>>i)&1)); -#ifdef DEBUG_PBCH_ENCODING - printf("i %d k %d offset %d (unscrambling_mask>>i)&1) %d s: %08x\t pbch_a_interleaved 0x%08x (!((unscrambling_mask>>i)&1)) %d\n", i, k, offset, (unscrambling_mask>>i)&1, s, *pbch_a_interleaved, - (!((unscrambling_mask>>i)&1))); -#endif + k += (!((unscrambling_mask >> i) & 1)); } else { if (((i + offset) & 0x1f) == 0) idxGold++; @@ -346,7 +318,6 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue, const struct complex16 rxdataF[][rxdataFSize]) { TracyCZone(ctx, true); - int max_h=0; int symbol; uint8_t Lmax=frame_parms->Lmax; int M = NR_POLAR_PBCH_E; @@ -390,11 +361,14 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue, LOG_I(PHY,"[PHY] PBCH starting channel_level\n"); #endif + int max_h = 0; if (symbol == 1) { - max_h = nr_pbch_channel_level(dl_ch_estimates_ext, - frame_parms, - nb_re); - log2_maxh = 3+(log2_approx(max_h)/2); + int avg[frame_parms->nb_antennas_rx]; + nr_channel_level(0, PBCH_MAX_RE_PER_SYMBOL, dl_ch_estimates_ext, frame_parms->nb_antennas_rx, 1, avg, nb_re); + max_h = avg[0]; + for (int i = 1; i < frame_parms->nb_antennas_rx; i++) + max_h = cmax(avg[i], max_h); + log2_maxh = 3 + (log2_approx(max_h) / 2); } #ifdef DEBUG_PBCH diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c b/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c index 7406855cc4..1010a6e5e8 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_rx.c @@ -25,6 +25,7 @@ #include "common/utils/LOG/log.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" #include "PHY/TOOLS/phy_scope_interface.h" +#include "PHY/nr_phy_common/inc/nr_phy_common.h" // #define DEBUG_PSBCH @@ -158,8 +159,11 @@ int nr_rx_psbch(PHY_VARS_NR_UE *ue, int max_h = 0; if (symbol == 0) { - max_h = nr_pbch_channel_level(dl_ch_estimates_ext, frame_parms, nb_re); - // log2_maxh = 3+(log2_approx(max_h)/2); + int avg[frame_parms->nb_antennas_rx]; + nr_channel_level(0, PBCH_MAX_RE_PER_SYMBOL, dl_ch_estimates_ext, frame_parms->nb_antennas_rx, 1, avg, nb_re); + max_h = avg[0]; + for (int i = 1; i < frame_parms->nb_antennas_rx; i++) + max_h = cmax(avg[i], max_h); log2_maxh = 5 + (log2_approx(max_h) / 2); // LLR32 crc error. LLR 16 CRC works } #ifdef DEBUG_PSBCH diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c b/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c index cc8993bc6d..5a80ca272b 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_psbch_tx.c @@ -40,11 +40,6 @@ void sl_psbch_scrambling(uint32_t *output, uint32_t id, uint16_t length) // x1 is set in lte_gold_generic x2 = id; // C_INIT -#ifdef SL_DEBUG - printf("SIDELINK: Function %s\n", __func__); - printf("Scrambling params: length %d id %d \n", length, id); -#endif - #ifdef SL_DEBUG for (int i = 0; i < 56; i++) { printf("\nBEFORE SCRAMBLING output[%d]:0x%x\n", i, output[i]); @@ -334,10 +329,6 @@ void nr_tx_psbch(PHY_VARS_NR_UE *UE, uint32_t frame_tx, uint32_t slot_tx, sl_nr_ psbch_payload |= (slot_tx << 10) & 0x10000; psbch_payload |= (slot_tx << 26) & 0xFC000000; -#ifdef SL_DEBUG - printf("DEBUG PSBCH TX: DFN, SLOT included. psbch_a :0x%08x, frame:%d, slot:%d\n", psbch_payload, frame_tx, slot_tx); -#endif - LOG_D(PHY, "PSBCH TX: Frame.Slot %d.%d. Payload::0x%08x, slssid:%d\n", frame_tx, slot_tx, psbch_payload, slss_id); // GENERATE Sidelink PSS,SSS Sequences, PSBCH DMRS Symbols, PSBCH Symbols diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 8e266a57a3..41747a9ef1 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -41,6 +41,15 @@ #define NR_PUSCH_x 2 // UCI placeholder bit TS 38.212 V15.4.0 subclause 5.3.3.1 #define NR_PUSCH_y 3 // UCI placeholder bit +typedef enum { + BIT_TYPE_ULSCH = 0, // Default: UL-SCH data + BIT_TYPE_ACK = 1, // HARQ-ACK bit + BIT_TYPE_ACK_RESERVED = 2, // Reserved for HARQ-ACK (punctured) + BIT_TYPE_ACK_ULSCH = 3, + BIT_TYPE_CSI1 = 4, // CSI Part 1 bit + BIT_TYPE_CSI2 = 5 // CSI Part 2 bit +} uci_on_pusch_bit_type_t; + // Specifies the data that should be copied to the scope during PDSCH RX typedef struct pdsch_scope_req_s { bool copy_chanest_to_scope; @@ -58,14 +67,6 @@ typedef struct pdsch_scope_req_s { /** \brief This function initialises structures for DLSCH at UE */ void nr_ue_dlsch_init(NR_UE_DLSCH_t *dlsch_list, int num_dlsch, uint8_t max_ldpc_iterations); - -void nr_dlsch_deinterleaving(uint8_t symbol, - uint8_t start_symbol, - uint16_t L, - uint16_t *llr, - uint16_t *llr_deint, - uint16_t nb_rb_pdsch); - void nr_conjch0_mult_ch1(c16_t *ch0, c16_t *ch1, c16_t *ch0conj_ch1, unsigned short nb_rb, unsigned char output_shift0); /** \brief This is the alternative top-level entry point for DLSCH decoding in UE. @@ -93,6 +94,13 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue, int nb_dlsch, uint8_t *DLSCH_ids); +int nr_ulsch_pre_encoding(PHY_VARS_NR_UE *ue, + const NR_UE_ULSCH_t *ulsch, + const uint32_t frame, + const uint8_t slot, + const unsigned int *G, + const int nb_ulsch, + const uint8_t *ULSCH_ids); /** \brief This is the alternative top-level entry point for ULSCH encoding in UE. It handles all the HARQ processes in only one call. The routine first computes the segmentation information, followed by LDPC encoding algorithm of the @@ -112,7 +120,8 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, const uint8_t slot, unsigned int *G, int nb_ulsch, - uint8_t *ULSCH_ids); + uint8_t *ULSCH_ids, + uint16_t number_dmrs_symbols); /*! \brief Perform PUSCH scrambling. TS 38.211 V15.4.0 subclause 6.3.1.1 @param[in] in Pointer to input bits @@ -127,8 +136,8 @@ void nr_pusch_codeword_scrambling(uint8_t *in, uint32_t Nid, uint32_t n_RNTI, bool uci_on_pusch, - uint32_t* out); - + const uci_on_pusch_bit_type_t *template, + uint32_t *out); /** \brief Alternative entry point to UE uplink shared channels procedures. It handles all the HARQ processes in only one call. @@ -160,7 +169,8 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, c16_t **txdataF, c16_t **txdata, uint32_t linktype, - bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]); + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT], + bool no_phase_pre_comp); void clean_UE_harq(PHY_VARS_NR_UE *UE); @@ -305,11 +315,14 @@ void nr_dci_decoding_procedure(PHY_VARS_NR_UE *ue, int nr_rx_pdsch(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, NR_UE_DLSCH_t dlsch[2], + const freq_alloc_bitmap_t *freq_alloc, unsigned char symbol, bool first_symbol_flag, unsigned char harq_pid, uint32_t pdsch_est_size, int32_t dl_ch_estimates[][pdsch_est_size], + int layer_llr_size, + int16_t layer_llr[][layer_llr_size], int16_t *llr[2], uint32_t dl_valid_re[NR_SYMBOLS_PER_SLOT], c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP], @@ -343,9 +356,6 @@ void nr_tx_psbch(PHY_VARS_NR_UE *UE, uint32_t frame_tx, uint32_t slot_tx, sl_nr_ nr_initial_sync_t sl_nr_slss_search(PHY_VARS_NR_UE *UE, UE_nr_rxtx_proc_t *proc, int num_frames); // Reuse already existing PBCH functions -int nr_pbch_channel_level(struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL], - const NR_DL_FRAME_PARMS *frame_parms, - int nb_re); void nr_pbch_channel_compensation(struct complex16 rxdataF_ext[][PBCH_MAX_RE_PER_SYMBOL], struct complex16 dl_ch_estimates_ext[][PBCH_MAX_RE_PER_SYMBOL], int nb_re, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h index ce7f41d2b9..596916f091 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h @@ -38,18 +38,16 @@ #include "nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h" #include "../NR_TRANSPORT/nr_transport_common_proto.h" -typedef enum { - NEW_TRANSMISSION_HARQ, - RETRANSMISSION_HARQ -} harq_result_t; +#define MAX_FA_BLOCKS 10 +typedef struct { + int start[MAX_FA_BLOCKS]; + int end[MAX_FA_BLOCKS]; + int num_rbs; + int num_blocks; + uint8_t bitmap[36]; +} freq_alloc_bitmap_t; typedef struct { - /// HARQ tx status - harq_result_t tx_status; - /// Last TPC command - uint8_t TPC; - /// Length of ACK information (bits) - uint8_t O_ACK; /// Index of current HARQ round for this ULSCH uint8_t round; /// pointer to pdu from MAC interface (TS 36.212 V15.4.0, Sec 5.1 p. 8) @@ -66,14 +64,10 @@ typedef struct { uint32_t C; /// Number of bits in code segments uint32_t K; - /// Total number of bits across all segments - uint32_t sumKr; + /// + uint32_t Kb; /// Number of "Filler" bits uint32_t F; - /// n_DMRS for cyclic shift of DMRS - uint8_t n_DMRS; - /// n_DMRS2 for cyclic shift of DMRS - uint8_t n_DMRS2; /// Number of soft channel bits uint32_t G; // Number of modulated symbols carrying data @@ -152,4 +146,13 @@ typedef struct { // PTRS symbol index, to be updated every PTRS symbol within a slot. uint8_t ptrs_symbol_index; } NR_UE_DLSCH_t; + +typedef struct { + uint16_t Q_dash_ACK; // number of coded HARQ-ACK symbols + uint16_t E_uci_ACK; // number of coded HARQ-ACK bits + uint16_t Q_dash_ACK_rvd; // number of coded HARQ-ACK symbols reserved + uint16_t E_uci_ACK_rvd; // number of coded HARQ-ACK bits reserved + uint32_t G_ulsch; // bit capacity of ULSCH +} rate_match_info_uci_t; + #endif diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c index 2eeb27d457..d68ae6e9ae 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c @@ -32,56 +32,29 @@ #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h" #include "executables/nr-uesoftmodem.h" #include "common/utils/LOG/vcd_signal_dumper.h" +#include "PHY/log_tools.h" -int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, - NR_UE_ULSCH_t *ulsch, - const uint32_t frame, - const uint8_t slot, - unsigned int *G, - int nb_ulsch, - uint8_t *ULSCH_ids) +int nr_ulsch_pre_encoding(PHY_VARS_NR_UE *ue, + const NR_UE_ULSCH_t *ulsch, + const uint32_t frame, + const uint8_t slot, + const unsigned int *G, + const int nb_ulsch, + const uint8_t *ULSCH_ids) { - start_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS); - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_IN); - - nrLDPC_TB_encoding_parameters_t TBs[nb_ulsch]; - memset(TBs, 0, sizeof(TBs)); - nrLDPC_slot_encoding_parameters_t slot_parameters = { - .frame = frame, - .slot = slot, - .nb_TBs = nb_ulsch, - .threadPool = &get_nrUE_params()->Tpool, - .tinput = NULL, - .tprep = NULL, - .tparity = NULL, - .toutput = NULL, - .TBs = TBs - }; - - int max_num_segments = 0; - - for (uint8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) { - uint8_t ULSCH_id = ULSCH_ids[pusch_id]; - uint8_t harq_pid = ulsch[ULSCH_id].pusch_pdu.pusch_data.harq_process_id; - - nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[pusch_id]; - /* Neither harq_pid nor ULSCH_id are unique in the instance - * but their combination is. - * Since ULSCH_id < 2 - * then 2 * harq_pid + ULSCH_id is unique. - */ - TB_parameters->harq_unique_pid = 2 * harq_pid + ULSCH_id; + for (uint_fast8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) { + const uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + const uint8_t harq_pid = ulsch[ULSCH_id].pusch_pdu.pusch_data.harq_process_id; /////////////////////////parameters and variables initialization///////////////////////// - unsigned int crc = 1; NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid]; const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch->pusch_pdu; - uint16_t nb_rb = pusch_pdu->rb_size; - uint32_t A = pusch_pdu->pusch_data.tb_size << 3; - uint8_t Qm = pusch_pdu->qam_mod_order; + const uint16_t nb_rb = pusch_pdu->rb_size; + const uint32_t A = pusch_pdu->pusch_data.tb_size << 3; + const uint8_t Qm = pusch_pdu->qam_mod_order; // target_code_rate is in 0.1 units - float Coderate = (float)pusch_pdu->target_code_rate / 10240.0f; + const float Coderate = (float)pusch_pdu->target_code_rate / 10240.0f; LOG_D(NR_PHY, "ulsch coding nb_rb %d, Nl = %d\n", nb_rb, pusch_pdu->nrOfLayers); LOG_D(NR_PHY, "ulsch coding A %d G %d mod_order %d Coderate %f\n", A, G[pusch_id], Qm, Coderate); @@ -89,11 +62,11 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, ///////////////////////// a---->| add CRC |---->b ///////////////////////// - int max_payload_bytes = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * pusch_pdu->nrOfLayers * 1056; + const int max_payload_bytes = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER * pusch_pdu->nrOfLayers * 1056; int B; if (A > NR_MAX_PDSCH_TBS) { // Add 24-bit crc (polynomial A) to payload - crc = crc24a(harq_process->payload_AB, A) >> 8; + const unsigned int crc = crc24a(harq_process->payload_AB, A) >> 8; harq_process->payload_AB[A >> 3] = ((uint8_t *)&crc)[2]; harq_process->payload_AB[1 + (A >> 3)] = ((uint8_t *)&crc)[1]; harq_process->payload_AB[2 + (A >> 3)] = ((uint8_t *)&crc)[0]; @@ -101,49 +74,120 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, AssertFatal((A / 8) + 4 <= max_payload_bytes, "A %d is too big (A/8+4 = %d > %d)\n", A, (A / 8) + 4, max_payload_bytes); } else { // Add 16-bit crc (polynomial A) to payload - crc = crc16(harq_process->payload_AB, A) >> 16; + const unsigned int crc = crc16(harq_process->payload_AB, A) >> 16; harq_process->payload_AB[A >> 3] = ((uint8_t *)&crc)[1]; harq_process->payload_AB[1 + (A >> 3)] = ((uint8_t *)&crc)[0]; B = A + 16; AssertFatal((A / 8) + 3 <= max_payload_bytes, "A %d is too big (A/8+3 = %d > %d)\n", A, (A / 8) + 3, max_payload_bytes); } +#if T_TRACER + if (T_ACTIVE(T_UE_PHY_UL_PAYLOAD_TX_BITS)) { + // Get Time Stamp for T-tracer messages + char trace_tx_payload_time_stamp_str[30]; + get_time_stamp_usec(trace_tx_payload_time_stamp_str); + // trace_time_stamp_str = 8 bytes timestamp = YYYYMMDD + // + 9 bytes timestamp = HHMMSSMMM + // Log UE_PHY_UL_PAYLOAD_TX_BITS using T-Tracer if activated + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : + // int,dmrs_nscid : nb_antennas_tx : int,number_of_bits : buffer,data Define the subcarrier spacing vector + // int subcarrier_spacing_vect[] = {15000, 30000, 60000, 120000}; + NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms; + int subcarrier_spacing_index = frame_parms->subcarrier_spacing / 15000 - 1; + T(T_UE_PHY_UL_PAYLOAD_TX_BITS, + T_INT((int)frame), + T_INT((int)slot), + T_INT((int)split_time_stamp_and_convert_to_int(trace_tx_payload_time_stamp_str, 0, 8)), + T_INT((int)split_time_stamp_and_convert_to_int(trace_tx_payload_time_stamp_str, 8, 9)), + T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure + T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2) + T_INT((int)subcarrier_spacing_index), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz) + T_INT((int)ulsch->pusch_pdu.cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended) + T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot + T_INT((int)frame_parms->Nid_cell), + T_INT((int)ulsch->pusch_pdu.rnti), + T_INT((int)ulsch->pusch_pdu.rb_size), + T_INT((int)ulsch->pusch_pdu.rb_start), + T_INT((int)ulsch->pusch_pdu.start_symbol_index), // start_ofdm_symbol + T_INT((int)ulsch->pusch_pdu.nr_of_symbols), // num_ofdm_symbols + T_INT((int)ulsch->pusch_pdu.qam_mod_order), // modulation + T_INT((int)ulsch->pusch_pdu.mcs_index), // mcs + T_INT((int)ulsch->pusch_pdu.mcs_table), // mcs_table_index + T_INT((int)ulsch->pusch_pdu.nrOfLayers), // num_layer + T_INT((int)ulsch->pusch_pdu.transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1 + T_INT((int)ulsch->pusch_pdu.dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1 + T_INT((int)ulsch->pusch_pdu.ul_dmrs_symb_pos), // used to derive the DMRS symbol positions + T_INT((int)get_num_dmrs(ulsch->pusch_pdu.ul_dmrs_symb_pos)), + // dmrs_start_ofdm_symbol + // dmrs_duration_num_ofdm_symbols + // dmrs_num_add_positions + T_INT((int)get_dmrs_port(0, ulsch->pusch_pdu.dmrs_ports)), // dmrs_antenna_port + T_INT((int)ulsch->pusch_pdu.scid), // dmrs_nscid + T_INT((int)frame_parms->nb_antennas_tx), // number of tx antennas + T_INT((int)A), // number_of_bits + T_BUFFER((uint8_t *)harq_process->payload_AB, A / 8)); + } +#endif ///////////////////////// b---->| block segmentation |---->c ///////////////////////// harq_process->BG = pusch_pdu->ldpcBaseGraph; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_IN); start_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS); - TB_parameters->Kb = nr_segmentation(harq_process->payload_AB, - harq_process->c, - B, - &harq_process->C, - &harq_process->K, - &harq_process->Z, - &harq_process->F, - harq_process->BG); - TB_parameters->C = harq_process->C; - TB_parameters->K = harq_process->K; - TB_parameters->Z = harq_process->Z; - TB_parameters->F = harq_process->F; - TB_parameters->BG = harq_process->BG; - if (TB_parameters->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * pusch_pdu->nrOfLayers) { - LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", TB_parameters->C, B); + harq_process->Kb = nr_segmentation(harq_process->payload_AB, + harq_process->c, + B, + &harq_process->C, + &harq_process->K, + &harq_process->Z, + &harq_process->F, + harq_process->BG); + if (harq_process->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * pusch_pdu->nrOfLayers) { + LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", harq_process->C, B); return (-1); } stop_meas_nr_ue_phy(ue, ULSCH_SEGMENTATION_STATS); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_OUT); - max_num_segments = max(max_num_segments, TB_parameters->C); - - TB_parameters->nb_rb = nb_rb; - TB_parameters->Qm = Qm; - TB_parameters->mcs = pusch_pdu->mcs_index; - TB_parameters->nb_layers = pusch_pdu->nrOfLayers; - TB_parameters->rv_index = pusch_pdu->pusch_data.rv_index; - TB_parameters->G = G[pusch_id]; - TB_parameters->tbslbrm = pusch_pdu->tbslbrm; - TB_parameters->A = A; } // pusch_id + return 0; +} + +int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, + NR_UE_ULSCH_t *ulsch, + const uint32_t frame, + const uint8_t slot, + unsigned int *G, + int nb_ulsch, + uint8_t *ULSCH_ids, + uint16_t number_dmrs_symbols) +{ + start_meas_nr_ue_phy(ue, ULSCH_ENCODING_STATS); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_IN); + + nrLDPC_TB_encoding_parameters_t TBs[nb_ulsch]; + memset(TBs, 0, sizeof(TBs)); + nrLDPC_slot_encoding_parameters_t slot_parameters = {.frame = frame, + .slot = slot, + .nb_TBs = nb_ulsch, + .threadPool = &get_nrUE_params()->Tpool, + .tinput = NULL, + .tprep = NULL, + .tparity = NULL, + .toutput = NULL, + .TBs = TBs}; + + int max_num_segments = 0; + for (uint_fast8_t pusch_id = 0; pusch_id < nb_ulsch; pusch_id++) { + const uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + const uint8_t harq_pid = ulsch[ULSCH_id].pusch_pdu.pusch_data.harq_process_id; + NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid]; + max_num_segments = max(max_num_segments, harq_process->C); + } nrLDPC_segment_encoding_parameters_t segments[nb_ulsch][max_num_segments]; memset(segments, 0, sizeof(segments)); @@ -154,10 +198,25 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue, nrLDPC_TB_encoding_parameters_t *TB_parameters = &TBs[pusch_id]; NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid]; + const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch[ULSCH_id].pusch_pdu; + const uint16_t nb_rb = pusch_pdu->rb_size; + TB_parameters->harq_unique_pid = 2 * harq_pid + ULSCH_id; + TB_parameters->C = harq_process->C; + TB_parameters->K = harq_process->K; + TB_parameters->Z = harq_process->Z; + TB_parameters->F = harq_process->F; + TB_parameters->BG = harq_process->BG; + TB_parameters->Kb = harq_process->Kb; + TB_parameters->nb_rb = nb_rb; + TB_parameters->Qm = pusch_pdu->qam_mod_order; + TB_parameters->mcs = pusch_pdu->mcs_index; + TB_parameters->nb_layers = pusch_pdu->nrOfLayers; + TB_parameters->rv_index = pusch_pdu->pusch_data.rv_index; + TB_parameters->G = G[pusch_id]; + TB_parameters->tbslbrm = pusch_pdu->tbslbrm; + TB_parameters->A = pusch_pdu->pusch_data.tb_size / 8; TB_parameters->segments = segments[pusch_id]; - const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch->pusch_pdu; - uint16_t nb_rb = pusch_pdu->rb_size; memset(harq_process->f, 0, 14 * nb_rb * 12 * 16); TB_parameters->output = harq_process->f; diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index e8217ee5aa..310fa7dc5f 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -48,6 +48,13 @@ #include "executables/softmodem-common.h" #include "PHY/NR_REFSIG/ul_ref_seq_nr.h" #include +#include "PHY/log_tools.h" +#include "PHY/NR_UE_TRANSPORT/pucch_nr.h" +#include + +#define MAX_RE_PER_SYMBOL_IN_ALLOC (275 * 12) +#define MAX_NLQM (4 * 8) +#define MAX_UCI_CODED_BITS 1024 //#define DEBUG_PUSCH_MAPPING //#define DEBUG_MAC_PDU @@ -55,33 +62,72 @@ //extern int32_t uplink_counter; -void nr_pusch_codeword_scrambling_uci(uint8_t *in, uint32_t size, uint32_t Nid, uint32_t n_RNTI, uint32_t* out) +static void nr_pusch_codeword_scrambling_uci(uint8_t *in, + uint32_t size, + uint32_t Nid, + uint32_t n_RNTI, + const uci_on_pusch_bit_type_t *template, + uint32_t *out) { uint32_t *seq = gold_cache((n_RNTI << 15) + Nid, (size + 31) / 32); - for (int i=0; i> 31; + uint32_t num_words = (size + 31) / 32; + + // Step 1: Initial general scrambling + // First convert unpacked input to bit-packed words + uint32_t in_words[num_words]; + memset(in_words, 0, num_words * sizeof(uint32_t)); + + for (uint32_t i = 0; i < size; i++) { + uint32_t word_idx = i / 32; + uint32_t bit_idx = i % 32; + if (in[i] & 1) { + in_words[word_idx] |= (1U << bit_idx); + } + } + + for (uint32_t i = 0; i < num_words; i++) { + out[i] = in_words[i] ^ seq[i]; + } + + // According to 38.211 6.3.1.1 + for (uint32_t i = 0; i < size; i++) { + if (template[i] == BIT_TYPE_ACK_ULSCH) { + // Step 2: Overwrite/Correct positions for UCI bits including placeholders X, Y when O_ACK <= 2 + uint32_t pos = i; + uint32_t idx = pos / 32; + uint32_t b_idx = pos % 32; + + if (in[pos] == NR_PUSCH_y) { + // Clear bit + out[idx] &= ~(1U << b_idx); + if (b_idx > 0) { + // Y depends on the final value of the previous bit in the same word. + // This previous bit could be an ACK (already corrected) or ULSCH (from initial scramble). + out[idx] |= ((out[idx] >> (b_idx - 1)) & 1) << b_idx; + } else if (idx > 0) { + // Y depends on the last bit of the previous word. + out[idx] |= ((out[idx - 1] >> 31) & 1); + } + } else if (in[pos] == NR_PUSCH_x) { + out[idx] |= (1U << b_idx); } } - else - out[idx] ^= (((in[i]) & 1) ^ ((seq[idx] >> b_idx) & 1)) << b_idx; - //printf("i %d b_idx %d in %d s 0x%08x out 0x%08x\n", i, b_idx, in[i], s, *out); } } -void nr_pusch_codeword_scrambling(uint8_t *in, uint32_t size, uint32_t Nid, uint32_t n_RNTI, bool uci_on_pusch, uint32_t* out) +void nr_pusch_codeword_scrambling(uint8_t *in, + uint32_t size, + uint32_t Nid, + uint32_t n_RNTI, + bool uci_on_pusch, + const uci_on_pusch_bit_type_t *template, + uint32_t *out) { if (uci_on_pusch) - nr_pusch_codeword_scrambling_uci(in, size, Nid, n_RNTI, out); + // in buffer is in byte-packed format + nr_pusch_codeword_scrambling_uci(in, size, Nid, n_RNTI, template, out); else + // in buffer is in bit-packed format nr_codeword_scrambling(in, size, 0, Nid, n_RNTI, out); } @@ -90,8 +136,8 @@ The function pointers are set once before calling the mapping funcion for all symbols based on different parameters. Then the mapping is done for each symbol by calling the function pointers. */ -static void (*map_dmrs_ptr)(const unsigned int, const c16_t *, c16_t *); -static void (*map_data_dmrs_ptr)(const unsigned int num_cdm_no_data, const c16_t *, c16_t *); +typedef void (*map_dmrs_func_t)(const unsigned int, const c16_t *, c16_t *); +typedef void (*map_data_dmrs_func_t)(const unsigned int, const c16_t *, c16_t *); /* The following set of functions map dmrs and/or data REs in one RB based on @@ -190,7 +236,9 @@ static void map_over_dc(const unsigned int right_dc, const c16_t **ptrs, const c16_t **dmrs, const c16_t **data, - c16_t **out) + c16_t **out, + map_dmrs_func_t map_data_dmrs_ptr, + map_dmrs_func_t map_dmrs_ptr) { // if first RE is DC no need to map in this function if (right_dc == 0) @@ -276,7 +324,9 @@ static void map_current_symbol(const nr_phy_pxsch_params_t p, const c16_t *dmrs_seq, const c16_t *ptrs_seq, const c16_t **data, - c16_t *out) + c16_t *out, + map_dmrs_func_t map_dmrs_ptr, + map_data_dmrs_func_t map_data_dmrs_ptr) { const unsigned int abs_start_rb = p.bwp_start + p.start_rb; const unsigned int start_sc = (p.first_sc_offset + abs_start_rb * NR_NB_SC_PER_RB) % p.fft_size; @@ -296,7 +346,7 @@ static void map_current_symbol(const nr_phy_pxsch_params_t p, // map RB at DC if (rb_over_dc) { // if DC is in middle of RB, the following function handles it. - map_over_dc(rb_over_dc, n_cdm, p.fft_size, dmrs_per_rb, data_per_rb, p.delta, 0, NULL, &p_mod_dmrs, NULL, &out_tmp); + map_over_dc(rb_over_dc, n_cdm, p.fft_size, dmrs_per_rb, data_per_rb, p.delta, 0, NULL, &p_mod_dmrs, NULL, &out_tmp, map_data_dmrs_ptr, map_dmrs_ptr); continue; } else { // else just move the pointer and following function will map the rb @@ -314,7 +364,7 @@ static void map_current_symbol(const nr_phy_pxsch_params_t p, for (unsigned int rb = 0; rb < p.nb_rb; rb++) { if (rb == dc_rb) { if (rb_over_dc) { - map_over_dc(rb_over_dc, n_cdm, p.fft_size, dmrs_per_rb, data_per_rb, p.delta, 0, NULL, &p_mod_dmrs, &data_tmp, &out_tmp); + map_over_dc(rb_over_dc, n_cdm, p.fft_size, dmrs_per_rb, data_per_rb, p.delta, 0, NULL, &p_mod_dmrs, &data_tmp, &out_tmp, map_data_dmrs_ptr, map_dmrs_ptr); continue; } else { out_tmp -= p.fft_size; @@ -338,7 +388,7 @@ static void map_current_symbol(const nr_phy_pxsch_params_t p, if (rb < non_ptrs_rb || ptrs_idx_rb % p.K_ptrs) { if (rb == dc_rb) { if (rb_over_dc) { - map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, 0, NULL, NULL, &data_tmp, &out_tmp); + map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, 0, NULL, NULL, &data_tmp, &out_tmp, map_data_dmrs_ptr, map_dmrs_ptr); continue; } else { out_tmp -= p.fft_size; @@ -350,7 +400,7 @@ static void map_current_symbol(const nr_phy_pxsch_params_t p, } else { if (rb == dc_rb) { if (rb_over_dc) { - map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, ptrs_idx_re, &p_mod_ptrs, NULL, &data_tmp, &out_tmp); + map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, ptrs_idx_re, &p_mod_ptrs, NULL, &data_tmp, &out_tmp, map_data_dmrs_ptr, map_dmrs_ptr); continue; } else { out_tmp -= p.fft_size; @@ -369,7 +419,7 @@ static void map_current_symbol(const nr_phy_pxsch_params_t p, for (unsigned int rb = 0; rb < p.nb_rb; rb++) { if (rb == dc_rb) { if (rb_over_dc) { - map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, 0, NULL, NULL, &data_tmp, &out_tmp); + map_over_dc(rb_over_dc, n_cdm, p.fft_size, 0, 0, p.delta, 0, NULL, NULL, &data_tmp, &out_tmp, map_data_dmrs_ptr, map_dmrs_ptr); continue; } else { out_tmp -= p.fft_size; @@ -395,7 +445,7 @@ static void dmrs_amp_mult(const uint32_t dmrs_port, const pusch_dmrs_type_t dmrs_type, const unsigned int num_cdm_groups_no_data) { - float beta_dmrs_pusch = get_beta_dmrs_pusch(num_cdm_groups_no_data, dmrs_type); + float beta_dmrs_pusch = get_beta_dmrs(num_cdm_groups_no_data, dmrs_type == pusch_dmrs_type2); /* short array that hold amplitude for k_prime = 0 and k_prime = 1 */ int32_t alpha_dmrs[2] __attribute((aligned(16))); for (int_fast8_t i = 0; i < sizeofArray(alpha_dmrs); i++) { @@ -419,6 +469,8 @@ static void map_symbols(const nr_phy_pxsch_params_t p, c16_t *out) { // asign the function pointers + map_dmrs_func_t map_dmrs_ptr = NULL; + map_data_dmrs_func_t map_data_dmrs_ptr = NULL; if (p.dmrs_type == pusch_dmrs_type1) { map_dmrs_ptr = map_dmrs_type1_cdm1_rb; map_data_dmrs_ptr = (p.num_cdm_no_data == 1) ? map_data_dmrs_type1_cdm1_rb : NULL; @@ -459,10 +511,506 @@ static void map_symbols(const nr_phy_pxsch_params_t p, mod_dmrs_amp, mod_ptrs_amp, &cur_data, // increments every symbol - out + l * p.fft_size); + out + l * p.fft_size, + map_dmrs_ptr, + map_data_dmrs_ptr); } } +// Function to lookup beta offset value from Table 9.3-1 in TS 38.213 +static double get_beta_offset_harq_ack(uint8_t beta_offset_index) +{ + static const double beta_offset_values[21] = { + 1.000, // Index 0 + 2.000, // Index 1 + 2.500, // Index 2 + 3.125, // Index 3 + 4.000, // Index 4 + 5.000, // Index 5 + 6.250, // Index 6 + 8.000, // Index 7 + 10.000, // Index 8 + 12.625, // Index 9 + 15.875, // Index 10 + 20.000, // Index 11 + 31.000, // Index 12 + 50.000, // Index 13 + 80.000, // Index 14 + 126.000, // Index 15 + 0.6, // Index 16 + 0.4, // Index 17 + 0.2, // Index 18 + 0.1, // Index 19 + 0.05, // Index 20 + }; + + if (beta_offset_index > 20) { + LOG_E(PHY, "Invalid beta_offset_index %d, using default value\n", beta_offset_index); + return 20.000; // Default value using index 11 + } + + return beta_offset_values[beta_offset_index]; +} + +static double get_alpha_scaling_value(uint8_t alpha_scaling) +{ + switch (alpha_scaling) { + case 0: + return 0.5; + case 1: + return 0.65; + case 2: + return 0.8; + case 3: + return 1.0; + default: + AssertFatal(false, "Invalid alpha_scaling value %d, valid range is 0-3", alpha_scaling); + return 1.0; + } +} + +/* + * This function gets the CRC size of UCI + */ +static int get_crc_uci(const uint16_t ouci) +{ + int L = 0; + if (ouci > 19) { + L = 11; + } else if (ouci > 11) { + L = 6; + } else { + L = 0; // no ACK/NACK + } + + return L; +} + +static uint16_t get_Qd(const uint16_t oack, double beta, double alpha, const uint32_t sumKr, const uint32_t s1, const uint32_t s2) +{ + if (oack == 0) + return 0; + + uint16_t first_term = ceil(((double)oack + get_crc_uci(oack)) * (double)beta * s1 / sumKr); + uint16_t second_term = ceil(alpha * s2); + + return (first_term < second_term) ? first_term : second_term; +} + +/* + * This function calculates the rate matching information for UCI multiplexing with PUSCH + */ +static rate_match_info_uci_t calc_rate_match_info_uci(const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, + const NR_UL_UE_HARQ_t *harq_process_ul_ue, + const uint8_t nlqm, + unsigned int *G) +{ + // get beta offset + uint8_t beta_offset_index = pusch_pdu->pusch_uci.beta_offset_harq_ack; + double beta = get_beta_offset_harq_ack(beta_offset_index); + + // get alpha scaling value + uint8_t alpha_scaling = pusch_pdu->pusch_uci.alpha_scaling; + double alpha = get_alpha_scaling_value(alpha_scaling); + + // Calculate sumKr (total bits in all code blocks) + uint32_t sumKr = 0; + if (harq_process_ul_ue->C == 0) { + sumKr = 0; + } else if (harq_process_ul_ue->C == 1) { + sumKr = harq_process_ul_ue->K; + } else { + sumKr = harq_process_ul_ue->K * harq_process_ul_ue->C; + } + + // Calculate s1: total number of non-DMRS REs in allocation + uint16_t nb_rb = pusch_pdu->rb_size; + uint8_t start_symbol = pusch_pdu->start_symbol_index; + uint8_t number_of_symbols = pusch_pdu->nr_of_symbols; + uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos; + + uint32_t s1 = 0; + for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) { + if (!((ul_dmrs_symb_pos >> l) & 0x01)) { + s1 += nb_rb * NR_NB_SC_PER_RB; + } + } + + // Calculate s2: number of non-DMRS REs after first DMRS symbol + int first_dmrs_symbol = -1; + for (int l = start_symbol; l < start_symbol + number_of_symbols; l++) { + if ((ul_dmrs_symb_pos >> l) & 0x01) { + first_dmrs_symbol = l; + break; + } + } + int l0 = -1; + if (first_dmrs_symbol >= 0 && first_dmrs_symbol < start_symbol + number_of_symbols - 1) { + l0 = first_dmrs_symbol + 1; + } + uint32_t s2 = 0; + for (int l = l0; l < start_symbol + number_of_symbols; l++) { + if (!((ul_dmrs_symb_pos >> l) & 0x01)) { + s2 += nb_rb * NR_NB_SC_PER_RB; + } + } + + uint16_t oack = pusch_pdu->pusch_uci.harq_ack_bit_length; + uint16_t oack_rvd = (oack <= 2) ? 2 : 0; // get the reserved bits when oACK <= 2 according to TS 38.212 section 6.2.7, step 1 + + rate_match_info_uci_t rminfo = {0}; + + // get the number of coded HARQ-ACK symbols and bits, TS 38.212 section 6.3.2.4.1.1 + rminfo.Q_dash_ACK = get_Qd(oack, beta, alpha, sumKr, s1, s2); + rminfo.E_uci_ACK = rminfo.Q_dash_ACK * nlqm; + + if (oack_rvd > 0) { + rminfo.Q_dash_ACK_rvd = get_Qd(oack_rvd, beta, alpha, sumKr, s1, s2); + rminfo.E_uci_ACK_rvd = rminfo.Q_dash_ACK_rvd * nlqm; + } + + if (oack_rvd == 0) { + rminfo.G_ulsch = *G - rminfo.E_uci_ACK; + } else { + rminfo.G_ulsch = *G; + } + + *G = rminfo.G_ulsch; + LOG_D(PHY, "[UCI_RATE_MATCH] sumKr=%u, s1=%u, s2=%u, Final G_ulsch (output G): %u\n", sumKr, s1, s2, *G); + LOG_D(PHY, + "[UCI_RATE_MATCH] rate matching info returned: E_uci_ACK=%u, E_uci_ACK_rvd=%u, G_ulsch=%u\n", + rminfo.E_uci_ACK, + rminfo.E_uci_ACK_rvd, + rminfo.G_ulsch); + + return rminfo; +} + +static int initialize_mapping_resources(const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, + uint32_t *m_ulsch_initial, + uint32_t *m_uci_current) +{ + if (!pusch_pdu || !m_ulsch_initial || !m_uci_current) + return -1; + + const uint8_t n_pusch_sym_all = pusch_pdu->nr_of_symbols; + const uint16_t ul_dmrs_symb_pos = pusch_pdu->ul_dmrs_symb_pos; + const uint8_t dmrs_type = pusch_pdu->dmrs_config_type; + const uint8_t cdm_grps_no_data = pusch_pdu->num_dmrs_cdm_grps_no_data; + const uint32_t res_per_symbol_non_dmrs = pusch_pdu->rb_size * NR_NB_SC_PER_RB; + const uint32_t data_re_on_dmrs_sym_per_prb = NR_NB_SC_PER_RB - get_num_dmrs_re_per_rb(dmrs_type, cdm_grps_no_data); + + // Initialize resources per symbol for ULSCH and UCI + for (uint8_t i = 0; i < n_pusch_sym_all; i++) { + uint8_t absolute_symbol_idx = pusch_pdu->start_symbol_index + i; + + if ((ul_dmrs_symb_pos >> absolute_symbol_idx) & 0x01) { + // Calculate available data REs on DMRS symbols based on DMRS configuration + + m_ulsch_initial[i] = pusch_pdu->rb_size * data_re_on_dmrs_sym_per_prb; + m_uci_current[i] = 0; // UCI is not mapped on DMRS symbols + + } else { // Not a DMRS symbol + + m_ulsch_initial[i] = res_per_symbol_non_dmrs; + m_uci_current[i] = res_per_symbol_non_dmrs; + } + } + + return 0; +} + +static void get_first_uci_symbol(const uint8_t start_symbol, + const uint8_t num_symbols, + const uint16_t dmrs_map, + uint8_t *first_non_dmrs_sym, + uint8_t *dmrs_p1) +{ + // First non-DMRS symbol + const uint16_t last_sym = start_symbol + num_symbols; + for (uint_fast8_t s = start_symbol; s < last_sym; s++) { + if (!is_dmrs_symbol(s, dmrs_map)) { + *first_non_dmrs_sym = s; + break; + } + } + + // Symbol after first consequtive DMRS symbol + const uint8_t first_dmrs_sym = get_next_dmrs_symbol_in_slot(dmrs_map, start_symbol, last_sym); + *dmrs_p1 = first_dmrs_sym + 1; + while (is_dmrs_symbol(*dmrs_p1, dmrs_map) && *dmrs_p1 < last_sym) { + (*dmrs_p1)++; + } + + // Return relative symbol idx + *first_non_dmrs_sym -= start_symbol; + *dmrs_p1 -= start_symbol; +} + +/* + * This function builds the initial template by reserving positions for HARQ-ACK. + */ +static void build_template_reserve_ack(uci_on_pusch_bit_type_t *template, + const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, + uint32_t G_ack_rvd, + uint8_t l1_c, + const uint32_t *m_uci_current, + const uint32_t *m_ulsch_initial, + uint32_t positions_by_sym[][MAX_UCI_CODED_BITS], + uint32_t *count_by_sym) +{ + const uint8_t n_symbols = pusch_pdu->nr_of_symbols; + const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; + + memset(count_by_sym, 0, n_symbols * sizeof(uint32_t)); + + uint32_t symbol_start_bit_idx[14] = {0}; + for (uint8_t s = 1; s < n_symbols; s++) { + symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm); + } + + // Reserve Positions using RE-level D-Factor Distribution + uint32_t total_reserved = 0; + + for (uint8_t sym = l1_c; sym < n_symbols && total_reserved < G_ack_rvd; sym++) { + const uint32_t uci_re_on_sym = m_uci_current[sym]; + + if (uci_re_on_sym > 0) { + const uint32_t remaining_to_reserve = G_ack_rvd - total_reserved; + uint32_t d_factor_re; + const uint32_t num_re_to_select = ceil((double)remaining_to_reserve / nlqm); + if (num_re_to_select >= uci_re_on_sym) { + d_factor_re = 1; + } else { + d_factor_re = floor((double)uci_re_on_sym / num_re_to_select); + if (d_factor_re == 0) { + d_factor_re = 1; + } + } + + for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_reserved < G_ack_rvd; re_offset += d_factor_re) { + for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { + if (total_reserved >= G_ack_rvd) { + break; + } + + uint32_t bit_offset_in_sym = (re_offset * nlqm) + bit_in_re; + uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym; + template[cw_idx] = BIT_TYPE_ACK_RESERVED; + positions_by_sym[sym][count_by_sym[sym]] = cw_idx; + count_by_sym[sym]++; + + total_reserved++; + } + } + } + } +} + +/* + * This function maps the HARQ-ACK bits when O_ACK > 2 + */ +static void map_non_overlapped_ack(uci_on_pusch_bit_type_t *template, + const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, + uint16_t G_ack, + uint8_t l1_c, + const uint32_t *m_uci_current, + const uint32_t *m_ulsch_initial) +{ + const uint8_t n_symbols = pusch_pdu->nr_of_symbols; + const uint32_t nlqm = pusch_pdu->qam_mod_order * pusch_pdu->nrOfLayers; + + uint32_t symbol_start_bit_idx[14] = {0}; + for (uint8_t s = 1; s < n_symbols; s++) { + symbol_start_bit_idx[s] = symbol_start_bit_idx[s - 1] + (m_ulsch_initial[s - 1] * nlqm); + } + + uint32_t total_placed = 0; + for (uint8_t sym = l1_c; sym < n_symbols && total_placed < G_ack; sym++) { + const uint32_t uci_re_on_sym = m_uci_current[sym]; + + if (uci_re_on_sym > 0) { + const uint32_t remaining_to_place = G_ack - total_placed; + uint32_t d_factor_re; + const uint32_t num_re_to_select = ceil((double)remaining_to_place / nlqm); + + if (num_re_to_select >= uci_re_on_sym) { + d_factor_re = 1; + } else { + d_factor_re = floor((double)uci_re_on_sym / num_re_to_select); + if (d_factor_re == 0) { + d_factor_re = 1; + } + } + + for (uint32_t re_offset = 0; re_offset < uci_re_on_sym && total_placed < G_ack; re_offset += d_factor_re) { + for (uint32_t bit_in_re = 0; bit_in_re < nlqm; bit_in_re++) { + if (total_placed >= G_ack) { + break; + } + + uint32_t bit_offset_in_sym = (re_offset * nlqm) + bit_in_re; + uint32_t cw_idx = symbol_start_bit_idx[sym] + bit_offset_in_sym; + template[cw_idx] = BIT_TYPE_ACK; + + total_placed++; + } + } + } + } +} + +/* + * This function maps the HARQ-ACK bits when O_ACK <= 2 + */ +static void map_overlapped_ack(uci_on_pusch_bit_type_t *template, + uint16_t G_ack, + uint8_t l1_c, + uint8_t n_symbols, + uint32_t positions_by_sym[][MAX_UCI_CODED_BITS], + const uint32_t *count_by_sym) +{ + uint32_t ack_bits_marked = 0; + + for (uint8_t sym_iter = l1_c; sym_iter < n_symbols && ack_bits_marked < G_ack; sym_iter++) { + const uint32_t num_reserved_bits_on_sym = count_by_sym[sym_iter]; + + if (num_reserved_bits_on_sym > 0) { + const uint32_t num_ack_remaining = G_ack - ack_bits_marked; + uint32_t d_factor; + + // This d-factor is calculated for stepping through the list of *reserved bits*. + if (num_ack_remaining >= num_reserved_bits_on_sym) { + d_factor = 1; + } else { + d_factor = floor((double)num_reserved_bits_on_sym / num_ack_remaining); + if (d_factor == 0) { + d_factor = 1; + } + } + + const uint32_t *reserved_indices_on_this_sym = positions_by_sym[sym_iter]; + + for (uint32_t i = 0; i < num_reserved_bits_on_sym && ack_bits_marked < G_ack; i += d_factor) { + uint32_t pos_to_mark = reserved_indices_on_this_sym[i]; + template[pos_to_mark] = BIT_TYPE_ACK_ULSCH; + + ack_bits_marked++; + } + } + } +} + +/* + * Applies the template to build the final codeword + */ +static void apply_template_to_codeword(uint8_t *codeword, + const uci_on_pusch_bit_type_t *template, + uint32_t codeword_len, + const uint8_t *ulsch_bits, + const uint64_t *cack, + uint16_t G_ack, + uint32_t G_ulsch) +{ + uint32_t ulsch_idx = 0; + uint32_t ack_idx = 0; + + for (uint32_t i = 0; i < codeword_len; i++) { + switch (template[i]) { + case BIT_TYPE_ACK: + if (G_ack > 0 && ack_idx < G_ack) { + uint32_t word_idx = ack_idx / 64; + uint32_t bit_in_word_idx = ack_idx % 64; + codeword[i] = (cack[word_idx] >> bit_in_word_idx) & 1; + ack_idx++; + } + break; + + case BIT_TYPE_ACK_ULSCH: + if (G_ack > 0 && ack_idx < G_ack) { + codeword[i] = ((const uint8_t *)cack)[ack_idx++]; + if (G_ulsch > 0 && ulsch_idx < G_ulsch) { + ulsch_idx++; + } + } + break; + + case BIT_TYPE_ACK_RESERVED: + case BIT_TYPE_ULSCH: + default: + if (G_ulsch > 0 && ulsch_idx < G_ulsch) { + uint32_t byte_idx = ulsch_idx / 8; + uint32_t bit_in_byte_idx = ulsch_idx % 8; + codeword[i] = (ulsch_bits[byte_idx] >> bit_in_byte_idx) & 1; + ulsch_idx++; + } + break; + } + } +} + +/* + * This function implements the UCI multiplexing on PUSCH according to TS 38.212 section 6.2.7. + */ +static uci_on_pusch_bit_type_t *nr_data_control_mapping(const nfapi_nr_ue_pusch_pdu_t *pusch_pdu, + uci_on_pusch_bit_type_t *template, + unsigned int G_ulsch, + uint16_t G_ack, + uint32_t G_ack_rvd, + uint8_t *codeword, + uint32_t codeword_len, + const uint8_t *ulsch_bits, + const uint64_t *cack) +{ + if (!pusch_pdu || !codeword || codeword_len == 0 || !template) + return NULL; + const uint8_t n_symbols = pusch_pdu->nr_of_symbols; + if (n_symbols == 0 || n_symbols > NR_NUMBER_OF_SYMBOLS_PER_SLOT) + return NULL; + + uint32_t m_ulsch_initial[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0}; + uint32_t m_uci_current[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0}; // This holds RE counts, not bit counts + + if (initialize_mapping_resources(pusch_pdu, m_ulsch_initial, m_uci_current) != 0) { + LOG_E(PHY, "Failed to initialize mapping resources\n"); + return NULL; + } + + uint8_t first_non_dmrs_sym = 0; + uint8_t l1_c = 0; + get_first_uci_symbol(pusch_pdu->start_symbol_index, + pusch_pdu->nr_of_symbols, + pusch_pdu->ul_dmrs_symb_pos, + &first_non_dmrs_sym, + &l1_c); + + memset(template, 0, codeword_len * sizeof(uci_on_pusch_bit_type_t)); + + uint32_t positions_by_sym[NR_NUMBER_OF_SYMBOLS_PER_SLOT][MAX_UCI_CODED_BITS] = {0}; + uint32_t count_by_sym[NR_NUMBER_OF_SYMBOLS_PER_SLOT] = {0}; + + if (G_ack_rvd > 0) { + build_template_reserve_ack(template, + pusch_pdu, + G_ack_rvd, + l1_c, + m_uci_current, + m_ulsch_initial, + positions_by_sym, + count_by_sym); + } else if (G_ack > 0) { + map_non_overlapped_ack(template, pusch_pdu, G_ack, l1_c, m_uci_current, m_ulsch_initial); + } + + if (G_ack > 0 && G_ack_rvd > 0) { + map_overlapped_ack(template, G_ack, l1_c, n_symbols, positions_by_sym, count_by_sym); + } + + apply_template_to_codeword(codeword, template, codeword_len, ulsch_bits, cack, G_ack, G_ulsch); + + return template; +} + void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, const uint32_t frame, const uint8_t slot, @@ -485,8 +1033,11 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, LOG_D(PHY, "nr_ue_ulsch_procedures_slot hard_id %d %d.%d prepare for coding\n", harq_pid, frame, slot); NR_UE_ULSCH_t *ulsch_ue = &phy_data->ulsch; + NR_UE_PUCCH *pucch_ue = &phy_data->pucch_vars; NR_UL_UE_HARQ_t *harq_process_ul_ue = &UE->ul_harq_processes[harq_pid]; const nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch_ue->pusch_pdu; + const fapi_nr_ul_config_pucch_pdu *pucch_pdu = &pucch_ue->pucch_pdu[0]; + uci_on_pusch_bit_type_t *uci_mapping_template = NULL; uint16_t number_dmrs_symbols = 0; @@ -527,6 +1078,11 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, G[pusch_id] = nr_get_G(nb_rb, number_of_symbols, nb_dmrs_re_per_rb, number_dmrs_symbols, unav_res, mod_order, Nl); + // Capture the initial total PUSCH bits. This is the total_codeword_length for mapping. + unsigned int G_initial_total_pusch_bits = G[pusch_id]; + + uci_on_pusch_bit_type_t template_buffer[G_initial_total_pusch_bits]; + ws_trace_t tmp = {.nr = true, .direction = DIRECTION_UPLINK, .pdu_buffer = harq_process_ul_ue->payload_AB, @@ -543,7 +1099,18 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH coding///////////////////////// - if (nr_ulsch_encoding(UE, &phy_data->ulsch, frame, slot, G, 1, ULSCH_ids) == -1) { + rate_match_info_uci_t rm_info = {0}; + const uint8_t nl_qm = Nl * mod_order; // product of number of layers and modulation order + if(nr_ulsch_pre_encoding(UE, &phy_data->ulsch, frame, slot, G, 1, ULSCH_ids) != 0) { + LOG_E(PHY, "Error pre-encoding\n"); + return; + } + + if (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) { + rm_info = calc_rate_match_info_uci(pusch_pdu, harq_process_ul_ue, nl_qm, &G[pusch_id]); + } + + if (nr_ulsch_encoding(UE, &phy_data->ulsch, frame, slot, G, 1, ULSCH_ids, number_dmrs_symbols) == -1) { stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS); return; } @@ -556,9 +1123,52 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, int N_PRB_oh = 0; // higher layer (RRC) parameter xOverhead in PUSCH-ServingCellConfig - AssertFatal(pusch_pdu->pusch_uci.harq_ack_bit_length == 0 && pusch_pdu->pusch_uci.csi_part1_bit_length == 0 - && pusch_pdu->pusch_uci.csi_part2_bit_length == 0, - "UCI on PUSCH not supported at PHY\n"); + if (pusch_pdu->pusch_uci.harq_ack_bit_length != 0) { + LOG_D(PHY, "[UCI_ON_PUSCH] Original HARQ-ACK bit length: %u\n", pusch_pdu->pusch_uci.harq_ack_bit_length); + LOG_D(PHY, "[UCI_ON_PUSCH] Initial G: %u\n", G_initial_total_pusch_bits); + // b is the block of bits transmitted on the physical channel after payload coding + uint64_t b[16] = {0}; // limit to 1024-bit encoded length + + if (pucch_pdu == NULL) { + LOG_E(PHY, "nr_ue_ulsch_procedures: pucch_pdu is NULL but HARQ-ACK is present. Cannot proceed with UCI encoding.\n"); + stop_meas_nr_ue_phy(UE, PUSCH_PROC_STATS); + return; + } + + nr_uci_encoding(pusch_pdu->pusch_uci.harq_payload, + pusch_pdu->pusch_uci.harq_ack_bit_length, + pucch_pdu->prb_size, + true, + rm_info.E_uci_ACK, + mod_order, + &b[0]); + + LOG_D(PHY, + "[UCI_ON_PUSCH] G_ulsch=%u (updated G[pusch_id]), G_ack=%u (M_bit), G_ack_rvd=%u, total_len=%u " + "(G_initial_total_pusch_bits).\n", + G[pusch_id], + rm_info.E_uci_ACK, + rm_info.E_uci_ACK_rvd, + G_initial_total_pusch_bits); + + uint8_t temp_codeword[G_initial_total_pusch_bits]; + start_meas_nr_ue_phy(UE, UCI_ON_PUSCH_MAPPING); + nr_data_control_mapping(pusch_pdu, + template_buffer, + G[pusch_id], + rm_info.E_uci_ACK, + rm_info.E_uci_ACK_rvd, + temp_codeword, + G_initial_total_pusch_bits, + harq_process_ul_ue->f, + b); + stop_meas_nr_ue_phy(UE, UCI_ON_PUSCH_MAPPING); + memcpy(harq_process_ul_ue->f, temp_codeword, G_initial_total_pusch_bits); + uci_mapping_template = template_buffer; + } + + AssertFatal(pusch_pdu->pusch_uci.csi_part1_bit_length == 0 && pusch_pdu->pusch_uci.csi_part2_bit_length == 0, + "UCI (CSI) on PUSCH not supported at PHY\n"); uint16_t start_rb = pusch_pdu->rb_start; uint16_t start_sc = frame_parms->first_carrier_offset + (start_rb + pusch_pdu->bwp_start) * NR_NB_SC_PER_RB; @@ -591,18 +1201,87 @@ void nr_ue_ulsch_procedures(PHY_VARS_NR_UE *UE, /////////////////////////ULSCH scrambling///////////////////////// - uint32_t available_bits = G[pusch_id]; - // +1 because size can be not modulo 4 - uint32_t scrambled_output[available_bits / (8 * sizeof(uint32_t)) + 1]; + uint32_t available_bits; + bool is_uci_on_pusch = (pusch_pdu->pusch_uci.harq_ack_bit_length != 0); + + if (is_uci_on_pusch) { + // UCI on PUSCH is present, so available bits are the total codeword length + available_bits = G_initial_total_pusch_bits; + } else { + // No UCI on PUSCH, so available bits are the initial G value + available_bits = G[pusch_id]; + } + + // +1 because size can be not modulo 4 for the uint32_t array + uint32_t scrambled_output_len_u32 = (available_bits + 31) / 32; // Round up to nearest uint32_t count + uint32_t scrambled_output[scrambled_output_len_u32]; memset(scrambled_output, 0, sizeof(scrambled_output)); nr_pusch_codeword_scrambling(harq_process_ul_ue->f, available_bits, pusch_pdu->data_scrambling_id, rnti, - false, + is_uci_on_pusch, + uci_mapping_template, scrambled_output); + if (UE->phy_sim_test_buf) { + memcpy(UE->phy_sim_test_buf, scrambled_output, (available_bits + 7) / 8); + } +#if T_TRACER + if (T_ACTIVE(T_UE_PHY_UL_SCRAMBLED_TX_BITS)) { + // Get Time Stamp for T-tracer messages + char trace_time_stamp_str[30]; + get_time_stamp_usec(trace_time_stamp_str); + // trace_time_stamp_str = 8 bytes timestamp = YYYYMMDD + // + 9 bytes timestamp = HHMMSSMMM + int dmrs_port = get_dmrs_port(0, pusch_pdu->dmrs_ports); + const uint8_t *in_bytes = (const uint8_t *)scrambled_output; + + // Log UE_PHY_UL_SCRAMBLED_TX_BITS using T-Tracer if activated + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : + // int,dmrs_nscid : nb_antennas_tx : int,number_of_bits : buffer,data Define the subcarrier spacing vector + // int subcarrier_spacing_vect[] = {15000, 30000, 60000, 120000}; + int subcarrier_spacing_index = frame_parms->subcarrier_spacing / 15000 - 1; + T(T_UE_PHY_UL_SCRAMBLED_TX_BITS, + T_INT((int)frame), + T_INT((int)slot), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)), + T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)), + T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure + T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2) + T_INT((int)subcarrier_spacing_index), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz) + T_INT((int)pusch_pdu->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended) + T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot + T_INT((int)frame_parms->Nid_cell), + T_INT((int)pusch_pdu->rnti), + T_INT((int)pusch_pdu->rb_size), + T_INT((int)pusch_pdu->rb_start), + T_INT((int)pusch_pdu->start_symbol_index), // start_ofdm_symbol + T_INT((int)pusch_pdu->nr_of_symbols), // num_ofdm_symbols + T_INT((int)pusch_pdu->qam_mod_order), // modulation + T_INT((int)pusch_pdu->mcs_index), // mcs + T_INT((int)pusch_pdu->mcs_table), // mcs_table_index + T_INT((int)pusch_pdu->nrOfLayers), // num_layer + T_INT((int)pusch_pdu->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1 + T_INT((int)pusch_pdu->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1 + T_INT((int)pusch_pdu->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions + T_INT((int)number_dmrs_symbols), + // dmrs_start_ofdm_symbol + // dmrs_duration_num_ofdm_symbols + // dmrs_num_add_positions + T_INT((int)dmrs_port), // dmrs_antenna_port + T_INT((int)pusch_pdu->scid), // dmrs_nscid + T_INT((int)frame_parms->nb_antennas_tx), // number of tx antennas + T_INT((int)available_bits), // number_of_bits + T_BUFFER((uint8_t *)in_bytes, available_bits / 8)); + } +#endif /////////////////////////ULSCH modulation///////////////////////// int max_num_re = Nl * number_of_symbols * nb_rb * NR_NB_SC_PER_RB; @@ -830,19 +1509,21 @@ uint8_t nr_ue_pusch_common_procedures(PHY_VARS_NR_UE *UE, c16_t **txdataF, c16_t **txdata, uint32_t linktype, - bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]) + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT], + bool no_phase_pre_comp) { int N_RB = (linktype == link_type_sl) ? frame_parms->N_RB_SL : frame_parms->N_RB_UL; - for (int i = 0; i < NR_NUMBER_OF_SYMBOLS_PER_SLOT; i++) { - if (was_symbol_used[i] == false) - continue; - for (int ap = 0; ap < n_antenna_ports; ap++) { - apply_nr_rotation_TX(frame_parms, txdataF[ap], frame_parms->symbol_rotation[linktype], slot, N_RB, i, 1); + if (!no_phase_pre_comp) { + for (int i = 0; i < NR_NUMBER_OF_SYMBOLS_PER_SLOT; i++) { + if (was_symbol_used[i] == false) + continue; + for (int ap = 0; ap < n_antenna_ports; ap++) { + apply_nr_rotation_TX(frame_parms, txdataF[ap], frame_parms->symbol_rotation[linktype], slot, N_RB, i, 1); + } } } - for (int ap = 0; ap < n_antenna_ports; ap++) { if (frame_parms->Ncp == 1) { // extended cyclic prefix for (int i = 0; i < NR_NUMBER_OF_SYMBOLS_PER_SLOT_EXTENDED_CP; i++) { diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c index c73af09eef..b6b20cefaf 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.c @@ -485,13 +485,52 @@ void nr_generate_pucch1(const PHY_VARS_NR_UE *ue, } } +// Calculate number of DMRS symbols for PUCCH formats 3 and 4 +static uint8_t nr_pucch_get_dmrs_symbols(uint8_t nrofSymbols, uint8_t add_dmrs) +{ + if (nrofSymbols == 4) { + return 1; + } else if (nrofSymbols > 4 && nrofSymbols <= 9) { + return 2; + } else if (nrofSymbols > 9) { + return (add_dmrs == 0) ? 2 : 4; + } + return 0; +} + +// Calculate PUCCH format 2/3/4 rate matching output sequence length according to TS 38.212 Table 6.3.1.4-1 +static uint16_t nr_pucch_output_sequence_length(uint8_t format_type, + uint8_t nrofSymbols, + uint16_t nrofPRB, + uint8_t n_SF_PUCCH_s, + uint8_t is_pi_over_2_bpsk_enabled, + uint8_t add_dmrs) +{ + uint16_t M_bit = 0; + + if (format_type == 2) { + M_bit = 16 * nrofSymbols * nrofPRB; + } else if (format_type == 3) { + uint16_t E_init = (is_pi_over_2_bpsk_enabled == 0) ? 24 : 12; + uint8_t num_dmrs_symbols = nr_pucch_get_dmrs_symbols(nrofSymbols, add_dmrs); + M_bit = E_init * (nrofSymbols - num_dmrs_symbols) * nrofPRB / n_SF_PUCCH_s; + } else if (format_type == 4) { + nrofPRB = 1; + uint16_t E_init = (is_pi_over_2_bpsk_enabled == 0) ? 24 : 12; + uint8_t num_dmrs_symbols = nr_pucch_get_dmrs_symbols(nrofSymbols, add_dmrs); + M_bit = E_init * (nrofSymbols - num_dmrs_symbols) * nrofPRB / n_SF_PUCCH_s; + } + + return M_bit; +} + static inline void nr_pucch2_3_4_scrambling(uint16_t M_bit, uint16_t rnti, uint16_t n_id, uint64_t *B64, uint8_t *btilde) { // c_init=nRNTI*2^15+n_id according to TS 38.211 Subclause 6.3.2.6.1 const int roundedSz = (M_bit + 31) / 32; uint32_t *seq = gold_cache((rnti << 15) + n_id, roundedSz); #ifdef DEBUG_NR_PUCCH_TX - printf("\t\t [nr_pucch2_3_4_scrambling] gold sequence s=%x, M_bit %d\n",s,M_bit); + printf("\t\t [nr_pucch2_3_4_scrambling] gold sequence s=%x, M_bit %d\n", *seq, M_bit); #endif uint8_t *btildep = btilde; @@ -506,7 +545,12 @@ static inline void nr_pucch2_3_4_scrambling(uint16_t M_bit, uint16_t rnti, uint1 uint8_t c = (uint8_t)((s >> i) & 1); btildep[i] = (((B>>i)&1) ^ c); #ifdef DEBUG_NR_PUCCH_TX - printf("\t\t\t btilde[%d]=%x from unscrambled bit %d and scrambling %d (%x)\n",i+(iprime<<5),btilde[i],((B>>i)&1),c,s>>i); + printf("\t\t\t btilde[%d]=%x from unscrambled bit %u and scrambling %d (%x)\n", + i + (iprime << 5), + btilde[i], + ((B >> i) & 1), + c, + s >> i); #endif } } @@ -515,101 +559,143 @@ static inline void nr_pucch2_3_4_scrambling(uint16_t M_bit, uint16_t rnti, uint1 printf("\t\t [nr_pucch2_3_4_scrambling] scrambling M_bit=%d bits\n", M_bit); #endif } -static void nr_uci_encoding(uint64_t payload, - uint8_t nr_bit, - int fmt, - uint8_t is_pi_over_2_bpsk_enabled, - uint8_t nrofSymbols, - uint8_t nrofPRB, - uint8_t n_SF_PUCCH_s, - uint8_t intraSlotFrequencyHopping, - uint8_t add_dmrs, - uint64_t *b, - uint16_t *M_bit) { + +void nr_uci_encoding(uint64_t payload, uint8_t nr_bit, uint8_t nrofPRB, bool uci_on_pusch, uint16_t E, uint8_t Qm, uint64_t *b) +{ /* - * Implementing TS 38.212 Subclause 6.3.1.2 + * Implementing TS 38.212 Subclause 6.3.1.2 and 6.3.2 * */ // A is the payload size, to be provided in function call uint8_t A = nr_bit; // L is the CRC size - //uint8_t L; + // uint8_t L; // E is the rate matching output sequence length as given in TS 38.212 subclause 6.3.1.4.1 - uint16_t E=0,E_init; - - if (fmt == 2) E = 16*nrofSymbols*nrofPRB; - - if (fmt == 3) { - E_init = (is_pi_over_2_bpsk_enabled == 0) ? 24:12; - - if (nrofSymbols == 4) { - E = (intraSlotFrequencyHopping == 0)?(E_init*(nrofSymbols-1)*nrofPRB):((E_init*(nrofSymbols-1)*nrofPRB)); + // int I_seg; #ifdef DEBUG_NR_PUCCH_TX - printf("format 3 nrofSymbols =4 and E_init=%d,E=%d\n",E_init,E); + printf("\t\t [nr_uci_encoding] start function with encoding A=%d bits into M_bit=%d (where nrofPRB=%d)\n", A, E, nrofPRB); #endif - } - if (nrofSymbols > 4) { - E = E_init*(nrofSymbols-2)*nrofPRB; -#ifdef DEBUG_NR_PUCCH_TX - printf("format 3 nrofSymbols >4 and E_init=%d,E = %d\n",E_init,E); -#endif - } + // For A=1 case (single bit UCI) + if (A == 1) { + uint8_t uci_bit_val = payload & 1; // Extract the single UCI bit + uint64_t pattern_word; + uint8_t *b_bytes = (uint8_t *)b; // Access b as bytes to set individual special values - if (nrofSymbols > 9) { - E = (add_dmrs == 0)?(E_init*(nrofSymbols-2)*nrofPRB):((E_init*(nrofSymbols-4)*nrofPRB)); -#ifdef DEBUG_NR_PUCCH_TX - printf("format 3 nrofSymbols >9 and E_init=%d,E = %d\n",E_init,E); -#endif + if (Qm == 1) { + // For BPSK, just repeat the input bit + pattern_word = uci_bit_val ? 0xFFFFFFFFFFFFFFFFULL : 0x0000000000000000ULL; + for (int i = 0; i < 8; i++) { + b[i] = pattern_word; + } + } else { + // For higher order modulation (QPSK, etc.), use placeholder values + memset(b, 0, 8 * sizeof(uint64_t)); + + // Fill the entire output with the pattern + for (int i = 0; i < E; i++) { + switch (i % Qm) { + case 0: + // First bit in each group is actual UCI bit + b_bytes[i] = uci_bit_val; + LOG_D(PHY, + "[UCI_ENCODING_A1_QAM_LOOP] i=%d, i%%Qm=%d (case 0), writing uci_bit_val %d to b_bytes[%d]\n", + i, + i % Qm, + uci_bit_val, + i); + break; + case 1: + b_bytes[i] = NR_PUSCH_y; + LOG_D(PHY, + "[UCI_ENCODING_A1_QAM_LOOP] i=%d, i%%Qm=%d (case 1), writing NR_PUSCH_y (0x%02X) to b_bytes[%d]\n", + i, + i % Qm, + NR_PUSCH_y, + i); + break; + default: + b_bytes[i] = NR_PUSCH_x; + break; + } + } } } + // For A=2 case (two bits UCI) + else if (A == 2) { + uint8_t bit0 = (payload >> 0) & 1; + uint8_t bit1 = (payload >> 1) & 1; + uint8_t c2 = bit0 ^ bit1; // Parity bit (XOR of the two bits) + uint8_t *b_bytes = (uint8_t *)b; - if (fmt == 4) { - E_init = (is_pi_over_2_bpsk_enabled == 0) ? 24:12; + if (Qm == 1) { + // For BPSK, output is [bit0, bit1, c2] + uint64_t pattern = (bit0) | (bit1 << 1) | (c2 << 2); + // Repeat this 3-bit pattern to fill the output + pattern |= pattern << 3; + pattern |= pattern << 6; + pattern |= pattern << 12; + pattern |= pattern << 24; + pattern |= pattern << 48; - if (nrofSymbols == 4) { - E = (intraSlotFrequencyHopping == 0)?(E_init*(nrofSymbols-1)/n_SF_PUCCH_s):((E_init*(nrofSymbols-1)/n_SF_PUCCH_s)); -#ifdef DEBUG_NR_PUCCH_TX - printf("format 4 nrofSymbols =4 and E_init=%d,E=%d\n",E_init,E); -#endif + for (int i = 0; i < 8; i++) { + b[i] = pattern; + } + } else { + // For higher order modulation (Qm>=2), using patterns from Table 5.3.3.2-1 + // Pattern: 3 groups of Qm bits each = 3*Qm total length + memset(b, 0, 8 * sizeof(uint64_t)); + + for (int i = 0; i < E; i++) { + int pos_in_pattern = i % (3 * Qm); + int group = pos_in_pattern / Qm; + int pos_in_group = pos_in_pattern % Qm; + uint8_t val_to_write; + + if (pos_in_group == 0) { + if (group == 0) + val_to_write = bit0; + else if (group == 1) + val_to_write = c2; + else + val_to_write = bit1; + } else if (pos_in_group == 1) { + if (group == 0) + val_to_write = bit1; + else if (group == 1) + val_to_write = bit0; + else + val_to_write = c2; + } else { + // Positions 2 and beyond are x placeholders + val_to_write = NR_PUSCH_x; + } + + b_bytes[i] = val_to_write; + } } - - if (nrofSymbols > 4) { - E = E_init*(nrofSymbols-2)/n_SF_PUCCH_s; -#ifdef DEBUG_NR_PUCCH_TX - printf("format 4 nrofSymbols >4 and E_init=%d,E = %d\n",E_init,E); -#endif - } - - if (nrofSymbols > 9) { - E = (add_dmrs == 0)?(E_init*(nrofSymbols-2)/n_SF_PUCCH_s):((E_init*(nrofSymbols-4)/n_SF_PUCCH_s)); -#ifdef DEBUG_NR_PUCCH_TX - printf("format 4 nrofSymbols >9 and E_init=%d,E = %d\n",E_init,E); -#endif - } - } - - *M_bit = E; - //int I_seg; -#ifdef DEBUG_NR_PUCCH_TX - printf("\t\t [nr_uci_encoding] start function with fmt=%d, encoding A=%d bits into M_bit=%d (where nrofSymbols=%d,nrofPRB=%d)\n",fmt,A,*M_bit,nrofSymbols,nrofPRB); -#endif - - if (A<=11) { + } else if (A <= 11) { // procedure in subclause 6.3.1.2.2 (UCI encoded by channel coding of small block lengths -> subclause 6.3.1.3.2) // CRC bits are not attached, and coding small block lengths (subclause 5.3.3) uint64_t b0 = encodeSmallBlock(payload, A); - // repetition for rate-matching up to 16 PRB - b[0] = b0 | (b0<<32); - b[1] = b[0]; - b[2] = b[0]; - b[3] = b[0]; - b[4] = b[0]; - b[5] = b[0]; - b[6] = b[0]; - b[7] = b[0]; - AssertFatal(nrofPRB<=16,"Number of PRB >16\n"); - } else if (A>=12) { + if (uci_on_pusch) { + b[0] = b0; + for (int i = 1; i < 8; i++) { + b[i] = 0; + } + } else { + // repetition for rate-matching up to 16 PRB + b[0] = b0 | (b0<<32); + b[1] = b[0]; + b[2] = b[0]; + b[3] = b[0]; + b[4] = b[0]; + b[5] = b[0]; + b[6] = b[0]; + b[7] = b[0]; + AssertFatal(nrofPRB<=16,"Number of PRB >16\n"); + } + } else if (A >= 12) { // Encoder reversal payload = reverse_bits(payload, A); @@ -618,7 +704,52 @@ static void nr_uci_encoding(uint64_t payload, A, nrofPRB); } - + + if (uci_on_pusch) { + // Rate matching for HARQ ACK following 38.212 section 5.4.3 + uint64_t output[8] = {0}; // Assuming max 512 bits (8 words of 64 bits) + uint16_t N; + if (nr_bit <= 2) { + // For A=1 (BPSK), N=1. For A=2 (QPSK), N=3 + N = (nr_bit == 1) ? 1 : 3; + } else if (nr_bit <= 11) { + // For 3 <= A <= 11, the small block encoder produces a 32-bit codeword + N = 32; + } else { + // For polar-coded UCI, output depends on nrofPRB + N = 16 * nrofPRB; + } + + if ((nr_bit == 1 || nr_bit == 2) && Qm > 1) { + LOG_D(PHY, + "[UCI_ENCODING_RM] Bypassing bit-wise rate matching for A=%d, Qm=%d. 'b' (length %d bytes) is assumed to be already " + "final.\n", + nr_bit, + Qm, + E); + } else { + if (N == 0) { + LOG_W(PHY, "HARQ-ACK rate matching with encoded_length=0 but E_uci_ack=%d\n", E); + return; + } + + // Rate matching with single loop for both repetition and puncturing + for (int i = 0; i < E; i++) { + int src_bit = i % N; // Modulo for cyclic repetition + int src_word = src_bit / 64; + int src_bit_pos = src_bit % 64; + int dst_word = i / 64; + int dst_bit_pos = i % 64; + + if ((b[src_word] >> src_bit_pos) & 1ULL) + output[dst_word] |= (1ULL << dst_bit_pos); + } + + for (int i = 0; i < (E + 63) / 64; i++) { + b[i] = output[i]; + } + } + } } //#if 0 void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, @@ -634,13 +765,8 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, // b is the block of bits transmitted on the physical channel after payload coding uint64_t b[16] = {0}; // limit to 1024-bit encoded length // M_bit is the number of bits of block b (payload after encoding) - uint16_t M_bit = 0; - nr_uci_encoding(pucch_pdu->payload, - pucch_pdu->n_bit, - 2,0, - pucch_pdu->nr_of_symbols, - pucch_pdu->prb_size, - 1,0,0,&b[0],&M_bit); + uint16_t M_bit = nr_pucch_output_sequence_length(pucch_pdu->format_type, pucch_pdu->nr_of_symbols, pucch_pdu->prb_size, 0, 0, 0); + nr_uci_encoding(pucch_pdu->payload, pucch_pdu->n_bit, pucch_pdu->prb_size, false, M_bit, 0, &b[0]); /* * Implementing TS 38.211 * Subclauses 6.3.2.5.1 Scrambling (PUCCH format 2) @@ -718,9 +844,10 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, temp_x2 *= 14UL * nr_slot_tx + l + startingSymbolIndex + 1; temp_x2 *= 2UL * pucch_pdu->dmrs_scrambling_id + 1; temp_x2 = (temp_x2 + 2ULL * pucch_pdu->dmrs_scrambling_id) % (1UL << 31); - uint idxGold = startingPRB >> 2; - uint32_t *seq = gold_cache(temp_x2, idxGold + pucch_pdu->prb_size); - int m = 0; + uint32_t idxGold = startingPRB * NR_PUCCH_DMRS_RB * DMRS_MOD_ORDER / 32; + uint32_t m = (startingPRB * NR_PUCCH_DMRS_RB * DMRS_MOD_ORDER) % 32; + const int seq_sz = ((startingPRB + pucch_pdu->prb_size) * NR_PUCCH_DMRS_RB * DMRS_MOD_ORDER + 31) / 32; + uint32_t *seq = gold_cache(temp_x2, seq_sz); for (int rb=0; rbprb_size; rb++) { //startingPRB = startingPRB + rb; const bool nb_rb_is_even = frame_parms->N_RB_DL & 1; @@ -757,15 +884,14 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, txdataF[0][re_offset] = d[outSample + k]; #ifdef DEBUG_NR_PUCCH_TX printf( - "\t [nr_generate_pucch2] (n=%d,i=%d) mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d " + "\t [nr_generate_pucch2] (n=%d) mapping PUCCH to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d " "\tfirst_carrier_offset=%d \tz_pucch[%d]=txptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n", n, - i, amp, frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, frame_parms->first_carrier_offset, - i + k, + k, re_offset, l, n, @@ -776,20 +902,19 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, } if (n%3 == 1) { // mapping DM-RS signal according to TS38.211 subclause 6.4.1.3.2 - txdataF[0][re_offset].r = (int16_t)(baseVal * (1 - (2 * ((uint8_t)((seq[idxGold] >> (2 * m)) & 1))))); - txdataF[0][re_offset].i = (int16_t)(baseVal * (1 - (2 * ((uint8_t)((seq[idxGold] >> (2 * m + 1)) & 1))))); - m++; + txdataF[0][re_offset].r = (int16_t)(baseVal * (1 - (2 * ((uint8_t)((seq[idxGold] >> (m)) & 1))))); + txdataF[0][re_offset].i = (int16_t)(baseVal * (1 - (2 * ((uint8_t)((seq[idxGold] >> (m + 1)) & 1))))); + m += 2; #ifdef DEBUG_NR_PUCCH_TX printf( - "\t [nr_generate_pucch2] (n=%d,i=%d) mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d " + "\t [nr_generate_pucch2] (n=%d) mapping DM-RS to RE \t amp=%d \tofdm_symbol_size=%d \tN_RB_DL=%d " "\tfirst_carrier_offset=%d \tz_dm-rs[%d]=txptr(%d)=(x_n(l=%d,n=%d)=(%d,%d))\n", n, - i, amp, frame_parms->ofdm_symbol_size, frame_parms->N_RB_DL, frame_parms->first_carrier_offset, - i + kk, + kk, re_offset, l, n, @@ -804,7 +929,7 @@ void nr_generate_pucch2(const PHY_VARS_NR_UE *ue, outSample += 8; - if (m % 16 == 0) { + if (m % 32 == 0) { idxGold++; m = 0; } @@ -825,7 +950,7 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, // b is the block of bits transmitted on the physical channel after payload coding uint64_t b[16]; // M_bit is the number of bits of block b (payload after encoding) - uint16_t M_bit; + uint16_t M_bit = 0; // parameter PUCCH-F4-preDFT-OCC-length set of {2,4} -> to use table -1 or -2 // in format 4, n_SF_PUCCH_s = {2,4}, provided by higher layer parameter PUCCH-F4-preDFT-OCC-length (in format 3 n_SF_PUCCH_s=1) uint8_t n_SF_PUCCH_s; @@ -852,17 +977,14 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, uint16_t startingPRB = pucch_pdu->prb_start + pucch_pdu->bwp_start; uint8_t add_dmrs = pucch_pdu->add_dmrs_flag; - nr_uci_encoding(pucch_pdu->payload, - pucch_pdu->n_bit, - pucch_pdu->format_type, - is_pi_over_2_bpsk_enabled, - nrofSymbols, - nrofPRB, - n_SF_PUCCH_s, - intraSlotFrequencyHopping, - add_dmrs, - b, - &M_bit); + M_bit = nr_pucch_output_sequence_length(pucch_pdu->format_type, + nrofSymbols, + nrofPRB, + n_SF_PUCCH_s, + is_pi_over_2_bpsk_enabled, + add_dmrs); + + nr_uci_encoding(pucch_pdu->payload, pucch_pdu->n_bit, nrofPRB, false, M_bit, 0, b); /* * Implementing TS 38.211 * Subclauses 6.3.2.6.1 Scrambling (PUCCH formats 3 and 4) diff --git a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h index 54620f1ba0..1f24b589f4 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h +++ b/openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h @@ -72,318 +72,9 @@ void nr_generate_pucch3_4(const PHY_VARS_NR_UE *ue, const int nr_slot_tx, const fapi_nr_ul_config_pucch_pdu *pucch_pdu); -// tables for mcs values for different payloads - static const uint8_t table1_mcs[]={0,6,3,9}; - static const uint8_t table2_mcs[]={0,3,9,6,1,4,10,7}; +void nr_uci_encoding(uint64_t payload, uint8_t nr_bit, uint8_t nrofPRB, bool uci_on_pusch, uint16_t E, uint8_t Qm, uint64_t *b); - /* - * The following tables implement TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (rows->u {0,1,..,29} / columns->n {0,1,...,M_ZC-1) - * Where base sequence r_u_v(n)=exp[j*phi(n)*pi/4] 0<=n<=M_ZC-1 and M_ZC={6,12,18,24} - * For M_ZC=30, base sequence r_u_v(n)=exp[-j((pi*[u+1]*[n+1]*[n+2])/31)] - */ - static const int16_t table_5_2_2_2_1_Re[30][6]={ // Table 5.2.2.2-1 (Re part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=6) - {-23170, 23170,-23170,-23170, 23170,-23170}, - {-23170,-23170, 23170, 23170,-23170,-23170}, - {-23170,-23170,-23170,-23170, 23170,-23170}, - { 23170, 23170, 23170,-23170, 23170,-23170}, - { 23170, 23170, 23170,-23170, 23170,-23170}, - {-23170, 23170, 23170,-23170,-23170,-23170}, - {-23170, 23170,-23170,-23170,-23170,-23170}, - {-23170, 23170, 23170,-23170, 23170, 23170}, - {-23170, 23170,-23170, 23170,-23170,-23170}, - {-23170,-23170, 23170,-23170,-23170,-23170}, - {-23170, 23170,-23170, 23170,-23170,-23170}, - {-23170, 23170,-23170, 23170, 23170,-23170}, - { 23170, 23170,-23170, 23170,-23170,-23170}, - { 23170, 23170,-23170,-23170, 23170,-23170}, - { 23170, 23170, 23170,-23170,-23170, 23170}, - { 23170, 23170, 23170, 23170,-23170,-23170}, - {-23170, 23170, 23170, 23170,-23170, 23170}, - {-23170,-23170, 23170, 23170, 23170,-23170}, - {-23170,-23170,-23170, 23170,-23170, 23170}, - {-23170, 23170, 23170,-23170, 23170,-23170}, - {-23170,-23170,-23170, 23170, 23170,-23170}, - {-23170, 23170,-23170,-23170,-23170, 23170}, - { 23170, 23170,-23170,-23170, 23170,-23170}, - { 23170, 23170,-23170,-23170, 23170,-23170}, - { 23170, 23170,-23170, 23170,-23170,-23170}, - { 23170, 23170,-23170, 23170,-23170,-23170}, - { 23170, 23170, 23170, 23170,-23170, 23170}, - { 23170, 23170, 23170,-23170, 23170, 23170}, - { 23170, 23170, 23170,-23170,-23170, 23170}, - { 23170, 23170,-23170, 23170, 23170, 23170} - }; - static const int16_t table_5_2_2_2_1_Im[30][6]={ // Table 5.2.2.2-1 (Im part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=6) - {-23170,-23170, 23170, 23170,-23170,-23170}, - {-23170, 23170,-23170,-23170, 23170,-23170}, - {-23170,-23170,-23170, 23170, 23170,-23170}, - { 23170, 23170, 23170, 23170,-23170,-23170}, - { 23170, 23170, 23170,-23170,-23170, 23170}, - {-23170, 23170,-23170,-23170,-23170,-23170}, - {-23170, 23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170,-23170, 23170,-23170}, - {-23170,-23170,-23170, 23170,-23170,-23170}, - {-23170,-23170, 23170,-23170, 23170,-23170}, - {-23170, 23170, 23170, 23170,-23170,-23170}, - {-23170,-23170,-23170, 23170, 23170,-23170}, - { 23170, 23170, 23170,-23170,-23170, 23170}, - { 23170, 23170, 23170, 23170,-23170, 23170}, - { 23170, 23170, 23170,-23170, 23170,-23170}, - { 23170, 23170, 23170,-23170, 23170,-23170}, - {-23170,-23170,-23170,-23170, 23170,-23170}, - {-23170,-23170,-23170, 23170,-23170,-23170}, - {-23170,-23170,-23170, 23170,-23170,-23170}, - {-23170, 23170, 23170,-23170,-23170,-23170}, - {-23170, 23170,-23170, 23170, 23170,-23170}, - {-23170, 23170,-23170,-23170,-23170,-23170}, - { 23170, 23170,-23170, 23170, 23170, 23170}, - { 23170, 23170,-23170,-23170, 23170,-23170}, - { 23170, 23170, 23170,-23170, 23170, 23170}, - { 23170, 23170,-23170, 23170, 23170, 23170}, - { 23170, 23170,-23170,-23170, 23170,-23170}, - { 23170, 23170,-23170, 23170,-23170,-23170}, - { 23170, 23170,-23170, 23170,-23170,-23170}, - { 23170, 23170,-23170, 23170,-23170,-23170} - }; - static const int16_t table_5_2_2_2_2_Re[30][12]={ // Table 5.2.2.2-2 (Re part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=12) - {-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170}, - {-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, - {-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170}, - {-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, - {-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170}, - {-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170}, - { 23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170}, - { 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170}, - {-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170}, - {-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170}, - {-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170}, - {-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, - {-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170}, - {-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170}, - { 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170}, - {-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170}, - { 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170}, - { 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170}, - {-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170}, - {-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170}, - {-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170}, - {-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170}, - {-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170}, - {-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170}, - {-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170}, - { 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170}, - {-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170}, - { 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170}, - {-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170} - }; - static const int16_t table_5_2_2_2_2_Im[30][12]={ // Table 5.2.2.2-2 (Im part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=12) - {-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170}, - {-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170}, - {-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170}, - {-23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170}, - {-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170}, - {-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170}, - { 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, - {-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170}, - {-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170}, - {-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170}, - {-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, - {-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170}, - {-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170}, - {-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170}, - { 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170}, - {-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, - {-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170}, - {-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170}, - {-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170}, - {-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170}, - { 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170}, - {-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170}, - {-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, - { 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170}, - {-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170}, - {-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170}, - {-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170}, - { 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170}, - {-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170} - }; - static const int16_t table_5_2_2_2_3_Re[30][18]={ // Table 5.2.2.2-3 (Re part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=18) - { 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170}, - {-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170}, - {-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170}, - { 23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170}, - {-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170}, - {-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170}, - { 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170}, - {-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, - {-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, - {-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170}, - {-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170}, - {-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170}, - { 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170}, - {-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170}, - {-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, - {-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170}, - {-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170}, - {-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170}, - {-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170}, - {-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, - { 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170}, - {-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170}, - {-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170}, - {-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170}, - {-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, - { 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170}, - {-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170} - }; - static const int16_t table_5_2_2_2_3_Im[30][18]={ // Table 5.2.2.2-3 (Im part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=18) - {-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, - { 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170}, - {-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170}, - { 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170}, - { 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170}, - {-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170}, - { 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170}, - {-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170}, - { 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170}, - {-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170}, - {-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170}, - {-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170}, - { 23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170}, - {-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170}, - { 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170}, - {-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170}, - {-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170}, - {-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170}, - { 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170}, - {-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170}, - { 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170}, - {-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170}, - { 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170}, - { 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170}, - {-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170}, - {-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170}, - {-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170}, - {-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170} - }; - static const int16_t table_5_2_2_2_4_Re[30][24]={ // Table 5.2.2.2-4 (Re part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=24) - { 23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170}, - { 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, - { 23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170}, - { 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170}, - { 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170}, - {-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170}, - {-23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170}, - {-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170}, - {-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170}, - { 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170}, - {-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170}, - {-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170}, - {-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170}, - {-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170}, - {-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170}, - {-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170}, - {-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170}, - {-23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170}, - {-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170}, - {-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170}, - {-23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170}, - {-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170}, - {-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170}, - {-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, - {-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170}, - {-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170}, - { 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170}, - {-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170}, - {-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170}, - {-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170} - }; - static const int16_t table_5_2_2_2_4_Im[30][24]={ // Table 5.2.2.2-4 (Im part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=24) - {-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170}, - {-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170}, - { 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, - {-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170}, - {-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, - {-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170}, - {-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, - {-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170}, - { 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170}, - {-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170}, - {-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170}, - { 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170}, - {-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170}, - {-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170}, - {-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170}, - {-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170}, - { 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170}, - {-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170}, - {-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170}, - {-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170}, - { 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, - {-23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170}, - {-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170}, - {-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, - {-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170}, - {-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170}, - { 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170}, - {-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170}, - { 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170} - }; - - /* - * The following tables implement TS 38.211 table 6.3.2.4.1-1: Number of PUCCH symbols and the corresponding N_SF_mprime_PUCCH_1 - * One table for no intra-slot hopping - * Two tables for intra-slot hopping (mprime=0 and mprime=1) - */ - static const uint8_t table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[14] = {0,0,0,2,2,3,3,4,4,5,5,6,6,7}; // for index PUCCH-length, we obtain N_SF_mprime_PUCCH_1 when no intra-slot hopping - static const uint8_t table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[14] = {0,0,0,1,1,1,1,2,2,2,2,3,3,3}; // for index PUCCH-length, we obtain N_SF_mprime_PUCCH_1 when intra-slot hopping and mprime=0 - static const uint8_t table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m1Hop[14] = {0,0,0,1,1,2,2,2,2,3,3,3,3,4}; // for index PUCCH-length, we obtain N_SF_mprime_PUCCH_1 when intra-slot hopping and mprime=1 - /* - * The following tables implement TS 38.211 table 6.4.1.3.1.1-1: Number of DM-RS symbols and the corresponding N_SF_mprime_PUCCH_1 - * One table for no intra-slot hopping - * Two tables for intra-slot hopping (mprime=0 and mprime=1) - */ - static const uint8_t table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[14] = {0,0,0,2,3,3,4,4,5,5,6,6,7,7}; // for index PUCCH-DM-RS-length, we obtain N_SF_mprime_PUCCH_1 when no intra-slot hopping - static const uint8_t table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[14] = {0,0,0,1,1,2,2,2,2,3,3,3,3,4}; // for index PUCCH-DM-RS-length, we obtain N_SF_mprime_PUCCH_1 when intra-slot hopping and mprime=0 - static const uint8_t table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m1Hop[14] = {0,0,0,1,2,1,2,2,3,2,3,3,4,3}; // for index PUCCH-DM-RS-length, we obtain N_SF_mprime_PUCCH_1 when intra-slot hopping and mprime=1 - /* The following tables implement TS 38.211 table 6.3.2.4.1-2: Orthogonal sequences wi(m)=exp(j*2*pi*phi(m)/N_SF) for PUCCH format 1 - uint16_t table_6_3_2_4_1_2_W2[2][2] = {{0,0}, {0,1}}; - uint16_t table_6_3_2_4_1_2_W3[3][3] = {{0,0,0}, {0,1,2}, {0,2,1}}; - uint16_t table_6_3_2_4_1_2_W4[4][4] = {{0,0,0,0}, {0,2,0,2}, {0,0,2,2} , {0,2,2,0}}; - uint16_t table_6_3_2_4_1_2_W5[2][2] = {{0,0,0,0,0}, {0,1,2,3,4}, {0,2,4,1,3}, {0,3,1,4,2}, {0,4,3,2,1}}; - uint16_t table_6_3_2_4_1_2_W6[2][2] = {{0,0,0,0,0,0}, {0,1,2,3,4,5}, {0,2,4,0,2,4}, {0,3,0,3,0,3}, {0,4,2,0,4,2}, {0,5,4,3,2,1}}; - uint16_t table_6_3_2_4_1_2_W7[2][2] = {{0,0,0,0,0,0,0},{0,1,2,3,4,5,6},{0,2,4,6,1,3,5},{0,3,6,2,5,1,4},{0,4,1,5,2,6,3},{0,5,3,1,6,4,2},{0,6,5,4,3,2,1}}; - */ - static const int16_t table_6_3_2_4_1_2_Wi_Re[8][7][7] = { - {{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{32767,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{32767,32767,0,0,0,0,0}, {32767,-32767,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{32767,32767,32767,0,0,0,0}, {32767,-16384,-16384,0,0,0,0}, {32767,-16384,-16384,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{32767,32767,32767,32767,0,0,0}, {32767,-32767,32767,-32767,0,0,0}, {32767,32767,-32767,-32767,0,0,0}, {32767,-32767,-32767,32767,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{32767,32767,32767,32767,32767,0,0}, {32767,10126,-26509,-26509,10126,0,0}, {32767,-26509,10126,10126,-26509,0,0}, {32767,-26509,10126,10126,-26509,0,0}, {32767,10126,-26509,-26509,10126,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{32767,32767,32767,32767,32767,32767,0}, {32767,16384,-16384,-32767,-16384,16384,0}, {32767,-16384,-16384,32767,-16384,-16384,0}, {32767,-32767,32767,-32767,32767,-32767,0}, {32767,-16384,-16384,32767,-16384,-16384,0}, {32767,16384,-16384,-32767,-16384,16384,0}, {0,0,0,0,0,0,0}}, - {{32767,32767,32767,32767,32767,32767,32767},{32767,20430,-7291,-29522,-29522,-7291,20430},{32767,-7291,-29522,20430,20430,-29522,-7291},{32767,-29522,20430,-7291,-7291,20430,-29522},{32767,-29522,20430,-7291,-7291,20430,-29522},{32767,-7291,-29522,20430,20430,-29522,-7291},{32767,20430,-7291,-29522,-29522,-7291,20430}} - }; - static const int16_t table_6_3_2_4_1_2_Wi_Im[8][7][7] = { - {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{0,0,0,0,0,0,0},{0,28377,-28377,0,0,0,0}, {0,-28377,28377,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{0,0,0,0,0,0,0},{0,31163,19260,-19260,-31163,0,0}, {0,19260,-31163,31163,-19260,0,0}, {0,-19260,31163,-31163,19260,0,0}, {0,-31163,-19260,19260,31163,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, - {{0,0,0,0,0,0,0},{0,28377,28377,0,-28377,-28377,0}, {0,28377,-28377,0,28377,-28377,0}, {0,0,0,0,0,0,0}, {0,-28377,28377,0,-28377,28377,0}, {0,-28377,-28377,0,28377,28377,0}, {0,0,0,0,0,0,0}}, - {{0,0,0,0,0,0,0},{0,25618,31945,14217,-14217,-31945,-25618},{0,31945,-14217,-25618,25618,14217,-31945},{0,14217,-25618,31945,-31945,25618,-14217},{0,-14217,25618,-31945,31945,-25618,14217},{0,-31945,14217,25618,-25618,-14217,31945},{0,-25618,-31945,-14217,14217,31945,25618}} - }; - - static const uint8_t list_of_prime_numbers[46] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, +static const uint8_t list_of_prime_numbers[46] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,103,107,109,113, 127,131,137,139,149,151,157,163,167,173, diff --git a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c deleted file mode 100644 index 44be6a578e..0000000000 --- a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * 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 - */ - -/*********************************************************************** -* -* FILENAME : srs_modulation_nr_nr.c -* -* MODULE : -* -* DESCRIPTION : function to set uplink reference symbols -* see TS 38211 6.4.1.4 Sounding reference signal -* -************************************************************************/ - -#include -#include - -#include "PHY/impl_defs_nr.h" -#include "PHY/defs_nr_UE.h" -#include "PHY/NR_REFSIG/ss_pbch_nr.h" -#include "PHY/NR_REFSIG/dmrs_nr.h" -#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" - -#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h" -//#define SRS_DEBUG - - -uint16_t group_number_hopping(int slot_number, - uint8_t n_ID_SRS, - uint8_t l0, - uint8_t l_line) { - - // Pseudo-random sequence c(i) defined by TS 38.211 - Section 5.2.1 - uint32_t cinit = n_ID_SRS; - uint8_t c_last_index = 8 * (slot_number * N_SYMB_SLOT + l0 + l_line) + 7; - uint32_t *c_sequence = calloc(c_last_index+1, sizeof(uint32_t)); - pseudo_random_sequence(c_last_index+1, c_sequence, cinit); - - // TS 38.211 - 6.4.1.4.2 Sequence generation - uint32_t f_gh = 0; - for (int m = 0; m <= 7; m++) { - f_gh += c_sequence[8 * (slot_number * N_SYMB_SLOT + l0 + l_line) + m] << m; - } - f_gh = f_gh%30; - uint8_t u = (f_gh + n_ID_SRS)%U_GROUP_NUMBER; - - free(c_sequence); - return u; -} - -uint16_t sequence_number_hopping(int slot_number, - uint8_t n_ID_SRS, - uint16_t M_sc_b_SRS, - uint8_t l0, - uint8_t l_line) { - uint16_t v = 0; - if (M_sc_b_SRS > 6 * NR_NB_SC_PER_RB) { - // Pseudo-random sequence c(i) defined by TS 38.211 - Section 5.2.1 - uint32_t cinit = n_ID_SRS; - uint8_t c_last_index = (slot_number * N_SYMB_SLOT + l0 + l_line); - uint32_t *c_sequence = calloc(c_last_index+1, sizeof(uint32_t)); - pseudo_random_sequence(c_last_index+1, c_sequence, cinit); - // TS 38.211 - 6.4.1.4.2 Sequence generation - v = c_sequence[c_last_index]; - free(c_sequence); - } - return v; -} - -uint16_t compute_F_b(frame_t frame_number, - slot_t slot_number, - uint16_t slots_per_frame, - uint8_t N_symb_SRS, - uint8_t B_SRS, - uint8_t C_SRS, - uint8_t b_hop, - uint8_t R, - uint16_t T_offset, - uint16_t T_SRS, - resourceType_t resource_type, - uint8_t l_line, - uint8_t b) { - - // Compute the number of SRS transmissions - uint16_t n_SRS = 0; - if (resource_type == aperiodic) { - n_SRS = l_line / R; - } else { - n_SRS = ((slots_per_frame*frame_number + slot_number - T_offset)/T_SRS)*(N_symb_SRS/R)+(l_line / R); - } - - uint16_t product_N_b = 1; - for (unsigned int b_prime = b_hop; b_prime < B_SRS; b_prime++) { - if (b_prime != b_hop) { - product_N_b *= get_N_b_srs(C_SRS, b_prime); - } - } - - uint16_t F_b = 0; - uint8_t N_b = get_N_b_srs(C_SRS, b); - if (N_b & 1) { // Nb odd - F_b = (N_b/2)*(n_SRS/product_N_b); - } else { // Nb even - uint16_t product_N_b_B_SRS = product_N_b; - product_N_b_B_SRS *= get_N_b_srs(C_SRS, B_SRS); /* product for b_hop to b */ - F_b = (N_b/2)*((n_SRS%product_N_b_B_SRS)/product_N_b) + ((n_SRS%product_N_b_B_SRS)/2*product_N_b); - } - - return F_b; -} - -uint16_t compute_n_b(frame_t frame_number, - slot_t slot_number, - uint16_t slots_per_frame, - uint8_t N_symb_SRS, - uint8_t B_SRS, - uint8_t C_SRS, - uint8_t b_hop, - uint8_t n_RRC, - uint8_t R, - uint16_t T_offset, - uint16_t T_SRS, - resourceType_t resource_type, - uint8_t l_line, - uint8_t b) { - - uint8_t N_b = get_N_b_srs(C_SRS, b); - uint16_t m_SRS_b = get_m_srs(C_SRS, B_SRS); - - uint16_t n_b = 0; - if (b_hop >= B_SRS) { - n_b = (4 * n_RRC/m_SRS_b)%N_b; - } else { - if (b <= b_hop) { - n_b = (4 * n_RRC/m_SRS_b)%N_b; - } else { - // Compute the hopping offset Fb - uint16_t F_b = compute_F_b(frame_number, slot_number, slots_per_frame, N_symb_SRS, B_SRS, C_SRS, b_hop, R, - T_offset, T_SRS, resource_type, l_line, b); - n_b = (F_b + (4 * n_RRC/m_SRS_b))%N_b; - } - } - - return n_b; -} - -/************************************************************************* -* -* NAME : generate_srs_nr -* -* PARAMETERS : pointer to srs config pdu -* pointer to transmit buffer -* amplitude scaling for this physical signal -* slot number of transmission -* RETURN : 0 if srs sequence has been successfully generated -* -1 if sequence can not be properly generated -* -* DESCRIPTION : generate/map srs symbol into transmit buffer -* See TS 38.211 - Section 6.4.1.4 Sounding reference signal -* -***************************************************************************/ -int generate_srs_nr(nfapi_nr_srs_pdu_t *srs_config_pdu, - NR_DL_FRAME_PARMS *frame_parms, - c16_t **txdataF, - uint16_t symbol_offset, - nr_srs_info_t *nr_srs_info, - int16_t amp, - frame_t frame_number, - slot_t slot_number) -{ -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"Calling %s function\n", __FUNCTION__); -#endif - - // SRS config parameters - uint8_t B_SRS = srs_config_pdu->bandwidth_index; - uint8_t C_SRS = srs_config_pdu->config_index; - uint8_t b_hop = srs_config_pdu->frequency_hopping; - uint8_t K_TC = 2<comb_size; - uint8_t K_TC_overbar = srs_config_pdu->comb_offset; - uint8_t n_SRS_cs = srs_config_pdu->cyclic_shift; - uint8_t n_ID_SRS = srs_config_pdu->sequence_id; - uint8_t n_shift = srs_config_pdu->frequency_position; // It adjusts the SRS allocation to align with the common resource block grid in multiples of four - uint8_t n_RRC = srs_config_pdu->frequency_shift; - uint8_t groupOrSequenceHopping = srs_config_pdu->group_or_sequence_hopping; - uint8_t l_offset = srs_config_pdu->time_start_position; - uint16_t T_SRS = srs_config_pdu->t_srs; - uint16_t T_offset = srs_config_pdu->t_offset; - uint8_t R = 1<num_repetitions; - /* Number of antenna ports (M) can't be higher than number of physical antennas (N): M <= N */ - uint8_t num_ant_ports = 1 << srs_config_pdu->num_ant_ports; // Number of antenna port for transmission - int N_ap = num_ant_ports > frame_parms->nb_antennas_tx ? frame_parms->nb_antennas_tx : num_ant_ports; - uint8_t N_symb_SRS = 1<num_symbols; // Number of consecutive OFDM symbols - uint8_t l0 = frame_parms->symbols_per_slot - 1 - l_offset; // Starting symbol position in the time domain - uint8_t n_SRS_cs_max = srs_max_number_cs[srs_config_pdu->comb_size]; - uint16_t m_SRS_b = get_m_srs(C_SRS, B_SRS); // Number of resource blocks - uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC; // Length of the SRS sequence - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"Frame = %i, slot = %i\n", frame_number, slot_number); - LOG_I(NR_PHY,"B_SRS = %i\n", B_SRS); - LOG_I(NR_PHY,"C_SRS = %i\n", C_SRS); - LOG_I(NR_PHY,"b_hop = %i\n", b_hop); - LOG_I(NR_PHY,"K_TC = %i\n", K_TC); - LOG_I(NR_PHY,"K_TC_overbar = %i\n", K_TC_overbar); - LOG_I(NR_PHY,"n_SRS_cs = %i\n", n_SRS_cs); - LOG_I(NR_PHY,"n_ID_SRS = %i\n", n_ID_SRS); - LOG_I(NR_PHY,"n_shift = %i\n", n_shift); - LOG_I(NR_PHY,"n_RRC = %i\n", n_RRC); - LOG_I(NR_PHY,"groupOrSequenceHopping = %i\n", groupOrSequenceHopping); - LOG_I(NR_PHY,"l_offset = %i\n", l_offset); - LOG_I(NR_PHY,"T_SRS = %i\n", T_SRS); - LOG_I(NR_PHY,"T_offset = %i\n", T_offset); - LOG_I(NR_PHY,"R = %i\n", R); - LOG_I(NR_PHY,"N_ap = %i\n", N_ap); - LOG_I(NR_PHY,"N_symb_SRS = %i\n", N_symb_SRS); - LOG_I(NR_PHY,"l0 = %i\n", l0); - LOG_I(NR_PHY,"n_SRS_cs_max = %i\n", n_SRS_cs_max); - LOG_I(NR_PHY,"m_SRS_b = %i\n", m_SRS_b); - LOG_I(NR_PHY,"M_sc_b_SRS = %i\n", M_sc_b_SRS); -#endif - - // Validation of SRS config parameters - - if (R == 0) { - LOG_E(NR_PHY, "generate_srs: this parameter repetition factor %d is not consistent !\n", R); - return -1; - } else if (R > N_symb_SRS) { - LOG_E(NR_PHY, "generate_srs: R %d can not be greater than N_symb_SRS %d !\n", R, N_symb_SRS); - return -1; - } - - if (n_SRS_cs >= n_SRS_cs_max) { - LOG_E(NR_PHY, "generate_srs: inconsistent parameter n_SRS_cs %d >= n_SRS_cs_max %d !\n", n_SRS_cs, n_SRS_cs_max); - return -1; - } - - if (T_SRS == 0) { - LOG_E(NR_PHY, "generate_srs: inconsistent parameter T_SRS %d can not be equal to zero !\n", T_SRS); - return -1; - } else { - int index = 0; - while (srs_periodicity[index] != T_SRS) { - index++; - if (index == SRS_PERIODICITY) { - LOG_E(NR_PHY, "generate_srs: inconsistent parameter T_SRS %d not specified !\n", T_SRS); - return -1; - } - } - } - - // Variable initialization - if(nr_srs_info) { - nr_srs_info->srs_generated_signal_bits = log2_approx(amp); - } - uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_config_pdu->bwp_start*NR_NB_SC_PER_RB; - double sqrt_N_ap = sqrt(N_ap); - uint16_t n_b[B_SRS + 1]; - - // Find index of table which is for this SRS length - uint16_t M_sc_b_SRS_index = 0; - while((ul_allocated_re[M_sc_b_SRS_index] != M_sc_b_SRS) && (M_sc_b_SRS_index < SRS_SB_CONF)){ - M_sc_b_SRS_index++; - } - - // SRS sequence generation and mapping, TS 38.211 - Section 6.4.1.4 - for (int p_index = 0; p_index < N_ap; p_index++) { - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"============ port %d ============\n", p_index); -#endif - - uint16_t n_SRS_cs_i = (n_SRS_cs + (n_SRS_cs_max * (SRS_antenna_port[p_index] - 1000)/N_ap))%n_SRS_cs_max; - double alpha_i = 2 * M_PI * ((double)n_SRS_cs_i / (double)n_SRS_cs_max); - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"n_SRS_cs_i = %i\n", n_SRS_cs_i); - LOG_I(NR_PHY,"alpha_i = %f\n", alpha_i); -#endif - - for (int l_line = 0; l_line < N_symb_SRS; l_line++) { - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,":::::::: OFDM symbol %d ::::::::\n", l0+l_line); -#endif - - // Set group and sequence numbers (u,v) per OFDM symbol - uint16_t u = 0; - uint16_t v = 0; - switch(groupOrSequenceHopping) { - case neitherHopping: - u = n_ID_SRS%U_GROUP_NUMBER; - v = 0; - break; - case groupHopping: - u = group_number_hopping(slot_number, n_ID_SRS, l0, l_line); - v = 0; - break; - case sequenceHopping: - u = n_ID_SRS%U_GROUP_NUMBER; - v = sequence_number_hopping(slot_number, n_ID_SRS, M_sc_b_SRS, l0, l_line); - break; - default: - LOG_E(NR_PHY, "generate_srs: unknown hopping setting %d !\n", groupOrSequenceHopping); - return -1; - } - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"u = %i\n", u); - LOG_I(NR_PHY,"v = %i\n", v); -#endif - - // Compute the frequency position index n_b - uint16_t sum_n_b = 0; - for (int b = 0; b <= B_SRS; b++) { - n_b[b] = compute_n_b(frame_number, slot_number, frame_parms->slots_per_frame, N_symb_SRS, B_SRS, - C_SRS, b_hop, n_RRC, R, T_offset, T_SRS, srs_config_pdu->resource_type, l_line, b); - - sum_n_b += n_b[b]; - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"n_b[%i] = %i\n", b, n_b[b]); -#endif - - } - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"sum_n_b = %i\n", sum_n_b); -#endif - - // Compute the frequency-domain starting position - uint8_t K_TC_p = 0; - if((n_SRS_cs >= n_SRS_cs_max/2)&&(n_SRS_cs < n_SRS_cs_max)&&(N_ap == 4) && ((SRS_antenna_port[p_index] == 1001) || (SRS_antenna_port[p_index] == 1003))) { - K_TC_p = (K_TC_overbar + K_TC/2)%K_TC; - } else { - K_TC_p = K_TC_overbar; - } - uint8_t k_l_offset = 0; // If the SRS is configured by the IE SRS-PosResource-r16, the quantity k_l_offset is - // given by TS 38.211 - Table 6.4.1.4.3-2, otherwise k_l_offset = 0. - uint8_t k_0_overbar_p = (n_shift*NR_NB_SC_PER_RB + (K_TC_p+k_l_offset))%K_TC; - uint8_t k_0_p = k_0_overbar_p + K_TC*M_sc_b_SRS*sum_n_b; - nr_srs_info->k_0_p[p_index][l_line] = k_0_p; - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"K_TC_p = %i\n", K_TC_p); - LOG_I(NR_PHY,"k_0_overbar_p = %i\n", k_0_overbar_p); - LOG_I(NR_PHY,"k_0_p = %i\n", k_0_p); -#endif - - uint16_t subcarrier = subcarrier_offset + k_0_p; - if (subcarrier>frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; - } - uint16_t l_line_offset = l_line*frame_parms->ofdm_symbol_size; - - // For each port, and for each OFDM symbol, here it is computed and mapped an SRS sequence with M_sc_b_SRS symbols - for (int k = 0; k < M_sc_b_SRS; k++) { - cd_t shift = {cos(alpha_i * k), sin(alpha_i * k)}; - const c16_t tmp = rv_ul_ref_sig[u][v][M_sc_b_SRS_index][k]; - cd_t r_overbar = {tmp.r, tmp.i}; - - // cos(x+y) = cos(x)cos(y) - sin(x)sin(y) - cd_t r = cdMul(shift, r_overbar); - - c16_t r_amp = {(((int32_t)round((double)amp * r.r / sqrt_N_ap)) >> 15), - (((int32_t)round((double)amp * r.i / sqrt_N_ap)) >> 15)}; - -#ifdef SRS_DEBUG - int subcarrier_log = subcarrier-subcarrier_offset; - if(subcarrier_log < 0) { - subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size; - } - if(subcarrier_log%12 == 0) { - LOG_I(NR_PHY,"------------ %d ------------\n", subcarrier_log/12); - } - LOG_I(NR_PHY, "(%d) \t%i\t%i\n", subcarrier_log, r_amp.r, r_amp.i); -#endif - - txdataF[p_index][symbol_offset + l_line_offset + subcarrier] = r_amp; - - // Subcarrier increment - subcarrier += K_TC; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier=subcarrier-frame_parms->ofdm_symbol_size; - } - - } // for (int k = 0; k < M_sc_b_SRS; k++) - } // for (int l_line = 0; l_line < N_symb_SRS; l_line++) - } // for (int p_index = 0; p_index < N_ap; p_index++) - - return 0; -} - -/******************************************************************* -* -* NAME : ue_srs_procedures_nr -* -* PARAMETERS : pointer to ue context -* pointer to rxtx context* -* -* RETURN : 0 if it is a valid slot for transmitting srs -* -1 if srs should not be transmitted -* -* DESCRIPTION : ue srs procedure -* send srs according to current configuration -* -*********************************************************************/ -int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - c16_t **txdataF, - nr_phy_data_tx_t *phy_data, - bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]) -{ - if(phy_data->srs_vars.active == false) { - return -1; - } - - // TODO: This is wrong: casting from UE fapi to gNB NFAPI srs pdu - nfapi_nr_srs_pdu_t *srs_config_pdu = (nfapi_nr_srs_pdu_t *)&phy_data->srs_vars.srs_config_pdu; - - int first_srs_symbol = ue->frame_parms.symbols_per_slot - 1 - srs_config_pdu->time_start_position; - // Num consecutive SRS symbols according to 38.211 6.4.1.4.1 - int num_srs_symbols[] = {1, 2, 4, 8, 12}; - int last_srs_symbol = first_srs_symbol + num_srs_symbols[srs_config_pdu->num_symbols] - 1; - for (int i = first_srs_symbol; i <= last_srs_symbol; i++) { - was_symbol_used[i] = true; - } - -#ifdef SRS_DEBUG - LOG_I(NR_PHY,"Frame = %i, slot = %i\n", proc->frame_tx, proc->nr_slot_tx); - LOG_I(NR_PHY,"srs_config_pdu->rnti = 0x%04x\n", srs_config_pdu->rnti); - LOG_I(NR_PHY,"srs_config_pdu->handle = %u\n", srs_config_pdu->handle); - LOG_I(NR_PHY,"srs_config_pdu->bwp_size = %u\n", srs_config_pdu->bwp_size); - LOG_I(NR_PHY,"srs_config_pdu->bwp_start = %u\n", srs_config_pdu->bwp_start); - LOG_I(NR_PHY,"srs_config_pdu->subcarrier_spacing = %u\n", srs_config_pdu->subcarrier_spacing); - LOG_I(NR_PHY,"srs_config_pdu->cyclic_prefix = %u (0: Normal; 1: Extended)\n", srs_config_pdu->cyclic_prefix); - LOG_I(NR_PHY,"srs_config_pdu->num_ant_ports = %u (0 = 1 port, 1 = 2 ports, 2 = 4 ports)\n", srs_config_pdu->num_ant_ports); - LOG_I(NR_PHY,"srs_config_pdu->num_symbols = %u (0 = 1 symbol, 1 = 2 symbols, 2 = 4 symbols)\n", srs_config_pdu->num_symbols); - LOG_I(NR_PHY,"srs_config_pdu->num_repetitions = %u (0 = 1, 1 = 2, 2 = 4)\n", srs_config_pdu->num_repetitions); - LOG_I(NR_PHY,"srs_config_pdu->time_start_position = %u\n", srs_config_pdu->time_start_position); - LOG_I(NR_PHY,"srs_config_pdu->config_index = %u\n", srs_config_pdu->config_index); - LOG_I(NR_PHY,"srs_config_pdu->sequence_id = %u\n", srs_config_pdu->sequence_id); - LOG_I(NR_PHY,"srs_config_pdu->bandwidth_index = %u\n", srs_config_pdu->bandwidth_index); - LOG_I(NR_PHY,"srs_config_pdu->comb_size = %u (0 = comb size 2, 1 = comb size 4, 2 = comb size 8)\n", srs_config_pdu->comb_size); - LOG_I(NR_PHY,"srs_config_pdu->comb_offset = %u\n", srs_config_pdu->comb_offset); - LOG_I(NR_PHY,"srs_config_pdu->cyclic_shift = %u\n", srs_config_pdu->cyclic_shift); - LOG_I(NR_PHY,"srs_config_pdu->frequency_position = %u\n", srs_config_pdu->frequency_position); - LOG_I(NR_PHY,"srs_config_pdu->frequency_shift = %u\n", srs_config_pdu->frequency_shift); - LOG_I(NR_PHY,"srs_config_pdu->frequency_hopping = %u\n", srs_config_pdu->frequency_hopping); - LOG_I(NR_PHY,"srs_config_pdu->group_or_sequence_hopping = %u (0 = No hopping, 1 = Group hopping groupOrSequenceHopping, 2 = Sequence hopping)\n", srs_config_pdu->group_or_sequence_hopping); - LOG_I(NR_PHY,"srs_config_pdu->resource_type = %u (0: aperiodic, 1: semi-persistent, 2: periodic)\n", srs_config_pdu->resource_type); - LOG_I(NR_PHY,"srs_config_pdu->t_srs = %u\n", srs_config_pdu->t_srs); - LOG_I(NR_PHY,"srs_config_pdu->t_offset = %u\n", srs_config_pdu->t_offset); -#endif - - NR_DL_FRAME_PARMS *frame_parms = &(ue->frame_parms); - uint16_t symbol_offset = (frame_parms->symbols_per_slot - 1 - srs_config_pdu->time_start_position)*frame_parms->ofdm_symbol_size; - - if (generate_srs_nr(srs_config_pdu, frame_parms, txdataF, symbol_offset, ue->nr_srs_info, AMP, proc->frame_tx, proc->nr_slot_tx) - == 0) { - return 0; - } else { - return -1; - } -} - - - - - - - - - - - - - - diff --git a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h b/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h deleted file mode 100644 index 1bbe3a27ef..0000000000 --- a/openair1/PHY/NR_UE_TRANSPORT/srs_modulation_nr.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 - */ - -/*********************************************************************** -* -* FILENAME : srs_modulation_nr.h -* -* MODULE : -* -* DESCRIPTION : function to generate uplink reference sequences -* see 3GPP TS 38.211 6.4.1.4 Sounding reference signal -* -************************************************************************/ - -#ifndef SRS_MODULATION_NR_H -#define SRS_MODULATION_NR_H - -#include "PHY/defs_nr_UE.h" - -#define SRS_PERIODICITY (17) - -static const uint16_t srs_periodicity[SRS_PERIODICITY] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560}; - -// TS 38.211 - Table 6.4.1.4.2-1 -static const uint16_t srs_max_number_cs[3] = {8, 12, 6}; - -/*************** FUNCTIONS *****************************************/ - -/** \brief This function generates the sounding reference symbol (SRS) for the uplink according to 38.211 6.4.1.4 Sounding reference signal - @param frame_parms NR DL Frame parameters - @param txdataF pointer to the frequency domain TX signal - @param symbol_offset symbol offset added in txdataF - @param nr_srs_info pointer to the srs info structure - @param amp amplitude of generated signal - @param frame_number frame number - @param slot_number slot number - @returns 0 on success -1 on error with message */ - -int generate_srs_nr(nfapi_nr_srs_pdu_t *srs_config_pdu, - NR_DL_FRAME_PARMS *frame_parms, - c16_t **txdataF, - uint16_t symbol_offset, - nr_srs_info_t *nr_srs_info, - int16_t amp, - frame_t frame_number, - slot_t slot_number); - -/** \brief This function checks for periodic srs if srs should be transmitted in this slot - * @param p_SRS_Resource pointer to active resource - @param frame_parms NR DL Frame parameters - @param txdataF pointer to the frequency domain TX signal - @returns 0 if srs should be transmitted -1 on error with message */ - -int is_srs_period_nr(SRS_Resource_t *p_SRS_Resource, - NR_DL_FRAME_PARMS *frame_parms, - int frame_tx, int slot_tx); - -/** \brief This function processes srs configuration - * @param ue context - @param rxtx context - @param current gNB_id identifier - @returns 0 if srs is transmitted -1 otherwise */ -int ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - c16_t **txdataF, - nr_phy_data_tx_t *phy_data, - bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]); - -#endif /* SRS_MODULATION_NR_H */ diff --git a/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c b/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c index 0a13462d8c..da27ca8603 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c +++ b/openair1/PHY/NR_UE_TRANSPORT/sss_nr.c @@ -499,7 +499,7 @@ bool rx_sss_nr(const NR_DL_FRAME_PARMS *frame_parms, int re = 0; int im = 0; - if (Nid1 == N_ID_1_NUMBER) { + if (Nid1 == Nid1_end) { LOG_D(PHY, "Failed to detect SSS after PSS, metric of SSS %d, threshold to consider SSS valid %d, detected PCI: %d\n", *tot_metric, diff --git a/openair1/PHY/TOOLS/CMakeLists.txt b/openair1/PHY/TOOLS/CMakeLists.txt index 8a3d912caa..dad31d0ede 100644 --- a/openair1/PHY/TOOLS/CMakeLists.txt +++ b/openair1/PHY/TOOLS/CMakeLists.txt @@ -45,6 +45,7 @@ if(ENABLE_UESCOPE OR ENABLE_ENBSCOPE OR ENABLE_NRSCOPE) lte_phy_scope.c ../../../executables/stats.c) target_link_libraries(xforms_common PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) + target_link_libraries(xforms_common PRIVATE log_headers) add_library(enbscope MODULE lte_enb_scope.c $) target_link_libraries(enbscope PUBLIC forms PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs UTIL) diff --git a/openair1/PHY/TOOLS/calibration_scope.c b/openair1/PHY/TOOLS/calibration_scope.c index d3397b033f..c7a305ab27 100644 --- a/openair1/PHY/TOOLS/calibration_scope.c +++ b/openair1/PHY/TOOLS/calibration_scope.c @@ -67,7 +67,7 @@ static void drawsymbol(FL_OBJECT *obj, int id, static void commonGraph(OAIgraph_t *graph, int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label, FL_COLOR pointColor) { if (type==WATERFALL) { graph->waterFallh=h-15; - graph->waterFallAvg=malloc(sizeof(*graph->waterFallAvg) * graph->waterFallh); + graph->waterFallAvg = malloc_or_fail(sizeof(*graph->waterFallAvg) * graph->waterFallh); for (int i=0; i< graph->waterFallh; i++) graph->waterFallAvg[i]=0; @@ -99,8 +99,9 @@ static void commonGraph(OAIgraph_t *graph, int type, FL_Coord x, FL_Coord y, FL_ } static OAIgraph_t calibrationCommonGraph( void (*funct) (OAIgraph_t *graph, calibData_t *context), - int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label, FL_COLOR pointColor) { - OAIgraph_t graph; + int type, FL_Coord x, FL_Coord y, FL_Coord w, FL_Coord h, const char *label, FL_COLOR pointColor) +{ + OAIgraph_t graph = {0}; commonGraph(&graph, type, x, y, w, h, label, pointColor); graph.funct=funct; return graph; @@ -236,7 +237,9 @@ static void genericWaterFall (OAIgraph_t *graph, scopeSample_t *values, const in graph->iteration++; } -static void genericPowerPerAntena(OAIgraph_t *graph, const int nb_ant, const scopeSample_t **data, const int len) { +__attribute__((unused)) +static void genericPowerPerAntena(OAIgraph_t *graph, const int nb_ant, const scopeSample_t **data, const int len) +{ float *values, *time; oai_xygraph_getbuff(graph, &time, &values, len, 0); @@ -263,7 +266,10 @@ static void gNBfreqWaterFall (OAIgraph_t *graph, calibData_t *context) { 0, 0, "X axis:one frame in time"); } -static void timeResponse (OAIgraph_t *graph, calibData_t *context) { + +__attribute__((unused)) +static void timeResponse (OAIgraph_t *graph, calibData_t *context) +{ #if 0 const int len=2*phy_vars_gnb->frame_parms.ofdm_symbol_size; float *values, *time; @@ -309,7 +315,7 @@ static void puschIQ (OAIgraph_t *graph, calibData_t *context) { static OAI_phy_scope_t *createScopeCalibration(calibData_t * context) { FL_OBJECT *obj; - OAI_phy_scope_t *fdui = calloc(( sizeof *fdui ),1); + OAI_phy_scope_t *fdui = calloc_or_fail((sizeof *fdui), 1); fdui->context=context; // Define form fdui->phy_scope = fl_bgn_form( FL_NO_BOX, 800, 800 ); @@ -380,7 +386,7 @@ static void *scopeThread(void *arg) { void CalibrationInitScope(void ** samplesRx,openair0_device *rfdevice) { pthread_t forms_thread; - calibData_t * tmp=(calibData_t *) malloc(sizeof(*tmp)); + calibData_t *tmp = (calibData_t *)malloc_or_fail(sizeof(*tmp)); tmp->samplesRx=samplesRx; tmp->rfdevice=rfdevice; threadCreate(&forms_thread, scopeThread, (void*) tmp, "scope", -1, OAI_PRIORITY_RT_LOW); diff --git a/openair1/PHY/TOOLS/calibration_test.c b/openair1/PHY/TOOLS/calibration_test.c index f69e468e7b..4d88ab542a 100644 --- a/openair1/PHY/TOOLS/calibration_test.c +++ b/openair1/PHY/TOOLS/calibration_test.c @@ -28,7 +28,6 @@ char *uecap_file; int read_recplayconfig(recplay_conf_t **recplay_conf, recplay_state_t **recplay_state) {return 0;} void nfapi_setmode(nfapi_mode_t nfapi_mode) {} void set_taus_seed(unsigned int seed_init){}; -configmodule_interface_t *uniqCfg = NULL; int main(int argc, char **argv) { ///static configuration for NR at the moment if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == NULL) { @@ -60,8 +59,6 @@ int main(int argc, char **argv) { openair0_config_t openair0_cfg= { //! Module ID for this configuration .Mod_id=0, - //! device log level - .log_level=0, //! duplexing mode .duplex_mode=0, //! number of downlink resource blocks @@ -130,8 +127,6 @@ int main(int argc, char **argv) { .recplay_conf=NULL, //! number of samples per tti .samples_per_tti=0, - //! check for threequarter sampling rate - .threequarter_fs=0, }; //----------------------- openair0_device rfdevice= { @@ -319,8 +314,13 @@ int main(int argc, char **argv) { rfdevice.trx_start_func(&rfdevice); while(!oai_exit) { - for (int i=0; iphy_scope = fl_bgn_form( FL_NO_BOX, 800, 800 ); fl_set_form_dblbuffer(fdui->phy_scope, 1); @@ -739,7 +739,7 @@ static void scopeUpdaterGnb(enum PlotTypeGnbIf plotType, int numElt) STATICFORXSCOPE void gNBinitScope(scopeParms_t *p) { - AssertFatal(p->gNB->scopeData = calloc(sizeof(scopeData_t), 1), ""); + AssertFatal(p->gNB->scopeData = calloc_or_fail(sizeof(scopeData_t), 1), ""); scopeData_t *scope=(scopeData_t *) p->gNB->scopeData; scope->argc=p->argc; scope->argv=p->argv; @@ -998,7 +998,7 @@ static void uePdschThroughput (scopeGraphData_t **data, OAIgraph_t *graph, PHY_ STATICFORXSCOPE OAI_phy_scope_t *create_phy_scope_nrue(int ID) { FL_OBJECT *obj; - OAI_phy_scope_t *fdui = calloc(( sizeof *fdui ),1); + OAI_phy_scope_t *fdui = calloc_or_fail((sizeof *fdui), 1); // Define form fdui->phy_scope = fl_bgn_form( FL_NO_BOX, 800, 900 ); fl_set_form_dblbuffer(fdui->phy_scope, 1); @@ -1139,7 +1139,7 @@ static void *nrUEscopeThread(void *arg) { STATICFORXSCOPE void nrUEinitScope(PHY_VARS_NR_UE *ue) { - AssertFatal(ue->scopeData = calloc(sizeof(scopeData_t), 1), ""); + AssertFatal(ue->scopeData = calloc_or_fail(sizeof(scopeData_t), 1), ""); scopeData_t *scope=(scopeData_t *) ue->scopeData; scope->copyData = copyData; #ifndef WEBSRVSCOPE @@ -1185,7 +1185,7 @@ static void reset_stats_gNB(FL_OBJECT *button, } static FD_stats_form *create_form_stats_form(int ID) { FL_OBJECT *obj; - FD_stats_form *fdui = calloc(( sizeof *fdui ),1); + FD_stats_form *fdui = calloc_or_fail(( sizeof *fdui ),1); fdui->vdata = fdui->cdata = NULL; fdui->ldata = 0; fdui->stats_form = fl_bgn_form( FL_NO_BOX, 1115, 900 ); diff --git a/openair1/PHY/TOOLS/phy_test_tools.hpp b/openair1/PHY/TOOLS/phy_test_tools.hpp index dcaa192dd4..bf9760cde6 100644 --- a/openair1/PHY/TOOLS/phy_test_tools.hpp +++ b/openair1/PHY/TOOLS/phy_test_tools.hpp @@ -81,7 +81,7 @@ AlignedVector512 generate_random_c16(size_t num) { std::random_device rd; std::mt19937 rng(rd()); - std::uniform_int_distribution dist(INT16_MIN, INT16_MAX); + std::uniform_int_distribution dist(-INT16_MAX, INT16_MAX); AlignedVector512 vec; vec.resize(num); auto gen = [&]() { return (c16_t){dist(rng), dist(rng)}; }; diff --git a/openair1/PHY/TOOLS/signal_energy.c b/openair1/PHY/TOOLS/signal_energy.c index 93544da758..a7c314dd44 100644 --- a/openair1/PHY/TOOLS/signal_energy.c +++ b/openair1/PHY/TOOLS/signal_energy.c @@ -27,8 +27,6 @@ // length : length of vector in complex samples #define shift 4 -//#define shift_DC 0 -//#define SHRT_MIN -32768 //----------------------------------------------------------------- // Average Power calculation with DC removing diff --git a/openair1/PHY/TOOLS/smbv.c b/openair1/PHY/TOOLS/smbv.c index a1088cc705..337fcbe13f 100644 --- a/openair1/PHY/TOOLS/smbv.c +++ b/openair1/PHY/TOOLS/smbv.c @@ -61,6 +61,8 @@ int smbv_init_config(const char* fname, uint16_t sequence_length) int k; f_ptr = fopen(fname,"w"); + if (!f_ptr) + return -1; if (sequence_length>4) { msg("ERROR invalid sequence length: %d, maximum is 4\n", sequence_length); @@ -101,6 +103,8 @@ int smbv_write_config_from_frame_parms(const char* fname, LTE_DL_FRAME_PARMS *fr FILE *f_ptr; f_ptr = fopen(fname,"a"); + if (!f_ptr) + return -1; fprintf(f_ptr, "BB:EUTR:SLEN %d\n",slen); @@ -188,6 +192,8 @@ int smbv_configure_datalist_for_alloc(const char* fname, uint8_t alloc, uint8_t { FILE *f_ptr; f_ptr = fopen(fname,"a"); + if (!f_ptr) + return -1; char strbuf[(8<<1)+1]; int i,k; strbuf[0] = '\0'; @@ -245,6 +251,8 @@ int smbv_configure_datalist_for_user(const char* fname, uint8_t user, uint8_t *b { FILE *f_ptr; f_ptr = fopen(fname,"a"); + if (!f_ptr) + return -1; char strbuf[(8<<1)+1]; int i,k; @@ -284,6 +292,8 @@ int smbv_configure_user(const char* fname, uint8_t user, uint8_t transmission_mo { FILE *f_ptr; f_ptr = fopen(fname,"a"); + if (!f_ptr) + return -1; fprintf(f_ptr, "BB:EUTR:DL:USER%d:TXM M1\n",user); fprintf(f_ptr, "BB:EUTR:DL:USER%d:UEC USER\n",user); @@ -302,6 +312,8 @@ int smbv_configure_pdcch(const char* fname,uint8_t subframe,uint8_t num_pdcch_sy FILE *f_ptr; f_ptr = fopen(fname,"a"); + if (!f_ptr) + return -1; fprintf(f_ptr, "BB:EUTR:DL:SUBF%d:ENCC:PCF:CREG %d\n",subframe,num_pdcch_symbols); fprintf(f_ptr, "BB:EUTR:DL:SUBF%d:ENCC:PDCC:FORM VAR\n",subframe); @@ -325,6 +337,8 @@ int smbv_configure_common_dci(const char* fname, uint8_t subframe, const char* t void *dci_pdu = &dci_alloc->dci_pdu[0]; f_ptr = fopen(fname,"a"); + if (!f_ptr) + return -1; fprintf(f_ptr, "BB:EUTR:DL:SUBF%d:ENCC:STAT ON\n",subframe); @@ -383,6 +397,8 @@ int smbv_configure_ue_spec_dci(const char* fname, uint8_t subframe, uint8_t user void *dci_pdu = &dci_alloc->dci_pdu[0]; f_ptr = fopen(fname,"a"); + if (!f_ptr) + return -1; fprintf(f_ptr, "BB:EUTR:DL:SUBF%d:ENCC:STAT ON\n",subframe); fprintf(f_ptr, "BB:EUTR:DL:SUBF%d:ENCC:PDCC:EXTC:ITEM%d:USER USER%d\n",subframe,item,user); diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index 64e5061476..c5a8ab13b7 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -32,7 +32,7 @@ #include #include #include - +#include "common/platform_types.h" #include "PHY/sse_intrin.h" #include "common/utils/assertions.h" @@ -51,39 +51,6 @@ extern "C" { #endif -#define ALIGNARRAYSIZE(a, b) (((a + b - 1) / b) * b) -#define ALNARS_16_4(a) ALIGNARRAYSIZE(a, 4) - - typedef struct complexd { - double r; - double i; - } cd_t; - - typedef struct complexf { - float r; - float i; - } cf_t; - - typedef struct complex8 { - int8_t r; - int8_t i; - } c8_t; - - typedef struct complex16 { - int16_t r; - int16_t i; - } c16_t; - - typedef struct complex32 { - int32_t r; - int32_t i; - } c32_t; - - typedef struct complex64 { - int64_t r; - int64_t i; - } c64_t; - typedef struct { int dim1; int dim2; @@ -163,7 +130,7 @@ extern "C" { __attribute__((always_inline)) inline c16_t c16conj(const c16_t a) { return (c16_t) { .r = a.r, - .i = (int16_t)-a.i + .i = (int16_t)-a.i }; } @@ -219,6 +186,7 @@ extern "C" { { return (c16_t){.r = (int16_t)((a.r * b) >> Shift), .i = (int16_t)((a.i * b) >> Shift)}; } + __attribute__((always_inline)) inline c16_t c16MulConjShift(const c16_t a, const c16_t b, const int Shift) { return (c16_t) { @@ -234,6 +202,14 @@ extern "C" { }; } + __attribute__((always_inline)) inline c16_t c16maddConjShift(const c16_t a, const c16_t b, c16_t c, const int Shift) + { + return (c16_t) { + .r = (int16_t)(((a.r * b.r + a.i * b.i ) >> Shift) + c.r), + .i = (int16_t)(((a.r * b.i - a.i * b.r ) >> Shift) + c.i) + }; + } + __attribute__((always_inline)) inline c32_t c32x16mulShift(const c16_t a, const c16_t b, const int Shift) { return (c32_t) { .r = (a.r * b.r - a.i * b.i) >> Shift, @@ -532,6 +508,20 @@ static inline void multadd_cpx_vector(const c16_t *x1, const c16_t *x2, c16_t *y } } +static const int16_t ones_epi16[16] __attribute__((aligned(32))) = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; +static inline simde__m256i protected_abs256(const simde__m256i in) +{ + const simde__m256i no32768 = + simde_mm256_adds_epi16(simde_mm256_subs_epi16(in, *(simde__m256i *)ones_epi16), *(simde__m256i *)ones_epi16); + return simde_mm256_abs_epi16(no32768); +} + +static inline simde__m128i protected_abs128(const simde__m128i in) +{ + const simde__m128i no32768 = simde_mm_adds_epi16(simde_mm_subs_epi16(in, *(simde__m128i *)ones_epi16), *(simde__m128i *)ones_epi16); + return simde_mm_abs_epi16(no32768); +} + // lte_dfts.c void init_fft(uint16_t size, uint8_t logsize, @@ -814,6 +804,47 @@ static inline void rotate_cpx_vector(const c16_t *const x, const c16_t *const al // log2_amp - increase the output amplitude by a factor 2^log2_amp (default is 0) // WARNING: log2_amp>0 can cause overflow!! + +#ifdef __aarch64__ + if (output_shift == 15) { // allows specific NEON instruction + + int16x8_t ar = (int16x8_t)vdupq_n_s16(alpha->r); + int16x8_t ai = (int16x8_t)vdupq_n_s16(alpha->i); + int16x8_t *y_128 = (int16x8_t *)y; + int16x8_t *x_128 = (int16x8_t *)x; + for (uint32_t i = 0; i < (N >> 2); i++) { + // Split interleaved -> separate real/imag + int16x8_t br = vuzp1q_s16(x_128[i], x_128[i]); + int16x8_t bi = vuzp2q_s16(x_128[i], x_128[i]); + + // Start with the two “diagonal” products using high-half, doubling, sat: + // x = round( (2*ar*br) / 2^16 ), y = round( (2*ar*bi) / 2^16 ) + int16x8_t real = vqdmulhq_s16(ar, br); + int16x8_t imag = vqdmulhq_s16(ar, bi); + + // real -= round( (2*ai*bi) / 2^16 ) + real = vqrdmlshq_s16(real, ai, bi); + + // imag += round( (2*ai*br) / 2^16 ) + imag = vqrdmlahq_s16(imag, ai, br); + + // Re-interleave [real, imag] + int16x8x2_t z = vzipq_s16(real, imag); + + y_128[i] = z.val[0]; + /* + printf("y : (%d %d) (%d %d) (%d %d) (%d %d)\n", + vgetq_lane_s16(y_128[i],0), + vgetq_lane_s16(y_128[i],1), + vgetq_lane_s16(y_128[i],2), + vgetq_lane_s16(y_128[i],3), + vgetq_lane_s16(y_128[i],4), + vgetq_lane_s16(y_128[i],5), + vgetq_lane_s16(y_128[i],6), + vgetq_lane_s16(y_128[i],7));*/ + } + } else { +#endif uint32_t i; // loop counter simd_q15_t *y_128, alpha_128; @@ -845,7 +876,10 @@ static inline void rotate_cpx_vector(const c16_t *const x, const c16_t *const al shift)); // print_ints("y_128[0]=", &y_128[0]); } -#if defined(__x86__) || defined(__x86_64__) +#ifdef __aarch64__ + } +#endif //__aarch64__ +#if defined(__x86_64__) || defined(__i386__) } #endif } @@ -919,6 +953,16 @@ c32_t dot_product(const c16_t *x, void oai_mm_separate_real_imag_parts(simde__m128i *out_re, simde__m128i *out_im, simde__m128i in0, simde__m128i in1); void oai_mm256_separate_real_imag_parts(simde__m256i *out_re, simde__m256i *out_im, simde__m256i in0, simde__m256i in1); +// generates vpcmpeqd ymm0, ymm0, ymm0 +static inline simde__m256i allones256(void) +{ + return simde_mm256_set1_epi64x(-1); +} +static inline simde__m128i allones128(void) +{ + return simde_mm_set1_epi32(-1); +} + void InitSinLUT(void); // fast calculation of e^{i*2*pi*phase} diff --git a/openair1/PHY/defs_L1_NB_IoT.h b/openair1/PHY/defs_L1_NB_IoT.h index aba1ffb255..97f243fae8 100644 --- a/openair1/PHY/defs_L1_NB_IoT.h +++ b/openair1/PHY/defs_L1_NB_IoT.h @@ -512,20 +512,20 @@ typedef struct PHY_VARS_eNB_NB_IoT_s { NB_IoT_DL_FRAME_PARMS frame_parms; PHY_MEASUREMENTS_eNB_NB_IoT measurements[NUMBER_OF_eNB_SECTORS_MAX_NB_IoT]; /// Measurement variables NB_IoT_eNB_COMMON common_vars; - NB_IoT_eNB_SRS srs_vars[NUMBER_OF_UE_MAX_NB_IoT]; + NB_IoT_eNB_SRS srs_vars[NUMBER_OF_UE_MAX]; NB_IoT_eNB_PBCH pbch; - NB_IoT_eNB_PUSCH *pusch_vars[NUMBER_OF_UE_MAX_NB_IoT]; + NB_IoT_eNB_PUSCH *pusch_vars[NUMBER_OF_UE_MAX]; NB_IoT_eNB_PRACH prach_vars; - //LTE_eNB_DLSCH_t *dlsch[NUMBER_OF_UE_MAX_NB_IoT][2]; // Nusers times two spatial streams - NB_IoT_eNB_NULSCH_t *ulsch[NUMBER_OF_UE_MAX_NB_IoT+1]; // Nusers + number of RA (the ulsch[0] contains RAR) + //LTE_eNB_DLSCH_t *dlsch[NUMBER_OF_UE_MAX][2]; // Nusers times two spatial streams + NB_IoT_eNB_NULSCH_t *ulsch[NUMBER_OF_UE_MAX+1]; // Nusers + number of RA (the ulsch[0] contains RAR) //LTE_eNB_DLSCH_t *dlsch_SI,*dlsch_ra; //LTE_eNB_DLSCH_t *dlsch_MCH; - NB_IoT_eNB_UE_stats UE_stats[NUMBER_OF_UE_MAX_NB_IoT]; - //LTE_eNB_UE_stats *UE_stats_ptr[NUMBER_OF_UE_MAX_NB_IoT]; + NB_IoT_eNB_UE_stats UE_stats[NUMBER_OF_UE_MAX]; + //LTE_eNB_UE_stats *UE_stats_ptr[NUMBER_OF_UE_MAX]; /// cell-specific reference symbols uint32_t lte_gold_table_NB_IoT[20][2][14]; /// UE-specific reference symbols (p=5), TM 7 - uint32_t lte_gold_uespec_port5_table[NUMBER_OF_UE_MAX_NB_IoT][20][38]; + uint32_t lte_gold_uespec_port5_table[NUMBER_OF_UE_MAX][20][38]; /// UE-specific reference symbols (p=7...14), TM 8/9/10 uint32_t lte_gold_uespec_table[2][20][2][21]; /// mbsfn reference symbols @@ -539,7 +539,7 @@ typedef struct PHY_VARS_eNB_NB_IoT_s { /// char eNB_generate_rar; /// Indicator set to 0 after first SR - uint8_t first_sr[NUMBER_OF_UE_MAX_NB_IoT]; + uint8_t first_sr[NUMBER_OF_UE_MAX]; uint32_t max_peak_val; /// @@ -549,7 +549,7 @@ typedef struct PHY_VARS_eNB_NB_IoT_s { /// N0 (used for abstraction) double N0; /// - unsigned char first_run_timing_advance[NUMBER_OF_UE_MAX_NB_IoT]; + unsigned char first_run_timing_advance[NUMBER_OF_UE_MAX]; unsigned char first_run_I0_measurements; unsigned char cooperation_flag; // for cooperative communication @@ -575,37 +575,37 @@ typedef struct PHY_VARS_eNB_NB_IoT_s { DCI_ALLOC_NB_IoT_t dci_alloc[2][NUM_DCI_MAX_NB_IoT]; // dci_alloc from even/odd subframes ///////////// // PDSCH Variables - PDSCH_CONFIG_DEDICATED_NB_IoT pdsch_config_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + PDSCH_CONFIG_DEDICATED_NB_IoT pdsch_config_dedicated[NUMBER_OF_UE_MAX]; // PUSCH Variables - PUSCH_CONFIG_DEDICATED_NB_IoT pusch_config_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + PUSCH_CONFIG_DEDICATED_NB_IoT pusch_config_dedicated[NUMBER_OF_UE_MAX]; // PUCCH variables - PUCCH_CONFIG_DEDICATED_NB_IoT pucch_config_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + PUCCH_CONFIG_DEDICATED_NB_IoT pucch_config_dedicated[NUMBER_OF_UE_MAX]; // UL-POWER-Control - UL_POWER_CONTROL_DEDICATED_NB_IoT ul_power_control_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + UL_POWER_CONTROL_DEDICATED_NB_IoT ul_power_control_dedicated[NUMBER_OF_UE_MAX]; // TPC - TPC_PDCCH_CONFIG_NB_IoT tpc_pdcch_config_pucch[NUMBER_OF_UE_MAX_NB_IoT]; + TPC_PDCCH_CONFIG_NB_IoT tpc_pdcch_config_pucch[NUMBER_OF_UE_MAX]; /// - TPC_PDCCH_CONFIG_NB_IoT tpc_pdcch_config_pusch[NUMBER_OF_UE_MAX_NB_IoT]; + TPC_PDCCH_CONFIG_NB_IoT tpc_pdcch_config_pusch[NUMBER_OF_UE_MAX]; // CQI reporting - CQI_REPORT_CONFIG_NB_IoT cqi_report_config[NUMBER_OF_UE_MAX_NB_IoT]; + CQI_REPORT_CONFIG_NB_IoT cqi_report_config[NUMBER_OF_UE_MAX]; // SRS Variables - SOUNDINGRS_UL_CONFIG_DEDICATED_NB_IoT soundingrs_ul_config_dedicated[NUMBER_OF_UE_MAX_NB_IoT]; + SOUNDINGRS_UL_CONFIG_DEDICATED_NB_IoT soundingrs_ul_config_dedicated[NUMBER_OF_UE_MAX]; /// uint8_t ncs_cell[20][7]; // Scheduling Request Config - SCHEDULING_REQUEST_CONFIG_NB_IoT scheduling_request_config[NUMBER_OF_UE_MAX_NB_IoT]; + SCHEDULING_REQUEST_CONFIG_NB_IoT scheduling_request_config[NUMBER_OF_UE_MAX]; // Transmission mode per UE - uint8_t transmission_mode[NUMBER_OF_UE_MAX_NB_IoT]; + uint8_t transmission_mode[NUMBER_OF_UE_MAX]; /// cba_last successful reception for each group, used for collision detection uint8_t cba_last_reception[4]; // Pointers for active physicalConfigDedicated to be applied in current subframe - struct PhysicalConfigDedicated *physicalConfigDedicated[NUMBER_OF_UE_MAX_NB_IoT]; + struct PhysicalConfigDedicated *physicalConfigDedicated[NUMBER_OF_UE_MAX]; //Pointers for actve physicalConfigDedicated for NB-IoT to be applied in current subframe - struct PhysicalConfigDedicated_NB_r13 *phy_config_dedicated_NB_IoT[NUMBER_OF_UE_MAX_NB_IoT]; + struct PhysicalConfigDedicated_NB_r13 *phy_config_dedicated_NB_IoT[NUMBER_OF_UE_MAX]; /// uint32_t rb_mask_ul[4]; /// Information regarding TM5 - MU_MIMO_mode_NB_IoT mu_mimo_mode[NUMBER_OF_UE_MAX_NB_IoT]; + MU_MIMO_mode_NB_IoT mu_mimo_mode[NUMBER_OF_UE_MAX]; /// target_ue_dl_mcs : only for debug purposes uint32_t target_ue_dl_mcs; /// target_ue_ul_mcs : only for debug purposes @@ -660,16 +660,16 @@ typedef struct PHY_VARS_eNB_NB_IoT_s { time_stats_t ulsch_tc_ext_stats; time_stats_t ulsch_tc_intl1_stats; time_stats_t ulsch_tc_intl2_stats; - int32_t pucch1_stats_cnt[NUMBER_OF_UE_MAX_NB_IoT][10]; - int32_t pucch1_stats[NUMBER_OF_UE_MAX_NB_IoT][10*1024]; - int32_t pucch1_stats_thres[NUMBER_OF_UE_MAX_NB_IoT][10*1024]; - int32_t pucch1ab_stats_cnt[NUMBER_OF_UE_MAX_NB_IoT][10]; - int32_t pucch1ab_stats[NUMBER_OF_UE_MAX_NB_IoT][2*10*1024]; - int32_t pusch_stats_rb[NUMBER_OF_UE_MAX_NB_IoT][10240]; - int32_t pusch_stats_round[NUMBER_OF_UE_MAX_NB_IoT][10240]; - int32_t pusch_stats_mcs[NUMBER_OF_UE_MAX_NB_IoT][10240]; - int32_t pusch_stats_bsr[NUMBER_OF_UE_MAX_NB_IoT][10240]; - int32_t pusch_stats_BO[NUMBER_OF_UE_MAX_NB_IoT][10240]; + int32_t pucch1_stats_cnt[NUMBER_OF_UE_MAX][10]; + int32_t pucch1_stats[NUMBER_OF_UE_MAX][10*1024]; + int32_t pucch1_stats_thres[NUMBER_OF_UE_MAX][10*1024]; + int32_t pucch1ab_stats_cnt[NUMBER_OF_UE_MAX][10]; + int32_t pucch1ab_stats[NUMBER_OF_UE_MAX][2*10*1024]; + int32_t pusch_stats_rb[NUMBER_OF_UE_MAX][10240]; + int32_t pusch_stats_round[NUMBER_OF_UE_MAX][10240]; + int32_t pusch_stats_mcs[NUMBER_OF_UE_MAX][10240]; + int32_t pusch_stats_bsr[NUMBER_OF_UE_MAX][10240]; + int32_t pusch_stats_BO[NUMBER_OF_UE_MAX][10240]; /// RF and Interface devices per CC openair0_device rfdevice; @@ -682,7 +682,7 @@ typedef struct PHY_VARS_eNB_NB_IoT_s { //------------------------ /* - * NUMBER_OF_UE_MAX_NB_IoT maybe in the future should be dynamic because could be very large and the memory may explode + * NUMBER_OF_UE_MAX maybe in the future should be dynamic because could be very large and the memory may explode * (is almost the indication of the number of UE context that we are storing at PHY layer) * * reasoning: the following data structure (ndlsch, nulsch ecc..) are used to store the context that should be transmitted in at least n+4 subframe later @@ -710,11 +710,10 @@ typedef struct PHY_VARS_eNB_NB_IoT_s { * */ - //TODO: check what should be NUMBER_OF_UE_MAX_NB_IoT value NB_IoT_eNB_NPBCH_t *npbch; - NB_IoT_eNB_NPDCCH_t *npdcch[NUMBER_OF_UE_MAX_NB_IoT]; - NB_IoT_eNB_NDLSCH_t *ndlsch[NUMBER_OF_UE_MAX_NB_IoT][2]; - NB_IoT_eNB_NULSCH_t *nulsch[NUMBER_OF_UE_MAX_NB_IoT+1]; //nulsch[0] contains the RAR + NB_IoT_eNB_NPDCCH_t *npdcch[NUMBER_OF_UE_MAX]; + NB_IoT_eNB_NDLSCH_t *ndlsch[NUMBER_OF_UE_MAX][2]; + NB_IoT_eNB_NULSCH_t *nulsch[NUMBER_OF_UE_MAX+1]; //nulsch[0] contains the RAR NB_IoT_eNB_NDLSCH_t *ndlsch_SI,*ndlsch_ra, *ndlsch_SIB1; NB_IoT_DL_FRAME_PARMS frame_parms_NB_IoT; diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index a2c39852f5..e72465c4a9 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -255,7 +255,6 @@ typedef struct RU_proc_t_s { int instance_cnt_feptx; /// \internal This variable is protected by \ref mutex_ru_thread int instance_cnt_ru; - int instance_cnt_emulateRF; /// pthread structure for RU FH processing thread pthread_t pthread_FH; pthread_t pthread_FH1; @@ -271,8 +270,6 @@ typedef struct RU_proc_t_s { pthread_t pthread_fep[8]; /// pthread struct for RU TX FEP worker thread pthread_t pthread_feptx; - /// pthread struct for emulated RF - pthread_t pthread_emulateRF; /// pthread structure for asychronous RX/TX processing thread pthread_t pthread_asynch_rxtx; /// flag to indicate first RX acquisition @@ -296,8 +293,6 @@ typedef struct RU_proc_t_s { pthread_attr_t attr_fep; /// pthread attributes for worker feptx thread pthread_attr_t attr_feptx; - /// pthread attributes for emulated RF - pthread_attr_t attr_emulateRF; /// scheduling parameters for RU FH thread struct sched_param sched_param_FH; struct sched_param sched_param_FH1; @@ -324,8 +319,6 @@ typedef struct RU_proc_t_s { pthread_cond_t cond_fep[8]; /// condition varible for RU TX FEP thread pthread_cond_t cond_feptx; - /// condition varible for emulated RF - pthread_cond_t cond_emulateRF; /// condition variable for eNB signal pthread_cond_t cond_eNBs; /// condition variable for gNB signal @@ -353,8 +346,6 @@ typedef struct RU_proc_t_s { pthread_mutex_t mutex_feptx; /// mutex for ru_thread pthread_mutex_t mutex_ru; - /// mutex for emulated RF thread - pthread_mutex_t mutex_emulateRF; /// symbol mask for IF4p5 reception per subframe uint32_t symbol_mask[10]; /// time measurements for each subframe @@ -394,7 +385,6 @@ typedef struct RU_proc_t_s { /// pipeline ready state int ru_rx_ready; int ru_tx_ready; - int emulate_rf_busy; /// structure for precoding thread RU_prec_t prec[16]; @@ -407,7 +397,6 @@ typedef enum { REMOTE_IF4p5 =3, REMOTE_IF1pp =4, MAX_RU_IF_TYPES =5 - //EMULATE_RF =6 } RU_if_south_t; @@ -453,8 +442,6 @@ typedef struct RU_t_s { node_function_t function; /// Ethernet parameters for fronthaul interface eth_params_t eth_params; - /// flag to indicate RF emulation mode - int emulate_rf; /// numerology index int numerology; /// flag to indicate the RU is in sync with a master reference diff --git a/openair1/PHY/defs_UE.h b/openair1/PHY/defs_UE.h index 17ae02610e..20d5a9ab8d 100644 --- a/openair1/PHY/defs_UE.h +++ b/openair1/PHY/defs_UE.h @@ -640,7 +640,7 @@ typedef struct { /// mbsfn reference symbols uint32_t lte_gold_mbsfn_khz_1dot25_table[10][150]; - uint32_t X_u[64][839]; + c16_t X_u[64][839]; uint32_t high_speed_flag; uint32_t perfect_ce; diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h index 68ebf65462..6ae50482cc 100644 --- a/openair1/PHY/defs_eNB.h +++ b/openair1/PHY/defs_eNB.h @@ -254,12 +254,6 @@ typedef struct { pthread_mutex_t mutex_RUs; tpool_t *threadPool; int nbDecode; - notifiedFIFO_t *respDecode; - pthread_mutex_t mutex_emulateRF; - int instance_cnt_emulateRF; - pthread_t pthread_emulateRF; - pthread_attr_t attr_emulateRF; - pthread_cond_t cond_emulateRF; int first_rx; } L1_rxtx_proc_t; @@ -600,8 +594,8 @@ typedef struct PHY_VARS_eNB_s { // PUCCH1a/b energy detection parameters for eMTC per CE-level int pucch1ab_DTX_threshold_emtc[4]; - uint32_t X_u[64][839]; - uint32_t X_u_br[4][64][839]; + c16_t X_u[64][839]; + c16_t X_u_br[4][64][839]; uint8_t pbch_configured; uint8_t pbch_pdu[4]; //PBCH_PDU_SIZE char eNB_generate_rar; diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index ad17c243ae..fb549d4734 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -501,6 +501,8 @@ typedef struct PHY_VARS_gNB_s { time_stats_t dlsch_encoding_stats; time_stats_t dlsch_modulation_stats; time_stats_t dlsch_scrambling_stats; + time_stats_t dlsch_pdsch_generation_stats; + time_stats_t dlsch_layer_mapping_stats; time_stats_t dlsch_resource_mapping_stats; time_stats_t dlsch_precoding_stats; time_stats_t tinput; @@ -521,6 +523,9 @@ typedef struct PHY_VARS_gNB_s { time_stats_t slot_indication_stats; time_stats_t schedule_response_stats; time_stats_t ulsch_decoding_stats; + time_stats_t ts_deinterleave; + time_stats_t ts_rate_unmatch; + time_stats_t ts_ldpc_decode; time_stats_t ulsch_deinterleaving_stats; time_stats_t ulsch_channel_estimation_stats; time_stats_t pusch_channel_estimation_antenna_processing_stats; @@ -534,17 +539,10 @@ typedef struct PHY_VARS_gNB_s { time_stats_t srs_beam_report_stats; time_stats_t srs_iq_matrix_stats; - notifiedFIFO_t respPuschSymb; - notifiedFIFO_t respDecode; notifiedFIFO_t resp_L1; - notifiedFIFO_t L1_tx_free; - notifiedFIFO_t L1_tx_filled; notifiedFIFO_t L1_tx_out; notifiedFIFO_t L1_rx_out; - notifiedFIFO_t resp_RU_tx; tpool_t threadPool; - int nbSymb; - int nbAarx; int num_pusch_symbols_per_thread; int dmrs_num_antennas_per_thread; pthread_t L1_rx_thread; diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 9d8683481d..935226b238 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -336,6 +336,7 @@ typedef struct { /// Top-level PHY Data Structure for UE typedef struct PHY_VARS_NR_UE_s { + openair0_config_t openair0_cfg[MAX_CARDS]; /// \brief Module ID indicator for this instance uint8_t Mod_id; /// \brief Component carrier ID for this PHY instance @@ -498,6 +499,9 @@ typedef struct PHY_VARS_NR_UE_s { /// RF and Interface devices per CC openair0_device rfdevice; + /// Phase precompensation flag + bool no_phase_pre_comp; + void* scopeData; // Pointers to hold PDSCH data only for phy simulators void *phy_sim_rxdataF; @@ -507,6 +511,7 @@ typedef struct PHY_VARS_NR_UE_s { void *phy_sim_pdsch_dl_ch_estimates; void *phy_sim_pdsch_dl_ch_estimates_ext; uint8_t *phy_sim_dlsch_b; + uint8_t *phy_sim_test_buf; dynamic_barrier_t process_slot_tx_barriers[NUM_PROCESS_SLOT_TX_BARRIERS]; diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index d125e382ff..0d1cab4045 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -91,6 +91,8 @@ #define PBCH_MAX_RE_PER_SYMBOL (20 * 12) +#define NR_PUCCH_DMRS_RB 4 + typedef enum { NR_MU_0=0, NR_MU_1, @@ -111,7 +113,24 @@ typedef struct { uint8_t k_0_p[MAX_NUM_NR_SRS_AP][MAX_NUM_NR_SRS_SYMBOLS]; uint8_t srs_generated_signal_bits; c16_t **srs_generated_signal; - nfapi_nr_srs_pdu_t srs_pdu; + bool is_signal_generated; + int B_SRS; + int C_SRS; + int b_hop; + int comb_size; + int K_TC_overbar; + int n_SRS_cs; + int n_ID_SRS; + int n_shift; + int n_RRC; + int groupOrSequenceHopping; + int l_offset; + int T_SRS; + int T_offset; + int R; + int N_symb_SRS; + int n_srs_ports; + int resource_type; } nr_srs_info_t; typedef struct NR_DL_FRAME_PARMS NR_DL_FRAME_PARMS; diff --git a/openair1/PHY/impl_defs_top_NB_IoT.h b/openair1/PHY/impl_defs_top_NB_IoT.h index f9560cb228..8b3360c087 100644 --- a/openair1/PHY/impl_defs_top_NB_IoT.h +++ b/openair1/PHY/impl_defs_top_NB_IoT.h @@ -158,30 +158,30 @@ typedef struct { short n0_subband_power_tot_dBm[100]; // eNB measurements (per user) //! estimated received spatial signal power (linear) - unsigned int rx_spatial_power[NUMBER_OF_UE_MAX_NB_IoT][2][2]; + unsigned int rx_spatial_power[NUMBER_OF_UE_MAX][2][2]; //! estimated received spatial signal power (dB) - unsigned short rx_spatial_power_dB[NUMBER_OF_UE_MAX_NB_IoT][2][2]; + unsigned short rx_spatial_power_dB[NUMBER_OF_UE_MAX][2][2]; //! estimated rssi (dBm) - short rx_rssi_dBm[NUMBER_OF_UE_MAX_NB_IoT]; + short rx_rssi_dBm[NUMBER_OF_UE_MAX]; //! estimated correlation (wideband linear) between spatial channels (computed in dlsch_demodulation) - int rx_correlation[NUMBER_OF_UE_MAX_NB_IoT][2]; + int rx_correlation[NUMBER_OF_UE_MAX][2]; //! estimated correlation (wideband dB) between spatial channels (computed in dlsch_demodulation) - int rx_correlation_dB[NUMBER_OF_UE_MAX_NB_IoT][2]; + int rx_correlation_dB[NUMBER_OF_UE_MAX][2]; /// Wideband CQI (= SINR) - int wideband_cqi[NUMBER_OF_UE_MAX_NB_IoT][NB_ANTENNAS_RX]; + int wideband_cqi[NUMBER_OF_UE_MAX][NB_ANTENNAS_RX]; /// Wideband CQI in dB (= SINR dB) - int wideband_cqi_dB[NUMBER_OF_UE_MAX_NB_IoT][NB_ANTENNAS_RX]; + int wideband_cqi_dB[NUMBER_OF_UE_MAX][NB_ANTENNAS_RX]; /// Wideband CQI (sum of all RX antennas, in dB) - char wideband_cqi_tot[NUMBER_OF_UE_MAX_NB_IoT]; + char wideband_cqi_tot[NUMBER_OF_UE_MAX]; /// Subband CQI per RX antenna and RB (= SINR) - int subband_cqi[NUMBER_OF_UE_MAX_NB_IoT][NB_ANTENNAS_RX][100]; + int subband_cqi[NUMBER_OF_UE_MAX][NB_ANTENNAS_RX][100]; /// Total Subband CQI and RB (= SINR) - int subband_cqi_tot[NUMBER_OF_UE_MAX_NB_IoT][100]; + int subband_cqi_tot[NUMBER_OF_UE_MAX][100]; /// Subband CQI in dB and RB (= SINR dB) - int subband_cqi_dB[NUMBER_OF_UE_MAX_NB_IoT][NB_ANTENNAS_RX][100]; + int subband_cqi_dB[NUMBER_OF_UE_MAX][NB_ANTENNAS_RX][100]; /// Total Subband CQI and RB - int subband_cqi_tot_dB[NUMBER_OF_UE_MAX_NB_IoT][100]; + int subband_cqi_tot_dB[NUMBER_OF_UE_MAX][100]; } PHY_MEASUREMENTS_eNB_NB_IoT; diff --git a/openair1/PHY/log_tools.c b/openair1/PHY/log_tools.c new file mode 100644 index 0000000000..9d75296dc2 --- /dev/null +++ b/openair1/PHY/log_tools.c @@ -0,0 +1,83 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair1/PHY/log_tools.c + * \brief log tools used by data recording application (to be merged to existing OAI log tools) + * \author Abdo Gaber + * \date 2024 + * \version 1.0 + * \company Emerson, NI Test and Measurement + * \email: + * \note + * \warning + */ + +#include "log_tools.h" +#include +#include +#include +#include +#include +#include +#include "PHY/TOOLS/tools_defs.h" + +// Get Time Stamp in microseconds in YYYYMMDDHHMMSSmmmuuu format +char* get_time_stamp_usec(char time_stamp_str[]) +{ + // initialization to measure time stamp --This part should be moved to inilization part + time_t my_time; + struct tm* timeinfo; + time(&my_time); + struct timeval tv; + + // get time stamp + timeinfo = localtime(&my_time); + gettimeofday(&tv, NULL); + // Add time stamp: yyyy mm dd hh mm ss msec + uint16_t year = timeinfo->tm_year + 1900; + uint8_t mon = timeinfo->tm_mon + 1; + uint8_t mday = timeinfo->tm_mday; + uint8_t hour = timeinfo->tm_hour; + uint8_t min = timeinfo->tm_min; + uint8_t sec = timeinfo->tm_sec; + uint16_t usec = (tv.tv_usec); + // printf ("Time stamp: %d_%d_%d_%d_%d_%d_%d \n",year,mon,mday,hour,min,sec,usec); + // sprintf(time_stamp_str, "%d_%d_%d_%d_%d_%d_%d",year,mon,mday,hour,min,sec,usec); + sprintf(time_stamp_str, "%04d%02d%02d%02d%02d%02d%06d", year, mon, mday, hour, min, sec, usec); + + return time_stamp_str; +} + +// Function to convert timestamp string to integer +int convert_time_stamp_to_int(const char* timestamp) +{ + return atoi(timestamp); +} + +int split_time_stamp_and_convert_to_int(char time_stamp_str[], int shift, int length) +{ + char time_part[length + 1]; // Buffer to hold the date part YYYYMMDD or HHMMSSmmm + // Copy the first 8 or 9 characters (YYYYMMDD) to HHMMSSmmm + strncpy(time_part, time_stamp_str + shift, length); + time_part[length] = '\0'; // Null-terminate the string + // Convert timestamp string to integer + return convert_time_stamp_to_int(time_part); +} \ No newline at end of file diff --git a/openair1/PHY/log_tools.h b/openair1/PHY/log_tools.h new file mode 100644 index 0000000000..e75ae05233 --- /dev/null +++ b/openair1/PHY/log_tools.h @@ -0,0 +1,43 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair1/PHY/log_tools.h + * \brief log tools used by data recording application (to be merged to existing OAI log tools) + * \author Abdo Gaber + * \date 2024 + * \version 1.0 + * \company Emerson, NI Test and Measurement + * \email: + * \note + * \warning + */ + +#ifndef __PHY_LOG_TOOLS_H__ +#define __PHY_LOG_TOOLS_H__ + +#include +#include "PHY/TOOLS/tools_defs.h" + +char* get_time_stamp_usec(char time_stamp_str[]); +int convert_time_stamp_to_int(const char* timestamp); +int split_time_stamp_and_convert_to_int(char time_stamp_str[], int shift, int length); + +#endif /*__PHY_LOG_TOOLS_H__ */ \ No newline at end of file diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h index 97e9bee87e..8303c510c7 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -26,14 +26,317 @@ #include "PHY/NR_REFSIG/nr_refsig_common.h" #include "PHY/MODULATION/nr_modulation.h" -extern simde__m128i byte2bit16_lut[256]; -void init_byte2bit16(void); void init_byte2m128i(void); +// tables for mcs values for different payloads +static const uint8_t table1_mcs[] = {0, 6, 3, 9}; +static const uint8_t table2_mcs[] = {0, 3, 9, 6, 1, 4, 10, 7}; -static inline simde__m128i byte2bit16(uint8_t b) -{ - return byte2bit16_lut[b]; -} + /* + * The following tables implement TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (rows->u {0,1,..,29} / columns->n {0,1,...,M_ZC-1) + * Where base sequence r_u_v(n)=exp[j*phi(n)*pi/4] 0<=n<=M_ZC-1 and M_ZC={6,12,18,24} + * For M_ZC=30, base sequence r_u_v(n)=exp[-j((pi*[u+1]*[n+1]*[n+2])/31)] + */ + static const int16_t table_5_2_2_2_1_Re[30][6]={ // Table 5.2.2.2-1 (Re part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=6) + {-23170, 23170,-23170,-23170, 23170,-23170}, + {-23170,-23170, 23170, 23170,-23170,-23170}, + {-23170,-23170,-23170,-23170, 23170,-23170}, + { 23170, 23170, 23170,-23170, 23170,-23170}, + { 23170, 23170, 23170,-23170, 23170,-23170}, + {-23170, 23170, 23170,-23170,-23170,-23170}, + {-23170, 23170,-23170,-23170,-23170,-23170}, + {-23170, 23170, 23170,-23170, 23170, 23170}, + {-23170, 23170,-23170, 23170,-23170,-23170}, + {-23170,-23170, 23170,-23170,-23170,-23170}, + {-23170, 23170,-23170, 23170,-23170,-23170}, + {-23170, 23170,-23170, 23170, 23170,-23170}, + { 23170, 23170,-23170, 23170,-23170,-23170}, + { 23170, 23170,-23170,-23170, 23170,-23170}, + { 23170, 23170, 23170,-23170,-23170, 23170}, + { 23170, 23170, 23170, 23170,-23170,-23170}, + {-23170, 23170, 23170, 23170,-23170, 23170}, + {-23170,-23170, 23170, 23170, 23170,-23170}, + {-23170,-23170,-23170, 23170,-23170, 23170}, + {-23170, 23170, 23170,-23170, 23170,-23170}, + {-23170,-23170,-23170, 23170, 23170,-23170}, + {-23170, 23170,-23170,-23170,-23170, 23170}, + { 23170, 23170,-23170,-23170, 23170,-23170}, + { 23170, 23170,-23170,-23170, 23170,-23170}, + { 23170, 23170,-23170, 23170,-23170,-23170}, + { 23170, 23170,-23170, 23170,-23170,-23170}, + { 23170, 23170, 23170, 23170,-23170, 23170}, + { 23170, 23170, 23170,-23170, 23170, 23170}, + { 23170, 23170, 23170,-23170,-23170, 23170}, + { 23170, 23170,-23170, 23170, 23170, 23170} + }; + static const int16_t table_5_2_2_2_1_Im[30][6]={ // Table 5.2.2.2-1 (Im part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=6) + {-23170,-23170, 23170, 23170,-23170,-23170}, + {-23170, 23170,-23170,-23170, 23170,-23170}, + {-23170,-23170,-23170, 23170, 23170,-23170}, + { 23170, 23170, 23170, 23170,-23170,-23170}, + { 23170, 23170, 23170,-23170,-23170, 23170}, + {-23170, 23170,-23170,-23170,-23170,-23170}, + {-23170, 23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170,-23170, 23170,-23170}, + {-23170,-23170,-23170, 23170,-23170,-23170}, + {-23170,-23170, 23170,-23170, 23170,-23170}, + {-23170, 23170, 23170, 23170,-23170,-23170}, + {-23170,-23170,-23170, 23170, 23170,-23170}, + { 23170, 23170, 23170,-23170,-23170, 23170}, + { 23170, 23170, 23170, 23170,-23170, 23170}, + { 23170, 23170, 23170,-23170, 23170,-23170}, + { 23170, 23170, 23170,-23170, 23170,-23170}, + {-23170,-23170,-23170,-23170, 23170,-23170}, + {-23170,-23170,-23170, 23170,-23170,-23170}, + {-23170,-23170,-23170, 23170,-23170,-23170}, + {-23170, 23170, 23170,-23170,-23170,-23170}, + {-23170, 23170,-23170, 23170, 23170,-23170}, + {-23170, 23170,-23170,-23170,-23170,-23170}, + { 23170, 23170,-23170, 23170, 23170, 23170}, + { 23170, 23170,-23170,-23170, 23170,-23170}, + { 23170, 23170, 23170,-23170, 23170, 23170}, + { 23170, 23170,-23170, 23170, 23170, 23170}, + { 23170, 23170,-23170,-23170, 23170,-23170}, + { 23170, 23170,-23170, 23170,-23170,-23170}, + { 23170, 23170,-23170, 23170,-23170,-23170}, + { 23170, 23170,-23170, 23170,-23170,-23170} + }; + static const int16_t table_5_2_2_2_2_Re[30][12]={ // Table 5.2.2.2-2 (Re part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=12) + {-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170}, + {-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, + {-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170}, + {-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, + {-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170}, + {-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170}, + { 23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170}, + { 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170}, + {-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170}, + {-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170}, + {-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170}, + {-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, + {-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170}, + {-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170}, + { 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170}, + {-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170}, + { 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170}, + { 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170}, + {-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170}, + {-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170}, + {-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170}, + {-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170}, + {-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170}, + {-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170}, + {-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170}, + { 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170}, + {-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170}, + { 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170}, + {-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170} + }; + static const int16_t table_5_2_2_2_2_Im[30][12]={ // Table 5.2.2.2-2 (Im part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=12) + {-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170}, + {-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170}, + {-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170}, + {-23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170}, + {-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170}, + {-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170}, + { 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, + {-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170}, + {-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170}, + {-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170}, + {-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, + {-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170}, + {-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170}, + {-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170}, + { 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170}, + {-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, + {-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170}, + {-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170}, + {-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170}, + {-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170}, + { 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170}, + {-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170}, + {-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, + { 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170}, + {-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170}, + {-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170}, + {-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170}, + { 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170}, + {-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170} + }; + static const int16_t table_5_2_2_2_3_Re[30][18]={ // Table 5.2.2.2-3 (Re part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=18) + { 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170}, + {-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170}, + {-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170}, + { 23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170}, + {-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170}, + {-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170}, + { 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170}, + {-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, + {-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, + {-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170}, + {-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170}, + {-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170}, + { 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170}, + {-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170}, + {-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, + {-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170}, + {-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170}, + {-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170}, + {-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170}, + {-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, + { 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170}, + {-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170}, + {-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170}, + {-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170}, + {-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170}, + { 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170}, + {-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170} + }; + static const int16_t table_5_2_2_2_3_Im[30][18]={ // Table 5.2.2.2-3 (Im part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=18) + {-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, + { 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170}, + {-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170}, + { 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170}, + { 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170}, + {-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170}, + { 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170}, + {-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170}, + { 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170}, + {-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170}, + {-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170}, + {-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170}, + { 23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170}, + {-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170}, + { 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170}, + {-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170}, + {-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170}, + {-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170}, + { 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170}, + {-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170}, + { 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170}, + {-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170}, + { 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170}, + { 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170}, + {-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170}, + {-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170}, + {-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170}, + {-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170} + }; + static const int16_t table_5_2_2_2_4_Re[30][24]={ // Table 5.2.2.2-4 (Re part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=24) + { 23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170}, + { 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, + { 23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170}, + { 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170}, + { 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170}, + {-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170}, + {-23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170}, + {-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170}, + {-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170}, + { 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170}, + {-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170}, + {-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170}, + {-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170}, + {-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170}, + {-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170}, + {-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170}, + {-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170}, + {-23170, 23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170}, + {-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170}, + {-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170}, + {-23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170}, + {-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170}, + {-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170}, + {-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, + {-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170}, + {-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170}, + { 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170}, + {-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170}, + {-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170}, + {-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170} + }; + static const int16_t table_5_2_2_2_4_Im[30][24]={ // Table 5.2.2.2-4 (Im part) TS 38.211 Subclause 5.2.2.2 Base sequences of length less than 36 (M_ZC=24) + {-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170}, + {-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170}, + { 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, + {-23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170}, + {-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, + {-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170}, + {-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170}, + {-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170}, + { 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170}, + {-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170}, + {-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170}, + { 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170}, + {-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170}, + {-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170}, + {-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170}, + {-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170}, + { 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170}, + {-23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170,-23170,-23170}, + {-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170}, + {-23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170,-23170,-23170}, + { 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170}, + {-23170, 23170,-23170, 23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170}, + {-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170}, + {-23170, 23170,-23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170,-23170,-23170,-23170}, + {-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170, 23170,-23170,-23170}, + {-23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170,-23170}, + { 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170, 23170,-23170, 23170, 23170,-23170,-23170,-23170}, + {-23170, 23170,-23170, 23170,-23170, 23170, 23170, 23170, 23170,-23170,-23170,-23170, 23170, 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170,-23170,-23170}, + { 23170,-23170,-23170, 23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170,-23170,-23170,-23170, 23170,-23170, 23170, 23170, 23170,-23170, 23170,-23170,-23170,-23170} + }; + + /* + * The following tables implement TS 38.211 table 6.3.2.4.1-1: Number of PUCCH symbols and the corresponding N_SF_mprime_PUCCH_1 + * One table for no intra-slot hopping + * Two tables for intra-slot hopping (mprime=0 and mprime=1) + */ + static const uint8_t table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_noHop[14] = {0,0,0,2,2,3,3,4,4,5,5,6,6,7}; // for index PUCCH-length, we obtain N_SF_mprime_PUCCH_1 when no intra-slot hopping + static const uint8_t table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m0Hop[14] = {0,0,0,1,1,1,1,2,2,2,2,3,3,3}; // for index PUCCH-length, we obtain N_SF_mprime_PUCCH_1 when intra-slot hopping and mprime=0 + static const uint8_t table_6_3_2_4_1_1_N_SF_mprime_PUCCH_1_m1Hop[14] = {0,0,0,1,1,2,2,2,2,3,3,3,3,4}; // for index PUCCH-length, we obtain N_SF_mprime_PUCCH_1 when intra-slot hopping and mprime=1 + /* + * The following tables implement TS 38.211 table 6.4.1.3.1.1-1: Number of DM-RS symbols and the corresponding N_SF_mprime_PUCCH_1 + * One table for no intra-slot hopping + * Two tables for intra-slot hopping (mprime=0 and mprime=1) + */ + static const uint8_t table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_noHop[14] = {0,0,0,2,3,3,4,4,5,5,6,6,7,7}; // for index PUCCH-DM-RS-length, we obtain N_SF_mprime_PUCCH_1 when no intra-slot hopping + static const uint8_t table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m0Hop[14] = {0,0,0,1,1,2,2,2,2,3,3,3,3,4}; // for index PUCCH-DM-RS-length, we obtain N_SF_mprime_PUCCH_1 when intra-slot hopping and mprime=0 + static const uint8_t table_6_4_1_3_1_1_1_N_SF_mprime_PUCCH_1_m1Hop[14] = {0,0,0,1,2,1,2,2,3,2,3,3,4,3}; // for index PUCCH-DM-RS-length, we obtain N_SF_mprime_PUCCH_1 when intra-slot hopping and mprime=1 + /* The following tables implement TS 38.211 table 6.3.2.4.1-2: Orthogonal sequences wi(m)=exp(j*2*pi*phi(m)/N_SF) for PUCCH format 1 + uint16_t table_6_3_2_4_1_2_W2[2][2] = {{0,0}, {0,1}}; + uint16_t table_6_3_2_4_1_2_W3[3][3] = {{0,0,0}, {0,1,2}, {0,2,1}}; + uint16_t table_6_3_2_4_1_2_W4[4][4] = {{0,0,0,0}, {0,2,0,2}, {0,0,2,2} , {0,2,2,0}}; + uint16_t table_6_3_2_4_1_2_W5[2][2] = {{0,0,0,0,0}, {0,1,2,3,4}, {0,2,4,1,3}, {0,3,1,4,2}, {0,4,3,2,1}}; + uint16_t table_6_3_2_4_1_2_W6[2][2] = {{0,0,0,0,0,0}, {0,1,2,3,4,5}, {0,2,4,0,2,4}, {0,3,0,3,0,3}, {0,4,2,0,4,2}, {0,5,4,3,2,1}}; + uint16_t table_6_3_2_4_1_2_W7[2][2] = {{0,0,0,0,0,0,0},{0,1,2,3,4,5,6},{0,2,4,6,1,3,5},{0,3,6,2,5,1,4},{0,4,1,5,2,6,3},{0,5,3,1,6,4,2},{0,6,5,4,3,2,1}}; + */ + static const int16_t table_6_3_2_4_1_2_Wi_Re[8][7][7] = { + {{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{32767,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{32767,32767,0,0,0,0,0}, {32767,-32767,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{32767,32767,32767,0,0,0,0}, {32767,-16384,-16384,0,0,0,0}, {32767,-16384,-16384,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{32767,32767,32767,32767,0,0,0}, {32767,-32767,32767,-32767,0,0,0}, {32767,32767,-32767,-32767,0,0,0}, {32767,-32767,-32767,32767,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{32767,32767,32767,32767,32767,0,0}, {32767,10126,-26509,-26509,10126,0,0}, {32767,-26509,10126,10126,-26509,0,0}, {32767,-26509,10126,10126,-26509,0,0}, {32767,10126,-26509,-26509,10126,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{32767,32767,32767,32767,32767,32767,0}, {32767,16384,-16384,-32767,-16384,16384,0}, {32767,-16384,-16384,32767,-16384,-16384,0}, {32767,-32767,32767,-32767,32767,-32767,0}, {32767,-16384,-16384,32767,-16384,-16384,0}, {32767,16384,-16384,-32767,-16384,16384,0}, {0,0,0,0,0,0,0}}, + {{32767,32767,32767,32767,32767,32767,32767},{32767,20430,-7291,-29522,-29522,-7291,20430},{32767,-7291,-29522,20430,20430,-29522,-7291},{32767,-29522,20430,-7291,-7291,20430,-29522},{32767,-29522,20430,-7291,-7291,20430,-29522},{32767,-7291,-29522,20430,20430,-29522,-7291},{32767,20430,-7291,-29522,-29522,-7291,20430}} + }; + static const int16_t table_6_3_2_4_1_2_Wi_Im[8][7][7] = { + {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0},{0,28377,-28377,0,0,0,0}, {0,-28377,28377,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0},{0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0},{0,31163,19260,-19260,-31163,0,0}, {0,19260,-31163,31163,-19260,0,0}, {0,-19260,31163,-31163,19260,0,0}, {0,-31163,-19260,19260,31163,0,0}, {0,0,0,0,0,0,0}, {0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0},{0,28377,28377,0,-28377,-28377,0}, {0,28377,-28377,0,28377,-28377,0}, {0,0,0,0,0,0,0}, {0,-28377,28377,0,-28377,28377,0}, {0,-28377,-28377,0,28377,28377,0}, {0,0,0,0,0,0,0}}, + {{0,0,0,0,0,0,0},{0,25618,31945,14217,-14217,-31945,-25618},{0,31945,-14217,-25618,25618,14217,-31945},{0,14217,-25618,31945,-31945,25618,-14217},{0,-14217,25618,-31945,31945,-25618,14217},{0,-31945,14217,25618,-25618,-14217,31945},{0,-25618,-31945,-14217,14217,31945,25618}} + }; typedef struct { int size; @@ -47,13 +350,29 @@ typedef struct { csi_mapping_parms_t get_csi_mapping_parms(int row, int b, int l0, int l1); int get_cdm_group_size(int cdm_type); void nr_qpsk_llr(int32_t *rxdataF_comp, int16_t *llr, uint32_t nb_re); -void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint32_t nb_re); -void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int16_t *llr, uint32_t nb_re); -void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int32_t *ch_mag3, int16_t *llr, uint32_t nb_re); +void nr_16qam_llr(int32_t *rxdataF_comp, c16_t *ch_mag_in, int16_t *llr, uint32_t nb_re); +void nr_64qam_llr(int32_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, int16_t *llr, uint32_t nb_re); +void nr_256qam_llr(int32_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, c16_t *ch_mag3, int16_t *llr, uint32_t nb_re); 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); void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size); +void nr_channel_level(const int symbol, + const int size_est, + const c16_t ch_estimates_ext[][size_est], + const int nb_rx, + const int Nl, + int32_t avg[nb_rx * Nl], + const uint32_t len); +void nr_scale_channel(int size, int ch_estimates_ext[][size], int symb, uint32_t len, int nrOfLayers, int nb_rx, int shift_ch_ext); +bool generate_srs_nr(NR_DL_FRAME_PARMS *frame_parms, + c16_t **txdataF, + uint16_t symbol_offset, + int bwp_start, + nr_srs_info_t *nr_srs_info, + int16_t amp, + frame_t frame_number, + slot_t slot_number); void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, const csi_mapping_parms_t *phy_csi_parms, const int16_t amp, diff --git a/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h b/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h index 9f91274bae..79b0b378e8 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h +++ b/openair1/PHY/nr_phy_common/inc/nr_ue_phy_meas.h @@ -47,6 +47,7 @@ FN(DLSCH_PROCEDURES_STATS),\ FN(PHY_PROC_TX),\ FN(PUSCH_PROC_STATS),\ + FN(UCI_ON_PUSCH_MAPPING),\ FN(ULSCH_SEGMENTATION_STATS),\ FN(ULSCH_LDPC_ENCODING_STATS),\ FN(ULSCH_RATE_MATCHING_STATS),\ diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common.c b/openair1/PHY/nr_phy_common/src/nr_phy_common.c index 5a950eba86..a723780f94 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c @@ -26,34 +26,18 @@ #endif #define PEAK_DETECT_THRESHOLD 15 - -simde__m128i byte2bit16_lut[256]; -void init_byte2bit16(void) +simde__m128i byte2m128i[256]; +void init_byte2m128i(void) { for (int s = 0; s < 256; s++) { - byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], s & 1, 0); - byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 1) & 1, 1); - byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 2) & 1, 2); - byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 3) & 1, 3); - byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 4) & 1, 4); - byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 5) & 1, 5); - byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 6) & 1, 6); - byte2bit16_lut[s] = simde_mm_insert_epi16(byte2bit16_lut[s], (s >> 7) & 1, 7); - } -} - -simde__m128i byte2m128i[256]; -void init_byte2m128i(void) { - - for (int s=0;s<256;s++) { - byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s],(1-2*(s&1)),0); - byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s],(1-2*((s>>1)&1)),1); - byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s],(1-2*((s>>2)&1)),2); - byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s],(1-2*((s>>3)&1)),3); - byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s],(1-2*((s>>4)&1)),4); - byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s],(1-2*((s>>5)&1)),5); - byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s],(1-2*((s>>6)&1)),6); - byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s],(1-2*((s>>7)&1)),7); + byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s], (1 - 2 * (s & 1)), 0); + byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s], (1 - 2 * ((s >> 1) & 1)), 1); + byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s], (1 - 2 * ((s >> 2) & 1)), 2); + byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s], (1 - 2 * ((s >> 3) & 1)), 3); + byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s], (1 - 2 * ((s >> 4) & 1)), 4); + byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s], (1 - 2 * ((s >> 5) & 1)), 5); + byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s], (1 - 2 * ((s >> 6) & 1)), 6); + byte2m128i[s] = simde_mm_insert_epi16(byte2m128i[s], (1 - 2 * ((s >> 7) & 1)), 7); } } @@ -71,17 +55,12 @@ void init_delay_table(uint16_t ofdm_symbol_size, } } -int16_t saturating_sub(int16_t a, int16_t b) +static inline c16_t saturating_sub(c16_t a, c16_t b) { - int32_t result = (int32_t)a - (int32_t)b; - - if (result < INT16_MIN) { - return INT16_MIN; - } else if (result > INT16_MAX) { - return INT16_MAX; - } else { - return (int16_t)result; - } + c32_t tmp = {a.r - abs(b.r), a.i - abs(b.i)}; + tmp = (c32_t){min(tmp.r, INT16_MAX), min(tmp.i, INT16_MAX)}; + c16_t tmp2 = (c16_t){max(tmp.r, -INT16_MAX), max(tmp.i, -INT16_MAX)}; + return tmp2; } //---------------------------------------------------------------------------------------------- @@ -101,23 +80,21 @@ void nr_qpsk_llr(int32_t *rxdataF_comp, int16_t *llr, uint32_t nb_re) // 16-QAM //---------------------------------------------------------------------------------------------- -void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint32_t nb_re) +void nr_16qam_llr(int32_t *rxdataF_comp, c16_t *ch_mag_in, int16_t *llr, uint32_t nb_re) { simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; - simde__m256i *ch_mag = (simde__m256i *)ch_mag_in; + simde__m256i *ch_mag256 = (simde__m256i *)ch_mag_in; int64_t *llr_64 = (int64_t *)llr; #ifndef USE_128BIT - simde__m256i xmm0, xmm1, xmm2; - for (int i = 0; i < (nb_re >> 3); i++) { // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm256_abs_epi16(*rxF_256); + simde__m256i xmm0 = protected_abs256(*rxF_256); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - xmm0 = simde_mm256_subs_epi16(*ch_mag, xmm0); + xmm0 = simde_mm256_subs_epi16(*ch_mag256, xmm0); - xmm1 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); - xmm2 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); + simde__m256i xmm1 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); + simde__m256i xmm2 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); // xmm1 |1st 2ed 3rd 4th 9th 10th 13rd 14th| // xmm2 |5th 6th 7th 8th 11st 12ed 15th 16th| @@ -131,20 +108,20 @@ void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint3 *llr_64++ = simde_mm256_extract_epi64(xmm2, 2); *llr_64++ = simde_mm256_extract_epi64(xmm2, 3); rxF_256++; - ch_mag++; + ch_mag256++; } nb_re &= 0x7; #endif simde__m128i *rxF_128 = (simde__m128i *)rxF_256; - simde__m128i *ch_mag_128 = (simde__m128i *)ch_mag; + simde__m128i *ch_mag_128 = (simde__m128i *)ch_mag256; simde__m128i *llr_128 = (simde__m128i *)llr_64; // Each iteration does 4 RE (gives 16 16bit-llrs) for (int i = 0; i < (nb_re >> 2); i++) { // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - simde__m128i xmm0 = simde_mm_abs_epi16(*rxF_128); + simde__m128i xmm0 = protected_abs128(*rxF_128); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 xmm0 = simde_mm_subs_epi16(*ch_mag_128, xmm0); @@ -157,18 +134,13 @@ void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint3 nb_re &= 0x3; - int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ch_mag_i16 = (int16_t *)ch_mag_128; - int16_t *llr_i16 = (int16_t *)llr_128; + c16_t *rxDataF = (c16_t *)rxF_128; + c16_t *ch_mag = (c16_t *)ch_mag_128; + c16_t *llr_tail = (c16_t *)llr_128; for (uint i = 0U; i < nb_re; i++) { - int16_t real = rxDataF_i16[2 * i]; - int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ch_mag_i16[2 * i]; - int16_t mag_imag = ch_mag_i16[2 * i + 1]; - llr_i16[4 * i] = real; - llr_i16[4 * i + 1] = imag; - llr_i16[4 * i + 2] = saturating_sub(mag_real, abs(real)); - llr_i16[4 * i + 3] = saturating_sub(mag_imag, abs(imag)); + c16_t tmp = *rxDataF++; + *llr_tail++ = tmp; + *llr_tail++ = saturating_sub(*ch_mag++, tmp); } } @@ -176,7 +148,7 @@ void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint3 // 64-QAM //---------------------------------------------------------------------------------------------- -void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int16_t *llr, uint32_t nb_re) +void nr_64qam_llr(int32_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, int16_t *llr, uint32_t nb_re) { simde__m256i *rxF = (simde__m256i *)rxdataF_comp; @@ -184,15 +156,14 @@ void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int1 simde__m256i *ch_magb = (simde__m256i *)ch_mag2; int32_t *llr_32 = (int32_t *)llr; - #ifndef USE_128BIT for (int i = 0; i < (nb_re >> 3); i++) { simde__m256i xmm0 = simde_mm256_loadu_si256(rxF); // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - simde__m256i xmm1 = simde_mm256_abs_epi16(xmm0); + simde__m256i xmm1 = protected_abs256(xmm0); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 xmm1 = simde_mm256_subs_epi16(*ch_maga, xmm1); - simde__m256i xmm2 = simde_mm256_abs_epi16(xmm1); + simde__m256i xmm2 = protected_abs256(xmm1); xmm2 = simde_mm256_subs_epi16(*ch_magb, xmm2); // xmm0 |1st 4th 7th 10th 13th 16th 19th 22ed| // xmm1 |2ed 5th 8th 11th 14th 17th 20th 23rd| @@ -244,9 +215,9 @@ void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int1 for (int i = 0; i < (nb_re >> 2); i++) { simde__m128i xmm0, xmm1, xmm2; xmm0 = *rxF_128; - xmm1 = simde_mm_abs_epi16(xmm0); + xmm1 = protected_abs128(xmm0); xmm1 = simde_mm_subs_epi16(*ch_mag_128, xmm1); - xmm2 = simde_mm_abs_epi16(xmm1); + xmm2 = protected_abs128(xmm1); xmm2 = simde_mm_subs_epi16(*ch_magb_128, xmm2); *llr_32++ = simde_mm_extract_epi32(xmm0, 0); @@ -268,27 +239,19 @@ void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int1 nb_re &= 0x3; - int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ch_mag_i16 = (int16_t *)ch_mag_128; - int16_t *ch_magb_i16 = (int16_t *)ch_magb_128; - int16_t *llr_i16 = (int16_t *)llr_32; + c16_t *rxDataF = (c16_t *)rxF_128; + c16_t *ch_mag_tail = (c16_t *)ch_mag_128; + c16_t *ch_magb_tail = (c16_t *)ch_magb_128; + c16_t *llr_tail = (c16_t *)llr_32; for (int i = 0; i < nb_re; i++) { - int16_t real = rxDataF_i16[2 * i]; - int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ch_mag_i16[2 * i]; - int16_t mag_imag = ch_mag_i16[2 * i + 1]; - llr_i16[6 * i] = real; - llr_i16[6 * i + 1] = imag; - llr_i16[6 * i + 2] = saturating_sub(mag_real, abs(real)); - llr_i16[6 * i + 3] = saturating_sub(mag_imag, abs(imag)); - int16_t mag_realb = ch_magb_i16[2 * i]; - int16_t mag_imagb = ch_magb_i16[2 * i + 1]; - llr_i16[6 * i + 4] = saturating_sub(mag_realb, abs(llr_i16[6 * i + 2])); - llr_i16[6 * i + 5] = saturating_sub(mag_imagb, abs(llr_i16[6 * i + 3])); + *llr_tail++ = *rxDataF; + c16_t tmp = saturating_sub(*ch_mag_tail++, *rxDataF++); + *llr_tail++ = tmp; + *llr_tail++ = saturating_sub(*ch_magb_tail++, tmp); } } -void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int32_t *ch_mag3, int16_t *llr, uint32_t nb_re) +void nr_256qam_llr(int32_t *rxdataF_comp, c16_t *ch_mag, c16_t *ch_mag2, c16_t *ch_mag3, int16_t *llr, uint32_t nb_re) { simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; simde__m256i *llr256 = (simde__m256i *)llr; @@ -297,26 +260,24 @@ void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int simde__m256i *ch_magb = (simde__m256i *)ch_mag2; simde__m256i *ch_magc = (simde__m256i *)ch_mag3; #ifndef USE_128BIT - simde__m256i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; - for (int i = 0; i < (nb_re >> 3); i++) { // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm256_abs_epi16(*rxF_256); + simde__m256i xmm0 = protected_abs256(*rxF_256); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 xmm0 = simde_mm256_subs_epi16(*ch_maga, xmm0); // xmmtmpD2 contains 16 LLRs - xmm1 = simde_mm256_abs_epi16(xmm0); + simde__m256i xmm1 = protected_abs256(xmm0); xmm1 = simde_mm256_subs_epi16(*ch_magb, xmm1); // contains 16 LLRs - xmm2 = simde_mm256_abs_epi16(xmm1); + simde__m256i xmm2 = protected_abs256(xmm1); xmm2 = simde_mm256_subs_epi16(*ch_magc, xmm2); // contains 16 LLRs // rxF[i] A0 A1 A2 A3 A4 A5 A6 A7 bits 7,6 // xmm0 B0 B1 B2 B3 B4 B5 B6 B7 bits 5,4 // xmm1 C0 C1 C2 C3 C4 C5 C6 C7 bits 3,2 // xmm2 D0 D1 D2 D3 D4 D5 D6 D7 bits 1,0 - xmm3 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); // A0 B0 A1 B1 A4 B4 A5 B5 - xmm4 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); // A2 B2 A3 B3 A6 B6 A7 B7 - xmm5 = simde_mm256_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 C4 D4 C5 D5 - xmm6 = simde_mm256_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 C6 D6 C7 D7 + simde__m256i xmm3 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); // A0 B0 A1 B1 A4 B4 A5 B5 + simde__m256i xmm4 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); // A2 B2 A3 B3 A6 B6 A7 B7 + simde__m256i xmm5 = simde_mm256_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 C4 D4 C5 D5 + simde__m256i xmm6 = simde_mm256_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 C6 D6 C7 D7 xmm0 = simde_mm256_unpacklo_epi64(xmm3, xmm5); // A0 B0 C0 D0 A4 B4 C4 D4 xmm1 = simde_mm256_unpackhi_epi64(xmm3, xmm5); // A1 B1 C1 D1 A5 B5 C5 D5 @@ -341,16 +302,15 @@ void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int simde__m128i *ch_maga_128 = (simde__m128i *)ch_maga; simde__m128i *ch_magb_128 = (simde__m128i *)ch_magb; simde__m128i *ch_magc_128 = (simde__m128i *)ch_magc; - for (int i = 0; i < (nb_re >> 2); i++) { simde__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm_abs_epi16(*rxF_128); + xmm0 = protected_abs128(*rxF_128); // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 xmm0 = simde_mm_subs_epi16(*ch_maga_128, xmm0); - xmm1 = simde_mm_abs_epi16(xmm0); + xmm1 = protected_abs128(xmm0); xmm1 = simde_mm_subs_epi16(*ch_magb_128, xmm1); // contains 8 LLRs - xmm2 = simde_mm_abs_epi16(xmm1); + xmm2 = protected_abs128(xmm1); xmm2 = simde_mm_subs_epi16(*ch_magc_128, xmm2); // contains 8 LLRs // rxF[i] A0 A1 A2 A3 // xmm0 B0 B1 B2 B3 @@ -372,30 +332,20 @@ void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int ch_magc_128++; } - if (nb_re & 3) { - for (int i = 0; i < (nb_re & 0x3); i++) { - int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ch_mag_i16 = (int16_t *)ch_maga_128; - int16_t *ch_magb_i16 = (int16_t *)ch_magb_128; - int16_t *ch_magc_i16 = (int16_t *)ch_magc_128; - int16_t *llr_i16 = (int16_t *)llr_128; - int16_t real = rxDataF_i16[2 * i + 0]; - int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ch_mag_i16[2 * i]; - int16_t mag_imag = ch_mag_i16[2 * i + 1]; - llr_i16[8 * i] = real; - llr_i16[8 * i + 1] = imag; - llr_i16[8 * i + 2] = saturating_sub(mag_real, abs(real)); - llr_i16[8 * i + 3] = saturating_sub(mag_imag, abs(imag)); - int16_t magb_real = ch_magb_i16[2 * i]; - int16_t magb_imag = ch_magb_i16[2 * i + 1]; - llr_i16[8 * i + 4] = saturating_sub(magb_real, abs(llr_i16[8 * i + 2])); - llr_i16[8 * i + 5] = saturating_sub(magb_imag, abs(llr_i16[8 * i + 3])); - int16_t magc_real = ch_magc_i16[2 * i]; - int16_t magc_imag = ch_magc_i16[2 * i + 1]; - llr_i16[8 * i + 6] = saturating_sub(magc_real, abs(llr_i16[8 * i + 4])); - llr_i16[8 * i + 7] = saturating_sub(magc_imag, abs(llr_i16[8 * i + 5])); - } + nb_re &= 0x3; + c16_t *rxDataF = (c16_t *)rxF_128; + c16_t *ch_mag_tail = (c16_t *)ch_maga_128; + c16_t *ch_magb_tail = (c16_t *)ch_magb_128; + c16_t *ch_magc_tail = (c16_t *)ch_magc_128; + c16_t *llr_tail = (c16_t *)llr_128; + for (int i = 0; i < nb_re; i++) { + c16_t tmp = *rxDataF++; + *llr_tail++ = tmp; + c16_t tmp1 = saturating_sub(*ch_mag_tail++, tmp); + *llr_tail++ = tmp1; + c16_t tmp2 = saturating_sub(*ch_magb_tail++, tmp1); + *llr_tail++ = tmp2; + *llr_tail++ = saturating_sub(*ch_magc_tail++, tmp2); } } @@ -454,6 +404,46 @@ unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, in return (0); } +// compute average channel_level on each antenna +void nr_channel_level(const int symbol, + const int size_est, + const c16_t ch_estimates_ext[][size_est], + const int nb_rx, + const int Nl, + int32_t avg[nb_rx * Nl], + const uint32_t len) +{ + int16_t x = factor2(len); + int16_t y = len >> x; + for (int aarx = 0; aarx < nb_rx; aarx++) { + for (int l = 0; l < Nl; l++) { + simde__m128i *ch128 = (simde__m128i *)&ch_estimates_ext[l * nb_rx + aarx][symbol * len]; + //compute average level + avg[l * nb_rx + aarx] = simde_mm_average(ch128, len, x, y); + LOG_D(PHY, "Channel level: %d\n", avg[l * nb_rx + aarx]); + } + } +} + +void nr_scale_channel(int size, int ch_estimates_ext[][size], int symb, uint32_t len, int nrOfLayers, int nb_rx, int shift_ch_ext) +{ + for (int l = 0; l < nrOfLayers; l++) { + for (int aarx = 0; aarx < nb_rx; aarx++) { + simde__m128i *ul_ch128 = (simde__m128i *)&ch_estimates_ext[l * nb_rx + aarx][symb * len]; + int loop_end = len >> 2; + for (int i = 0; i < loop_end; i++) { + ul_ch128[i] = simde_mm_srai_epi16(ul_ch128[i], shift_ch_ext); + } + // loop for the remaining elements + int start_index = loop_end * 4; + for (int j = start_index; j < len; j++) { + c16_t *temp = ((c16_t *)ul_ch128) + j; + *temp = c16Shift(*temp, shift_ch_ext); + } + } + } +} + void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size) { const double phase_inc = -fo_Hz / (samples_per_ms * 1000); diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c new file mode 100644 index 0000000000..ba5d792428 --- /dev/null +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c @@ -0,0 +1,343 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "PHY/nr_phy_common/inc/nr_phy_common.h" +#include "PHY/NR_REFSIG/dmrs_nr.h" +#include "PHY/NR_REFSIG/ul_ref_seq_nr.h" + +#define SRS_PERIODICITY (17) +static const uint16_t srs_periodicity[SRS_PERIODICITY] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560}; +// TS 38.211 - Table 6.4.1.4.2-1 +static const uint16_t srs_max_number_cs[3] = {8, 12, 6}; + +//#define SRS_DEBUG + +static int group_number_hopping(int slot_number, uint8_t n_ID_SRS, uint8_t l0, uint8_t l_line) +{ + // Pseudo-random sequence c(i) defined by TS 38.211 - Section 5.2.1 + uint32_t cinit = n_ID_SRS; + uint8_t c_last_index = 8 * (slot_number * NR_SYMBOLS_PER_SLOT + l0 + l_line) + 7; + uint32_t *c_sequence = calloc(c_last_index + 1, sizeof(uint32_t)); + pseudo_random_sequence(c_last_index + 1, c_sequence, cinit); + + // TS 38.211 - 6.4.1.4.2 Sequence generation + uint32_t f_gh = 0; + for (int m = 0; m <= 7; m++) { + f_gh += c_sequence[8 * (slot_number * NR_SYMBOLS_PER_SLOT + l0 + l_line) + m] << m; + } + f_gh = f_gh % 30; + int u = (f_gh + n_ID_SRS) % U_GROUP_NUMBER; + free(c_sequence); + return u; +} + +static int sequence_number_hopping(int slot_number, uint8_t n_ID_SRS, uint16_t M_sc_b_SRS, uint8_t l0, uint8_t l_line) +{ + int v = 0; + if (M_sc_b_SRS > 6 * NR_NB_SC_PER_RB) { + // Pseudo-random sequence c(i) defined by TS 38.211 - Section 5.2.1 + uint32_t cinit = n_ID_SRS; + uint8_t c_last_index = (slot_number * NR_SYMBOLS_PER_SLOT + l0 + l_line); + uint32_t *c_sequence = calloc(c_last_index + 1, sizeof(uint32_t)); + pseudo_random_sequence(c_last_index + 1, c_sequence, cinit); + // TS 38.211 - 6.4.1.4.2 Sequence generation + v = c_sequence[c_last_index]; + free(c_sequence); + } + return v; +} + +static int compute_F_b(frame_t frame_number, + slot_t slot_number, + int slots_per_frame, + nr_srs_info_t *nr_srs_info, + uint8_t l_line, + uint8_t b) +{ + // Compute the number of SRS transmissions + uint16_t n_SRS = 0; + if (nr_srs_info->resource_type == aperiodic) { + n_SRS = l_line / nr_srs_info->R; + } else { + int t = (slots_per_frame * frame_number + slot_number - nr_srs_info->T_offset) / nr_srs_info->T_SRS; + n_SRS = t * (nr_srs_info->N_symb_SRS / nr_srs_info->R) + (l_line / nr_srs_info->R); + } + + uint16_t product_N_b = 1; + for (unsigned int b_prime = nr_srs_info->b_hop; b_prime < nr_srs_info->B_SRS; b_prime++) { + if (b_prime != nr_srs_info->b_hop) { + product_N_b *= get_N_b_srs(nr_srs_info->C_SRS, b_prime); + } + } + + int F_b = 0; + uint8_t N_b = get_N_b_srs(nr_srs_info->C_SRS, b); + if (N_b & 1) { // Nb odd + F_b = (N_b / 2) * (n_SRS / product_N_b); + } else { // Nb even + uint16_t product_N_b_B_SRS = product_N_b; + product_N_b_B_SRS *= get_N_b_srs(nr_srs_info->C_SRS, nr_srs_info->B_SRS); /* product for b_hop to b */ + F_b = (N_b / 2) * ((n_SRS % product_N_b_B_SRS) / product_N_b) + ((n_SRS % product_N_b_B_SRS) / 2 * product_N_b); + } + return F_b; +} + +static int compute_n_b(frame_t frame_number, + slot_t slot_number, + uint16_t slots_per_frame, + nr_srs_info_t *nr_srs_info, + uint8_t l_line, + uint8_t b, + int m_SRS_b) +{ + uint8_t N_b = get_N_b_srs(nr_srs_info->C_SRS, b); + int n_b = 0; + if (nr_srs_info->b_hop >= nr_srs_info->B_SRS) { + n_b = (4 * nr_srs_info->n_RRC / m_SRS_b) % N_b; + } else { + if (b <= nr_srs_info->b_hop) { + n_b = (4 * nr_srs_info->n_RRC / m_SRS_b) % N_b; + } else { + // Compute the hopping offset Fb + int F_b = compute_F_b(frame_number, slot_number, slots_per_frame, nr_srs_info, l_line, b); + n_b = (F_b + (4 * nr_srs_info->n_RRC / m_SRS_b)) % N_b; + } + } + return n_b; +} + +/************************************************************************* +* +* NAME : generate_srs_nr +* +* PARAMETERS : pointer to srs config pdu +* pointer to transmit buffer +* amplitude scaling for this physical signal +* slot number of transmission +* RETURN : 0 if srs sequence has been successfully generated +* -1 if sequence can not be properly generated +* +* DESCRIPTION : generate/map srs symbol into transmit buffer +* See TS 38.211 - Section 6.4.1.4 Sounding reference signal +* +***************************************************************************/ +bool generate_srs_nr(NR_DL_FRAME_PARMS *frame_parms, + c16_t **txdataF, + uint16_t symbol_offset, + int bwp_start, + nr_srs_info_t *nr_srs_info, + int16_t amp, + frame_t frame_number, + slot_t slot_number) +{ + uint8_t K_TC = 2 << nr_srs_info->comb_size; + /* Number of antenna ports (M) can't be higher than number of physical antennas (N): M <= N */ + int N_ap = nr_srs_info->n_srs_ports > frame_parms->nb_antennas_tx ? frame_parms->nb_antennas_tx : nr_srs_info->n_srs_ports; + uint8_t l0 = frame_parms->symbols_per_slot - 1 - nr_srs_info->l_offset; // Starting symbol position in the time domain + uint8_t n_SRS_cs_max = srs_max_number_cs[nr_srs_info->comb_size]; + int m_SRS_b = get_m_srs(nr_srs_info->C_SRS, nr_srs_info->B_SRS); // Number of resource blocks + uint16_t M_sc_b_SRS = m_SRS_b * NR_NB_SC_PER_RB/K_TC; // Length of the SRS sequence + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"Frame = %i, slot = %i\n", frame_number, slot_number); + LOG_I(NR_PHY,"B_SRS = %i\n", nr_srs_info->B_SRS); + LOG_I(NR_PHY,"C_SRS = %i\n", nr_srs_info->C_SRS); + LOG_I(NR_PHY,"b_hop = %i\n", nr_srs_info->b_hop); + LOG_I(NR_PHY,"K_TC = %i\n", K_TC); + LOG_I(NR_PHY,"K_TC_overbar = %i\n", nr_srs_info->K_TC_overbar); + LOG_I(NR_PHY,"n_SRS_cs = %i\n", nr_srs_info->n_SRS_cs); + LOG_I(NR_PHY,"n_ID_SRS = %i\n", nr_srs_info->n_ID_SRS); + LOG_I(NR_PHY,"n_shift = %i\n", nr_srs_info->n_shift); + LOG_I(NR_PHY,"n_RRC = %i\n", nr_srs_info->n_RRC); + LOG_I(NR_PHY,"groupOrSequenceHopping = %i\n", nr_srs_info->groupOrSequenceHopping); + LOG_I(NR_PHY,"l_offset = %i\n", nr_srs_info->l_offset); + LOG_I(NR_PHY,"T_SRS = %i\n", nr_srs_info->T_SRS); + LOG_I(NR_PHY,"T_offset = %i\n", nr_srs_info->T_offset); + LOG_I(NR_PHY,"R = %i\n", nr_srs_info->R); + LOG_I(NR_PHY,"N_ap = %i\n", N_ap); + LOG_I(NR_PHY,"N_symb_SRS = %i\n", nr_srs_info->N_symb_SRS); + LOG_I(NR_PHY,"l0 = %i\n", l0); + LOG_I(NR_PHY,"n_SRS_cs_max = %i\n", n_SRS_cs_max); + LOG_I(NR_PHY,"m_SRS_b = %i\n", m_SRS_b); + LOG_I(NR_PHY,"M_sc_b_SRS = %i\n", M_sc_b_SRS); +#endif + + // Validation of SRS config parameters + + if (nr_srs_info->R == 0) { + LOG_E(NR_PHY, "generate_srs: this parameter repetition factor %d is not consistent !\n", nr_srs_info->R); + return false; + } else if (nr_srs_info->R > nr_srs_info->N_symb_SRS) { + LOG_E(NR_PHY, "generate_srs: R %d can not be greater than N_symb_SRS %d !\n", nr_srs_info->R, nr_srs_info->N_symb_SRS); + return false; + } + + if (nr_srs_info->n_SRS_cs >= n_SRS_cs_max) { + LOG_E(NR_PHY, "generate_srs: inconsistent parameter n_SRS_cs %d >= n_SRS_cs_max %d !\n", nr_srs_info->n_SRS_cs, n_SRS_cs_max); + return false; + } + + if (nr_srs_info->T_SRS == 0) { + LOG_E(NR_PHY, "generate_srs: inconsistent parameter T_SRS %d can not be equal to zero !\n", nr_srs_info->T_SRS); + return false; + } else { + int index = 0; + while (srs_periodicity[index] != nr_srs_info->T_SRS) { + index++; + if (index == SRS_PERIODICITY) { + LOG_E(NR_PHY, "generate_srs: inconsistent parameter T_SRS %d not specified !\n", nr_srs_info->T_SRS); + return false; + } + } + } + + // Variable initialization + if(nr_srs_info) { + nr_srs_info->srs_generated_signal_bits = log2_approx(amp); + } + uint64_t subcarrier_offset = frame_parms->first_carrier_offset + bwp_start * NR_NB_SC_PER_RB; + double sqrt_N_ap = sqrt(N_ap); + int n_b[nr_srs_info->B_SRS + 1]; + + // Find index of table which is for this SRS length + uint16_t M_sc_b_SRS_index = 0; + while((ul_allocated_re[M_sc_b_SRS_index] != M_sc_b_SRS) && (M_sc_b_SRS_index < SRS_SB_CONF)) + M_sc_b_SRS_index++; + + // SRS sequence generation and mapping, TS 38.211 - Section 6.4.1.4 + for (int p_index = 0; p_index < N_ap; p_index++) { +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"============ port %d ============\n", p_index); +#endif + + uint16_t n_SRS_cs_i = (nr_srs_info->n_SRS_cs + (n_SRS_cs_max * (SRS_antenna_port[p_index] - 1000) / N_ap)) % n_SRS_cs_max; + double alpha_i = 2 * M_PI * ((double)n_SRS_cs_i / (double)n_SRS_cs_max); + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"n_SRS_cs_i = %i\n", n_SRS_cs_i); + LOG_I(NR_PHY,"alpha_i = %f\n", alpha_i); +#endif + + for (int l_line = 0; l_line < nr_srs_info->N_symb_SRS; l_line++) { +#ifdef SRS_DEBUG + LOG_I(NR_PHY,":::::::: OFDM symbol %d ::::::::\n", l0+l_line); +#endif + + // Set group and sequence numbers (u,v) per OFDM symbol + int u = 0, v = 0; + switch(nr_srs_info->groupOrSequenceHopping) { + case neitherHopping: + u = nr_srs_info->n_ID_SRS % U_GROUP_NUMBER; + v = 0; + break; + case groupHopping: + u = group_number_hopping(slot_number, nr_srs_info->n_ID_SRS, l0, l_line); + v = 0; + break; + case sequenceHopping: + u = nr_srs_info->n_ID_SRS % U_GROUP_NUMBER; + v = sequence_number_hopping(slot_number, nr_srs_info->n_ID_SRS, M_sc_b_SRS, l0, l_line); + break; + default: + LOG_E(NR_PHY, "generate_srs: unknown hopping setting %d !\n", nr_srs_info->groupOrSequenceHopping); + return false; + } + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"u = %i\n", u); + LOG_I(NR_PHY,"v = %i\n", v); +#endif + + // Compute the frequency position index n_b + uint16_t sum_n_b = 0; + for (int b = 0; b <= nr_srs_info->B_SRS; b++) { + n_b[b] = compute_n_b(frame_number, slot_number, frame_parms->slots_per_frame, nr_srs_info, l_line, b, m_SRS_b); + sum_n_b += n_b[b]; + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"n_b[%i] = %i\n", b, n_b[b]); +#endif + } + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"sum_n_b = %i\n", sum_n_b); +#endif + + // Compute the frequency-domain starting position + uint8_t K_TC_p = 0; + if((nr_srs_info->n_SRS_cs >= n_SRS_cs_max / 2) + && (nr_srs_info->n_SRS_cs < n_SRS_cs_max) + && (N_ap == 4) + && ((SRS_antenna_port[p_index] == 1001) || (SRS_antenna_port[p_index] == 1003))) { + K_TC_p = (nr_srs_info->K_TC_overbar + K_TC / 2) % K_TC; + } else { + K_TC_p = nr_srs_info->K_TC_overbar; + } + uint8_t k_l_offset = 0; // If the SRS is configured by the IE SRS-PosResource-r16, the quantity k_l_offset is + // given by TS 38.211 - Table 6.4.1.4.3-2, otherwise k_l_offset = 0. + uint8_t k_0_overbar_p = (nr_srs_info->n_shift * NR_NB_SC_PER_RB + (K_TC_p + k_l_offset)) % K_TC; + uint8_t k_0_p = k_0_overbar_p + K_TC * M_sc_b_SRS * sum_n_b; + nr_srs_info->k_0_p[p_index][l_line] = k_0_p; + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"K_TC_p = %i\n", K_TC_p); + LOG_I(NR_PHY,"k_0_overbar_p = %i\n", k_0_overbar_p); + LOG_I(NR_PHY,"k_0_p = %i\n", k_0_p); +#endif + + uint16_t subcarrier = subcarrier_offset + k_0_p; + if (subcarrier >= frame_parms->ofdm_symbol_size) + subcarrier -= frame_parms->ofdm_symbol_size; + uint16_t l_line_offset = l_line * frame_parms->ofdm_symbol_size; + // For each port, and for each OFDM symbol, here it is computed and mapped an SRS sequence with M_sc_b_SRS symbols + for (int k = 0; k < M_sc_b_SRS; k++) { + cd_t shift = {cos(alpha_i * k), sin(alpha_i * k)}; + const c16_t tmp = rv_ul_ref_sig[u][v][M_sc_b_SRS_index][k]; + cd_t r_overbar = {tmp.r, tmp.i}; + + // cos(x+y) = cos(x)cos(y) - sin(x)sin(y) + cd_t r = cdMul(shift, r_overbar); + c16_t r_amp = {(((int32_t)round((double)amp * r.r / sqrt_N_ap)) >> 15), + (((int32_t)round((double)amp * r.i / sqrt_N_ap)) >> 15)}; + +#ifdef SRS_DEBUG + int subcarrier_log = subcarrier-subcarrier_offset; + if(subcarrier_log < 0) { + subcarrier_log = subcarrier_log + frame_parms->ofdm_symbol_size; + } + if(subcarrier_log%12 == 0) { + LOG_I(NR_PHY,"------------ %d ------------\n", subcarrier_log/12); + } + LOG_I(NR_PHY, "(%d) \t%i\t%i\n", subcarrier_log, r_amp.r, r_amp.i); +#endif + + txdataF[p_index][symbol_offset + l_line_offset + subcarrier] = r_amp; + + // Subcarrier increment + subcarrier += K_TC; + if (subcarrier >= frame_parms->ofdm_symbol_size) + subcarrier -= frame_parms->ofdm_symbol_size; + + } // for (int k = 0; k < M_sc_b_SRS; k++) + } // for (int l_line = 0; l_line < N_symb_SRS; l_line++) + } // for (int p_index = 0; p_index < N_ap; p_index++) + return true; +} diff --git a/openair1/SCHED/nfapi_lte_dummy.c b/openair1/SCHED/nfapi_lte_dummy.c index 6856d85806..d61f0d0548 100644 --- a/openair1/SCHED/nfapi_lte_dummy.c +++ b/openair1/SCHED/nfapi_lte_dummy.c @@ -4,6 +4,10 @@ #include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h" #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" #include "openair1/PHY/LTE_TRANSPORT/transport_common.h" +typedef struct pnf_t pnf_t; +typedef struct pnf_p7_t pnf_p7_t; +typedef struct vnf_t vnf_t; +typedef struct vnf_p7_t vnf_p7_t; void handle_nfapi_nr_pdcch_pdu(PHY_VARS_gNB *gNB, int frame, int slot, @@ -52,3 +56,80 @@ void install_nr_schedule_handlers(NR_IF_Module_t *if_inst){} void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp){} +bool vnf_nr_send_p5_msg(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) +{ + return false; +} + +bool vnf_nr_send_p7_msg(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *header) +{ + return false; +} + +void *vnf_nr_start_p7_thread(void *ptr) +{ + return 0; +} + +bool pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) +{ + return false; +} + +bool pnf_nr_send_p7_message(pnf_p7_t *pnf_p7, nfapi_nr_p7_message_header_t *header, uint32_t msg_len) +{ + return false; +} + +void *pnf_start_p5_thread(void *ptr) +{ + return 0; +} + +void vnf_start_p5_thread(void *ptr) +{ +} + +void *pnf_nr_p7_thread_start(void *ptr) +{ + return 0; +} + +bool wls_vnf_nr_send_p7_message(vnf_p7_t *vnf_p7, nfapi_nr_p7_message_header_t *msg) +{ + return false; +} + +void wls_vnf_set_p7_config(void *p7_config) +{ +} + +bool wls_vnf_nr_send_p5_message(vnf_t *vnf,uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t* msg, uint32_t msg_len) +{ + return false; +} + +void *wls_fapi_vnf_nr_start_thread(void *ptr) +{ + return NULL; +} + +bool wls_pnf_nr_send_p7_message(pnf_p7_t* pnf_p7,nfapi_nr_p7_message_header_t *msg, uint32_t msg_len) +{ + return false; +} + +bool wls_pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len) +{ + return false; +} + +void *wls_fapi_pnf_nr_start_thread(void *ptr) +{ + return NULL; +} + +void wls_pnf_set_p7_config(void *p7_config) +{ + +} diff --git a/openair1/SCHED/sched_common_extern.h b/openair1/SCHED/sched_common_extern.h index 57d70f7d1e..f413ba683c 100644 --- a/openair1/SCHED/sched_common_extern.h +++ b/openair1/SCHED/sched_common_extern.h @@ -27,11 +27,12 @@ #include "sched_eNB.h" // This is the formula from Section 5.1.1.1 in 36.213 100*10*log10((2^(MPR*Ks)-1)), where MPR is in the range [0,6] and Ks=1.25 -static const int16_t hundred_times_delta_TF[100] = {-32768, -1268, -956, -768, -631, -523, -431, -352, -282, -219, -161, -107, -57, -9, 36, 79, 120, 159, 197, 234, - 269, 304, 337, 370, 402, 434, 465, 495, 525, 555, 583, 612, 640, 668, 696, 723, 750, 777, 803, 829, - 856, 881, 907, 933, 958, 983, 1008, 1033, 1058, 1083, 1108, 1132, 1157, 1181, 1205, 1229, 1254, 1278, 1302, 1325, - 1349, 1373, 1397, 1421, 1444, 1468, 1491, 1515, 1538, 1562, 1585, 1609, 1632, 1655, 1679, 1702, 1725, 1748, 1772, 1795, - 1818, 1841, 1864, 1887, 1910, 1933, 1956, 1980, 2003, 2026, 2049, 2072, 2095, 2118, 2141, 2164, 2186, 2209, 2232, 2255}; +static const int16_t hundred_times_delta_TF[100] = { + -32767, -1268, -956, -768, -631, -523, -431, -352, -282, -219, -161, -107, -57, -9, 36, 79, 120, 159, 197, 234, + 269, 304, 337, 370, 402, 434, 465, 495, 525, 555, 583, 612, 640, 668, 696, 723, 750, 777, 803, 829, + 856, 881, 907, 933, 958, 983, 1008, 1033, 1058, 1083, 1108, 1132, 1157, 1181, 1205, 1229, 1254, 1278, 1302, 1325, + 1349, 1373, 1397, 1421, 1444, 1468, 1491, 1515, 1538, 1562, 1585, 1609, 1632, 1655, 1679, 1702, 1725, 1748, 1772, 1795, + 1818, 1841, 1864, 1887, 1910, 1933, 1956, 1980, 2003, 2026, 2049, 2072, 2095, 2118, 2141, 2164, 2186, 2209, 2232, 2255}; static const uint16_t hundred_times_log10_NPRB[100] = {0, 301, 477, 602, 698, 778, 845, 903, 954, 1000, 1041, 1079, 1113, 1146, 1176, 1204, 1230, 1255, 1278, 1301, 1322, 1342, 1361, 1380, 1397, 1414, 1431, 1447, 1462, 1477, 1491, 1505, 1518, 1531, 1544, 1556, 1568, 1579, 1591, 1602, 1612, 1623, 1633, 1643, 1653, 1662, 1672, 1681, 1690, 1698, 1707, 1716, 1724, 1732, 1740, 1748, 1755, 1763, 1770, 1778, diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 6b671abcfe..74a2178982 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -29,9 +29,6 @@ * \note * \warning */ -#ifdef ENABLE_AERIAL -#include "nfapi/oai_integration/aerial/fapi_vnf_p5.h" -#endif #include "fapi_nr_l1.h" #include "common/ran_context.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 8da471f4c1..51e8c771e5 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -32,15 +32,16 @@ #include "common/utils/LOG/vcd_signal_dumper.h" #include "PHY/INIT/nr_phy_init.h" #include "PHY/MODULATION/nr_modulation.h" -#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h" #include "T.h" #include "executables/nr-softmodem.h" #include "executables/softmodem-common.h" #include "nfapi/oai_integration/vendor_ext.h" #include "assertions.h" #include +#include #include #include +#include "PHY/log_tools.h" //#define DEBUG_RXDATA //#define SRS_IND_DEBUG @@ -425,6 +426,68 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo crc_valid = true; } } +#if T_TRACER + if (T_ACTIVE(T_GNB_PHY_UL_PAYLOAD_RX_BITS)) { + // capture Rx Payload via T-Tracer for both CRC valid and invalid cases + // Get Time Stamp for T-tracer messages + char trace_rx_payload_time_stamp_str[30]; + get_time_stamp_usec(trace_rx_payload_time_stamp_str); + // trace_rx_payload_time_stamp_str = 8 bytes timestamp = YYYYMMDD + // + 9 bytes timestamp = HHMMSSMMM + + // Log GNB_PHY_UL_PAYLOAD_RX_BITS using T-Tracer if activated + // FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : + // int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : + // int,Nid_cell : int,rnti : + // int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : + // int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : + // int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : + // int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data + + NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + int dmrs_port = get_dmrs_port(0, pusch_pdu->dmrs_ports); + // int num_bytes = rdata->Kr_bytes - (ulsch_harq->F >> 3) - ((ulsch_harq->C > 1) ? 3 : 0); + // printf("num_bytes %d, len with CRC %d, data len %d\n", num_bytes, lenWithCrc(1, rdata->A), rdata->A); + // calculate the number of dmrs symbols in the slot + int number_dmrs_symbols = 0; + for (int l = pusch_pdu->start_symbol_index; l < pusch_pdu->start_symbol_index + pusch_pdu->nr_of_symbols; l++) + number_dmrs_symbols += ((pusch_pdu->ul_dmrs_symb_pos) >> l) & 0x01; + + // Log GNB_PHY_UL_PAYLOAD_RX_BITS using T-Tracer if activated + T(T_GNB_PHY_UL_PAYLOAD_RX_BITS, + T_INT((int)ulsch->frame), + T_INT((int)ulsch->slot), + T_INT((int)split_time_stamp_and_convert_to_int(trace_rx_payload_time_stamp_str, 0, 8)), + T_INT((int)split_time_stamp_and_convert_to_int(trace_rx_payload_time_stamp_str, 8, 9)), + T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure + T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2) + T_INT((int)pusch_pdu->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz) + T_INT((int)pusch_pdu->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended) + T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot + T_INT((int)frame_parms->Nid_cell), + T_INT((int)pusch_pdu->rnti), + T_INT((int)pusch_pdu->rb_size), + T_INT((int)pusch_pdu->rb_start), + T_INT((int)pusch_pdu->start_symbol_index), // start_ofdm_symbol + T_INT((int)pusch_pdu->nr_of_symbols), // num_ofdm_symbols + T_INT((int)pusch_pdu->qam_mod_order), // modulation + T_INT((int)pusch_pdu->mcs_index), // mcs + T_INT((int)pusch_pdu->mcs_table), // mcs_table_index + T_INT((int)pusch_pdu->nrOfLayers), // num_layer + T_INT((int)pusch_pdu->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1 + T_INT((int)pusch_pdu->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1 + T_INT((int)pusch_pdu->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions + T_INT((int)number_dmrs_symbols), + // dmrs_start_ofdm_symbol + // dmrs_duration_num_ofdm_symbols + // dmrs_num_add_positions + T_INT((int)dmrs_port), // dmrs_antenna_port + T_INT((int)pusch_pdu->scid), // dmrs_nscid + T_INT((int)frame_parms->nb_antennas_rx), // rx antenna + T_INT(((ulsch_harq->TBS) << 3)), // number_of_bits + T_BUFFER((uint8_t *)((ulsch_harq->b)), ((ulsch_harq->TBS) << 3) / 8)); // data + } +#endif nfapi_nr_crc_t *crc = &UL_INFO->crc_ind.crc_list[UL_INFO->crc_ind.number_crcs++]; nfapi_nr_rx_data_pdu_t *pdu = &UL_INFO->rx_ind.pdu_list[UL_INFO->rx_ind.number_of_pdus++]; @@ -647,7 +710,7 @@ static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, uint32 int fill_srs_reported_symbol(nfapi_nr_srs_reported_symbol_t *reported_symbol, const nfapi_nr_srs_pdu_t *srs_pdu, const int N_RB_UL, - const int8_t *snr_per_rb, + const int16_t *snr_per_rb, const int srs_est) { reported_symbol->num_prgs = srs_pdu->beamforming.num_prgs; for (int prg_idx = 0; prg_idx < reported_symbol->num_prgs; prg_idx++) { @@ -687,7 +750,7 @@ int fill_srs_channel_matrix(uint8_t *channel_matrix, for(int gI = 0; gI < num_gnb_antenna_elements; gI++) { uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[uI][0]; - if (subcarrier>frame_parms->ofdm_symbol_size) { + if (subcarrier >= frame_parms->ofdm_symbol_size) { subcarrier -= frame_parms->ofdm_symbol_size; } @@ -706,7 +769,7 @@ int fill_srs_channel_matrix(uint8_t *channel_matrix, // Subcarrier increment subcarrier += step; if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier=subcarrier-frame_parms->ofdm_symbol_size; + subcarrier -= frame_parms->ofdm_symbol_size; } } } @@ -715,18 +778,56 @@ int fill_srs_channel_matrix(uint8_t *channel_matrix, return 0; } -int check_srs_pdu(const nfapi_nr_srs_pdu_t *srs_pdu, nfapi_nr_srs_pdu_t *saved_srs_pdu) +static void copy_srs_info(const nfapi_nr_srs_pdu_t *srs_config_pdu, nr_srs_info_t *nr_srs_info) { - if (saved_srs_pdu->bwp_start == srs_pdu->bwp_start && - saved_srs_pdu->bwp_size == srs_pdu->bwp_size && - saved_srs_pdu->num_ant_ports == srs_pdu->num_ant_ports && - saved_srs_pdu->time_start_position == srs_pdu->time_start_position && - saved_srs_pdu->num_symbols == srs_pdu->num_symbols && - saved_srs_pdu->config_index == srs_pdu->config_index) { - return 1; + nr_srs_info->B_SRS = srs_config_pdu->bandwidth_index; + nr_srs_info->C_SRS = srs_config_pdu->config_index; + nr_srs_info->b_hop = srs_config_pdu->frequency_hopping; + nr_srs_info->comb_size = srs_config_pdu->comb_size; + nr_srs_info->K_TC_overbar = srs_config_pdu->comb_offset; + nr_srs_info->n_SRS_cs = srs_config_pdu->cyclic_shift; + nr_srs_info->n_ID_SRS = srs_config_pdu->sequence_id; + // It adjusts the SRS allocation to align with the common resource block grid in multiples of four + nr_srs_info->n_shift = srs_config_pdu->frequency_position; + nr_srs_info->n_RRC = srs_config_pdu->frequency_shift; + nr_srs_info->groupOrSequenceHopping = srs_config_pdu->group_or_sequence_hopping; + nr_srs_info->l_offset = srs_config_pdu->time_start_position; + nr_srs_info->T_SRS = srs_config_pdu->t_srs; + nr_srs_info->T_offset = srs_config_pdu->t_offset; + nr_srs_info->R = 1 << srs_config_pdu->num_repetitions; + nr_srs_info->N_symb_SRS = 1 << srs_config_pdu->num_symbols; // Number of consecutive OFDM symbols + nr_srs_info->n_srs_ports = 1 << srs_config_pdu->num_ant_ports; // Number of antenna port for transmission + nr_srs_info->resource_type = srs_config_pdu->resource_type; +} + +static bool srs_has_changed(const nfapi_nr_srs_pdu_t *srs_config_pdu, nr_srs_info_t *nr_srs_info) +{ + return nr_srs_info->B_SRS != srs_config_pdu->bandwidth_index + || nr_srs_info->C_SRS != srs_config_pdu->config_index + || nr_srs_info->b_hop != srs_config_pdu->frequency_hopping + || nr_srs_info->comb_size != srs_config_pdu->comb_size + || nr_srs_info->K_TC_overbar != srs_config_pdu->comb_offset + || nr_srs_info->n_SRS_cs != srs_config_pdu->cyclic_shift + || nr_srs_info->n_ID_SRS != srs_config_pdu->sequence_id + || nr_srs_info->n_shift != srs_config_pdu->frequency_position + || nr_srs_info->n_RRC != srs_config_pdu->frequency_shift + || nr_srs_info->groupOrSequenceHopping != srs_config_pdu->group_or_sequence_hopping + || nr_srs_info->l_offset != srs_config_pdu->time_start_position + || nr_srs_info->T_SRS != srs_config_pdu->t_srs + || nr_srs_info->T_offset != srs_config_pdu->t_offset + || nr_srs_info->R != 1 << srs_config_pdu->num_repetitions + || nr_srs_info->N_symb_SRS != 1 << srs_config_pdu->num_symbols + || nr_srs_info->n_srs_ports != 1 << srs_config_pdu->num_ant_ports + || nr_srs_info->resource_type != srs_config_pdu->resource_type; +} + +static bool check_and_configure_srs_info(nfapi_nr_srs_pdu_t *srs_config_pdu, nr_srs_info_t *nr_srs_info) +{ + if (srs_has_changed(srs_config_pdu, nr_srs_info)) { + copy_srs_info(srs_config_pdu, nr_srs_info); + return true; } - *saved_srs_pdu = *srs_pdu; - return 0; + return false; } int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO) @@ -821,10 +922,8 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid); if ((ulsch->active == true) && (ulsch->frame == frame_rx) && (ulsch->slot == slot_rx) && (ulsch->handled == 0)) { LOG_D(PHY, "PUSCH ID %d with RNTI %x detection started in frame %d slot %d\n", ULSCH_id, ulsch->rnti, frame_rx, slot_rx); - - int num_dmrs = 0; - for (int s = 0; s < NR_NUMBER_OF_SYMBOLS_PER_SLOT; s++) - num_dmrs += (ulsch_harq->ulsch_pdu.ul_dmrs_symb_pos >> s) & 1; + nfapi_nr_pusch_pdu_t *pdu = &ulsch_harq->ulsch_pdu; + int num_dmrs = count_bits64_with_mask(pdu->ul_dmrs_symb_pos, 0, NR_NUMBER_OF_SYMBOLS_PER_SLOT); #ifdef DEBUG_RXDATA NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; @@ -832,7 +931,6 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N int slot_offset = frame_parms->get_samples_slot_timestamp(slot_rx, frame_parms, 0); slot_offset -= ru->N_TA_offset; int32_t sample_offset = gNB->common_vars.debugBuff_sample_offset; - nfapi_nr_pusch_pdu_t *pdu = &ulsch_harq->ulsch_pdu; int16_t *buf = (int16_t *)&gNB->common_vars.debugBuff[offset]; buf[0] = (int16_t)ulsch->rnti; buf[1] = (int16_t)pdu->rb_size; @@ -947,22 +1045,31 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; c16_t srs_received_signal[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size * N_symb_SRS]; + c16_t srs_received_noise[frame_parms->nb_antennas_rx][frame_parms->ofdm_symbol_size * N_symb_SRS]; c16_t srs_estimated_channel_freq[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports] [frame_parms->ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); c16_t srs_estimated_channel_time[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); c16_t srs_estimated_channel_time_shifted[frame_parms->nb_antennas_rx][1 << srs_pdu->num_ant_ports] [frame_parms->ofdm_symbol_size]; - int8_t snr_per_rb[srs_pdu->bwp_size]; + int16_t snr_per_rb[srs_pdu->bwp_size]; start_meas(&gNB->generate_srs_stats); - if (check_srs_pdu(srs_pdu, &gNB->nr_srs_info[i]->srs_pdu) == 0) { - generate_srs_nr(srs_pdu, frame_parms, gNB->nr_srs_info[i]->srs_generated_signal, 0, gNB->nr_srs_info[i], AMP, frame_rx, slot_rx); + + if (check_and_configure_srs_info(srs_pdu, gNB->nr_srs_info[i])) { + generate_srs_nr(frame_parms, + gNB->nr_srs_info[i]->srs_generated_signal, + 0, + srs_pdu->bwp_start, + gNB->nr_srs_info[i], + AMP, + frame_rx, + slot_rx); } stop_meas(&gNB->generate_srs_stats); c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb]; start_meas(&gNB->get_srs_signal_stats); - int srs_est = nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, gNB->nr_srs_info[i], srs_received_signal); + int srs_est = nr_get_srs_signal(gNB, rxdataF, frame_rx, slot_rx, srs_pdu, gNB->nr_srs_info[i], srs_received_signal, srs_received_noise); stop_meas(&gNB->get_srs_signal_stats); if (srs_est >= 0) { @@ -974,6 +1081,7 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N gNB->nr_srs_info[i], (const c16_t**)gNB->nr_srs_info[i]->srs_generated_signal, srs_received_signal, + srs_received_noise, srs_estimated_channel_freq, srs_estimated_channel_time, srs_estimated_channel_time_shifted, @@ -1002,6 +1110,14 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N T_INT(0), T_BUFFER(srs_estimated_channel_time_shifted[0][0], frame_parms->ofdm_symbol_size * sizeof(int32_t))); + T(T_GNB_PHY_UL_SNR_ESTIMATE, + T_INT(0), + T_INT(srs_pdu->rnti), + T_INT(frame_rx), + T_INT(0), + T_INT(0), + T_BUFFER(snr_per_rb, srs_pdu->bwp_size * sizeof(int16_t))); + UL_INFO->srs_ind.sfn = frame_rx; UL_INFO->srs_ind.slot = slot_rx; diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c index 6bb7ed3e4c..cbdd91c949 100644 --- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c +++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c @@ -31,7 +31,6 @@ */ #include - #include "fapi_nr_ue_interface.h" #include "fapi_nr_ue_l1.h" #include "harq_nr.h" @@ -39,247 +38,11 @@ #include "PHY/defs_nr_UE.h" #include "PHY/impl_defs_nr.h" #include "utils.h" -#include "openair2/PHY_INTERFACE/queue_t.h" #include "SCHED_NR_UE/phy_sch_processing_time.h" #include "openair1/PHY/phy_extern_nr_ue.h" const char *const dl_pdu_type[] = {"DCI", "DLSCH", "RA_DLSCH", "SI_DLSCH", "P_DLSCH", "CSI_RS", "CSI_IM", "TA"}; const char *const ul_pdu_type[] = {"PRACH", "PUCCH", "PUSCH", "SRS"}; -queue_t nr_rx_ind_queue; -queue_t nr_crc_ind_queue; -queue_t nr_uci_ind_queue; -queue_t nr_rach_ind_queue; - -static void fill_uci_2_3_4(nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu_2_3_4, - fapi_nr_ul_config_pucch_pdu *pucch_pdu) -{ - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - memset(pdu_2_3_4, 0, sizeof(*pdu_2_3_4)); - pdu_2_3_4->handle = 0; - pdu_2_3_4->rnti = pucch_pdu->rnti; - pdu_2_3_4->pucch_format = 2; - pdu_2_3_4->ul_cqi = 255; - pdu_2_3_4->timing_advance = 0; - pdu_2_3_4->rssi = 0; - // TODO: Eventually check 38.212:Sect.631 to know when to use csi_part2, for now only using csi_part1 - pdu_2_3_4->pduBitmap = 4; - pdu_2_3_4->csi_part1.csi_part1_bit_len = mac->nr_ue_emul_l1.num_csi_reports; - int csi_part1_byte_len = (int)((pdu_2_3_4->csi_part1.csi_part1_bit_len / 8) + 1); - AssertFatal(!pdu_2_3_4->csi_part1.csi_part1_payload, "pdu_2_3_4->csi_part1.csi_part1_payload != NULL\n"); - pdu_2_3_4->csi_part1.csi_part1_payload = CALLOC(csi_part1_byte_len, - sizeof(pdu_2_3_4->csi_part1.csi_part1_payload)); - for (int k = 0; k < csi_part1_byte_len; k++) - { - pdu_2_3_4->csi_part1.csi_part1_payload[k] = (pucch_pdu->payload >> (k * 8)) & 0xff; - } - pdu_2_3_4->csi_part1.csi_part1_crc = 0; -} - -static void free_uci_inds(nfapi_nr_uci_indication_t *uci_ind) -{ - for (int k = 0; k < uci_ind->num_ucis; k++) - { - if (uci_ind->uci_list[k].pdu_type == NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE) - { - //nfapi_nr_uci_pucch_pdu_format_0_1_t *pdu_0_1 = &uci_ind->uci_list[k].pucch_pdu_format_0_1; - // Warning: pdu_0_1 is unused - } - if (uci_ind->uci_list[k].pdu_type == NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE) - { - nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu_2_3_4 = &uci_ind->uci_list[k].pucch_pdu_format_2_3_4; - free(pdu_2_3_4->sr.sr_payload); - pdu_2_3_4->sr.sr_payload = NULL; - free(pdu_2_3_4->harq.harq_payload); - pdu_2_3_4->harq.harq_payload = NULL; - } - } - free(uci_ind->uci_list); - uci_ind->uci_list = NULL; - free(uci_ind); -} - -int8_t nr_ue_scheduled_response_stub(nr_scheduled_response_t *scheduled_response) { - - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - - if (scheduled_response && scheduled_response->ul_config) { - int frame = scheduled_response->ul_config->frame; - int slot = scheduled_response->ul_config->slot; - fapi_nr_ul_config_request_pdu_t *it = fapiLockIterator(scheduled_response->ul_config, frame, slot); - while (it->pdu_type != FAPI_NR_END) { - switch (it->pdu_type) { - case FAPI_NR_UL_CONFIG_TYPE_PRACH: { - fapi_nr_ul_config_prach_pdu *prach_pdu = &it->prach_config_pdu; - nfapi_nr_rach_indication_t *rach_ind = CALLOC(1, sizeof(*rach_ind)); - rach_ind->sfn = frame; - rach_ind->slot = slot; - rach_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION; - uint8_t pdu_index = 0; - rach_ind->pdu_list = CALLOC(1, sizeof(*rach_ind->pdu_list)); - rach_ind->number_of_pdus = 1; - rach_ind->pdu_list[pdu_index].phy_cell_id = prach_pdu->phys_cell_id; - rach_ind->pdu_list[pdu_index].symbol_index = prach_pdu->prach_start_symbol; - rach_ind->pdu_list[pdu_index].slot_index = prach_pdu->prach_slot; - rach_ind->pdu_list[pdu_index].freq_index = prach_pdu->num_ra; - rach_ind->pdu_list[pdu_index].avg_rssi = 128; - rach_ind->pdu_list[pdu_index].avg_snr = 0xff; // invalid for now - const int num_p = rach_ind->pdu_list[pdu_index].num_preamble; - AssertFatal(num_p == 1, "can handle only one preamble in preamble_list\n"); - rach_ind->pdu_list[pdu_index].num_preamble = 1; - rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_index = prach_pdu->ra_PreambleIndex; - rach_ind->pdu_list[pdu_index].preamble_list[0].timing_advance = 0; - rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_pwr = 0xffffffff; - - if (!put_queue(&nr_rach_ind_queue, rach_ind)) { - free(rach_ind->pdu_list); - free(rach_ind); - } - LOG_D(NR_MAC, "We have successfully filled the rach_ind queue with the recently filled rach ind\n"); - break; - } - case (FAPI_NR_UL_CONFIG_TYPE_PUSCH): { - nfapi_nr_rx_data_indication_t *rx_ind = CALLOC(1, sizeof(*rx_ind)); - nfapi_nr_crc_indication_t *crc_ind = CALLOC(1, sizeof(*crc_ind)); - nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu = &it->pusch_config_pdu; - if (pusch_config_pdu->tx_request_body.fapiTxPdu) { - rx_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION; - rx_ind->sfn = frame; - rx_ind->slot = slot; - rx_ind->number_of_pdus = 1; - rx_ind->pdu_list = CALLOC(rx_ind->number_of_pdus, sizeof(*rx_ind->pdu_list)); - for (int j = 0; j < rx_ind->number_of_pdus; j++) { - fapi_nr_tx_request_body_t *tx_req_body = &pusch_config_pdu->tx_request_body; - rx_ind->pdu_list[j].handle = pusch_config_pdu->handle; - rx_ind->pdu_list[j].harq_id = pusch_config_pdu->pusch_data.harq_process_id; - rx_ind->pdu_list[j].pdu_length = tx_req_body->pdu_length; - rx_ind->pdu_list[j].pdu = CALLOC(tx_req_body->pdu_length, sizeof(*rx_ind->pdu_list[j].pdu)); - memcpy(rx_ind->pdu_list[j].pdu, tx_req_body->fapiTxPdu, tx_req_body->pdu_length * sizeof(*rx_ind->pdu_list[j].pdu)); - rx_ind->pdu_list[j].rnti = pusch_config_pdu->rnti; - /* TODO: Implement channel modeling to abstract TA and CQI. For now, - we hard code the values below since they are set in L1 and we are - abstracting L1. */ - rx_ind->pdu_list[j].timing_advance = 31; - rx_ind->pdu_list[j].ul_cqi = 255; - } - - crc_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION; - crc_ind->number_crcs = rx_ind->number_of_pdus; - crc_ind->sfn = frame; - crc_ind->slot = slot; - crc_ind->crc_list = CALLOC(crc_ind->number_crcs, sizeof(*crc_ind->crc_list)); - for (int j = 0; j < crc_ind->number_crcs; j++) { - crc_ind->crc_list[j].handle = pusch_config_pdu->handle; - crc_ind->crc_list[j].harq_id = pusch_config_pdu->pusch_data.harq_process_id; - LOG_D(NR_MAC, "This is the harq pid %d for crc_list[%d]\n", crc_ind->crc_list[j].harq_id, j); - LOG_D(NR_MAC, "This is sched sfn/sl [%d %d] and crc sfn/sl [%d %d]\n", frame, slot, crc_ind->sfn, crc_ind->slot); - crc_ind->crc_list[j].num_cb = pusch_config_pdu->pusch_data.num_cb; - crc_ind->crc_list[j].rnti = pusch_config_pdu->rnti; - crc_ind->crc_list[j].tb_crc_status = 0; - crc_ind->crc_list[j].timing_advance = 31; - crc_ind->crc_list[j].ul_cqi = 255; - emul_l1_harq_t *harq = &mac->nr_ue_emul_l1.harq[crc_ind->crc_list[j].harq_id]; - AssertFatal(harq->active_ul_harq_sfn == -1 && harq->active_ul_harq_slot == -1, - "We did not send an active CRC when we should have!\n"); - harq->active_ul_harq_sfn = crc_ind->sfn; - harq->active_ul_harq_slot = crc_ind->slot; - LOG_D(NR_MAC, - "This is sched sfn/sl [%d %d] and crc sfn/sl [%d %d] with mcs_index in ul_cqi -> %d\n", - frame, - slot, - crc_ind->sfn, - crc_ind->slot, - pusch_config_pdu->mcs_index); - } - - if (!put_queue(&nr_rx_ind_queue, rx_ind)) { - LOG_E(NR_MAC, "Put_queue failed for rx_ind\n"); - for (int i = 0; i < rx_ind->number_of_pdus; i++) { - free(rx_ind->pdu_list[i].pdu); - rx_ind->pdu_list[i].pdu = NULL; - } - - free(rx_ind->pdu_list); - rx_ind->pdu_list = NULL; - free(rx_ind); - rx_ind = NULL; - } - if (!put_queue(&nr_crc_ind_queue, crc_ind)) { - LOG_E(NR_MAC, "Put_queue failed for crc_ind\n"); - free(crc_ind->crc_list); - crc_ind->crc_list = NULL; - free(crc_ind); - crc_ind = NULL; - } - - LOG_D(PHY, "In %s: Filled queue rx/crc_ind which was filled by ulconfig. \n", __FUNCTION__); - } - break; - } - case FAPI_NR_UL_CONFIG_TYPE_PUCCH: { - nfapi_nr_uci_indication_t *uci_ind = CALLOC(1, sizeof(*uci_ind)); - uci_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION; - uci_ind->sfn = frame; - uci_ind->slot = slot; - uci_ind->num_ucis = 1; - uci_ind->uci_list = CALLOC(uci_ind->num_ucis, sizeof(*uci_ind->uci_list)); - for (int j = 0; j < uci_ind->num_ucis; j++) { - LOG_D(NR_MAC, "pucch_config_pdu.n_bit = %d\n", it->pucch_config_pdu.n_bit); - if (it->pucch_config_pdu.n_bit > 3 && mac->nr_ue_emul_l1.num_csi_reports > 0) { - uci_ind->uci_list[j].pdu_type = NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE; - uci_ind->uci_list[j].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_2_3_4_t); - nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu_2_3_4 = &uci_ind->uci_list[j].pucch_pdu_format_2_3_4; - fill_uci_2_3_4(pdu_2_3_4, &it->pucch_config_pdu); - } else { - nfapi_nr_uci_pucch_pdu_format_0_1_t *pdu_0_1 = &uci_ind->uci_list[j].pucch_pdu_format_0_1; - uci_ind->uci_list[j].pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; - uci_ind->uci_list[j].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); - memset(pdu_0_1, 0, sizeof(*pdu_0_1)); - pdu_0_1->handle = 0; - pdu_0_1->rnti = it->pucch_config_pdu.rnti; - pdu_0_1->pucch_format = 1; - pdu_0_1->ul_cqi = 255; - pdu_0_1->timing_advance = 0; - pdu_0_1->rssi = 0; - if (mac->nr_ue_emul_l1.num_harqs > 0) { - int harq_index = 0; - pdu_0_1->pduBitmap = 2; // (value->pduBitmap >> 1) & 0x01) == HARQ and (value->pduBitmap) & 0x01) == SR - pdu_0_1->harq.num_harq = mac->nr_ue_emul_l1.num_harqs; - pdu_0_1->harq.harq_confidence_level = 0; - int harq_pid = -1; - for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) { - if (mac->nr_ue_emul_l1.harq[k].active && mac->nr_ue_emul_l1.harq[k].active_dl_harq_sfn == uci_ind->sfn - && mac->nr_ue_emul_l1.harq[k].active_dl_harq_slot == uci_ind->slot) { - mac->nr_ue_emul_l1.harq[k].active = false; - harq_pid = k; - AssertFatal(harq_index < pdu_0_1->harq.num_harq, "Invalid harq_index %d\n", harq_index); - pdu_0_1->harq.harq_list[harq_index].harq_value = !mac->dl_harq_info[k].ack; - harq_index++; - } - } - AssertFatal(harq_pid != -1, "No active harq_pid, sfn_slot = %u.%u", uci_ind->sfn, uci_ind->slot); - } - } - } - - LOG_D(NR_PHY, "Sending UCI with %d PDUs in sfn.slot %d/%d\n", uci_ind->num_ucis, uci_ind->sfn, uci_ind->slot); - NR_UL_IND_t ul_info = { - .uci_ind = *uci_ind, - }; - send_nsa_standalone_msg(&ul_info, uci_ind->header.message_id); - free_uci_inds(uci_ind); - break; - } - - default: - LOG_W(NR_MAC, "Unknown ul_config->pdu_type %d\n", it->pdu_type); - break; - } - it++; - } - release_ul_config(it, true); - } - return 0; -} static void configure_dlsch(NR_UE_DLSCH_t *dlsch0, NR_DL_UE_HARQ_t *harq_list, @@ -287,26 +50,6 @@ static void configure_dlsch(NR_UE_DLSCH_t *dlsch0, NR_UE_MAC_INST_t *mac, int rnti) { - // Temporary code to process type0 as type1 when the RB allocation is contiguous - if (dlsch_config_pdu->resource_alloc == 0) { - dlsch_config_pdu->number_rbs = count_bits(dlsch_config_pdu->rb_bitmap, sizeofArray(dlsch_config_pdu->rb_bitmap)); - int state = 0; - for (int i = 0; i < sizeof(dlsch_config_pdu->rb_bitmap) * 8; i++) { - int allocated = dlsch_config_pdu->rb_bitmap[i / 8] & (1 << (i % 8)); - if (allocated) { - if (state == 0) { - dlsch_config_pdu->start_rb = i; - state = 1; - } else - AssertFatal(state == 1, "non-contiguous RB allocation in RB allocation type 0 not implemented"); - } else { - if (state == 1) { - state = 2; - } - } - } - } - const uint8_t current_harq_pid = dlsch_config_pdu->harq_process_nbr; dlsch0->active = true; dlsch0->rnti = rnti; @@ -352,10 +95,12 @@ static void configure_ntn_params(PHY_VARS_NR_UE *ue, fapi_nr_dl_ntn_config_comma ue->ntn_config_message = CALLOC(1, sizeof(*ue->ntn_config_message)); } + ue->ntn_config_message->ntn_config_params.epoch_sfn = ntn_params_message->epoch_sfn; + ue->ntn_config_message->ntn_config_params.epoch_subframe = ntn_params_message->epoch_subframe; ue->ntn_config_message->ntn_config_params.cell_specific_k_offset = ntn_params_message->cell_specific_k_offset; - ue->ntn_config_message->ntn_config_params.N_common_ta_adj = ntn_params_message->N_common_ta_adj; - ue->ntn_config_message->ntn_config_params.ntn_ta_commondrift = ntn_params_message->ntn_ta_commondrift; ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_ms = ntn_params_message->ntn_total_time_advance_ms; + ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift = ntn_params_message->ntn_total_time_advance_drift; + ue->ntn_config_message->ntn_config_params.ntn_total_time_advance_drift_variant = ntn_params_message->ntn_total_time_advance_drift_variant; ue->ntn_config_message->update = true; } diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 791f3e4631..f22d13c5fc 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -40,10 +40,10 @@ #include "PHY/phy_extern_nr_ue.h" #include "PHY/MODULATION/modulation_UE.h" #include "PHY/INIT/nr_phy_init.h" +#include "PHY/nr_phy_common/inc/nr_phy_common.h" #include "PHY/NR_REFSIG/ptrs_nr.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_ue.h" #include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h" -#include "PHY/NR_UE_TRANSPORT/srs_modulation_nr.h" #include "SCHED_NR_UE/phy_sch_processing_time.h" #include "PHY/NR_UE_ESTIMATION/nr_estimation.h" #ifdef EMOS @@ -176,8 +176,6 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, rx->ssb_pdu.ssb_length = frame_parms->Lmax; rx->ssb_pdu.cell_id = frame_parms->Nid_cell; rx->ssb_pdu.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier; - rx->ssb_pdu.rsrp_dBm = ue->measurements.ssb_rsrp_dBm[frame_parms->ssb_index]; - rx->ssb_pdu.sinr_dB = ue->measurements.ssb_sinr_dB[frame_parms->ssb_index]; rx->ssb_pdu.arfcn = get_ssb_arfcn(frame_parms); rx->ssb_pdu.radiolink_monitoring = RLM_in_sync; // TODO to be removed from here rx->ssb_pdu.decoded_pdu = true; @@ -186,8 +184,8 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, rx->ssb_pdu.decoded_pdu = false; } } break; - case FAPI_NR_CSIRS_IND: - memcpy(&rx->csirs_measurements, typeSpecific, sizeof(fapi_nr_csirs_measurements_t)); + case FAPI_NR_MEAS_IND: + memcpy(&rx->l1_measurements, typeSpecific, sizeof(fapi_nr_l1_measurements_t)); break; default: break; @@ -270,6 +268,102 @@ void ue_ta_procedures(PHY_VARS_NR_UE *ue, int slot_tx, int frame_tx) } } +static void configure_srs_info(fapi_nr_ul_config_srs_pdu *srs_config_pdu, nr_srs_info_t *nr_srs_info) +{ + nr_srs_info->B_SRS = srs_config_pdu->bandwidth_index; + nr_srs_info->C_SRS = srs_config_pdu->config_index; + nr_srs_info->b_hop = srs_config_pdu->frequency_hopping; + nr_srs_info->comb_size = srs_config_pdu->comb_size; + nr_srs_info->K_TC_overbar = srs_config_pdu->comb_offset; + nr_srs_info->n_SRS_cs = srs_config_pdu->cyclic_shift; + nr_srs_info->n_ID_SRS = srs_config_pdu->sequence_id; + // It adjusts the SRS allocation to align with the common resource block grid in multiples of four + nr_srs_info->n_shift = srs_config_pdu->frequency_position; + nr_srs_info->n_RRC = srs_config_pdu->frequency_shift; + nr_srs_info->groupOrSequenceHopping = srs_config_pdu->group_or_sequence_hopping; + nr_srs_info->l_offset = srs_config_pdu->time_start_position; + nr_srs_info->T_SRS = srs_config_pdu->t_srs; + nr_srs_info->T_offset = srs_config_pdu->t_offset; + nr_srs_info->R = 1 << srs_config_pdu->num_repetitions; + nr_srs_info->N_symb_SRS = 1 << srs_config_pdu->num_symbols; // Number of consecutive OFDM symbols + nr_srs_info->n_srs_ports = 1 << srs_config_pdu->num_ant_ports; // Number of antenna port for transmission + nr_srs_info->resource_type = srs_config_pdu->resource_type; +} + +/******************************************************************* +* +* NAME : ue_srs_procedures_nr +* +* PARAMETERS : pointer to ue context +* pointer to rxtx context* +* +* RETURN : 0 if it is a valid slot for transmitting srs +* -1 if srs should not be transmitted +* +* DESCRIPTION : ue srs procedure +* send srs according to current configuration +* +*********************************************************************/ +static bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + c16_t **txdataF, + nr_phy_data_tx_t *phy_data, + bool was_symbol_used[NR_NUMBER_OF_SYMBOLS_PER_SLOT]) +{ + if(phy_data->srs_vars.active == false) { + return false; + } + + fapi_nr_ul_config_srs_pdu *srs_config_pdu = &phy_data->srs_vars.srs_config_pdu; + int first_srs_symbol = ue->frame_parms.symbols_per_slot - 1 - srs_config_pdu->time_start_position; + // Num consecutive SRS symbols according to 38.211 6.4.1.4.1 + int num_srs_symbols[] = {1, 2, 4, 8, 12}; + int last_srs_symbol = first_srs_symbol + num_srs_symbols[srs_config_pdu->num_symbols] - 1; + for (int i = first_srs_symbol; i <= last_srs_symbol; i++) { + was_symbol_used[i] = true; + } + +#ifdef SRS_DEBUG + LOG_I(NR_PHY,"Frame = %i, slot = %i\n", proc->frame_tx, proc->nr_slot_tx); + LOG_I(NR_PHY,"srs_config_pdu->rnti = 0x%04x\n", srs_config_pdu->rnti); + LOG_I(NR_PHY,"srs_config_pdu->handle = %u\n", srs_config_pdu->handle); + LOG_I(NR_PHY,"srs_config_pdu->bwp_size = %u\n", srs_config_pdu->bwp_size); + LOG_I(NR_PHY,"srs_config_pdu->bwp_start = %u\n", srs_config_pdu->bwp_start); + LOG_I(NR_PHY,"srs_config_pdu->subcarrier_spacing = %u\n", srs_config_pdu->subcarrier_spacing); + LOG_I(NR_PHY,"srs_config_pdu->cyclic_prefix = %u (0: Normal; 1: Extended)\n", srs_config_pdu->cyclic_prefix); + LOG_I(NR_PHY,"srs_config_pdu->num_ant_ports = %u (0 = 1 port, 1 = 2 ports, 2 = 4 ports)\n", srs_config_pdu->num_ant_ports); + LOG_I(NR_PHY,"srs_config_pdu->num_symbols = %u (0 = 1 symbol, 1 = 2 symbols, 2 = 4 symbols)\n", srs_config_pdu->num_symbols); + LOG_I(NR_PHY,"srs_config_pdu->num_repetitions = %u (0 = 1, 1 = 2, 2 = 4)\n", srs_config_pdu->num_repetitions); + LOG_I(NR_PHY,"srs_config_pdu->time_start_position = %u\n", srs_config_pdu->time_start_position); + LOG_I(NR_PHY,"srs_config_pdu->config_index = %u\n", srs_config_pdu->config_index); + LOG_I(NR_PHY,"srs_config_pdu->sequence_id = %u\n", srs_config_pdu->sequence_id); + LOG_I(NR_PHY,"srs_config_pdu->bandwidth_index = %u\n", srs_config_pdu->bandwidth_index); + LOG_I(NR_PHY,"srs_config_pdu->comb_size = %u (0 = comb size 2, 1 = comb size 4, 2 = comb size 8)\n", srs_config_pdu->comb_size); + LOG_I(NR_PHY,"srs_config_pdu->comb_offset = %u\n", srs_config_pdu->comb_offset); + LOG_I(NR_PHY,"srs_config_pdu->cyclic_shift = %u\n", srs_config_pdu->cyclic_shift); + LOG_I(NR_PHY,"srs_config_pdu->frequency_position = %u\n", srs_config_pdu->frequency_position); + LOG_I(NR_PHY,"srs_config_pdu->frequency_shift = %u\n", srs_config_pdu->frequency_shift); + LOG_I(NR_PHY,"srs_config_pdu->frequency_hopping = %u\n", srs_config_pdu->frequency_hopping); + LOG_I(NR_PHY,"srs_config_pdu->group_or_sequence_hopping = %u (0 = No hopping, 1 = Group hopping groupOrSequenceHopping, 2 = Sequence hopping)\n", srs_config_pdu->group_or_sequence_hopping); + LOG_I(NR_PHY,"srs_config_pdu->resource_type = %u (0: aperiodic, 1: semi-persistent, 2: periodic)\n", srs_config_pdu->resource_type); + LOG_I(NR_PHY,"srs_config_pdu->t_srs = %u\n", srs_config_pdu->t_srs); + LOG_I(NR_PHY,"srs_config_pdu->t_offset = %u\n", srs_config_pdu->t_offset); +#endif + + configure_srs_info(srs_config_pdu, ue->nr_srs_info); + NR_DL_FRAME_PARMS *frame_parms = &(ue->frame_parms); + uint16_t symbol_offset = (frame_parms->symbols_per_slot - 1 - srs_config_pdu->time_start_position)*frame_parms->ofdm_symbol_size; + bool generated = generate_srs_nr(frame_parms, + txdataF, + symbol_offset, + srs_config_pdu->bwp_start, + ue->nr_srs_info, + AMP, + proc->frame_tx, + proc->nr_slot_tx); + return generated; +} + void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_data_tx_t *phy_data, c16_t **txp) { const int slot_tx = proc->nr_slot_tx; @@ -310,7 +404,8 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n (c16_t **)txdataF, txp, link_type_ul, - was_symbol_used); + was_symbol_used, + ue->no_phase_pre_comp); stop_meas_nr_ue_phy(ue, OFDM_MOD_STATS); } @@ -322,28 +417,25 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n stop_meas_nr_ue_phy(ue, PHY_PROC_TX); } -void nr_ue_measurement_procedures(uint16_t l, - PHY_VARS_NR_UE *ue, - const UE_nr_rxtx_proc_t *proc, - NR_UE_DLSCH_t *dlsch, - uint32_t pdsch_est_size, - int32_t dl_ch_estimates[][pdsch_est_size]) +static void nr_ue_measurement_procedures(uint16_t l, + PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + int number_rbs, + uint32_t pdsch_est_size, + int32_t dl_ch_estimates[][pdsch_est_size]) { NR_DL_FRAME_PARMS *frame_parms=&ue->frame_parms; int nr_slot_rx = proc->nr_slot_rx; int gNB_id = proc->gNB_id; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_MEASUREMENT_PROCEDURES, VCD_FUNCTION_IN); - if (l==2) { - + if (l == 2) { LOG_D(PHY,"Doing UE measurement procedures in symbol l %u Ncp %d nr_slot_rx %d, rxdata %p\n", - l, - ue->frame_parms.Ncp, - nr_slot_rx, - ue->common_vars.rxdata); - - nr_ue_measurements(ue, proc, dlsch, pdsch_est_size, dl_ch_estimates); - + l, + ue->frame_parms.Ncp, + nr_slot_rx, + ue->common_vars.rxdata); + nr_ue_measurements(ue, proc, number_rbs, pdsch_est_size, dl_ch_estimates); #if T_TRACER if(nr_slot_rx == 0) T(T_UE_PHY_MEAS, @@ -482,6 +574,51 @@ int nr_ue_pdcch_procedures(PHY_VARS_NR_UE *ue, return (dci_ind.number_of_dcis); } +static freq_alloc_bitmap_t set_start_end_from_bitmap(int size, int alloc_size, const uint8_t bitmap[alloc_size]) +{ + freq_alloc_bitmap_t alloc = { + .num_rbs = 0, + .num_blocks = 0 + }; + + bool pos_bit = false; + for (int i = 0; i < size; i++) { + if ((bitmap[i / 8] >> i % 8) & 0x1) { + if (!pos_bit) { + pos_bit = true; + alloc.start[alloc.num_blocks] = i; + AssertFatal(alloc.num_blocks < MAX_FA_BLOCKS, "Number of type0 PDSCH RBG exceeting %d\n", MAX_FA_BLOCKS); + alloc.num_blocks++; + } + alloc.num_rbs++; + } else { + if (pos_bit) { + pos_bit = false; + alloc.end[alloc.num_blocks - 1] = i - 1; + } + } + } + if (pos_bit) + alloc.end[alloc.num_blocks - 1] = size - 1; + AssertFatal(alloc.num_blocks > 0, "Frequency allocation bitmap empty\n"); + memcpy(alloc.bitmap, bitmap, alloc_size * sizeof(uint8_t)); + return alloc; +} + +static freq_alloc_bitmap_t set_bitmap_from_start_size(int start, int size) +{ + freq_alloc_bitmap_t alloc = { + .num_rbs = size, + .num_blocks = 1, + .start[0] = start, + .end[0] = start + size - 1 + }; + memset(alloc.bitmap, 0, 36 * sizeof(uint8_t)); + for (int i = start; i < size + start; i++) + alloc.bitmap[i / 8] += 1 << (i % 8); + return alloc; +} + static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, NR_UE_DLSCH_t dlsch[2], @@ -500,8 +637,15 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, // dlsch0_harq contains the previous transmissions data for this harq pid NR_DL_UE_HARQ_t *dlsch0_harq = &ue->dl_harq_processes[0][harq_pid]; + freq_alloc_bitmap_t freq_alloc = {0}; + if (dlschCfg->resource_alloc == 0) { + int alloc_size = (dlschCfg->BWPSize / 8) + (dlschCfg->BWPSize % 8 > 0); + freq_alloc = set_start_end_from_bitmap(dlschCfg->BWPSize, alloc_size, dlschCfg->rb_bitmap); + } else + freq_alloc = set_bitmap_from_start_size(dlschCfg->start_rb, dlschCfg->number_rbs); + LOG_D(PHY, - "[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask " + "[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, start RB %d, end RB %d, symbol_start %d, nb_symbols %d, DMRS mask " "%x, Nl %d\n", ue->Mod_id, frame_rx, @@ -509,8 +653,8 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, harq_pid, dlsch0_harq->status, dlschCfg->BWPStart, - dlschCfg->start_rb, - dlschCfg->number_rbs, + freq_alloc.start[0], + freq_alloc.end[freq_alloc.num_blocks - 1], dlschCfg->start_symbol, dlschCfg->number_symbols, dlschCfg->dlDmrsSymbPos, @@ -526,7 +670,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, int32_t ptrs_re_per_slot[ue->frame_parms.nb_antennas_rx][NR_SYMBOLS_PER_SLOT]; memset(ptrs_re_per_slot, 0, sizeof(ptrs_re_per_slot)); - const uint32_t rx_size_symbol = (dlsch[0].dlsch_config.number_rbs * NR_NB_SC_PER_RB + 15) & ~15; + const uint32_t rx_size_symbol = (freq_alloc.num_rbs * NR_NB_SC_PER_RB + 15) & ~15; fourDimArray_t *toFree2 = NULL; allocCast3D(rxdataF_comp, int32_t, @@ -546,16 +690,11 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, uint32_t nvar_tmp = 0; nr_pdsch_channel_estimation(ue, proc, + dlschCfg, + &freq_alloc, nl, get_dmrs_port(nl, dlschCfg->dmrs_ports), m, - dlschCfg->nscid, - dlschCfg->dlDmrsScramblingId, - dlschCfg->BWPStart, - dlschCfg->dmrsConfigType, - dlschCfg->rb_offset, - ue->frame_parms.first_carrier_offset + (dlschCfg->BWPStart + dlschCfg->start_rb) * 12, - dlschCfg->number_rbs, pdsch_est_size, pdsch_dl_ch_estimates, ue->frame_parms.samples_per_slot_wCP, @@ -575,10 +714,8 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, } } stop_meas_nr_ue_phy(ue, DLSCH_CHANNEL_ESTIMATION_STATS); - nvar /= (dlschCfg->number_symbols * dlsch0->Nl * ue->frame_parms.nb_antennas_rx); - - nr_ue_measurement_procedures(2, ue, proc, &dlsch[0], pdsch_est_size, pdsch_dl_ch_estimates); + nr_ue_measurement_procedures(2, ue, proc, freq_alloc.num_rbs, pdsch_est_size, pdsch_dl_ch_estimates); if (ue->chest_time == 1) { // averaging time domain channel estimates nr_chest_time_domain_avg(&ue->frame_parms, @@ -586,7 +723,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, dlschCfg->number_symbols, dlschCfg->start_symbol, dlschCfg->dlDmrsSymbPos, - dlschCfg->number_rbs); + freq_alloc.num_rbs); } uint16_t first_symbol_with_data = dlschCfg->start_symbol; @@ -605,6 +742,15 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, uint32_t llr_offset[NR_SYMBOLS_PER_SLOT] = {0}; int32_t log2_maxh = 0; + + const uint32_t rx_llr_layer_size = (G + dlsch[0].Nl - 1) / dlsch[0].Nl; + + if (dlsch[0].Nl == 0 || rx_llr_layer_size == 0 || rx_llr_layer_size > 10 * 1000 * 1000) { + LOG_E(PHY, "rx_llr_layer_size %d, G %d, Nl, %d, discarding this pdsch\n", rx_llr_layer_size, G, dlsch[0].Nl); + return -1; + } + __attribute__((aligned(32))) int16_t layer_llr[dlsch[0].Nl][rx_llr_layer_size]; + start_meas_nr_ue_phy(ue, RX_PDSCH_STATS); pdsch_scope_req_t scope_req = { .copy_chanest_to_scope = false, .copy_rxdataF_to_scope = false, @@ -615,13 +761,13 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, pdschChanEstimates, sizeof(c16_t), 1, - dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, + freq_alloc.num_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, &mt); scope_req.copy_rxdataF_to_scope = UETryLockScopeData(ue, pdschRxdataF, sizeof(c16_t), 1, - dlschCfg->number_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, + freq_alloc.num_rbs * NR_NB_SC_PER_RB * dlschCfg->number_symbols, &mt); } for (int m = dlschCfg->start_symbol; m < (dlschCfg->number_symbols + dlschCfg->start_symbol); m++) { @@ -634,11 +780,14 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, if (nr_rx_pdsch(ue, proc, dlsch, + &freq_alloc, m, first_symbol_flag, harq_pid, pdsch_est_size, pdsch_dl_ch_estimates, + rx_llr_layer_size, + layer_llr, llr, dl_valid_re, rxdataF, @@ -687,7 +836,7 @@ static uint32_t compute_csi_rm_unav_res(fapi_nr_dl_config_dlsch_pdu_rel15_t *dls int num_symb = num_l0[csi_pdu->row - 1]; for (int s = 0; s < num_symb; s++) { int l0_symb = csi_pdu->symb_l0 + s; - if (l0_symb >= dlsch_config->start_symbol && l0_symb <= dlsch_config->start_symbol + dlsch_config->number_symbols) + if (l0_symb >= dlsch_config->start_symbol && l0_symb < dlsch_config->start_symbol + dlsch_config->number_symbols) num_overlap_symb++; } // check also l1 if relevant @@ -695,7 +844,7 @@ static uint32_t compute_csi_rm_unav_res(fapi_nr_dl_config_dlsch_pdu_rel15_t *dls num_symb += 2; for (int s = 0; s < 2; s++) { // two consecutive symbols including l1 int l1_symb = csi_pdu->symb_l1 + s; - if (l1_symb >= dlsch_config->start_symbol && l1_symb <= dlsch_config->start_symbol + dlsch_config->number_symbols) + if (l1_symb >= dlsch_config->start_symbol && l1_symb < dlsch_config->start_symbol + dlsch_config->number_symbols) num_overlap_symb++; } } @@ -955,31 +1104,38 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_ nr_ue_ssb_rsrp_measurements(ue, ssb_index, proc, rxdataF); // resetting ssb index for PBCH detection if there is a stronger SSB index - if(ue->measurements.ssb_rsrp_dBm[ssb_index] > ue->measurements.ssb_rsrp_dBm[fp->ssb_index]) + if(ue->measurements.ssb_rsrp_dBm[ssb_index] > ue->measurements.ssb_rsrp_dBm[fp->ssb_index]) { fp->ssb_index = ssb_index; - - if(ssb_index == fp->ssb_index) { - - LOG_D(PHY," ------ Decode MIB: frame.slot %d.%d ------ \n", frame_rx%1024, nr_slot_rx); - const int pbchSuccess = nr_ue_pbch_procedures(ue, proc, estimateSz, dl_ch_estimates, rxdataF); - - if (ue->no_timing_correction==0 && pbchSuccess == 0) { - LOG_D(PHY,"start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction); - sampleShift = - nr_adjust_synch_ue(fp, ue, gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384); - } - - if (get_nrUE_params()->cont_fo_comp && pbchSuccess == 0) { - double freq_offset = nr_ue_pbch_freq_offset(fp, estimateSz, dl_ch_estimates); - LOG_D(PHY,"compensated frequency offset = %.3f Hz, detected residual frequency offset = %.3f Hz, accumulated frequency offset = %.3f Hz\n", ue->freq_offset, freq_offset, ue->freq_off_acc); - - // PI controller - const double PID_P = get_nrUE_params()->freq_sync_P; - const double PID_I = get_nrUE_params()->freq_sync_I; - ue->freq_offset += freq_offset * PID_P + ue->freq_off_acc * PID_I; - ue->freq_off_acc += freq_offset; - } + LOG_D(PHY, "New best SSB: index %d RSRP %d\n", ssb_index, ue->measurements.ssb_rsrp_dBm[ssb_index]); } + + if(ssb_index != fp->ssb_index) + continue; + + LOG_D(PHY, " ------ Decode MIB: frame.slot %d.%d ------ \n", frame_rx % 1024, nr_slot_rx); + const int pbchSuccess = nr_ue_pbch_procedures(ue, proc, estimateSz, dl_ch_estimates, rxdataF); + + if (ue->no_timing_correction == 0 && pbchSuccess == 0) { + LOG_D(PHY,"start adjust sync slot = %d no timing %d\n", nr_slot_rx, ue->no_timing_correction); + sampleShift = + nr_adjust_synch_ue(fp, ue, gNB_id, fp->ofdm_symbol_size, dl_ch_estimates_time, frame_rx, nr_slot_rx, 16384); + } + + if (get_nrUE_params()->cont_fo_comp && pbchSuccess == 0) { + double freq_offset = nr_ue_pbch_freq_offset(fp, estimateSz, dl_ch_estimates); + LOG_D(PHY, + "compensated freq offset = %.3f Hz, detected residual freq offset = %.3f Hz, accumulated freq offset = %.3f Hz\n", + ue->freq_offset, + freq_offset, + ue->freq_off_acc); + + // PI controller + const double PID_P = get_nrUE_params()->freq_sync_P; + const double PID_I = get_nrUE_params()->freq_sync_I; + ue->freq_offset += freq_offset * PID_P + ue->freq_off_acc * PID_I; + ue->freq_off_acc += freq_offset; + } + LOG_D(PHY, "Doing N0 measurements in %s\n", __FUNCTION__); nr_ue_rrc_measurements(ue, proc, rxdataF); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PBCH, VCD_FUNCTION_OUT); @@ -1042,6 +1198,8 @@ int pbch_pdcch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_ phy_pdcch_config->nb_search_space = 0; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDCCH, VCD_FUNCTION_OUT); TracyCZoneEnd(ctx); + if (ue->phy_sim_rxdataF) + memcpy(ue->phy_sim_rxdataF, rxdataF[0], sizeof(int32_t) * nb_symb_pdcch * ue->frame_parms.ofdm_symbol_size); return sampleShift; } @@ -1099,13 +1257,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_SLOT_FEP_PDSCH, VCD_FUNCTION_OUT); - uint8_t nb_re_dmrs; - if (dlsch_config->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) { - nb_re_dmrs = 6 * dlsch_config->n_dmrs_cdm_groups; - } - else { - nb_re_dmrs = 4 * dlsch_config->n_dmrs_cdm_groups; - } + const uint8_t nb_re_dmrs = get_num_dmrs_re_per_rb(dlsch_config->dmrsConfigType, dlsch_config->n_dmrs_cdm_groups); uint16_t dmrs_len = get_num_dmrs(dlsch_config->dlDmrsSymbPos); uint32_t unav_res = 0; if(dlsch_config->pduBitmap & 0x1) { @@ -1166,9 +1318,11 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_ } if (ue->phy_sim_rxdataF) - memcpy(ue->phy_sim_rxdataF, rxdataF, sizeof(int32_t)*rxdataF_sz*ue->frame_parms.nb_antennas_rx); + memcpy(ue->phy_sim_rxdataF + start_symb_sch * ue->frame_parms.ofdm_symbol_size * sizeof(c16_t), + &rxdataF[0][start_symb_sch * ue->frame_parms.ofdm_symbol_size], + sizeof(int32_t) * nb_symb_sch * ue->frame_parms.ofdm_symbol_size); if (ue->phy_sim_pdsch_llr) - memcpy(ue->phy_sim_pdsch_llr, llr[0], sizeof(int16_t)*rx_llr_buf_sz); + memcpy(ue->phy_sim_pdsch_llr, llr[0], sizeof(int16_t) * rx_llr_buf_sz); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC, VCD_FUNCTION_OUT); for (int i=0; iMod_id,frame_rx,ue->total_TBS[gNB_id], ue->total_TBS_last[gNB_id],(float) ue->bitrate[gNB_id]/1000.0); - -#if UE_AUTOTEST_TRACE - if ((frame_rx % 100 == 0)) { - LOG_I(PHY,"[UE %d] AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", ue->Mod_id, (float) ue->bitrate[gNB_id]/1000.0, frame_rx); - } -#endif - } #ifdef EMOS diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c index 13b081385d..e03c0a1fae 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue_sl.c @@ -227,7 +227,7 @@ int psbch_pscch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr sym = (sym == 0) ? 5 : sym + 1; } - ue->adjust_rxgain = nr_sl_psbch_rsrp_measurements(sl_phy_params, fp, rxdataF, false); + ue->adjust_rxgain = nr_sl_psbch_rsrp_measurements(sl_phy_params, fp, rxdataF, false, ue->openair0_cfg); LOG_D(NR_PHY, " ------ Decode SL-MIB: frame.slot %d.%d ------ \n", frame_rx % 1024, nr_slot_rx); @@ -313,7 +313,15 @@ void phy_procedures_nrUE_SL_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc was_symbol_used[i] = true; if (tx_action) { LOG_D(NR_PHY, "Sending Uplink data \n"); - nr_ue_pusch_common_procedures(ue, proc->nr_slot_tx, fp, fp->nb_antennas_tx, txdataF, txp, link_type_sl, was_symbol_used); + nr_ue_pusch_common_procedures(ue, + proc->nr_slot_tx, + fp, + fp->nb_antennas_tx, + txdataF, + txp, + link_type_sl, + was_symbol_used, + ue->no_phase_pre_comp); } LOG_D(NR_PHY, "****** end Sidelink TX-Chain for AbsSubframe %d.%d ******\n", frame_tx, slot_tx); diff --git a/openair1/SCHED_UE/phy_procedures_lte_ue.c b/openair1/SCHED_UE/phy_procedures_lte_ue.c index 0b336fdce6..0e4c59dc0e 100644 --- a/openair1/SCHED_UE/phy_procedures_lte_ue.c +++ b/openair1/SCHED_UE/phy_procedures_lte_ue.c @@ -4320,13 +4320,6 @@ int phy_procedures_slot_parallelization_UE_RX(PHY_VARS_UE *ue, LOG_D(PHY,"[UE %d] Calculating bitrate Frame %d: total_TBS = %d, total_TBS_last = %d, bitrate %f kbits\n", ue->Mod_id,frame_rx,ue->total_TBS[eNB_id], ue->total_TBS_last[eNB_id],(float) ue->bitrate[eNB_id]/1000.0); -#if UE_AUTOTEST_TRACE - - if ((frame_rx % 100 == 0)) { - LOG_I(PHY,"[UE %d] AUTOTEST Metric : UE_DLSCH_BITRATE = %5.2f kbps (frame = %d) \n", ue->Mod_id, (float) ue->bitrate[eNB_id]/1000.0, frame_rx); - } - -#endif } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_UE_RX, VCD_FUNCTION_OUT); diff --git a/openair1/SIMULATION/CMakeLists.txt b/openair1/SIMULATION/CMakeLists.txt new file mode 100644 index 0000000000..b93118ccb7 --- /dev/null +++ b/openair1/SIMULATION/CMakeLists.txt @@ -0,0 +1,3 @@ +if(ENABLE_PHYSIM_TESTS) + add_subdirectory(tests) +endif() diff --git a/openair1/SIMULATION/LTE_PHY/dlsim.c b/openair1/SIMULATION/LTE_PHY/dlsim.c index 5e6140db9d..d6e8482919 100644 --- a/openair1/SIMULATION/LTE_PHY/dlsim.c +++ b/openair1/SIMULATION/LTE_PHY/dlsim.c @@ -90,7 +90,6 @@ static int cmpdouble(const void *p1, const void *p2) { } RAN_CONTEXT_t RC; -int emulate_rf = 0; void handler(int sig) { void *array[10]; size_t size; @@ -1264,9 +1263,7 @@ int main(int argc, char **argv) { L1_rxtx_proc_t *proc_eNB = &eNB->proc.L1_proc; proc_eNB->threadPool = (tpool_t *)malloc(sizeof(tpool_t)); - proc_eNB->respDecode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); initTpool("n", proc_eNB->threadPool, true); - initNotifiedFIFO(proc_eNB->respDecode); proc_eNB->frame_tx=0; diff --git a/openair1/SIMULATION/LTE_PHY/mbmssim.c b/openair1/SIMULATION/LTE_PHY/mbmssim.c index ac50bf62bd..dac151e4fe 100644 --- a/openair1/SIMULATION/LTE_PHY/mbmssim.c +++ b/openair1/SIMULATION/LTE_PHY/mbmssim.c @@ -89,8 +89,6 @@ int n_rx_dropped = 0; /*!< \brief initial max process time for rx */ THREAD_STRUCT thread_struct; -int emulate_rf = 0; - void handler(int sig) { void *array[10]; size_t size; diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c index d17f767a2a..76cc2e0716 100644 --- a/openair1/SIMULATION/LTE_PHY/ulsim.c +++ b/openair1/SIMULATION/LTE_PHY/ulsim.c @@ -795,9 +795,7 @@ int main(int argc, char **argv) { proc_rxtx_ue->subframe_tx = proc_rxtx->subframe_rx; proc_rxtx_ue->subframe_rx = (proc_rxtx->subframe_tx+6)%10; proc_rxtx->threadPool = (tpool_t *)malloc(sizeof(tpool_t)); - proc_rxtx->respDecode=(notifiedFIFO_t*) malloc(sizeof(notifiedFIFO_t)); initTpool("n", proc_rxtx->threadPool, true); - initNotifiedFIFO(proc_rxtx->respDecode); printf("Init UL hopping UE\n"); init_ul_hopping(&UE->frame_parms); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index b858945018..6329d5849f 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -216,6 +216,7 @@ void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, slot_t slot) NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; sched_pdsch->rbStart = g_rbStart; sched_pdsch->rbSize = g_rbSize; + sched_pdsch->bwp_info = get_pdsch_bwp_start_size(RC.nrmac[module_id], UE_info); sched_pdsch->mcs = g_mcsIndex; sched_pdsch->nrOfLayers = g_nrOfLayers; sched_pdsch->pm_index = g_pmi; @@ -310,9 +311,9 @@ int main(int argc, char **argv) int i,aa;//,l; double sigma2, sigma2_dB=10, SNR, snr0=-2.0, snr1=2.0; uint8_t snr1set=0; - float effRate; + double effRate; //float psnr; - float eff_tp_check = 0.7; + double eff_tp_check = 0.7; uint32_t TBS = 0; c16_t **txdata; double **s_re,**s_im,**r_re,**r_im; @@ -546,7 +547,7 @@ int main(int argc, char **argv) break; case 't': - eff_tp_check = (float)atoi(optarg)/100; + eff_tp_check = atof(optarg) / 100.0; break; case 'w': @@ -646,14 +647,13 @@ int main(int argc, char **argv) break; } } -printf("%d\n", slot); + logInit(); set_glog(loglvl); /* initialize the sin table */ InitSinLUT(); get_softmodem_params()->phy_test = 1; - get_softmodem_params()->usim_test = 1; get_softmodem_params()->do_ra = 0; IS_SOFTMODEM_DLSIM = true; @@ -701,6 +701,8 @@ printf("%d\n", slot); .minRXTXTIME = 6, .do_CSIRS = 0, .do_SRS = 0, + .num_dlharq = 16, + .num_ulharq = 16, .maxMIMO_layers = g_nrOfLayers, .force_256qam_off = false, .timer_config.sr_ProhibitTimer = 0, @@ -743,7 +745,7 @@ printf("%d\n", slot); RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); for (i = 0; i < RC.nb_nr_macrlc_inst; i++) RC.nb_nr_mac_CC[i] = 1; - mac_top_init_gNB(ngran_gNB, scc, NULL, &conf, &rlc_config); + mac_top_init_gNB(ngran_gNB, scc, &conf, &rlc_config); gNB_mac = RC.nrmac[0]; nr_mac_config_scc(RC.nrmac[0], scc, &conf); @@ -791,11 +793,6 @@ printf("%d\n", slot); NR_ServingCellConfigCommon_t *scc = secondaryCellGroup->spCellConfig->reconfigurationWithSync->spCellConfigCommon; */ - NR_ServingCellConfig_t *scd = calloc(1,sizeof(*scd)); - prepare_scd(scd); - /* removes unnecessary BWPs, if any */ - fix_scd(scd); - gNB->ap_N1 = pdsch_AntennaPorts.N1; gNB->ap_N2 = pdsch_AntennaPorts.N2; gNB->ap_XP = pdsch_AntennaPorts.XP; @@ -806,8 +803,8 @@ printf("%d\n", slot); prepare_sim_uecap(UE_Capability_nr, scc, mu, N_RB_DL, g_mcsTableIdx, 0); rnti_t rnti = 0x1234; int uid = 0; - NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, uid); - secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc); + NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, UE_Capability_nr, 0, 1, &conf, uid); + secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc, frame); /* -U option modify DMRS */ if(modify_dmrs) { @@ -924,8 +921,7 @@ printf("%d\n", slot); init_nr_ue_transport(UE); - nr_l2_init_ue(1); - UE_mac = get_mac_inst(0); + UE_mac = nr_l2_init_ue(0); ue_init_config_request(UE_mac, get_slots_per_frame_from_scs(mu)); UE->if_inst = nr_ue_if_module_init(0); @@ -953,7 +949,7 @@ printf("%d\n", slot); //Configure UE NR_BCCH_BCH_Message_t *mib = get_new_MIB_NR(scc); - nr_rrc_mac_config_req_mib(0, 0, mib->message.choice.mib, false); + nr_rrc_mac_config_req_mib(0, 0, mib->message.choice.mib, false, false); nr_rrc_mac_config_req_cg(0, 0, UE_CellGroup, UE_Capability_nr); asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, UE_CellGroup); @@ -969,12 +965,9 @@ printf("%d\n", slot); //NR_COMMON_channels_t *cc = RC.nrmac[0]->common_channels; int ret = 1; initNamedTpool(gNBthreads, &gNB->threadPool, true, "gNB-tpool"); - initNotifiedFIFO(&gNB->L1_tx_free); - initNotifiedFIFO(&gNB->L1_tx_filled); initNotifiedFIFO(&gNB->L1_tx_out); // we create 2 threads for L1 tx processing - notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t),0,&gNB->L1_tx_free,processSlotTX); - processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); + processingData_L1tx_t *msgDataTx = malloc(sizeof(processingData_L1tx_t)); init_DLSCH_struct(gNB, msgDataTx); msgDataTx->slot = slot; msgDataTx->frame = frame; @@ -1033,6 +1026,10 @@ printf("%d\n", slot); reset_meas(&gNB->dlsch_rate_matching_stats); reset_meas(&gNB->dlsch_segmentation_stats); reset_meas(&gNB->dlsch_modulation_stats); + reset_meas(&gNB->dlsch_pdsch_generation_stats); + reset_meas(&gNB->dlsch_precoding_stats); + reset_meas(&gNB->dlsch_layer_mapping_stats); + reset_meas(&gNB->dlsch_resource_mapping_stats); reset_meas(&gNB->dlsch_encoding_stats); reset_meas(&gNB->dci_generation_stats); reset_meas(&gNB->tinput); @@ -1081,8 +1078,6 @@ printf("%d\n", slot); Sched_INFO->sched_response_id = -1; while (round < num_rounds && !UE_harq_process->decodeResult && !stop) { - round_trials[round]++; - clear_nr_nfapi_information(RC.nrmac[0], 0, frame, slot, &Sched_INFO->DL_req, &Sched_INFO->TX_req, &Sched_INFO->UL_dci_req); UE_info->UE_sched_ctrl.harq_processes[harq_pid].ndi = !(trial&1); UE_info->UE_sched_ctrl.harq_processes[harq_pid].round = round; @@ -1096,7 +1091,6 @@ printf("%d\n", slot); Sched_INFO->frame = frame; Sched_INFO->slot = slot; Sched_INFO->UL_dci_req.numPdus = 0; - pushNotifiedFIFO(&gNB->L1_tx_free,msgL1Tx); nr_schedule_response(Sched_INFO); /* PTRS values for DLSIM calculations */ @@ -1235,14 +1229,17 @@ printf("%d\n", slot); if (dlsch0->last_iteration_cnt >= dlsch0->max_ldpc_iterations) n_errors[round]++; + if (dlsch0->active) + round_trials[round]++; + int16_t *UE_llr = (int16_t*)UE->phy_sim_pdsch_llr; TBS = dlsch0->dlsch_config.TBS;//rel15->TBSize[0]; - uint16_t length_dmrs = get_num_dmrs(rel15->dlDmrsSymbPos); - uint16_t nb_rb = rel15->rbSize; - uint8_t nb_re_dmrs = rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6*dlsch0->dlsch_config.n_dmrs_cdm_groups : 4*dlsch0->dlsch_config.n_dmrs_cdm_groups; - uint8_t mod_order = rel15->qamModOrder[0]; - uint8_t nb_symb_sch = rel15->NrOfSymbols; + uint16_t length_dmrs = get_num_dmrs(dlsch0->dlsch_config.dlDmrsSymbPos); + uint16_t nb_rb = dlsch0->dlsch_config.number_rbs; + uint8_t nb_re_dmrs = dlsch0->dlsch_config.dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6*dlsch0->dlsch_config.n_dmrs_cdm_groups : 4*dlsch0->dlsch_config.n_dmrs_cdm_groups; + uint8_t mod_order = dlsch0->dlsch_config.qamModOrder; + uint8_t nb_symb_sch = dlsch0->dlsch_config.number_symbols; uint32_t unav_res = ptrsSymbPerSlot * ptrsRePerSymb; available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, unav_res, mod_order, rel15->nrOfLayers); if (pdu_bit_map & 0x1) { @@ -1252,9 +1249,8 @@ printf("%d\n", slot); } for (i = 0; i < available_bits; i++) { - if(((gNB_dlsch->harq_process.f[i] == 0) && (UE_llr[i] <= 0)) || - ((gNB_dlsch->harq_process.f[i] == 1) && (UE_llr[i] >= 0))) - { + const uint8_t current_bit = (gNB_dlsch->harq_process.f[i / 8] & (1 << (i & 7))) >> (i & 7); + if (((current_bit == 0) && (UE_llr[i] <= 0)) || ((current_bit == 1) && (UE_llr[i] >= 0))) { if (errors_scrambling[round] == 0) { LOG_D(PHY,"First bit in error in unscrambling = %d\n",i); } @@ -1267,8 +1263,8 @@ printf("%d\n", slot); } // round if (test_input_bit == NULL) { - test_input_bit = (unsigned char *)malloc16(sizeof(unsigned char) * TBS); - estimated_output_bit = (unsigned char *)malloc16(sizeof(unsigned char) * TBS); + test_input_bit = (unsigned char *)malloc16(8 * rel15->TBSize[0]); + estimated_output_bit = (unsigned char *)malloc16(8 * rel15->TBSize[0]); } for (i = 0; i < TBS; i++) { @@ -1289,12 +1285,12 @@ printf("%d\n", slot); if (n_trials == 1) printf("errors_bit = %u (trial %d)\n", errors_bit, trial); } - roundStats += ((float)round); + roundStats += round; if (UE_harq_process->decodeResult) - effRate += ((float)TBS) / round; + effRate += ((double)TBS) / round; } // noise trials - roundStats /= ((float)n_trials); + roundStats /= n_trials; for (int r = 0; r < num_rounds; r++) { blerStats[r] = (double)n_errors[r] / round_trials[r]; @@ -1317,7 +1313,7 @@ printf("%d\n", slot); printf("), Channel BER (%e", berStats[0]); for (int r = 1; r < num_rounds; r++) printf(",%e", berStats[r]); - printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", roundStats, effRate, effRate / TBS * 100, TBS); + printf(") Avg round %.2f, Eff Rate %.4f bits/slot, Eff Throughput %.2f, TBS %u bits/slot\n", roundStats, effRate, effRate / (8 * rel15->TBSize[0]) * 100, 8 * rel15->TBSize[0]); printf("*****************************************\n"); printf("\n"); // writing to csv file @@ -1325,7 +1321,7 @@ printf("%d\n", slot); fprintf(csv_file,"%f,%d/%d,",SNR,n_false_positive,n_trials); for (int r = 0; r < num_rounds; r++) fprintf(csv_file,"%d/%d,%u/%u,%f,%e,",n_errors[r], round_trials[r], errors_scrambling[r], available_bits * round_trials[r],blerStats[r],berStats[r]); - fprintf(csv_file,"%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / TBS * 100, TBS); + fprintf(csv_file,"%.2f,%.4f,%.2f,%u\n", roundStats, effRate, effRate / (8 * rel15->TBSize[0]) * 100, 8 * rel15->TBSize[0]); } if (print_perf==1) { printf("\ngNB TX function statistics (per %d us slot, NPRB %d, mcs %d, C %d, block %d)\n", @@ -1333,7 +1329,7 @@ printf("%d\n", slot); g_rbSize, g_mcsIndex, UE->dl_harq_processes[0][slot].C, - msgDataTx->dlsch[0][0].harq_process.pdsch_pdu.pdsch_pdu_rel15.TBSize[0] << 3); + 8 * rel15->TBSize[0]); printDistribution(&gNB->phy_proc_tx,table_tx,"PHY proc tx"); printStatIndent2(&gNB->dci_generation_stats, "DCI encoding time"); printStatIndent2(&gNB->dlsch_encoding_stats,"DLSCH encoding time"); @@ -1342,11 +1338,16 @@ printf("%d\n", slot); printStatIndent3(&gNB->tprep,"DLSCH LDPC input preparation time"); printStatIndent3(&gNB->tparity,"DLSCH LDPC parity generation time"); printStatIndent3(&gNB->toutput,"DLSCH LDPC output generation time"); - printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Mataching time"); + printStatIndent3(&gNB->dlsch_rate_matching_stats,"DLSCH Rate Matching time"); printStatIndent3(&gNB->dlsch_interleaving_stats, "DLSCH Interleaving time"); printStatIndent2(&gNB->dlsch_modulation_stats,"DLSCH modulation time"); printStatIndent2(&gNB->dlsch_scrambling_stats, "DLSCH scrambling time"); - printStatIndent2(&gNB->dlsch_precoding_stats,"DLSCH Mapping/Precoding time"); + printStatIndent2(&gNB->dlsch_pdsch_generation_stats,"DLSCH PDSCH Generation time"); + printStatIndent3(&gNB->dlsch_layer_mapping_stats,"DLSCH Layer Mapping time"); + gNB->dlsch_resource_mapping_stats.trials = gNB->dlsch_layer_mapping_stats.trials; + printStatIndent3(&gNB->dlsch_resource_mapping_stats,"DLSCH Resource Mapping time"); + gNB->dlsch_precoding_stats.trials = gNB->dlsch_layer_mapping_stats.trials; + printStatIndent3(&gNB->dlsch_precoding_stats,"DLSCH Precoding time"); if (gNB->phase_comp) printStatIndent2(&gNB->phase_comp_stats, "Phase Compensation"); @@ -1367,23 +1368,38 @@ printf("%d\n", slot); if (UE->frame_parms.nb_antennas_rx>1) LOG_M("rxsig1.m", "rxs1", UE->common_vars.rxdata[1], frame_length_complex_samples, dec, op_format); LOG_M("rxF0.m", "rxF0", UE->phy_sim_rxdataF, frame_parms->samples_per_slot_wCP, dec, op_format); - LOG_M("rxF_ext.m", "rxFe", UE->phy_sim_pdsch_rxdataF_ext, g_rbSize * 12 * 14, dec, op_format); const uint32_t numReSym = (g_rbSize * 12 + 15) & (~15); - const uint32_t numValidReSym = g_rbSize * 12; - { - const int s = rel15->StartSymbolIndex; - const int n = rel15->NrOfSymbols; - for (int i = s; i < s + n; i++) { - char fName[50]; - snprintf(fName, sizeof(fName), "chestF0_ext_s%d.m", i); - LOG_M(fName, - "chF0_ext", - ((c16_t *)UE->phy_sim_pdsch_dl_ch_estimates_ext) + (i * numReSym), - numValidReSym, - dec, - op_format); - snprintf(fName, sizeof(fName), "rxF_comp_s%d.m", i); - LOG_M(fName, "rxFc", ((c16_t *)UE->phy_sim_pdsch_rxdataF_comp) + (i * numReSym), numValidReSym, dec, op_format); + for (int l = 0; l < g_nrOfLayers; l++) { + for (int r = 0; r < n_rx; r++) { + const int s = rel15->StartSymbolIndex; + const int n = rel15->NrOfSymbols; + for (int i = s; i < s + n; i++) { + const uint32_t dmrsBitMap = phy_data.dlsch[0].dlsch_config.dlDmrsSymbPos; + const uint32_t dmrsCfg = phy_data.dlsch[0].dlsch_config.dmrsConfigType; + const uint32_t nrb = phy_data.dlsch[0].dlsch_config.number_rbs; + const uint32_t ncdmg = phy_data.dlsch[0].dlsch_config.n_dmrs_cdm_groups; + const uint32_t numValidReSym = ((dmrsBitMap >> i) & 1) + ? ((dmrsCfg == NFAPI_NR_DMRS_TYPE1) ? nrb * (12 - 6 * ncdmg) : nrb * (12 - 4 * ncdmg)) + : (nrb * 12); + char fName[50]; + snprintf(fName, sizeof(fName), "chestF_ext_l%d_r%d_s%d.m", l, r, i); + uint32_t buff_offset = (i * g_nrOfLayers * n_rx * numReSym) + (l * n_rx * numReSym) + (r * numReSym); + LOG_M(fName, + "chF0_ext", + ((c16_t *)UE->phy_sim_pdsch_dl_ch_estimates_ext) + buff_offset, + numValidReSym, + dec, + op_format); + snprintf(fName, sizeof(fName), "rxF_comp_l%d_s%d.m", l, i); + LOG_M(fName, "rxFc", ((c16_t *)UE->phy_sim_pdsch_rxdataF_comp) + (l * NR_SYMBOLS_PER_SLOT * numReSym) + (i * numReSym), numValidReSym, dec, op_format); + if (l == 0) { + snprintf(fName, sizeof(fName), "rxF_ext_r%d_s%d.m", r, i); + buff_offset = (i * n_rx * numReSym) + (r * numReSym); + LOG_M(fName, "rxFext", ((c16_t *)UE->phy_sim_pdsch_rxdataF_ext) + buff_offset, numValidReSym, dec, op_format); + } + snprintf(fName, sizeof(fName), "chestF0_s%d.m", i); + LOG_M(fName, "chF0", ((c16_t *)UE->phy_sim_pdsch_dl_ch_estimates) + i * frame_parms->ofdm_symbol_size, nrb*12, dec, op_format); + } } } LOG_M("chestF0.m", "chF0", UE->phy_sim_pdsch_dl_ch_estimates, frame_parms->ofdm_symbol_size * 14, dec, op_format); @@ -1392,7 +1408,7 @@ printf("%d\n", slot); break; } - if (effRate > (eff_tp_check*TBS)) { + if (effRate >= (eff_tp_check * 8 * rel15->TBSize[0])) { printf("PDSCH test OK\n"); ret = 0; break; diff --git a/openair1/SIMULATION/NR_PHY/nr_unitary_common.c b/openair1/SIMULATION/NR_PHY/nr_unitary_common.c index 734a62d994..604e7a8c2a 100644 --- a/openair1/SIMULATION/NR_PHY/nr_unitary_common.c +++ b/openair1/SIMULATION/NR_PHY/nr_unitary_common.c @@ -112,20 +112,20 @@ int32_t get_uldl_offset(int nr_bandP) void configure_nr_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port) { } -void configure_nr_nfapi_vnf(char *vnf_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port) +void configure_nr_nfapi_vnf(eth_params_t params) { } int nfapi_nr_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t *config) { return 0; } -int nfapi_nr_p7_message_unpack(void *pMessageBuf, +bool nfapi_nr_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen, nfapi_p7_codec_config_t *config) { - return 0; + return false; } int nfapi_p7_message_header_unpack(void *pMessageBuf, uint32_t messageBufLen, @@ -178,3 +178,12 @@ void *rrc_nrue(void *notUsed) { return NULL; } + +void nr_mac_rrc_meas_ind_ue(module_id_t module_id, + uint32_t gNB_index, + uint16_t Nid_cell, + bool csi_meas, + bool is_neighboring_cell, + int rsrp_dBm) +{ +} diff --git a/openair1/SIMULATION/NR_PHY/pbchsim.c b/openair1/SIMULATION/NR_PHY/pbchsim.c index 4fc6f788b7..6279663e74 100644 --- a/openair1/SIMULATION/NR_PHY/pbchsim.c +++ b/openair1/SIMULATION/NR_PHY/pbchsim.c @@ -154,7 +154,6 @@ int main(int argc, char **argv) int ssb_scan_threads = 0; channel_desc_t *gNB2UE; - get_softmodem_params()->usim_test = 1; //uint8_t extended_prefix_flag=0; //int8_t interf1=-21,interf2=-21; diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index a13918a606..35e242cad3 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -64,7 +64,6 @@ #include "nfapi/oai_integration/vendor_ext.h" #include "nfapi_interface.h" #include "nfapi_nr_interface_scf.h" -#include "nr_common.h" #include "time_meas.h" #define NR_PRACH_DEBUG 1 diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index ef6fd34ee4..77a0046e1f 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -391,7 +391,6 @@ int main(int argc, char **argv) //gNB_config = &gNB->gNB_config; initTpool("n", &gNB->threadPool, true); - initNotifiedFIFO(&gNB->respDecode); frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH) frame_parms->N_RB_DL = N_RB_DL; frame_parms->N_RB_UL = N_RB_UL; @@ -513,7 +512,8 @@ int main(int argc, char **argv) if (input_fd == NULL) { uint8_t ULSCH_ids[] = {0}; - nr_ulsch_encoding(UE, ulsch_ue, 0, 0, &G, 1, ULSCH_ids); + nr_ulsch_pre_encoding(UE, ulsch_ue, 0, 0, &G, 1, ULSCH_ids); + nr_ulsch_encoding(UE, ulsch_ue, 0, 0, &G, 1, ULSCH_ids, 0); } printf("\n"); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 4e127fe0b7..c4b2f854c2 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -160,6 +160,108 @@ openair0_config_t openair0_cfg[MAX_CARDS]; channel_desc_t *UE2gNB[MAX_MOBILES_PER_GNB][NUMBER_OF_gNB_MAX]; +static void copy_bytes_to_packed_bits(const uint8_t *in, const uint32_t num_bits, const bool is_ulsch, uint8_t *out) +{ + if (is_ulsch) { // MATLAB computes CRC for input of MSB first + for (uint_fast32_t b = 0; b < num_bits; b++) { + out[b / 8] |= ((in[b] & 1) << (7 - (b % 8))); + } + } else { + for (uint_fast32_t b = 0; b < num_bits; b++) { + out[b / 8] |= (in[b] << (b % 8)); + } + } +} + +static void prepare_ue_pusch_pdu_from_matlab_vector(const bool uci_on_pusch, + FILE *vect_file, + nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, + uint8_t *cw_buf) +{ + if (!uci_on_pusch) + return; + + if (vect_file == NULL) + return; + + struct vect_vars { + uint32_t A; + uint32_t oack; + uint32_t ocsi1; + uint32_t ocsi2; + uint32_t cwlen; + uint32_t cwlen_scr; + } __attribute__((packed)); + + struct vect_vars var = {0}; + if (1 != fread(&var, sizeof(var), 1, vect_file)) { + printf("Error reading from matlab vector file\n"); + exit(-1); + } + + const uint16_t buff_len = var.A + var.oack + var.ocsi1 + var.ocsi2; + uint8_t vec_bits[buff_len]; + memset(vec_bits, 0, sizeof(vect_file)); + + uint8_t *p_vec_bits = vec_bits; + if (var.A != fread(p_vec_bits, sizeof(uint8_t), var.A, vect_file)) { + printf("Error reading ULSCH bits from file\n"); + exit(-1); + } + p_vec_bits += var.A; + if (var.oack != fread(p_vec_bits, sizeof(uint8_t), var.oack, vect_file)) { + printf("Error reading ACK bits from file\n"); + exit(-1); + } + p_vec_bits += var.oack; + if (var.ocsi1 != fread(p_vec_bits, sizeof(uint8_t), var.ocsi1, vect_file)) { + printf("Error reading CSI1 bits from file\n"); + exit(-1); + } + p_vec_bits += var.ocsi1; + if (var.ocsi2 != fread(p_vec_bits, sizeof(uint8_t), var.ocsi2, vect_file)) { + printf("Error reading CSI2 bits from file\n"); + exit(-1); + } + + if (var.cwlen != fread(cw_buf, sizeof(uint8_t), var.cwlen, vect_file)) { + printf("Error reading cw bits from file\n"); + exit(-1); + } + + memset(cw_buf, 0, var.cwlen_scr); + if (var.cwlen_scr != fread(cw_buf, sizeof(uint8_t), var.cwlen_scr, vect_file)) { + printf("Error reading cw bits from file\n"); + exit(-1); + } + + uint16_t tb_buf_size = (var.A + 7) / 8; + pusch_config_pdu->pusch_data.tb_size = tb_buf_size; + pusch_config_pdu->tx_request_body.pdu_length = tb_buf_size; + uint8_t *pb = pusch_config_pdu->tx_request_body.fapiTxPdu; + memset(pb, 0, tb_buf_size); + p_vec_bits = vec_bits; + copy_bytes_to_packed_bits(p_vec_bits, var.A, true, pb); + + pusch_config_pdu->pusch_uci.harq_ack_bit_length = var.oack; + pb = (uint8_t *)&pusch_config_pdu->pusch_uci.harq_payload; + memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.harq_payload)); + p_vec_bits += var.A; + copy_bytes_to_packed_bits(p_vec_bits, var.oack, false, pb); + + pusch_config_pdu->pusch_uci.csi_part1_bit_length = var.ocsi1; + pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_part1_payload; + memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_part1_payload)); + p_vec_bits += var.oack; + copy_bytes_to_packed_bits(p_vec_bits, var.ocsi1, false, pb); + + pusch_config_pdu->pusch_uci.csi_part2_bit_length = var.ocsi2; + pb = (uint8_t *)&pusch_config_pdu->pusch_uci.csi_part2_payload; + memset(pb, 0, sizeof(pusch_config_pdu->pusch_uci.csi_part2_payload)); + p_vec_bits += var.ocsi1; + copy_bytes_to_packed_bits(p_vec_bits, var.ocsi2, false, pb); +} + configmodule_interface_t *uniqCfg = NULL; int main(int argc, char *argv[]) { @@ -204,6 +306,8 @@ int main(int argc, char *argv[]) int print_perf = 0; cpuf = get_cpu_freq_GHz(); int msg3_flag = 0; + bool uci_on_pusch = false; + bool no_phase_pre_comp = false; int rv_index = 0; float roundStats; double effRate; @@ -227,6 +331,7 @@ int main(int argc, char *argv[]) UE_nr_rxtx_proc_t UE_proc; FILE *scg_fd=NULL; + FILE *uci_ulsch_matlab_vec = NULL; int file_offset = 0; double DS_TDL = .03; @@ -237,6 +342,8 @@ int main(int argc, char *argv[]) int max_ldpc_iterations = 5; int num_antennas_per_thread = 1; uint32_t log_format = 0; + int threequarter_fs = 0; + if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == 0) { exit_fun("[NR_ULSIM] Error, configuration module init failed\n"); } @@ -250,7 +357,8 @@ int main(int argc, char *argv[]) int c; bool setAffinity=false; char gNBthreads[128]="n"; - while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:jk:m:n:p:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:Y:")) != -1) { + while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:jk:m:n:o::p:q:r:s:t:u:v:w:y:z:A:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:Y:")) + != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ /* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */ if (c == 1 || c == '-' || c == 'O') @@ -351,13 +459,27 @@ int main(int argc, char *argv[]) case 'k': printf("Setting threequarter_fs_flag\n"); - openair0_cfg[0].threequarter_fs= 1; + threequarter_fs = 1; break; case 'm': Imcs = atoi(optarg); break; + case 'o': + uci_on_pusch = true; + // UCI on PUSCH is not implemented in OAI gNB yet. + // So this flag is needed to verify in MATLAB + no_phase_pre_comp = true; + if (optarg) { // -o with file input: use matlab vector + uci_ulsch_matlab_vec = fopen(optarg, "rb"); + if (uci_ulsch_matlab_vec == NULL) { + printf("Error opening %s\n", optarg); + exit(-1); + } + } + break; + case 'W': precod_nbr_layers = atoi(optarg); break; @@ -537,6 +659,7 @@ int main(int argc, char *argv[]) printf("-k 3/4 sampling\n"); printf("-m MCS value\n"); printf("-n Number of trials to simulate\n"); + printf("-o Enable UCI on PUSCH. Optionally accepts input file (without space). This feature is not yet available in gNB so only used to verify with MATLAB generated vector\n"); printf("-p Use extended prefix mode\n"); printf("-q MCS table\n"); printf("-r Number of allocated resource blocks for PUSCH\n"); @@ -576,7 +699,6 @@ int main(int argc, char *argv[]) get_softmodem_params()->phy_test = 1; get_softmodem_params()->do_ra = 0; - get_softmodem_params()->usim_test = 1; if (snr1set == 0) snr1 = snr0 + 10; @@ -585,7 +707,7 @@ int main(int argc, char *argv[]) uint32_t samples; get_samplerate_and_bw(mu, N_RB_DL, - openair0_cfg[0].threequarter_fs, + threequarter_fs, &sampling_frequency, &samples, &tx_bandwidth, @@ -605,14 +727,7 @@ int main(int argc, char *argv[]) else initNamedTpool(gNBthreads, &gNB->threadPool, true, "gNB-tpool"); - initNotifiedFIFO(&gNB->respDecode); - - initNotifiedFIFO(&gNB->respPuschSymb); - initNotifiedFIFO(&gNB->L1_tx_free); - initNotifiedFIFO(&gNB->L1_tx_filled); - initNotifiedFIFO(&gNB->L1_tx_out); - notifiedFIFO_elt_t *msgL1Tx = newNotifiedFIFO_elt(sizeof(processingData_L1tx_t), 0, &gNB->L1_tx_free, NULL); - processingData_L1tx_t *msgDataTx = (processingData_L1tx_t *)NotifiedFifoData(msgL1Tx); + processingData_L1tx_t *msgDataTx = malloc(sizeof(processingData_L1tx_t)); msgDataTx->slot = -1; gNB->msgDataTx = msgDataTx; //gNB_config = &gNB->gNB_config; @@ -657,6 +772,8 @@ int main(int argc, char *argv[]) .minRXTXTIME = 0, .do_CSIRS = 0, .do_SRS = 0, + .num_dlharq = 16, + .num_ulharq = 16, .force_256qam_off = false, .timer_config.sr_ProhibitTimer = 0, .timer_config.sr_TransMax = 64, @@ -697,20 +814,15 @@ int main(int argc, char *argv[]) RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); for (i = 0; i < RC.nb_nr_macrlc_inst; i++) RC.nb_nr_mac_CC[i] = 1; - mac_top_init_gNB(ngran_gNB, scc, NULL /* scd will be updated further below */, &conf, &rlc_config); + mac_top_init_gNB(ngran_gNB, scc, &conf, &rlc_config); nr_mac_config_scc(RC.nrmac[0], scc, &conf); - NR_ServingCellConfig_t *scd = calloc(1,sizeof(NR_ServingCellConfig_t)); - prepare_scd(scd); - /* removes unnecessary BWPs, if any */ - fix_scd(scd); - NR_UE_NR_Capability_t* UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t)); prepare_sim_uecap(UE_Capability_nr, scc, mu, N_RB_UL, 0, mcs_table); rnti_t rnti = 0x1234; int uid = 0; - NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, uid); - secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc); + NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, UE_Capability_nr, 0, 1, &conf, uid); + secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc, frame); NR_BCCH_BCH_Message_t *mib = get_new_MIB_NR(scc); @@ -779,8 +891,7 @@ int main(int argc, char *argv[]) init_nr_ue_transport(UE); //Configure UE - nr_l2_init_ue(1); - NR_UE_MAC_INST_t* UE_mac = get_mac_inst(0); + NR_UE_MAC_INST_t* UE_mac = nr_l2_init_ue(0); ue_init_config_request(UE_mac, get_slots_per_frame_from_scs(mu)); @@ -789,7 +900,8 @@ int main(int argc, char *argv[]) UE->if_inst->phy_config_request = nr_ue_phy_config_request; UE->if_inst->dl_indication = nr_ue_dl_indication; UE->if_inst->ul_indication = nr_ue_ul_indication; - + UE->no_phase_pre_comp = no_phase_pre_comp; + UE_mac->if_module = nr_ue_if_module_init(0); initFloatingCoresTpool(threadCnt, &nrUE_params.Tpool, false, "UE-tpool"); @@ -847,14 +959,12 @@ int main(int argc, char *argv[]) uint8_t length_dmrs = pusch_len1; uint16_t l_prime_mask = get_l_prime(nb_symb_sch, mapping_type, add_pos, length_dmrs, start_symbol, NR_MIB__dmrs_TypeA_Position_pos2); - uint16_t number_dmrs_symbols = get_dmrs_symbols_in_slot(l_prime_mask, nb_symb_sch, start_symbol); + int number_dmrs_symbols = count_bits64_with_mask(l_prime_mask, start_symbol, nb_symb_sch); uint8_t nb_re_dmrs = (dmrs_config_type == pusch_dmrs_type1) ? 6 : 4; uint32_t tbslbrm = 0; if (ilbrm) - tbslbrm = nr_compute_tbslbrm(mcs_table, - N_RB_UL, - precod_nbr_layers); + tbslbrm = nr_compute_tbslbrm(mcs_table, N_RB_UL, precod_nbr_layers); if ((UE->frame_parms.nb_antennas_tx==4)&&(precod_nbr_layers==4)) num_dmrs_cdm_grps_no_data = 2; @@ -929,6 +1039,9 @@ int main(int argc, char *argv[]) } unsigned int available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, number_dmrs_symbols, unav_res, mod_order, precod_nbr_layers); + uint8_t cw_buf[available_bits]; + memset(cw_buf, 0, available_bits); + UE->phy_sim_test_buf = calloc(1, (available_bits + 7) / 8); printf("[ULSIM]: VALUE OF G: %u, TBS: %u\n", available_bits, TBS); int frame_length_complex_samples = gNB->frame_parms.samples_per_subframe * NR_NUMBER_OF_SUBFRAMES_PER_FRAME; @@ -1029,6 +1142,9 @@ int main(int argc, char *argv[]) reset_meas(&gNB->rx_pusch_init_stats); reset_meas(&gNB->rx_pusch_symbol_processing_stats); reset_meas(&gNB->ulsch_decoding_stats); + reset_meas(&gNB->ts_deinterleave); + reset_meas(&gNB->ts_rate_unmatch); + reset_meas(&gNB->ts_ldpc_decode); reset_meas(&gNB->ulsch_channel_estimation_stats); reset_meas(&gNB->pusch_channel_estimation_antenna_processing_stats); reset_meas(&gNB->rx_srs_stats); @@ -1176,7 +1292,6 @@ int main(int argc, char *argv[]) UE_proc.gNB_id = 0; // prepare ULSCH/PUSCH reception - pushNotifiedFIFO(&gNB->L1_tx_free, msgL1Tx); // to unblock the process in the beginning nr_schedule_response(Sched_INFO); // --------- setting parameters for UE -------- @@ -1224,6 +1339,20 @@ int main(int argc, char *argv[]) // pusch_config_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_DFTS_OFDM; pusch_config_pdu->num_dmrs_cdm_grps_no_data = num_dmrs_cdm_grps_no_data; } + if (uci_on_pusch) { + const nfapi_nr_ue_pusch_uci_t pusch_uci = { + .alpha_scaling = 3, + .beta_offset_csi1 = 13, + .beta_offset_csi2 = 13, + .beta_offset_harq_ack = 11, + .harq_ack_bit_length = 3, + .harq_payload = 3, + //.csi_part1_bit_length = 4, + //.csi_part1_payload = 15 + }; + pusch_config_pdu->pusch_uci = pusch_uci; + prepare_ue_pusch_pdu_from_matlab_vector(uci_on_pusch, uci_ulsch_matlab_vec, pusch_config_pdu, cw_buf); + } if (do_SRS == 1) { fapi_nr_ul_config_request_pdu_t *ul_config1 = &ul_config.ul_config_list[1]; @@ -1459,7 +1588,7 @@ int main(int argc, char *argv[]) } if ((ulsch_gNB->last_iteration_cnt >= ulsch_gNB->max_ldpc_iterations) || ul_proc_error == 1) { - error_flag = 1; + error_flag = uci_on_pusch ? 0 : 1; n_errors[round]++; crc_status = 1; } else @@ -1476,15 +1605,29 @@ int main(int argc, char *argv[]) available_bits, (ptrsSymbPerSlot * ptrsRePerSymb * mod_order * precod_nbr_layers)); } - for (i = 0; i < available_bits; i++) { - if (((UE->ul_harq_processes[harq_pid].f[i] == 0) && (pusch_vars->llr[i] <= 0)) - || ((UE->ul_harq_processes[harq_pid].f[i] == 1) && (pusch_vars->llr[i] >= 0))) { - /*if(errors_scrambling == 0) - printf("\x1B[34m" "[frame %d][trial %d]\t1st bit in error in unscrambling = %d\n" "\x1B[0m", frame, trial, i);*/ - errors_scrambling[round]++; + if (uci_on_pusch) { + for (i = 0; i < available_bits; i++) { + const uint8_t current_bit = (UE->phy_sim_test_buf[i / 8] >> (i & 7)) & 1; + const uint8_t test_vector_bit = cw_buf[i] & 1; + if (current_bit != test_vector_bit) + errors_scrambling[round]++; + } + } else { + for (i = 0; i < available_bits; i++) { + const uint8_t current_bit = (UE->ul_harq_processes[harq_pid].f[i / 8] >> (i & 7)) & 1; + if (((current_bit == 0) && (pusch_vars->llr[i] <= 0)) || ((current_bit == 1) && (pusch_vars->llr[i] >= 0))) { + errors_scrambling[round]++; + } } } round++; + if (uci_on_pusch && uci_ulsch_matlab_vec && (errors_scrambling[round] == 0)) { + ret = 0; + printf("*************\n"); + printf("UCI on PUSCH test OK against MATLAB generated codeword\n"); + printf("*************\n"); + break; + } } // round if (n_trials == 1 && errors_scrambling[0] > 0) { @@ -1582,7 +1725,12 @@ int main(int argc, char *argv[]) if (print_perf==1) { - printf("gNB RX\n"); + printf("UE TX\n"); + for (int i = PHY_PROC_TX; i <= OFDM_MOD_STATS; i++) { + printStatIndent(&UE->phy_cpu_stats.cpu_time_stats[i], UE->phy_cpu_stats.cpu_time_stats[i].meas_name); + } + + printf("\ngNB RX\n"); printDistribution(&gNB->phy_proc_rx,table_rx, "Total PHY proc rx"); printStatIndent(&gNB->rx_pusch_stats, "RX PUSCH time"); printStatIndent2(&gNB->ulsch_channel_estimation_stats, "ULSCH channel estimation time"); @@ -1590,11 +1738,9 @@ int main(int argc, char *argv[]) printStatIndent2(&gNB->rx_pusch_init_stats, "RX PUSCH Initialization time"); printStatIndent2(&gNB->rx_pusch_symbol_processing_stats, "RX PUSCH Symbol Processing time"); printStatIndent(&gNB->ulsch_decoding_stats,"ULSCH total decoding time"); - - printf("\nUE TX\n"); - for (int i = PHY_PROC_TX; i <= OFDM_MOD_STATS; i++) { - printStatIndent(&UE->phy_cpu_stats.cpu_time_stats[i], UE->phy_cpu_stats.cpu_time_stats[i].meas_name); - } + printStatIndent2(&gNB->ts_deinterleave, "ULSCH segment deinterleaving time"); + printStatIndent2(&gNB->ts_rate_unmatch, "ULSCH segment rate recovery time"); + printStatIndent2(&gNB->ts_ldpc_decode, "ULSCH segments decoding time"); printStatIndent(&gNB->rx_srs_stats,"RX SRS time"); printStatIndent2(&gNB->generate_srs_stats,"Generate SRS sequence time"); printStatIndent2(&gNB->get_srs_signal_stats,"Get SRS signal time"); @@ -1654,5 +1800,10 @@ int main(int argc, char *argv[]) free(filename_csv); } + if (uci_ulsch_matlab_vec) + fclose(uci_ulsch_matlab_vec); + + free_and_zero(UE->phy_sim_test_buf); + return ret; } diff --git a/openair1/SIMULATION/TOOLS/sim.h b/openair1/SIMULATION/TOOLS/sim.h index 98b4fb26c6..359df00b55 100644 --- a/openair1/SIMULATION/TOOLS/sim.h +++ b/openair1/SIMULATION/TOOLS/sim.h @@ -77,6 +77,8 @@ typedef struct { struct complexd **a; ///interpolated (sample-spaced) channel impulse response. size(ch) = (n_tx * n_rx) * channel_length. ATTENTION: the dimensions of ch are the transposed ones of a. This is to allow the use of BLAS when applying the correlation matrices to the state. struct complexd **ch; + ///Same as above but single precision + struct complexf **ch_ps; ///Sampled frequency response (90 kHz resolution) struct complexd **chF; ///Maximum path delay in mus. diff --git a/openair1/SIMULATION/TOOLS/uci_on_pusch_decode.m b/openair1/SIMULATION/TOOLS/uci_on_pusch_decode.m new file mode 100644 index 0000000000..122b4912fb --- /dev/null +++ b/openair1/SIMULATION/TOOLS/uci_on_pusch_decode.m @@ -0,0 +1,79 @@ +% ULSIM command line +% ./nr_ulsim -m 27 -u 1 -R 51 -r 51 -s 300 -L 4 -o + +carrier = nrCarrierConfig; +carrier.NSizeGrid = 51; +carrier.NSlot = 8; +carrier.SubcarrierSpacing = 30; +carrier.CyclicPrefix = "normal"; + +pusch = nrPUSCHConfig; +pusch.PRBSet = 0:carrier.NSizeGrid-1; +pusch.SymbolAllocation = [0,12]; +pusch.MappingType = "B"; +pusch.NID = 0; +pusch.RNTI = 4660; +pusch.NumLayers = 1; +pusch.TransformPrecoding = false; +pusch.TransmissionScheme = "nonCodebook"; +pusch.NumAntennaPorts = 1; +pusch.TPMI = 0; +pusch.Modulation = "64QAM"; + +pusch.DMRS.DMRSConfigurationType = 1; +pusch.DMRS.DMRSTypeAPosition = 2; +pusch.DMRS.NumCDMGroupsWithoutData = 1; +pusch.DMRS.DMRSAdditionalPosition = 0; +pusch.DMRS.NIDNSCID = 0; +pusch.DMRS.NRSID = 0; +pusch.DMRS.NSCID = 0; +pusch.DMRS.GroupHopping = 0; +pusch.DMRS.SequenceHopping = 0; + +pusch.BetaOffsetACK = 20; +pusch.BetaOffsetCSI1 = 6.25; +pusch.BetaOffsetCSI2 = 1; +pusch.UCIScaling = 1; + +[puschIndices,puschIndicesInfo] = nrPUSCHIndices(carrier,pusch); + +dmrsLayerSymbols = nrPUSCHDMRS(carrier,pusch); +dmrsLayerIndices = nrPUSCHDMRSIndices(carrier,pusch); + +run("../../../cmake_targets/ran_build/build/txsig0.m"); +rxGrid = nrOFDMDemodulate(carrier,txs0); +[estChannelGrid,noiseEst] = nrChannelEstimate(carrier,rxGrid,dmrsLayerIndices,dmrsLayerSymbols); +[puschRx,puschHest] = nrExtractResources(puschIndices,rxGrid,estChannelGrid); +[puschEq,csi] = nrEqualizeMMSE(puschRx,puschHest,noiseEst); + +decodeULSCH = nrULSCHDecoder; +decodeULSCH.MultipleHARQProcesses = false; +decodeULSCH.CBGTransmission = false; +decodeULSCH.TargetCodeRate = 910 / 1024; +decodeULSCH.LDPCDecodingAlgorithm = 'Normalized min-sum'; +decodeULSCH.MaximumLDPCIterationCount = 6; +decodeULSCH.TransportBlockLength = 37896; + +oack = 3; +ocsi1 = 0; +ocsi2 = 0; +[ulschLLRs,rxSymbols] = nrPUSCHDecode(carrier,pusch,decodeULSCH.TargetCodeRate,... + decodeULSCH.TransportBlockLength,oack,ocsi1,ocsi2,puschEq,noiseEst); +rmInfo = nrULSCHInfo(pusch,decodeULSCH.TargetCodeRate,... + decodeULSCH.TransportBlockLength,oack,ocsi1,ocsi2); +[culsch,cack,ccsi1,ccsi2] = nrULSCHDemultiplex(pusch,decodeULSCH.TargetCodeRate,... + decodeULSCH.TransportBlockLength,oack,ocsi1,ocsi2,ulschLLRs); + +plot(rxSymbols,'*'); + +decodeULSCH.reset(); +rv = 0; % Redundancy version for decoding +[decodedBits,blkerr] = decodeULSCH(culsch,pusch.Modulation,pusch.NumLayers,rv); +% Display the decoded bits +disp('Block error:'); +disp(blkerr); + +ucibits = nrUCIDecode(cack,oack); +% Display the decoded UCI bits +disp('Decoded UCI bits:'); +disp(ucibits); diff --git a/openair1/SIMULATION/TOOLS/uci_on_pusch_encode.m b/openair1/SIMULATION/TOOLS/uci_on_pusch_encode.m new file mode 100644 index 0000000000..0b83d211d2 --- /dev/null +++ b/openair1/SIMULATION/TOOLS/uci_on_pusch_encode.m @@ -0,0 +1,85 @@ +% ulsim command for same pusch config +% ./nr_ulsim -m 27 -u 1 -R 51 -r 51 -s 300 -o uci_on_pusch_7.bin + +carrier = nrCarrierConfig; +carrier.NSizeGrid = 51; +carrier.NSlot = 8; +carrier.SubcarrierSpacing = 30; +carrier.CyclicPrefix = "normal"; + +pusch = nrPUSCHConfig; +pusch.PRBSet = 0:carrier.NSizeGrid-1; +pusch.SymbolAllocation = [0,12]; +pusch.MappingType = "B"; +pusch.NID = 0; +pusch.RNTI = 4660; +pusch.NumLayers = 1; +pusch.TransformPrecoding = false; +pusch.TransmissionScheme = "nonCodebook"; +pusch.NumAntennaPorts = 1; +pusch.TPMI = 0; +pusch.Modulation = "64QAM"; + +pusch.DMRS.DMRSConfigurationType = 1; +pusch.DMRS.DMRSTypeAPosition = 2; +pusch.DMRS.NumCDMGroupsWithoutData = 1; +pusch.DMRS.DMRSAdditionalPosition = 0; +pusch.DMRS.NIDNSCID = 0; +pusch.DMRS.NRSID = 0; +pusch.DMRS.NSCID = 0; +pusch.DMRS.GroupHopping = 0; +pusch.DMRS.SequenceHopping = 0; + +pusch.BetaOffsetACK = 20; +pusch.BetaOffsetCSI1 = 6.25; +pusch.BetaOffsetCSI2 = 1; +pusch.UCIScaling = 1; + +A = 37896; +rate = 910 / 1024; +rv = 0; +modulation = pusch.Modulation; +nlayers = pusch.NumLayers; % Number of layers for decoding + +oack = 7; +ocsi1 = 0; +ocsi2 = 0; +cbsInfo = nrULSCHInfo(pusch, rate, A, oack, ocsi1, ocsi2); % Get ULSCH information + +ack = randi([0 1],oack,1); +csi1 = randi([0 1],ocsi1,1); +csi2 = randi([0 1],ocsi2,1); +cack = nrUCIEncode(ack,cbsInfo.GACK,pusch.Modulation); +ccsi1 = []; +ccsi2 = []; + +tb_data = randi([0 1],A,1); +% Transport block CRC attachment +tbIn = nrCRCEncode(tb_data,cbsInfo.CRC); + +% Code block segmentation and CRC attachment +cbsIn = nrCodeBlockSegmentLDPC(tbIn,cbsInfo.BGN); + +% LDPC encoding +enc = nrLDPCEncode(cbsIn,cbsInfo.BGN); + +% Rate matching and code block concatenation +chIn = nrRateMatchLDPC(enc,cbsInfo.GULSCH,rv,modulation,nlayers); +culsch = chIn; + + +% Get the codeword and locations of each type (data and UCI) +[cw,indInfo] = nrULSCHMultiplex(pusch,rate,A,culsch,cack,ccsi1,ccsi2); +cw_scr = nrPUSCHScramble(cw,pusch.NID,pusch.RNTI); + +% Write to bin file +fid = fopen('uci_on_pusch_7.bin', 'wb'); +to_write = [A,oack,ocsi1,ocsi2,length(cw),length(cw_scr)]; +fwrite(fid, to_write, 'uint32'); % Write the data to the binary file +fwrite(fid, tb_data, "uint8"); +fwrite(fid, ack, "uint8"); +fwrite(fid, csi1, "uint8"); +fwrite(fid, csi2, "uint8"); +fwrite(fid, cw, "uint8"); +fwrite(fid, cw_scr, "uint8"); +fclose(fid); % Close the file after writing diff --git a/openair1/SIMULATION/tests/CMakeLists.txt b/openair1/SIMULATION/tests/CMakeLists.txt new file mode 100644 index 0000000000..566028234d --- /dev/null +++ b/openair1/SIMULATION/tests/CMakeLists.txt @@ -0,0 +1,400 @@ +# This defines a cmake file with timing thresholds to include (empty by default) +set(PHYSIM_CHECK_FILES "" CACHE STRING "CMake files ('\;' separated) with timing thresholds to include for timed physim tests") + +if(PHYSIM_CHECK_FILES) + foreach(PHYSIM_CHECK_FILE IN LISTS PHYSIM_CHECK_FILES) + # Construct full path relative to current source dir + set(CHECK_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${PHYSIM_CHECK_FILE}") + if(EXISTS "${CHECK_FILE_PATH}") + message(STATUS "Including file for physim timing threshold check: ${PHYSIM_CHECK_FILE}") + else() + message(FATAL_ERROR "Threshold file '${PHYSIM_CHECK_FILE}' not found at ${CHECK_FILE_PATH}") + endif() + endforeach() +endif() + +define_property(TEST PROPERTY TEST_DESCRIPTION + BRIEF_DOCS "A human-readable description of this test" + FULL_DOCS "A human-readable description of this test") + +define_property(TEST PROPERTY CHECK_COUNT + BRIEF_DOCS "helper property to enumerate checks in environment" + FULL_DOCS "the property counts the number of threshold checks, used to enumerate environment variables given to analyze-timing.sh") + +function(add_physim_test test_name test_description test_exec) + # catch all the arguments past the last expected arqument and store them in the options_list + if (NOT TARGET ${test_exec}) + message(FATAL_ERROR "test executable ${test_exec} is not an executable") + endif() + set(test_invocation $ ${ARGN}) + add_test( + NAME ${test_name} + COMMAND ${CMAKE_COMMAND} "-DTEST_CMD=${test_invocation}" "-DCHECK_SCRIPT=${CMAKE_CURRENT_SOURCE_DIR}/analyze-timing.sh" -P ${CMAKE_CURRENT_SOURCE_DIR}/RunTimedTest.cmake + ) + set_tests_properties(${test_name} PROPERTIES + LABELS "${test_exec}" + TEST_DESCRIPTION "${test_description}" + # pass test description also through environment variable: for cmake < 3.30, + # in JSON export, we cannot recover the description otherwise + # see also https://gitlab.kitware.com/cmake/cmake/-/issues/21490 + ENVIRONMENT "LD_LIBRARY_PATH=.;TEST_DESCRIPTION=${test_description}" + ) + set_tests_properties(${test_name} PROPERTIES CHECK_COUNT 0) +endfunction() + +function(check_threshold testname threshold condition) + # check that threshold and condition don't have a colon (;), because that + # would interfere with cmake's list management + string(FIND "${threshold}" ";" pos) + if (pos GREATER -1) + message(FATAL_ERROR "colon not allowed in threshold, but have \"${threshold}\"") + endif() + string(FIND "${condition}" ";" pos) + if (pos GREATER -1) + message(FATAL_ERROR "colon not allowed in condition, but have \"${condition}\"") + endif() + set(THRCOND "${threshold}\;${condition}") + + get_test_property(${testname} CHECK_COUNT count) + #message(STATUS "add check ${count} ${THRCOND}") + if (${count} GREATER 10) + message(FATAL_ERROR "only maximum of 10 checks per test allowed") + endif() + + # add a new environment variable CHECK_X with this threshold+condition, then + # increase test property regarding check count + set_property(TEST ${testname} APPEND PROPERTY ENVIRONMENT "CHECK_${count}=${THRCOND}") + MATH(EXPR count "${count}+1") + set_tests_properties(${testname} PROPERTIES CHECK_COUNT ${count}) +endfunction() + +function(check_threshold_range testname threshold) + cmake_parse_arguments(RANGE "" "LOWER;UPPER" "" ${ARGN}) + if (NOT RANGE_LOWER AND NOT RANGE_UPPER) + message(FATAL_ERROR "need at least one LOWER or one UPPER threshold") + endif() + if (RANGE_LOWER) + check_threshold(${testname} ${threshold} "> ${RANGE_LOWER}") + endif() + if (RANGE_UPPER) + check_threshold(${testname} ${threshold} "< ${RANGE_UPPER}") + endif() +endfunction() + +function(check_threshold_variance testname threshold) + cmake_parse_arguments(VARIANCE "" "AVG;ABS_VAR" "" ${ARGN}) + if (NOT VARIANCE_AVG AND NOT VARIANCE_ABS_VAR) + message(FATAL_ERROR "need both AVG and ABS_VAR") + endif() + MATH(EXPR upper "${VARIANCE_AVG}+${VARIANCE_ABS_VAR}") + MATH(EXPR lower "${VARIANCE_AVG}-${VARIANCE_ABS_VAR}") + check_threshold_range(${testname} ${threshold} LOWER ${lower} UPPER ${upper}) +endfunction() + + +#################################################################################### +###### dlsim unit test ###### +#################################################################################### + +add_physim_test(physim.4g.dlsim.basic.test1 "10 MHz, R2.FDD (MCS 5), EVA5, -1dB" dlsim -m=5 -g=F -s=-1 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -z=2 -Tperf=60) +add_physim_test(physim.4g.dlsim.basic.test2 "1.4 MHz, R4.FDD (MCS 4), EVA5, 0dB (70%)" dlsim -m=4 -g=F -s=0 -w=1.0 -f=.2 -n=1500 -B=6 -c=4 -z=2 -Tperf=60) +add_physim_test(physim.4g.dlsim.basic.test3 "10 MHz, R3.FDD (MCS 15), EVA5, 6.7dB (70%)" dlsim -m=15 -g=F -s=6.7 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -z=2 -Tperf=60) +add_physim_test(physim.4g.dlsim.basic.test4 "5 MHz, R3-1.FDD (MCS 15), EVA5, 6.7dB (70%)" dlsim -m=15 -g=F -s=6.7 -w=1.0 -f=.2 -n=1500 -B=25 -c=2 -z=2 -Tperf=60) +add_physim_test(physim.4g.dlsim.basic.test5 "10 MHz, R3-1.FDD (MCS 15), EVA5, 6.7dB (30%)" dlsim -m=15 -g=G -s=1.4 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -z=2 -Tperf=25) +add_physim_test(physim.4g.dlsim.basic.test6 "5 MHz, R3-1.FDD (MCS 15), ETU70, 1.4 dB (30%)" dlsim -m=15 -g=G -s=1.4 -w=1.0 -f=.2 -n=1500 -B=25 -c=2 -z=2 -Tperf=25) +add_physim_test(physim.4g.dlsim.basic.test7 "5 MHz, R6.FDD (MCS 25), EVA5, 17.4 dB (70%)" dlsim -m=25 -g=F -s=17.4 -w=1.0 -f=.2 -n=1500 -B=25 -c=3 -z=2 -Tperf=60) +add_physim_test(physim.4g.dlsim.basic.test8 "5 MHz, R6-1.FDD (MCS 24,18 PRB), EVA5, 17.5dB (70%)" dlsim -m=25 -g=F -s=17.5 -w=1.0 -f=.2 -n=1500 -B=25 -c=3 -z=2 -r=1022 -Tperf=60) +add_physim_test(physim.4g.dlsim.basic.test9 "10 MHz, R7.FDD (MCS 25), EVA5, 17.7dB (70%)" dlsim -m=26 -g=F -s=17.7 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -z=2 -Tperf=60) +add_physim_test(physim.4g.dlsim.100rb.tm2.test1 "20 MHz, R.9 FDD (MCS 26), EVA5, 17.6dB (70%)" dlsim -m=26 -g=F -s=17.6 -w=1.0 -f=.2 -n=1500 -B=100 -c=2 -z=2 -Tperf=60) +add_physim_test(physim.4g.dlsim.100rb.tm2.test2 "20 MHz, R.9-2 FDD (MCS 26, 17PRB), EVA5, 17.3dB (70%)" dlsim -m=26 -g=F -s=17.3 -w=1.0 -f=.2 -n=1500 -B=100 -c=2 -z=2 -r=1600 -Tperf=60) +add_physim_test(physim.4g.dlsim.100rb.tm2.test3 "20 MHz, R.9-1 FDD (MCS 26, 83 PRB), EVA5, 16.6dB (70%)" dlsim -m=26 -g=F -s=16.6 -w=1.0 -f=.2 -n=1500 -B=100 -c=2 -z=2 -r=1899 -Tperf=60) +add_physim_test(physim.4g.dlsim.100rb.tm2.test4 "10 MHz, R.11 FDD (MCS 14), EVA5, 6.8 dB (70%)" dlsim -m=14 -g=F -s=6.8 -w=1.0 -f=.2 -n=1500 -B=50 -c=2 -x=2 -y=2 -z=2 -Tperf=60) +add_physim_test(physim.4g.dlsim.100rb.tm2.test5 "5 MHz, R.11-2 FDD (MCS 13), EVA5, 5.9 dB (70%)" dlsim -m=13 -g=F -s=5.9 -w=1.0 -f=.2 -n=1500 -B=25 -c=3 -x=2 -y=2 -z=2 -Tperf=60) + +#################################################################################### +###### ulsim unit test ###### +#################################################################################### + +add_physim_test(physim.4g.ulsim.test1 "5 MHz, FDD (MCS 5), AWGN, 6dB" ulsim -BnbRBs=25 -mcs=5 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=6 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) +add_physim_test(physim.4g.ulsim.test2 "5 MHz, FDD (MCS 16), AWGN , 12dB (70%)" ulsim -BnbRBs=25 -mcs=16 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=12 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) +add_physim_test(physim.4g.ulsim.test3 "10 MHz, R3.FDD (MCS 5), AWGN, 6dB (70%)" ulsim -BnbRBs=50 -mcs=5 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=6 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) +add_physim_test(physim.4g.ulsim.test4 "10 MHz, R3-1.FDD (MCS 16), AWGN, 12dB (70%)" ulsim -BnbRBs=50 -mcs=16 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=12 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) +add_physim_test(physim.4g.ulsim.test5 "20 MHz, FDD (MCS 5), AWGN, 6dB (70%)" ulsim -BnbRBs=100 -mcs=5 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=6 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) +add_physim_test(physim.4g.ulsim.test6 "20 MHz, FDD (MCS 16), AWGN, 12 dB (70%)" ulsim -BnbRBs=100 -mcs=16 -yN_rx=1 -gchannel=N -xTransmission=1 -snr=12 -wsnrInterrupt=1.0 -e_snr_step=.1 -P -nb_frame=1500 -Tperf=70) + +#################################################################################### +###### ldpctest unit test ###### +#################################################################################### + +add_physim_test(physim.5g.ldpctest.test1 "block length = 3872, BG1" ldpctest -l3872 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test2 "block length = 4224, BG1" ldpctest -l4224 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test3 "block length = 4576, BG1" ldpctest -l4576 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test4 "block length = 4928, BG1" ldpctest -l4928 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test5 "block length = 5280, BG1" ldpctest -l5280 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test6 "block length = 5632, BG1" ldpctest -l5632 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test7 "block length = 6336, BG1" ldpctest -l6336 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test8 "block length = 7040, BG1" ldpctest -l7040 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test9 "block length = 7744, BG1" ldpctest -l7744 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test10 "block length = 8448, BG1" ldpctest -l8448 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test11 "block length = 1, BG2" ldpctest -l1 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test12 "block length = 100, BG2" ldpctest -l100 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test13 "block length = 193, BG2" ldpctest -l193 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test14 "block length = 500, BG2" ldpctest -l500 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test15 "block length = 561, BG2" ldpctest -l561 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test16 "block length = 600, BG2" ldpctest -l600 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test17 "block length = 641, BG2" ldpctest -l641 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test18 "block length = 2000, BG1" ldpctest -l2000 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test19 "block length = 3000, BG1" ldpctest -l3000 -s10 -n300) +add_physim_test(physim.5g.ldpctest.test20 "block length = 3840, BG1" ldpctest -l3840 -s10 -n300) + +#################################################################################### +###### polartest unit test ###### +#################################################################################### + +add_physim_test(physim.5g.polartest.test1 "PBCH polar test" polartest -q -s-10 -f0) +add_physim_test(physim.5g.polartest.test2 "DCI polar test" polartest -q -s-10 -f0 -m1) +add_physim_test(physim.5g.polartest.test3 "UCI polar test,6-bit CRC" polartest -q -s-2 -f2 -m2 -k12) +add_physim_test(physim.5g.polartest.test4 "UCI polar test,11-bit CRC" polartest -q -s-2 -f2 -m2 -k20) + +#################################################################################### +###### nr_pbchsim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_pbchsim.106rb.test1 "PBCH-only, 106 PRB, NID 2" nr_pbchsim -s-11 -S-8 -n30 -R106 -N2) +add_physim_test(physim.5g.nr_pbchsim.106rb.test2 "PBCH and synchronization, 106PBR" nr_pbchsim -s-11 -S-8 -n30 -o8000 -I -R106) +add_physim_test(physim.5g.nr_pbchsim.106rb.test3 "PBCH and synchronization, 106PBR, SSB SC OFFSET 6" nr_pbchsim -s-11 -S-8 -n30 -R106 -c6) +add_physim_test(physim.5g.nr_pbchsim.217rb.test1 "PBCH-only, 217 PRB" nr_pbchsim -s-10 -S-8 -n30 -R217) +add_physim_test(physim.5g.nr_pbchsim.217rb.test2 "PBCH and synchronization, 217 RPB" nr_pbchsim -s-10 -S-8 -n30 -o8000 -I -R217) +add_physim_test(physim.5g.nr_pbchsim.273rb.test1 "PBCH-only, 273 PRB" nr_pbchsim -s-10 -S-8 -n30 -R273) +add_physim_test(physim.5g.nr_pbchsim.273rb.test2 "PBCH and synchronization, 273 PRB" nr_pbchsim -s-10 -S-8 -n30 -o8000 -I -R273) +add_physim_test(physim.5g.nr_pbchsim.otherSCS.test1 "PBCH-only, 15Khz, 5Mhz" nr_pbchsim -s-10 -S-8 -n30 -m0 -R25) +add_physim_test(physim.5g.nr_pbchsim.otherSCS.test2 "PBCH-only, 120Khz, 50Mhz" nr_pbchsim -s-10 -S-8 -n30 -m3 -R32) + +#################################################################################### +###### nr_dlsim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_dlsim.basic.test1 "106 PRB" nr_dlsim -P -n300 -R106 -b106 -s5) +add_physim_test(physim.5g.nr_dlsim.basic.test2 "217 PRB" nr_dlsim -P -n300 -R217 -b217 -s5) +add_physim_test(physim.5g.nr_dlsim.basic.test3 "273 PRB" nr_dlsim -P -n300 -R273 -b273 -s5) +add_physim_test(physim.5g.nr_dlsim.basic.test4 "HARQ test 25% TP 4 rounds" nr_dlsim -P -n300 -s1 -S2 -t25) +add_physim_test(physim.5g.nr_dlsim.basic.test5 "HARQ test 33% TP 3 rounds" nr_dlsim -P -n300 -s1 -S2 -t33) +add_physim_test(physim.5g.nr_dlsim.basic.test6 "HARQ test 50% TP 2 rounds" nr_dlsim -P -n300 -s5 -S7 -t50) +add_physim_test(physim.5g.nr_dlsim.basic.test7 "25 PRBs, 15 kHz SCS" nr_dlsim -P -n300 -m0 -e0 -R25 -b25 -i 2 1 0) +add_physim_test(physim.5g.nr_dlsim.basic.test8 "32 PRBs, 120 kHz SCS" nr_dlsim -P -n300 -s5 -m3 -R32 -b32) +add_physim_test(physim.5g.nr_dlsim.offset.test1 "106 PRB 25 PDSCH-Offset" nr_dlsim -P -n300 -R106 -a25 -s5) +add_physim_test(physim.5g.nr_dlsim.offset.test2 "106 PRB 51 PDSCH-Offset" nr_dlsim -P -n300 -R106 -a51 -s5) +add_physim_test(physim.5g.nr_dlsim.offset.test3 "217 PRB 100 PDSCH-PRBs" nr_dlsim -P -n300 -R217 -b100 -s5) +add_physim_test(physim.5g.nr_dlsim.offset.test4 "217 PRB 80 PDSCH-Offset" nr_dlsim -P -n300 -R217 -a80 -s5) +add_physim_test(physim.5g.nr_dlsim.offset.test5 "217 PRB 100 PDSCH-PRBs 110 PDSCH-Offset" nr_dlsim -P -n300 -R217 -a110 -s5 -b100) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test1 "106 PRBs 50 PDSCH-PRBs MCS Index 27" nr_dlsim -P -n300 -e27 -s30) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test2 "106 PRBs 50 PDSCH-PRBs MCS Index 16" nr_dlsim -P -n300 -e16 -s11 -S13) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test3 "106 MCS-TABLE 256 QAM MCS Index 26" nr_dlsim -P -n300 -q1 -e26 -s30) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test4 "106 MCS-TABLE 256 QAM Fading Channel" nr_dlsim -P -n300 -q1 -e24 -s30 -gA) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test5 "MCS 0, low SNR performance" nr_dlsim -P -n300 -e0 -t95 -S-1.0 -i 2 1 0) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test6 "4x4 MIMO, 1 Layer" nr_dlsim -P -n30 -s20 -U 3 0 0 2 -gA -x1 -y4 -z4) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test7 "4x4 MIMO, 2 Layers" nr_dlsim -P -n30 -s20 -U 3 0 0 2 -gA -x2 -y4 -z4) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test8 "4x4 MIMO, 2 Layers 256 QAM" nr_dlsim -P -n30 -s25 -e22 -q1 -U 3 0 0 2 -gA -x2 -y4 -z4) +add_physim_test(physim.5g.nr_dlsim.mcs.mimo.test9 "4x4 MIMO, 4 Layers" nr_dlsim -P -n30 -s20 -U 3 0 0 2 -x4 -y4 -z4) +add_physim_test(physim.5g.nr_dlsim.dmrs.ptrs.test1 "3 PTRS, 8 Interpolated Symbols" nr_dlsim -P -n300 -s5 -T 2 2 2) +add_physim_test(physim.5g.nr_dlsim.dmrs.ptrs.test2 "6 PTRS, 5 Interpolated Symbols" nr_dlsim -P -n300 -s5 -T 2 1 2) +add_physim_test(physim.5g.nr_dlsim.dmrs.ptrs.test3 "11 PTRS, 0 Interpolated Symbols" nr_dlsim -P -n300 -s5 -T 2 0 4) +add_physim_test(physim.5g.nr_dlsim.dmrs.ptrs.test4 "Mapping type A, 2 DMRS Symbols" nr_dlsim -P -n300 -s5 -S7 -U 2 0 1) +add_physim_test(physim.5g.nr_dlsim.dmrs.ptrs.test5 "Mapping type A, 3 DMRS Symbols" nr_dlsim -P -n300 -s5 -S7 -U 2 0 2) +add_physim_test(physim.5g.nr_dlsim.dmrs.ptrs.test6 "Mapping type B, 4 DMRS Symbols" nr_dlsim -P -n300 -s5 -S7 -U 2 1 3) + +#################################################################################### +###### nr_dlschsim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_dlschsim.test1 "106 PRBs" nr_dlschsim -R 106 -m9 -s13 -n300) +add_physim_test(physim.5g.nr_dlschsim.test2 "217 PRBs" nr_dlschsim -R 217 -m15 -s15 -n300) +add_physim_test(physim.5g.nr_dlschsim.test3 "273 PRBs" nr_dlschsim -R 273 -m19 -s20 -n300) + +#################################################################################### +###### smallblocktest unit test ###### +#################################################################################### + +add_physim_test(physim.5g.smallblocktest.test1 "3 bits" smallblocktest -l 3 -s -4 -d 1 -i 10000) +add_physim_test(physim.5g.smallblocktest.test2 "6 bits" smallblocktest -l 6 -s -4 -d 1 -i 10000) +add_physim_test(physim.5g.smallblocktest.test3 "7 bits" smallblocktest -l 7 -s -4 -d 1 -i 10000) +add_physim_test(physim.5g.smallblocktest.test4 "11 bits" smallblocktest -l 11 -s -4 -d 1 -i 10000) + +#################################################################################### +###### nr_ulschsim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_ulschsim.test1 "106 PRBs" nr_ulschsim -R 106 -m9 -s13 -n300) +add_physim_test(physim.5g.nr_ulschsim.test2 "217 PRBs" nr_ulschsim -R 217 -m15 -s15 -n300) +add_physim_test(physim.5g.nr_ulschsim.test3 "273 PRBs" nr_ulschsim -R 273 -m19 -s20 -n300) +add_physim_test(physim.5g.nr_ulschsim.test4 "106 PRBs 4-layer MIMO" nr_ulschsim -R 106 -m9 -s13 -n300 -y4 -z4 -W4) + +#################################################################################### +###### nr_pucchsim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_pucchsim.test1 "Format 0 1-bit ACK miss 106 PRB" nr_pucchsim -R 106 -i 1 -P 0 -b 1 -s-2 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test2 "Format 0 2-bit ACK miss 106 PRB" nr_pucchsim -R 106 -i 1 -P 0 -b 2 -s-2 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test3 "Format 0 2-bit ACK miss, 1-bit SR 106 PRB" nr_pucchsim -R 106 -i 1 -P 0 -b 2 -s-2 -c -n3000) +add_physim_test(physim.5g.nr_pucchsim.test4 "Format 2 3-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 3 -s0 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test5 "Format 2 4-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 4 -s0 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test6 "Format 2 5-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 5 -s1 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test7 "Format 2 6-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 6 -s2 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test8 "Format 2 7-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 7 -s3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test9 "Format 2 8-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 8 -s4 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test10 "Format 2 9-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 9 -s5 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test11 "Format 2 10-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 10 -s6 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test12 "Format 2 11-bit 2/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -b 11 -s6 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test13 "Format 2 12-bit 4/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -q4 -b 12 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test14 "Format 2 19-bit 4/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -q4 -b 19 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test15 "Format 2 12-bit 8/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -q8 -b 12 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test16 "Format 2 19-bit 8/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -q8 -b 19 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test17 "Format 2 32-bit 8/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -q8 -b 32 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test18 "Format 2 32-bit 16/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -q16 -b 32 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test19 "Format 2 64-bit 16/106 PRB" nr_pucchsim -R 106 -i 1 -P 2 -q16 -b 64 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test20 "Format 0 1-bit Ack miss 273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 0 -b 1 -s-2 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test21 "Format 0 2-bit Ack miss 273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 0 -b 2 -s-2 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test22 "Format 0 2-bit Ack miss+SR 273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 0 -b 2 -s-2 -c -n3000) +add_physim_test(physim.5g.nr_pucchsim.test23 "Format 2 4-bit 2/273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 2 -b 4 -s-8 -S0 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test24 "Format 2 7-bit 2/273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 2 -b 7 -s3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test25 "Format 2 11-bit 2/273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 2 -b 11 -s6 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test26 "Format 2 12-bit 8/273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 2 -q8 -b 12 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test27 "Format 2 19-bit 8/273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 2 -q8 -b 19 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test28 "Format 2 64-bit 16/273 PRB" nr_pucchsim -R 273 -z8 -i 1 -P 2 -q16 -b 64 -s-3 -n3000) +add_physim_test(physim.5g.nr_pucchsim.test29 "Format 2 64-bit 16/273 PRB Delay 2us" nr_pucchsim -R 273 -z8 -i 1 -P 2 -q16 -b 64 -s0 -S7 -d 2 -n3000) + +#################################################################################### +###### nr_ulsim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_ulsim.misc.test1 "MCS 9 106 PRBs" nr_ulsim -P -n300 -m9 -r106 -s5) +add_physim_test(physim.5g.nr_ulsim.misc.test2 "MCS 16 50 PRBs" nr_ulsim -P -n300 -m16 -s10) +add_physim_test(physim.5g.nr_ulsim.misc.test3 "MCS 28 50 PRBs" nr_ulsim -P -n300 -m28 -s20) +add_physim_test(physim.5g.nr_ulsim.misc.test4 "MCS 27 50 PRBs 256QAM" nr_ulsim -P -n300 -m27 -s25 -q1) +add_physim_test(physim.5g.nr_ulsim.misc.test5 "MCS 9 217 PRBs" nr_ulsim -P -n300 -m9 -R217 -r217 -s5) +add_physim_test(physim.5g.nr_ulsim.misc.test6 "MCS 9 273 PRBs" nr_ulsim -P -n300 -m9 -R273 -r273 -s5) +add_physim_test(physim.5g.nr_ulsim.misc.test7 "PUSCH Type A, 2 DMRS Symbols" nr_ulsim -P -n300 -s5 -U 0,1,1,1) +add_physim_test(physim.5g.nr_ulsim.misc.test8 "PUSCH Type A, 3 DMRS, 4 PTRS, 5 Interpolated Symbols" nr_ulsim -P -n300 -s5 -T 1,2 -U 0,2,1,1) +add_physim_test(physim.5g.nr_ulsim.misc.test9 "PUSCH Type B, 3 DMRS, 2 PTRS, 7 Interpolated Symbols" nr_ulsim -P -n300 -s5 -T 2,2 -U 1,2,1,1) +add_physim_test(physim.5g.nr_ulsim.misc.test10 "PUSCH Type B, 3 DMRS, 2 PTRS, 3 Interpolated Symbols" nr_ulsim -P -n300 -s5 -a4 -b8 -T 1,2 -U 1,3,1,1) +add_physim_test(physim.5g.nr_ulsim.misc.test11 "25 PRBs, 15 kHz SCS" nr_ulsim -P -n300 -u0 -m0 -R25 -r25 -i 1,0) +add_physim_test(physim.5g.nr_ulsim.misc.test12 "32 PRBs, 120 kHz SCS" nr_ulsim -P -n300 -s5 -r32 -R32 -u3) +add_physim_test(physim.5g.nr_ulsim.misc.test13 "MCS 0, low SNR performance" nr_ulsim -P -n300 -m0 -S -0.6 -i 1,0) +add_physim_test(physim.5g.nr_ulsim.misc.test14 "MCS 28, 106 PRBs, Time shift 8" nr_ulsim -P -n300 -m28 -R106 -r106 -t90 -s24 -S24 -d 8) +add_physim_test(physim.5g.nr_ulsim.misc.test15 "SRS, SNR 40 dB" nr_ulsim -P -n300 -s40 -E 1) +add_physim_test(physim.5g.nr_ulsim.sc-fdma.test1 "SC-FDMA, 50 PRBs" nr_ulsim -P -n300 -s5 -Z) +add_physim_test(physim.5g.nr_ulsim.sc-fdma.test2 "SC-FDMA, 75 PRBs" nr_ulsim -P -n300 -s5 -Z -r75) +add_physim_test(physim.5g.nr_ulsim.sc-fdma.test3 "SC-FDMA, 216 PRBs" nr_ulsim -P -n150 -s5 -Z -r216 -R217) +add_physim_test(physim.5g.nr_ulsim.sc-fdma.test4 "SC-FDMA, 273 PRBs" nr_ulsim -P -n150 -s5 -Z -r270 -R273) +add_physim_test(physim.5g.nr_ulsim.sc-fdma.test5 "SC-FDMA, 3 DMRS" nr_ulsim -P -n300 -s5 -Z -U 0,2,1,2) +add_physim_test(physim.5g.nr_ulsim.mimo.test1 "MCS 19 50 PRBs 2 RX_Antenna" nr_ulsim -P -n300 -m19 -s10 -S15 -z2) +add_physim_test(physim.5g.nr_ulsim.mimo.test2 "MCS 9 106 PRBs MIMO 2 layers" nr_ulsim -P -n300 -m9 -r106 -s8 -W2 -y2 -z2) +add_physim_test(physim.5g.nr_ulsim.mimo.test3 "MCS 10 106 PRBs MIMO 2 layers" nr_ulsim -P -n300 -m10 -r106 -s12 -W2 -y2 -z2) +add_physim_test(physim.5g.nr_ulsim.mimo.test4 "MCS 19 106 PRBs MIMO 2 layers" nr_ulsim -P -n300 -m19 -r106 -s22 -W2 -y2 -z2) +add_physim_test(physim.5g.nr_ulsim.mimo.test5 "MCS 9 106 PRBs MIMO 4 layers" nr_ulsim -P -n300 -m9 -r106 -s10 -W4 -y4 -z4) +add_physim_test(physim.5g.nr_ulsim.3gpp.test1 "3GPP G-FR1-A5-13, PUSCH Type A, 40 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 0,1,1,2 -z2 -s12.4 -S12.4) +add_physim_test(physim.5g.nr_ulsim.3gpp.test2 "3GPP G-FR1-A5-13, PUSCH Type A, 40 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 0,1,1,2 -z4 -s8.5 -S8.5) +add_physim_test(physim.5g.nr_ulsim.3gpp.test3 "3GPP G-FR1-A5-13, PUSCH Type A, 40 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 0,1,1,2 -z8 -s5.4 -S5.4) +add_physim_test(physim.5g.nr_ulsim.3gpp.test4 "3GPP G-FR1-A5-8, PUSCH Type B, 5 MHz BW, 15 kHz SCS, 2 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R25 -r25 -U 1,1,1,2 -z2 -s12.5 -S12.5) +add_physim_test(physim.5g.nr_ulsim.3gpp.test5 "3GPP G-FR1-A5-8, PUSCH Type B, 5 MHz BW, 15 kHz SCS, 4 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R25 -r25 -U 1,1,1,2 -z4 -s8.9 -S8.9) +add_physim_test(physim.5g.nr_ulsim.3gpp.test6 "3GPP G-FR1-A5-8, PUSCH Type B, 5 MHz BW, 15 kHz SCS, 8 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R25 -r25 -U 1,1,1,2 -z8 -s5.7 -S5.7) +add_physim_test(physim.5g.nr_ulsim.3gpp.test7 "3GPP G-FR1-A5-9, PUSCH Type B, 10 MHz BW, 15 kHz SCS, 2 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R52 -r52 -U 1,1,1,2 -z2 -s12.6 -S12.6) +add_physim_test(physim.5g.nr_ulsim.3gpp.test8 "3GPP G-FR1-A5-9, PUSCH Type B, 10 MHz BW, 15 kHz SCS, 4 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R52 -r52 -U 1,1,1,2 -z4 -s8.9 -S8.9) +add_physim_test(physim.5g.nr_ulsim.3gpp.test9 "3GPP G-FR1-A5-9, PUSCH Type B, 10 MHz BW, 15 kHz SCS, 8 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R52 -r52 -U 1,1,1,2 -z8 -s5.8 -S5.8) +add_physim_test(physim.5g.nr_ulsim.3gpp.test10 "3GPP G-FR1-A5-10, PUSCH Type B, 20 MHz BW, 15 kHz SCS, 2 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R106 -r106 -U 1,1,1,2 -z2 -s12.3 -S12.3) +add_physim_test(physim.5g.nr_ulsim.3gpp.test11 "3GPP G-FR1-A5-10, PUSCH Type B, 20 MHz BW, 15 kHz SCS, 4 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R106 -r106 -U 1,1,1,2 -z4 -s8.8 -S8.8) +add_physim_test(physim.5g.nr_ulsim.3gpp.test12 "3GPP G-FR1-A5-10, PUSCH Type B, 20 MHz BW, 15 kHz SCS, 8 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 0 -m20 -R106 -r106 -U 1,1,1,2 -z8 -s5.7 -S5.7) +add_physim_test(physim.5g.nr_ulsim.3gpp.test13 "3GPP G-FR1-A5-11, PUSCH Type B, 10 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R24 -r24 -U 1,1,1,2 -z2 -s12.5 -S12.5) +add_physim_test(physim.5g.nr_ulsim.3gpp.test14 "3GPP G-FR1-A5-11, PUSCH Type B, 10 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R24 -r24 -U 1,1,1,2 -z4 -s8.6 -S8.6) +add_physim_test(physim.5g.nr_ulsim.3gpp.test15 "3GPP G-FR1-A5-11, PUSCH Type B, 10 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R24 -r24 -U 1,1,1,2 -z8 -s5.6 -S5.6) +add_physim_test(physim.5g.nr_ulsim.3gpp.test16 "3GPP G-FR1-A5-12, PUSCH Type B, 20 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R51 -r51 -U 1,1,1,2 -z2 -s12.5 -S12.5) +add_physim_test(physim.5g.nr_ulsim.3gpp.test17 "3GPP G-FR1-A5-12, PUSCH Type B, 20 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R51 -r51 -U 1,1,1,2 -z4 -s8.6 -S8.6) +add_physim_test(physim.5g.nr_ulsim.3gpp.test18 "3GPP G-FR1-A5-12, PUSCH Type B, 20 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R51 -r51 -U 1,1,1,2 -z8 -s5.6 -S5.6) +add_physim_test(physim.5g.nr_ulsim.3gpp.test19 "3GPP G-FR1-A5-13, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 1,1,1,2 -z2 -s12.5 -S12.5) +add_physim_test(physim.5g.nr_ulsim.3gpp.test20 "3GPP G-FR1-A5-13, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 1,1,1,2 -z4 -s8.7 -S8.7) +add_physim_test(physim.5g.nr_ulsim.3gpp.test21 "3GPP G-FR1-A5-13, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R106 -r106 -U 1,1,1,2 -z8 -s5.5 -S5.5) +add_physim_test(physim.5g.nr_ulsim.3gpp.test22 "3GPP G-FR1-A5-14, PUSCH Type B, 100 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R273 -r273 -U 1,1,1,2 -z2 -s13.1 -S13.1) +add_physim_test(physim.5g.nr_ulsim.3gpp.test23 "3GPP G-FR1-A5-14, PUSCH Type B, 100 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I7 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R273 -r273 -U 1,1,1,2 -z4 -s9.2 -S9.2) +add_physim_test(physim.5g.nr_ulsim.3gpp.test24 "3GPP G-FR1-A5-14, PUSCH Type B, 100 MHz BW, 30 kHz SCS, 8 RX Antennas Requirements Test" nr_ulsim -P -n300 -b14 -I8 -i 0,1 -g A,l,10 -t70 -u 1 -m20 -R273 -r273 -U 1,1,1,2 -z8 -s5.9 -S5.9) +add_physim_test(physim.5g.nr_ulsim.3gpp.test25 "3GPP G-FR1-A3-27, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test, 2 layers" nr_ulsim -P -n300 -b14 -I15 -i 0,1 -g B,l -t70 -u 1 -m2 -R106 -r106 -U 1,1,1,2 -W2 -y2 -z2 -s1.7 -S1.7) +add_physim_test(physim.5g.nr_ulsim.3gpp.test26 "3GPP G-FR1-A3-27, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test, 2 layers" nr_ulsim -P -n300 -b14 -I15 -i 0,1 -g B,l -t70 -u 1 -m2 -R106 -r106 -U 1,1,1,2 -W2 -y2 -z4 -s-2.1 -S-2.1) +add_physim_test(physim.5g.nr_ulsim.3gpp.test27 "3GPP G-FR1-A4-27, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 2 RX Antennas Requirements Test, 2 layers" nr_ulsim -P -n300 -b14 -I15 -i 0,1 -g C,l -t70 -u 1 -m16 -R106 -r106 -U 1,1,1,2 -W2 -y2 -z2 -s18.7 -S18.7) +add_physim_test(physim.5g.nr_ulsim.3gpp.test28 "3GPP G-FR1-A4-27, PUSCH Type B, 40 MHz BW, 30 kHz SCS, 4 RX Antennas Requirements Test, 2 layers" nr_ulsim -P -n300 -b14 -I15 -i 0,1 -g C,l -t70 -u 1 -m16 -R106 -r106 -U 1,1,1,2 -W2 -y2 -z4 -s11.2 -S11.2) + +#################################################################################### +###### nr_prachsim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_prachsim.test1 "30kHz SCS, 106 PRBs, Prach format A2" nr_prachsim -a -s -30 -n 300 -p 63 -R 106) +add_physim_test(physim.5g.nr_prachsim.test2 "30kHz SCS, 217 PRBs, Prach format A2" nr_prachsim -a -s -30 -n 300 -p 63 -R 217) +add_physim_test(physim.5g.nr_prachsim.test3 "30kHz SCS, 273 PRBs, Prach format A2" nr_prachsim -a -s -30 -n 300 -p 63 -R 273) +add_physim_test(physim.5g.nr_prachsim.test4 "30kHz SCS, 106 PRBs, Prach format 0" nr_prachsim -a -s -30 -n 300 -p 63 -R 106 -c 4) +add_physim_test(physim.5g.nr_prachsim.test5 "120kHz SCS, 32 PRBs, Prach format A2" nr_prachsim -a -s -30 -n 300 -p 32 -R 32 -m 3 -c52) +add_physim_test(physim.5g.nr_prachsim.test6 "120kHz SCS, 66 PRBs, Prach format A2" nr_prachsim -a -s -30 -n 300 -p 32 -R 66 -m 3 -c52) +add_physim_test(physim.5g.nr_prachsim.test7 "120kHz SCS, 66 PRBs, High Speed Enabled" nr_prachsim -a -s -30 -n 300 -R 66 -m 3 -c52 -H) +add_physim_test(physim.5g.nr_prachsim.test8 "15kHz SCS, 25 PRBs" nr_prachsim -a -s -30 -n 300 -p 99 -R 25 -m 0) + +#################################################################################### +###### nr_psbchsim unit test ###### +#################################################################################### + +add_physim_test(physim.5g.nr_psbchsim.test1 "SLSS Search" nr_psbchsim -I) +add_physim_test(physim.5g.nr_psbchsim.test2 "PSBCH TxRx" nr_psbchsim -n 30) + +#################################################################################### +###### offload-specific tests ###### +#################################################################################### + +if (ENABLE_LDPC_AAL) + +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.1 "CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e5 -b106 -R106 -X 8,9,10,11,12 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.1 "T2 LDPC offload: SNR = 30, MCS = 5, 106 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e5 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.2 "CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e15 -b106 -R106 -X 8,9,10,11,12 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.2 "T2 LDPC offload: SNR = 30, MCS = 15, 106 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e15 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.3 "CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e25 -b106 -R106 -X 8,9,10,11,12 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.3 "T2 LDPC offload: SNR = 30, MCS = 25, 106 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e25 -b106 -R106 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.4 "CPU: SNR = 30, MCS = 5, 273 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e5 -b273 -R273 -X 8,9,10,11,12 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.4 "T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.5 "CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e15 -b273 -R273 -X 8,9,10,11,12 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.5 "T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.6 "CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e25 -b273 -R273 -X 8,9,10,11,12 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.6 "T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 1 layer" nr_dlsim -n1000 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.7 "CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers" nr_dlsim -n1000 -s30 -S30.2 -e5 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.7 "T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers" nr_dlsim -n1000 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.8 "CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers" nr_dlsim -n1000 -s30 -S30.2 -e15 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.8 "T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 2 layers" nr_dlsim -n1000 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.9 "CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers" nr_dlsim -n1000 -s30 -S30.2 -e25 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.9 "T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers" nr_dlsim -n1000 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -x2 -z2 -y2 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.10 "CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers, 4 antennas" nr_dlsim -n1000 -s30 -S30.2 -e5 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.10 "T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers, 4 antennas" nr_dlsim -n1000 -s30 -S30.2 -e5 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.11 "CPU: SNR = 30, MCS = 20, 273 PRBs, 2 layers, 4 antennas" nr_dlsim -n1000 -s30 -S30.2 -e15 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.11 "T2 LDPC offload: SNR = 30, MCS = 20, 273 PRBs, 2 layers, 4 antennas" nr_dlsim -n1000 -s30 -S30.2 -e15 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_dlsim.testCPU.12 "CPU: SNR = 30, MCS = 27, 273 PRBs, 2 layers, 4 antennas" nr_dlsim -n1000 -s30 -S30.2 -e25 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P) +add_physim_test(physim.5g-offload.nr_dlsim.testT2.12 "T2 LDPC offload: SNR = 30, MCS = 27, 273 PRBs, 2 layers, 4 antennas" nr_dlsim -n1000 -s30 -S30.2 -e25 -b273 -R273 -X4,5,6,7,8,9 -x2 -z4 -y4 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) + +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.1 "CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m5 -r106 -R106 -C10 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.1 "T2 LDPC offload: SNR = 30, MCS = 5, 106 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m5 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.2 "CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m15 -r106 -R106 -C10 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.2 "T2 LDPC offload: SNR = 30, MCS = 15, 106 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m15 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.3 "CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m25 -r106 -R106 -C10 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.3 "T2 LDPC offload: SNR = 30, MCS = 25, 106 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m25 -r106 -R106 -C10 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.4 "CPU: SNR = 30, MCS = 5, 273 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m5 -r273 -R273 -C10 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.4 "T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m5 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.5 "CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m15 -r273 -R273 -C10 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.5 "T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m15 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.6 "CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m25 -r273 -R273 -C10 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.6 "T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 1 layer" nr_ulsim -n1000 -s30 -S30.2 -m25 -r273 -R273 -C10 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.7 "CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers" nr_ulsim -n1000 -s30 -S30.2 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.7 "T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers" nr_ulsim -n1000 -s30 -S30.2 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.8 "CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers" nr_ulsim -n1000 -s30 -S30.2 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.8 "T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 2 layers" nr_ulsim -n1000 -s30 -S30.2 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) +add_physim_test(physim.5g-offload.nr_ulsim.testCPU.9 "CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers" nr_ulsim -n1000 -s30 -S30.2 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P) +add_physim_test(physim.5g-offload.nr_ulsim.testT2.9 "T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers" nr_ulsim -n1000 -s30 -S30.2 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P --loader.ldpc.shlibversion _aal --nrLDPC_coding_aal.dpdk_dev af:00.0 --nrLDPC_coding_aal.dpdk_core_list 11-12 --nrLDPC_coding_aal.is_t2 1) + +endif() + +if(PHYSIM_CHECK_FILES) + foreach(PHYSIM_CHECK_FILE IN LISTS PHYSIM_CHECK_FILES) + include("${CMAKE_CURRENT_SOURCE_DIR}/${PHYSIM_CHECK_FILE}") + endforeach() +endif() diff --git a/openair1/SIMULATION/tests/RunTimedTest.cmake b/openair1/SIMULATION/tests/RunTimedTest.cmake new file mode 100644 index 0000000000..779d781bec --- /dev/null +++ b/openair1/SIMULATION/tests/RunTimedTest.cmake @@ -0,0 +1,41 @@ +# this script expects +# - TEST_CMD (program + options) +# - CHECK_SCRIPT (path to analyze-timing.sh) +# further, it analyzes the (test-specific) environment for CHECK_0, CHECK_1, +# etc. to construct the input to the check script. + +# the calling process writes env vars CHECK_0, CHECK_1, ... +# each has "condition;threshold" as it's content +# combine all necessary CHECK0, CHECK1, ... into a single array CHECKS +# to be passed to the check script +foreach(count RANGE 9) + set(CHECK "CHECK_${count}") + if (NOT DEFINED ENV{${CHECK}}) + break() + endif() + list(APPEND CHECKS "$ENV{${CHECK}}") +endforeach() + +# execute the actual test command TEST_CMD and pipe its output into the +# check script. Afterwards, check both commands return codes. +execute_process(COMMAND ${TEST_CMD} + COMMAND ${CHECK_SCRIPT} ${CHECKS} + COMMAND_ECHO STDOUT + RESULTS_VARIABLE RET_CODES +) +list(LENGTH RET_CODES LEN_RET_CODES) +if(NOT LEN_RET_CODES EQUAL 2) + message(SEND_ERROR "execute_process() did not run both commands!") +endif() + +list(GET RET_CODES 0 TEST_RET_CODE) +message(STATUS "test command finished with ${TEST_RET_CODE}") +if(NOT ${TEST_RET_CODE} MATCHES "0") + message(SEND_ERROR " => test failed!") +endif() + +list(GET RET_CODES 1 CHECK_RET_CODE) +message(STATUS "check command finished with ${CHECK_RET_CODE}") +if(NOT ${CHECK_RET_CODE} MATCHES "0") + message(SEND_ERROR " => check failed!") +endif() diff --git a/openair1/SIMULATION/tests/ThresholdsGracehopper.cmake b/openair1/SIMULATION/tests/ThresholdsGracehopper.cmake new file mode 100644 index 0000000000..7041a4f91b --- /dev/null +++ b/openair1/SIMULATION/tests/ThresholdsGracehopper.cmake @@ -0,0 +1,123 @@ +check_threshold_variance(physim.5g.nr_dlsim.basic.test1 "DLSCH encoding time" AVG 31 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.basic.test2 "DLSCH encoding time" AVG 36 ABS_VAR 8) +check_threshold_variance(physim.5g.nr_dlsim.basic.test3 "DLSCH encoding time" AVG 49 ABS_VAR 10) +check_threshold_variance(physim.5g.nr_dlsim.basic.test4 "DLSCH encoding time" AVG 33 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.basic.test5 "DLSCH encoding time" AVG 33 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.basic.test6 "DLSCH encoding time" AVG 31 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.basic.test7 "DLSCH encoding time" AVG 8 ABS_VAR 2) +check_threshold_variance(physim.5g.nr_dlsim.basic.test8 "DLSCH encoding time" AVG 20 ABS_VAR 4) +check_threshold_variance(physim.5g.nr_dlsim.offset.test1 "DLSCH encoding time" AVG 32 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.offset.test2 "DLSCH encoding time" AVG 25 ABS_VAR 5) +check_threshold_variance(physim.5g.nr_dlsim.offset.test3 "DLSCH encoding time" AVG 30 ABS_VAR 6) +check_threshold_variance(physim.5g.nr_dlsim.offset.test4 "DLSCH encoding time" AVG 34 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.offset.test5 "DLSCH encoding time" AVG 30 ABS_VAR 6) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test1 "DLSCH encoding time" AVG 72 ABS_VAR 15) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test2 "DLSCH encoding time" AVG 36 ABS_VAR 8) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test3 "DLSCH encoding time" AVG 83 ABS_VAR 17) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test4 "DLSCH encoding time" AVG 79 ABS_VAR 16) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test5 "DLSCH encoding time" AVG 30 ABS_VAR 6) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test6 "DLSCH encoding time" AVG 39 ABS_VAR 8) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test7 "DLSCH encoding time" AVG 48 ABS_VAR 10) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test8 "DLSCH encoding time" AVG 141 ABS_VAR 29) +check_threshold_variance(physim.5g.nr_dlsim.mcs.mimo.test9 "DLSCH encoding time" AVG 32 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.dmrs.ptrs.test1 "DLSCH encoding time" AVG 31 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.dmrs.ptrs.test2 "DLSCH encoding time" AVG 31 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.dmrs.ptrs.test3 "DLSCH encoding time" AVG 31 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.dmrs.ptrs.test4 "DLSCH encoding time" AVG 31 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.dmrs.ptrs.test5 "DLSCH encoding time" AVG 31 ABS_VAR 7) +check_threshold_variance(physim.5g.nr_dlsim.dmrs.ptrs.test6 "DLSCH encoding time" AVG 31 ABS_VAR 7) + +check_threshold_variance(physim.5g.nr_ulsim.misc.test1 "ULSCH total decoding time" AVG 326 ABS_VAR 66) +check_threshold_variance(physim.5g.nr_ulsim.misc.test2 "ULSCH total decoding time" AVG 466 ABS_VAR 94) +check_threshold_variance(physim.5g.nr_ulsim.misc.test3 "ULSCH total decoding time" AVG 558 ABS_VAR 112) +check_threshold_variance(physim.5g.nr_ulsim.misc.test4 "ULSCH total decoding time" AVG 578 ABS_VAR 116) +check_threshold_variance(physim.5g.nr_ulsim.misc.test5 "ULSCH total decoding time" AVG 1019 ABS_VAR 204) +check_threshold_variance(physim.5g.nr_ulsim.misc.test6 "ULSCH total decoding time" AVG 1234 ABS_VAR 247) +check_threshold_variance(physim.5g.nr_ulsim.misc.test7 "ULSCH total decoding time" AVG 244 ABS_VAR 49) +check_threshold_variance(physim.5g.nr_ulsim.misc.test8 "ULSCH total decoding time" AVG 150 ABS_VAR 30) +check_threshold_variance(physim.5g.nr_ulsim.misc.test9 "ULSCH total decoding time" AVG 148 ABS_VAR 30) +check_threshold_variance(physim.5g.nr_ulsim.misc.test10 "ULSCH total decoding time" AVG 151 ABS_VAR 31) +check_threshold_variance(physim.5g.nr_ulsim.misc.test11 "ULSCH total decoding time" AVG 46 ABS_VAR 10) +check_threshold_variance(physim.5g.nr_ulsim.misc.test12 "ULSCH total decoding time" AVG 109 ABS_VAR 22) +check_threshold_variance(physim.5g.nr_ulsim.misc.test13 "ULSCH total decoding time" AVG 85 ABS_VAR 17) +check_threshold_variance(physim.5g.nr_ulsim.misc.test14 "ULSCH total decoding time" AVG 1185 ABS_VAR 237) +check_threshold_variance(physim.5g.nr_ulsim.misc.test15 "ULSCH total decoding time" AVG 114 ABS_VAR 23) +check_threshold_variance(physim.5g.nr_ulsim.sc-fdma.test1 "ULSCH total decoding time" AVG 239 ABS_VAR 48) +check_threshold_variance(physim.5g.nr_ulsim.sc-fdma.test2 "ULSCH total decoding time" AVG 229 ABS_VAR 46) +check_threshold_variance(physim.5g.nr_ulsim.sc-fdma.test3 "ULSCH total decoding time" AVG 989 ABS_VAR 198) +check_threshold_variance(physim.5g.nr_ulsim.sc-fdma.test4 "ULSCH total decoding time" AVG 797 ABS_VAR 160) +check_threshold_variance(physim.5g.nr_ulsim.sc-fdma.test5 "ULSCH total decoding time" AVG 132 ABS_VAR 27) +check_threshold_variance(physim.5g.nr_ulsim.mimo.test1 "ULSCH total decoding time" AVG 513 ABS_VAR 103) +check_threshold_variance(physim.5g.nr_ulsim.mimo.test2 "ULSCH total decoding time" AVG 435 ABS_VAR 87) +check_threshold_variance(physim.5g.nr_ulsim.mimo.test3 "ULSCH total decoding time" AVG 1082 ABS_VAR 217) +check_threshold_variance(physim.5g.nr_ulsim.mimo.test4 "ULSCH total decoding time" AVG 1561 ABS_VAR 313) +check_threshold_variance(physim.5g.nr_ulsim.mimo.test5 "ULSCH total decoding time" AVG 1162 ABS_VAR 233) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test1 "ULSCH total decoding time" AVG 993 ABS_VAR 199) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test2 "ULSCH total decoding time" AVG 1038 ABS_VAR 208) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test3 "ULSCH total decoding time" AVG 1168 ABS_VAR 234) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test4 "ULSCH total decoding time" AVG 304 ABS_VAR 61) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test5 "ULSCH total decoding time" AVG 311 ABS_VAR 63) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test6 "ULSCH total decoding time" AVG 333 ABS_VAR 67) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test7 "ULSCH total decoding time" AVG 527 ABS_VAR 106) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test8 "ULSCH total decoding time" AVG 559 ABS_VAR 112) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test9 "ULSCH total decoding time" AVG 591 ABS_VAR 119) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test10 "ULSCH total decoding time" AVG 969 ABS_VAR 194) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test11 "ULSCH total decoding time" AVG 1056 ABS_VAR 212) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test12 "ULSCH total decoding time" AVG 1202 ABS_VAR 241) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test13 "ULSCH total decoding time" AVG 303 ABS_VAR 61) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test14 "ULSCH total decoding time" AVG 320 ABS_VAR 64) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test15 "ULSCH total decoding time" AVG 332 ABS_VAR 67) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test16 "ULSCH total decoding time" AVG 536 ABS_VAR 108) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test17 "ULSCH total decoding time" AVG 560 ABS_VAR 112) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test18 "ULSCH total decoding time" AVG 606 ABS_VAR 122) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test19 "ULSCH total decoding time" AVG 1019 ABS_VAR 204) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test20 "ULSCH total decoding time" AVG 1060 ABS_VAR 212) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test21 "ULSCH total decoding time" AVG 1158 ABS_VAR 232) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test22 "ULSCH total decoding time" AVG 2466 ABS_VAR 494) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test23 "ULSCH total decoding time" AVG 2557 ABS_VAR 512) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test24 "ULSCH total decoding time" AVG 3149 ABS_VAR 630) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test25 "ULSCH total decoding time" AVG 469 ABS_VAR 94) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test26 "ULSCH total decoding time" AVG 416 ABS_VAR 84) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test27 "ULSCH total decoding time" AVG 1587 ABS_VAR 318) +check_threshold_variance(physim.5g.nr_ulsim.3gpp.test28 "ULSCH total decoding time" AVG 1792 ABS_VAR 359) + +check_threshold_variance(physim.5g.ldpctest.test1 "Encoding time mean:" AVG 6 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test1 "Decoding time mean:" AVG 103 ABS_VAR 21) +check_threshold_variance(physim.5g.ldpctest.test2 "Encoding time mean:" AVG 9 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test2 "Decoding time mean:" AVG 113 ABS_VAR 23) +check_threshold_variance(physim.5g.ldpctest.test3 "Encoding time mean:" AVG 8 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test3 "Decoding time mean:" AVG 123 ABS_VAR 25) +check_threshold_variance(physim.5g.ldpctest.test4 "Encoding time mean:" AVG 11 ABS_VAR 3) +check_threshold_variance(physim.5g.ldpctest.test4 "Decoding time mean:" AVG 137 ABS_VAR 28) +check_threshold_variance(physim.5g.ldpctest.test5 "Encoding time mean:" AVG 10 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test5 "Decoding time mean:" AVG 143 ABS_VAR 29) +check_threshold_variance(physim.5g.ldpctest.test6 "Encoding time mean:" AVG 16 ABS_VAR 4) +check_threshold_variance(physim.5g.ldpctest.test6 "Decoding time mean:" AVG 148 ABS_VAR 30) +check_threshold_variance(physim.5g.ldpctest.test7 "Encoding time mean:" AVG 14 ABS_VAR 3) +check_threshold_variance(physim.5g.ldpctest.test7 "Decoding time mean:" AVG 171 ABS_VAR 35) +check_threshold_variance(physim.5g.ldpctest.test8 "Encoding time mean:" AVG 17 ABS_VAR 4) +check_threshold_variance(physim.5g.ldpctest.test8 "Decoding time mean:" AVG 185 ABS_VAR 37) +check_threshold_variance(physim.5g.ldpctest.test9 "Encoding time mean:" AVG 19 ABS_VAR 4) +check_threshold_variance(physim.5g.ldpctest.test9 "Decoding time mean:" AVG 206 ABS_VAR 42) +check_threshold_variance(physim.5g.ldpctest.test10 "Encoding time mean:" AVG 14 ABS_VAR 3) +check_threshold_variance(physim.5g.ldpctest.test10 "Decoding time mean:" AVG 222 ABS_VAR 45) +check_threshold_variance(physim.5g.ldpctest.test11 "Encoding time mean:" AVG 2 ABS_VAR 1) +check_threshold_variance(physim.5g.ldpctest.test11 "Decoding time mean:" AVG 8 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test12 "Encoding time mean:" AVG 10 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test12 "Decoding time mean:" AVG 10 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test13 "Encoding time mean:" AVG 18 ABS_VAR 4) +check_threshold_variance(physim.5g.ldpctest.test13 "Decoding time mean:" AVG 10 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test14 "Encoding time mean:" AVG 44 ABS_VAR 9) +check_threshold_variance(physim.5g.ldpctest.test14 "Decoding time mean:" AVG 15 ABS_VAR 3) +check_threshold_variance(physim.5g.ldpctest.test15 "Encoding time mean:" AVG 49 ABS_VAR 10) +check_threshold_variance(physim.5g.ldpctest.test15 "Decoding time mean:" AVG 14 ABS_VAR 3) +check_threshold_variance(physim.5g.ldpctest.test16 "Encoding time mean:" AVG 3 ABS_VAR 1) +check_threshold_variance(physim.5g.ldpctest.test16 "Decoding time mean:" AVG 15 ABS_VAR 3) +check_threshold_variance(physim.5g.ldpctest.test17 "Encoding time mean:" AVG 3 ABS_VAR 1) +check_threshold_variance(physim.5g.ldpctest.test17 "Decoding time mean:" AVG 14 ABS_VAR 3) +check_threshold_variance(physim.5g.ldpctest.test18 "Encoding time mean:" AVG 5 ABS_VAR 1) +check_threshold_variance(physim.5g.ldpctest.test18 "Decoding time mean:" AVG 32 ABS_VAR 7) +check_threshold_variance(physim.5g.ldpctest.test19 "Encoding time mean:" AVG 8 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test19 "Decoding time mean:" AVG 48 ABS_VAR 10) +check_threshold_variance(physim.5g.ldpctest.test20 "Encoding time mean:" AVG 10 ABS_VAR 2) +check_threshold_variance(physim.5g.ldpctest.test20 "Decoding time mean:" AVG 57 ABS_VAR 12) diff --git a/openair1/SIMULATION/tests/ThresholdsOffload.cmake b/openair1/SIMULATION/tests/ThresholdsOffload.cmake new file mode 100644 index 0000000000..9f787f993a --- /dev/null +++ b/openair1/SIMULATION/tests/ThresholdsOffload.cmake @@ -0,0 +1,43 @@ +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.1 "DLSCH encoding time" AVG 50 ABS_VAR 10) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.1 "DLSCH encoding time" AVG 19 ABS_VAR 4) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.2 "DLSCH encoding time" AVG 65 ABS_VAR 13) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.2 "DLSCH encoding time" AVG 27 ABS_VAR 6) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.3 "DLSCH encoding time" AVG 97 ABS_VAR 20) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.3 "DLSCH encoding time" AVG 33 ABS_VAR 7) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.4 "DLSCH encoding time" AVG 68 ABS_VAR 14) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.4 "DLSCH encoding time" AVG 26 ABS_VAR 6) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.5 "DLSCH encoding time" AVG 108 ABS_VAR 22) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.5 "DLSCH encoding time" AVG 46 ABS_VAR 10) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.6 "DLSCH encoding time" AVG 131 ABS_VAR 27) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.6 "DLSCH encoding time" AVG 80 ABS_VAR 16) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.7 "DLSCH encoding time" AVG 120 ABS_VAR 24) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.7 "DLSCH encoding time" AVG 44 ABS_VAR 9) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.8 "DLSCH encoding time" AVG 146 ABS_VAR 30) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.8 "DLSCH encoding time" AVG 87 ABS_VAR 18) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.9 "DLSCH encoding time" AVG 204 ABS_VAR 41) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.9 "DLSCH encoding time" AVG 138 ABS_VAR 28) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.10 "DLSCH encoding time" AVG 149 ABS_VAR 30) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.10 "DLSCH encoding time" AVG 49 ABS_VAR 10) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.11 "DLSCH encoding time" AVG 164 ABS_VAR 33) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.11 "DLSCH encoding time" AVG 90 ABS_VAR 18) +check_threshold_variance(physim.5g-offload.nr_dlsim.testCPU.12 "DLSCH encoding time" AVG 223 ABS_VAR 45) +check_threshold_variance(physim.5g-offload.nr_dlsim.testT2.12 "DLSCH encoding time" AVG 146 ABS_VAR 30) + +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.1 "ULSCH total decoding time" AVG 141 ABS_VAR 29) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.1 "ULSCH total decoding time" AVG 40 ABS_VAR 8) +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.2 "ULSCH total decoding time" AVG 165 ABS_VAR 33) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.2 "ULSCH total decoding time" AVG 63 ABS_VAR 13) +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.3 "ULSCH total decoding time" AVG 156 ABS_VAR 32) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.3 "ULSCH total decoding time" AVG 87 ABS_VAR 18) +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.4 "ULSCH total decoding time" AVG 170 ABS_VAR 34) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.4 "ULSCH total decoding time" AVG 74 ABS_VAR 15) +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.5 "ULSCH total decoding time" AVG 299 ABS_VAR 60) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.5 "ULSCH total decoding time" AVG 120 ABS_VAR 24) +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.6 "ULSCH total decoding time" AVG 324 ABS_VAR 65) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.6 "ULSCH total decoding time" AVG 180 ABS_VAR 36) +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.7 "ULSCH total decoding time" AVG 200 ABS_VAR 40) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.7 "ULSCH total decoding time" AVG 120 ABS_VAR 24) +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.8 "ULSCH total decoding time" AVG 436 ABS_VAR 88) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.8 "ULSCH total decoding time" AVG 229 ABS_VAR 46) +check_threshold_variance(physim.5g-offload.nr_ulsim.testCPU.9 "ULSCH total decoding time" AVG 530 ABS_VAR 106) +check_threshold_variance(physim.5g-offload.nr_ulsim.testT2.9 "ULSCH total decoding time" AVG 334 ABS_VAR 67) diff --git a/openair1/SIMULATION/tests/analyze-timing.sh b/openair1/SIMULATION/tests/analyze-timing.sh new file mode 100755 index 0000000000..f88b595a97 --- /dev/null +++ b/openair1/SIMULATION/tests/analyze-timing.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# This bash script builds an awk script. The awk script tries to match +# (provided) patterns and compares them against given thresholds condition +# (e.g., threshold is "< 10"). + +function die() { echo $@ 1>&2; exit 1; } + +# Print every line, because the logs are piped into this script, but a user is +# typically also interested into the raw logs. +SCRIPT=' + { print $0 } +' + +NUM=0 +# for each pair of /, add corresponding rules. +while [ $# -gt 0 ]; do + [ $# -ne 1 ] || die "unmatched /" + PATTERN=${1} + COND=${2} + shift 2 + + # Add a rule that searches for a PATTERN + number, and checks against + # CONDition. If the condition does not hold, it is counted as a failure. In + # both cases, the result is logged in an array to output at the end of the + # script. + # + # To search for the number, first substr() returns what has been matched + # (PATTERN + number), and sub() deletes PATTERN and whitespace, resulting in + # the number (measurement). To force number into a numeric context, we add 0, + # as awk would otherwise compare a string to a number (example: + # gawk 'BEGIN { meas = "117"; if (meas > 96) { } else { print "fail";}}' + # printfs "fail"). + # + # Example: pattern "PHY proc tx", condition "< 200" + # The awk script tries to match every line for "PHY proc tx _NUMBER_" (where + # number is a decimal), and compares _NUMBER_ against condition "< 200", + # i.e., "_NUMBER_ < 200". + # If the condition holds, will set "CHECK PHY proc tx _NUMBER_ < 200 SUCCESS". + # If the condition fails, will set "CHECK PHY proc tx _NUMBER_ < 200 FAIL". + SCRIPT+=' + match($0, /'${PATTERN}' +([0-9]+(\.[0-9]+)?)/) { + meas = substr($0, RSTART, RLENGTH); + sub(/'${PATTERN}' +/, "", meas); + if ((meas+0) '${COND}') { + r = "SUCCESS"; + } else { + r = "FAIL"; + } + RESULTS['${NUM}']=sprintf("CHECK %-35s %7.2f %-8s %s", "'${PATTERN}'", meas, " '${COND}'", r); + } +' + + # Generate an additional rule for the end of the logs: if the pattern is not + # found, it is counted as a failure and logged appropriately. + # Following the above example "PHY proc tx" and "< 200": if such log is not + # found, will set "CHECK PHY proc tx < 200 NOTFOUND" + SCRIPT+=' + END { + if (!RESULTS['${NUM}']) { + RESULTS['${NUM}']=sprintf("CHECK %-35s %-7s NOTFOUND", "'${PATTERN}'", "'${COND}'"); + } + } +' + + let NUM=${NUM}+1 +done + +# After passing through all logs, print all results, and exit with return code +# (0 on success, i.e..all conditions checked, otherwise 1 on failure). +SCRIPT+=' + END { + RC = 0; + for (i = 0; i < '${NUM}'; ++i) { + print RESULTS[i] + if (!(RESULTS[i] ~ /SUCCESS$/)) + RC = 1; + } + exit RC + } +' + +# Read from separate file descriptor 3: this allows us to pipe the actual log +# to analyze into awk (by using the script like so: analyze-timing.sh < log) +awk -f /dev/fd/3 3<<< ${SCRIPT} diff --git a/openair2/COMMON/as_message.h b/openair2/COMMON/as_message.h index 1fb59c6aa9..a134c1b47c 100644 --- a/openair2/COMMON/as_message.h +++ b/openair2/COMMON/as_message.h @@ -218,10 +218,6 @@ typedef struct kenb_refresh_req_s { uint8_t kenb[32]; } kenb_refresh_req_t; -typedef struct nsa_oai_tun_nsa_s { - uint8_t buffer[500]; -} nas_oai_tun_nsa_t; - /* * NAS->AS - Cell Information request * NAS request AS to search for a suitable cell belonging to the selected diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index f4e9090f66..788236ca05 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -283,6 +283,22 @@ typedef struct bearer_context_pdcp_config_s { bool pDCP_Reestablishment; } bearer_context_pdcp_config_t; +/* 9.3.1.35 3GPP TS 38.463 */ +typedef struct { + // PDCP SN + uint32_t sn; + // HFN + uint32_t hfn; +} e1_pdcp_count_t; + +/* 9.3.1.58 3GPP TS 38.463 */ +typedef struct { + // UL Count Value + e1_pdcp_count_t ul_count; + // DL Count Value + e1_pdcp_count_t dl_count; +} e1_pdcp_status_info_t; + typedef struct drb_to_setup_s { long drbId; bearer_context_pdcp_config_t pdcp_config; @@ -384,6 +400,8 @@ typedef struct DRB_nGRAN_to_modify_s { bearer_context_pdcp_config_t *pdcp_config; // PDCP SN Status Request (O) bool pdcp_sn_status_requested; + // PDCP SN Status Information + e1_pdcp_status_info_t *pdcp_status; // DL UP Transport Layer Information (O) (clause 9.3.1.13, 9.3.2.1) int numDlUpParam; up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM]; @@ -561,9 +579,8 @@ typedef struct DRB_nGRAN_modified_s { // Flow Failed List (O) int numQosFlowFailed; qos_flow_failed_t qosFlowsFailed[E1AP_MAX_NUM_QOS_FLOWS]; - // Old QoS Flow List (O) - int numOldQosFlow; - qos_flow_list_t oldQosFlows[E1AP_MAX_NUM_QOS_FLOWS]; + // PDCP SN Status Information (0) + e1_pdcp_status_info_t *pdcp_status; } DRB_nGRAN_modified_t; typedef struct DRB_nGRAN_failed_s { diff --git a/openair2/COMMON/f1ap_messages_def.h b/openair2/COMMON/f1ap_messages_def.h index 405ecae3d5..18b16563d8 100644 --- a/openair2/COMMON/f1ap_messages_def.h +++ b/openair2/COMMON/f1ap_messages_def.h @@ -48,18 +48,18 @@ MESSAGE_DEF(F1AP_INITIAL_UL_RRC_MESSAGE , MESSAGE_PRIORITY_MED, f1ap_i MESSAGE_DEF(F1AP_UL_RRC_MESSAGE , MESSAGE_PRIORITY_MED, f1ap_ul_rrc_message_t , f1ap_ul_rrc_message) //MESSAGE_DEF(F1AP_INITIAL_CONTEXT_SETUP_RESP, MESSAGE_PRIORITY_MED, f1ap_initial_context_setup_resp_t, f1ap_initial_context_setup_resp) //MESSAGE_DEF(F1AP_INITIAL_CONTEXT_SETUP_FAILURE, MESSAGE_PRIORITY_MED, f1ap_initial_context_setup_failure_t, f1ap_initial_context_setup_failure) -MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_release_req_t, f1ap_ue_context_release_req) -MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_CMD, MESSAGE_PRIORITY_MED, f1ap_ue_context_release_cmd_t, f1ap_ue_context_release_cmd) -MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_COMPLETE, MESSAGE_PRIORITY_MED, f1ap_ue_context_release_complete_t, f1ap_ue_context_release_complete) +MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_rel_req_t, f1ap_ue_context_release_req) +MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_CMD, MESSAGE_PRIORITY_MED, f1ap_ue_context_rel_cmd_t, f1ap_ue_context_release_cmd) +MESSAGE_DEF(F1AP_UE_CONTEXT_RELEASE_COMPLETE, MESSAGE_PRIORITY_MED, f1ap_ue_context_rel_cplt_t, f1ap_ue_context_release_complete) MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_REQUIRED, MESSAGE_PRIORITY_MED, f1ap_ue_context_modif_required_t, f1ap_ue_context_modification_required) /* RRC -> F1AP messages */ MESSAGE_DEF(F1AP_DL_RRC_MESSAGE , MESSAGE_PRIORITY_MED, f1ap_dl_rrc_message_t , f1ap_dl_rrc_message ) //MESSAGE_DEF(F1AP_INITIAL_CONTEXT_SETUP_REQ , MESSAGE_PRIORITY_MED, f1ap_initial_context_setup_req_t , f1ap_initial_context_setup_req ) -MESSAGE_DEF(F1AP_UE_CONTEXT_SETUP_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_setup_t, f1ap_ue_context_setup_req) -MESSAGE_DEF(F1AP_UE_CONTEXT_SETUP_RESP, MESSAGE_PRIORITY_MED, f1ap_ue_context_setup_t, f1ap_ue_context_setup_resp) -MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_modif_req_t, f1ap_ue_context_modification_req) -MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_RESP, MESSAGE_PRIORITY_MED, f1ap_ue_context_modif_resp_t, f1ap_ue_context_modification_resp) +MESSAGE_DEF(F1AP_UE_CONTEXT_SETUP_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_setup_req_t, f1ap_ue_context_setup_req) +MESSAGE_DEF(F1AP_UE_CONTEXT_SETUP_RESP, MESSAGE_PRIORITY_MED, f1ap_ue_context_setup_resp_t, f1ap_ue_context_setup_resp) +MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_REQ, MESSAGE_PRIORITY_MED, f1ap_ue_context_mod_req_t, f1ap_ue_context_mod_req) +MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_RESP, MESSAGE_PRIORITY_MED, f1ap_ue_context_mod_resp_t, f1ap_ue_context_modification_resp) MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_CONFIRM, MESSAGE_PRIORITY_MED, f1ap_ue_context_modif_confirm_t, f1ap_ue_context_modification_confirm) MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_REFUSE, MESSAGE_PRIORITY_MED, f1ap_ue_context_modif_refuse_t, f1ap_ue_context_modification_refuse) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 84d887f8f9..e44e1dccb4 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -26,6 +26,7 @@ #include #include "common/5g_platform_types.h" #include "common/platform_constants.h" +#include "common/utils/ds/byte_array.h" //-------------------------------------------------------------------------------------------// // Defines to access message fields. @@ -54,7 +55,7 @@ #define F1AP_UL_RRC_MESSAGE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ul_rrc_message #define F1AP_UE_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_setup_req #define F1AP_UE_CONTEXT_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_setup_resp -#define F1AP_UE_CONTEXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_req +#define F1AP_UE_CONTEXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_mod_req #define F1AP_UE_CONTEXT_MODIFICATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_resp #define F1AP_UE_CONTEXT_MODIFICATION_FAIL(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_fail #define F1AP_UE_CONTEXT_MODIFICATION_REQUIRED(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_modification_required @@ -362,7 +363,6 @@ typedef struct f1ap_ul_rrc_message_s { typedef struct f1ap_up_tnl_s { in_addr_t tl_address; // currently only IPv4 supported uint32_t teid; - uint16_t port; } f1ap_up_tnl_t; typedef enum preemption_capability_e { @@ -375,82 +375,20 @@ typedef enum preemption_vulnerability_e { PREEMPTABLE, } preemption_vulnerability_t; -typedef struct f1ap_qos_characteristics_s { - union { - struct { - long fiveqi; - long qos_priority_level; - } non_dynamic; - struct { - long fiveqi; // -1 -> optional - long qos_priority_level; - long packet_delay_budget; - struct { - long per_scalar; - long per_exponent; - } packet_error_rate; - } dynamic; - }; - fiveQI_t qos_type; -} f1ap_qos_characteristics_t; - -typedef struct f1ap_ngran_allocation_retention_priority_s { - uint16_t priority_level; - preemption_capability_t preemption_capability; - preemption_vulnerability_t preemption_vulnerability; -} f1ap_ngran_allocation_retention_priority_t; - -typedef struct f1ap_qos_flow_level_qos_parameters_s { - f1ap_qos_characteristics_t qos_characteristics; - f1ap_ngran_allocation_retention_priority_t alloc_reten_priority; -} f1ap_qos_flow_level_qos_parameters_t; - -typedef struct f1ap_flows_mapped_to_drb_s { - long qfi; // qos flow identifier - f1ap_qos_flow_level_qos_parameters_t qos_params; -} f1ap_flows_mapped_to_drb_t; - -typedef struct f1ap_drb_information_s { - f1ap_qos_flow_level_qos_parameters_t drb_qos; - f1ap_flows_mapped_to_drb_t *flows_mapped_to_drb; - uint8_t flows_to_be_setup_length; -} f1ap_drb_information_t; - typedef enum f1ap_rlc_mode_t { F1AP_RLC_MODE_AM, F1AP_RLC_MODE_UM_BIDIR, F1AP_RLC_UM_UNI_UL, F1AP_RLC_UM_UNI_DL } f1ap_rlc_mode_t; -typedef struct f1ap_drb_to_be_setup_s { - long drb_id; - f1ap_up_tnl_t up_ul_tnl[2]; - uint8_t up_ul_tnl_length; - f1ap_up_tnl_t up_dl_tnl[2]; - uint8_t up_dl_tnl_length; - f1ap_drb_information_t drb_info; - f1ap_rlc_mode_t rlc_mode; - nssai_t nssai; -} f1ap_drb_to_be_setup_t; -typedef struct f1ap_srb_to_be_setup_s { - long srb_id; - uint8_t lcid; -} f1ap_srb_to_be_setup_t; +typedef struct f1ap_cu_to_du_rrc_info_s { + byte_array_t *cg_configinfo; + byte_array_t *ue_cap; + byte_array_t *meas_config; + byte_array_t *meas_timing_config; + byte_array_t *ho_prep_info; +} f1ap_cu_to_du_rrc_info_t; -typedef struct f1ap_rb_failed_to_be_setup_s { - long rb_id; -} f1ap_rb_failed_to_be_setup_t; - -typedef struct f1ap_drb_to_be_released_t { - long rb_id; -} f1ap_drb_to_be_released_t; - -typedef struct cu_to_du_rrc_information_s { - uint8_t * cG_ConfigInfo; - uint32_t cG_ConfigInfo_length; - uint8_t * uE_CapabilityRAT_ContainerList; - uint32_t uE_CapabilityRAT_ContainerList_length; - uint8_t * measConfig; - uint32_t measConfig_length; - uint8_t *handoverPreparationInfo; - uint32_t handoverPreparationInfo_length; -}cu_to_du_rrc_information_t; +typedef struct f1ap_du_to_cu_rrc_info_t { + byte_array_t cell_group_config; + byte_array_t *meas_gap_config; +} f1ap_du_to_cu_rrc_info_t; typedef struct du_to_cu_rrc_information_s { uint8_t * cellGroupConfig; @@ -461,11 +399,6 @@ typedef struct du_to_cu_rrc_information_s { uint32_t requestedP_MaxFR1_length; }du_to_cu_rrc_information_t; -typedef enum QoS_information_e { - NG_RAN_QoS = 0, - EUTRAN_QoS = 1, -} QoS_information_t; - typedef enum ReconfigurationCompl_e { RRCreconf_info_not_present = 0, RRCreconf_failure = 1, @@ -477,39 +410,173 @@ typedef enum TransmActionInd_e { TransmActionInd_RESTART, } TransmActionInd_t; -typedef struct f1ap_ue_context_setup_s { +typedef enum lower_layer_status_e { + LOWER_LAYERS_SUSPEND, + LOWER_LAYERS_RESUME, +} lower_layer_status_t; + +typedef struct f1ap_srb_to_setup_t { + int id; +} f1ap_srb_to_setup_t; + +typedef struct f1ap_srb_setup_t { + int id; + int lcid; +} f1ap_srb_setup_t; + +/// 9.3.1.52 Packet Error Rate +typedef struct f1ap_per_t { + uint8_t scalar; + uint8_t exponent; +} f1ap_per_t; + +// 9.3.1.49 Non-Dynamic 5QI Descriptor +typedef struct f1ap_nondynamic_5qi_t { + int fiveQI; +} f1ap_nondynamic_5qi_t; + +// 9.3.1.47 Dynamic 5QI Descriptor +typedef struct f1ap_dynamic_5qi_t { + int prio; /// QoS Priority Level + int pdb; /// Packet Delay Budget + f1ap_per_t per; /// Packet Error Rate + bool *delay_critical; /// Delay Critical + int *avg_win; /// Averaging Window +} f1ap_dynamic_5qi_t; + +typedef struct f1ap_arp_t { + uint16_t prio; + preemption_capability_t preempt_cap; + preemption_vulnerability_t preempt_vuln; +} f1ap_arp_t; + +// 9.3.1.45 QoS Flow Level QoS Parameters +typedef struct f1ap_qos_flow_param_t { + fiveQI_t qos_type; + union { + f1ap_nondynamic_5qi_t nondyn; + f1ap_dynamic_5qi_t dyn; + }; + f1ap_arp_t arp; +} f1ap_qos_flow_param_t; + +// in 9.2.2.1 Flows Mapped to DRB Item +typedef struct f1ap_drb_flows_mapped_t { + int qfi; + f1ap_qos_flow_param_t param; +} f1ap_drb_flows_mapped_t; + +/// in 9.2.2.1 DRB Info in UE Context Setup Request +typedef struct f1ap_drb_info_nr_t { + f1ap_qos_flow_param_t drb_qos; + nssai_t nssai; + int flows_len; + f1ap_drb_flows_mapped_t *flows; +} f1ap_drb_info_nr_t; + +typedef enum { F1AP_PDCP_SN_12B, F1AP_PDCP_SN_18B } f1ap_pdcp_sn_len_t; +/// in 9.2.2.1 DRB to Be Setup Item IEs +typedef struct f1ap_drb_to_setup_t { + int id; + enum { F1AP_QOS_CHOICE_EUTRAN, F1AP_QOS_CHOICE_NR } qos_choice; + union { + // eutran not implemented + f1ap_drb_info_nr_t nr; + }; + int up_ul_tnl_len; + f1ap_up_tnl_t up_ul_tnl[2]; + f1ap_rlc_mode_t rlc_mode; + f1ap_pdcp_sn_len_t *dl_pdcp_sn_len; // in setup mandatory, in setupmod optional + f1ap_pdcp_sn_len_t *ul_pdcp_sn_len; +} f1ap_drb_to_setup_t; + +typedef struct f1ap_drb_setup_t { + int id; + int *lcid; + int up_dl_tnl_len; + f1ap_up_tnl_t up_dl_tnl[2]; +} f1ap_drb_setup_t; + +typedef struct f1ap_drb_to_release_t { + int id; +} f1ap_drb_to_release_t; + +typedef struct f1ap_ue_context_setup_req_s { uint32_t gNB_CU_ue_id; - uint32_t gNB_DU_ue_id; - // SpCell Info + uint32_t *gNB_DU_ue_id; + plmn_id_t plmn; uint64_t nr_cellid; uint8_t servCellIndex; - uint8_t *cellULConfigured; - uint32_t servCellId; - cu_to_du_rrc_information_t *cu_to_du_rrc_information; - uint8_t cu_to_du_rrc_information_length; - //uint8_t *du_to_cu_rrc_information; - du_to_cu_rrc_information_t *du_to_cu_rrc_information; - uint32_t du_to_cu_rrc_information_length; + + f1ap_cu_to_du_rrc_info_t cu_to_du_rrc_info; + + int srbs_len; + f1ap_srb_to_setup_t *srbs; + + int drbs_len; + f1ap_drb_to_setup_t *drbs; + + byte_array_t *rrc_container; + + uint64_t *gnb_du_ue_agg_mbr_ul; // C-ifDRBSetup +} f1ap_ue_context_setup_req_t; + +typedef struct f1ap_ue_context_setup_resp_s { + uint32_t gNB_CU_ue_id; + uint32_t gNB_DU_ue_id; + + f1ap_du_to_cu_rrc_info_t du_to_cu_rrc_info; + uint16_t *crnti; - f1ap_drb_to_be_setup_t *drbs_to_be_setup; - uint8_t drbs_to_be_setup_length; - f1ap_drb_to_be_setup_t *drbs_to_be_modified; - uint8_t drbs_to_be_modified_length; - QoS_information_t QoS_information_type; - uint8_t drbs_failed_to_be_setup_length; - f1ap_rb_failed_to_be_setup_t *drbs_failed_to_be_setup; - f1ap_srb_to_be_setup_t *srbs_to_be_setup; - uint8_t srbs_to_be_setup_length; - uint8_t srbs_failed_to_be_setup_length; - uint8_t drbs_to_be_released_length; - f1ap_drb_to_be_released_t *drbs_to_be_released; - f1ap_rb_failed_to_be_setup_t *srbs_failed_to_be_setup; - ReconfigurationCompl_t ReconfigComplOutcome; - uint8_t *rrc_container; - int rrc_container_length; + + int drbs_len; + f1ap_drb_setup_t *drbs; + + int srbs_len; + f1ap_srb_setup_t *srbs; +} f1ap_ue_context_setup_resp_t; + +typedef struct f1ap_ue_context_mod_req_t { + uint32_t gNB_CU_ue_id; + uint32_t gNB_DU_ue_id; + + plmn_id_t *plmn; + uint64_t *nr_cellid; + uint8_t *servCellIndex; + + f1ap_cu_to_du_rrc_info_t *cu_to_du_rrc_info; + TransmActionInd_t *transm_action_ind; -} f1ap_ue_context_setup_t, f1ap_ue_context_modif_req_t, f1ap_ue_context_modif_resp_t; + ReconfigurationCompl_t *reconfig_compl; + + byte_array_t *rrc_container; + + int srbs_len; + f1ap_srb_to_setup_t *srbs; // reuse the same type as for setup; there is a + // list for SRB modification + + int drbs_len; + f1ap_drb_to_setup_t *drbs; // as for SRBs + + int drbs_rel_len; + f1ap_drb_to_release_t *drbs_rel; + + lower_layer_status_t *status; +} f1ap_ue_context_mod_req_t; + +typedef struct f1ap_ue_context_mod_resp { + uint32_t gNB_CU_ue_id; + uint32_t gNB_DU_ue_id; + + f1ap_du_to_cu_rrc_info_t *du_to_cu_rrc_info; + + int drbs_len; + f1ap_drb_setup_t *drbs; + + int srbs_len; + f1ap_srb_setup_t *srbs; +} f1ap_ue_context_mod_resp_t; typedef enum F1ap_Cause_e { F1AP_CAUSE_NOTHING, /* No components present */ @@ -541,15 +608,29 @@ typedef struct f1ap_ue_context_modif_refuse_t { long cause_value; } f1ap_ue_context_modif_refuse_t; -typedef struct f1ap_ue_context_release_s { +typedef struct f1ap_ue_context_rel_req_t { uint32_t gNB_CU_ue_id; uint32_t gNB_DU_ue_id; - f1ap_Cause_t cause; - long cause_value; - uint8_t *rrc_container; - int rrc_container_length; - int srb_id; -} f1ap_ue_context_release_req_t, f1ap_ue_context_release_cmd_t, f1ap_ue_context_release_complete_t; + f1ap_Cause_t cause; + long cause_value; +} f1ap_ue_context_rel_req_t; + +typedef struct f1ap_ue_context_rel_cmd_t { + uint32_t gNB_CU_ue_id; + uint32_t gNB_DU_ue_id; + f1ap_Cause_t cause; + long cause_value; + + byte_array_t *rrc_container; + int *srb_id; // C-ifRRCContainer + + uint32_t *old_gNB_DU_ue_id; // if after reestablishment request +} f1ap_ue_context_rel_cmd_t; + +typedef struct f1ap_ue_context_rel_cplt_t { + uint32_t gNB_CU_ue_id; + uint32_t gNB_DU_ue_id; +} f1ap_ue_context_rel_cplt_t; typedef struct f1ap_paging_ind_s { uint16_t ueidentityindexvalue; diff --git a/openair2/COMMON/gtpv1_u_messages_def.h b/openair2/COMMON/gtpv1_u_messages_def.h index 19001b883e..6fad3df938 100644 --- a/openair2/COMMON/gtpv1_u_messages_def.h +++ b/openair2/COMMON/gtpv1_u_messages_def.h @@ -25,4 +25,3 @@ MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_dat MESSAGE_DEF(GTPV1U_ENB_END_MARKER_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_req_t, Gtpv1uEndMarkerReq) MESSAGE_DEF(GTPV1U_ENB_END_MARKER_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_ind_t, Gtpv1uEndMarkerInd) MESSAGE_DEF(GTPV1U_REQ, MESSAGE_PRIORITY_MED, Gtpv1uReq, gtpv1uReq) -MESSAGE_DEF(GTPV1U_DU_BUFFER_REPORT_REQ, MESSAGE_PRIORITY_MED, gtpv1u_DU_buffer_report_req_t, NRGtpv1uBufferReportReq) diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h index 5f12d1e9a2..05ca7d7a74 100644 --- a/openair2/COMMON/gtpv1_u_messages_types.h +++ b/openair2/COMMON/gtpv1_u_messages_types.h @@ -37,8 +37,6 @@ #define GTPV1U_REQ(mSGpTR) (mSGpTR)->ittiMsg.gtpv1uReq -#define GTPV1U_DU_BUFFER_REPORT_REQ(mSGpTR) (mSGpTR)->ittiMsg.NRGtpv1uBufferReportReq - #define GTPV1U_ALL_TUNNELS_TEID (teid_t)0xFFFFFFFF typedef struct gtpv1u_enb_create_x2u_tunnel_req_s { @@ -163,7 +161,7 @@ typedef struct gtpv1u_gnb_create_tunnel_req_s { int num_tunnels; teid_t outgoing_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; int outgoing_qfi[NR_GTPV1U_MAX_BEARERS_PER_UE]; - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; ebi_t incoming_rb_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; transport_layer_addr_t dst_addr[NR_GTPV1U_MAX_BEARERS_PER_UE]; } gtpv1u_gnb_create_tunnel_req_t; @@ -173,13 +171,13 @@ typedef struct gtpv1u_gnb_create_tunnel_resp_s { ue_id_t ue_id; int num_tunnels; teid_t gnb_NGu_teid[NR_GTPV1U_MAX_BEARERS_PER_UE]; ///< Tunnel Endpoint Identifier - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; transport_layer_addr_t gnb_addr; } gtpv1u_gnb_create_tunnel_resp_t; typedef struct gtpv1u_gnb_delete_tunnel_req_s { ue_id_t ue_id; uint8_t num_pdusession; - pdusessionid_t pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; + int pdusession_id[NR_GTPV1U_MAX_BEARERS_PER_UE]; } gtpv1u_gnb_delete_tunnel_req_t; typedef struct gtpv1u_gnb_delete_tunnel_resp_s { @@ -188,11 +186,4 @@ typedef struct gtpv1u_gnb_delete_tunnel_resp_s { teid_t gnb_NGu_teid; ///< local NGU Tunnel Endpoint Identifier to be deleted } gtpv1u_gnb_delete_tunnel_resp_t; - -typedef struct gtpv1u_DU_buffer_report_req_s { - uint32_t buffer_availability; - ue_id_t ue_id; - pdusessionid_t pdusession_id; -} gtpv1u_DU_buffer_report_req_t; - #endif /* GTPV1_U_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/mac_messages_def.h b/openair2/COMMON/mac_messages_def.h index e3ef328017..11e8ab6f5e 100644 --- a/openair2/COMMON/mac_messages_def.h +++ b/openair2/COMMON/mac_messages_def.h @@ -60,3 +60,9 @@ MESSAGE_DEF(NR_RRC_MAC_CCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacCcch MESSAGE_DEF(NR_RRC_MAC_BCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacBcchDataInd, nr_rrc_mac_bcch_data_ind) MESSAGE_DEF(NR_RRC_MAC_SBCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacSBcchDataInd, nr_rrc_mac_sbcch_data_ind) +// Message to GNB_APP to update SIB19 satellite position information +MESSAGE_DEF(GNB_SAT_POSITION_UPDATE, MESSAGE_PRIORITY_MED, gnb_sat_position_update_t, gnb_sat_position_update) + +// nrUE +MESSAGE_DEF(NR_RRC_MAC_MEAS_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacMeasDataInd, nr_rrc_mac_meas_data_ind) + diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index ebbda2fc26..c5c18a12f2 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -31,6 +31,7 @@ #include #include "OCTET_STRING.h" +#include "NR_MAC_gNB/mac_config.h" //-------------------------------------------------------------------------------------------// // Defines to access message fields. @@ -43,6 +44,8 @@ #define NR_RRC_MAC_BCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_bcch_data_ind #define NR_RRC_MAC_SBCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_sbcch_data_ind +#define NR_RRC_MAC_MEAS_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_meas_data_ind + #define RRC_MAC_BCCH_MBMS_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_mbms_data_req #define RRC_MAC_BCCH_MBMS_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_bcch_mbms_data_ind @@ -61,6 +64,8 @@ #define RRC_MAC_DRX_CONFIG_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_drx_config_req +#define GNB_SAT_POSITION_UPDATE(mSGpTR) (mSGpTR)->ittiMsg.gnb_sat_position_update + // Some constants from "LAYER2/MAC/defs.h" #define BCCH_SDU_SIZE (512) #define BCCH_SDU_MBMS_SIZE (512) @@ -139,6 +144,14 @@ typedef struct NRRrcMacSBcchDataInd_s { uint8_t rsrp; } NRRrcMacSBcchDataInd; +typedef struct NRRrcMacMeasDataInd_s { + uint8_t gnb_index; + int rsrp_dBm; + uint16_t Nid_cell; + bool is_csi_meas; + bool is_neighboring_cell; +} NRRrcMacMeasDataInd; + typedef struct RrcMacBcchMbmsDataReq_s { uint32_t frame; uint32_t sdu_size; diff --git a/openair2/COMMON/ngap_messages_def.h b/openair2/COMMON/ngap_messages_def.h index 62498698f2..98c1f82260 100644 --- a/openair2/COMMON/ngap_messages_def.h +++ b/openair2/COMMON/ngap_messages_def.h @@ -71,9 +71,13 @@ MESSAGE_DEF(NGAP_UE_CTXT_MODIFICATION_FAIL , MESSAGE_PRIORITY_MED, ngap_ue_ctxt_ MESSAGE_DEF(NGAP_PDUSESSION_SETUP_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_setup_resp_t , ngap_pdusession_setup_resp) MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_resp_t , ngap_pdusession_modify_resp) MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, ngap_pdusession_release_resp_t , ngap_pdusession_release_resp) -MESSAGE_DEF(NGAP_PATH_SWITCH_REQ , MESSAGE_PRIORITY_MED, ngap_path_switch_req_t , ngap_path_switch_req) -MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_ACK , MESSAGE_PRIORITY_MED, ngap_path_switch_req_ack_t , ngap_path_switch_req_ack) -MESSAGE_DEF(NGAP_PDUSESSION_MODIFICATION_IND , MESSAGE_PRIORITY_MED, ngap_pdusession_modification_ind_t , ngap_pdusession_modification_ind) +MESSAGE_DEF(NGAP_HANDOVER_REQUIRED, MESSAGE_PRIORITY_MED, ngap_handover_required_t, ngap_handover_required) +MESSAGE_DEF(NGAP_HANDOVER_FAILURE, MESSAGE_PRIORITY_MED, ngap_handover_failure_t, ngap_handover_failure) +MESSAGE_DEF(NGAP_HANDOVER_REQUEST_ACKNOWLEDGE, MESSAGE_PRIORITY_MED, ngap_handover_request_ack_t, ngap_handover_request_ack) +MESSAGE_DEF(NGAP_HANDOVER_NOTIFY, MESSAGE_PRIORITY_MED, ngap_handover_notify_t, ngap_handover_notify) +MESSAGE_DEF(NGAP_HANDOVER_CANCEL, MESSAGE_PRIORITY_MED, ngap_handover_cancel_t, ngap_handover_cancel) +MESSAGE_DEF(NGAP_UL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_ul_ran_status_transfer) +MESSAGE_DEF(NGAP_DL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_dl_ran_status_transfer) /* NGAP -> RRC messages */ MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas ) @@ -84,6 +88,9 @@ MESSAGE_DEF(NGAP_PDUSESSION_SETUP_REQ , MESSAGE_PRIORITY_MED, ngap_pd MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_REQ , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_req_t , ngap_pdusession_modify_req ) MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_COMMAND , MESSAGE_PRIORITY_MED, ngap_pdusession_release_command_t , ngap_pdusession_release_command) MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_COMMAND, MESSAGE_PRIORITY_MED, ngap_ue_release_command_t , ngap_ue_release_command) +MESSAGE_DEF(NGAP_HANDOVER_REQUEST, MESSAGE_PRIORITY_MED, ngap_handover_request_t, ngap_handover_request) +MESSAGE_DEF(NGAP_HANDOVER_COMMAND, MESSAGE_PRIORITY_MED, ngap_handover_command_t, ngap_handover_command) +MESSAGE_DEF(NGAP_HANDOVER_CANCEL_ACK, MESSAGE_PRIORITY_MED, ngap_handover_cancel_ack_t, ngap_handover_cancel_ack) /* NGAP <-> RRC messages (can be initiated either by MME or gNB) */ MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_REQ , MESSAGE_PRIORITY_MED, ngap_ue_release_req_t , ngap_ue_release_req) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index b899bb33e2..2c4b0f8a0a 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -65,11 +65,22 @@ #define NGAP_PDUSESSION_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_setup_req #define NGAP_PDUSESSION_MODIFY_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_modify_req #define NGAP_PAGING_IND(mSGpTR) (mSGpTR)->ittiMsg.ngap_paging_ind +#define NGAP_HANDOVER_REQUIRED(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_required +#define NGAP_HANDOVER_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_failure +#define NGAP_HANDOVER_REQUEST(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_request +#define NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_request_ack +#define NGAP_HANDOVER_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_command +#define NGAP_HANDOVER_NOTIFY(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_notify +#define NGAP_HANDOVER_CANCEL(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_cancel +#define NGAP_HANDOVER_CANCEL_ACK(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_cancel_ack #define NGAP_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_release_req #define NGAP_PDUSESSION_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_release_command #define NGAP_PDUSESSION_RELEASE_RESPONSE(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_release_resp +#define NGAP_UL_RAN_STATUS_TRANSFER(mSGpTR) (mSGpTR)->ittiMsg.ngap_ul_ran_status_transfer +#define NGAP_DL_RAN_STATUS_TRANSFER(mSGpTR) (mSGpTR)->ittiMsg.ngap_dl_ran_status_transfer + //-------------------------------------------------------------------------------------------// /* Length of the transport layer address string @@ -80,7 +91,7 @@ #define NGAP_MAX_NB_AMF_IP_ADDRESS 10 #define NGAP_IMSI_LENGTH 16 -#define QOSFLOW_MAX_VALUE 64 +#define NGAP_MAX_NO_TAI_PAGING 16 // 9.2.4.1 3GPP TS 38.413 /* Security key length used within gNB * Even if only 16 bytes will be effectively used, @@ -128,43 +139,6 @@ typedef struct ngap_ambr_s { bitrate_t br_dl; } ngap_ambr_t; -typedef enum ngap_priority_level_s { - NGAP_PRIORITY_LEVEL_SPARE = 0, - NGAP_PRIORITY_LEVEL_HIGHEST = 1, - NGAP_PRIORITY_LEVEL_2 = 2, - NGAP_PRIORITY_LEVEL_3 = 3, - NGAP_PRIORITY_LEVEL_4 = 4, - NGAP_PRIORITY_LEVEL_5 = 5, - NGAP_PRIORITY_LEVEL_6 = 6, - NGAP_PRIORITY_LEVEL_7 = 7, - NGAP_PRIORITY_LEVEL_8 = 8, - NGAP_PRIORITY_LEVEL_9 = 9, - NGAP_PRIORITY_LEVEL_10 = 10, - NGAP_PRIORITY_LEVEL_11 = 11, - NGAP_PRIORITY_LEVEL_12 = 12, - NGAP_PRIORITY_LEVEL_13 = 13, - NGAP_PRIORITY_LEVEL_LOWEST = 14, - NGAP_PRIORITY_LEVEL_NO_PRIORITY = 15 -} ngap_priority_level_t; - -typedef enum ngap_pre_emp_capability_e { - NGAP_PRE_EMPTION_CAPABILITY_SHALL_NOT_TRIGGER_PREEMPTION = 0, - NGAP_PRE_EMPTION_CAPABILITY_MAY_TRIGGER_PREEMPTION = 1, - NGAP_PRE_EMPTION_CAPABILITY_MAX, -} ngap_pre_emp_capability_t; - -typedef enum ngap_pre_emp_vulnerability_e { - NGAP_PRE_EMPTION_VULNERABILITY_NOT_PREEMPTABLE = 0, - NGAP_PRE_EMPTION_VULNERABILITY_PREEMPTABLE = 1, - NGAP_PRE_EMPTION_VULNERABILITY_MAX, -} ngap_pre_emp_vulnerability_t; - -typedef struct ngap_allocation_retention_priority_s { - ngap_priority_level_t priority_level; - ngap_pre_emp_capability_t pre_emp_capability; - ngap_pre_emp_vulnerability_t pre_emp_vulnerability; -} ngap_allocation_retention_priority_t; - typedef struct ngap_security_capabilities_s { uint16_t nRencryption_algorithms; uint16_t nRintegrity_algorithms; @@ -192,26 +166,12 @@ typedef enum ngap_rrc_establishment_cause_e { NGAP_RRC_CAUSE_LAST } ngap_rrc_establishment_cause_t; -typedef struct pdusession_level_qos_parameter_s { - uint8_t qfi; - uint64_t fiveQI; - uint64_t qos_priority; - fiveQI_t fiveQI_type; - ngap_allocation_retention_priority_t allocation_retention_priority; -} pdusession_level_qos_parameter_t; - typedef struct fiveg_s_tmsi_s { uint16_t amf_set_id; uint8_t amf_pointer; uint32_t m_tmsi; } fiveg_s_tmsi_t; -typedef struct ngap_tai_plmn_identity_s { - uint16_t mcc; - uint16_t mnc; - uint8_t mnc_digit_length; -} ngap_plmn_identity_t; - typedef struct ngap_ue_paging_identity_s { fiveg_s_tmsi_t s_tmsi; } ngap_ue_paging_identity_t; @@ -228,38 +188,17 @@ typedef struct ngap_ue_identity_s { } ngap_ue_identity_t; typedef struct ngap_mobility_restriction_s{ - ngap_plmn_identity_t serving_plmn; + plmn_id_t serving_plmn; }ngap_mobility_restriction_t; -typedef enum pdu_session_type_e { - PDUSessionType_ipv4 = 0, - PDUSessionType_ipv6 = 1, - PDUSessionType_ipv4v6 = 2, - PDUSessionType_ethernet = 3, - PDUSessionType_unstructured = 4 -}pdu_session_type_t; - -typedef struct pdusession_s { - /* Unique pdusession_id for the UE. */ - int pdusession_id; - byte_array_t nas_pdu; - byte_array_t pdusessionTransfer; +/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ +typedef struct { uint8_t nb_qos; - /* Quality of service for this pdusession */ - pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; - /* The transport layer address for the IP packets */ + pdusession_level_qos_parameter_t qos[MAX_QOS_FLOWS]; pdu_session_type_t pdu_session_type; - transport_layer_addr_t upf_addr; - /* Outgoing (UL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gtp_teid; - /* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gNB_teid_N3; - transport_layer_addr_t gNB_addr_N3; - /* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t UPF_teid_N3; - transport_layer_addr_t UPF_addr_N3; - nssai_t nssai; -} pdusession_t; + // UPF endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_incoming; +} pdusession_transfer_t; typedef enum pdusession_qosflow_mapping_ind_e{ QOSFLOW_MAPPING_INDICATION_UL = 0, @@ -278,30 +217,17 @@ typedef struct pdusession_setup_s { /* The transport layer address for the IP packets */ uint8_t pdu_session_type; - transport_layer_addr_t gNB_addr; - /* Incoming NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ - uint32_t gtp_teid; + // NG-U (N3) Tunnel Endpoint on the RAN side + gtpu_tunnel_t n3_outgoing; /* qos flow list number */ uint8_t nb_of_qos_flow; /* qos flow list(1 ~ 64) */ - pdusession_associate_qosflow_t associated_qos_flows[QOSFLOW_MAX_VALUE]; + pdusession_associate_qosflow_t associated_qos_flows[MAX_QOS_FLOWS]; } pdusession_setup_t; -typedef struct pdusession_tobeswitched_s { - /* Unique pdusession_id for the UE. */ - uint8_t pdusession_id; - - /* The transport layer address for the IP packets */ - uint8_t pdu_session_type; - transport_layer_addr_t upf_addr; - - /* S-GW Tunnel endpoint identifier */ - uint32_t gtp_teid; -} pdusession_tobeswitched_t; - typedef struct qos_flow_tobe_modified_s { uint8_t qfi; // 0~63 } qos_flow_tobe_modified_t; @@ -313,7 +239,7 @@ typedef struct pdusession_modify_s { uint8_t nb_of_qos_flow; // qos_flow_add_or_modify - qos_flow_tobe_modified_t qos[QOSFLOW_MAX_VALUE]; + qos_flow_tobe_modified_t qos[MAX_QOS_FLOWS]; } pdusession_modify_t; /* Cause (9.3.1.2 of 3GPP TS 38.413) */ @@ -510,6 +436,242 @@ typedef struct ngap_uplink_nas_s { byte_array_t nas_pdu; } ngap_uplink_nas_t; +typedef struct target_cell_id_s { + plmn_id_t plmn_identity; + uint32_t nrCellIdentity; +} cell_id_t; + +typedef struct target_ran_node_id_s { + uint32_t targetgNBId; + plmn_id_t plmn_identity; + uint32_t tac; +} target_ran_node_id_t; + +/* 3GPP TS 38.413 9.3.1.29 */ +typedef struct { + // QoS Flow Identifier + uint8_t qfi; +} qosflow_info_t; + +/* 3GPP TS 38.413 9.3.1.29 */ +typedef struct { + // PDU Session ID + uint8_t pdusession_id; + // QoS Flow Information List + uint8_t nb_of_qos_flow; + qosflow_info_t qos_flow_info[MAX_QOS_FLOWS]; +} pdusession_resource_info_t; + +/* 3GPP TS 38.413 9.3.1.97 */ +typedef struct { + // Global Cell ID + cell_id_t id; + // Cell type + uint8_t type; + // Time UE Stayed in Cell + long time_in_cell; + // Cause + ngap_cause_t *cause; +} last_visited_ngran_cell_info_t; + +/* 3GPP TS 38.413 9.3.1.29 */ +typedef struct { + // RRC Container: HandoverPreparationInformation message + byte_array_t handoverInfo; + // Target Cell ID + cell_id_t targetCellId; + // PDU Session Resource Information List + uint16_t nb_pdu_session_resource; + pdusession_resource_info_t pdu_session_resource[NGAP_MAX_PDU_SESSION]; + // UE History Information + last_visited_ngran_cell_info_t ue_history_info; +} source_to_target_transparent_container_t; + +typedef enum { + HANDOVER_TYPE_INTRA5GS, // Intra5GS: NG-RAN node to NG-RAN node + HANDOVER_TYPE_5GSTOEPS, // 5GStoEPS: NG-RAN node to eNB + HANDOVER_TYPE_EPSTO5GS, // EPSto5GS: eNB to NG-RAN node + HANDOVER_TYPE_5GSTOUTRA, // 5GStoUTRA: NG-RAN node to UTRA +} ho_type_t; + +/* 3GPP TS 38.413 9.2.3.1 */ +typedef struct { + // PDU Session ID + uint8_t pdusession_id; +} pdusession_resource_t; + +/* 3GPP TS 38.413 9.2.3.1 */ +typedef struct { + // RAN UE NGAP ID + uint32_t gNB_ue_ngap_id; + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id; + // Handover Type + ho_type_t handoverType; + // Cause + ngap_cause_t cause; + // Target ID + target_ran_node_id_t target_gnb_id; + // PDU Session Resource List + uint16_t nb_of_pdusessions; + pdusession_resource_t pdusessions[NGAP_MAX_PDU_SESSION]; + // Source to Target Transparent Container + source_to_target_transparent_container_t *source2target; +} ngap_handover_required_t; + +/* 3GPP TS 38.413 9.2.3.6 */ +typedef struct { + // AMF UE NGAP ID (M) + uint64_t amf_ue_ngap_id; + // Cause (M) + ngap_cause_t cause; +} ngap_handover_failure_t; + +typedef struct { + // Next-Hop NH + uint8_t next_hop[SECURITY_KEY_LENGTH]; + // Next Hop Chaining Count + uint8_t next_hop_chain_count; +} ngap_security_context_t; + +/* Handover Request (3GPP TS 38.413 9.2.3.4) + PDU Session Resource Setup Item */ +typedef struct { + // PDU Session ID + uint8_t pdusession_id; + pdu_session_type_t pdu_session_type; + // S-NSSAI + nssai_t nssai; + // Handover Required Transfer + pdusession_transfer_t pdusessionTransfer; +} ho_request_pdusession_t; + +/* 3GPP TS 38.413 9.2.3.4 */ +typedef struct { + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id; + // Handover Type + ho_type_t ho_type; + // Cause + ngap_cause_t cause; + // UE Aggregate Maximum Bit Rate + ngap_ambr_t ue_ambr; + // UE Security Capabilities + ngap_security_capabilities_t security_capabilities; + // Security Context + ngap_security_context_t security_context; + // PDU Session Resource Setup List + uint16_t nb_of_pdusessions; + ho_request_pdusession_t pduSessionResourceSetupList[NGAP_MAX_PDU_SESSION]; + // Allowed NSSAI + uint8_t nb_allowed_nssais; + nssai_t allowed_nssai[8]; + // Source to Target Transparent Container contents + uint64_t nr_cell_id; + byte_array_t ue_ho_prep_info; + byte_array_t ue_cap; + // Mobility Restriction List + ngap_mobility_restriction_t *mobility_restriction; + // GUAMI + nr_guami_t guami; +} ngap_handover_request_t; + +/* 9.3.4.11 3GPP TS 38.413 */ +typedef struct { + // QoS Flow Setup Response List + uint8_t nb_of_qos_flow; + pdusession_associate_qosflow_t qos_setup_list[MAX_QOS_FLOWS]; + // DL NG-U UP TNL Information + uint32_t gtp_teid; + transport_layer_addr_t gNB_addr; +} ho_request_ack_transfer_t; + +/* 9.2.3.5 3GPP TS 38.413 */ +typedef struct { + // PDU Session ID (M) + uint8_t pdu_session_id; + // Handover Request Acknowledge Transfer (M) + ho_request_ack_transfer_t ack_transfer; +} pdu_session_resource_admitted_t; + +typedef struct { + // AMF UE NGAP ID + uint32_t gNB_ue_ngap_id; + // RAN UE NGAP ID + uint64_t amf_ue_ngap_id; + // PDU Session Resource Admitted List + pdu_session_resource_admitted_t pdusessions[NGAP_MAX_PDU_SESSION]; + uint16_t nb_of_pdusessions; + // Target to Source Transparent Container + byte_array_t target2source; +} ngap_handover_request_ack_t; + +/* 9.3.4.10 3GPP TS 38.413 */ +typedef struct { + // QoS Flow to be Forwarded List + uint8_t nb_of_qos_flow; + pdusession_associate_qosflow_t qos_setup_list[MAX_QOS_FLOWS]; + // UL Forwarding UP TNL Information + uint32_t gtp_teid; + transport_layer_addr_t gNB_addr; +} ho_command_transfer_t; + +typedef struct { + // PDU Session ID (M) + uint8_t pdusession_id; + // Handover Command Transfer (M) + ho_command_transfer_t ho_command_transfer; +} pdusession_resource_handover_t; + +typedef struct { + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id; + // RAN UE NGAP ID + uint32_t gNB_ue_ngap_id; + // Handover Type + ho_type_t handoverType; + // PDU Session Resource Handover List + uint16_t nb_of_pdusessions; + pdusession_resource_handover_t pdu_sessions[NGAP_MAX_PDU_SESSION]; + // Target to Source Transparent Container + byte_array_t handoverCommand; +} ngap_handover_command_t; + +/* 9.3.1.16 3GPP TS 38.413 */ +typedef struct { + // NR user location information + target_ran_node_id_t target_ng_ran; + uint32_t nrCellIdentity; +} user_location_information_t; + +/* 9.2.3.7 3GPP TS 38.413 */ +typedef struct { + // RAN UE NGAP ID + uint32_t gNB_ue_ngap_id; + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id; + // User Location Information + user_location_information_t user_info; +} ngap_handover_notify_t; + +/* 9.2.3.11 3GPP TS 38.413 */ +typedef struct { + // RAN UE NGAP ID + uint32_t gNB_ue_ngap_id; + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id; + // Cause + ngap_cause_t cause; +} ngap_handover_cancel_t; + +/* 9.2.3.12 3GPP TS 38.413 */ +typedef struct { + // RAN UE NGAP ID + uint32_t gNB_ue_ngap_id; + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id; +} ngap_handover_cancel_ack_t; + typedef struct ngap_ue_cap_info_ind_s { uint32_t gNB_ue_ngap_id; byte_array_t ue_radio_cap; @@ -519,12 +681,12 @@ typedef struct ngap_initial_context_setup_resp_s { uint32_t gNB_ue_ngap_id; /* Number of pdusession setup-ed in the list */ - uint8_t nb_of_pdusessions; + uint16_t nb_of_pdusessions; /* list of pdusession setup-ed by RRC layers */ pdusession_setup_t pdusessions[NGAP_MAX_PDU_SESSION]; /* Number of pdusession failed to be setup in list */ - uint8_t nb_of_pdusessions_failed; + uint16_t nb_of_pdusessions_failed; /* list of pdusessions that failed to be setup */ pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION]; } ngap_initial_context_setup_resp_t; @@ -580,6 +742,13 @@ typedef struct ngap_downlink_nas_s { byte_array_t nas_pdu; } ngap_downlink_nas_t; +/* PDU Session Resource Setup/Modify Request Item */ +typedef struct { + int pdusession_id; + byte_array_t nas_pdu; + nssai_t nssai; + pdusession_transfer_t pdusessionTransfer; +} pdusession_resource_item_t; typedef struct ngap_initial_context_setup_req_s { /* UE id for initial connection to NGAP */ @@ -588,6 +757,7 @@ typedef struct ngap_initial_context_setup_req_s { uint64_t amf_ue_ngap_id; /* UE aggregate maximum bitrate */ + bool has_ue_ambr; ngap_ambr_t ue_ambr; /* guami */ @@ -604,9 +774,9 @@ typedef struct ngap_initial_context_setup_req_s { uint8_t security_key[SECURITY_KEY_LENGTH]; /* Number of pdusession to be setup in the list */ - uint8_t nb_of_pdusessions; - /* list of pdusession to be setup by RRC layers */ - pdusession_t pdusession_param[NGAP_MAX_PDU_SESSION]; + uint16_t nb_of_pdusessions; + // PDU Session Resource Setup Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; /* Mobility Restriction List */ uint8_t mobility_restriction_flag; @@ -626,10 +796,10 @@ typedef struct ngap_paging_ind_s { ngap_cn_domain_t cn_domain; /* PLMN_identity in TAI of Paging*/ - ngap_plmn_identity_t plmn_identity[256]; + plmn_id_t plmn_identity[NGAP_MAX_NO_TAI_PAGING]; /* TAC in TAIList of Paging*/ - int16_t tac[256]; + int16_t tac[NGAP_MAX_NO_TAI_PAGING]; /* size of TAIList*/ int16_t tai_size; @@ -640,13 +810,6 @@ typedef struct ngap_paging_ind_s { ngap_paging_priority_t paging_priority; } ngap_paging_ind_t; -typedef struct { - /* Unique pdusession_id for the UE. */ - int pdusession_id; - byte_array_t nas_pdu; - byte_array_t pdusessionTransfer; -} pdusession_setup_req_t; - typedef struct ngap_pdusession_setup_req_s { /* UE id for initial connection to NGAP */ uint32_t gNB_ue_ngap_id; @@ -659,12 +822,13 @@ typedef struct ngap_pdusession_setup_req_s { nssai_t allowed_nssai[8]; /* Number of pdusession to be setup in the list */ - uint8_t nb_pdusessions_tosetup; + uint16_t nb_pdusessions_tosetup; - /* E RAB setup request */ - pdusession_t pdusession_setup_params[NGAP_MAX_PDU_SESSION]; + // PDU Session Resource Setup Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; /* UE Aggregated Max Bitrates */ + bool has_ue_ambr; ngap_ambr_t ueAggMaxBitRate; } ngap_pdusession_setup_req_t; @@ -672,88 +836,16 @@ typedef struct ngap_pdusession_setup_req_s { typedef struct ngap_pdusession_setup_resp_s { uint32_t gNB_ue_ngap_id; /* Number of pdusession setup-ed in the list */ - uint8_t nb_of_pdusessions; + uint16_t nb_of_pdusessions; /* list of pdusession setup-ed by RRC layers */ pdusession_setup_t pdusessions[NGAP_MAX_PDU_SESSION]; /* Number of pdusession failed to be setup in list */ - uint8_t nb_of_pdusessions_failed; + uint16_t nb_of_pdusessions_failed; /* list of pdusessions that failed to be setup */ pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_setup_resp_t; -typedef struct ngap_path_switch_req_s { - uint32_t gNB_ue_ngap_id; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_of_pdusessions; - - /* list of pdusession setup-ed by RRC layers */ - pdusession_setup_t pdusessions_tobeswitched[NGAP_MAX_PDU_SESSION]; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - nr_guami_t ue_guami; - - uint16_t ue_initial_id; - /* Security algorithms */ - ngap_security_capabilities_t security_capabilities; - -} ngap_path_switch_req_t; - -typedef struct ngap_path_switch_req_ack_s { - - /* UE id for initial connection to NGAP */ - uint16_t ue_initial_id; - - uint32_t gNB_ue_ngap_id; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - /* UE aggregate maximum bitrate */ - ngap_ambr_t ue_ambr; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_pdusessions_tobeswitched; - - /* list of pdusession to be switched by RRC layers */ - pdusession_tobeswitched_t pdusessions_tobeswitched[NGAP_MAX_PDU_SESSION]; - - /* Number of pdusessions to be released by RRC */ - uint8_t nb_pdusessions_tobereleased; - - /* list of pdusessions to be released */ - pdusession_failed_t pdusessions_tobereleased[NGAP_MAX_PDU_SESSION]; - - /* Security key */ - int next_hop_chain_count; - uint8_t next_security_key[SECURITY_KEY_LENGTH]; - -} ngap_path_switch_req_ack_t; - -typedef struct ngap_pdusession_modification_ind_s { - - uint32_t gNB_ue_ngap_id; - - /* AMF UE id */ - uint64_t amf_ue_ngap_id; - - /* Number of pdusession setup-ed in the list */ - uint8_t nb_of_pdusessions_tobemodified; - - uint8_t nb_of_pdusessions_nottobemodified; - - /* list of pdusession setup-ed by RRC layers */ - pdusession_setup_t pdusessions_tobemodified[NGAP_MAX_PDU_SESSION]; - - pdusession_setup_t pdusessions_nottobemodified[NGAP_MAX_PDU_SESSION]; - - uint16_t ue_initial_id; - -} ngap_pdusession_modification_ind_t; - // NGAP --> RRC messages typedef struct ngap_ue_release_command_s { @@ -773,7 +865,7 @@ typedef struct pdusession_release_s { typedef struct ngap_ue_release_req_s { uint32_t gNB_ue_ngap_id; /* Number of pdusession resource in the list */ - uint8_t nb_of_pdusessions; + uint16_t nb_of_pdusessions; /* list of pdusession resource by RRC layers */ pdusession_release_t pdusessions[NGAP_MAX_PDU_SESSION]; ngap_cause_t cause; @@ -787,22 +879,22 @@ typedef struct ngap_pdusession_modify_req_s { uint32_t gNB_ue_ngap_id; /* Number of pdusession to be modify in the list */ - uint8_t nb_pdusessions_tomodify; + uint16_t nb_pdusessions_tomodify; - /* pdu session modify request */ - pdusession_t pdusession_modify_params[NGAP_MAX_PDU_SESSION]; + // PDU Session Resource Modify Request List + pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_modify_req_t; typedef struct ngap_pdusession_modify_resp_s { uint32_t gNB_ue_ngap_id; /* Number of pdusession modify-ed in the list */ - uint8_t nb_of_pdusessions; + uint16_t nb_of_pdusessions; /* list of pdusession modify-ed by RRC layers */ pdusession_modify_t pdusessions[NGAP_MAX_PDU_SESSION]; /* Number of pdusession failed to be modify in list */ - uint8_t nb_of_pdusessions_failed; + uint16_t nb_of_pdusessions_failed; /* list of pdusessions that failed to be modify */ pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION]; } ngap_pdusession_modify_resp_t; @@ -818,7 +910,7 @@ typedef struct ngap_pdusession_release_command_s { byte_array_t nas_pdu; /* Number of pdusession to be released in the list */ - uint8_t nb_pdusessions_torelease; + uint16_t nb_pdusessions_torelease; /* PDUSession release command */ pdusession_release_t pdusession_release_params[NGAP_MAX_PDU_SESSION]; @@ -826,23 +918,56 @@ typedef struct ngap_pdusession_release_command_s { } ngap_pdusession_release_command_t; typedef struct ngap_pdusession_release_resp_s { - /* AMF UE id */ + // AMF UE NGAP ID uint64_t amf_ue_ngap_id; - - /* gNB ue ngap id as initialized by NGAP layer */ - uint32_t gNB_ue_ngap_id; - - /* Number of pdusession released in the list */ - uint8_t nb_of_pdusessions_released; - - /* list of pdusessions released */ + // RAN UE NGAP ID + uint32_t gNB_ue_ngap_id; + // PDU Session Resource Released List + uint16_t nb_of_pdusessions_released; pdusession_release_t pdusession_release[NGAP_MAX_PDU_SESSION]; - - /* Number of pdusession failed to be released in list */ - uint8_t nb_of_pdusessions_failed; - /* list of pdusessions that failed to be released */ - pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION]; - } ngap_pdusession_release_resp_t; +/** 9.2.3.14 Uplink RAN Status Transfer (3GPP TS 38.413) + * COUNT value used for both UL and DL PDCP SN + HFN (12-bit or 18-bit SN) */ + +// Indicates PDCP SN length +typedef enum { NGAP_SN_LENGTH_12 = 0, NGAP_SN_LENGTH_18 = 1 } ngap_sn_length_t; + +typedef struct { + // PDCP Sequence Number + uint32_t pdcp_sn; + // Hyper Frame Number + uint32_t hfn; + // SN length + ngap_sn_length_t sn_len; +} ngap_drb_count_value_t; + +// DRBs Subject to Status Transfer Item +typedef struct { + // DRB ID + uint8_t drb_id; + // UL COUNT value + ngap_drb_count_value_t ul_count; + // DL COUNT value + ngap_drb_count_value_t dl_count; +} ngap_drb_status_t; + +// RAN Status Transfer Transparent Container (9.3.1.108) +typedef struct { + // Number of DRBs in the list + uint8_t nb_drb; + // DRB Status List + ngap_drb_status_t drb_status_list[MAX_DRBS_PER_UE]; +} ngap_ran_status_container_t; + +// Uplink RAN Status Transfer message (9.2.3.14) +typedef struct { + // AMF UE NGAP ID (Mandatory) + uint64_t amf_ue_ngap_id; + // RAN UE NGAP ID (Mandatory) + uint32_t gnb_ue_ngap_id; + // RAN Status Transfer Transparent Container (Mandatory) + ngap_ran_status_container_t ran_status; +} ngap_ran_status_transfer_t; + #endif /* NGAP_MESSAGES_TYPES_H_ */ diff --git a/openair2/COMMON/pdcp_messages_def.h b/openair2/COMMON/pdcp_messages_def.h index 5392c9e04d..da7d87f142 100644 --- a/openair2/COMMON/pdcp_messages_def.h +++ b/openair2/COMMON/pdcp_messages_def.h @@ -31,7 +31,6 @@ MESSAGE_DEF(RRC_DCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataReq, rrc_dcch_data_req) MESSAGE_DEF(RRC_DCCH_DATA_IND, MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataInd, rrc_dcch_data_ind) MESSAGE_DEF(RRC_PCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcPcchDataReq, rrc_pcch_data_req) -MESSAGE_DEF(RRC_NRUE_CAP_INFO_IND, MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataInd, rrc_nrue_cap_info_ind) MESSAGE_DEF(RRC_DCCH_DATA_COPY_IND, MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataInd, rrc_dcch_data_copy_ind) // gNB diff --git a/openair2/COMMON/pdcp_messages_types.h b/openair2/COMMON/pdcp_messages_types.h index b97fdef986..cf7a1f8f0c 100644 --- a/openair2/COMMON/pdcp_messages_types.h +++ b/openair2/COMMON/pdcp_messages_types.h @@ -34,7 +34,6 @@ #define RRC_DCCH_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_dcch_data_req #define RRC_DCCH_DATA_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_dcch_data_ind #define RRC_PCCH_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_pcch_data_req -#define RRC_NRUE_CAP_INFO_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_nrue_cap_info_ind #define RRC_DCCH_DATA_COPY_IND(mSGpTR) (mSGpTR)->ittiMsg.rrc_dcch_data_copy_ind // gNB diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index 67aadb2869..7dda028565 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -67,8 +67,6 @@ MESSAGE_DEF(NAS_5GMM_IND, MESSAGE_PRIORITY_MED, nas_5gmm_ind_t, nas_5gmm_ind) MESSAGE_DEF(NAS_RAB_ESTABLI_RSP, MESSAGE_PRIORITY_MED, rab_establish_rsp_t, nas_rab_est_rsp) -MESSAGE_DEF(NAS_OAI_TUN_NSA, MESSAGE_PRIORITY_MED, nas_oai_tun_nsa_t, nas_oai_tun_nsa) - // UE: RRC -> NAS messages MESSAGE_DEF(NAS_CELL_SELECTION_CNF, MESSAGE_PRIORITY_MED, cell_info_cnf_t, nas_cell_selection_cnf) MESSAGE_DEF(NAS_CELL_SELECTION_IND, MESSAGE_PRIORITY_MED, cell_info_ind_t, nas_cell_selection_ind) @@ -85,13 +83,6 @@ MESSAGE_DEF(NAS_INIT_NOS1_IF, MESSAGE_PRIORITY_MED, nas_nos1_msg_t, nas_init_nos MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process) MESSAGE_DEF(NRRRC_FRAME_PROCESS, MESSAGE_PRIORITY_MED, NRRrcFrameProcess, nr_rrc_frame_process) -// UE: RRC -> MAC messages -MESSAGE_DEF(NR_MAC_RRC_CONFIG_RESET, MESSAGE_PRIORITY_MED, nr_mac_rrc_config_reset_t, nr_mac_rrc_config_reset) -MESSAGE_DEF(NR_MAC_RRC_CONFIG_CG, MESSAGE_PRIORITY_MED, nr_mac_rrc_config_cg_t, nr_mac_rrc_config_cg) -MESSAGE_DEF(NR_MAC_RRC_CONFIG_MIB, MESSAGE_PRIORITY_MED, nr_mac_rrc_config_mib_t, nr_mac_rrc_config_mib) -MESSAGE_DEF(NR_MAC_RRC_CONFIG_SIB1, MESSAGE_PRIORITY_MED, nr_mac_rrc_config_sib1_t, nr_mac_rrc_config_sib1) -MESSAGE_DEF(NR_MAC_RRC_CONFIG_OTHER_SIB, MESSAGE_PRIORITY_MED, nr_mac_rrc_config_other_sib_t, nr_mac_rrc_config_other_sib) - // eNB: RLC -> RRC messages MESSAGE_DEF(RLC_SDU_INDICATION, MESSAGE_PRIORITY_MED, RlcSduIndication, rlc_sdu_indication) MESSAGE_DEF(NAS_PDU_SESSION_REQ, MESSAGE_PRIORITY_MED, nas_pdu_session_req_t, nas_pdu_session_req) diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index a3db7ebba6..255da9f189 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -103,13 +103,7 @@ #define RLC_SDU_INDICATION(mSGpTR) (mSGpTR)->ittiMsg.rlc_sdu_indication #define NRDuDlReq(mSGpTR) (mSGpTR)->ittiMsg.nr_du_dl_req -#define NAS_OAI_TUN_NSA(mSGpTR) (mSGpTR)->ittiMsg.nas_oai_tun_nsa #define NAS_PDU_SESSION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_pdu_session_req -#define NR_MAC_RRC_CONFIG_RESET(mSGpTR) (mSGpTR)->ittiMsg.nr_mac_rrc_config_reset -#define NR_MAC_RRC_CONFIG_CG(mSGpTR) (mSGpTR)->ittiMsg.nr_mac_rrc_config_cg -#define NR_MAC_RRC_CONFIG_MIB(mSGpTR) (mSGpTR)->ittiMsg.nr_mac_rrc_config_mib -#define NR_MAC_RRC_CONFIG_SIB1(mSGpTR) (mSGpTR)->ittiMsg.nr_mac_rrc_config_sib1 -#define NR_MAC_RRC_CONFIG_OTHER_SIB(mSGpTR) (mSGpTR)->ittiMsg.nr_mac_rrc_config_other_sib #define NR_RRC_RLC_MAXRTX(mSGpTR) (mSGpTR)->ittiMsg.nr_rlc_maxrtx_indication @@ -470,6 +464,11 @@ typedef struct { int ue_id; } RlcMaxRtxIndication; +typedef struct { + bool is_srb; + int rb_id; +} nr_mac_rrc_resume_rb_t; + typedef struct { NR_ReestablishmentCause_t cause; } nr_mac_rrc_config_reset_t; @@ -480,6 +479,7 @@ typedef struct { typedef struct { NR_BCCH_BCH_Message_t *bcch; int get_sib; + bool access_barred; } nr_mac_rrc_config_mib_t; typedef struct { NR_SIB1_t *sib1; @@ -490,4 +490,25 @@ typedef struct { bool can_start_ra; } nr_mac_rrc_config_other_sib_t; +enum payload_type { + NR_MAC_RRC_CONFIG_RESET, + NR_MAC_RRC_CONFIG_CG, + NR_MAC_RRC_CONFIG_MIB, + NR_MAC_RRC_CONFIG_SIB1, + NR_MAC_RRC_CONFIG_OTHER_SIB, + NR_MAC_RRC_RESUME_RB +}; + +typedef struct { + enum payload_type payload_type; + union { + nr_mac_rrc_config_reset_t config_reset; + nr_mac_rrc_config_cg_t config_cg; + nr_mac_rrc_config_mib_t config_mib; + nr_mac_rrc_config_sib1_t config_sib1; + nr_mac_rrc_config_other_sib_t config_other_sib; + nr_mac_rrc_resume_rb_t resume_rb; + } payload; +} nr_mac_rrc_message_t; + #endif /* RRC_MESSAGES_TYPES_H_ */ diff --git a/openair2/E1AP/e1ap_common.h b/openair2/E1AP/e1ap_common.h index 452762965c..6c556a6cc6 100644 --- a/openair2/E1AP/e1ap_common.h +++ b/openair2/E1AP/e1ap_common.h @@ -41,8 +41,6 @@ typedef struct e1ap_upcp_inst_s { e1ap_net_config_t net_config; } e1ap_upcp_inst_t; -extern int asn1_xer_print; - // forward declaration so we don't require E1AP ASN.1 when including this // header struct E1AP_E1AP_PDU; diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index 2c4f938a24..109b0008d3 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -360,12 +360,44 @@ static E1AP_UP_Parameters_t encode_dl_up_parameters(const int numUpParam, const return out; } +/** @brief PDCP SN Status Information (9.3.1.58 3GPP TS 38.463) */ +static E1AP_PDCP_SN_Status_Information_t encode_pdcp_status_info(const e1_pdcp_status_info_t *in) +{ + E1AP_PDCP_SN_Status_Information_t pdcp = {0}; + pdcp.pdcpStatusTransfer_DL.hFN = in->dl_count.hfn; + pdcp.pdcpStatusTransfer_DL.pDCP_SN = in->dl_count.sn; + pdcp.pdcpStatusTransfer_UL.countValue.hFN = in->ul_count.hfn; + pdcp.pdcpStatusTransfer_UL.countValue.pDCP_SN = in->ul_count.sn; + return pdcp; +} + +/** @brief PDCP SN Status Information (9.3.1.58 3GPP TS 38.463) */ +static e1_pdcp_status_info_t decode_pdcp_status_info(const E1AP_PDCP_SN_Status_Information_t* in) +{ + e1_pdcp_status_info_t out = {0}; + const E1AP_PDCP_Count_t *dl = &in->pdcpStatusTransfer_DL; + const E1AP_PDCP_Count_t *ul = &in->pdcpStatusTransfer_UL.countValue; + out.dl_count.hfn = dl->hFN; + out.dl_count.sn = dl->pDCP_SN; + out.ul_count.hfn = ul->hFN; + out.ul_count.sn = ul->pDCP_SN; + return out; +} + +static bool eq_pdcp_info(const e1_pdcp_status_info_t *a, const e1_pdcp_status_info_t *b) +{ + _E1_EQ_CHECK_INT(a->dl_count.hfn, b->dl_count.hfn); + _E1_EQ_CHECK_INT(a->dl_count.sn, b->dl_count.sn); + _E1_EQ_CHECK_INT(a->ul_count.hfn, b->ul_count.hfn); + _E1_EQ_CHECK_INT(a->ul_count.sn, b->ul_count.sn); + return true; +} + /** * @brief Equality check for DRB_nGRAN_to_setup_t */ static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_setup_t *b) { - bool result = true; _E1_EQ_CHECK_LONG(a->id, b->id); _E1_EQ_CHECK_INT(a->numCellGroups, b->numCellGroups); for (int i = 0; i < a->numCellGroups; i++) { @@ -373,11 +405,14 @@ static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_se } _E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup); for (int i = 0; i < a->numQosFlow2Setup; i++) { - result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); + if (!eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i])) + return false; } - result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config); - result &= eq_sdap_config(&a->sdap_config, &b->sdap_config); - return result; + if (!eq_pdcp_config(&a->pdcp_config, &b->pdcp_config)) + return false; + if (!eq_sdap_config(&a->sdap_config, &b->sdap_config)) + return false; + return true; } static void free_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg) @@ -1409,6 +1444,11 @@ static E1AP_PDU_Session_Resource_To_Modify_Item_t e1_encode_pdu_session_to_mod_i asn1cCalloc(drb2Mod->pDCP_SN_Status_Request, pDCP_SN_Status_Request); *pDCP_SN_Status_Request = E1AP_PDCP_SN_Status_Request_requested; } + // PDCP Status Information (O) + if (j->pdcp_status) { + asn1cCalloc(drb2Mod->pdcp_SN_Status_Information, pdcp); + *pdcp = encode_pdcp_status_info(j->pdcp_status); + } // DL UP TNL parameters (O) if (j->numDlUpParam > 0) { asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List); @@ -1658,7 +1698,7 @@ static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E drb->id = drb2Mod->dRB_ID; // PDCP Config (O) if (drb2Mod->pDCP_Configuration) { - drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config)); + drb->pdcp_config = calloc_or_fail(1, sizeof(*drb->pdcp_config)); CHECK_E1AP_DEC(e1_decode_pdcp_config(drb->pdcp_config, drb2Mod->pDCP_Configuration)); } // SDAP Config (O) @@ -1667,9 +1707,14 @@ static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E CHECK_E1AP_DEC(e1_decode_sdap_config(drb->sdap_config, drb2Mod->sDAP_Configuration)); } // PDCP SN Status Request (O) - if (drb2Mod->pDCP_SN_Status_Request) { + if (drb2Mod->pDCP_SN_Status_Request && *drb2Mod->pDCP_SN_Status_Request == E1AP_PDCP_SN_Status_Request_requested) { drb->pdcp_sn_status_requested = true; } + // PDCP SN Status Information (O) + if (drb2Mod->pdcp_SN_Status_Information) { + drb->pdcp_status = malloc_or_fail(sizeof(*drb->pdcp_status)); + *drb->pdcp_status = decode_pdcp_status_info(drb2Mod->pdcp_SN_Status_Information); + } // DL UP TNL parameters (O) if (drb2Mod->dL_UP_Parameters) { E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; @@ -1843,6 +1888,7 @@ static DRB_nGRAN_to_mod_t cp_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) cp = *msg; _E1_CP_OPTIONAL_IE(&cp, msg, sdap_config); _E1_CP_OPTIONAL_IE(&cp, msg, pdcp_config); + _E1_CP_OPTIONAL_IE(&cp, msg, pdcp_status); return cp; } @@ -1895,29 +1941,42 @@ static bool eq_security_ind(security_indication_t *a, security_indication_t *b) */ static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b) { - bool result = true; _E1_EQ_CHECK_LONG(a->id, b->id); _E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup); for (int i = 0; i < a->numQosFlow2Setup; i++) { - result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); + if (!eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i])) + return false; } _E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam); for (int i = 0; i < a->numDlUpParam; i++) { _E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id); - eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info); + if (!eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info)) + return false; } - if (a->pdcp_config && b->pdcp_config) - result &= eq_pdcp_config(a->pdcp_config, b->pdcp_config); - if (a->sdap_config && b->sdap_config) - result &= eq_sdap_config(a->sdap_config, b->sdap_config); - return result; + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, pdcp_config); + if (a->pdcp_config && b->pdcp_config) { + if (!eq_pdcp_config(a->pdcp_config, b->pdcp_config)) + return false; + } + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, sdap_config); + if (a->sdap_config && b->sdap_config) { + if (!eq_sdap_config(a->sdap_config, b->sdap_config)) + return false; + } + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, pdcp_status); + if (a->pdcp_status && b->pdcp_status) { + if (!eq_pdcp_info(a->pdcp_status, b->pdcp_status)) + return false; + } + return true; } /** @brief Equality check for PDU session item to modify */ static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_session_to_mod_t *b) { _E1_EQ_CHECK_LONG(a->sessionId, b->sessionId); - if (a->UP_TL_information && a->UP_TL_information) { + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, UP_TL_information); + if (a->UP_TL_information && b->UP_TL_information) { if (!eq_up_tl_info(a->UP_TL_information, b->UP_TL_information)) return false; } @@ -1931,8 +1990,10 @@ static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_ if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i])) return false; } + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, securityIndication); if (a->securityIndication && b->securityIndication) { - eq_security_ind(a->securityIndication, b->securityIndication); + if (!eq_security_ind(a->securityIndication, b->securityIndication)) + return false; } return true; } @@ -1984,6 +2045,7 @@ static void free_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) { free(msg->pdcp_config); free(msg->sdap_config); + free(msg->pdcp_status); } /* Free PDU Session to modify item */ @@ -2111,6 +2173,13 @@ struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_response(const e1ap_bearer_mo asn1cSequenceAdd(drb_mod->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail); encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]); } + + // PDCP Status Information (O) + if (drb->pdcp_status) { + asn1cCalloc(drb_mod->pDCP_SN_Status_Information, pdcp); + *pdcp = encode_pdcp_status_info(drb->pdcp_status); + } + // UL UP Parameters (O) if (drb->numUpParam) drb_mod->uL_UP_Transport_Parameters = calloc_or_fail(1, sizeof(*drb_mod->uL_UP_Transport_Parameters)); @@ -2310,6 +2379,11 @@ bool decode_E1_bearer_context_mod_response(e1ap_bearer_modif_resp_t *out, const drbMod->qosFlowsFailed[i] = decode_qos_flow_failed_item(drbIE->flow_Failed_List->list.array[i]); } } + // PDCP Status Info (O) + if (drbIE->pDCP_SN_Status_Information) { + drbMod->pdcp_status = malloc_or_fail(sizeof(*drbMod->pdcp_status)); + *drbMod->pdcp_status = decode_pdcp_status_info(drbIE->pDCP_SN_Status_Information); + } } } // DRB Failed to Mod list @@ -2347,8 +2421,12 @@ e1ap_bearer_modif_resp_t cp_bearer_context_mod_response(const e1ap_bearer_modif_ // Shallow copy cp = *msg; // Deep copy PDU sessions modified items - for (int i = 0; i < msg->numPDUSessionsMod; i++) + for (int i = 0; i < msg->numPDUSessionsMod; i++) { cp.pduSessionMod[i] = cp_pdu_session_mod_item(&msg->pduSessionMod[i]); + for (int j = 0; j < msg->pduSessionMod[i].numDRBModified; j++) { + _E1_CP_OPTIONAL_IE(&cp.pduSessionMod[i].DRBnGRanModList[j], &msg->pduSessionMod[i].DRBnGRanModList[j], pdcp_status); + } + } return cp; } @@ -2374,8 +2452,10 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a _E1_EQ_CHECK_OPTIONAL_IE(pduA, pduB, integrityProtectionIndication, _E1_EQ_CHECK_INT); _E1_EQ_CHECK_OPTIONAL_PTR(pduA, pduB, ng_DL_UP_TL_info); - if (pduA->ng_DL_UP_TL_info && pduB->ng_DL_UP_TL_info) - eq_up_tl_info(pduA->ng_DL_UP_TL_info, pduB->ng_DL_UP_TL_info); + if (pduA->ng_DL_UP_TL_info && pduB->ng_DL_UP_TL_info) { + if (!eq_up_tl_info(pduA->ng_DL_UP_TL_info, pduB->ng_DL_UP_TL_info)) + return false; + } // DRB Modified List _E1_EQ_CHECK_INT(pduA->numDRBModified, pduB->numDRBModified); @@ -2387,6 +2467,11 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a for (int j = 0; j < drbModA->numQosFlowSetup; j++) { _E1_EQ_CHECK_LONG(drbModA->qosFlows[j].qfi, drbModB->qosFlows[j].qfi); } + _E1_EQ_CHECK_OPTIONAL_PTR(drbModA, drbModB, pdcp_status); + if (drbModA->pdcp_status && drbModB->pdcp_status) { + if (!eq_pdcp_info(drbModA->pdcp_status, drbModB->pdcp_status)) + return false; + } } // DRB Failed to Modify List @@ -2432,6 +2517,9 @@ void free_e1ap_context_mod_response(const e1ap_bearer_modif_resp_t *msg) free(msg->pduSessionMod[i].confidentialityProtectionIndication); free(msg->pduSessionMod[i].integrityProtectionIndication); free(msg->pduSessionMod[i].ng_DL_UP_TL_info); + for (int j = 0; j < msg->pduSessionMod[i].numDRBModified; j++) { + free(msg->pduSessionMod[i].DRBnGRanModList[j].pdcp_status); + } } } diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index a9fd7aa390..b168ff9e82 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -490,6 +490,13 @@ static void test_bearer_context_modification_request(void) .qos_params.qos_characteristics.non_dynamic.fiveqi = 9, }; + const e1_pdcp_status_info_t dummy_pdcp_status = { + .dl_count.hfn = 12, + .dl_count.sn = 34, + .ul_count.hfn = 56, + .ul_count.sn = 78, + }; + DRB_nGRAN_to_mod_t drb_to_mod = { .numDlUpParam = 1, .DlUpParamList[0].cell_group_id = MCG, @@ -497,10 +504,12 @@ static void test_bearer_context_modification_request(void) .id = 1, .pdcp_config = malloc_or_fail(sizeof(*drb_to_mod.pdcp_config)), .pdcp_sn_status_requested = true, + .pdcp_status = malloc_or_fail(sizeof(*drb_to_mod.pdcp_status)), .numQosFlow2Setup = 1, .qosFlows[0] = dummy_qos_flows, }; *drb_to_mod.pdcp_config = dummy_pdcp_config; + *drb_to_mod.pdcp_status = dummy_pdcp_status; pdu_session_to_mod_t pdusession_mod_item = { .sessionId = 1, @@ -592,12 +601,21 @@ const DRB_nGRAN_failed_t dummy_drb_failed = { */ static void test_bearer_context_modification_response(void) { + const e1_pdcp_status_info_t dummy_pdcp_status = { + .dl_count.hfn = 12, + .dl_count.sn = 2, + .ul_count.hfn = 12, + .ul_count.sn = 3, + }; + // DRB Modified List DRB_nGRAN_modified_t drb_mod = { .id = 1, .numQosFlowSetup = 1, .qosFlows[0].qfi = 1, + .pdcp_status = malloc_or_fail(sizeof(*drb_mod.pdcp_status)), }; + *drb_mod.pdcp_status = dummy_pdcp_status; // DRB Setup List DRB_nGRAN_setup_t setup = { diff --git a/openair2/E2AP/CMakeLists.txt b/openair2/E2AP/CMakeLists.txt index d86dafb0b9..8cbaae73db 100644 --- a/openair2/E2AP/CMakeLists.txt +++ b/openair2/E2AP/CMakeLists.txt @@ -129,4 +129,4 @@ add_subdirectory(flexric/src/util) add_subdirectory(RAN_FUNCTION) add_library(e2_agent_arg STATIC e2_agent_arg.c) -add_dependencies(e2_agent_arg generate_T) +target_link_libraries(e2_agent_arg PRIVATE CONFIG_LIB log_headers) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c index 31d96433c1..4e30773313 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c @@ -27,10 +27,11 @@ #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair2/E2AP/flexric/src/util/time_now_us.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" - +#include "ds/seq_arr.h" #if defined (NGRAN_GNB_CUCP) #include "openair2/RRC/NR/rrc_gNB_UE_context.h" +#include "openair2/RRC/NR/rrc_gNB_radio_bearers.h" #endif bool read_gtp_sm(void * data) @@ -62,16 +63,15 @@ bool read_gtp_sm(void * data) rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[0], ue_id_list[i]); gtp->msg.ngut[i].rnti = ue_id_list[i]; - int nb_pdu_session = ue_context_p->ue_context.nb_of_pdusessions; - if (nb_pdu_session > 0) { - int nb_pdu_idx = nb_pdu_session - 1; - gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.gNB_teid_N3; - gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.UPF_teid_N3; + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t*, session, &ue_context_p->ue_context.pduSessions) { + gtp->msg.ngut[i].teidgnb = session->param.n3_outgoing.teid; + gtp->msg.ngut[i].teidupf = session->param.n3_incoming.teid; // TODO: one PDU session has multiple QoS Flow - int nb_qos_flow = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos; - if (nb_qos_flow > 0) { - gtp->msg.ngut[i].qfi = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.qos[nb_qos_flow - 1].qfi; + DevAssert(seq_arr_size(&session->param.qos) == 1); + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->param.qos) { + gtp->msg.ngut[i].qfi = qos->qos.qfi; } + break; } } diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c index 5a451cff01..13b6306a1c 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_mac.c @@ -66,7 +66,7 @@ bool read_mac_sm(void* data) } if (is_ul_slot(rd->slot, &RC.nrmac[mod_id]->frame_structure)) { rd->ul_curr_tbs = UE->mac_stats.ul.current_bytes; - rd->ul_sched_rb = sched_ctrl->sched_pusch.rbSize; + rd->ul_sched_rb = UE->mac_stats.ul.current_rbs; } rd->rnti = UE->rnti; diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c index c3f6277f6f..a81a01d394 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_e2sm_ue_id.c @@ -30,7 +30,12 @@ ue_id_e2sm_t fill_e2sm_gnb_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, __attr // 6.2.3.16 // Mandatory // AMF UE NGAP ID - ue_id.gnb.amf_ue_ngap_id = rrc_ue_context->amf_ue_ngap_id; + // it seems that certain messages can be triggered before the ue has an AMF + // UE NGAP ID (e.g., RRC setup). In that case, the AMF UE NGAP ID is set to + // an invalid value. Below, check for this, and set 0 in that case (which + // historically used to be in amf_ue_ngap_id). + uint64_t auni = rrc_ue_context->amf_ue_ngap_id; + ue_id.gnb.amf_ue_ngap_id = auni < (1LL << 40) ? auni : 0; // Mandatory //GUAMI 6.2.3.17 diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c index ea5c683a37..02760c4984 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -27,6 +27,7 @@ #include "openair2/E1AP/e1ap_common.h" #include "openair2/E2AP/flexric/src/util/time_now_us.h" #include "openair2/F1AP/f1ap_ids.h" +#include "ds/seq_arr.h" static pthread_once_t once_kpm_mutex = PTHREAD_ONCE_INIT; @@ -209,8 +210,11 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_cu(const test_info_lst_t test_info) struct rrc_gNB_ue_context_s* rrc_ue_context = NULL; RB_FOREACH(rrc_ue_context, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) { gNB_RRC_UE_t *ue = &rrc_ue_context->ue_context; - for (int p = 0; p < ue->nb_of_pdusessions; ++p) { - pdusession_t *pdu = &ue->pduSession[p].param; + /* UE has no AMF UE NGAP ID yet => can't send message */ + if (ue->amf_ue_ngap_id >= (1LL << 40)) + continue; + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t*, item, &ue->pduSessions) { + pdusession_t* pdu = &item->param; if (nssai_matches(pdu->nssai, sst, sd)) { arr_ue_id.ue_id[arr_ue_id.sz] = fill_ue_id_data[ngran_gNB_CU](ue, 0, 0); @@ -296,6 +300,9 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst arr_ue_id.ue_id[arr_ue_id.sz] = fill_ue_id_data[ngran_gNB_DU](NULL, rrc_ue_id.secondary_ue, 0); } else { rrc_gNB_ue_context_t* rrc_ue_context = rrc_gNB_get_ue_context_by_rnti(RC.nrrrc[0], -1, ue->rnti); + /* UE has no AMF UE NGAP ID yet => can't send message */ + if (rrc_ue_context->ue_context.amf_ue_ngap_id >= (1LL << 40)) + continue; arr_ue_id.ue_id[arr_ue_id.sz] = fill_ue_id_data[ngran_gNB](&rrc_ue_context->ue_context, 0, 0); } diff --git a/openair2/ENB_APP/NB_IoT_config.c b/openair2/ENB_APP/NB_IoT_config.c deleted file mode 100644 index e6fe6e5d71..0000000000 --- a/openair2/ENB_APP/NB_IoT_config.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * 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 - */ - -/* - nbiot_config.c - ------------------- - AUTHOR : Francois Taburet - COMPANY : NOKIA - EMAIL : francois.taburet@nokia-bell-labs.com -*/ - -#include -#include - -#include "log.h" -#include "assertions.h" -#include "intertask_interface.h" -#include "s1ap_eNB.h" -#include "sctp_eNB_task.h" -#include "SystemInformationBlockType2.h" - -#include "PHY/phy_extern.h" -#include "radio/ETHERNET/ethernet_lib.h" -#include "common/config/config_userapi.h" -#include "RRC_config_tools.h" -#include "RRC_paramsvalues.h" -#include "NB_IoT_paramdef.h" -#include "L1_paramdef.h" -#include "MACRLC_paramdef.h" -#include "LAYER2/MAC/proto_NB_IoT.h" - - -void RCconfig_NbIoTL1(void) { - paramdef_t NbIoT_L1_Params[] = L1PARAMS_DESC; - paramlist_def_t NbIoT_L1_ParamList = {NBIOT_L1LIST_CONFIG_STRING,NULL,0}; - /* No component carrier for NbIoT, ignore number of CC */ - // NbIoT_L1_Params[L1_CC_IDX ].paramflags = PARAMFLAG_DONOTREAD; - config_getlist(&NbIoT_L1_ParamList, NbIoT_L1_Params, sizeofArray(NbIoT_L1_Params), NULL); - - if (NbIoT_L1_ParamList.numelt > 0) { - if (RC.L1_NB_IoT == NULL) { - RC.L1_NB_IoT = (PHY_VARS_eNB_NB_IoT **)malloc(RC.nb_nb_iot_L1_inst*sizeof(PHY_VARS_eNB_NB_IoT *)); - LOG_I(PHY,"RC.L1_NB_IoT = %p\n",RC.L1_NB_IoT); - memset(RC.L1_NB_IoT,0,RC.nb_nb_iot_L1_inst*sizeof(PHY_VARS_eNB_NB_IoT *)); - } - - for(int j = 0; j eth_params_n.local_if_name = strdup(*(NbIoT_L1_ParamList.paramarray[j][L1_LOCAL_N_IF_NAME_IDX].strptr)); - RC.L1_NB_IoT[j]->eth_params_n.my_addr = strdup(*(NbIoT_L1_ParamList.paramarray[j][L1_LOCAL_N_ADDRESS_IDX].strptr)); - RC.L1_NB_IoT[j]->eth_params_n.remote_addr = strdup(*(NbIoT_L1_ParamList.paramarray[j][L1_REMOTE_N_ADDRESS_IDX].strptr)); - RC.L1_NB_IoT[j]->eth_params_n.my_portc = *(NbIoT_L1_ParamList.paramarray[j][L1_LOCAL_N_PORTC_IDX].iptr); - RC.L1_NB_IoT[j]->eth_params_n.remote_portc = *(NbIoT_L1_ParamList.paramarray[j][L1_REMOTE_N_PORTC_IDX].iptr); - RC.L1_NB_IoT[j]->eth_params_n.my_portd = *(NbIoT_L1_ParamList.paramarray[j][L1_LOCAL_N_PORTD_IDX].iptr); - RC.L1_NB_IoT[j]->eth_params_n.remote_portd = *(NbIoT_L1_ParamList.paramarray[j][L1_REMOTE_N_PORTD_IDX].iptr); - RC.L1_NB_IoT[j]->eth_params_n.transp_preference = ETH_UDP_MODE; - } else { // other midhaul - } - }// j=0..num_inst - - printf("Initializing northbound interface for NB-IoT L1\n"); - l1_north_init_NB_IoT(); - } else { - LOG_I(PHY,"No " NBIOT_L1LIST_CONFIG_STRING " configuration found"); - } -} - -void RCconfig_NbIoTmacrlc(void) { - paramdef_t NbIoT_MacRLC_Params[] = MACRLCPARAMS_DESC; - paramlist_def_t NbIoT_MacRLC_ParamList = {NBIOT_MACRLCLIST_CONFIG_STRING,NULL,0}; - /* No component carrier for NbIoT, ignore number of CC */ - // NbIoT_MacRLC_Params[MACRLC_CC_IDX ].paramflags = PARAMFLAG_DONOTREAD; - config_getlist(&NbIoT_MacRLC_ParamList, NbIoT_MacRLC_Params, sizeofArray(NbIoT_MacRLC_Params), NULL); - - if ( NbIoT_MacRLC_ParamList.numelt > 0) { - mac_top_init_eNB_NB_IoT(); - - for (int j=0; jeth_params_n.local_if_name = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_IF_NAME_IDX].strptr)); - RC.nb_iot_mac[j]->eth_params_n.my_addr = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_ADDRESS_IDX].strptr)); - RC.nb_iot_mac[j]->eth_params_n.remote_addr = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_ADDRESS_IDX].strptr)); - RC.nb_iot_mac[j]->eth_params_n.my_portc = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTC_IDX].iptr); - RC.nb_iot_mac[j]->eth_params_n.remote_portc = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTC_IDX].iptr); - RC.nb_iot_mac[j]->eth_params_n.my_portd = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTD_IDX].iptr); - RC.nb_iot_mac[j]->eth_params_n.remote_portd = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTD_IDX].iptr);; - RC.nb_iot_mac[j]->eth_params_n.transp_preference = ETH_UDP_MODE; - } else { // other midhaul - AssertFatal(1==0,"MACRLC %d: %s unknown northbound midhaul\n",j, *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr)); - } - - if (strcmp(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_L1") == 0) { - } else if (strcmp(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "nfapi") == 0) { - RC.nb_iot_mac[j]->eth_params_s.local_if_name = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_IF_NAME_IDX].strptr)); - RC.nb_iot_mac[j]->eth_params_s.my_addr = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_ADDRESS_IDX].strptr)); - RC.nb_iot_mac[j]->eth_params_s.remote_addr = strdup(*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_ADDRESS_IDX].strptr)); - RC.nb_iot_mac[j]->eth_params_s.my_portc = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTC_IDX].iptr); - RC.nb_iot_mac[j]->eth_params_s.remote_portc = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTC_IDX].iptr); - RC.nb_iot_mac[j]->eth_params_s.my_portd = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_LOCAL_S_PORTD_IDX].iptr); - RC.nb_iot_mac[j]->eth_params_s.remote_portd = *(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTD_IDX].iptr); - RC.nb_iot_mac[j]->eth_params_s.transp_preference = ETH_UDP_MODE; - } else { // other midhaul - AssertFatal(1==0,"MACRLC %d: %s unknown southbound midhaul\n",j,*(NbIoT_MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); - } - }// j=0..num_inst */ - } else {// MacRLC_ParamList.numelt > 0 - AssertFatal (0, - "No " NBIOT_MACRLCLIST_CONFIG_STRING " configuration found"); - } -} - - - - -int RCconfig_NbIoTRRC(MessageDef *msg_p, int nbiotrrc_id,eNB_RRC_INST_NB_IoT *nbiotrrc) { - char instprefix[MAX_OPTNAME_SIZE*3 + 32]; - checkedparam_t NBIoTCheckParams[] = NBIOT_RRCPARAMS_CHECK_DESC_0_14; - checkedparam_t NBIoTCheckParamsB[] = NBIOT_RRCPARAMS_CHECK_DESC_15_end; - paramdef_t NBIoTParams[] = NBIOTRRCPARAMS_DESC; - paramdef_t NBIoTPrachParams[] = NBIOTRRC_NPRACH_PARAMS_DESC; - checkedparam_t NBIoTPrachCheckParams[] = NBIOT_RRCLIST_NPRACHPARAMSCHECK_DESC; - paramdef_t NBIoTRRCRefParams[] = NBIOTRRCPARAMS_RRCREF_DESC; - paramdef_t NBIoTLteCCParams[] = NBIOT_LTECCPARAMS_DESC; - checkedparam_t NBIoTLteCCCheckParams[] = NBIOT_LTECCPARAMS_CHECK_DESC; - - /* map parameter checking array instances to parameter definition array instances */ - for (int i = 0; i < sizeofArray(NBIoTParams) && i < sizeofArray(NBIoTCheckParams); i++) { - NBIoTParams[i].chkPptr = &(NBIoTCheckParams[i]); - } - - for (int i = 0; i < sizeofArray(NBIoTParams) && i < sizeofArray(NBIoTCheckParamsB); i++) { - NBIoTParams[i + 15].chkPptr = &(NBIoTCheckParamsB[i]); - } - - for (int i = 0; i < sizeofArray(NBIoTPrachParams) && i < sizeofArray(NBIoTPrachCheckParams); i++) { - NBIoTPrachParams[i].chkPptr = &(NBIoTPrachCheckParams[i]); - } - - /* brut force itti message fields assignment, to be redesigned with itti replacement */ - NBIoTParams[NBIOT_RACH_RARESPONSEWINDOWSIZE_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).rach_raResponseWindowSize_NB); - NBIoTParams[NBIOT_RACH_MACCONTENTIONRESOLUTIONTIMER_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).rach_macContentionResolutionTimer_NB); - NBIoTParams[NBIOT_RACH_POWERRAMPINGSTEP_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).rach_powerRampingStep_NB); - NBIoTParams[NBIOT_RACH_PREAMBLEINITIALRECEIVEDTARGETPOWER_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).rach_preambleInitialReceivedTargetPower_NB); - NBIoTParams[NBIOT_RACH_PREAMBLETRANSMAX_CE_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).rach_preambleTransMax_CE_NB); - NBIoTParams[NBIOT_BCCH_MODIFICATIONPERIODCOEFF_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).bcch_modificationPeriodCoeff_NB); - NBIoTParams[NBIOT_PCCH_DEFAULTPAGINGCYCLE_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).pcch_defaultPagingCycle_NB); - NBIoTParams[NBIOT_NPRACH_CP_LENGTH_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).nprach_CP_Length); - NBIoTParams[NBIOT_NPRACH_RSRP_RANGE_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).nprach_rsrp_range); - NBIoTParams[NBIOT_MAXNUMPREAMBLEATTEMPTCE_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).maxNumPreambleAttemptCE_NB); - NBIoTParams[NBIOT_NPDSCH_NRS_POWER_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).npdsch_nrs_Power); - NBIoTParams[NBIOT_NPUSCH_ACK_NACK_NUMREPETITIONS_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p). npusch_ack_nack_numRepetitions_NB); - NBIoTParams[NBIOT_NPUSCH_SRS_SUBFRAMECONFIG_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p). npusch_srs_SubframeConfig_NB); - NBIoTParams[NBIOT_NPUSCH_THREETONE_CYCLICSHIFT_R13_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).npusch_threeTone_CyclicShift_r13); - NBIoTParams[NBIOT_NPUSCH_SIXTONE_CYCLICSHIFT_R13_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).npusch_sixTone_CyclicShift_r13); - NBIoTParams[NBIOT_NPUSCH_GROUPASSIGNMENTNPUSCH_R13_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).npusch_groupAssignmentNPUSCH_r13); - NBIoTParams[NBIOT_DL_GAPTHRESHOLD_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).dl_GapThreshold_NB); - NBIoTParams[NBIOT_DL_GAPPERIODICITY_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).dl_GapPeriodicity_NB); - NBIoTParams[NBIOT_NPUSCH_P0_NOMINALNPUSCH_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).npusch_p0_NominalNPUSCH); - NBIoTParams[NBIOT_DELTAPREAMBLEMSG3_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).deltaPreambleMsg3); - NBIoTParams[NBIOT_UE_TIMERSANDCONSTANTS_T300_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t300_NB); - NBIoTParams[NBIOT_UE_TIMERSANDCONSTANTS_T301_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t301_NB); - NBIoTParams[NBIOT_UE_TIMERSANDCONSTANTS_T310_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t310_NB); - NBIoTParams[NBIOT_UE_TIMERSANDCONSTANTS_T311_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_t311_NB); - NBIoTParams[NBIOT_UE_TIMERSANDCONSTANTS_N310_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n310_NB); - NBIoTParams[NBIOT_UE_TIMERSANDCONSTANTS_N311_NB_IDX].uptr = (uint32_t *)&(NBIOTRRC_CONFIGURATION_REQ (msg_p).ue_TimersAndConstants_n311_NB); - sprintf(instprefix, NBIOT_RRCLIST_CONFIG_STRING ".[%i]",nbiotrrc_id); - config_get( NBIoTParams,sizeofArray(NBIoTParams),instprefix); - NBIOTRRC_CONFIGURATION_REQ (msg_p).nprach_SubcarrierMSG3_RangeStart = config_get_processedint(config_get_if(), &(NBIoTParams[NBIOT_NPRACH_SUBCARRIERMSG3_RANGESTART_IDX]) ); - NBIOTRRC_CONFIGURATION_REQ (msg_p).npusch_groupHoppingEnabled = config_get_processedint(config_get_if(), &(NBIoTParams[NBIOT_NPUSCH_GROUPHOPPINGENABLED_IDX] ) ); - NBIOTRRC_CONFIGURATION_REQ (msg_p).dl_GapDurationCoeff_NB = config_get_processedint(config_get_if(), &(NBIoTParams[NBIOT_DL_GAPDURATIONCOEFF_NB_IDX] ) ); - NBIOTRRC_CONFIGURATION_REQ (msg_p).npusch_alpha = config_get_processedint(config_get_if(), &(NBIoTParams[NBIOT_NPUSCH_ALPHA_IDX] ) ); - - for (int i=0; inb_nb_iot_rrc_inst = NbIoT_ParamList.numelt; - config_getlist( &NbIoT_MACRLCParamList,NULL,0, NULL); - RC->nb_nb_iot_macrlc_inst = NbIoT_MACRLCParamList.numelt; - // Get num L1 instances - config_getlist( &NbIoT_L1ParamList,NULL,0, NULL); - RC->nb_nb_iot_L1_inst = NbIoT_L1ParamList.numelt; -} diff --git a/openair2/ENB_APP/NB_IoT_paramdef.h b/openair2/ENB_APP/NB_IoT_paramdef.h deleted file mode 100644 index 8778f6d2e4..0000000000 --- a/openair2/ENB_APP/NB_IoT_paramdef.h +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file openair2/ENB_APP/enb_paramdef.f - * \brief definition of configuration parameters for all eNodeB modules - * \author Francois TABURET - * \date 2017 - * \version 0.1 - * \company NOKIA BellLabs France - * \email: francois.taburet@nokia-bell-labs.com - * \note - * \warning - */ - -#ifndef __ENB_APP_NB_IOT_PARAMDEF__H__ -#define __ENB_APP_NB_IOT_PARAMDEF__H__ - -#include "common/config/config_paramdesc.h" -#include "SystemInformationBlockType2.h" -#include "DL-GapConfig-NB-r13.h" -#include "NPRACH-Parameters-NB-r13.h" -#include "PowerRampingParameters.h" -#include "BCCH-Config-NB-r13.h" -#include "PCCH-Config-NB-r13.h" -#include "ACK-NACK-NumRepetitions-NB-r13.h" -#include "TDD-Config.h" - - - - - -/* - int16_t eutra_band; - uint32_t downlink_frequency; - int32_t uplink_frequency_offset; - int16_t Nid_cell;// for testing, change later - int16_t N_RB_DL;// for testing, change later -*/ -/*-------------------------------------------------------------------------------------------------------------------*/ -/* SIB1 parameters possibly coming from LTE RRC (in band deployment) */ -/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* component carriers configuration parameters */ -/* optname helpstr paramflags XXXptr defXXXval type numelt checked_param */ -/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define NBIOT_LTECCPARAMS_CHECK_DESC { \ - { .s3a= { config_checkstr_assign_integer, FRAMETYPE_OKVALUES, FRAMETYPE_MODVALUES,2}} , \ - { .s2= { config_check_intrange, TDDCONFIG_OKRANGE}}, \ - { .s2= { config_check_intrange, TDDCONFIGS_OKRANGE}}, \ - { .s3a= { config_checkstr_assign_integer, PREFIX_OKVALUES, PREFIX_MODVALUES,2}} , \ - { .s3a= { config_checkstr_assign_integer, PREFIXUL_OKVALUES, PREFIXUL_MODVALUES,2}} , \ - { .s5= {NULL }} , \ - { .s5= {NULL }} , \ - { .s5= {NULL }} , \ - { .s5= {NULL }} , \ - { .s1= { config_check_intval, NRBDL_OKVALUES,6}} , \ -} - - -#define NBIOT_LTECCPARAMS_DESC { \ -{ENB_CONFIG_STRING_FRAME_TYPE, NULL, 0, strptr:NULL, defstrval:"FDD", TYPE_STRING, 0}, \ -{ENB_CONFIG_STRING_TDD_CONFIG, NULL, 0, iptr:NULL, defintval:3, TYPE_UINT, 0}, \ -{ENB_CONFIG_STRING_TDD_CONFIG_S, NULL, 0, iptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{ENB_CONFIG_STRING_PREFIX_TYPE, NULL, 0, strptr:NULL, defstrval:"NORMAL", TYPE_STRING, 0}, \ -{ENB_CONFIG_STRING_PREFIX_TYPE_UL, NULL, 0, strptr:NULL, defstrval:"NORMAL", TYPE_STRING, 0}, \ -{ENB_CONFIG_STRING_EUTRA_BAND, NULL, 0, iptr:NULL, defintval:7, TYPE_UINT, 0}, \ -{ENB_CONFIG_STRING_DOWNLINK_FREQUENCY, NULL, 0, i64ptr:NULL, defint64val:2680000000, TYPE_UINT64, 0}, \ -{ENB_CONFIG_STRING_UPLINK_FREQUENCY_OFFSET, NULL, 0, iptr:NULL, defintval:-120000000, TYPE_INT, 0}, \ -{ENB_CONFIG_STRING_NID_CELL, NULL, 0, iptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{ENB_CONFIG_STRING_N_RB_DL, NULL, 0, iptr:NULL, defintval:25, TYPE_UINT, 0}, \ -} -#define LTECCPARAMS_FRAME_TYPE_IDX 0 -#define LTECCPARAMS_TDD_CONFIG_IDX 1 -#define LTECCPARAMS_TDD_CONFIG_S_IDX 2 -#define LTECCPARAMS_PREFIX_TYPE_IDX 3 -#define LTECCPARAMS_PREFIX_TYPE_UL_IDX 4 -#define LTECCPARAMS_EUTRA_BAND_IDX 5 -#define LTECCPARAMS_DOWNLINK_FREQUENCY_IDX 6 -#define LTECCPARAMS_UPLINK_FREQUENCY_OFFSET_IDX 7 -#define LTECCPARAMS_NID_CELL_IDX 8 -#define LTECCPARAMS_N_RB_DL_IDX 9 - - -/*-------------------------------------------------------------------------------------------------------------------*/ - -/* NB-Iot RRC list section name */ -#define NBIOT_RRCLIST_CONFIG_STRING "NB-IoT_RRCs" - - -#define RACH_RARESPONSEWINDOWSIZE_NB_OKVALUES {20,50,80,120,180,240,320,400} -#define PREF1(A) RACH_CE_LevelInfo_r13__ra_ResponseWindowSize_r13_ ## A -#define RACH_RARESPONSEWINDOWSIZE_NB_MODVALUES { PREF1(sf20),PREF1(sf50),PREF1(sf80),PREF1(sf120), \ - PREF1(sf180),PREF1(sf240),PREF1(sf320),PREF1(sf400) } - - -#define RACH_MACCONTENTIONRESOLUTIONTIMER_NB_OKVALUES {80,100,120,160,200,240,480,960} -#define PREF2(A) RACH_CE_LevelInfo_r13__mac_ContentionResolutionTimer_r13_ ## A -#define RACH_MACCONTENTIONRESOLUTIONTIMER_NB_MODVALUES { PREF2(sf80),PREF2(sf100),PREF2(sf120),PREF2(sf160), \ - PREF2(sf200),PREF2(sf240),PREF2(sf480),PREF2(sf960) } - - -#define RACH_POWERRAMPINGSTEP_NB_OKVALUES {0,2,4,6} -#define PREF3(A) PowerRampingParameters__powerRampingStep_ ## A -#define RACH_POWERRAMPINGSTEP_NB_MODVALUES { PREF3(dB0),PREF3(dB2),PREF3(dB4),PREF3(dB6) } - - -#define RACH_PREAMBLEINITIALRECEIVEDTARGETPOWER_NB_OKRANGE {-120, -90} - -#define RACH_PREAMBLETRANSMAX_CE_NB_OKVALUES {3,4,5,6,7,8,10,20,50,100,200} -#define PREF4(A) PreambleTransMax_ ## A -#define RACH_PREAMBLETRANSMAX_CE_NB_MODVALUES { PREF4(n3), PREF4(n4), PREF4(n5), PREF4(n6), PREF4(n7), PREF4(n8), \ - PREF4(n10),PREF4(n20),PREF4(n50),PREF4(n100),PREF4(n200) } - -#define BCCH_MODIFICATIONPERIODCOEFF_NB_OKVALUES {16,32,64,128} -#define PREF5(A) BCCH_Config_NB_r13__modificationPeriodCoeff_r13_ ## A -#define BCCH_MODIFICATIONPERIODCOEFF_NB_MODVALUES { PREF5(n16), PREF5(n32), PREF5(n64),PREF5(n128) } - -#define PCCH_DEFAULTPAGINGCYCLE_NB_OKVALUES {128,256,512,1024} -#define PREF6(A) PCCH_Config_NB_r13__defaultPagingCycle_r13_ ## A -#define PCCH_DEFAULTPAGINGCYCLE_NB_MODVALUES { PREF6(rf128), PREF6(rf256), PREF6(rf512), PREF6(rf1024) } - -#define NPRACH_CP_LENGTH_OKVALUES {0,1} -#define NPRACH_RSRP_RANGE_OKVALUES {0,96} - -#define MSG3RANGESTART_OKVALUES {"zero","oneThird","twoThird","one"} -#define MSG3RANGESTART_MODVALUES {NPRACH_Parameters_NB_r13__nprach_SubcarrierMSG3_RangeStart_r13_zero, NPRACH_Parameters_NB_r13__nprach_SubcarrierMSG3_RangeStart_r13_oneThird, \ - NPRACH_Parameters_NB_r13__nprach_SubcarrierMSG3_RangeStart_r13_twoThird, NPRACH_Parameters_NB_r13__nprach_SubcarrierMSG3_RangeStart_r13_one} - - -#define MAXNUMPREAMBLEATTEMPTCE_OKVALUES {3,4,5,6,7,8,10} -#define MAXNUMPREAMBLEATTEMPTCE_MODVALUES { NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n3, NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n4, \ - NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n5, NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n6, \ - NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n7, NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n8, \ - NPRACH_Parameters_NB_r13__maxNumPreambleAttemptCE_r13_n10 } - -#define NPDSCH_NRS_POWER_OKRANGE {-60,50} - -#define NPUSCH_ACK_NACK_NUMREPETITIONS_NB_OKVALUES {1,2,4,8,16,32,64,128} -#define PREF9(A) ACK_NACK_NumRepetitions_NB_r13_ ## A -#define NPUSCH_ACK_NACK_NUMREPETITIONS_NB_MODVALUES { PREF9(r1), PREF9(r2), PREF9(r4), PREF9(r8), \ - PREF9(r16), PREF9(r32), PREF9(r64), PREF9(r128) } - -#define NPUSCH_SRS_SUBFRAMECONFIG_NB_OKRANGE {0,15} -#define NPUSCH_THREETONE_CYCLICSHIFT_R13_OKRANGE {0,2} -#define NPUSCH_SIXTONE_CYCLICSHIFT_R13_OKRANGE {0,3} - -#define NPUSCH_GROUPHOPPINGENABLED_OKVALUES {"enable","disable"} -#define NPUSCH_GROUPHOPPINGENABLED_MODVALUES {1,0} - -#define NPUSCH_GROUPASSIGNMENTNPUSCH_R13_OKRANGE {0,29} - -#define DLGAPTHRESHOLD_OKVALUES {32,64,128,256} -#define DLGAPTHRESHOLD_MODVALUES { DL_GapConfig_NB_r13__dl_GapThreshold_r13_n32, DL_GapConfig_NB_r13__dl_GapThreshold_r13_n64, \ - DL_GapConfig_NB_r13__dl_GapThreshold_r13_n128, DL_GapConfig_NB_r13__dl_GapThreshold_r13_n256} \ - -#define DLGAPPERIODICITY_OKVALUES {64,128,256,512} -#define DLGAPPERIODICITY_MODVALUES { DL_GapConfig_NB_r13__dl_GapPeriodicity_r13_sf64, DL_GapConfig_NB_r13__dl_GapPeriodicity_r13_sf128, \ - DL_GapConfig_NB_r13__dl_GapPeriodicity_r13_sf256,DL_GapConfig_NB_r13__dl_GapPeriodicity_r13_sf512} - -#define DLGAPDURATION_OKVALUES {"oneEighth","oneFourth","threeEighth","oneHalf"} -#define DLGAPDURATION_MODVALUES {DL_GapConfig_NB_r13__dl_GapDurationCoeff_r13_oneEighth, DL_GapConfig_NB_r13__dl_GapDurationCoeff_r13_oneFourth, \ - DL_GapConfig_NB_r13__dl_GapDurationCoeff_r13_threeEighth, DL_GapConfig_NB_r13__dl_GapDurationCoeff_r13_oneHalf} - -#define NPUSCH_P0_NOMINALNPUSCH_OKRANGE {-126,24} - -#define NPUSCH_ALPHA_OKVALUES {"AL0","AL04","AL05","AL06","AL07","AL08","AL09","AL1"} -#define NPUSCH_ALPHA_MODVALUES { Alpha_r12_al0, Alpha_r12_al04, Alpha_r12_al05, Alpha_r12_al06, \ - Alpha_r12_al07, Alpha_r12_al08, Alpha_r12_al09, Alpha_r12_al1} - -#define DELTAPREAMBLEMSG3_OKRANGE {-1,6} - - - - - -#define NBIOT_RRCPARAMS_CHECK_DESC { \ - { .s1a= { config_check_modify_integer, RACH_RARESPONSEWINDOWSIZE_NB_OKVALUES, RACH_RARESPONSEWINDOWSIZE_NB_MODVALUES, 8}}, \ - { .s1a= { config_check_modify_integer, RACH_MACCONTENTIONRESOLUTIONTIMER_NB_OKVALUES, RACH_MACCONTENTIONRESOLUTIONTIMER_NB_MODVALUES, 8}}, \ - { .s1a= { config_check_modify_integer, RACH_POWERRAMPINGSTEP_NB_OKVALUES, RACH_POWERRAMPINGSTEP_NB_MODVALUES, 4}} , \ - { .s2= { config_check_intrange, RACH_PREAMBLEINITIALRECEIVEDTARGETPOWER_NB_OKRANGE}}, \ - { .s1a= { config_check_modify_integer, RACH_PREAMBLETRANSMAX_CE_NB_OKVALUES, RACH_PREAMBLETRANSMAX_CE_NB_MODVALUES, 11}} , \ - { .s1a= { config_check_modify_integer, BCCH_MODIFICATIONPERIODCOEFF_NB_OKVALUES, BCCH_MODIFICATIONPERIODCOEFF_NB_MODVALUES, 4}} , \ - { .s1a= { config_check_modify_integer, PCCH_DEFAULTPAGINGCYCLE_NB_OKVALUES, PCCH_DEFAULTPAGINGCYCLE_NB_MODVALUES, 4}} , \ - { .s1= { NULL, NPRACH_CP_LENGTH_OKVALUES ,4}} , \ - { .s2= { config_check_intrange, NPRACH_RSRP_RANGE_OKVALUES}} , \ - { .s3a= { config_checkstr_assign_integer, MSG3RANGESTART_OKVALUES, MSG3RANGESTART_MODVALUES, 4}} , \ - { .s1a= { config_check_modify_integer, MAXNUMPREAMBLEATTEMPTCE_OKVALUES, MAXNUMPREAMBLEATTEMPTCE_MODVALUES, 7}} , \ - { .s1= { config_check_intval, NPDSCH_NRS_POWER_OKRANGE,4}} , \ - { .s1a= { config_check_modify_integer, NPUSCH_ACK_NACK_NUMREPETITIONS_NB_OKVALUES, NPUSCH_ACK_NACK_NUMREPETITIONS_NB_MODVALUES, 8}} , \ - { .s2= { config_check_intrange, NPUSCH_SRS_SUBFRAMECONFIG_NB_OKRANGE}} , \ - { .s2= { config_check_intrange, NPUSCH_THREETONE_CYCLICSHIFT_R13_OKRANGE}} , \ - { .s2= { config_check_intrange, NPUSCH_SIXTONE_CYCLICSHIFT_R13_OKRANGE}} , \ - { .s3a= { config_checkstr_assign_integer, NPUSCH_GROUPHOPPINGENABLED_OKVALUES, NPUSCH_GROUPHOPPINGENABLED_MODVALUES, 2}} , \ - { .s2= { config_check_intrange, NPUSCH_GROUPASSIGNMENTNPUSCH_R13_OKRANGE}} , \ - { .s1a= { config_check_modify_integer, DLGAPTHRESHOLD_OKVALUES, DLGAPTHRESHOLD_MODVALUES, 4}} , \ - { .s1a= { config_check_modify_integer, DLGAPPERIODICITY_OKVALUES, DLGAPPERIODICITY_MODVALUES, 4}} , \ - { .s3a= { config_checkstr_assign_integer, DLGAPDURATION_OKVALUES, DLGAPDURATION_MODVALUES , 4}} , \ - { .s2= { config_check_intrange, NPUSCH_P0_NOMINALNPUSCH_OKRANGE}} , \ - { .s3a= { config_checkstr_assign_integer, NPUSCH_ALPHA_OKVALUES, NPUSCH_ALPHA_MODVALUES, 8}} , \ - { .s2= { config_check_intrange, DELTAPREAMBLEMSG3_OKRANGE}} , \ - { .s1a= { config_check_modify_integer, UETIMER_T300_OKVALUES, UETIMER_T300_MODVALUES,8}} , \ - { .s1a= { config_check_modify_integer, UETIMER_T301_OKVALUES, UETIMER_T301_MODVALUES,8}} , \ - { .s1a= { config_check_modify_integer, UETIMER_T310_OKVALUES, UETIMER_T310_MODVALUES,7}} , \ - { .s1a= { config_check_modify_integer, UETIMER_T311_OKVALUES, UETIMER_T311_MODVALUES,7}} , \ - { .s1a= { config_check_modify_integer, UETIMER_N310_OKVALUES, UETIMER_N310_MODVALUES,8}} , \ - { .s1a= { config_check_modify_integer, UETIMER_N311_OKVALUES, UETIMER_N311_MODVALUES,8}} , \ -} -/*-----------------------------------------------------------------------------------------------------------------------------------------*/ -/* NB-IoT RRC configuration parameters */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*-----------------------------------------------------------------------------------------------------------------------------------------*/ -#define NBIOTRRCPARAMS_DESC { \ -{"rach_raResponseWindowSize_NB", NULL, 0, uptr:NULL, defintval:20, TYPE_UINT, 0}, \ -{"rach_macContentionResolutionTimer_NB", NULL, 0, uptr:NULL, defintval:80, TYPE_UINT, 0}, \ -{"rach_powerRampingStep_NB", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"rach_preambleInitialReceivedTargetPower_NB", NULL, 0, iptr:NULL, defintval:-112, TYPE_INT32, 0}, \ -{"rach_preambleTransMax_CE_NB", NULL, 0, uptr:NULL, defintval:3, TYPE_UINT, 0}, \ -{"bcch_modificationPeriodCoeff_NB", NULL, 0, uptr:NULL, defintval:16, TYPE_UINT, 0}, \ -{"pcch_defaultPagingCycle_NB", NULL, 0, uptr:NULL, defintval:256, TYPE_UINT, 0}, \ -{"nprach_CP_Length", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"nprach_rsrp_range", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"nprach_SubcarrierMSG3_RangeStart", NULL, 0, strptr:NULL, defstrval:"one", TYPE_STRING, 0}, \ -{"maxNumPreambleAttemptCE_NB", NULL, 0, uptr:NULL, defintval:10, TYPE_UINT, 0}, \ -{"npdsch_nrs_Power", NULL, 0, iptr:NULL, defintval:0, TYPE_INT, 0}, \ -{"npusch_ack_nack_numRepetitions_NB", NULL, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \ -{"npusch_srs_SubframeConfig_NB", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"npusch_threeTone_CyclicShift_r13", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"npusch_sixTone_CyclicShift_r13", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"npusch_groupHoppingEnabled", NULL, 0, strptr:NULL, defstrval:"disable", TYPE_STRING, 0}, \ -{"npusch_groupAssignmentNPUSCH_r13", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"dl_GapThreshold_NB", NULL, 0, uptr:NULL, defintval:32, TYPE_UINT, 0}, \ -{"dl_GapPeriodicity_NB", NULL, 0, uptr:NULL, defintval:64, TYPE_UINT, 0}, \ -{"dl_GapDurationCoeff_NB", NULL, 0, strptr:NULL, defstrval:"oneEighth", TYPE_STRING, 0}, \ -{"npusch_p0_NominalNPUSCH", NULL, 0, iptr:NULL, defintval:0, TYPE_INT32, 0}, \ -{"npusch_alpha", NULL, 0, strptr:NULL, defstrval:"AL0", TYPE_STRING, 0}, \ -{"deltaPreambleMsg3", NULL, 0, iptr:NULL, defintval:0, TYPE_INT32, 0}, \ -{"ue_TimersAndConstants_t300_NB", NULL, 0, uptr:NULL, defintval:1000, TYPE_UINT, 0}, \ -{"ue_TimersAndConstants_t301_NB", NULL, 0, uptr:NULL, defintval:1000, TYPE_UINT, 0}, \ -{"ue_TimersAndConstants_t310_NB", NULL, 0, uptr:NULL, defintval:1000, TYPE_UINT, 0}, \ -{"ue_TimersAndConstants_t311_NB", NULL, 0, uptr:NULL, defintval:10000, TYPE_UINT, 0}, \ -{"ue_TimersAndConstants_n310_NB", NULL, 0, uptr:NULL, defintval:20, TYPE_UINT, 0}, \ -{"ue_TimersAndConstants_n311_NB", NULL, 0, uptr:NULL, defintval:1, TYPE_UINT, 0}, \ -} - -#define NBIOT_RACH_RARESPONSEWINDOWSIZE_NB_IDX 0 -#define NBIOT_RACH_MACCONTENTIONRESOLUTIONTIMER_NB_IDX 1 -#define NBIOT_RACH_POWERRAMPINGSTEP_NB_IDX 2 -#define NBIOT_RACH_PREAMBLEINITIALRECEIVEDTARGETPOWER_NB_IDX 3 -#define NBIOT_RACH_PREAMBLETRANSMAX_CE_NB_IDX 4 -#define NBIOT_BCCH_MODIFICATIONPERIODCOEFF_NB_IDX 5 -#define NBIOT_PCCH_DEFAULTPAGINGCYCLE_NB_IDX 6 -#define NBIOT_NPRACH_CP_LENGTH_IDX 7 -#define NBIOT_NPRACH_RSRP_RANGE_IDX 8 -#define NBIOT_NPRACH_SUBCARRIERMSG3_RANGESTART_IDX 9 -#define NBIOT_MAXNUMPREAMBLEATTEMPTCE_NB_IDX 10 -#define NBIOT_NPDSCH_NRS_POWER_IDX 11 -#define NBIOT_NPUSCH_ACK_NACK_NUMREPETITIONS_NB_IDX 12 -#define NBIOT_NPUSCH_SRS_SUBFRAMECONFIG_NB_IDX 13 -#define NBIOT_NPUSCH_THREETONE_CYCLICSHIFT_R13_IDX 14 -#define NBIOT_NPUSCH_SIXTONE_CYCLICSHIFT_R13_IDX 15 -#define NBIOT_NPUSCH_GROUPHOPPINGENABLED_IDX 16 -#define NBIOT_NPUSCH_GROUPASSIGNMENTNPUSCH_R13_IDX 17 -#define NBIOT_DL_GAPTHRESHOLD_NB_IDX 18 -#define NBIOT_DL_GAPPERIODICITY_NB_IDX 19 -#define NBIOT_DL_GAPDURATIONCOEFF_NB_IDX 20 -#define NBIOT_NPUSCH_P0_NOMINALNPUSCH_IDX 21 -#define NBIOT_NPUSCH_ALPHA_IDX 22 -#define NBIOT_DELTAPREAMBLEMSG3_IDX 23 -#define NBIOT_UE_TIMERSANDCONSTANTS_T300_NB_IDX 24 -#define NBIOT_UE_TIMERSANDCONSTANTS_T301_NB_IDX 25 -#define NBIOT_UE_TIMERSANDCONSTANTS_T310_NB_IDX 26 -#define NBIOT_UE_TIMERSANDCONSTANTS_T311_NB_IDX 27 -#define NBIOT_UE_TIMERSANDCONSTANTS_N310_NB_IDX 28 -#define NBIOT_UE_TIMERSANDCONSTANTS_N311_NB_IDX 29 - -/* NB-Iot RRC: link to LTE RRC section name */ -#define NBIOT_LTERRCREF_CONFIG_STRING "LTERRC_Ref" -/*---------------------------------------------------------------------------------------------------------------*/ -/* NB-IoT RRC configuration parameters to link to a LTE RRC instance (in-guard, in-band) */ -/* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*---------------------------------------------------------------------------------------------------------------*/ -#define NBIOTRRCPARAMS_RRCREF_DESC { \ -{"RRC_inst", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"CC_inst", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -} -/*--------------------------------------------------------------------------------------------------------------*/ -#define NBIOT_RRCINST_IDX 0 -#define NBIOT_CCINST_IDX 1 - -#define NBIOT_RRCLIST_NPRACHPARAMS_CONFIG_STRING "NPRACH-NB-r13" - - -#define NPRACH_PERIODICITY_OKVALUES {40,80,160,240,320,640,1280,2560} -#define NPRACH_PERIODICITY_MODVALUES { NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms40, NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms80, \ - NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms160, NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms240, \ - NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms320, NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms640, \ - NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms1280, NPRACH_Parameters_NB_r13__nprach_Periodicity_r13_ms2560 } - -#define NPRACH_STARTTIME_OKVALUES {8,16,32,64,128,256,512,1024} -#define NPRACH_STARTTIME_MODVALUES { NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms8, NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms16, \ - NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms32, NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms64, \ - NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms128, NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms256, \ - NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms512, NPRACH_Parameters_NB_r13__nprach_StartTime_r13_ms1024 } - -#define NPRACH_SUBCARRIEROFFSET_OKVALUES {0,12,24,36,2,18,34} -#define NPRACH_SUBCARRIEROFFSET_MODVALUES { NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n0, NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n12, \ - NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n24, NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n36, \ - NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n2, NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n18, \ - NPRACH_Parameters_NB_r13__nprach_SubcarrierOffset_r13_n34 } - -#define NPRACH_NUMSUBCARRIERS_OKVALUES {12,24,36,48} -#define NPRACH_NUMSUBCARRIERS_MODVALUES { NPRACH_Parameters_NB_r13__nprach_NumSubcarriers_r13_n12, NPRACH_Parameters_NB_r13__nprach_NumSubcarriers_r13_n24, \ - NPRACH_Parameters_NB_r13__nprach_NumSubcarriers_r13_n36, NPRACH_Parameters_NB_r13__nprach_NumSubcarriers_r13_n48 } - - -#define NUMREPETITIONSPERPREAMBLEATTEMPT_OKVALUES {1,2,4,8,16,32,64,128} -#define NUMREPETITIONSPERPREAMBLEATTEMPT_MODVALUES { NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n1, NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n2, \ - NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n4, NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n8, \ - NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n16, NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n32, \ - NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n64, NPRACH_Parameters_NB_r13__numRepetitionsPerPreambleAttempt_r13_n128} - -#define NPDCCHNUMREPETITIONSRA_OKVALUES {1,2,4,8,16,32,64,128,256,512,1024,2048} -#define NPDCCHNUMREPETITIONSRA_MODVALUES { NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r1, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r2, \ - NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r4, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r8, \ - NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r16, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r32, \ - NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r64, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r128, \ - NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r256, NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r512, \ - NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r1024,NPRACH_Parameters_NB_r13__npdcch_NumRepetitions_RA_r13_r2048} - -#define NPDCCHSTARTSFCSSRA_OKVALUES {1,2,4,8,16,32,48,64} -#define NPDCCHSTARTSFCSSRA_MODVALUES { NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v1dot5, NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v2, \ - NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v4, NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v8, \ - NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v16, NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v32, \ - NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v48, NPRACH_Parameters_NB_r13__npdcch_StartSF_CSS_RA_r13_v64} - -#define NPDCCHOFFSETRA_OKVALUES {"zero","oneEighth","oneFourth","threeEighth"} -#define NPDCCHOFFSETRA_MODVALUES { NPRACH_Parameters_NB_r13__npdcch_Offset_RA_r13_zero, NPRACH_Parameters_NB_r13__npdcch_Offset_RA_r13_oneEighth, \ - NPRACH_Parameters_NB_r13__npdcch_Offset_RA_r13_oneFourth, NPRACH_Parameters_NB_r13__npdcch_Offset_RA_r13_threeEighth} - - - -#define NBIOT_RRCLIST_NPRACHPARAMSCHECK_DESC { \ - { .s1a= { config_check_modify_integer, NPRACH_PERIODICITY_OKVALUES, NPRACH_PERIODICITY_MODVALUES, 8 }}, \ - { .s1a= { config_check_modify_integer, NPRACH_STARTTIME_OKVALUES, NPRACH_STARTTIME_MODVALUES, 8 }}, \ - { .s1a= { config_check_modify_integer, NPRACH_SUBCARRIEROFFSET_OKVALUES, NPRACH_SUBCARRIEROFFSET_MODVALUES, 7 }}, \ - { .s1a= { config_check_modify_integer, NPRACH_NUMSUBCARRIERS_OKVALUES, NPRACH_NUMSUBCARRIERS_MODVALUES, 4 }}, \ - { .s1a= { config_check_modify_integer, NUMREPETITIONSPERPREAMBLEATTEMPT_OKVALUES, NUMREPETITIONSPERPREAMBLEATTEMPT_MODVALUES,8 }}, \ - { .s1a= { config_check_modify_integer, NPDCCHNUMREPETITIONSRA_OKVALUES, NPDCCHNUMREPETITIONSRA_MODVALUES, 12}}, \ - { .s1a= { config_check_modify_integer, NPDCCHSTARTSFCSSRA_OKVALUES, NPDCCHSTARTSFCSSRA_MODVALUES, 8 }}, \ - { .s3a= { config_checkstr_assign_integer, NPDCCHOFFSETRA_OKVALUES, NPDCCHOFFSETRA_MODVALUES, 4 }}, \ -} - - - -/*------------------------------------------------------------------------------------------------------------------------------*/ -/* NB-IoT NPrach parameters, there will be three ocuurences of these parameters in each RRC instance */ - /* optname helpstr paramflags XXXptr defXXXval type numelt */ -/*------------------------------------------------------------------------------------------------------------------------------*/ -#define NBIOTRRC_NPRACH_PARAMS_DESC { \ -{"nprach_Periodicity", NULL, 0, uptr:NULL, defintval:320, TYPE_UINT, 0}, \ -{"nprach_StartTime", NULL, 0, uptr:NULL, defintval:8, TYPE_UINT, 0}, \ -{"nprach_SubcarrierOffset", NULL, 0, uptr:NULL, defintval:0, TYPE_UINT, 0}, \ -{"nprach_NumSubcarriers", NULL, 0, uptr:NULL, defintval:12, TYPE_UINT, 0}, \ -{"numRepetitionsPerPreambleAttempt", NULL, 0, uptr:NULL, defintval:2, TYPE_UINT, 0}, \ -{"npdcch_NumRepetitions_RA", NULL, 0, uptr:NULL, defintval:16, TYPE_UINT, 0}, \ -{"npdcch_StartSF_CSS_RA", NULL, 0, uptr:NULL, defintval:2, TYPE_UINT, 0}, \ -{"npdcch_Offset_RA", NULL, 0, strptr:NULL, defstrval:"zero", TYPE_STRING, 0}, \ -} - -#define NBIOT_NPRACH_PERIODICITY_IDX 0 -#define NBIOT_NPRACH_STARTTIME_IDX 1 -#define NBIOT_NPRACH_SUBCARRIEROFFSET_IDX 2 -#define NBIOT_NPRACH_NUMSUBCARRIERS_IDX 3 -#define NBIOT_NUMREPETITIONSPERPREAMBLEATTEMPT_NB_IDX 4 -#define NBIOT_NPDCCH_NUMREPETITIONS_RA_IDX 5 -#define NBIOT_NPDCCH_STARTSF_CSS_RA_IDX 6 -#define NBIOT_NPDCCH_OFFSET_RA_IDX 7 - -/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* NB IoT MACRLC configuration list section name */ -#define NBIOT_MACRLCLIST_CONFIG_STRING "NB-IoT_MACRLCs" - - -/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* NB IoT L1 configuration list section name */ -#define NBIOT_L1LIST_CONFIG_STRING "NB-IoT_L1s" - -#endif diff --git a/openair2/F1AP/CMakeLists.txt b/openair2/F1AP/CMakeLists.txt index 78bc9435a2..53ab2823ed 100644 --- a/openair2/F1AP/CMakeLists.txt +++ b/openair2/F1AP/CMakeLists.txt @@ -3,7 +3,7 @@ add_subdirectory(MESSAGES) if(ENABLE_TESTS) add_executable(f1ap_ids_test f1ap_ids_test.c f1ap_ids.c) - target_link_libraries(f1ap_ids_test UTIL HASHTABLE minimal_lib) + target_link_libraries(f1ap_ids_test HASHTABLE minimal_lib) add_dependencies(tests f1ap_ids_test) add_test(NAME F1AP_ID_test COMMAND f1ap_ids_test) diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c index 4528a7766f..b7d19b7a6a 100644 --- a/openair2/F1AP/f1ap_cu_task.c +++ b/openair2/F1AP/f1ap_cu_task.c @@ -36,6 +36,7 @@ #include "f1ap_cu_ue_context_management.h" #include "lib/f1ap_rrc_message_transfer.h" #include "lib/f1ap_interface_management.h" +#include "lib/f1ap_ue_context.h" #include "f1ap_cu_paging.h" #include "f1ap_cu_task.h" #include "openair2/RRC/NR/nr_rrc_defs.h" @@ -186,18 +187,19 @@ void *F1AP_CU_task(void *arg) { break; case F1AP_UE_CONTEXT_SETUP_REQ: // from rrc - CU_send_UE_CONTEXT_SETUP_REQUEST(assoc_id, - &F1AP_UE_CONTEXT_SETUP_REQ(received_msg)); + CU_send_UE_CONTEXT_SETUP_REQUEST(assoc_id, &F1AP_UE_CONTEXT_SETUP_REQ(received_msg)); + free_ue_context_setup_req(&F1AP_UE_CONTEXT_SETUP_REQ(received_msg)); break; case F1AP_UE_CONTEXT_MODIFICATION_REQ: - CU_send_UE_CONTEXT_MODIFICATION_REQUEST(assoc_id, - &F1AP_UE_CONTEXT_MODIFICATION_REQ(received_msg)); + CU_send_UE_CONTEXT_MODIFICATION_REQUEST(assoc_id, &F1AP_UE_CONTEXT_MODIFICATION_REQ(received_msg)); + free_ue_context_mod_req(&F1AP_UE_CONTEXT_MODIFICATION_REQ(received_msg)); break; case F1AP_UE_CONTEXT_RELEASE_CMD: // from rrc CU_send_UE_CONTEXT_RELEASE_COMMAND(assoc_id, &F1AP_UE_CONTEXT_RELEASE_CMD(received_msg)); + free_ue_context_rel_cmd(&F1AP_UE_CONTEXT_RELEASE_CMD(received_msg)); break; case F1AP_PAGING_IND: diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index f4bffe6144..2d0959eb25 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -34,6 +34,7 @@ #include "f1ap_encoder.h" #include "f1ap_itti_messaging.h" #include "f1ap_cu_ue_context_management.h" +#include "lib/f1ap_ue_context.h" #include #include "rrc_extern.h" @@ -44,705 +45,40 @@ #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" #endif -static void f1ap_write_drb_qos_param(const f1ap_qos_flow_level_qos_parameters_t *drb_qos_in, F1AP_QoSFlowLevelQoSParameters_t *asn1_qosparam) +int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, const f1ap_ue_context_setup_req_t *req) { - int type = drb_qos_in->qos_characteristics.qos_type; + F1AP_F1AP_PDU_t *pdu = encode_ue_context_setup_req(req); - const f1ap_qos_characteristics_t *drb_qos_char_in = &drb_qos_in->qos_characteristics; - if (type == NON_DYNAMIC) { - asn1_qosparam->qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; - asn1cCalloc(asn1_qosparam->qoS_Characteristics.choice.non_Dynamic_5QI, tmp); - - /* 5QI */ - tmp->fiveQI = drb_qos_char_in->non_dynamic.fiveqi; - } else { - asn1_qosparam->qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(asn1_qosparam->qoS_Characteristics.choice.dynamic_5QI, tmp); - /* qoSPriorityLevel */ - tmp->qoSPriorityLevel = drb_qos_char_in->dynamic.qos_priority_level; - /* packetDelayBudget */ - tmp->packetDelayBudget = drb_qos_char_in->dynamic.packet_delay_budget; - /* packetErrorRate */ - tmp->packetErrorRate.pER_Scalar = drb_qos_char_in->dynamic.packet_error_rate.per_scalar; - tmp->packetErrorRate.pER_Exponent = drb_qos_char_in->dynamic.packet_error_rate.per_scalar; - - /* OPTIONAL delayCritical */ - // asn1cCallocOne(asn1_qosparam->qoS_Characteristics.choice.dynamic_5QI->delayCritical, 1L); - - /* OPTIONAL averagingWindow */ - // asn1cCallocOne(asn1_qosparam->qoS_Characteristics.choice.dynamic_5QI->averagingWindow, 1L); - - /* OPTIONAL maxDataBurstVolume */ - // asn1cCallocOne(asn1_qosparam->qoS_Characteristics.choice.dynamic_5QI->maxDataBurstVolume, 1L); - } - - { - asn1_qosparam->nGRANallocationRetentionPriority.priorityLevel = drb_qos_in->alloc_reten_priority.priority_level; - asn1_qosparam->nGRANallocationRetentionPriority.pre_emptionCapability = drb_qos_in->alloc_reten_priority.preemption_capability; - asn1_qosparam->nGRANallocationRetentionPriority.pre_emptionVulnerability = - drb_qos_in->alloc_reten_priority.preemption_vulnerability; - } // nGRANallocationRetentionPriority - - /* OPTIONAL */ - /* gBR_QoS_Flow_Information */ - if (0) { - asn1cCalloc(asn1_qosparam->gBR_QoS_Flow_Information, tmp); - asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); - - /* OPTIONAL */ - /* maxPacketLossRateDownlink */ - // asn1cCallocOne(asn1_qosparam->gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); - - /* OPTIONAL */ - /* maxPacketLossRateUplink */ - //asn1cCallocOne(asn1_qosparam->gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); - } - - /* OPTIONAL */ - /* reflective_QoS_Attribute */ - if (0) { - asn1cCallocOne(asn1_qosparam->reflective_QoS_Attribute, 1L); - } -} - -static void f1ap_write_drb_nssai(const nssai_t *nssai, F1AP_SNSSAI_t *asn1_nssai) -{ - OCTET_STRING_fromBuf(&asn1_nssai->sST, (char *)&nssai->sst, 1); - - /* OPTIONAL */ - if (nssai->sd != 0xffffff) { - char sd_buffer[3]; - INT24_TO_BUFFER(nssai->sd, sd_buffer); - asn1cCalloc(asn1_nssai->sD, sD); - OCTET_STRING_fromBuf(sD, sd_buffer, 3); - } -} - -static void f1ap_write_flows_mapped(const f1ap_flows_mapped_to_drb_t *flows_mapped, F1AP_Flows_Mapped_To_DRB_List_t *asn1_flows_mapped, int n) -{ - for (int k = 0; k < n; k++) { - asn1cSequenceAdd(asn1_flows_mapped->list, F1AP_Flows_Mapped_To_DRB_Item_t, flow_item); - - const f1ap_flows_mapped_to_drb_t *qos_flow_in = flows_mapped + k; - - /* qoSFlowIndicator */ - flow_item->qoSFlowIdentifier = qos_flow_in->qfi; - - /* qoSFlowLevelQoSParameters */ - const f1ap_qos_flow_level_qos_parameters_t *flow_qos_params_in = &qos_flow_in->qos_params; - /* qoS_Characteristics */ - - F1AP_QoS_Characteristics_t *QosParams = &flow_item->qoSFlowLevelQoSParameters.qoS_Characteristics; - const f1ap_qos_characteristics_t *flow_qos_char_in = &flow_qos_params_in->qos_characteristics; - - int type = flow_qos_params_in->qos_characteristics.qos_type; - if (type == NON_DYNAMIC) { - QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; - asn1cCalloc(QosParams->choice.non_Dynamic_5QI, tmp); - - /* 5QI */ - tmp->fiveQI = flow_qos_char_in->non_dynamic.fiveqi; - } else { - QosParams->present = F1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(QosParams->choice.dynamic_5QI, tmp); - /* qoSPriorityLevel */ - tmp->qoSPriorityLevel = flow_qos_char_in->dynamic.qos_priority_level; - /* packetDelayBudget */ - tmp->packetDelayBudget = flow_qos_char_in->dynamic.packet_delay_budget; - /* packetErrorRate */ - tmp->packetErrorRate.pER_Scalar = flow_qos_char_in->dynamic.packet_error_rate.per_scalar; - tmp->packetErrorRate.pER_Exponent = flow_qos_char_in->dynamic.packet_error_rate.per_exponent; - - /* OPTIONAL delayCritical */ - //asn1cCallocOne(QosParams->choice.dynamic_5QI->delayCritical, 1); - - /* OPTIONAL averagingWindow */ - //asn1cCallocOne(QosParams->choice.dynamic_5QI->averagingWindow, 1); - - /* OPTIONAL maxDataBurstVolume */ - //asn1cCallocOne(QosParams->choice.dynamic_5QI->maxDataBurstVolume, 1); - } - - /* nGRANallocationRetentionPriority */ - { - flow_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = - flow_qos_params_in->alloc_reten_priority.priority_level; - flow_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = - flow_qos_params_in->alloc_reten_priority.preemption_capability; - flow_item->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = - flow_qos_params_in->alloc_reten_priority.preemption_vulnerability; - } // nGRANallocationRetentionPriority - - /* OPTIONAL */ - /* gBR_QoS_Flow_Information */ - if (0) { - asn1cCalloc(flow_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information, tmp); - asn_long2INTEGER(&tmp->maxFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->maxFlowBitRateUplink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateDownlink, 1L); - asn_long2INTEGER(&tmp->guaranteedFlowBitRateUplink, 1L); - - /* OPTIONAL maxPacketLossRateDownlink */ - //asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateDownlink, 1L); - - /* OPTIONAL maxPacketLossRateUplink */ - //asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.gBR_QoS_Flow_Information->maxPacketLossRateUplink, 1L); - } - - /* OPTIONAL reflective_QoS_Attribute */ - //asn1cCallocOne(flows_mapped_to_drb_item->qoSFlowLevelQoSParameters.reflective_QoS_Attribute, 1L); - } -} - -int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setup_t *f1ap_ue_context_setup_req) -{ - F1AP_F1AP_PDU_t pdu= {0}; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_UEContextSetup; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextSetupRequest; - F1AP_UEContextSetupRequest_t *out = &pdu.choice.initiatingMessage->value.choice.UEContextSetupRequest; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_UEContextSetupRequestIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = f1ap_ue_context_setup_req->gNB_CU_ue_id; - - /* optional */ - /* c2. GNB_DU_UE_F1AP_ID */ - if (f1ap_ue_context_setup_req->gNB_DU_ue_id) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_ignore; - ie2->value.present = F1AP_UEContextSetupRequestIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = f1ap_ue_context_setup_req->gNB_DU_ue_id; - } - - /* mandatory */ - /* c3. SpCell_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_SpCell_ID; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_UEContextSetupRequestIEs__value_PR_NRCGI; - /* - nRCGI */ - addnRCGI(ie3->value.choice.NRCGI, f1ap_ue_context_setup_req); - /* mandatory */ - /* c4. ServCellIndex */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_ServCellIndex; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_UEContextSetupRequestIEs__value_PR_ServCellIndex; - ie4->value.choice.ServCellIndex = 0; - - /* optional */ - /* c5. CellULConfigured */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_SpCellULConfigured; - ie5->criticality = F1AP_Criticality_ignore; - ie5->value.present = F1AP_UEContextSetupRequestIEs__value_PR_CellULConfigured; - ie5->value.choice.CellULConfigured = F1AP_CellULConfigured_ul; - } - - /* mandatory */ - /* c6. CUtoDURRCInformation */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie6); - ie6->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation; - ie6->criticality = F1AP_Criticality_reject; - ie6->value.present = F1AP_UEContextSetupRequestIEs__value_PR_CUtoDURRCInformation; - - if (f1ap_ue_context_setup_req->cu_to_du_rrc_information!=NULL) { - /* optional */ - /* 6.1 cG_ConfigInfo */ - if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo_length > 0) { - DevAssert(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo != NULL); - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.cG_ConfigInfo, cG_ConfigInfo); - OCTET_STRING_fromBuf(cG_ConfigInfo, (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo, - f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo_length); - } - - /* optional */ - /* 6.2 uE_CapabilityRAT_ContainerList */ - if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList ); - OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, - f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); - } - /* optional */ - /* 6.3 measConfig */ - if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig!=NULL){ - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.measConfig, measConfig); - OCTET_STRING_fromBuf(measConfig, (const char*)f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig, - f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig_length); - } - - /* optional */ - /* HandoverPreparationInformation */ - if (f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo_length > 0) { - DevAssert(f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo != NULL); - F1AP_ProtocolExtensionContainer_10696P60_t *p = calloc(1, sizeof(*p)); - ie6->value.choice.CUtoDURRCInformation.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; - asn1cSequenceAdd(p->list, F1AP_CUtoDURRCInformation_ExtIEs_t, ie_ext); - ie_ext->id = F1AP_ProtocolIE_ID_id_HandoverPreparationInformation; - ie_ext->criticality = F1AP_Criticality_ignore; - ie_ext->extensionValue.present = F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_HandoverPreparationInformation; - OCTET_STRING_fromBuf(&ie_ext->extensionValue.choice.HandoverPreparationInformation, - (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo, - f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo_length); - } - } - - /* optional */ - if (0) { - /* c7. Candidate_SpCell_List */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie7); - ie7->id = F1AP_ProtocolIE_ID_id_Candidate_SpCell_List; // 90 - ie7->criticality = F1AP_Criticality_ignore; - ie7->value.present = F1AP_UEContextSetupRequestIEs__value_PR_Candidate_SpCell_List; - - for (int i = 0; i < 1; i++) { - asn1cSequenceAdd(ie7->value.choice.Candidate_SpCell_List.list, F1AP_Candidate_SpCell_ItemIEs_t, candidate_spCell_item_ies); - candidate_spCell_item_ies->id = F1AP_ProtocolIE_ID_id_Candidate_SpCell_Item; // 91 - candidate_spCell_item_ies->criticality = F1AP_Criticality_ignore; - candidate_spCell_item_ies->value.present = F1AP_Candidate_SpCell_ItemIEs__value_PR_Candidate_SpCell_Item; - /* 7.1 Candidate_SpCell_Item */ - F1AP_Candidate_SpCell_Item_t *candidate_spCell_item = &candidate_spCell_item_ies->value.choice.Candidate_SpCell_Item; - /* - candidate_SpCell_ID */ - // FixMe: first cell ??? - addnRCGI(candidate_spCell_item->candidate_SpCell_ID, f1ap_ue_context_setup_req); - /* TODO add correct mcc/mnc */ - } - } - - /* optional */ - /* c8. DRXCycle */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie8); - ie8->id = F1AP_ProtocolIE_ID_id_DRXCycle; - ie8->criticality = F1AP_Criticality_ignore; - ie8->value.present = F1AP_UEContextSetupRequestIEs__value_PR_DRXCycle; - /* 8.1 longDRXCycleLength */ - ie8->value.choice.DRXCycle.longDRXCycleLength = F1AP_LongDRXCycleLength_ms10; // enum - - /* optional */ - /* 8.2 shortDRXCycleLength */ - if (0) { - asn1cCallocOne(ie6->value.choice.DRXCycle.shortDRXCycleLength, - F1AP_ShortDRXCycleLength_ms2); // enum - } - - /* optional */ - /* 8.3 shortDRXCycleTimer */ - if (0) { - asn1cCallocOne(ie8->value.choice.DRXCycle.shortDRXCycleTimer, - 123L); - } - } - - /* optional */ - /* c9. ResourceCoordinationTransferContainer */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie9); - ie9->id = F1AP_ProtocolIE_ID_id_ResourceCoordinationTransferContainer; - ie9->criticality = F1AP_Criticality_ignore; - ie9->value.present = F1AP_UEContextSetupRequestIEs__value_PR_ResourceCoordinationTransferContainer; - ie9->value.choice.ResourceCoordinationTransferContainer.buf = malloc(4); - ie9->value.choice.ResourceCoordinationTransferContainer.size = 4; - strncpy((char *)ie9->value.choice.ResourceCoordinationTransferContainer.buf, "123", 4); - OCTET_STRING_fromBuf(&ie9->value.choice.ResourceCoordinationTransferContainer, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); - } - - /* optional */ - if (0) { - /* c10. SCell_ToBeSetup_List */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie10); - ie10->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetup_List; - ie10->criticality = F1AP_Criticality_ignore; - ie10->value.present = F1AP_UEContextSetupRequestIEs__value_PR_SCell_ToBeSetup_List; - - for (int i = 0; i < 1; i++) { - asn1cSequenceAdd(ie10->value.choice.SCell_ToBeSetup_List.list, F1AP_SCell_ToBeSetup_ItemIEs_t, scell_toBeSetup_item_ies); - scell_toBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetup_Item; // 53 - scell_toBeSetup_item_ies->criticality = F1AP_Criticality_ignore; - scell_toBeSetup_item_ies->value.present = F1AP_SCell_ToBeSetup_ItemIEs__value_PR_SCell_ToBeSetup_Item; - /* 10.1 SCell_ToBeSetup_Item */ - F1AP_SCell_ToBeSetup_Item_t *scell_toBeSetup_item = &scell_toBeSetup_item_ies->value.choice.SCell_ToBeSetup_Item; - /* 10.1.1 sCell_ID */ - addnRCGI(scell_toBeSetup_item->sCell_ID, f1ap_ue_context_setup_req); - /* TODO correct MCC/MNC */ - /* 10.1.2 sCellIndex */ - scell_toBeSetup_item->sCellIndex = 3; // issue here - - /* OPTIONAL */ - /* 10.1.3 sCellULConfigured*/ - if (0) { - asn1cCallocOne(scell_toBeSetup_item->sCellULConfigured, - F1AP_CellULConfigured_ul_and_sul); // enum - } - } - } - - /* mandatory */ - /* c11. SRBs_ToBeSetup_List */ - if(f1ap_ue_context_setup_req->srbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie11); - ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List; - ie11->criticality = F1AP_Criticality_reject; // ? - ie11->value.present = F1AP_UEContextSetupRequestIEs__value_PR_SRBs_ToBeSetup_List; - - for (int i=0; isrbs_to_be_setup_length; i++) { - asn1cSequenceAdd(ie11->value.choice.SRBs_ToBeSetup_List.list, F1AP_SRBs_ToBeSetup_ItemIEs_t, srbs_toBeSetup_item_ies); - srbs_toBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_Item; // 73 - srbs_toBeSetup_item_ies->criticality = F1AP_Criticality_reject; - srbs_toBeSetup_item_ies->value.present = F1AP_SRBs_ToBeSetup_ItemIEs__value_PR_SRBs_ToBeSetup_Item; - /* 11.1 SRBs_ToBeSetup_Item */ - F1AP_SRBs_ToBeSetup_Item_t *srbs_toBeSetup_item=&srbs_toBeSetup_item_ies->value.choice.SRBs_ToBeSetup_Item; - /* 11.1.1 sRBID */ - srbs_toBeSetup_item->sRBID = f1ap_ue_context_setup_req->srbs_to_be_setup[i].srb_id; - /* OPTIONAL */ - /* 11.1.2 duplicationIndication */ - asn1cCallocOne(srbs_toBeSetup_item->duplicationIndication, - F1AP_DuplicationIndication_true); // enum - } - } - - /* mandatory */ - /* c12. DRBs_ToBeSetup_List */ - if(f1ap_ue_context_setup_req->drbs_to_be_setup_length){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie12); - ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List; - ie12->criticality = F1AP_Criticality_reject; - ie12->value.present = F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List; - - for (int i = 0; i < f1ap_ue_context_setup_req->drbs_to_be_setup_length; i++) { - const f1ap_drb_to_be_setup_t *drb = &f1ap_ue_context_setup_req->drbs_to_be_setup[i]; - asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetup_List.list, F1AP_DRBs_ToBeSetup_ItemIEs_t, drbs_toBeSetup_item_ies); - drbs_toBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_Item; - drbs_toBeSetup_item_ies->criticality = F1AP_Criticality_reject; - drbs_toBeSetup_item_ies->value.present = F1AP_DRBs_ToBeSetup_ItemIEs__value_PR_DRBs_ToBeSetup_Item; - /* 12.1 DRBs_ToBeSetup_Item */ - F1AP_DRBs_ToBeSetup_Item_t *drbs_toBeSetup_item=&drbs_toBeSetup_item_ies->value.choice.DRBs_ToBeSetup_Item; - /* 12.1.1 dRBID */ - drbs_toBeSetup_item->dRBID = drb->drb_id; - /* 12.1.2 qoSInformation */ - int some_decide_qos = 0; // BK: Need Check - - if (some_decide_qos) { - drbs_toBeSetup_item->qoSInformation.present = F1AP_QoSInformation_PR_eUTRANQoS; - /* 12.1.2.1 eUTRANQoS */ - asn1cCalloc(drbs_toBeSetup_item->qoSInformation.choice.eUTRANQoS, eUTRANQoS); - /* 12.1.2.1.1 qCI */ - eUTRANQoS->qCI = 254L; - /* 12.1.2.1.2 allocationAndRetentionPriority */ - { - /* 12.1.2.1.2.1 priorityLevel */ - eUTRANQoS->allocationAndRetentionPriority.priorityLevel = F1AP_PriorityLevel_highest; // enum - /* 12.1.2.1.2.2 pre_emptionCapability */ - eUTRANQoS->allocationAndRetentionPriority.pre_emptionCapability = F1AP_Pre_emptionCapability_may_trigger_pre_emption; // enum - /* 12.1.2.1.2.2 pre_emptionVulnerability */ - eUTRANQoS->allocationAndRetentionPriority.pre_emptionVulnerability = F1AP_Pre_emptionVulnerability_not_pre_emptable; // enum - } - - /* OPTIONAL */ - /* 12.1.2.1.3 gbrQosInformation */ - if (0) { - eUTRANQoS->gbrQosInformation = (F1AP_GBR_QosInformation_t *)calloc(1, sizeof(F1AP_GBR_QosInformation_t)); - asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_MaximumBitrateDL, 1L); - asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_MaximumBitrateUL, 1L); - asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_GuaranteedBitrateDL, 1L); - asn_long2INTEGER(&eUTRANQoS->gbrQosInformation->e_RAB_GuaranteedBitrateUL, 1L); - } - } else { - /* 12.1.2 DRB_Information */ - const f1ap_drb_information_t *drb_info = &drb->drb_info; - drbs_toBeSetup_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; - F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie)); - ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; - ie->criticality = F1AP_Criticality_reject; - ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; - F1AP_DRB_Information_t *DRB_Information = &ie->value.choice.DRB_Information; - drbs_toBeSetup_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie; - - /* 12.1.2.1 dRB_QoS */ - f1ap_write_drb_qos_param(&drb_info->drb_qos, &DRB_Information->dRB_QoS); - - /* 12.1.2.2 sNSSAI */ - f1ap_write_drb_nssai(&drb->nssai, &DRB_Information->sNSSAI); - - /* OPTIONAL */ - /* 12.1.2.3 notificationControl */ - if (0) { - asn1cCallocOne(DRB_Information->notificationControl, - F1AP_NotificationControl_active); // enum - } - - /* 12.1.2.4 flows_Mapped_To_DRB_List */ // BK: need verifiy - f1ap_write_flows_mapped(drb_info->flows_mapped_to_drb, &DRB_Information->flows_Mapped_To_DRB_List, drb_info->flows_to_be_setup_length); - } // if some_decide_qos - - /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ - for (int j = 0; j < f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) { - DevAssert(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid > 0); - /* 12.3.1 ULTunnels_ToBeSetup_Item */ - asn1cSequenceAdd(drbs_toBeSetup_item->uLUPTNLInformation_ToBeSetup_List.list, - F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc( uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, - gTPTunnel); - /* 12.3.1.1.1 transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].tl_address, - &gTPTunnel->transportLayerAddress); - /* 12.3.1.1.2 gTP_TEID */ - INT32_TO_OCTET_STRING(f1ap_ue_context_setup_req->drbs_to_be_setup[i].up_ul_tnl[j].teid, - &gTPTunnel->gTP_TEID); - } - - /* 12.1.4 rLCMode */ - /* TODO use rlc_mode from f1ap_drb_to_be_setup */ - switch (f1ap_ue_context_setup_req->drbs_to_be_setup[i].rlc_mode) { - case F1AP_RLC_MODE_AM: - drbs_toBeSetup_item->rLCMode = F1AP_RLCMode_rlc_am; - break; - case F1AP_RLC_MODE_UM_BIDIR: - drbs_toBeSetup_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; - break; - default: - AssertFatal(false, "modes other than AM/UM-Bidir not supported\n"); - break; - } - - /* OPTIONAL */ - /* 12.1.5 ULConfiguration */ - if (0) { - asn1cCalloc(drbs_toBeSetup_item->uLConfiguration, tmp); - tmp->uLUEConfiguration = F1AP_ULUEConfiguration_no_data; - } - - /* OPTIONAL */ - /* 12.1.6 duplicationActivation */ - if (0) { - asn1cCalloc(drbs_toBeSetup_item->duplicationActivation, tmp); - *tmp = F1AP_DuplicationActivation_active; // enum - } - } - } - - /* OPTIONAL */ - /* InactivityMonitoringRequest */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie12); - ie12->id = F1AP_ProtocolIE_ID_id_InactivityMonitoringRequest; - ie12->criticality = F1AP_Criticality_reject; - ie12->value.present = F1AP_UEContextSetupRequestIEs__value_PR_InactivityMonitoringRequest; - ie12->value.choice.InactivityMonitoringRequest = F1AP_InactivityMonitoringRequest_true; // 0 - } - - /* OPTIONAL */ - /* RAT_FrequencyPriorityInformation */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie13); - ie13->id = F1AP_ProtocolIE_ID_id_RAT_FrequencyPriorityInformation; - ie13->criticality = F1AP_Criticality_reject; - ie13->value.present = F1AP_UEContextSetupRequestIEs__value_PR_RAT_FrequencyPriorityInformation; - int endc = 1; // RK: Get this from somewhere ... - - if (endc) { - ie13->value.choice.RAT_FrequencyPriorityInformation.present = F1AP_RAT_FrequencyPriorityInformation_PR_eNDC; - ie13->value.choice.RAT_FrequencyPriorityInformation.choice.eNDC = 11L; - } else { - ie13->value.choice.RAT_FrequencyPriorityInformation.present = F1AP_RAT_FrequencyPriorityInformation_PR_nGRAN; - ie13->value.choice.RAT_FrequencyPriorityInformation.choice.nGRAN = 11L; - } - } - - /* OPTIONAL */ - /* RRCContainer */ - if(f1ap_ue_context_setup_req->rrc_container_length > 0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie14); - ie14->id = F1AP_ProtocolIE_ID_id_RRCContainer; - ie14->criticality = F1AP_Criticality_ignore; - ie14->value.present = F1AP_UEContextSetupRequestIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie14->value.choice.RRCContainer, (const char *)f1ap_ue_context_setup_req->rrc_container, - f1ap_ue_context_setup_req->rrc_container_length); - } - - /* OPTIONAL */ - /* MaskedIMEISV */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie15); - ie15->id = F1AP_ProtocolIE_ID_id_MaskedIMEISV; - ie15->criticality = F1AP_Criticality_reject; - ie15->value.present = F1AP_UEContextSetupRequestIEs__value_PR_MaskedIMEISV; - MaskedIMEISV_TO_BIT_STRING(12340000l, &ie15->value.choice.MaskedIMEISV); // size (64) - } - - /* encode */ - uint8_t *buffer=NULL; - uint32_t len=0; - - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + uint8_t *buffer = NULL; + uint32_t len = 0; + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 UE CONTEXT SETUP REQUEST\n"); return -1; } + f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + #ifdef E2_AGENT - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[0], f1ap_ue_context_setup_req->gNB_CU_ue_id); + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[0], req->gNB_CU_ue_id); signal_ue_id(&ue_context_p->ue_context, F1_NETWORK_INTERFACE_TYPE, 0); #endif - // xer_fprint(stdout, &asn_DEF_F1AP_F1AP_PDU, (void *)pdu); - // asn_encode_to_new_buffer_result_t res = { NULL, {0, NULL, NULL} }; - // res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_F1AP_F1AP_PDU, pdu); - // buffer = res.buffer; - // len = res.result.encoded; - // if (res.result.encoded <= 0) { - // LOG_E(F1AP, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); - // return -1; - // } - LOG_D(F1AP,"F1AP UEContextSetupRequest Encoded %u bits\n", len); - f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } int CU_handle_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - MessageDef *msg_p; - F1AP_UEContextSetupResponse_t *container; - F1AP_UEContextSetupResponseIEs_t *ie; - DevAssert(pdu); - msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_SETUP_RESP); - msg_p->ittiMsgHeader.originInstance = assoc_id; - f1ap_ue_context_setup_t *f1ap_ue_context_setup_resp = &F1AP_UE_CONTEXT_SETUP_RESP(msg_p); - container = &pdu->choice.successfulOutcome->value.choice.UEContextSetupResponse; - int i; - /* GNB_CU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - f1ap_ue_context_setup_resp->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; - LOG_D(F1AP, "f1ap_ue_context_setup_resp->gNB_CU_ue_id is: %d \n", f1ap_ue_context_setup_resp->gNB_CU_ue_id); - /* GNB_DU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - f1ap_ue_context_setup_resp->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; - LOG_D(F1AP, "f1ap_ue_context_setup_resp->gNB_DU_ue_id is: %d \n", f1ap_ue_context_setup_resp->gNB_DU_ue_id); - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, F1AP_ProtocolIE_ID_id_C_RNTI, false); - if (ie) { - f1ap_ue_context_setup_resp->crnti = calloc(1, sizeof(uint16_t)); - *f1ap_ue_context_setup_resp->crnti = ie->value.choice.C_RNTI; - } - - // DUtoCURRCInformation - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, true); - - if (ie == NULL) { - LOG_E(F1AP,"%s %d: ie is a NULL pointer \n",__FILE__,__LINE__); + f1ap_ue_context_setup_resp_t resp = {0}; + if (!decode_ue_context_setup_resp(pdu, &resp)) { + LOG_E(F1AP, "cannot decode F1 UE Context Setup Resp\n"); + free_ue_context_setup_resp(&resp); return -1; } - f1ap_ue_context_setup_resp->du_to_cu_rrc_information = (du_to_cu_rrc_information_t *)calloc(1,sizeof(du_to_cu_rrc_information_t)); - f1ap_ue_context_setup_resp->du_to_cu_rrc_information->cellGroupConfig = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - memcpy(f1ap_ue_context_setup_resp->du_to_cu_rrc_information->cellGroupConfig, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - f1ap_ue_context_setup_resp->du_to_cu_rrc_information->cellGroupConfig_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; - // DRBs_Setup_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_DRBs_Setup_List, false); - - if(ie!=NULL) { - f1ap_ue_context_setup_resp->drbs_to_be_setup_length = ie->value.choice.DRBs_Setup_List.list.count; - f1ap_ue_context_setup_resp->drbs_to_be_setup = calloc(f1ap_ue_context_setup_resp->drbs_to_be_setup_length, - sizeof(f1ap_drb_to_be_setup_t)); - AssertFatal(f1ap_ue_context_setup_resp->drbs_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_resp->drbs_setup\n"); - - for (i = 0; i < f1ap_ue_context_setup_resp->drbs_to_be_setup_length; ++i) { - f1ap_drb_to_be_setup_t *drb_p = &f1ap_ue_context_setup_resp->drbs_to_be_setup[i]; - F1AP_DRBs_Setup_Item_t *drbs_setup_item_p; - drbs_setup_item_p = &((F1AP_DRBs_Setup_ItemIEs_t *)ie->value.choice.DRBs_Setup_List.list.array[i])->value.choice.DRBs_Setup_Item; - drb_p->drb_id = drbs_setup_item_p->dRBID; - // TODO in the following, assume only one UP UL TNL is present. - // this matches/assumes OAI CU/DU implementation, can be up to 2! - drb_p->up_dl_tnl_length = 1; - AssertFatal(drbs_setup_item_p->dLUPTNLInformation_ToBeSetup_List.list.count > 0, - "no DL UP TNL Information in DRBs to be Setup list\n"); - F1AP_DLUPTNLInformation_ToBeSetup_Item_t *dl_up_tnl_info_p = (F1AP_DLUPTNLInformation_ToBeSetup_Item_t *)drbs_setup_item_p->dLUPTNLInformation_ToBeSetup_List.list.array[0]; - F1AP_GTPTunnel_t *dl_up_tnl0 = dl_up_tnl_info_p->dLUPTNLInformation.choice.gTPTunnel; - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&dl_up_tnl0->transportLayerAddress, drb_p->up_dl_tnl[0].tl_address); - OCTET_STRING_TO_UINT32(&dl_up_tnl0->gTP_TEID, drb_p->up_dl_tnl[0].teid); - } - } - - // SRBs_FailedToBeSetup_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetup_List, false); - - if(ie!=NULL) { - f1ap_ue_context_setup_resp->srbs_failed_to_be_setup_length = ie->value.choice.SRBs_FailedToBeSetup_List.list.count; - f1ap_ue_context_setup_resp->srbs_failed_to_be_setup = calloc(f1ap_ue_context_setup_resp->srbs_failed_to_be_setup_length, - sizeof(f1ap_rb_failed_to_be_setup_t)); - AssertFatal(f1ap_ue_context_setup_resp->srbs_failed_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_resp->srbs_failed_to_be_setup\n"); - - for (i = 0; i < f1ap_ue_context_setup_resp->srbs_failed_to_be_setup_length; ++i) { - f1ap_rb_failed_to_be_setup_t *srb_p = &f1ap_ue_context_setup_resp->srbs_failed_to_be_setup[i]; - srb_p->rb_id = ((F1AP_SRBs_FailedToBeSetup_Item_t *)ie->value.choice.SRBs_FailedToBeSetup_List.list.array[i])->sRBID; - } - } - - // DRBs_FailedToBeSetup_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetup_List, false); - - if(ie!=NULL) { - f1ap_ue_context_setup_resp->drbs_failed_to_be_setup_length = ie->value.choice.DRBs_FailedToBeSetup_List.list.count; - f1ap_ue_context_setup_resp->drbs_failed_to_be_setup = calloc(f1ap_ue_context_setup_resp->drbs_failed_to_be_setup_length, - sizeof(f1ap_rb_failed_to_be_setup_t)); - AssertFatal(f1ap_ue_context_setup_resp->drbs_failed_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_resp->drbs_failed_to_be_setup\n"); - - for (i = 0; i < f1ap_ue_context_setup_resp->drbs_failed_to_be_setup_length; ++i) { - f1ap_rb_failed_to_be_setup_t *drb_p = &f1ap_ue_context_setup_resp->drbs_failed_to_be_setup[i]; - drb_p->rb_id = ((F1AP_DRBs_FailedToBeSetup_Item_t *)ie->value.choice.DRBs_FailedToBeSetup_List.list.array[i])->dRBID; - } - } - - // SCell_FailedtoSetup_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SCell_FailedtoSetup_List, false); - - if(ie!=NULL) { - LOG_E (F1AP, "Not supporting handling of SCell_FailedtoSetup_List \n"); - } - - // SRBs_Setup_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SRBs_Setup_List, false); - - if(ie!=NULL) { - f1ap_ue_context_setup_resp->srbs_to_be_setup_length = ie->value.choice.SRBs_Setup_List.list.count; - f1ap_ue_context_setup_resp->srbs_to_be_setup = calloc(f1ap_ue_context_setup_resp->srbs_to_be_setup_length, - sizeof(f1ap_srb_to_be_setup_t)); - AssertFatal(f1ap_ue_context_setup_resp->srbs_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_resp->drbs_setup\n"); - - for (i = 0; i < f1ap_ue_context_setup_resp->srbs_to_be_setup_length; ++i) { - f1ap_srb_to_be_setup_t *srb_p = &f1ap_ue_context_setup_resp->srbs_to_be_setup[i]; - F1AP_SRBs_Setup_Item_t *srbs_setup_item_p; - srbs_setup_item_p = &((F1AP_SRBs_Setup_ItemIEs_t *)ie->value.choice.SRBs_Setup_List.list.array[i])->value.choice.SRBs_Setup_Item; - srb_p->srb_id = srbs_setup_item_p->sRBID; - srb_p->lcid = srbs_setup_item_p->lCID; - } - } - + MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_SETUP_RESP); + msg_p->ittiMsgHeader.originInstance = assoc_id; + F1AP_UE_CONTEXT_SETUP_RESP(msg_p) = resp; itti_send_msg_to_task(TASK_RRC_GNB, instance, msg_p); return 0; } @@ -754,762 +90,81 @@ int CU_handle_UE_CONTEXT_SETUP_FAILURE(instance_t instance, sctp_assoc_t assoc_i int CU_handle_UE_CONTEXT_RELEASE_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { + f1ap_ue_context_rel_req_t req = {0}; + if (!decode_ue_context_rel_req(pdu, &req)) { + LOG_E(F1AP, "cannot decode F1 UE Context Release Request\n"); + free_ue_context_rel_req(&req); + return -1; + } + MessageDef *msg = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_UE_CONTEXT_RELEASE_REQ); msg->ittiMsgHeader.originInstance = assoc_id; - f1ap_ue_context_release_req_t *req = &F1AP_UE_CONTEXT_RELEASE_REQ(msg); - F1AP_UEContextReleaseRequest_t *container; - F1AP_UEContextReleaseRequestIEs_t *ie; - DevAssert(pdu); - container = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseRequest; - /* GNB_CU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseRequestIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - req->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; - - /* GNB_DU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseRequestIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - req->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; - - /* Cause */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseRequestIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_Cause, true); - - switch(ie->value.choice.Cause.present) - { - case F1AP_Cause_PR_radioNetwork: - req->cause = F1AP_CAUSE_RADIO_NETWORK; - req->cause_value = ie->value.choice.Cause.choice.radioNetwork; - break; - case F1AP_Cause_PR_transport: - req->cause = F1AP_CAUSE_TRANSPORT; - req->cause_value = ie->value.choice.Cause.choice.transport; - break; - case F1AP_Cause_PR_protocol: - req->cause = F1AP_CAUSE_PROTOCOL; - req->cause_value = ie->value.choice.Cause.choice.protocol; - break; - case F1AP_Cause_PR_misc: - req->cause = F1AP_CAUSE_MISC; - req->cause_value = ie->value.choice.Cause.choice.misc; - break; - case F1AP_Cause_PR_NOTHING: - default: - req->cause = F1AP_CAUSE_NOTHING; - break; - } - - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseRequestIEs_t, ie, container, F1AP_ProtocolIE_ID_id_targetCellsToCancel, false); - if (ie != NULL) { - LOG_W(F1AP, "ignoring list of target cells to cancel in UE Context Release Request: implementation missing\n"); - } - + F1AP_UE_CONTEXT_RELEASE_REQ(msg) = req; itti_send_msg_to_task(TASK_RRC_GNB, instance, msg); - return 0; } -int CU_send_UE_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, f1ap_ue_context_release_cmd_t *cmd) +int CU_send_UE_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, f1ap_ue_context_rel_cmd_t *cmd) { - F1AP_F1AP_PDU_t pdu= {0}; - F1AP_UEContextReleaseCommand_t *out; - uint8_t *buffer=NULL; - uint32_t len=0; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_UEContextRelease; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextReleaseCommand; - out = &tmp->value.choice.UEContextReleaseCommand; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = cmd->gNB_CU_ue_id; - /* mandatory */ - /* c2. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = cmd->gNB_DU_ue_id; - /* mandatory */ - /* c3. Cause */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_Cause; - ie3->criticality = F1AP_Criticality_ignore; - ie3->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_Cause; + F1AP_F1AP_PDU_t *pdu = encode_ue_context_rel_cmd(cmd); - switch (cmd->cause) { - case F1AP_CAUSE_RADIO_NETWORK: - ie3->value.choice.Cause.present = F1AP_Cause_PR_radioNetwork; - ie3->value.choice.Cause.choice.radioNetwork = cmd->cause_value; - break; - - case F1AP_CAUSE_TRANSPORT: - ie3->value.choice.Cause.present = F1AP_Cause_PR_transport; - ie3->value.choice.Cause.choice.transport = cmd->cause_value; - break; - - case F1AP_CAUSE_PROTOCOL: - ie3->value.choice.Cause.present = F1AP_Cause_PR_protocol; - ie3->value.choice.Cause.choice.protocol = cmd->cause_value; - break; - - case F1AP_CAUSE_MISC: - ie3->value.choice.Cause.present = F1AP_Cause_PR_misc; - ie3->value.choice.Cause.choice.misc = cmd->cause_value; - break; - - case F1AP_CAUSE_NOTHING: - default: - ie3->value.choice.Cause.present = F1AP_Cause_PR_NOTHING; - break; - } - - /* optional */ - /* c4. RRCContainer */ - if(cmd->rrc_container!=NULL){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer; - ie4->criticality = F1AP_Criticality_ignore; - ie4->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, (const char *)cmd->rrc_container, - cmd->rrc_container_length); - - // conditionally have SRBID if RRC Container - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_SRBID; - ie5->criticality = F1AP_Criticality_ignore; - ie5->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_SRBID; - ie5->value.choice.SRBID = cmd->srb_id; - } - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + uint8_t *buffer = NULL; + uint32_t len = 0; + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 context release command\n"); return -1; } f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return 0; } int CU_handle_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - F1AP_UEContextReleaseComplete_t *container; - F1AP_UEContextReleaseCompleteIEs_t *ie; - DevAssert(pdu); - MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_RELEASE_COMPLETE); - msg_p->ittiMsgHeader.originInstance = assoc_id; - f1ap_ue_context_release_complete_t *complete = &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg_p); - container = &pdu->choice.successfulOutcome->value.choice.UEContextReleaseComplete; - /* GNB_CU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCompleteIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - complete->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; - /* GNB_DU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCompleteIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - complete->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; - - /* Optional*/ - /* CriticalityDiagnostics */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCompleteIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_CriticalityDiagnostics, false); - - if (ie) { - // ie->value.choice.CriticalityDiagnostics.procedureCode - // ie->value.choice.CriticalityDiagnostics.triggeringMessage - // ie->value.choice.CriticalityDiagnostics.procedureCriticality - // ie->value.choice.CriticalityDiagnostics.transactionID - // F1AP_CriticalityDiagnostics_IE_List + f1ap_ue_context_rel_cplt_t cplt = {0}; + if (!decode_ue_context_rel_cplt(pdu, &cplt)) { + LOG_E(F1AP, "cannot decode F1 UE Context Release Complete\n"); + free_ue_context_rel_cplt(&cplt); + return -1; } + MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_RELEASE_COMPLETE); + msg_p->ittiMsgHeader.originInstance = assoc_id; + F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg_p) = cplt; itti_send_msg_to_task(TASK_RRC_GNB, instance, msg_p); - return 0; } -int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_modif_req_t *f1ap_ue_context_modification_req) +int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, const f1ap_ue_context_mod_req_t *req) { - F1AP_F1AP_PDU_t pdu= {0}; - F1AP_UEContextModificationRequest_t *out; + F1AP_F1AP_PDU_t *pdu = encode_ue_context_mod_req(req); + uint8_t *buffer=NULL; uint32_t len=0; - - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_UEContextModification; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextModificationRequest; - out = &tmp->value.choice.UEContextModificationRequest; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_UEContextModificationRequestIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = f1ap_ue_context_modification_req->gNB_CU_ue_id; - /* mandatory */ - /* c2. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_UEContextModificationRequestIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = f1ap_ue_context_modification_req->gNB_DU_ue_id; - - /* optional */ - /* c3. NRCGI */ - if (true) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_SpCell_ID; - ie3->criticality = F1AP_Criticality_ignore; - ie3->value.present = F1AP_UEContextModificationRequestIEs__value_PR_NRCGI; - /* - nRCGI */ - - f1ap_served_cell_info_t nrcgi = { - .plmn = f1ap_ue_context_modification_req->plmn, - .nr_cellid = f1ap_ue_context_modification_req->nr_cellid, - }; - addnRCGI(ie3->value.choice.NRCGI, &nrcgi); - } - - /* optional */ - /* c4. ServCellIndex */ - if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_ServCellIndex; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_UEContextModificationRequestIEs__value_PR_ServCellIndex; - ie4->value.choice.ServCellIndex = 5L; - } - - /* optional */ - /* c5. DRXCycle */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_DRXCycle; - ie5->criticality = F1AP_Criticality_ignore; - ie5->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRXCycle; - ie5->value.choice.DRXCycle.longDRXCycleLength = F1AP_LongDRXCycleLength_ms10; // enum - - if (0) { - asn1cCallocOne(ie5->value.choice.DRXCycle.shortDRXCycleLength, - F1AP_ShortDRXCycleLength_ms2); // enum - } - - if (0) { - asn1cCallocOne(ie5->value.choice.DRXCycle.shortDRXCycleTimer, 123L); - } - } - - /* optional */ - /* c6. CUtoDURRCInformation */ - if (f1ap_ue_context_modification_req->cu_to_du_rrc_information!=NULL) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie6); - ie6->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation; - ie6->criticality = F1AP_Criticality_reject; - ie6->value.present = F1AP_UEContextModificationRequestIEs__value_PR_CUtoDURRCInformation; - /* 6.1 cG_ConfigInfo */ - if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->cG_ConfigInfo!=NULL){ - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.cG_ConfigInfo, cG_ConfigInfo); - OCTET_STRING_fromBuf(cG_ConfigInfo, (const char *)f1ap_ue_context_modification_req->cu_to_du_rrc_information->cG_ConfigInfo, - f1ap_ue_context_modification_req->cu_to_du_rrc_information->cG_ConfigInfo_length); - } - /* optional */ - /* 6.2 uE_CapabilityRAT_ContainerList */ - if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){ - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList ); - OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, - f1ap_ue_context_modification_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length) ; - } - /* optional */ - /* 6.3 measConfig */ - if(f1ap_ue_context_modification_req->cu_to_du_rrc_information->measConfig!=NULL){ - asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.measConfig, measConfig); - OCTET_STRING_fromBuf(measConfig, (const char *)f1ap_ue_context_modification_req->cu_to_du_rrc_information->measConfig, - f1ap_ue_context_modification_req->cu_to_du_rrc_information->measConfig_length); - } - } - - /* optional */ - /* c7. TransmissionActionIndicator */ - if (f1ap_ue_context_modification_req->transm_action_ind != NULL) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie7); - ie7->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator; - ie7->criticality = F1AP_Criticality_ignore; - ie7->value.present = F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator; - ie7->value.choice.TransmissionActionIndicator = *f1ap_ue_context_modification_req->transm_action_ind; - // Stop is guaranteed to be 0, by restart might be different from 1 - static_assert((int)F1AP_TransmissionActionIndicator_restart == (int)TransmActionInd_RESTART, - "mismatch of ASN.1 and internal representation\n"); - } - - /* optional */ - /* c8. ResourceCoordinationTransferContainer */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie8); - ie8->id = F1AP_ProtocolIE_ID_id_ResourceCoordinationTransferContainer; - ie8->criticality = F1AP_Criticality_ignore; - ie8->value.present = F1AP_UEContextModificationRequestIEs__value_PR_ResourceCoordinationTransferContainer; - OCTET_STRING_fromBuf(&ie8->value.choice.ResourceCoordinationTransferContainer, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); - } - - /* optional */ - /* c7. RRCRconfigurationCompleteIndicator */ - if (f1ap_ue_context_modification_req->ReconfigComplOutcome == RRCreconf_success) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie71); - ie71->id = F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator; - ie71->criticality = F1AP_Criticality_ignore; - ie71->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCReconfigurationCompleteIndicator; - ie71->value.choice.RRCReconfigurationCompleteIndicator = F1AP_RRCReconfigurationCompleteIndicator_true; - } - - /* optional */ - /* c8. RRCContainer */ - if (f1ap_ue_context_modification_req->rrc_container != NULL) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie81); - ie81->id = F1AP_ProtocolIE_ID_id_RRCContainer; - ie81->criticality = F1AP_Criticality_ignore; - ie81->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie81->value.choice.RRCContainer, (const char*)f1ap_ue_context_modification_req->rrc_container, - f1ap_ue_context_modification_req->rrc_container_length); - } - - /* optional */ - /* c9. SCell_ToBeSetupMod_List */ - if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie9); - ie9->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetupMod_List; - ie9->criticality = F1AP_Criticality_ignore; - ie9->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SCell_ToBeSetupMod_List; - - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie9->value.choice.SCell_ToBeSetupMod_List.list, - F1AP_SCell_ToBeSetupMod_ItemIEs_t, scell_toBeSetupMod_item_ies); - scell_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_ToBeSetupMod_Item; - scell_toBeSetupMod_item_ies->criticality = F1AP_Criticality_ignore; - scell_toBeSetupMod_item_ies->value.present = F1AP_SCell_ToBeSetupMod_ItemIEs__value_PR_SCell_ToBeSetupMod_Item; - /* 8.1 SCell_ToBeSetup_Item */ - F1AP_SCell_ToBeSetupMod_Item_t *scell_toBeSetupMod_item= - &scell_toBeSetupMod_item_ies->value.choice.SCell_ToBeSetupMod_Item; - // /* - sCell_ID */ - f1ap_served_cell_info_t hardCoded = {0}; - addnRCGI(scell_toBeSetupMod_item->sCell_ID, &hardCoded); - /* sCellIndex */ - scell_toBeSetupMod_item->sCellIndex = 6; // issue here - } - } - - /* optional */ - /* c10. SCell_ToBeRemoved_List */ - if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie10); - ie10->id = F1AP_ProtocolIE_ID_id_SCell_ToBeRemoved_List; - ie10->criticality = F1AP_Criticality_ignore; - ie10->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SCell_ToBeRemoved_List; - - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie10->value.choice.SCell_ToBeRemoved_List.list, - F1AP_SCell_ToBeRemoved_ItemIEs_t, scell_toBeRemoved_item_ies); - scell_toBeRemoved_item_ies = (F1AP_SCell_ToBeRemoved_ItemIEs_t *)calloc(1, sizeof(F1AP_SCell_ToBeRemoved_ItemIEs_t)); - //memset((void *)&scell_toBeRemoved_item_ies, 0, sizeof(F1AP_SCell_ToBeRemoved_ItemIEs_t)); - scell_toBeRemoved_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_ToBeRemoved_Item; - scell_toBeRemoved_item_ies->criticality = F1AP_Criticality_ignore; - scell_toBeRemoved_item_ies->value.present = F1AP_SCell_ToBeRemoved_ItemIEs__value_PR_SCell_ToBeRemoved_Item; - /* 10.1 SCell_ToBeRemoved_Item */ - F1AP_SCell_ToBeRemoved_Item_t *scell_toBeRemoved_item= - &scell_toBeRemoved_item_ies->value.choice.SCell_ToBeRemoved_Item; - /* - sCell_ID */ - f1ap_served_cell_info_t hardCoded = {0}; - addnRCGI(scell_toBeRemoved_item->sCell_ID, &hardCoded); - } - } - - /* mandatory */ - /* c11. SRBs_ToBeSetupMod_List */ - if(f1ap_ue_context_modification_req->srbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie11); - ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List; - ie11->criticality = F1AP_Criticality_reject; - ie11->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeSetupMod_List; - - for (int i=0; isrbs_to_be_setup_length; i++) { - // - asn1cSequenceAdd(ie11->value.choice.SRBs_ToBeSetupMod_List, F1AP_SRBs_ToBeSetupMod_ItemIEs_t, srbs_toBeSetupMod_item_ies); - srbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item; // 73 - srbs_toBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; - srbs_toBeSetupMod_item_ies->value.present = F1AP_SRBs_ToBeSetupMod_ItemIEs__value_PR_SRBs_ToBeSetupMod_Item; - /* 11.1 SRBs_ToBeSetup_Item */ - F1AP_SRBs_ToBeSetupMod_Item_t *srbs_toBeSetupMod_item=&srbs_toBeSetupMod_item_ies->value.choice.SRBs_ToBeSetupMod_Item; - /* 11.1.1 sRBID */ - srbs_toBeSetupMod_item->sRBID = f1ap_ue_context_modification_req->srbs_to_be_setup[i].srb_id; - /* OPTIONAL */ - /* 11.1.2 duplicationIndication */ - asn1cCallocOne(srbs_toBeSetupMod_item->duplicationIndication, - F1AP_DuplicationIndication_true); // enum - } - } - - /* mandatory */ - /* c12. DRBs_ToBeSetupMod_List */ - if(f1ap_ue_context_modification_req->drbs_to_be_setup_length){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie12); - ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List; - ie12->criticality = F1AP_Criticality_reject; - ie12->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List; - - for (int i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_setup_length; i++) { - const f1ap_drb_to_be_setup_t *drb = &f1ap_ue_context_modification_req->drbs_to_be_setup[i]; - asn1cSequenceAdd(ie12->value.choice.DRBs_ToBeSetupMod_List.list, - F1AP_DRBs_ToBeSetupMod_ItemIEs_t, drbs_toBeSetupMod_item_ies); - drbs_toBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item; - drbs_toBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; - drbs_toBeSetupMod_item_ies->value.present = F1AP_DRBs_ToBeSetupMod_ItemIEs__value_PR_DRBs_ToBeSetupMod_Item; - /* 12.1 DRBs_ToBeSetupMod_Item */ - F1AP_DRBs_ToBeSetupMod_Item_t *drbs_toBeSetupMod_item= - &drbs_toBeSetupMod_item_ies->value.choice.DRBs_ToBeSetupMod_Item; - /* dRBID */ - drbs_toBeSetupMod_item->dRBID = drb->drb_id; - /* qoSInformation */ - - if(f1ap_ue_context_modification_req->QoS_information_type == EUTRAN_QoS){ - drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_eUTRANQoS; - drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS = (F1AP_EUTRANQoS_t *)calloc(1, sizeof(F1AP_EUTRANQoS_t)); - drbs_toBeSetupMod_item->qoSInformation.choice.eUTRANQoS->qCI = 253L; - /* uLUPTNLInformation_ToBeSetup_List */ - int maxnoofULTunnels = 1; // 2; - - for (int j=0; juLUPTNLInformation_ToBeSetup_List.list, - F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, - gTPTunnel); - /* transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); - /* gTP_TEID */ - OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "4567", - strlen("4567")); - } - - /* rLCMode */ - drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; // enum - - /* OPTIONAL */ - /* ULConfiguration */ - if (0) { - drbs_toBeSetupMod_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); - } - } //QoS information - - else{ - /* 12.1.2 DRB_Information */ - f1ap_drb_information_t *drb_info_in = &f1ap_ue_context_modification_req->drbs_to_be_setup[i].drb_info; - drbs_toBeSetupMod_item->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; - F1AP_QoSInformation_ExtIEs_t *ie = (F1AP_QoSInformation_ExtIEs_t *)calloc(1, sizeof(*ie)); - ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; - ie->criticality = F1AP_Criticality_reject; - ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; - F1AP_DRB_Information_t *DRB_Information = &ie->value.choice.DRB_Information; - drbs_toBeSetupMod_item->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)ie; - - /* 12.1.2.1 dRB_QoS */ - f1ap_write_drb_qos_param(&drb_info_in->drb_qos, &DRB_Information->dRB_QoS); - - /* 12.1.2.2 sNSSAI */ - f1ap_write_drb_nssai(&drb->nssai, &DRB_Information->sNSSAI); - - /* OPTIONAL */ - /* 12.1.2.3 notificationControl */ - if (0) { - asn1cCallocOne(DRB_Information->notificationControl, - F1AP_NotificationControl_active); // enum - } - - /* 12.1.2.4 flows_Mapped_To_DRB_List */ - f1ap_write_flows_mapped(drb_info_in->flows_mapped_to_drb, &DRB_Information->flows_Mapped_To_DRB_List, drb_info_in->flows_to_be_setup_length); - - } //QoS information - - /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ - for (int j = 0; j < f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl_length; j++) { - /* Use a dummy address and teid for the outgoing GTP-U tunnel (DU) which will be updated once we get the UE context modification response from the DU */ - asn1cSequenceAdd(drbs_toBeSetupMod_item->uLUPTNLInformation_ToBeSetup_List.list, - F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc( uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, - gTPTunnel); - /* 12.3.1.1.1 transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].tl_address, - &gTPTunnel->transportLayerAddress); - /* 12.3.1.1.2 gTP_TEID */ - INT32_TO_OCTET_STRING(f1ap_ue_context_modification_req->drbs_to_be_setup[i].up_ul_tnl[j].teid, - &gTPTunnel->gTP_TEID); - } - /* 12.1.4 rLCMode */ - /* TODO use rlc_mode from f1ap_drb_to_be_setup */ - switch (f1ap_ue_context_modification_req->drbs_to_be_setup[i].rlc_mode) { - case F1AP_RLC_MODE_AM: - drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_am; - break; - case F1AP_RLC_MODE_UM_BIDIR: - drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; - break; - default: - AssertFatal(false, "modes other than AM/UM-Bidir not supported\n"); - break; - } - - /* OPTIONAL */ - /* 12.1.5 ULConfiguration */ - if (0) { - asn1cCalloc(drbs_toBeSetupMod_item->uLConfiguration, tmp); - tmp->uLUEConfiguration = F1AP_ULUEConfiguration_no_data; - } - - /* OPTIONAL */ - /* 12.1.6 duplicationActivation */ - if (0) { - asn1cCalloc(drbs_toBeSetupMod_item->duplicationActivation, tmp); - *tmp = F1AP_DuplicationActivation_active; // enum - } - } - } - - /* optional */ - if(0){ - /* c13. DRBs_ToBeModified_List */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie13); - ie13->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeModified_List; - ie13->criticality = F1AP_Criticality_reject; - ie13->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeModified_List; - - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd( ie13->value.choice.DRBs_ToBeModified_List.list, - F1AP_DRBs_ToBeModified_ItemIEs_t, drbs_toBeModified_item_ies); - drbs_toBeModified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeModified_Item; - drbs_toBeModified_item_ies->criticality = F1AP_Criticality_reject; - drbs_toBeModified_item_ies->value.present = F1AP_DRBs_ToBeModified_ItemIEs__value_PR_DRBs_ToBeModified_Item; - /* 13.1 SRBs_ToBeModified_Item */ - F1AP_DRBs_ToBeModified_Item_t *drbs_toBeModified_item= - &drbs_toBeModified_item_ies->value.choice.DRBs_ToBeModified_Item; - /* dRBID */ - drbs_toBeModified_item->dRBID = 30L; - /* qoSInformation */ - asn1cCalloc(drbs_toBeModified_item->qoSInformation, tmp); - tmp->present = F1AP_QoSInformation_PR_eUTRANQoS; - tmp->choice.eUTRANQoS = (F1AP_EUTRANQoS_t *)calloc(1, sizeof(F1AP_EUTRANQoS_t)); - tmp->choice.eUTRANQoS->qCI = 254L; - /* ULTunnels_ToBeModified_List */ - int maxnoofULTunnels = 1; // 2; - - for (int j=0; juLUPTNLInformation_ToBeSetup_List.list, - F1AP_ULUPTNLInformation_ToBeSetup_Item_t, uLUPTNLInformation_ToBeSetup_Item); - uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(uLUPTNLInformation_ToBeSetup_Item->uLUPTNLInformation.choice.gTPTunnel, - gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &gTPTunnel->transportLayerAddress); - OCTET_STRING_fromBuf(&gTPTunnel->gTP_TEID, "1204", - strlen("1204")); - } - - /* OPTIONAL */ - /* ULConfiguration */ - if (0) { - drbs_toBeModified_item->uLConfiguration = (F1AP_ULConfiguration_t *)calloc(1, sizeof(F1AP_ULConfiguration_t)); - } - } - } - - /* optional */ - if(0){ - /* c14. SRBs_ToBeReleased_List */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie14); - ie14->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeReleased_List; - ie14->criticality = F1AP_Criticality_reject; - ie14->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeReleased_List; - - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie14->value.choice.SRBs_ToBeReleased_List.list, - F1AP_SRBs_ToBeReleased_ItemIEs_t, srbs_toBeReleased_item_ies); - srbs_toBeReleased_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeReleased_Item; - srbs_toBeReleased_item_ies->criticality = F1AP_Criticality_ignore; - srbs_toBeReleased_item_ies->value.present = F1AP_SRBs_ToBeReleased_ItemIEs__value_PR_SRBs_ToBeReleased_Item; - /* 9.1 SRBs_ToBeReleased_Item */ - F1AP_SRBs_ToBeReleased_Item_t *srbs_toBeReleased_item= - &srbs_toBeReleased_item_ies->value.choice.SRBs_ToBeReleased_Item; - /* - sRBID */ - srbs_toBeReleased_item->sRBID = 2L; - } - } - - /* optional */ - if (f1ap_ue_context_modification_req->drbs_to_be_released_length > 0) { - /* c15. DRBs_ToBeReleased_List */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie15); - ie15->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List; - ie15->criticality = F1AP_Criticality_reject; - ie15->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List; - - for (int i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_released_length; i++) { - // - asn1cSequenceAdd(ie15->value.choice.DRBs_ToBeReleased_List.list, - F1AP_DRBs_ToBeReleased_ItemIEs_t, drbs_toBeReleased_item_ies); - drbs_toBeReleased_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item; - drbs_toBeReleased_item_ies->criticality = F1AP_Criticality_reject; - drbs_toBeReleased_item_ies->value.present = F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item; - /* 14.1 SRBs_ToBeReleased_Item */ - F1AP_DRBs_ToBeReleased_Item_t *drbs_toBeReleased_item= - &drbs_toBeReleased_item_ies->value.choice.DRBs_ToBeReleased_Item; - /* dRBID */ - drbs_toBeReleased_item->dRBID = f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id; - } - } - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { - LOG_E(F1AP, "Failed to encode F1 UE CONTEXT_MODIFICATION REQUEST\n"); + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { + LOG_E(F1AP, "Failed to encode F1 UE Context Modification Request\n"); return -1; } + f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return 0; } int CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - MessageDef *msg_p; - F1AP_UEContextModificationResponse_t *container; - F1AP_UEContextModificationResponseIEs_t *ie; - DevAssert(pdu); - msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_MODIFICATION_RESP); + f1ap_ue_context_mod_resp_t resp = {0}; + if (!decode_ue_context_mod_resp(pdu, &resp)) { + LOG_E(F1AP, "cannot decode F1 UE Context Modification Response\n"); + free_ue_context_mod_resp(&resp); + return -1; + } + MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_UE_CONTEXT_MODIFICATION_RESP); msg_p->ittiMsgHeader.originInstance = assoc_id; - f1ap_ue_context_modif_resp_t *f1ap_ue_context_modification_resp = &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg_p); - container = &pdu->choice.successfulOutcome->value.choice.UEContextModificationResponse; - int i; - - /* GNB_CU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - f1ap_ue_context_modification_resp->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; - - LOG_D(F1AP, "f1ap_ue_context_modif_resp->gNB_CU_ue_id is: %d \n", f1ap_ue_context_modification_resp->gNB_CU_ue_id); - - /* GNB_DU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - f1ap_ue_context_modification_resp->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; - - LOG_D(F1AP, "f1ap_ue_context_modification_resp->gNB_DU_ue_id is: %d \n", f1ap_ue_context_modification_resp->gNB_DU_ue_id); - - // DUtoCURRCInformation - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, false); - if(ie!=NULL){ - f1ap_ue_context_modification_resp->du_to_cu_rrc_information = (du_to_cu_rrc_information_t *)calloc(1, sizeof(du_to_cu_rrc_information_t)); - f1ap_ue_context_modification_resp->du_to_cu_rrc_information->cellGroupConfig = (uint8_t *)calloc(1,ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - - memcpy(f1ap_ue_context_modification_resp->du_to_cu_rrc_information->cellGroupConfig, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.buf, ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size); - f1ap_ue_context_modification_resp->du_to_cu_rrc_information->cellGroupConfig_length = ie->value.choice.DUtoCURRCInformation.cellGroupConfig.size; - } - - // DRBs_SetupMod_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List, false); - if(ie!=NULL){ - f1ap_ue_context_modification_resp->drbs_to_be_setup_length = ie->value.choice.DRBs_SetupMod_List.list.count; - f1ap_ue_context_modification_resp->drbs_to_be_setup = calloc(f1ap_ue_context_modification_resp->drbs_to_be_setup_length, - sizeof(f1ap_drb_to_be_setup_t)); - AssertFatal(f1ap_ue_context_modification_resp->drbs_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_resp->drbs_setup\n"); - for (i = 0; i < f1ap_ue_context_modification_resp->drbs_to_be_setup_length; ++i) { - f1ap_drb_to_be_setup_t *drb_p = &f1ap_ue_context_modification_resp->drbs_to_be_setup[i]; - F1AP_DRBs_SetupMod_Item_t *drbs_setupmod_item_p; - drbs_setupmod_item_p = &((F1AP_DRBs_SetupMod_ItemIEs_t *)ie->value.choice.DRBs_SetupMod_List.list.array[i])->value.choice.DRBs_SetupMod_Item; - drb_p->drb_id = drbs_setupmod_item_p->dRBID; - // TODO in the following, assume only one UP UL TNL is present. - // this matches/assumes OAI CU/DU implementation, can be up to 2! - drb_p->up_dl_tnl_length = 1; - AssertFatal(drbs_setupmod_item_p->dLUPTNLInformation_ToBeSetup_List.list.count > 0, - "no DL UP TNL Information in DRBs to be Setup list\n"); - F1AP_DLUPTNLInformation_ToBeSetup_Item_t *dl_up_tnl_info_p = (F1AP_DLUPTNLInformation_ToBeSetup_Item_t *)drbs_setupmod_item_p->dLUPTNLInformation_ToBeSetup_List.list.array[0]; - F1AP_GTPTunnel_t *dl_up_tnl0 = dl_up_tnl_info_p->dLUPTNLInformation.choice.gTPTunnel; - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&dl_up_tnl0->transportLayerAddress, drb_p->up_dl_tnl[0].tl_address); - OCTET_STRING_TO_UINT32(&dl_up_tnl0->gTP_TEID, drb_p->up_dl_tnl[0].teid); - } - } - // SRBs_FailedToBeSetupMod_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_List, false); - if(ie!=NULL){ - f1ap_ue_context_modification_resp->srbs_failed_to_be_setup_length = ie->value.choice.SRBs_FailedToBeSetupMod_List.list.count; - f1ap_ue_context_modification_resp->srbs_failed_to_be_setup = calloc(f1ap_ue_context_modification_resp->srbs_failed_to_be_setup_length, - sizeof(f1ap_rb_failed_to_be_setup_t)); - AssertFatal(f1ap_ue_context_modification_resp->srbs_failed_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_resp->srbs_failed_to_be_setup\n"); - for (i = 0; i < f1ap_ue_context_modification_resp->srbs_failed_to_be_setup_length; ++i) { - f1ap_rb_failed_to_be_setup_t *srb_p = &f1ap_ue_context_modification_resp->srbs_failed_to_be_setup[i]; - srb_p->rb_id = ((F1AP_SRBs_FailedToBeSetupMod_Item_t *)ie->value.choice.SRBs_FailedToBeSetupMod_List.list.array[i])->sRBID; - } - - } - // DRBs_FailedToBeSetupMod_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_List, false); - if(ie!=NULL){ - f1ap_ue_context_modification_resp->drbs_failed_to_be_setup_length = ie->value.choice.DRBs_FailedToBeSetupMod_List.list.count; - f1ap_ue_context_modification_resp->drbs_failed_to_be_setup = calloc(f1ap_ue_context_modification_resp->drbs_failed_to_be_setup_length, - sizeof(f1ap_rb_failed_to_be_setup_t)); - AssertFatal(f1ap_ue_context_modification_resp->drbs_failed_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_resp->drbs_failed_to_be_setup\n"); - for (i = 0; i < f1ap_ue_context_modification_resp->drbs_failed_to_be_setup_length; ++i) { - f1ap_rb_failed_to_be_setup_t *drb_p = &f1ap_ue_context_modification_resp->drbs_failed_to_be_setup[i]; - drb_p->rb_id = ((F1AP_DRBs_FailedToBeSetupMod_Item_t *)ie->value.choice.DRBs_FailedToBeSetupMod_List.list.array[i])->dRBID; - } - } - - // SCell_FailedtoSetupMod_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_List, false); - if(ie!=NULL){ - LOG_E (F1AP, "Not supporting handling of SCell_FailedtoSetupMod_List \n"); - } - - // SRBs_Setup_List - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationResponseIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List, false); - if(ie!=NULL){ - f1ap_ue_context_modification_resp->srbs_to_be_setup_length = ie->value.choice.SRBs_SetupMod_List.list.count; - f1ap_ue_context_modification_resp->srbs_to_be_setup = calloc(f1ap_ue_context_modification_resp->srbs_to_be_setup_length, - sizeof(f1ap_srb_to_be_setup_t)); - AssertFatal(f1ap_ue_context_modification_resp->srbs_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_resp->drbs_setup\n"); - for (i = 0; i < f1ap_ue_context_modification_resp->srbs_to_be_setup_length; ++i) { - f1ap_srb_to_be_setup_t *srb_p = &f1ap_ue_context_modification_resp->srbs_to_be_setup[i]; - F1AP_SRBs_SetupMod_Item_t *srbs_setup_item_p; - srbs_setup_item_p = &((F1AP_SRBs_SetupMod_ItemIEs_t *)ie->value.choice.SRBs_SetupMod_List.list.array[i])->value.choice.SRBs_SetupMod_Item; - srb_p->srb_id = srbs_setup_item_p->sRBID; - srb_p->lcid = srbs_setup_item_p->lCID; - } - } - - itti_send_msg_to_task(TASK_RRC_GNB, instance, msg_p); - return 0; + F1AP_UE_CONTEXT_MODIFICATION_RESP(msg_p) = resp; + itti_send_msg_to_task(TASK_RRC_GNB, instance, msg_p); + return 0; } int CU_handle_UE_CONTEXT_MODIFICATION_FAILURE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.h b/openair2/F1AP/f1ap_cu_ue_context_management.h index 05e67930b3..0bc1815658 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.h +++ b/openair2/F1AP/f1ap_cu_ue_context_management.h @@ -36,8 +36,7 @@ /* * UE Context Setup */ -int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, - f1ap_ue_context_setup_t *f1ap_ue_context_setup_req); +int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, const f1ap_ue_context_setup_req_t *req); int CU_handle_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); @@ -51,15 +50,14 @@ int CU_handle_UE_CONTEXT_RELEASE_REQUEST(instance_t instance, sctp_assoc_t assoc /* * UE Context Release (gNB-CU initiated) */ -int CU_send_UE_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, - f1ap_ue_context_release_cmd_t *cmd); +int CU_send_UE_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, f1ap_ue_context_rel_cmd_t *cmd); int CU_handle_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); /* * UE Context Modification (gNB-CU initiated) */ -int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_modif_req_t *f1ap_ue_context_modification_req); +int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, const f1ap_ue_context_mod_req_t *req); int CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); int CU_handle_UE_CONTEXT_MODIFICATION_FAILURE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index c231561eec..94b4befb76 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -36,6 +36,7 @@ #include "f1ap_du_rrc_message_transfer.h" #include "lib/f1ap_rrc_message_transfer.h" #include "lib/f1ap_interface_management.h" +#include "lib/f1ap_ue_context.h" #include "f1ap_du_task.h" #include @@ -188,6 +189,7 @@ void *F1AP_DU_task(void *arg) { case F1AP_UE_CONTEXT_SETUP_RESP: DU_send_UE_CONTEXT_SETUP_RESPONSE(assoc_id, &F1AP_UE_CONTEXT_SETUP_RESP(msg)); + free_ue_context_setup_resp(&F1AP_UE_CONTEXT_SETUP_RESP(msg)); break; case F1AP_UE_CONTEXT_MODIFICATION_RESP: diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index cd9b2865c9..e09f038864 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -34,636 +34,40 @@ #include "f1ap_encoder.h" #include "f1ap_itti_messaging.h" #include "f1ap_du_ue_context_management.h" +#include "lib/f1ap_ue_context.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" -static void f1ap_read_drb_qos_param(const F1AP_QoSFlowLevelQoSParameters_t *asn1_qos, f1ap_qos_flow_level_qos_parameters_t *drb_qos) -{ - f1ap_qos_characteristics_t *drb_qos_char = &drb_qos->qos_characteristics; - const F1AP_QoS_Characteristics_t *dRB_QoS_Char = &asn1_qos->qoS_Characteristics; - - if (dRB_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) { - drb_qos_char->qos_type = NON_DYNAMIC; - drb_qos_char->non_dynamic.fiveqi = dRB_QoS_Char->choice.non_Dynamic_5QI->fiveQI; - drb_qos_char->non_dynamic.qos_priority_level = (dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL) - ? *dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel - : -1; - } else { - drb_qos_char->qos_type = DYNAMIC; - drb_qos_char->dynamic.fiveqi = - (dRB_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *dRB_QoS_Char->choice.dynamic_5QI->fiveQI : -1; - drb_qos_char->dynamic.qos_priority_level = dRB_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel; - drb_qos_char->dynamic.packet_delay_budget = dRB_QoS_Char->choice.dynamic_5QI->packetDelayBudget; - drb_qos_char->dynamic.packet_error_rate.per_scalar = dRB_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Scalar; - drb_qos_char->dynamic.packet_error_rate.per_exponent = dRB_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Exponent; - } - - /* nGRANallocationRetentionPriority */ - drb_qos->alloc_reten_priority.priority_level = asn1_qos->nGRANallocationRetentionPriority.priorityLevel; - drb_qos->alloc_reten_priority.preemption_vulnerability = asn1_qos->nGRANallocationRetentionPriority.pre_emptionVulnerability; - drb_qos->alloc_reten_priority.preemption_capability = asn1_qos->nGRANallocationRetentionPriority.pre_emptionVulnerability; -} - -static void f1ap_read_flows_mapped(const F1AP_Flows_Mapped_To_DRB_List_t *asn1_flows_mapped, f1ap_flows_mapped_to_drb_t *flows_mapped, int n) -{ - for (int k = 0; k < n; k++) { - f1ap_flows_mapped_to_drb_t *flows_mapped_to_drb = flows_mapped + k; - const F1AP_Flows_Mapped_To_DRB_Item_t *flows_Mapped_To_Drb = asn1_flows_mapped->list.array[0] + k; - - flows_mapped_to_drb->qfi = flows_Mapped_To_Drb->qoSFlowIdentifier; - - /* QoS-Flow-Level-QoS-Parameters */ - { - f1ap_qos_flow_level_qos_parameters_t *flow_qos = &flows_mapped_to_drb->qos_params; - const F1AP_QoSFlowLevelQoSParameters_t *Flow_QoS = &flows_Mapped_To_Drb->qoSFlowLevelQoSParameters; - - /* QoS Characteristics*/ - f1ap_qos_characteristics_t *flow_qos_char = &flow_qos->qos_characteristics; - const F1AP_QoS_Characteristics_t *Flow_QoS_Char = &Flow_QoS->qoS_Characteristics; - - if (Flow_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) { - flow_qos_char->qos_type = NON_DYNAMIC; - flow_qos_char->non_dynamic.fiveqi = Flow_QoS_Char->choice.non_Dynamic_5QI->fiveQI; - flow_qos_char->non_dynamic.qos_priority_level = (Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL) - ? *Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel - : -1; - } else { - flow_qos_char->qos_type = DYNAMIC; - flow_qos_char->dynamic.fiveqi = - (Flow_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *Flow_QoS_Char->choice.dynamic_5QI->fiveQI : -1; - flow_qos_char->dynamic.qos_priority_level = Flow_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel; - flow_qos_char->dynamic.packet_delay_budget = Flow_QoS_Char->choice.dynamic_5QI->packetDelayBudget; - flow_qos_char->dynamic.packet_error_rate.per_scalar = Flow_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Scalar; - flow_qos_char->dynamic.packet_error_rate.per_exponent = Flow_QoS_Char->choice.dynamic_5QI->packetErrorRate.pER_Exponent; - } - - /* nGRANallocationRetentionPriority */ - flow_qos->alloc_reten_priority.priority_level = Flow_QoS->nGRANallocationRetentionPriority.priorityLevel; - flow_qos->alloc_reten_priority.preemption_vulnerability = Flow_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability; - flow_qos->alloc_reten_priority.preemption_capability = Flow_QoS->nGRANallocationRetentionPriority.pre_emptionVulnerability; - } - } -} - -static void f1ap_read_drb_nssai(const F1AP_SNSSAI_t *asn1_nssai, nssai_t *nssai) -{ - OCTET_STRING_TO_INT8(&asn1_nssai->sST, nssai->sst); - nssai->sd = 0xffffff; - if (asn1_nssai->sD != NULL) { - BUFFER_TO_INT24(asn1_nssai->sD->buf, nssai->sd); - } -} - int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - F1AP_UEContextSetupRequest_t *container; - int i; - DevAssert(pdu); - f1ap_ue_context_setup_t ue_context_setup = {0}; - f1ap_ue_context_setup_t *f1ap_ue_context_setup_req = &ue_context_setup; - container = &pdu->choice.initiatingMessage->value.choice.UEContextSetupRequest; - /* GNB_CU_UE_F1AP_ID */ - F1AP_UEContextSetupRequestIEs_t *ieCU; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieCU, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - f1ap_ue_context_setup_req->gNB_CU_ue_id = ieCU->value.choice.GNB_CU_UE_F1AP_ID; - /* optional */ - /* GNB_DU_UE_F1AP_ID */ - F1AP_UEContextSetupRequestIEs_t *ieDU_UE; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieDU_UE, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, false); - // this should be optional. At present, the DU uses the RNTI, and hence, this - // value cannot exceed 0xffff (or something below, whatever is a valid - // C-RNTI). So we use a value > 0xffff to mark optionality - f1ap_ue_context_setup_req->gNB_DU_ue_id = -1; // 0xffffffff - if (ieDU_UE != NULL) - f1ap_ue_context_setup_req->gNB_DU_ue_id = ieDU_UE->value.choice.GNB_DU_UE_F1AP_ID; - - /* SpCell_ID */ - F1AP_UEContextSetupRequestIEs_t *ieNet; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieNet, container, - F1AP_ProtocolIE_ID_id_SpCell_ID, true); - PLMNID_TO_MCC_MNC(&ieNet->value.choice.NRCGI.pLMN_Identity, - f1ap_ue_context_setup_req->plmn.mcc, - f1ap_ue_context_setup_req->plmn.mnc, - f1ap_ue_context_setup_req->plmn.mnc_digit_length); - BIT_STRING_TO_NR_CELL_IDENTITY(&ieNet->value.choice.NRCGI.nRCellIdentity, f1ap_ue_context_setup_req->nr_cellid); - /* ServCellIndex */ - F1AP_UEContextSetupRequestIEs_t *ieCell; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieCell, container, - F1AP_ProtocolIE_ID_id_ServCellIndex, true); - f1ap_ue_context_setup_req->servCellIndex = ieCell->value.choice.ServCellIndex; - /* optional */ - /* CellULConfigured */ - F1AP_UEContextSetupRequestIEs_t *ieULCell; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieULCell, container, - F1AP_ProtocolIE_ID_id_SpCellULConfigured, false); // SpCellULConfigured - - if (ieULCell) { - /* correct here */ - f1ap_ue_context_setup_req->cellULConfigured = malloc(sizeof(uint32_t)); - - if (f1ap_ue_context_setup_req->cellULConfigured) - *f1ap_ue_context_setup_req->cellULConfigured = ieULCell->value.choice.CellULConfigured; - } else { - f1ap_ue_context_setup_req->cellULConfigured = NULL; + f1ap_ue_context_setup_req_t req = {0}; + if (!decode_ue_context_setup_req(pdu, &req)) { + LOG_E(F1AP, "cannot decode F1 UE Context Setup Request\n"); + free_ue_context_setup_req(&req); + return -1; } - F1AP_UEContextSetupRequestIEs_t *ieCuRrcInfo; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieCuRrcInfo, container, - F1AP_ProtocolIE_ID_id_CUtoDURRCInformation, false); - if(ieCuRrcInfo!=NULL){ - f1ap_ue_context_setup_req->cu_to_du_rrc_information = (cu_to_du_rrc_information_t *)calloc(1,sizeof(cu_to_du_rrc_information_t)); - cu_to_du_rrc_information_t *cu2du = f1ap_ue_context_setup_req->cu_to_du_rrc_information; - const F1AP_CUtoDURRCInformation_t *cu2duie = &ieCuRrcInfo->value.choice.CUtoDURRCInformation; - if (cu2duie->cG_ConfigInfo != NULL) { - cu2du->cG_ConfigInfo = malloc_or_fail(cu2duie->cG_ConfigInfo->size); - cu2du->cG_ConfigInfo_length = cu2duie->cG_ConfigInfo->size; - memcpy(cu2du->cG_ConfigInfo, cu2duie->cG_ConfigInfo->buf, cu2du->cG_ConfigInfo_length); - } - if(cu2duie->uE_CapabilityRAT_ContainerList!=NULL){ - cu2du->uE_CapabilityRAT_ContainerList = calloc(1, cu2duie->uE_CapabilityRAT_ContainerList->size); - memcpy(cu2du->uE_CapabilityRAT_ContainerList, - cu2duie->uE_CapabilityRAT_ContainerList->buf, - cu2duie->uE_CapabilityRAT_ContainerList->size); - cu2du->uE_CapabilityRAT_ContainerList_length = cu2duie->uE_CapabilityRAT_ContainerList->size; - LOG_D(F1AP, "Size f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length: %d \n", f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); - } - if (cu2duie->iE_Extensions != NULL) { - const F1AP_ProtocolExtensionContainer_10696P60_t *ext = (const F1AP_ProtocolExtensionContainer_10696P60_t *)cu2duie->iE_Extensions; - for (int i = 0; i < ext->list.count; ++i) { - const F1AP_CUtoDURRCInformation_ExtIEs_t *cu2du_info = ext->list.array[i]; - switch (cu2du_info->id) { - case F1AP_ProtocolIE_ID_id_HandoverPreparationInformation: - DevAssert(cu2du_info->extensionValue.present == F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_HandoverPreparationInformation); - const F1AP_HandoverPreparationInformation_t *hopi = &cu2du_info->extensionValue.choice.MeasurementTimingConfiguration; - cu2du->handoverPreparationInfo = calloc_or_fail(1, hopi->size); - memcpy(cu2du->handoverPreparationInfo, hopi->buf, hopi->size); - cu2du->handoverPreparationInfo_length = hopi->size; - break; - default: - LOG_W(F1AP, "unsupported CUtoDURRCInformation_ExtIE %ld encountered, ignoring\n", cu2du_info->id); - break; - } - } - } - } + ue_context_setup_request(&req); + free_ue_context_setup_req(&req); - /* DRB */ - F1AP_UEContextSetupRequestIEs_t *ieDrb; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieDrb, container, - F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List, false); - - if(ieDrb!=NULL) { - f1ap_ue_context_setup_req->drbs_to_be_setup_length = ieDrb->value.choice.DRBs_ToBeSetup_List.list.count; - f1ap_ue_context_setup_req->drbs_to_be_setup = calloc(f1ap_ue_context_setup_req->drbs_to_be_setup_length, - sizeof(f1ap_drb_to_be_setup_t)); - AssertFatal(f1ap_ue_context_setup_req->drbs_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_req->drbs_to_be_setup\n"); - - for (i = 0; i < f1ap_ue_context_setup_req->drbs_to_be_setup_length; ++i) { - f1ap_drb_to_be_setup_t *drb_p = &f1ap_ue_context_setup_req->drbs_to_be_setup[i]; - F1AP_DRBs_ToBeSetup_Item_t *drbs_tobesetup_item_p = - &((F1AP_DRBs_ToBeSetup_ItemIEs_t *)ieDrb->value.choice.DRBs_ToBeSetup_List.list.array[i])->value.choice.DRBs_ToBeSetup_Item; - drb_p->drb_id = drbs_tobesetup_item_p->dRBID; - /* TODO in the following, assume only one UP UL TNL is present. - * this matches/assumes OAI CU implementation, can be up to 2! */ - drb_p->up_ul_tnl_length = 1; - AssertFatal(drbs_tobesetup_item_p->uLUPTNLInformation_ToBeSetup_List.list.count > 0, - "no UL UP TNL Information in DRBs to be Setup list\n"); - F1AP_ULUPTNLInformation_ToBeSetup_Item_t *ul_up_tnl_info_p = (F1AP_ULUPTNLInformation_ToBeSetup_Item_t *)drbs_tobesetup_item_p->uLUPTNLInformation_ToBeSetup_List.list.array[0]; - F1AP_GTPTunnel_t *ul_up_tnl0 = ul_up_tnl_info_p->uLUPTNLInformation.choice.gTPTunnel; - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&ul_up_tnl0->transportLayerAddress, drb_p->up_ul_tnl[0].tl_address); - OCTET_STRING_TO_UINT32(&ul_up_tnl0->gTP_TEID, drb_p->up_ul_tnl[0].teid); - // 3GPP assumes GTP-U is on port 2152, but OAI is configurable - drb_p->up_ul_tnl[0].port = getCxt(instance)->net_config.CUport; - - switch (drbs_tobesetup_item_p->rLCMode) { - case F1AP_RLCMode_rlc_am: - drb_p->rlc_mode = F1AP_RLC_MODE_AM; - break; - case F1AP_RLCMode_rlc_um_bidirectional: - drb_p->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; - break; - default: - LOG_W(F1AP, "unsupported RLC Mode %ld received: setting UM bidir\n", drbs_tobesetup_item_p->rLCMode); - drb_p->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; - break; - } - - if (drbs_tobesetup_item_p->qoSInformation.present == F1AP_QoSInformation_PR_eUTRANQoS) { - AssertFatal(false, "Decode of eUTRANQoS is not implemented yet"); - } // EUTRAN QoS Information - else { - /* 12.1.2 DRB_Information */ - if (drbs_tobesetup_item_p->qoSInformation.present == F1AP_QoSInformation_PR_choice_extension) { - F1AP_QoSInformation_ExtIEs_t *ie = - (F1AP_QoSInformation_ExtIEs_t *)drbs_tobesetup_item_p->qoSInformation.choice.choice_extension; - if (ie->id == F1AP_ProtocolIE_ID_id_DRB_Information && ie->criticality == F1AP_Criticality_reject - && ie->value.present == F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information) { - - const F1AP_DRB_Information_t *dRB_Info = &ie->value.choice.DRB_Information; - f1ap_drb_information_t *drb_info = &drb_p->drb_info; - - /* QoS-Flow-Level-QoS-Parameters */ - /* QoS Characteristics*/ - f1ap_read_drb_qos_param(&dRB_Info->dRB_QoS, &drb_info->drb_qos); - - // 12.1.2.4 flows_Mapped_To_DRB_List - drb_info->flows_to_be_setup_length = dRB_Info->flows_Mapped_To_DRB_List.list.count; - drb_info->flows_mapped_to_drb = calloc(drb_info->flows_to_be_setup_length, sizeof(f1ap_flows_mapped_to_drb_t)); - AssertFatal(drb_info->flows_mapped_to_drb, "could not allocate memory for drb_p->drb_info.flows_mapped_to_drb\n"); - f1ap_read_flows_mapped(&dRB_Info->flows_Mapped_To_DRB_List, drb_info->flows_mapped_to_drb, drb_info->flows_to_be_setup_length); - - /* S-NSSAI */ - f1ap_read_drb_nssai(&dRB_Info->sNSSAI, &drb_p->nssai); - } - } - } - } - } - - /* SRB */ - F1AP_UEContextSetupRequestIEs_t *ieSrb; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieSrb, container, - F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List, false); - - if(ieSrb != NULL) { - f1ap_ue_context_setup_req->srbs_to_be_setup_length = ieSrb->value.choice.SRBs_ToBeSetup_List.list.count; - f1ap_ue_context_setup_req->srbs_to_be_setup = calloc(f1ap_ue_context_setup_req->srbs_to_be_setup_length, - sizeof(f1ap_srb_to_be_setup_t)); - AssertFatal(f1ap_ue_context_setup_req->srbs_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_req->srbs_to_be_setup\n"); - - for (i = 0; i < f1ap_ue_context_setup_req->srbs_to_be_setup_length; ++i) { - f1ap_srb_to_be_setup_t *srb_p = &f1ap_ue_context_setup_req->srbs_to_be_setup[i]; - F1AP_SRBs_ToBeSetup_Item_t *srbs_tobesetup_item_p; - srbs_tobesetup_item_p = &((F1AP_SRBs_ToBeSetup_ItemIEs_t *)ieSrb->value.choice.SRBs_ToBeSetup_List.list.array[i])->value.choice.SRBs_ToBeSetup_Item; - srb_p->srb_id = srbs_tobesetup_item_p->sRBID; - } - } - - /* RRCContainer */ - F1AP_UEContextSetupRequestIEs_t *ieRRC; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieRRC, container, - F1AP_ProtocolIE_ID_id_RRCContainer, false); - - if (ieRRC) { - /* correct here */ - if ( ieRRC->value.choice.RRCContainer.size ) { - f1ap_ue_context_setup_req->rrc_container = malloc(ieRRC->value.choice.RRCContainer.size); - memcpy(f1ap_ue_context_setup_req->rrc_container, - ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); - f1ap_ue_context_setup_req->rrc_container_length = ieRRC->value.choice.RRCContainer.size; - } else { - LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n"); - } - } - - ue_context_setup_request(f1ap_ue_context_setup_req); return 0; } -int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_setup_t *resp) +int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_setup_resp_t *resp) { - F1AP_F1AP_PDU_t pdu= {0}; - F1AP_UEContextSetupResponse_t *out; - uint8_t *buffer=NULL; - uint32_t len=0; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu.choice.successfulOutcome, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_UEContextSetup; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextSetupResponse; - out = &tmp->value.choice.UEContextSetupResponse; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_UEContextSetupResponseIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = resp->gNB_CU_ue_id; - /* mandatory */ - /* c2. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_UEContextSetupResponseIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = resp->gNB_DU_ue_id; + F1AP_F1AP_PDU_t *pdu = encode_ue_context_setup_resp(resp); - /* mandatory */ - /* c3. DUtoCURRCInformation */ - if(resp->du_to_cu_rrc_information){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation; - if(resp->du_to_cu_rrc_information->cellGroupConfig!=NULL){ - /* cellGroupConfig */ - OCTET_STRING_fromBuf(&ie3->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)resp->du_to_cu_rrc_information->cellGroupConfig, - resp->du_to_cu_rrc_information->cellGroupConfig_length); - } - - /* OPTIONAL */ - /* measGapConfig */ - if (resp->du_to_cu_rrc_information->measGapConfig!=NULL) { - OCTET_STRING_fromBuf(ie3->value.choice.DUtoCURRCInformation.measGapConfig, (const char *)resp->du_to_cu_rrc_information->measGapConfig, - resp->du_to_cu_rrc_information->measGapConfig_length); - } - - /* OPTIONAL */ - /* requestedP_MaxFR1 */ - if (resp->du_to_cu_rrc_information->requestedP_MaxFR1!=NULL) { - OCTET_STRING_fromBuf(ie3->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, (const char *)resp->du_to_cu_rrc_information->requestedP_MaxFR1, - resp->du_to_cu_rrc_information->requestedP_MaxFR1_length); - } - } - - /* optional */ - /* c4. C_RNTI */ - if (resp->crnti!=NULL) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_C_RNTI; - ie4->criticality = F1AP_Criticality_ignore; - ie4->value.present = F1AP_UEContextSetupResponseIEs__value_PR_C_RNTI; - ie4->value.choice.C_RNTI = *resp->crnti; - } - - /* optional */ - /* c5. ResourceCoordinationTransferContainer */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_ResourceCoordinationTransferContainer; - ie5->criticality = F1AP_Criticality_ignore; - ie5->value.present = F1AP_UEContextSetupResponseIEs__value_PR_ResourceCoordinationTransferContainer; - OCTET_STRING_fromBuf(&ie5->value.choice.ResourceCoordinationTransferContainer, "asdsa", - strlen("asdsa")); - } - - /* optional */ - /* c6. FullConfiguration */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie6); - ie6->id = F1AP_ProtocolIE_ID_id_FullConfiguration; - ie6->criticality = F1AP_Criticality_ignore; - ie6->value.present = F1AP_UEContextSetupResponseIEs__value_PR_FullConfiguration; - ie6->value.choice.FullConfiguration = F1AP_FullConfiguration_full; //enum - } - - /* mandatory */ - /* c7. DRBs_Setup_List */ - if(resp->drbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie7); - ie7->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_List; - ie7->criticality = F1AP_Criticality_ignore; - ie7->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DRBs_Setup_List; - for (int i=0; i< resp->drbs_to_be_setup_length; i++) { - f1ap_drb_to_be_setup_t *drb = &resp->drbs_to_be_setup[i]; - // - asn1cSequenceAdd(ie7->value.choice.DRBs_Setup_List.list, - F1AP_DRBs_Setup_ItemIEs_t, drbs_setup_item_ies); - drbs_setup_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_Item; - drbs_setup_item_ies->criticality = F1AP_Criticality_ignore; - drbs_setup_item_ies->value.present = F1AP_DRBs_Setup_ItemIEs__value_PR_DRBs_Setup_Item; - /* 7.1 DRBs_Setup_Item */ - /* ADD */ - F1AP_DRBs_Setup_Item_t *drbs_setup_item=&drbs_setup_item_ies->value.choice.DRBs_Setup_Item; - /* dRBID */ - drbs_setup_item->dRBID = drb->drb_id; - - /* OPTIONAL */ - /* lCID */ - //drbs_setup_item.lCID = (F1AP_LCID_t *)calloc(1, sizeof(F1AP_LCID_t)); - //drbs_setup_item.lCID = 1L; - - for (int j = 0; j < drb->up_dl_tnl_length; j++) { - const f1ap_up_tnl_t *tnl = &drb->up_dl_tnl[j]; - DevAssert(tnl->teid > 0); - - /* ADD */ - asn1cSequenceAdd(drbs_setup_item->dLUPTNLInformation_ToBeSetup_List.list, - F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); - dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - /* gTPTunnel */ - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel); - /* transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(tnl->tl_address, &gTPTunnel->transportLayerAddress); - /* gTP_TEID */ - INT32_TO_OCTET_STRING(tnl->teid, &gTPTunnel->gTP_TEID); - } // for j - } // for i - - } - - /* mandatory */ - /* c8. SRBs_FailedToBeSetup_List */ - if(0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie8); - ie8->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetup_List; - ie8->criticality = F1AP_Criticality_ignore; - ie8->value.present = F1AP_UEContextSetupResponseIEs__value_PR_SRBs_FailedToBeSetup_List; - - for (int i=0; i<1; i++) { - // - asn1cSequenceAdd(ie8->value.choice.SRBs_FailedToBeSetup_List.list, - F1AP_SRBs_FailedToBeSetup_ItemIEs_t, srbs_failedToBeSetup_item_ies); - srbs_failedToBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetup_Item; - srbs_failedToBeSetup_item_ies->criticality = F1AP_Criticality_ignore; - srbs_failedToBeSetup_item_ies->value.present = F1AP_SRBs_FailedToBeSetup_ItemIEs__value_PR_SRBs_FailedToBeSetup_Item; - /* 8.1 SRBs_Setup_Item */ - F1AP_SRBs_FailedToBeSetup_Item_t *srbs_failedToBeSetup_item= - &srbs_failedToBeSetup_item_ies->value.choice.SRBs_FailedToBeSetup_Item; - /* sRBID */ - srbs_failedToBeSetup_item->sRBID = 13L; - /* cause */ - asn1cCalloc(srbs_failedToBeSetup_item->cause, tmp); - // dummy value - tmp->present = F1AP_Cause_PR_radioNetwork; - - switch(tmp->present) { - case F1AP_Cause_PR_radioNetwork: - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unspecified; - break; - - case F1AP_Cause_PR_transport: - tmp->choice.transport = F1AP_CauseTransport_unspecified; - break; - - case F1AP_Cause_PR_protocol: - tmp->choice.protocol = F1AP_CauseProtocol_unspecified; - break; - - case F1AP_Cause_PR_misc: - tmp->choice.misc = F1AP_CauseMisc_unspecified; - break; - - case F1AP_Cause_PR_NOTHING: - default: - break; - } // switch - } // for i - } - - /* */ - /* c9. DRBs_FailedToBeSetup_List */ - if(0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie9); - ie9->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetup_List; - ie9->criticality = F1AP_Criticality_ignore; - ie9->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DRBs_FailedToBeSetup_List; - - for (int i=0; i<1; i++) { - asn1cSequenceAdd(ie9->value.choice.DRBs_FailedToBeSetup_List.list, - F1AP_DRBs_FailedToBeSetup_ItemIEs_t, drbs_failedToBeSetup_item_ies); - drbs_failedToBeSetup_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetup_Item; - drbs_failedToBeSetup_item_ies->criticality = F1AP_Criticality_ignore; - drbs_failedToBeSetup_item_ies->value.present = F1AP_DRBs_FailedToBeSetup_ItemIEs__value_PR_DRBs_FailedToBeSetup_Item; - /* 9.1 DRBs_Setup_Item */ - /* ADD */ - F1AP_DRBs_FailedToBeSetup_Item_t *drbs_failedToBeSetup_item= - &drbs_failedToBeSetup_item_ies->value.choice.DRBs_FailedToBeSetup_Item; - /* dRBID */ - drbs_failedToBeSetup_item->dRBID = 14; - /* cause */ - asn1cCalloc(drbs_failedToBeSetup_item->cause,tmp); - // dummy value - tmp->present = F1AP_Cause_PR_radioNetwork; - - switch(tmp->present) { - case F1AP_Cause_PR_radioNetwork: - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unspecified; - break; - - case F1AP_Cause_PR_transport: - tmp->choice.transport = F1AP_CauseTransport_unspecified; - break; - - case F1AP_Cause_PR_protocol: - tmp->choice.protocol = F1AP_CauseProtocol_unspecified; - break; - - case F1AP_Cause_PR_misc: - tmp->choice.misc = F1AP_CauseMisc_unspecified; - break; - - case F1AP_Cause_PR_NOTHING: - default: - break; - } // switch - } // for i - } - - // /* */ - /* c10. SCell_FailedtoSetup_List */ - if(0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie10); - ie10->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetup_List; - ie10->criticality = F1AP_Criticality_ignore; - ie10->value.present = F1AP_UEContextSetupResponseIEs__value_PR_SCell_FailedtoSetup_List; - - for (int i=0; i<1; i++) { - asn1cSequenceAdd(ie10->value.choice.SCell_FailedtoSetup_List.list, - F1AP_SCell_FailedtoSetup_ItemIEs_t, sCell_FailedtoSetup_item_ies); - sCell_FailedtoSetup_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetup_Item; - sCell_FailedtoSetup_item_ies->criticality = F1AP_Criticality_ignore; - sCell_FailedtoSetup_item_ies->value.present = F1AP_SCell_FailedtoSetup_ItemIEs__value_PR_SCell_FailedtoSetup_Item; - /* 10.1 DRBs_Setup_Item */ - F1AP_SCell_FailedtoSetup_Item_t *sCell_FailedtoSetup_item= - &sCell_FailedtoSetup_item_ies->value.choice.SCell_FailedtoSetup_Item; - /* sCell_ID */ - AssertFatal(false, "handle correct CellID\n"); - f1ap_served_cell_info_t cellID = {0}; - addnRCGI(sCell_FailedtoSetup_item->sCell_ID, &cellID); - /* cause */ - asn1cCalloc(sCell_FailedtoSetup_item->cause, tmp); - // dummy value - tmp->present = F1AP_Cause_PR_radioNetwork; - - switch(tmp->present) { - case F1AP_Cause_PR_radioNetwork: - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unspecified; - break; - - case F1AP_Cause_PR_transport: - tmp->choice.transport = F1AP_CauseTransport_unspecified; - break; - - case F1AP_Cause_PR_protocol: - tmp->choice.protocol = F1AP_CauseProtocol_unspecified; - break; - - case F1AP_Cause_PR_misc: - tmp->choice.misc = F1AP_CauseMisc_unspecified; - break; - - case F1AP_Cause_PR_NOTHING: - default: - break; - } // switch - } // for i - } - - /* mandatory */ - /* c11. SRBs_Setup_List */ - if(resp->srbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie11); - ie11->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_List; - ie11->criticality = F1AP_Criticality_ignore; - ie11->value.present = F1AP_UEContextSetupResponseIEs__value_PR_SRBs_Setup_List; - - for (int i=0; i< resp->srbs_to_be_setup_length; i++) {// - asn1cSequenceAdd(ie11->value.choice.SRBs_Setup_List.list, - F1AP_SRBs_Setup_ItemIEs_t, srbs_setup_item_ies); - srbs_setup_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_Item; - srbs_setup_item_ies->criticality = F1AP_Criticality_ignore; - srbs_setup_item_ies->value.present = F1AP_SRBs_Setup_ItemIEs__value_PR_SRBs_Setup_Item; - /* 11.1 SRBs_Setup_Item */ - /* ADD */ - F1AP_SRBs_Setup_Item_t *srbs_setup_item=&srbs_setup_item_ies->value.choice.SRBs_Setup_Item; - /* sRBID */ - srbs_setup_item->sRBID = resp->srbs_to_be_setup[i].srb_id; - srbs_setup_item->lCID = resp->srbs_to_be_setup[i].lcid; - } - } - - /* Optional */ - /* c12. InactivityMonitoringResponse */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie11); - ie11->id = F1AP_ProtocolIE_ID_id_InactivityMonitoringResponse; - ie11->criticality = F1AP_Criticality_ignore; - ie11->value.present = F1AP_UEContextSetupResponseIEs__value_PR_InactivityMonitoringResponse; - ie11->value.choice.InactivityMonitoringResponse = F1AP_InactivityMonitoringResponse_not_supported; - } - - /* Optional */ - /* c13. CriticalityDiagnostics */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie12); - ie12->id = F1AP_ProtocolIE_ID_id_CriticalityDiagnostics; - ie12->criticality = F1AP_Criticality_ignore; - ie12->value.present = F1AP_UEContextSetupResponseIEs__value_PR_CriticalityDiagnostics; - asn1cCallocOne(ie12->value.choice.CriticalityDiagnostics.procedureCode, - F1AP_ProcedureCode_id_UEContextSetup); - asn1cCallocOne(ie12->value.choice.CriticalityDiagnostics.triggeringMessage, - F1AP_TriggeringMessage_initiating_message); - asn1cCallocOne(ie12->value.choice.CriticalityDiagnostics.procedureCriticality, - F1AP_Criticality_reject); - asn1cCallocOne(ie12->value.choice.CriticalityDiagnostics.transactionID, - 0); - } - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + uint8_t *buffer = NULL; + uint32_t len = 0; + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 UE CONTEXT SETUP RESPONSE\n"); return -1; } f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return 0; } @@ -672,757 +76,79 @@ int DU_send_UE_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id) AssertFatal(1==0,"Not implemented yet\n"); } -int DU_send_UE_CONTEXT_RELEASE_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_release_req_t *req) +int DU_send_UE_CONTEXT_RELEASE_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_rel_req_t *req) { - F1AP_F1AP_PDU_t pdu = {0}; - F1AP_UEContextReleaseRequest_t *out; - uint8_t *buffer=NULL; - uint32_t len=0; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_UEContextReleaseRequest; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextReleaseRequest; - out = &tmp->value.choice.UEContextReleaseRequest; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = req->gNB_CU_ue_id; - /* mandatory */ - /* c2. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = req->gNB_DU_ue_id; - /* mandatory */ - /* c3. Cause */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_Cause; - ie3->criticality = F1AP_Criticality_ignore; - ie3->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_Cause; + F1AP_F1AP_PDU_t *pdu = encode_ue_context_rel_req(req); - switch (req->cause) { - case F1AP_CAUSE_RADIO_NETWORK: - ie3->value.choice.Cause.present = F1AP_Cause_PR_radioNetwork; - ie3->value.choice.Cause.choice.radioNetwork = req->cause_value; - break; - - case F1AP_CAUSE_TRANSPORT: - ie3->value.choice.Cause.present = F1AP_Cause_PR_transport; - ie3->value.choice.Cause.choice.transport = req->cause_value; - break; - - case F1AP_CAUSE_PROTOCOL: - ie3->value.choice.Cause.present = F1AP_Cause_PR_protocol; - ie3->value.choice.Cause.choice.protocol = req->cause_value; - break; - - case F1AP_CAUSE_MISC: - ie3->value.choice.Cause.present = F1AP_Cause_PR_misc; - ie3->value.choice.Cause.choice.misc = req->cause_value; - break; - - case F1AP_CAUSE_NOTHING: - default: - ie3->value.choice.Cause.present = F1AP_Cause_PR_NOTHING; - break; - } - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + uint8_t *buffer = NULL; + uint32_t len = 0; + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 context release request\n"); return -1; } f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return 0; } int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - F1AP_UEContextReleaseCommand_t *container; - F1AP_UEContextReleaseCommandIEs_t *ie; - - f1ap_ue_context_release_req_t ue_context_release = {0}; - f1ap_ue_context_release_req_t *f1ap_ue_context_release_cmd = &ue_context_release; - - DevAssert(pdu); - container = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseCommand; - // GNB_CU_UE_F1AP_ID - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - f1ap_ue_context_release_cmd->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; - // GNB_DU_UE_F1AP_ID - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - f1ap_ue_context_release_cmd->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; - - // We don't need the Cause - // Optional RRC Container: if present, send to UE - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_RRCContainer, false); - - if (ie != NULL) { - f1ap_ue_context_release_cmd->rrc_container = malloc(ie->value.choice.RRCContainer.size); - AssertFatal(f1ap_ue_context_release_cmd->rrc_container != NULL, "out of memory\n"); - memcpy(f1ap_ue_context_release_cmd->rrc_container, ie->value.choice.RRCContainer.buf, ie->value.choice.RRCContainer.size); - f1ap_ue_context_release_cmd->rrc_container_length = ie->value.choice.RRCContainer.size; - - // conditionally have SRB ID if there is RRC container - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, F1AP_ProtocolIE_ID_id_SRBID, true); - f1ap_ue_context_release_cmd->srb_id = ie->value.choice.SRBID; + f1ap_ue_context_rel_cmd_t cmd = {0}; + if (!decode_ue_context_rel_cmd(pdu, &cmd)) { + LOG_E(F1AP, "cannot decode F1 UE Context Release Command\n"); + free_ue_context_rel_cmd(&cmd); + return -1; } - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextReleaseCommandIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_Cause, true); - switch (ie->value.choice.Cause.present){ - case F1AP_Cause_PR_radioNetwork: - f1ap_ue_context_release_cmd->cause = F1AP_CAUSE_RADIO_NETWORK; - break; - case F1AP_Cause_PR_transport: - f1ap_ue_context_release_cmd->cause = F1AP_CAUSE_TRANSPORT; - break; - case F1AP_Cause_PR_protocol: - f1ap_ue_context_release_cmd->cause = F1AP_CAUSE_PROTOCOL; - break; - case F1AP_Cause_PR_misc: - f1ap_ue_context_release_cmd->cause = F1AP_CAUSE_MISC; - break; - default: - LOG_W(F1AP, "Unknown cause for UE context release command\n"); - break; - - } - - ue_context_release_command(f1ap_ue_context_release_cmd); + ue_context_release_command(&cmd); + free_ue_context_rel_cmd(&cmd); return 0; } -int DU_send_UE_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, f1ap_ue_context_release_complete_t *complete) +int DU_send_UE_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, f1ap_ue_context_rel_cplt_t *cplt) { - F1AP_F1AP_PDU_t pdu= {0}; - F1AP_UEContextReleaseComplete_t *out; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu.choice.successfulOutcome, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_UEContextRelease; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextReleaseComplete; - out = &tmp->value.choice.UEContextReleaseComplete; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCompleteIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = complete->gNB_CU_ue_id; - /* mandatory */ - /* c2. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list,F1AP_UEContextReleaseCompleteIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = complete->gNB_DU_ue_id; - /* optional -> currently not used */ - /* c3. CriticalityDiagnostics */ - //if (0) { - // ie = (F1AP_UEContextReleaseCompleteIEs_t *)calloc(1, sizeof(F1AP_UEContextReleaseCompleteIEs_t)); - // ie->id = F1AP_ProtocolIE_ID_id_CriticalityDiagnostics; - // ie->criticality = F1AP_Criticality_ignore; - // ie->value.present = F1AP_UEContextReleaseCompleteIEs__value_PR_CriticalityDiagnostics; - // // dummy value - // /* optional */ - // /* procedureCode */ - // if (0) { - // ie->value.choice.CriticalityDiagnostics.procedureCode = (F1AP_ProcedureCode_t *)calloc(1, sizeof(F1AP_ProcedureCode_t)); - // ie->value.choice.CriticalityDiagnostics.procedureCode = 0L; - // } - // /* optional */ - // /* triggeringMessage */ - // if (0) { - // ie->value.choice.CriticalityDiagnostics.triggeringMessage = (F1AP_TriggeringMessage_t *)calloc(1, sizeof(F1AP_TriggeringMessage_t)); - // ie->value.choice.CriticalityDiagnostics.triggeringMessage = (F1AP_TriggeringMessage_t *)F1AP_TriggeringMessage_successful_outcome; - // } - // /* optional */ - // /* procedureCriticality */ - // if (0) { - // ie->value.choice.CriticalityDiagnostics.procedureCriticality = (F1AP_Criticality_t *)calloc(1, sizeof(F1AP_Criticality_t)); - // ie->value.choice.CriticalityDiagnostics.procedureCriticality = F1AP_Criticality_reject; - // } - // /* optional */ - // /* transactionID */ - // if (0) { - // ie->value.choice.CriticalityDiagnostics.transactionID = (F1AP_TransactionID_t *)calloc(1, sizeof(F1AP_TransactionID_t)); - // ie->value.choice.CriticalityDiagnostics.transactionID = 0L; - // } - // /* optional */ - // /* F1AP_CriticalityDiagnostics_IE_List */ - // if (0) { - // for (i=0; - // i<0; - // i++) { - // F1AP_CriticalityDiagnostics_IE_Item_t *criticalityDiagnostics_ie_item = (F1AP_CriticalityDiagnostics_IE_Item_t *)calloc(1, sizeof(F1AP_CriticalityDiagnostics_IE_Item_t));; - // criticalityDiagnostics_ie_item->iECriticality = F1AP_Criticality_reject; - // criticalityDiagnostics_ie_item->iE_ID = 0L; - // criticalityDiagnostics_ie_item->typeOfError = F1AP_TypeOfError_not_understood; - // asn1cSeqAdd(&ie->value.choice.CriticalityDiagnostics.iEsCriticalityDiagnostics->list, - // criticalityDiagnostics_ie_item); - // } - // } - // asn1cSeqAdd(&out->protocolIEs.list, ie); - //} - /* encode */ + F1AP_F1AP_PDU_t *pdu = encode_ue_context_rel_cplt(cplt); + uint8_t *buffer; uint32_t len; - - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 context release complete\n"); return -1; } f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return 0; } int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - F1AP_UEContextModificationRequest_t *container; - int i; - f1ap_ue_context_modif_req_t ue_context_modification = {0}; - f1ap_ue_context_modif_req_t *f1ap_ue_context_modification_req = &ue_context_modification; - container = &pdu->choice.initiatingMessage->value.choice.UEContextModificationRequest; - - /* mandatory */ - /* GNB_CU_UE_F1AP_ID */ - F1AP_UEContextModificationRequestIEs_t *ieCU; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieCU, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - f1ap_ue_context_modification_req->gNB_CU_ue_id = ieCU->value.choice.GNB_CU_UE_F1AP_ID; - - /* mandatory */ - /* GNB_DU_UE_F1AP_ID */ - F1AP_UEContextModificationRequestIEs_t *ieDU_UE; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieDU_UE, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - f1ap_ue_context_modification_req->gNB_DU_ue_id = ieDU_UE->value.choice.GNB_DU_UE_F1AP_ID; - - /* SRB */ - F1AP_UEContextModificationRequestIEs_t *ieSrb; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieSrb, container, - F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List, false); - - F1AP_UEContextModificationRequestIEs_t *ieTxInd; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, - ieTxInd, - container, - F1AP_ProtocolIE_ID_id_TransmissionActionIndicator, - false); - - if (ieTxInd != NULL) { - f1ap_ue_context_modification_req->transm_action_ind = calloc_or_fail(1, sizeof(*f1ap_ue_context_modification_req->transm_action_ind)); - *f1ap_ue_context_modification_req->transm_action_ind = ieTxInd->value.choice.TransmissionActionIndicator; - // Stop is guaranteed to be 0, by restart might be different from 1 - static_assert((int)F1AP_TransmissionActionIndicator_restart == (int)TransmActionInd_RESTART, - "mismatch of ASN.1 and internal representation\n"); - } - - if(ieSrb != NULL) { - f1ap_ue_context_modification_req->srbs_to_be_setup_length = ieSrb->value.choice.SRBs_ToBeSetupMod_List.list.count; - f1ap_ue_context_modification_req->srbs_to_be_setup = calloc(f1ap_ue_context_modification_req->srbs_to_be_setup_length, - sizeof(f1ap_srb_to_be_setup_t)); - AssertFatal(f1ap_ue_context_modification_req->srbs_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_req->srbs_to_be_setup\n"); - - for (i = 0; i < f1ap_ue_context_modification_req->srbs_to_be_setup_length; ++i) { - f1ap_srb_to_be_setup_t *srb_p = &f1ap_ue_context_modification_req->srbs_to_be_setup[i]; - F1AP_SRBs_ToBeSetupMod_Item_t *srbs_tobesetupmod_item_p; - srbs_tobesetupmod_item_p = &((F1AP_SRBs_ToBeSetupMod_ItemIEs_t *)ieSrb->value.choice.SRBs_ToBeSetupMod_List.list.array[i])->value.choice.SRBs_ToBeSetupMod_Item; - srb_p->srb_id = srbs_tobesetupmod_item_p->sRBID; - } - } - - /* DRB */ - F1AP_UEContextModificationRequestIEs_t *ieDrb; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieDrb, container, - F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List, false); - - if(ieDrb!=NULL) { - f1ap_ue_context_modification_req->drbs_to_be_setup_length = ieDrb->value.choice.DRBs_ToBeSetupMod_List.list.count; - f1ap_ue_context_modification_req->drbs_to_be_setup = calloc(f1ap_ue_context_modification_req->drbs_to_be_setup_length, - sizeof(f1ap_drb_to_be_setup_t)); - AssertFatal(f1ap_ue_context_modification_req->drbs_to_be_setup, - "could not allocate memory for f1ap_ue_context_setup_req->drbs_to_be_setup\n"); - - for (i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_setup_length; ++i) { - f1ap_drb_to_be_setup_t *drb_p = &f1ap_ue_context_modification_req->drbs_to_be_setup[i]; - F1AP_DRBs_ToBeSetupMod_Item_t *drbs_tobesetupmod_item_p = - &((F1AP_DRBs_ToBeSetupMod_ItemIEs_t *)ieDrb->value.choice.DRBs_ToBeSetupMod_List.list.array[i])->value.choice.DRBs_ToBeSetupMod_Item; - drb_p->drb_id = drbs_tobesetupmod_item_p->dRBID; - /* TODO in the following, assume only one UP UL TNL is present. - * this matches/assumes OAI CU implementation, can be up to 2! */ - drb_p->up_ul_tnl_length = 1; - AssertFatal(drbs_tobesetupmod_item_p->uLUPTNLInformation_ToBeSetup_List.list.count > 0, - "no UL UP TNL Information in DRBs to be Setup list\n"); - F1AP_ULUPTNLInformation_ToBeSetup_Item_t *ul_up_tnl_info_p = (F1AP_ULUPTNLInformation_ToBeSetup_Item_t *)drbs_tobesetupmod_item_p->uLUPTNLInformation_ToBeSetup_List.list.array[0]; - F1AP_GTPTunnel_t *ul_up_tnl0 = ul_up_tnl_info_p->uLUPTNLInformation.choice.gTPTunnel; - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&ul_up_tnl0->transportLayerAddress, drb_p->up_ul_tnl[0].tl_address); - OCTET_STRING_TO_UINT32(&ul_up_tnl0->gTP_TEID, drb_p->up_ul_tnl[0].teid); - // 3GPP assumes GTP-U is on port 2152, but OAI is configurable - drb_p->up_ul_tnl[0].port = getCxt(instance)->net_config.CUport; - - switch (drbs_tobesetupmod_item_p->rLCMode) { - case F1AP_RLCMode_rlc_am: - drb_p->rlc_mode = F1AP_RLC_MODE_AM; - break; - case F1AP_RLCMode_rlc_um_bidirectional: - drb_p->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; - break; - default: - LOG_W(F1AP, "unsupported RLC Mode %ld received: setting UM bidir\n", drbs_tobesetupmod_item_p->rLCMode); - drb_p->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; - break; - } - - if (drbs_tobesetupmod_item_p->qoSInformation.present == F1AP_QoSInformation_PR_eUTRANQoS) { - AssertFatal(false, "Decode of eUTRANQoS is not implemented yet"); - } // EUTRAN QoS Information - else { - /* 12.1.2 DRB_Information */ - if (drbs_tobesetupmod_item_p->qoSInformation.present == F1AP_QoSInformation_PR_choice_extension) { - F1AP_QoSInformation_ExtIEs_t *ie = - (F1AP_QoSInformation_ExtIEs_t *)drbs_tobesetupmod_item_p->qoSInformation.choice.choice_extension; - if (ie->id == F1AP_ProtocolIE_ID_id_DRB_Information && ie->criticality == F1AP_Criticality_reject - && ie->value.present == F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information) { - - const F1AP_DRB_Information_t *dRB_Info = &ie->value.choice.DRB_Information; - f1ap_drb_information_t *drb_info = &drb_p->drb_info; - - /* QoS-Flow-Level-QoS-Parameters */ - /* QoS Characteristics*/ - f1ap_read_drb_qos_param(&dRB_Info->dRB_QoS, &drb_info->drb_qos); - - // 12.1.2.4 flows_Mapped_To_DRB_List - drb_info->flows_to_be_setup_length = dRB_Info->flows_Mapped_To_DRB_List.list.count; - drb_info->flows_mapped_to_drb = calloc(drb_info->flows_to_be_setup_length, sizeof(f1ap_flows_mapped_to_drb_t)); - AssertFatal(drb_info->flows_mapped_to_drb, "could not allocate memory for drb_p->drb_info.flows_mapped_to_drb\n"); - f1ap_read_flows_mapped(&dRB_Info->flows_Mapped_To_DRB_List, drb_info->flows_mapped_to_drb, drb_info->flows_to_be_setup_length); - - /* S-NSSAI */ - f1ap_read_drb_nssai(&dRB_Info->sNSSAI, &drb_p->nssai); - } - } - } - } - } - - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieDrb, container, - F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List, false); - if (ieDrb != NULL) { - f1ap_ue_context_modification_req->drbs_to_be_released_length = ieDrb->value.choice.DRBs_ToBeReleased_List.list.count; - f1ap_ue_context_modification_req->drbs_to_be_released = - calloc(f1ap_ue_context_modification_req->drbs_to_be_released_length, sizeof(f1ap_drb_to_be_released_t)); - AssertFatal(f1ap_ue_context_modification_req->drbs_to_be_released, - "could not allocate memory for f1ap_ue_context_released_req->drbs_to_be_released\n"); - for (i = 0; i < f1ap_ue_context_modification_req->drbs_to_be_released_length; ++i) { - F1AP_DRBs_ToBeReleased_ItemIEs_t *tbrel = (F1AP_DRBs_ToBeReleased_ItemIEs_t *)ieDrb->value.choice.DRBs_ToBeReleased_List.list.array[i]; - DevAssert(tbrel->id == F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item); - DevAssert(tbrel->value.present == F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item); - f1ap_ue_context_modification_req->drbs_to_be_released[i].rb_id = tbrel->value.choice.DRBs_ToBeReleased_Item.dRBID; - } - } - - /* RRC Reconfiguration Complete indicator */ - F1AP_UEContextModificationRequestIEs_t *ieReconf; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieReconf, container, - F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator, false); - - if(ieReconf) { - switch(ieReconf->value.choice.RRCReconfigurationCompleteIndicator){ - case F1AP_RRCReconfigurationCompleteIndicator_true: - f1ap_ue_context_modification_req->ReconfigComplOutcome = RRCreconf_success; - break; - - case F1AP_RRCReconfigurationCompleteIndicator_failure: - f1ap_ue_context_modification_req->ReconfigComplOutcome = RRCreconf_failure; - break; - } - } - - /* RRCContainer */ - F1AP_UEContextModificationRequestIEs_t *ieRRC; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieRRC, container, - F1AP_ProtocolIE_ID_id_RRCContainer, false); - - if (ieRRC) { - /* correct here */ - if ( ieRRC->value.choice.RRCContainer.size ) { - f1ap_ue_context_modification_req->rrc_container = malloc(ieRRC->value.choice.RRCContainer.size); - memcpy(f1ap_ue_context_modification_req->rrc_container, - ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); - f1ap_ue_context_modification_req->rrc_container_length = ieRRC->value.choice.RRCContainer.size; - } else { - LOG_E(F1AP, " RRCContainer in UEContextModificationRequestIEs size id 0\n"); - } - } else { - LOG_D(F1AP, "can't find RRCContainer in UEContextModificationRequestIEs by id %ld \n", F1AP_ProtocolIE_ID_id_RRCContainer); - } - - /* CU2DU Information */ - F1AP_UEContextModificationRequestIEs_t *ieCU2DU = NULL; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, - ieCU2DU, - container, - F1AP_ProtocolIE_ID_id_CUtoDURRCInformation, - false); - if (ieCU2DU != NULL) { - f1ap_ue_context_modification_req->cu_to_du_rrc_information = - calloc(1, sizeof(*f1ap_ue_context_modification_req->cu_to_du_rrc_information)); - AssertFatal(f1ap_ue_context_modification_req->cu_to_du_rrc_information != NULL, "out of memory\n"); - cu_to_du_rrc_information_t *cu2du = f1ap_ue_context_modification_req->cu_to_du_rrc_information; - const F1AP_CUtoDURRCInformation_t *cu2duie = &ieCU2DU->value.choice.CUtoDURRCInformation; - if (cu2duie->cG_ConfigInfo != NULL) - LOG_W(F1AP, "UE RNTI %04x: ignoring cg_ConfigInfo, not implemented\n", f1ap_ue_context_modification_req->gNB_DU_ue_id); - if (cu2duie->measConfig != NULL) - LOG_W(F1AP, "UE RNTI %04x: ignoring measConfig, not implemented\n", f1ap_ue_context_modification_req->gNB_DU_ue_id); - if (cu2duie->uE_CapabilityRAT_ContainerList != NULL) { - F1AP_UE_CapabilityRAT_ContainerList_t *uecap = cu2duie->uE_CapabilityRAT_ContainerList; - cu2du->uE_CapabilityRAT_ContainerList = calloc(uecap->size, sizeof(*cu2du->uE_CapabilityRAT_ContainerList)); - AssertFatal(cu2du->uE_CapabilityRAT_ContainerList != NULL, "out of memory\n"); - cu2du->uE_CapabilityRAT_ContainerList_length = uecap->size; - memcpy(cu2du->uE_CapabilityRAT_ContainerList, uecap->buf, uecap->size); - } - } - - ue_context_modification_request(f1ap_ue_context_modification_req); - return 0; -} - -int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_modif_resp_t *resp) -{ - F1AP_F1AP_PDU_t pdu= {0}; - F1AP_UEContextModificationResponse_t *out; - uint8_t *buffer=NULL; - uint32_t len=0; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu.choice.successfulOutcome,tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_UEContextModification; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextModificationResponse; - out = &tmp->value.choice.UEContextModificationResponse; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_UEContextModificationResponseIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = resp->gNB_CU_ue_id; - /* mandatory */ - /* c2. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_UEContextModificationResponseIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = resp->gNB_DU_ue_id; - - /* optional */ - /* c3. ResourceCoordinationTransferContainer */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_ResourceCoordinationTransferContainer; - ie3->criticality = F1AP_Criticality_ignore; - ie3->value.present = F1AP_UEContextModificationResponseIEs__value_PR_ResourceCoordinationTransferContainer; - OCTET_STRING_fromBuf(&ie3->value.choice.ResourceCoordinationTransferContainer, "asdsa1d32sa1d31asd31as", - strlen("asdsa1d32sa1d31asd31as")); - } - - /* optional */ - /* c4. DUtoCURRCInformation */ - if(resp->du_to_cu_rrc_information!=NULL){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DUtoCURRCInformation; - if(resp->du_to_cu_rrc_information->cellGroupConfig!=NULL){ - /* cellGroupConfig */ - OCTET_STRING_fromBuf(&ie4->value.choice.DUtoCURRCInformation.cellGroupConfig, (const char *)resp->du_to_cu_rrc_information->cellGroupConfig, - resp->du_to_cu_rrc_information->cellGroupConfig_length); - } - - /* OPTIONAL */ - /* measGapConfig */ - if (resp->du_to_cu_rrc_information->measGapConfig!=NULL) { - OCTET_STRING_fromBuf(ie4->value.choice.DUtoCURRCInformation.measGapConfig, (const char *)resp->du_to_cu_rrc_information->measGapConfig, - resp->du_to_cu_rrc_information->measGapConfig_length); - } - - /* OPTIONAL */ - /* requestedP_MaxFR1 */ - if (resp->du_to_cu_rrc_information->requestedP_MaxFR1!=NULL) { - OCTET_STRING_fromBuf(ie4->value.choice.DUtoCURRCInformation.requestedP_MaxFR1, (const char *)resp->du_to_cu_rrc_information->requestedP_MaxFR1, - resp->du_to_cu_rrc_information->requestedP_MaxFR1_length); - } - } - - - /* optional */ - /* c5. DRBs_Setup_List */ - if(resp->drbs_to_be_setup_length > 0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List; - ie5->criticality = F1AP_Criticality_ignore; - ie5->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_SetupMod_List; - for (int i=0; i< resp->drbs_to_be_setup_length; i++) { - asn1cSequenceAdd(ie5->value.choice.DRBs_SetupMod_List.list, F1AP_DRBs_SetupMod_ItemIEs_t, drbs_setupmod_item_ies); - drbs_setupmod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item; - drbs_setupmod_item_ies->criticality = F1AP_Criticality_ignore; - drbs_setupmod_item_ies->value.present = F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item; - /* 7.1 DRBs_Setup_Item */ - /* ADD */ - F1AP_DRBs_SetupMod_Item_t *drbs_setupmod_item=&drbs_setupmod_item_ies->value.choice.DRBs_SetupMod_Item; - /* dRBID */ - drbs_setupmod_item->dRBID = resp->drbs_to_be_setup[i].drb_id; - - for (int j=0; jdrbs_to_be_setup[i].up_dl_tnl_length; j++) { - const f1ap_up_tnl_t *tnl = &resp->drbs_to_be_setup[i].up_dl_tnl[j]; - DevAssert(tnl->teid > 0); - - /* ADD */ - asn1cSequenceAdd(drbs_setupmod_item->dLUPTNLInformation_ToBeSetup_List.list, - F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); - dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - /* gTPTunnel */ - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel,gTPTunnel); - /* transportLayerAddress */ - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(tnl->tl_address, &gTPTunnel->transportLayerAddress); - /* gTP_TEID */ - INT32_TO_OCTET_STRING(tnl->teid, &gTPTunnel->gTP_TEID); - } // for j - } // for i - } - - /* optional */ - /* c6. DRBs_Modified_List */ - if(resp->drbs_to_be_modified_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie6); - ie6->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_List; - ie6->criticality = F1AP_Criticality_ignore; - ie6->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_Modified_List; - - for (int i=0; idrbs_to_be_modified_length; i++) { - asn1cSequenceAdd(ie6->value.choice.DRBs_Modified_List.list, - F1AP_DRBs_Modified_ItemIEs_t, drbs_modified_item_ies); - drbs_modified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_Modified_Item; - drbs_modified_item_ies->criticality = F1AP_Criticality_ignore; - drbs_modified_item_ies->value.present = F1AP_DRBs_Modified_ItemIEs__value_PR_DRBs_Modified_Item; - /* DRBs_modified_Item */ - F1AP_DRBs_Modified_Item_t *drbs_modified_item= &drbs_modified_item_ies->value.choice.DRBs_Modified_Item; - /* dRBID */ - drbs_modified_item->dRBID = resp->drbs_to_be_modified[i].drb_id; - - /* ULTunnels_Modified_List */ - for (int j=0; jdrbs_to_be_modified[i].up_dl_tnl_length; j++) { - /* DLTunnels_Modified_Item */ - asn1cSequenceAdd(drbs_modified_item->dLUPTNLInformation_ToBeSetup_List.list, - F1AP_DLUPTNLInformation_ToBeSetup_Item_t, dLUPTNLInformation_ToBeSetup_Item); - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item, tmp); - tmp->dLUPTNLInformation.present = F1AP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(dLUPTNLInformation_ToBeSetup_Item->dLUPTNLInformation.choice.gTPTunnel, gTPTunnel); - /* transportLayerAddress */ - struct sockaddr_in addr= {0}; - inet_pton(AF_INET, getCxt(0)->net_config.DU_f1u_ip_address, &addr.sin_addr.s_addr); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(addr.sin_addr.s_addr, &gTPTunnel->transportLayerAddress); - /* gTP_TEID */ - INT32_TO_OCTET_STRING(resp->drbs_to_be_modified[i].up_dl_tnl[j].teid, &gTPTunnel->gTP_TEID); - } - } - } - - /* optional */ - /* c7. SRBs_FailedToBeSetupMod_List */ - if(resp->srbs_failed_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie7); - ie7->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_List; - ie7->criticality = F1AP_Criticality_reject; - ie7->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_FailedToBeSetupMod_List; - - for (int i=0; isrbs_to_be_setup_length; i++) { - asn1cSequenceAdd(ie7->value.choice.SRBs_FailedToBeSetupMod_List.list, - F1AP_SRBs_FailedToBeSetupMod_ItemIEs_t, srbs_failedToBeSetupMod_item_ies); - srbs_failedToBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_FailedToBeSetupMod_Item; - srbs_failedToBeSetupMod_item_ies->criticality = F1AP_Criticality_ignore; - srbs_failedToBeSetupMod_item_ies->value.present = F1AP_SRBs_FailedToBeSetupMod_ItemIEs__value_PR_SRBs_FailedToBeSetupMod_Item; - /* 9.1 SRBs_FailedToBeSetupMod_Item */ - F1AP_SRBs_FailedToBeSetupMod_Item_t *srbs_failedToBeSetupMod_item= - &srbs_failedToBeSetupMod_item_ies->value.choice.SRBs_FailedToBeSetupMod_Item; - /* - sRBID */ - srbs_failedToBeSetupMod_item->sRBID = resp->srbs_failed_to_be_setup[i].rb_id; - asn1cCalloc(srbs_failedToBeSetupMod_item->cause, tmp); - tmp->present = F1AP_Cause_PR_radioNetwork; - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; - } - } - - /* optional */ - /* c8. DRBs_FailedToBeSetupMod_List */ - if(resp->drbs_failed_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie8); - ie8->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_List; - ie8->criticality = F1AP_Criticality_reject; - ie8->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_FailedToBeSetupMod_List; - - for (int i=0; idrbs_failed_to_be_setup_length; i++) { - asn1cSequenceAdd(ie8->value.choice.DRBs_FailedToBeSetupMod_List.list, - F1AP_DRBs_FailedToBeSetupMod_ItemIEs_t, drbs_failedToBeSetupMod_item_ies); - drbs_failedToBeSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeSetupMod_Item; - drbs_failedToBeSetupMod_item_ies->criticality = F1AP_Criticality_reject; - drbs_failedToBeSetupMod_item_ies->value.present = F1AP_DRBs_FailedToBeSetupMod_ItemIEs__value_PR_DRBs_FailedToBeSetupMod_Item; - /* DRBs_FailedToBeSetupMod_Item */ - F1AP_DRBs_FailedToBeSetupMod_Item_t *drbs_failedToBeSetupMod_item= - &drbs_failedToBeSetupMod_item_ies->value.choice.DRBs_FailedToBeSetupMod_Item; - /* dRBID */ - drbs_failedToBeSetupMod_item->dRBID = resp->drbs_failed_to_be_setup[i].rb_id; - drbs_failedToBeSetupMod_item->cause = (F1AP_Cause_t *)calloc(1, sizeof(F1AP_Cause_t)); - drbs_failedToBeSetupMod_item->cause->present = F1AP_Cause_PR_radioNetwork; - drbs_failedToBeSetupMod_item->cause->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; - } - } - - /* optional */ - /* c9. SCell_FailedtoSetupMod_List */ - if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie9); - ie9->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_List; - ie9->criticality = F1AP_Criticality_ignore; - ie9->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SCell_FailedtoSetupMod_List; - - for (int i=0; i<1; i++) { - asn1cSequenceAdd(ie9->value.choice.SCell_FailedtoSetupMod_List.list, - F1AP_SCell_FailedtoSetupMod_ItemIEs_t, scell_failedtoSetupMod_item_ies); - scell_failedtoSetupMod_item_ies->id = F1AP_ProtocolIE_ID_id_SCell_FailedtoSetupMod_Item; - scell_failedtoSetupMod_item_ies->criticality = F1AP_Criticality_ignore; - scell_failedtoSetupMod_item_ies->value.present = F1AP_SCell_FailedtoSetupMod_ItemIEs__value_PR_SCell_FailedtoSetupMod_Item; - /* 8.1 SCell_ToBeSetup_Item */ - F1AP_SCell_FailedtoSetupMod_Item_t *scell_failedtoSetupMod_item=&scell_failedtoSetupMod_item_ies->value.choice.SCell_FailedtoSetupMod_Item; - /* - sCell_ID */ - addnRCGI(scell_failedtoSetupMod_item->sCell_ID, &getCxt(0)->setupReq.cell[i].info); - asn1cCalloc(scell_failedtoSetupMod_item->cause, tmp); - tmp->present = F1AP_Cause_PR_radioNetwork; - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; - } - } - - /* optional */ - /* c10. DRBs_FailedToBeModified_List */ - if(0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie10); - ie10->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeModified_List; - ie10->criticality = F1AP_Criticality_reject; - ie10->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_FailedToBeModified_List; - - for (int i=0; i<1; i++) { - asn1cSequenceAdd(ie10->value.choice.DRBs_FailedToBeModified_List.list, - F1AP_DRBs_FailedToBeModified_ItemIEs_t, drbs_failedToBeModified_item_ies); - drbs_failedToBeModified_item_ies->id = F1AP_ProtocolIE_ID_id_DRBs_FailedToBeModified_Item; - drbs_failedToBeModified_item_ies->criticality = F1AP_Criticality_reject; - drbs_failedToBeModified_item_ies->value.present = F1AP_DRBs_FailedToBeModified_ItemIEs__value_PR_DRBs_FailedToBeModified_Item; - /* 13.1 DRBs_FailedToBeModified_Item */ - F1AP_DRBs_FailedToBeModified_Item_t *drbs_failedToBeModified_item= - &drbs_failedToBeModified_item_ies->value.choice.DRBs_FailedToBeModified_Item ; - /* dRBID */ - drbs_failedToBeModified_item->dRBID = 30L; - asn1cCalloc(drbs_failedToBeModified_item->cause, tmp); - tmp->present = F1AP_Cause_PR_radioNetwork; - tmp->choice.radioNetwork = F1AP_CauseRadioNetwork_unknown_or_already_allocated_gnb_du_ue_f1ap_id; - } - } - - // /* */ - /* c11. CriticalityDiagnostics */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie11); - ie11->id = F1AP_ProtocolIE_ID_id_CriticalityDiagnostics; - ie11->criticality = F1AP_Criticality_ignore; - ie11->value.present = F1AP_UEContextModificationResponseIEs__value_PR_CriticalityDiagnostics; - - // dummy value - /* optional */ - /* procedureCode */ - if (0) { - ie11->value.choice.CriticalityDiagnostics.procedureCode = (F1AP_ProcedureCode_t *)calloc(1, sizeof(F1AP_ProcedureCode_t)); - *ie11->value.choice.CriticalityDiagnostics.procedureCode = 0L; - } - - /* optional */ - /* triggeringMessage */ - if (0) { - ie11->value.choice.CriticalityDiagnostics.triggeringMessage = (F1AP_TriggeringMessage_t *)calloc(1, sizeof(F1AP_TriggeringMessage_t)); - *ie11->value.choice.CriticalityDiagnostics.triggeringMessage = F1AP_TriggeringMessage_successful_outcome; - } - - /* optional */ - /* procedureCriticality */ - if (0) { - ie11->value.choice.CriticalityDiagnostics.procedureCriticality = (F1AP_Criticality_t *)calloc(1, sizeof(F1AP_Criticality_t)); - *ie11->value.choice.CriticalityDiagnostics.procedureCriticality = F1AP_Criticality_reject; - } - - /* optional */ - /* transactionID */ - if (0) { - ie11->value.choice.CriticalityDiagnostics.transactionID = (F1AP_TransactionID_t *)calloc(1, sizeof(F1AP_TransactionID_t)); - *ie11->value.choice.CriticalityDiagnostics.transactionID = 0L; - } - - /* optional */ - /* F1AP_CriticalityDiagnostics_IE_List */ - if (0) { - for (int i=0; i<0; i++) { - asn1cSequenceAdd(ie11->value.choice.CriticalityDiagnostics.iEsCriticalityDiagnostics->list, F1AP_CriticalityDiagnostics_IE_Item_t, criticalityDiagnostics_ie_item); - criticalityDiagnostics_ie_item->iECriticality = F1AP_Criticality_reject; - criticalityDiagnostics_ie_item->iE_ID = 0L; - criticalityDiagnostics_ie_item->typeOfError = F1AP_TypeOfError_not_understood; - } - } - } - /* optional */ - /* c12. SRBs_Setup_List */ - if(resp->srbs_to_be_setup_length > 0){ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie12); - ie12->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List; - ie12->criticality = F1AP_Criticality_ignore; - ie12->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_SetupMod_List; - - for (int i=0; i< resp->srbs_to_be_setup_length; i++) {// - asn1cSequenceAdd(ie12->value.choice.SRBs_SetupMod_List.list, - F1AP_SRBs_SetupMod_ItemIEs_t, srbs_setupmod_item_ies); - srbs_setupmod_item_ies->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_Item; - srbs_setupmod_item_ies->criticality = F1AP_Criticality_ignore; - srbs_setupmod_item_ies->value.present = F1AP_SRBs_SetupMod_ItemIEs__value_PR_SRBs_SetupMod_Item; - /* 11.1 SRBs_Setup_Item */ - /* ADD */ - F1AP_SRBs_SetupMod_Item_t *srbs_setupmod_item=&srbs_setupmod_item_ies->value.choice.SRBs_SetupMod_Item; - /* sRBID */ - srbs_setupmod_item->sRBID = resp->srbs_to_be_setup[i].srb_id; - srbs_setupmod_item->lCID = resp->srbs_to_be_setup[i].srb_id; - } - } - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { - LOG_E(F1AP, "Failed to encode F1 UE CONTEXT MODIFICATION RESPONSE\n"); + f1ap_ue_context_mod_req_t req = {0}; + if (!decode_ue_context_mod_req(pdu, &req)) { + LOG_E(F1AP, "cannot decode F1 UE Context Modification Request\n"); + free_ue_context_mod_req(&req); return -1; } + ue_context_modification_request(&req); + free_ue_context_mod_req(&req); + + return 0; +} + +int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_mod_resp_t *resp) +{ + F1AP_F1AP_PDU_t *pdu = encode_ue_context_mod_resp(resp); + + uint8_t *buffer = NULL; + uint32_t len = 0; + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { + LOG_E(F1AP, "Failed to encode F1 UE CONTEXT SETUP RESPONSE\n"); + return -1; + } f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return 0; } diff --git a/openair2/F1AP/f1ap_du_ue_context_management.h b/openair2/F1AP/f1ap_du_ue_context_management.h index 43663ba538..b6c12de18b 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.h +++ b/openair2/F1AP/f1ap_du_ue_context_management.h @@ -36,7 +36,7 @@ /* * UE Context Setup */ -int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_setup_t *req); +int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_setup_resp_t *resp); int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); int DU_send_UE_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id); @@ -45,9 +45,7 @@ int DU_send_UE_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id); /* * UE Context Release Request (gNB-DU initiated) */ -int DU_send_UE_CONTEXT_RELEASE_REQUEST(sctp_assoc_t assoc_id, - f1ap_ue_context_release_req_t *req); - +int DU_send_UE_CONTEXT_RELEASE_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_rel_req_t *req); /* * UE Context Release Command (gNB-CU initiated) @@ -57,13 +55,13 @@ int DU_handle_UE_CONTEXT_RELEASE_COMMAND(instance_t instance, sctp_assoc_t assoc /* * UE Context Release Complete (gNB-DU initiated) */ -int DU_send_UE_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, f1ap_ue_context_release_complete_t *complete); +int DU_send_UE_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, f1ap_ue_context_rel_cplt_t *cplt); /* * UE Context Modification (gNB-CU initiated) */ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); -int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_modif_resp_t *resp); +int DU_send_UE_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_mod_resp_t *resp); int DU_send_UE_CONTEXT_MODIFICATION_FAILURE(sctp_assoc_t assoc_id); diff --git a/openair2/F1AP/lib/CMakeLists.txt b/openair2/F1AP/lib/CMakeLists.txt index 0c6137dc30..978f69fb29 100644 --- a/openair2/F1AP/lib/CMakeLists.txt +++ b/openair2/F1AP/lib/CMakeLists.txt @@ -2,8 +2,9 @@ add_library(f1ap_lib OBJECT f1ap_lib_common.c f1ap_rrc_message_transfer.c f1ap_interface_management.c + f1ap_ue_context.c ) -target_link_libraries(f1ap_lib PRIVATE asn1_f1ap) +target_link_libraries(f1ap_lib PRIVATE asn1_f1ap ds) target_include_directories(f1ap_lib PUBLIC ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index 0ac1f8d63a..acd6859ad7 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -30,7 +30,7 @@ #include "f1ap_lib_common.h" #include "f1ap_lib_includes.h" #include "f1ap_messages_types.h" -#include "f1ap_lib_extern.h" +#include "lib/f1ap_interface_management.h" F1AP_UE_associatedLogicalF1_ConnectionItem_t encode_f1ap_ue_to_reset(const f1ap_ue_to_reset_t *to_reset) { @@ -156,9 +156,9 @@ bool decode_f1ap_reset(const F1AP_F1AP_PDU_t *pdu, f1ap_reset_t *out) /* Check presence of mandatory IEs */ F1AP_Reset_t *in = &pdu->choice.initiatingMessage->value.choice.Reset; F1AP_ResetIEs_t *ie; - F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); - F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, in, F1AP_ProtocolIE_ID_id_Cause, true); - F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, in, F1AP_ProtocolIE_ID_id_ResetType, true); + F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_Cause, true); + F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_ResetType, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { @@ -303,7 +303,7 @@ bool decode_f1ap_reset_ack(const struct F1AP_F1AP_PDU *pdu, f1ap_reset_ack_t *ou /* Check presence of mandatory IEs */ F1AP_ResetAcknowledge_t *in = &pdu->choice.successfulOutcome->value.choice.ResetAcknowledge; F1AP_ResetAcknowledgeIEs_t *ie; - F1AP_LIB_FIND_IE(F1AP_ResetAcknowledgeIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_ResetAcknowledgeIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { @@ -394,11 +394,7 @@ static int read_slice_info(const F1AP_ServedPLMNs_Item_t *plmn, nssai_t *nssai, AssertFatal(ssl->list.count <= max_nssai, "cannot handle more than 16 slices\n"); for (int s = 0; s < ssl->list.count; ++s) { const F1AP_SliceSupportItem_t *sl = ssl->list.array[s]; - nssai_t *n = &nssai[s]; - OCTET_STRING_TO_INT8(&sl->sNSSAI.sST, n->sst); - n->sd = 0xffffff; - if (sl->sNSSAI.sD != NULL) - OCTET_STRING_TO_INT24(sl->sNSSAI.sD, n->sd); + nssai[s] = decode_nssai(&sl->sNSSAI); } return ssl->list.count; @@ -418,12 +414,7 @@ static F1AP_ProtocolExtensionContainer_10696P34_t *write_slice_info(int num_ssi, for (int s = 0; s < num_ssi; s++) { asn1cSequenceAdd(slice_support_list->list, F1AP_SliceSupportItem_t, slice); - const nssai_t *n = &nssai[s]; - INT8_TO_OCTET_STRING(n->sst, &slice->sNSSAI.sST); - if (n->sd != 0xffffff) { - asn1cCalloc(slice->sNSSAI.sD, tmp); - INT24_TO_OCTET_STRING(n->sd, tmp); - } + slice->sNSSAI = encode_nssai(&nssai[s]); } return p; @@ -822,9 +813,9 @@ bool decode_f1ap_setup_request(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_req_t *out /* Check presence of mandatory IEs */ F1AP_F1SetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.F1SetupRequest; F1AP_F1SetupRequestIEs_t *ie; - F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); - F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, in, F1AP_ProtocolIE_ID_id_gNB_DU_ID, true); - F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, in, F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_ID, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { AssertError(in->protocolIEs.list.array[i] != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); @@ -1095,8 +1086,8 @@ bool decode_f1ap_setup_response(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_resp_t *o /* Check presence of mandatory IEs */ F1AP_F1SetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.F1SetupResponse; F1AP_F1SetupResponseIEs_t *ie; - F1AP_LIB_FIND_IE(F1AP_F1SetupResponseIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); - F1AP_LIB_FIND_IE(F1AP_F1SetupResponseIEs_t, ie, in, F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -1306,8 +1297,8 @@ bool decode_f1ap_setup_failure(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_failure_t F1AP_F1SetupFailureIEs_t *ie; F1AP_F1SetupFailure_t *in = &pdu->choice.unsuccessfulOutcome->value.choice.F1SetupFailure; /* Check presence of mandatory IEs */ - F1AP_LIB_FIND_IE(F1AP_F1SetupFailureIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); - F1AP_LIB_FIND_IE(F1AP_F1SetupFailureIEs_t, ie, in, F1AP_ProtocolIE_ID_id_Cause, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupFailureIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupFailureIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_Cause, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -1503,7 +1494,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du F1AP_GNBDUConfigurationUpdate_t *in = &pdu->choice.initiatingMessage->value.choice.GNBDUConfigurationUpdate; F1AP_GNBDUConfigurationUpdateIEs_t *ie; /* Check mandatory IEs */ - F1AP_LIB_FIND_IE(F1AP_GNBDUConfigurationUpdateIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_GNBDUConfigurationUpdateIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { AssertError(in->protocolIEs.list.array[i] != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); @@ -1760,7 +1751,7 @@ bool decode_f1ap_cu_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_cu /* Check presence of mandatory IEs */ F1AP_GNBCUConfigurationUpdate_t *in = &pdu->choice.initiatingMessage->value.choice.GNBCUConfigurationUpdate; F1AP_GNBCUConfigurationUpdateIEs_t *ie; - F1AP_LIB_FIND_IE(F1AP_GNBCUConfigurationUpdateIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_GNBCUConfigurationUpdateIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -1912,7 +1903,7 @@ bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu, F1AP_GNBCUConfigurationUpdateAcknowledge_t *in = &pdu->choice.successfulOutcome->value.choice.GNBCUConfigurationUpdateAcknowledge; F1AP_GNBCUConfigurationUpdateAcknowledgeIEs_t *ie; /* Check mandatory IEs */ - F1AP_LIB_FIND_IE(F1AP_GNBCUConfigurationUpdateAcknowledgeIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_GNBCUConfigurationUpdateAcknowledgeIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; @@ -2088,7 +2079,7 @@ bool decode_f1ap_du_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu, F1AP_GNBDUConfigurationUpdateAcknowledge_t *in = &pdu->choice.successfulOutcome->value.choice.GNBDUConfigurationUpdateAcknowledge; F1AP_GNBDUConfigurationUpdateAcknowledgeIEs_t *ie; /* Check mandatory IEs */ - F1AP_LIB_FIND_IE(F1AP_GNBDUConfigurationUpdateAcknowledgeIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_GNBDUConfigurationUpdateAcknowledgeIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_TransactionID, true); /* Loop over all IEs */ for (int i = 0; i < in->protocolIEs.list.count; i++) { ie = in->protocolIEs.list.array[i]; diff --git a/openair2/F1AP/lib/f1ap_lib_common.c b/openair2/F1AP/lib/f1ap_lib_common.c index e32f7e6779..0e1d07a71d 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.c +++ b/openair2/F1AP/lib/f1ap_lib_common.c @@ -25,7 +25,7 @@ #include "OCTET_STRING.h" #include "common/utils/utils.h" #include "common/utils/assertions.h" -#include "common/utils/utils.h" +#include "common/utils/oai_asn1.h" bool eq_f1ap_plmn(const plmn_id_t *a, const plmn_id_t *b) { @@ -115,6 +115,28 @@ uint8_t *cp_octet_string(const OCTET_STRING_t *os, int *len) return buf; } +F1AP_SNSSAI_t encode_nssai(const nssai_t *nssai) +{ + F1AP_SNSSAI_t enc = {0}; + INT8_TO_OCTET_STRING(nssai->sst, &enc.sST); + // see 23.003 sec. 28.4.2: 0xffffff means "no SD" + if (nssai->sd != 0xffffff) { + asn1cCalloc(enc.sD, tmp); + INT24_TO_OCTET_STRING(nssai->sd, tmp); + } + return enc; +} + +nssai_t decode_nssai(const F1AP_SNSSAI_t *nssai) +{ + // see 23.003 sec. 28.4.2: 0xffffff means "no SD" + nssai_t dec = { .sd = 0xffffff, }; + OCTET_STRING_TO_INT8(&nssai->sST, dec.sst); + if (nssai->sD != NULL) + OCTET_STRING_TO_INT24(nssai->sD, dec.sd); + return dec; +} + F1AP_Cause_t encode_f1ap_cause(f1ap_Cause_t cause, long cause_value) { F1AP_Cause_t f1_cause = {0}; diff --git a/openair2/F1AP/lib/f1ap_lib_common.h b/openair2/F1AP/lib/f1ap_lib_common.h index 8a3ddfba4a..b49fad88c1 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.h +++ b/openair2/F1AP/lib/f1ap_lib_common.h @@ -27,40 +27,51 @@ #include #include "openair3/UTILS/conversions.h" #include "common/5g_platform_types.h" +#include "common/utils/ds/byte_array.h" #include "F1AP_Cause.h" +#include "F1AP_SNSSAI.h" #include "f1ap_messages_types.h" #ifdef ENABLE_TESTS - #define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__) + #define PRINT_ERROR(fmt, ...) fprintf(stderr, "%s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__) #else #define PRINT_ERROR(...) // Do nothing #endif -#define _F1_EQ_CHECK_GENERIC(condition, fmt, ...) \ - do { \ - if (!(condition)) { \ - PRINT_ERROR("F1 Equality Check failure: %s:%d: Condition '%s' failed: " fmt " != " fmt "\n", \ - __FILE__, \ - __LINE__, \ - #condition, \ - ##__VA_ARGS__); \ - return false; \ - } \ +#define _F1_EQ_CHECK_GENERIC(condition, fmt, ...) \ + do { \ + if (!(condition)) { \ + PRINT_ERROR("Equality condition '%s' failed: " fmt " != " fmt "\n", #condition, ##__VA_ARGS__); \ + return false; \ + } \ } while (0) #define _F1_EQ_CHECK_LONG(A, B) _F1_EQ_CHECK_GENERIC(A == B, "%ld", A, B); #define _F1_EQ_CHECK_INT(A, B) _F1_EQ_CHECK_GENERIC(A == B, "%d", A, B); #define _F1_EQ_CHECK_STR(A, B) _F1_EQ_CHECK_GENERIC(strcmp(A, B) == 0, "'%s'", A, B); +#define _F1_CHECK_EXP(EXP) \ + do { \ + if (!(EXP)) { \ + PRINT_ERROR("Failed at " #EXP "\n"); \ + return false; \ + } \ + } while (0) + +#define _F1_EQ_CHECK_OPTIONAL_IE(A, B, FIELD, EQ_MACRO) \ + do { \ + _F1_CHECK_EXP(((A)->FIELD && (B)->FIELD) || (!(A)->FIELD && !(B)->FIELD)); \ + if ((A)->FIELD && (B)->FIELD) \ + EQ_MACRO(*(A)->FIELD, *(B)->FIELD); \ + } while (0) + /* macro to look up IE. If mandatory and not found, macro will print * descriptive debug message to stderr and force exit in calling function */ -#define F1AP_LIB_FIND_IE(IE_TYPE, ie, container, IE_ID, mandatory) \ +#define F1AP_LIB_FIND_IE(IE_TYPE, ie, IE_LIST, IE_ID, mandatory) \ do { \ ie = NULL; \ - for (IE_TYPE **ptr = container->protocolIEs.list.array; \ - ptr < &container->protocolIEs.list.array[container->protocolIEs.list.count]; \ - ptr++) { \ + for (IE_TYPE **ptr = (IE_LIST)->array; ptr < &(IE_LIST)->array[(IE_LIST)->count]; ptr++) { \ if ((*ptr)->id == IE_ID) { \ ie = *ptr; \ break; \ @@ -72,6 +83,29 @@ } \ } while (0) +#define CP_OPT_BYTE_ARRAY(dst, src) \ + do { \ + if (src) { \ + dst = calloc_or_fail(1, sizeof(*dst)); \ + *(dst) = copy_byte_array(*(src)); \ + } \ + } while (0) + +#define FREE_OPT_BYTE_ARRAY(a) \ + do { \ + if (a) { \ + free_byte_array(*(a)); \ + } \ + free(a); \ + } while (0) + +/* similar to asn1cCallocOne(), duplicated to not confuse with asn.1 types */ +#define _F1_MALLOC(VaR, VaLue) \ + do { \ + VaR = malloc_or_fail(sizeof(*VaR)); \ + *VaR = VaLue; \ + } while (0) + bool eq_f1ap_plmn(const plmn_id_t *a, const plmn_id_t *b); struct f1ap_served_cell_info_t; bool eq_f1ap_cell_info(const struct f1ap_served_cell_info_t *a, const struct f1ap_served_cell_info_t *b); @@ -85,6 +119,9 @@ bool eq_f1ap_tx_bandwidth(const struct f1ap_transmission_bandwidth_t *a, const s struct OCTET_STRING; uint8_t *cp_octet_string(const struct OCTET_STRING *os, int *len); +F1AP_SNSSAI_t encode_nssai(const nssai_t *nssai); +nssai_t decode_nssai(const F1AP_SNSSAI_t *nssai); + F1AP_Cause_t encode_f1ap_cause(f1ap_Cause_t cause, long cause_value); bool decode_f1ap_cause(F1AP_Cause_t f1_cause, f1ap_Cause_t *cause, long *cause_value); diff --git a/openair2/F1AP/lib/f1ap_lib_includes.h b/openair2/F1AP/lib/f1ap_lib_includes.h index 267e7243e7..3f039bf6f0 100644 --- a/openair2/F1AP/lib/f1ap_lib_includes.h +++ b/openair2/F1AP/lib/f1ap_lib_includes.h @@ -41,5 +41,11 @@ #include "F1AP_SibtypetobeupdatedListItem.h" #include "F1AP_UnsuccessfulOutcome.h" #include "F1AP_UE-associatedLogicalF1-ConnectionListRes.h" +#include "F1AP_ULUPTNLInformation-ToBeSetup-Item.h" +#include "F1AP_GTPTunnel.h" +#include "F1AP_Flows-Mapped-To-DRB-Item.h" +#include "F1AP_NonDynamic5QIDescriptor.h" +#include "F1AP_Dynamic5QIDescriptor.h" +#include "F1AP_DLUPTNLInformation-ToBeSetup-Item.h" #endif /* F1AP_LIB_INCLUDES_H_ */ diff --git a/openair2/F1AP/lib/f1ap_rrc_message_transfer.c b/openair2/F1AP/lib/f1ap_rrc_message_transfer.c index 5fc9e2d622..c2f6e780aa 100644 --- a/openair2/F1AP/lib/f1ap_rrc_message_transfer.c +++ b/openair2/F1AP/lib/f1ap_rrc_message_transfer.c @@ -114,26 +114,27 @@ bool decode_initial_ul_rrc_message_transfer(const F1AP_F1AP_PDU_t *pdu, f1ap_ini memset(out, 0, sizeof(*out)); F1AP_InitialULRRCMessageTransfer_t *container = &pdu->choice.initiatingMessage->value.choice.InitialULRRCMessageTransfer; + F1AP_ProtocolIE_Container_10659P31_t *pIEs = &container->protocolIEs; F1AP_InitialULRRCMessageTransferIEs_t *ie; - F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; - F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_NRCGI, true); + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_NRCGI, true); PLMNID_TO_MCC_MNC(&ie->value.choice.NRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length); BIT_STRING_TO_NR_CELL_IDENTITY(&ie->value.choice.NRCGI.nRCellIdentity, out->nr_cellid); - F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_C_RNTI, true); + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_C_RNTI, true); out->crnti = ie->value.choice.C_RNTI; - F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_RRCContainer, true); + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_RRCContainer, true); out->rrc_container = cp_octet_string(&ie->value.choice.RRCContainer, &out->rrc_container_length); - F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_DUtoCURRCContainer, false); + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_DUtoCURRCContainer, false); if (ie != NULL) out->du2cu_rrc_container = cp_octet_string(&ie->value.choice.DUtoCURRCContainer, &out->du2cu_rrc_container_length); - F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_TransactionID, true); out->transaction_id = ie->value.choice.TransactionID; return true; @@ -258,19 +259,20 @@ bool decode_ul_rrc_message_transfer(const F1AP_F1AP_PDU_t *pdu, f1ap_ul_rrc_mess DevAssert(pdu != NULL); F1AP_ULRRCMessageTransfer_t *container = &pdu->choice.initiatingMessage->value.choice.ULRRCMessageTransfer; + F1AP_ProtocolIE_Container_10659P33_t *pIEs = &container->protocolIEs; F1AP_ULRRCMessageTransferIEs_t *ie; // gNB-CU UE F1AP ID (M) - F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; // gNB-DU UE F1AP ID (M) - F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; // SRB ID (M) - F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_SRBID, true); + F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_SRBID, true); out->srb_id = ie->value.choice.SRBID; // RRC-Container (M) - F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_RRCContainer, true); + F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_RRCContainer, true); out->rrc_container = cp_octet_string(&ie->value.choice.RRCContainer, &out->rrc_container_length); return true; @@ -392,30 +394,31 @@ bool decode_dl_rrc_message_transfer(const F1AP_F1AP_PDU_t *pdu, f1ap_dl_rrc_mess DevAssert(pdu != NULL); F1AP_DLRRCMessageTransfer_t *container = &pdu->choice.initiatingMessage->value.choice.DLRRCMessageTransfer; + F1AP_ProtocolIE_Container_10659P32_t *pIEs = &container->protocolIEs; F1AP_DLRRCMessageTransferIEs_t *ie; // gNB-CU UE F1AP ID (M) - F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; // gNB-DU UE F1AP ID (M) - F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; // old gNB-DU UE F1AP ID (O) out->old_gNB_DU_ue_id = NULL; - F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID, false); + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID, false); if (ie) { out->old_gNB_DU_ue_id = malloc_or_fail(sizeof(*out->old_gNB_DU_ue_id)); *out->old_gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID_1; } // SRB ID (M) - F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_SRBID, true); + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_SRBID, true); out->srb_id = ie->value.choice.SRBID; // Execute Duplication (O) - F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_ExecuteDuplication, false); + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_ExecuteDuplication, false); if (ie) { out->execute_duplication = ie->value.choice.ExecuteDuplication; } // RRC-Container (M) - F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_RRCContainer, true); + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, &pIEs->list, F1AP_ProtocolIE_ID_id_RRCContainer, true); out->rrc_container = cp_octet_string(&ie->value.choice.RRCContainer, &out->rrc_container_length); return true; diff --git a/openair2/F1AP/lib/f1ap_ue_context.c b/openair2/F1AP/lib/f1ap_ue_context.c new file mode 100644 index 0000000000..9d8cbfe15f --- /dev/null +++ b/openair2/F1AP/lib/f1ap_ue_context.c @@ -0,0 +1,2491 @@ +/* + * 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 "f1ap_ue_context.h" + +#include "f1ap_lib_common.h" +#include "f1ap_lib_includes.h" +#include "f1ap_messages_types.h" + +#include "common/utils/assertions.h" +#include "openair3/UTILS/conversions.h" +#include "common/utils/oai_asn1.h" +#include "common/utils/utils.h" +#include "common/utils/ds/byte_array.h" + +static F1AP_CUtoDURRCInformation_t encode_cu_to_du_rrc_info(const f1ap_cu_to_du_rrc_info_t *cu2du) +{ + F1AP_CUtoDURRCInformation_t enc = {0}; + + /* optional: cG_ConfigInfo */ + if (cu2du->cg_configinfo) { + asn1cCalloc(enc.cG_ConfigInfo, cG_ConfigInfo); + const byte_array_t *ba = cu2du->cg_configinfo; + OCTET_STRING_fromBuf(cG_ConfigInfo, (const char *)ba->buf, ba->len); + } + + /* optional: uE_CapabilityRAT_ContainerList */ + if (cu2du->ue_cap) { + asn1cCalloc(enc.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList); + const byte_array_t *ba = cu2du->ue_cap; + OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)ba->buf, ba->len); + } + + /* optional: measConfig */ + if (cu2du->meas_config) { + asn1cCalloc(enc.measConfig, measConfig); + const byte_array_t *ba = cu2du->meas_config; + OCTET_STRING_fromBuf(measConfig, (const char *)ba->buf, ba->len); + } + + /* optional: HandoverPreparationInformation */ + F1AP_ProtocolExtensionContainer_10696P60_t *p = NULL; + if (cu2du->ho_prep_info) { + p = calloc_or_fail(1, sizeof(*p)); + enc.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; + asn1cSequenceAdd(p->list, F1AP_CUtoDURRCInformation_ExtIEs_t, ie_ext); + ie_ext->id = F1AP_ProtocolIE_ID_id_HandoverPreparationInformation; + ie_ext->criticality = F1AP_Criticality_ignore; + ie_ext->extensionValue.present = F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_HandoverPreparationInformation; + const byte_array_t *ba = cu2du->ho_prep_info; + F1AP_HandoverPreparationInformation_t *hpi = &ie_ext->extensionValue.choice.HandoverPreparationInformation; + OCTET_STRING_fromBuf(hpi, (const char *)ba->buf, ba->len); + } + + /* optional: iE_Extensions */ + if (cu2du->meas_timing_config) { + if (!p) + p = calloc_or_fail(1, sizeof(*p)); + enc.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; + asn1cSequenceAdd(p->list, F1AP_CUtoDURRCInformation_ExtIEs_t, ie_ext); + ie_ext->id = F1AP_ProtocolIE_ID_id_MeasurementTimingConfiguration; + ie_ext->criticality = F1AP_Criticality_ignore; + ie_ext->extensionValue.present = F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_MeasurementTimingConfiguration; + const byte_array_t *ba = cu2du->meas_timing_config; + F1AP_MeasurementTimingConfiguration_t *mtc = &ie_ext->extensionValue.choice.MeasurementTimingConfiguration; + OCTET_STRING_fromBuf(mtc, (const char *)ba->buf, ba->len); + } + return enc; +} + +static bool decode_cu_to_du_rrc_info(f1ap_cu_to_du_rrc_info_t *dec, const F1AP_CUtoDURRCInformation_t *cu2du) +{ + if (cu2du->cG_ConfigInfo) { + dec->cg_configinfo = calloc_or_fail(1, sizeof(*dec->cg_configinfo)); + const F1AP_CG_ConfigInfo_t *cgci = cu2du->cG_ConfigInfo; + *dec->cg_configinfo = create_byte_array(cgci->size, (uint8_t*)cgci->buf); + } + if (cu2du->uE_CapabilityRAT_ContainerList) { + dec->ue_cap = calloc_or_fail(1, sizeof(*dec->ue_cap)); + const F1AP_UE_CapabilityRAT_ContainerList_t *l = cu2du->uE_CapabilityRAT_ContainerList; + *dec->ue_cap = create_byte_array(l->size, (uint8_t*)l->buf); + } + if (cu2du->measConfig) { + dec->meas_config = calloc_or_fail(1, sizeof(*dec->meas_config)); + const F1AP_MeasConfig_t *mc = cu2du->measConfig; + *dec->meas_config = create_byte_array(mc->size, (uint8_t*)mc->buf); + } + if (cu2du->iE_Extensions) { + const F1AP_ProtocolExtensionContainer_10696P60_t *ext = (const F1AP_ProtocolExtensionContainer_10696P60_t *)cu2du->iE_Extensions; + for (int i = 0; i < ext->list.count; ++i) { + const F1AP_CUtoDURRCInformation_ExtIEs_t *cu2du_info_ext = ext->list.array[i]; + switch (cu2du_info_ext->id) { + case F1AP_ProtocolIE_ID_id_HandoverPreparationInformation: + dec->ho_prep_info = calloc_or_fail(1, sizeof(*dec->ho_prep_info)); + const F1AP_HandoverPreparationInformation_t *hopi = &cu2du_info_ext->extensionValue.choice.HandoverPreparationInformation; + *dec->ho_prep_info = create_byte_array(hopi->size, (uint8_t*) hopi->buf); + break; + case F1AP_ProtocolIE_ID_id_MeasurementTimingConfiguration: + dec->meas_timing_config = calloc_or_fail(1, sizeof(*dec->meas_timing_config)); + const F1AP_MeasurementTimingConfiguration_t *mtc = &cu2du_info_ext->extensionValue.choice.MeasurementTimingConfiguration; + *dec->meas_timing_config = create_byte_array(mtc->size, (uint8_t *)mtc->buf); + break; + default: + PRINT_ERROR("received unsupported F1AP CUtoDURRCInfo extension container %ld\n", cu2du_info_ext->id); + } + } + } + return true; +} + +static f1ap_cu_to_du_rrc_info_t cp_cu_to_du_rrc_info(const f1ap_cu_to_du_rrc_info_t *src) +{ + f1ap_cu_to_du_rrc_info_t dst = {0}; + CP_OPT_BYTE_ARRAY(dst.cg_configinfo, src->cg_configinfo); + CP_OPT_BYTE_ARRAY(dst.ue_cap, src->ue_cap); + CP_OPT_BYTE_ARRAY(dst.meas_config, src->meas_config); + CP_OPT_BYTE_ARRAY(dst.meas_timing_config, src->meas_timing_config); + CP_OPT_BYTE_ARRAY(dst.ho_prep_info, src->ho_prep_info); + return dst; +} + +static bool eq_ba(const byte_array_t a, const byte_array_t b) +{ + return eq_byte_array(&a, &b); +} + +static bool eq_cu_to_du_rrc_info(const f1ap_cu_to_du_rrc_info_t *a, const f1ap_cu_to_du_rrc_info_t *b) +{ + _F1_EQ_CHECK_OPTIONAL_IE(a, b, cg_configinfo, eq_ba); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, ue_cap, eq_ba); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, meas_config, eq_ba); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, meas_timing_config, eq_ba); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, ho_prep_info, eq_ba); + return true; +} + +static void free_cu_to_du_rrc_info(f1ap_cu_to_du_rrc_info_t *cu2du) +{ + FREE_OPT_BYTE_ARRAY(cu2du->cg_configinfo); + FREE_OPT_BYTE_ARRAY(cu2du->ue_cap); + FREE_OPT_BYTE_ARRAY(cu2du->meas_config); + FREE_OPT_BYTE_ARRAY(cu2du->meas_timing_config); + FREE_OPT_BYTE_ARRAY(cu2du->ho_prep_info); +} + +static F1AP_DUtoCURRCInformation_t encode_du_to_cu_rrc_info(const f1ap_du_to_cu_rrc_info_t *du2cu) +{ + F1AP_DUtoCURRCInformation_t enc = {0}; + + /* mandatory: cellGroupConfig */ + const byte_array_t *ba = &du2cu->cell_group_config; + OCTET_STRING_fromBuf(&enc.cellGroupConfig, (const char *)ba->buf, ba->len); + + /* optional: MeasGapConfig */ + if (du2cu->meas_gap_config) { + ba = du2cu->meas_gap_config; + asn1cCalloc(enc.measGapConfig, measGapConfig); + OCTET_STRING_fromBuf(measGapConfig, (const char *)ba->buf, ba->len); + } + + return enc; +} + +static bool decode_du_to_cu_rrc_info(f1ap_du_to_cu_rrc_info_t *dec, const F1AP_DUtoCURRCInformation_t *du2cu) +{ + const F1AP_CellGroupConfig_t *cgc = &du2cu->cellGroupConfig; + dec->cell_group_config = create_byte_array(cgc->size, (uint8_t *)cgc->buf); + + if (du2cu->measGapConfig) { + const F1AP_MeasGapConfig_t *mgc = du2cu->measGapConfig; + dec->meas_gap_config = calloc_or_fail(1, sizeof(*dec->meas_gap_config)); + *dec->meas_gap_config = create_byte_array(mgc->size, (uint8_t *)mgc->buf); + } + return true; +} + +static f1ap_du_to_cu_rrc_info_t cp_du_to_cu_rrc_info(const f1ap_du_to_cu_rrc_info_t *src) +{ + f1ap_du_to_cu_rrc_info_t cp = {0}; + cp.cell_group_config = copy_byte_array(src->cell_group_config); + CP_OPT_BYTE_ARRAY(cp.meas_gap_config, src->meas_gap_config); + return cp; +} + +static bool eq_du_to_cu_rrc_info(const f1ap_du_to_cu_rrc_info_t *a, const f1ap_du_to_cu_rrc_info_t *b) +{ + _F1_CHECK_EXP(eq_byte_array(&a->cell_group_config, &b->cell_group_config)); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, meas_gap_config, eq_ba); + return true; +} + +static void free_du_to_cu_rrc_info(f1ap_du_to_cu_rrc_info_t *du2cu) +{ + free_byte_array(du2cu->cell_group_config); + FREE_OPT_BYTE_ARRAY(du2cu->meas_gap_config); +} + +/* \brief Encode SRB-ToBeSetup List, for UE Context Setup Request, from + * f1ap_srb_to_setup_t. */ +static F1AP_SRBs_ToBeSetup_List_t encode_srbs_to_setup(int n, const f1ap_srb_to_setup_t *srbs) +{ + F1AP_SRBs_ToBeSetup_List_t list = {0}; + for (int i = 0; i < n; ++i) { + asn1cSequenceAdd(list, F1AP_SRBs_ToBeSetup_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_Item; + itie->criticality = F1AP_Criticality_reject; + itie->value.present = F1AP_SRBs_ToBeSetup_ItemIEs__value_PR_SRBs_ToBeSetup_Item; + itie->value.choice.SRBs_ToBeSetup_Item.sRBID = srbs[i].id; + } + return list; +} + +/* \brief Encode SRB-ToBeSetupMod List, for UE context Modification Request, + * from f1ap_srb_to_setup_t. The ToBeSetup/ToBeSetupMod lists are basically the + * same in both cases, but the asn1c types are different. */ +static F1AP_SRBs_ToBeSetupMod_List_t encode_srbs_to_setupmod(int n, const f1ap_srb_to_setup_t *srbs) +{ + F1AP_SRBs_ToBeSetupMod_List_t list = {0}; + for (int i = 0; i < n; ++i) { + asn1cSequenceAdd(list, F1AP_SRBs_ToBeSetupMod_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item; + itie->criticality = F1AP_Criticality_reject; + itie->value.present = F1AP_SRBs_ToBeSetupMod_ItemIEs__value_PR_SRBs_ToBeSetupMod_Item; + itie->value.choice.SRBs_ToBeSetupMod_Item.sRBID = srbs[i].id; + } + return list; +} + +/* \brief Decode SRB-ToBeSetup List, from UE Context Setup Request, into + * f1ap_srb_to_setup_t. */ +static bool decode_srbs_to_setup(const F1AP_SRBs_ToBeSetup_List_t *f1ap, int *n, f1ap_srb_to_setup_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_srb_to_setup_t *srbs = *out = calloc_or_fail(count, sizeof(*srbs)); + for (int i = 0; i < count; ++i) { + const F1AP_SRBs_ToBeSetup_ItemIEs_t *itie = (F1AP_SRBs_ToBeSetup_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_SRBs_ToBeSetup_ItemIEs__value_PR_SRBs_ToBeSetup_Item); + srbs[i].id = itie->value.choice.SRBs_ToBeSetup_Item.sRBID; + } + + return true; +} + +/* \brief Decode SRB-ToBeSetupMod List, from UE Context Modification Request, + * into f1ap_srb_to_setup_t. The ToBeSetup/ToBeSetupMod lists are basically the + * same, but the asn1c types are different. */ +static bool decode_srbs_to_setupmod(const F1AP_SRBs_ToBeSetupMod_List_t *f1ap, int *n, f1ap_srb_to_setup_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_srb_to_setup_t *srbs = *out = calloc_or_fail(count, sizeof(*srbs)); + for (int i = 0; i < count; ++i) { + const F1AP_SRBs_ToBeSetupMod_ItemIEs_t *itie = (F1AP_SRBs_ToBeSetupMod_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_SRBs_ToBeSetupMod_ItemIEs__value_PR_SRBs_ToBeSetupMod_Item); + srbs[i].id = itie->value.choice.SRBs_ToBeSetupMod_Item.sRBID; + } + + return true; +} + +static f1ap_srb_to_setup_t cp_srb_to_setup(const f1ap_srb_to_setup_t *orig) +{ + f1ap_srb_to_setup_t cp = { + .id = orig->id, + }; + return cp; +} + +static bool eq_srb_to_setup(const f1ap_srb_to_setup_t *a, const f1ap_srb_to_setup_t *b) +{ + _F1_EQ_CHECK_INT(a->id, b->id); + return true; +} + +static void free_srb_to_setup(f1ap_srb_to_setup_t *srbs) +{ + // nothing to free +} + +static F1AP_SRBs_Setup_List_t encode_srbs_setup(int n, const f1ap_srb_setup_t *srbs) +{ + F1AP_SRBs_Setup_List_t list = {0}; + for (int i = 0; i < n; ++i) { + asn1cSequenceAdd(list, F1AP_SRBs_Setup_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_Item; + itie->criticality = F1AP_Criticality_ignore; + itie->value.present = F1AP_SRBs_Setup_ItemIEs__value_PR_SRBs_Setup_Item; + F1AP_SRBs_Setup_Item_t *it = &itie->value.choice.SRBs_Setup_Item; + it->sRBID = srbs[i].id; + it->lCID = srbs[i].lcid; + } + return list; +} + +static F1AP_SRBs_SetupMod_List_t encode_srbs_setupmod(int n, const f1ap_srb_setup_t *srbs) +{ + F1AP_SRBs_SetupMod_List_t list = {0}; + for (int i = 0; i < n; ++i) { + asn1cSequenceAdd(list, F1AP_SRBs_SetupMod_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_Item; + itie->criticality = F1AP_Criticality_ignore; + itie->value.present = F1AP_SRBs_SetupMod_ItemIEs__value_PR_SRBs_SetupMod_Item; + F1AP_SRBs_SetupMod_Item_t *it = &itie->value.choice.SRBs_SetupMod_Item; + it->sRBID = srbs[i].id; + it->lCID = srbs[i].lcid; + } + return list; +} + +static bool decode_srbs_setup(const F1AP_SRBs_Setup_List_t *f1ap, int *n, f1ap_srb_setup_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_srb_setup_t *srbs = *out = calloc_or_fail(count, sizeof(*srbs)); + for (int i = 0; i < count; ++i) { + const F1AP_SRBs_Setup_ItemIEs_t *itie = (F1AP_SRBs_Setup_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_SRBs_Setup_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_SRBs_Setup_ItemIEs__value_PR_SRBs_Setup_Item); + const F1AP_SRBs_Setup_Item_t *it = &itie->value.choice.SRBs_Setup_Item; + srbs[i].id = it->sRBID; + srbs[i].lcid = it->lCID; + } + return true; +} + +static bool decode_srbs_setupmod(const F1AP_SRBs_SetupMod_List_t *f1ap, int *n, f1ap_srb_setup_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_srb_setup_t *srbs = *out = calloc_or_fail(count, sizeof(*srbs)); + for (int i = 0; i < count; ++i) { + const F1AP_SRBs_SetupMod_ItemIEs_t *itie = (F1AP_SRBs_SetupMod_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_SRBs_SetupMod_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_SRBs_SetupMod_ItemIEs__value_PR_SRBs_SetupMod_Item); + const F1AP_SRBs_SetupMod_Item_t *it = &itie->value.choice.SRBs_SetupMod_Item; + srbs[i].id = it->sRBID; + srbs[i].lcid = it->lCID; + } + return true; +} + +static f1ap_srb_setup_t cp_srb_setup(const f1ap_srb_setup_t *orig) +{ + f1ap_srb_setup_t cp = {.id = orig->id, .lcid = orig->lcid}; + return cp; +} + +static bool eq_srb_setup(const f1ap_srb_setup_t *a, const f1ap_srb_setup_t *b) +{ + _F1_EQ_CHECK_INT(a->id, b->id); + _F1_EQ_CHECK_INT(a->lcid, b->lcid); + return true; +} + +static void free_srb_setup(f1ap_srb_setup_t *srbs) +{ + // nothing to free +} + +static F1AP_QoSFlowLevelQoSParameters_t encode_qos_flow_param(const f1ap_qos_flow_param_t *p) +{ + F1AP_QoSFlowLevelQoSParameters_t f1ap = {0}; + + if (p->qos_type == NON_DYNAMIC) { + f1ap.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + asn1cCalloc(f1ap.qoS_Characteristics.choice.non_Dynamic_5QI, nd); + nd->fiveQI = p->nondyn.fiveQI; + } else { + DevAssert(p->qos_type == DYNAMIC); + f1ap.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(f1ap.qoS_Characteristics.choice.dynamic_5QI, d); + + d->qoSPriorityLevel = p->dyn.prio; + d->packetDelayBudget = p->dyn.pdb; + d->packetErrorRate.pER_Scalar = p->dyn.per.scalar; + d->packetErrorRate.pER_Exponent = p->dyn.per.exponent; + + if (p->dyn.delay_critical) { + e_F1AP_Dynamic5QIDescriptor__delayCritical v = *p->dyn.delay_critical + ? F1AP_Dynamic5QIDescriptor__delayCritical_delay_critical + : F1AP_Dynamic5QIDescriptor__delayCritical_non_delay_critical; + asn1cCallocOne(d->delayCritical, v); + } + + if (p->dyn.avg_win) + asn1cCallocOne(d->averagingWindow, *p->dyn.avg_win); + } + + F1AP_NGRANAllocationAndRetentionPriority_t *arp = &f1ap.nGRANallocationRetentionPriority; + arp->priorityLevel = p->arp.prio; + arp->pre_emptionCapability = p->arp.preempt_cap; + arp->pre_emptionVulnerability = p->arp.preempt_vuln; + return f1ap; +} + +static bool decode_qos_flow_param(const F1AP_QoSFlowLevelQoSParameters_t *f1ap, f1ap_qos_flow_param_t *out) +{ + if (f1ap->qoS_Characteristics.present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) { + out->qos_type = NON_DYNAMIC; + const F1AP_NonDynamic5QIDescriptor_t *nondyn = f1ap->qoS_Characteristics.choice.non_Dynamic_5QI; + out->nondyn.fiveQI = nondyn->fiveQI; + } else { + _F1_EQ_CHECK_INT(f1ap->qoS_Characteristics.present, F1AP_QoS_Characteristics_PR_dynamic_5QI); + const F1AP_Dynamic5QIDescriptor_t *d = f1ap->qoS_Characteristics.choice.dynamic_5QI; + out->qos_type = DYNAMIC; + out->dyn.prio = d->qoSPriorityLevel; + out->dyn.pdb = d->packetDelayBudget; + out->dyn.per.scalar = d->packetErrorRate.pER_Scalar; + out->dyn.per.exponent = d->packetErrorRate.pER_Exponent; + + if (d->delayCritical) { + bool v = *d->delayCritical == F1AP_Dynamic5QIDescriptor__delayCritical_delay_critical; + _F1_MALLOC(out->dyn.delay_critical, v); + } + + if (d->averagingWindow) + _F1_MALLOC(out->dyn.avg_win, *d->averagingWindow); + } + + const F1AP_NGRANAllocationAndRetentionPriority_t *arp = &f1ap->nGRANallocationRetentionPriority; + out->arp.prio = arp->priorityLevel; + out->arp.preempt_cap = arp->pre_emptionCapability; + out->arp.preempt_vuln = arp->pre_emptionVulnerability; + return true; +} + +static f1ap_qos_flow_param_t cp_qos_flow_param(const f1ap_qos_flow_param_t *orig) +{ + f1ap_qos_flow_param_t cp = { + .qos_type = orig->qos_type, + // dyn/nondyn below + .arp = orig->arp, + }; + if (cp.qos_type == NON_DYNAMIC) { + cp.nondyn.fiveQI = orig->nondyn.fiveQI; + } else { + DevAssert(cp.qos_type == DYNAMIC); + f1ap_dynamic_5qi_t *cpdyn = &cp.dyn; + const f1ap_dynamic_5qi_t *odyn = &orig->dyn; + cpdyn->prio = odyn->prio; + cpdyn->pdb = odyn->pdb; + cpdyn->per.scalar = odyn->per.scalar; + cpdyn->per.exponent = odyn->per.exponent; + if (odyn->delay_critical) + _F1_MALLOC(cpdyn->delay_critical, *odyn->delay_critical); + if (odyn->avg_win) + _F1_MALLOC(cpdyn->avg_win, *odyn->avg_win); + } + return cp; +} + +static bool eq_qos_flow_param(const f1ap_qos_flow_param_t *a, const f1ap_qos_flow_param_t *b) +{ + _F1_EQ_CHECK_INT(a->qos_type, b->qos_type); + if (a->qos_type == NON_DYNAMIC) { + _F1_EQ_CHECK_INT(a->nondyn.fiveQI, b->nondyn.fiveQI); + } else { + DevAssert(a->qos_type == DYNAMIC); + DevAssert(b->qos_type == DYNAMIC); + const f1ap_dynamic_5qi_t *adyn = &a->dyn, *bdyn = &b->dyn; + _F1_EQ_CHECK_INT(adyn->prio, bdyn->prio); + _F1_EQ_CHECK_INT(adyn->pdb, bdyn->pdb); + _F1_EQ_CHECK_INT(adyn->per.scalar, bdyn->per.scalar); + _F1_EQ_CHECK_INT(adyn->per.exponent, bdyn->per.exponent); + _F1_EQ_CHECK_OPTIONAL_IE(adyn, bdyn, delay_critical, _F1_EQ_CHECK_INT); + _F1_EQ_CHECK_OPTIONAL_IE(adyn, bdyn, avg_win, _F1_EQ_CHECK_INT); + } + _F1_EQ_CHECK_INT(a->arp.prio, b->arp.prio); + _F1_EQ_CHECK_INT(a->arp.preempt_cap, b->arp.preempt_cap); + _F1_EQ_CHECK_INT(a->arp.preempt_vuln, b->arp.preempt_vuln); + return true; +} + +static void free_qos_flow_param(f1ap_qos_flow_param_t *p) +{ + if (p->qos_type == NON_DYNAMIC) { + // nothing to free + } else { + DevAssert(p->qos_type == DYNAMIC); + free(p->dyn.delay_critical); + free(p->dyn.avg_win); + } + // arp: nothing to free +} + +static F1AP_DRB_Information_t encode_drb_info_nr(const f1ap_drb_info_nr_t *drb) +{ + F1AP_DRB_Information_t f1ap = {0}; + + f1ap.dRB_QoS = encode_qos_flow_param(&drb->drb_qos); + f1ap.sNSSAI = encode_nssai(&drb->nssai); + + for (int i = 0; i < drb->flows_len; ++i) { + asn1cSequenceAdd(f1ap.flows_Mapped_To_DRB_List.list, F1AP_Flows_Mapped_To_DRB_Item_t, it); + it->qoSFlowIdentifier = drb->flows[i].qfi; + it->qoSFlowLevelQoSParameters = encode_qos_flow_param(&drb->flows[i].param); + } + + return f1ap; +} + +static bool decode_drb_info_nr(const F1AP_DRB_Information_t *f1ap, f1ap_drb_info_nr_t *out) +{ + _F1_CHECK_EXP(decode_qos_flow_param(&f1ap->dRB_QoS, &out->drb_qos)); + out->nssai = decode_nssai(&f1ap->sNSSAI); + out->flows_len = f1ap->flows_Mapped_To_DRB_List.list.count; + out->flows = calloc_or_fail(out->flows_len, sizeof(*out->flows)); + for (int i = 0; i < out->flows_len; ++i) { + const F1AP_Flows_Mapped_To_DRB_Item_t *it = f1ap->flows_Mapped_To_DRB_List.list.array[i]; + out->flows[i].qfi = it->qoSFlowIdentifier; + _F1_CHECK_EXP(decode_qos_flow_param(&it->qoSFlowLevelQoSParameters, &out->flows[i].param)); + } + return true; +} + +static f1ap_drb_info_nr_t cp_drb_info_nr(const f1ap_drb_info_nr_t *orig) +{ + f1ap_drb_info_nr_t cp = { + .drb_qos = cp_qos_flow_param(&orig->drb_qos), + .nssai = orig->nssai, + .flows_len = orig->flows_len, + // flows below + }; + cp.flows = calloc_or_fail(cp.flows_len, sizeof(*cp.flows)); + for (int i = 0; i < cp.flows_len; ++i) { + cp.flows[i].qfi = orig->flows[i].qfi; + cp.flows[i].param = cp_qos_flow_param(&orig->flows[i].param); + } + return cp; +} + +static bool eq_drb_info_nr(const f1ap_drb_info_nr_t *a, const f1ap_drb_info_nr_t *b) +{ + _F1_CHECK_EXP(eq_qos_flow_param(&a->drb_qos, &b->drb_qos)); + _F1_EQ_CHECK_INT(a->nssai.sst, b->nssai.sst); + _F1_EQ_CHECK_INT(a->nssai.sd, b->nssai.sd); + _F1_EQ_CHECK_INT(a->flows_len, b->flows_len); + for (int i = 0; i < a->flows_len; ++i) { + _F1_EQ_CHECK_INT(a->flows[i].qfi, b->flows[i].qfi); + _F1_CHECK_EXP(eq_qos_flow_param(&a->flows[i].param, &b->flows[i].param)); + } + return true; +} + +static void free_drb_info_nr(f1ap_drb_info_nr_t *p) +{ + free_qos_flow_param(&p->drb_qos); + // nssai: nothing + for (int i = 0; i < p->flows_len; ++i) + free_qos_flow_param(&p->flows[i].param); + free(p->flows); +} + +static F1AP_RLCMode_t rlc_mode_to_asn1(f1ap_rlc_mode_t mode) +{ + switch (mode) { + case F1AP_RLC_MODE_AM: + return F1AP_RLCMode_rlc_am; + case F1AP_RLC_MODE_UM_BIDIR: + return F1AP_RLCMode_rlc_um_bidirectional; + default: + break; + } + AssertFatal(false, "unsupported RLC Mode %d received\n", mode); + return F1AP_RLCMode_rlc_am; // won't be reached +} + +static bool rlc_mode_from_asn1(F1AP_RLCMode_t mode, f1ap_rlc_mode_t *out) +{ + switch (mode) { + case F1AP_RLCMode_rlc_am: + *out = F1AP_RLC_MODE_AM; + return true; + case F1AP_RLCMode_rlc_um_bidirectional: + *out = F1AP_RLC_MODE_UM_BIDIR; + return true; + default: + PRINT_ERROR("unsupported RLC Mode %ld received: setting AM\n", mode); + break; + } + return false; +} + +static F1AP_UPTransportLayerInformation_t encode_up_tnl(const f1ap_up_tnl_t *tnl) +{ + F1AP_UPTransportLayerInformation_t tnl_info = { .present = F1AP_UPTransportLayerInformation_PR_gTPTunnel, }; + asn1cCalloc(tnl_info.choice.gTPTunnel, gtp_tnl); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(tnl->tl_address, >p_tnl->transportLayerAddress); + INT32_TO_OCTET_STRING(tnl->teid, >p_tnl->gTP_TEID); + return tnl_info; +} + +static bool decode_up_tnl(const F1AP_UPTransportLayerInformation_t *tnl_info, f1ap_up_tnl_t *out) +{ + _F1_EQ_CHECK_INT(tnl_info->present, F1AP_UPTransportLayerInformation_PR_gTPTunnel); + const F1AP_GTPTunnel_t *gtp_tnl = tnl_info->choice.gTPTunnel; + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(>p_tnl->transportLayerAddress, out->tl_address); + OCTET_STRING_TO_UINT32(>p_tnl->gTP_TEID, out->teid); + return true; +} + +static f1ap_up_tnl_t cp_up_tnl(const f1ap_up_tnl_t *orig) +{ + f1ap_up_tnl_t cp = { .teid = orig->teid, }; + memcpy(&cp.tl_address, &orig->tl_address, sizeof(orig->tl_address)); + return cp; +} + +static bool eq_up_tnl(const f1ap_up_tnl_t *a, const f1ap_up_tnl_t *b) +{ + if (memcmp(&a->tl_address, &b->tl_address, sizeof(a->tl_address)) != 0) { + PRINT_ERROR("tl_address mismatch\n"); + return false; + } + _F1_EQ_CHECK_INT(a->teid, b->teid); + return true; +} + +static void free_up_tnl(const f1ap_up_tnl_t *tnl) +{ + // nothing to free +} + +/* Encode a DRBs_ToSetup list for UE Context Setup Request, from f1ap_drb_to_setup_t. */ +static F1AP_DRBs_ToBeSetup_List_t encode_drbs_to_setup(int n, const f1ap_drb_to_setup_t *drbs) +{ + F1AP_DRBs_ToBeSetup_List_t list = {0}; + for (int i = 0; i < n; ++i) { + const f1ap_drb_to_setup_t *drb = &drbs[i]; + asn1cSequenceAdd(list, F1AP_DRBs_ToBeSetup_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_Item; + itie->criticality = F1AP_Criticality_reject; + itie->value.present = F1AP_DRBs_ToBeSetup_ItemIEs__value_PR_DRBs_ToBeSetup_Item; + + F1AP_DRBs_ToBeSetup_Item_t *it = &itie->value.choice.DRBs_ToBeSetup_Item; + it->dRBID = drb->id; + AssertFatal(drb->qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS choice implemented\n"); + it->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; + F1AP_QoSInformation_ExtIEs_t *qos_ext_ie = calloc_or_fail(1, sizeof(*qos_ext_ie)); + it->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)qos_ext_ie; + qos_ext_ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; + qos_ext_ie->criticality = F1AP_Criticality_reject; + qos_ext_ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; + qos_ext_ie->value.choice.DRB_Information = encode_drb_info_nr(&drb->nr); + + /* 12.1.3 uLUPTNLInformation_ToBeSetup_List */ + for (int j = 0; j < drb->up_ul_tnl_len; j++) { + DevAssert(drb->up_ul_tnl[j].teid > 0); + asn1cSequenceAdd(it->uLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, tnl_it); + tnl_it->uLUPTNLInformation = encode_up_tnl(&drb->up_ul_tnl[j]); + } + + it->rLCMode = rlc_mode_to_asn1(drb->rlc_mode); + + F1AP_ProtocolExtensionContainer_10696P82_t *ext = calloc_or_fail(1, sizeof(*ext)); + it->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)ext; + asn1cSequenceAdd(ext->list, F1AP_DRBs_ToBeSetup_ItemExtIEs_t, ext_ie); + ext_ie->id = F1AP_ProtocolIE_ID_id_DLPDCPSNLength; + ext_ie->criticality = F1AP_Criticality_ignore; + ext_ie->extensionValue.present = F1AP_DRBs_ToBeSetup_ItemExtIEs__extensionValue_PR_PDCPSNLength; + AssertFatal(drb->dl_pdcp_sn_len != NULL, "dl_pdcp_sn_len required for setup\n"); + ext_ie->extensionValue.choice.PDCPSNLength = *drb->dl_pdcp_sn_len; + + if (drb->ul_pdcp_sn_len) { + asn1cSequenceAdd(ext->list, F1AP_DRBs_ToBeSetup_ItemExtIEs_t, ext_ie); + ext_ie->id = F1AP_ProtocolIE_ID_id_ULPDCPSNLength; + ext_ie->criticality = F1AP_Criticality_ignore; + ext_ie->extensionValue.present = F1AP_DRBs_ToBeSetup_ItemExtIEs__extensionValue_PR_PDCPSNLength_1; + ext_ie->extensionValue.choice.PDCPSNLength_1 = *drb->ul_pdcp_sn_len; + } + } + return list; +} + +/* Encode a DRBs_ToBeSetupMod list for UE Context Modification Request, from + * f1ap_drb_to_setup_t. The ToBeSetup/ToBeSetupMod lists are almost the same + * (with the exception that one field is optional in the latter), so that we + * can reuse the internal types, but the asn1c types are different. */ +static F1AP_DRBs_ToBeSetupMod_List_t encode_drbs_to_setupmod(int n, const f1ap_drb_to_setup_t *drbs) +{ + F1AP_DRBs_ToBeSetupMod_List_t list = {0}; + for (int i = 0; i < n; ++i) { + const f1ap_drb_to_setup_t *drb = &drbs[i]; + asn1cSequenceAdd(list, F1AP_DRBs_ToBeSetupMod_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item; + itie->criticality = F1AP_Criticality_reject; + itie->value.present = F1AP_DRBs_ToBeSetupMod_ItemIEs__value_PR_DRBs_ToBeSetupMod_Item; + + F1AP_DRBs_ToBeSetupMod_Item_t *it = &itie->value.choice.DRBs_ToBeSetupMod_Item; + it->dRBID = drb->id; + AssertFatal(drb->qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS choice implemented\n"); + it->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension; + F1AP_QoSInformation_ExtIEs_t *qos_ext_ie = calloc_or_fail(1, sizeof(*qos_ext_ie)); + it->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)qos_ext_ie; + qos_ext_ie->id = F1AP_ProtocolIE_ID_id_DRB_Information; + qos_ext_ie->criticality = F1AP_Criticality_reject; + qos_ext_ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information; + qos_ext_ie->value.choice.DRB_Information = encode_drb_info_nr(&drb->nr); + + /* 12.1.3 uLUPTNLInformation_ToBeSetupMod_List */ + for (int j = 0; j < drb->up_ul_tnl_len; j++) { + DevAssert(drb->up_ul_tnl[j].teid > 0); + asn1cSequenceAdd(it->uLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, tnl_it); + tnl_it->uLUPTNLInformation = encode_up_tnl(&drb->up_ul_tnl[j]); + } + + it->rLCMode = rlc_mode_to_asn1(drb->rlc_mode); + + if (!drb->dl_pdcp_sn_len && !drb->ul_pdcp_sn_len) + continue; + + F1AP_ProtocolExtensionContainer_10696P83_t *ext = calloc_or_fail(1, sizeof(*ext)); + it->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)ext; + if (drb->dl_pdcp_sn_len) { + asn1cSequenceAdd(ext->list, F1AP_DRBs_ToBeSetupMod_ItemExtIEs_t, ext_ie); + ext_ie->id = F1AP_ProtocolIE_ID_id_DLPDCPSNLength; + ext_ie->criticality = F1AP_Criticality_ignore; + ext_ie->extensionValue.present = F1AP_DRBs_ToBeSetupMod_ItemExtIEs__extensionValue_PR_PDCPSNLength; + ext_ie->extensionValue.choice.PDCPSNLength = *drb->dl_pdcp_sn_len; + } + + if (drb->ul_pdcp_sn_len) { + asn1cSequenceAdd(ext->list, F1AP_DRBs_ToBeSetupMod_ItemExtIEs_t, ext_ie); + ext_ie->id = F1AP_ProtocolIE_ID_id_ULPDCPSNLength; + ext_ie->criticality = F1AP_Criticality_ignore; + ext_ie->extensionValue.present = F1AP_DRBs_ToBeSetupMod_ItemExtIEs__extensionValue_PR_PDCPSNLength_1; + ext_ie->extensionValue.choice.PDCPSNLength_1 = *drb->ul_pdcp_sn_len; + } + } + return list; +} + +/* \brief Decode DRBS-ToBeSetup list from UE Context Setup request, into + * f1ap_drb_to_setup_t. */ +static bool decode_drbs_to_setup(const F1AP_DRBs_ToBeSetup_List_t *f1ap, int *n, f1ap_drb_to_setup_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_drb_to_setup_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs)); + for (int i = 0; i < count; ++i) { + const F1AP_DRBs_ToBeSetup_ItemIEs_t *itie = (const F1AP_DRBs_ToBeSetup_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_ToBeSetup_ItemIEs__value_PR_DRBs_ToBeSetup_Item); + const F1AP_DRBs_ToBeSetup_Item_t *it = &itie->value.choice.DRBs_ToBeSetup_Item; + + f1ap_drb_to_setup_t *drb = &drbs[i]; + drb->id = it->dRBID; + + _F1_EQ_CHECK_INT(it->qoSInformation.present, F1AP_QoSInformation_PR_choice_extension); + const F1AP_QoSInformation_ExtIEs_t *qos_ext = (F1AP_QoSInformation_ExtIEs_t *)it->qoSInformation.choice.choice_extension; + _F1_EQ_CHECK_LONG(qos_ext->id, F1AP_ProtocolIE_ID_id_DRB_Information); + _F1_EQ_CHECK_INT(qos_ext->value.present, F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information); + drb->qos_choice = F1AP_QOS_CHOICE_NR; + _F1_CHECK_EXP(decode_drb_info_nr(&qos_ext->value.choice.DRB_Information, &drb->nr)); + + drb->up_ul_tnl_len = it->uLUPTNLInformation_ToBeSetup_List.list.count; + _F1_EQ_CHECK_GENERIC(drb->up_ul_tnl_len > 0 && drb->up_ul_tnl_len <= 2, "%d", drb->up_ul_tnl_len, 1); + for (int j = 0; j < drb->up_ul_tnl_len; ++j) { + const F1AP_ULUPTNLInformation_ToBeSetup_Item_t *it_tnl = it->uLUPTNLInformation_ToBeSetup_List.list.array[j]; + _F1_CHECK_EXP(decode_up_tnl(&it_tnl->uLUPTNLInformation, &drb->up_ul_tnl[j])); + } + + _F1_CHECK_EXP(rlc_mode_from_asn1(it->rLCMode, &drb->rlc_mode)); + + _F1_CHECK_EXP(it->iE_Extensions); // PDCP SN length is under extension, is mandatory + const F1AP_ProtocolExtensionContainer_10696P82_t *ext = (const F1AP_ProtocolExtensionContainer_10696P82_t *)it->iE_Extensions; + const F1AP_DRBs_ToBeSetup_ItemExtIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_DRBs_ToBeSetup_ItemExtIEs_t, ie, &ext->list, F1AP_ProtocolIE_ID_id_DLPDCPSNLength, true); + + for (int j = 0; j < ext->list.count; ++j) { + ie = ext->list.array[j]; + AssertError(ie != NULL, return false, "ext->list.array[j] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_DLPDCPSNLength: + _F1_EQ_CHECK_INT(ie->extensionValue.present, F1AP_DRBs_ToBeSetup_ItemExtIEs__extensionValue_PR_PDCPSNLength); + _F1_MALLOC(drb->dl_pdcp_sn_len, ie->extensionValue.choice.PDCPSNLength); + break; + case F1AP_ProtocolIE_ID_id_ULPDCPSNLength: + _F1_EQ_CHECK_INT(ie->extensionValue.present, F1AP_DRBs_ToBeSetup_ItemExtIEs__extensionValue_PR_PDCPSNLength_1); + _F1_MALLOC(drb->ul_pdcp_sn_len, ie->extensionValue.choice.PDCPSNLength_1); + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + } + + return true; +} + +/* \brief Decode DRBS-ToBeSetupMod list from UE Context Modification Request, into + * f1ap_drb_to_setup_t. The ToBeSetup/ToBeSetupMod lists are almost the same + * (except for some optional types in the latter), so we reuse the internal + * representation, but the asn1c types are different. */ +static bool decode_drbs_to_setupmod(const F1AP_DRBs_ToBeSetupMod_List_t *f1ap, int *n, f1ap_drb_to_setup_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_drb_to_setup_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs)); + for (int i = 0; i < count; ++i) { + const F1AP_DRBs_ToBeSetupMod_ItemIEs_t *itie = (const F1AP_DRBs_ToBeSetupMod_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_ToBeSetupMod_ItemIEs__value_PR_DRBs_ToBeSetupMod_Item); + const F1AP_DRBs_ToBeSetupMod_Item_t *it = &itie->value.choice.DRBs_ToBeSetupMod_Item; + + f1ap_drb_to_setup_t *drb = &drbs[i]; + drb->id = it->dRBID; + + _F1_EQ_CHECK_INT(it->qoSInformation.present, F1AP_QoSInformation_PR_choice_extension); + const F1AP_QoSInformation_ExtIEs_t *qos_ext = (F1AP_QoSInformation_ExtIEs_t *)it->qoSInformation.choice.choice_extension; + _F1_EQ_CHECK_LONG(qos_ext->id, F1AP_ProtocolIE_ID_id_DRB_Information); + _F1_EQ_CHECK_INT(qos_ext->value.present, F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information); + drb->qos_choice = F1AP_QOS_CHOICE_NR; + _F1_CHECK_EXP(decode_drb_info_nr(&qos_ext->value.choice.DRB_Information, &drb->nr)); + + drb->up_ul_tnl_len = it->uLUPTNLInformation_ToBeSetup_List.list.count; + _F1_EQ_CHECK_GENERIC(drb->up_ul_tnl_len > 0 && drb->up_ul_tnl_len <= 2, "%d", drb->up_ul_tnl_len, 1); + for (int j = 0; j < drb->up_ul_tnl_len; ++j) { + const F1AP_ULUPTNLInformation_ToBeSetup_Item_t *it_tnl = it->uLUPTNLInformation_ToBeSetup_List.list.array[j]; + _F1_CHECK_EXP(decode_up_tnl(&it_tnl->uLUPTNLInformation, &drb->up_ul_tnl[j])); + } + + _F1_CHECK_EXP(rlc_mode_from_asn1(it->rLCMode, &drb->rlc_mode)); + + if (!it->iE_Extensions) + continue; + const F1AP_ProtocolExtensionContainer_10696P83_t *ext = (const F1AP_ProtocolExtensionContainer_10696P83_t *)it->iE_Extensions; + const F1AP_DRBs_ToBeSetupMod_ItemExtIEs_t *ie; + + for (int j = 0; j < ext->list.count; ++j) { + ie = ext->list.array[j]; + AssertError(ie != NULL, return false, "ext->list.array[j] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_DLPDCPSNLength: + _F1_EQ_CHECK_INT(ie->extensionValue.present, F1AP_DRBs_ToBeSetupMod_ItemExtIEs__extensionValue_PR_PDCPSNLength); + _F1_MALLOC(drb->dl_pdcp_sn_len, ie->extensionValue.choice.PDCPSNLength); + break; + case F1AP_ProtocolIE_ID_id_ULPDCPSNLength: + _F1_EQ_CHECK_INT(ie->extensionValue.present, F1AP_DRBs_ToBeSetupMod_ItemExtIEs__extensionValue_PR_PDCPSNLength_1); + _F1_MALLOC(drb->ul_pdcp_sn_len, ie->extensionValue.choice.PDCPSNLength_1); + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + } + + return true; +} + +static f1ap_drb_to_setup_t cp_drb_to_setup(const f1ap_drb_to_setup_t *orig) +{ + f1ap_drb_to_setup_t cp = { + .id = orig->id, + .qos_choice = orig->qos_choice, + // nr below + .up_ul_tnl_len = orig->up_ul_tnl_len, + .up_ul_tnl[0] = cp_up_tnl(&orig->up_ul_tnl[0]), + .up_ul_tnl[1] = cp_up_tnl(&orig->up_ul_tnl[1]), + .rlc_mode = orig->rlc_mode, + // dl_pdcp_sn_len below + // ul_pdcp_sn_len below + }; + AssertFatal(cp.qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS choice implemented\n"); + if (orig->qos_choice == F1AP_QOS_CHOICE_NR) + cp.nr = cp_drb_info_nr(&orig->nr); + if (orig->dl_pdcp_sn_len) { + _F1_MALLOC(cp.dl_pdcp_sn_len, *orig->dl_pdcp_sn_len); + } + if (orig->ul_pdcp_sn_len) { + _F1_MALLOC(cp.ul_pdcp_sn_len, *orig->ul_pdcp_sn_len); + } + return cp; +} + +static bool eq_drb_to_setup(const f1ap_drb_to_setup_t *a, const f1ap_drb_to_setup_t *b) +{ + _F1_EQ_CHECK_INT(a->id, b->id); + _F1_EQ_CHECK_INT(a->qos_choice, b->qos_choice); + AssertFatal(a->qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS choice implemented\n"); + if (a->qos_choice == F1AP_QOS_CHOICE_NR) + eq_drb_info_nr(&a->nr, &b->nr); + _F1_EQ_CHECK_INT(a->up_ul_tnl_len, b->up_ul_tnl_len); + for (int i = 0; i < a->up_ul_tnl_len; ++i) { + _F1_CHECK_EXP(eq_up_tnl(&a->up_ul_tnl[i], &b->up_ul_tnl[i])); + } + _F1_EQ_CHECK_INT(a->rlc_mode, b->rlc_mode); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, dl_pdcp_sn_len, _F1_EQ_CHECK_INT); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, ul_pdcp_sn_len, _F1_EQ_CHECK_INT); + return true; +} + +static void free_drb_to_setup(f1ap_drb_to_setup_t *drb) +{ + if (drb->qos_choice == F1AP_QOS_CHOICE_NR) + free_drb_info_nr(&drb->nr); + for (int i = 0; i < drb->up_ul_tnl_len; ++i) + free_up_tnl(&drb->up_ul_tnl[i]); + free(drb->dl_pdcp_sn_len); + free(drb->ul_pdcp_sn_len); +} + +static F1AP_DRBs_Setup_List_t encode_drbs_setup(int n, const f1ap_drb_setup_t *drbs) +{ + F1AP_DRBs_Setup_List_t list = {0}; + for (int i = 0; i < n; ++i) { + const f1ap_drb_setup_t *drb = &drbs[i]; + asn1cSequenceAdd(list, F1AP_DRBs_Setup_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_Item; + itie->criticality = F1AP_Criticality_ignore; + itie->value.present = F1AP_DRBs_Setup_ItemIEs__value_PR_DRBs_Setup_Item; + + F1AP_DRBs_Setup_Item_t *it = &itie->value.choice.DRBs_Setup_Item; + it->dRBID = drb->id; + if (drb->lcid) + asn1cCallocOne(it->lCID, *drb->lcid); + for (int j = 0; j < drb->up_dl_tnl_len; ++j) { + DevAssert(drb->up_dl_tnl[j].teid > 0); + asn1cSequenceAdd(it->dLUPTNLInformation_ToBeSetup_List.list, F1AP_DLUPTNLInformation_ToBeSetup_Item_t, tnl_it); + tnl_it->dLUPTNLInformation = encode_up_tnl(&drb->up_dl_tnl[j]); + } + } + return list; +} + +static F1AP_DRBs_SetupMod_List_t encode_drbs_setupmod(int n, const f1ap_drb_setup_t *drbs) +{ + F1AP_DRBs_SetupMod_List_t list = {0}; + for (int i = 0; i < n; ++i) { + const f1ap_drb_setup_t *drb = &drbs[i]; + asn1cSequenceAdd(list, F1AP_DRBs_SetupMod_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item; + itie->criticality = F1AP_Criticality_ignore; + itie->value.present = F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item; + + F1AP_DRBs_SetupMod_Item_t *it = &itie->value.choice.DRBs_SetupMod_Item; + it->dRBID = drb->id; + if (drb->lcid) + asn1cCallocOne(it->lCID, *drb->lcid); + for (int j = 0; j < drb->up_dl_tnl_len; ++j) { + DevAssert(drb->up_dl_tnl[j].teid > 0); + asn1cSequenceAdd(it->dLUPTNLInformation_ToBeSetup_List.list, F1AP_DLUPTNLInformation_ToBeSetup_Item_t, tnl_it); + tnl_it->dLUPTNLInformation = encode_up_tnl(&drb->up_dl_tnl[j]); + } + } + return list; +} + +static bool decode_drbs_setup(const F1AP_DRBs_Setup_List_t *f1ap, int *n, f1ap_drb_setup_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_drb_setup_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs)); + for (int i = 0; i < count; ++i) { + const F1AP_DRBs_Setup_ItemIEs_t *itie = (const F1AP_DRBs_Setup_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_Setup_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_Setup_ItemIEs__value_PR_DRBs_Setup_Item); + const F1AP_DRBs_Setup_Item_t *it = &itie->value.choice.DRBs_Setup_Item; + + f1ap_drb_setup_t *drb = &drbs[i]; + drb->id = it->dRBID; + if (it->lCID) + _F1_MALLOC(drb->lcid, *it->lCID); + + drb->up_dl_tnl_len = it->dLUPTNLInformation_ToBeSetup_List.list.count; + _F1_EQ_CHECK_GENERIC(drb->up_dl_tnl_len > 0 && drb->up_dl_tnl_len <= 2, "%d", drb->up_dl_tnl_len, 1); + for (int j = 0; j < drb->up_dl_tnl_len; ++j) { + F1AP_DLUPTNLInformation_ToBeSetup_Item_t *it_tnl = it->dLUPTNLInformation_ToBeSetup_List.list.array[j]; + _F1_CHECK_EXP(decode_up_tnl(&it_tnl->dLUPTNLInformation, &drb->up_dl_tnl[j])); + } + } + + return true; +} + +static bool decode_drbs_setupmod(const F1AP_DRBs_SetupMod_List_t *f1ap, int *n, f1ap_drb_setup_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_drb_setup_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs)); + for (int i = 0; i < count; ++i) { + const F1AP_DRBs_SetupMod_ItemIEs_t *itie = (const F1AP_DRBs_SetupMod_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item); + const F1AP_DRBs_SetupMod_Item_t *it = &itie->value.choice.DRBs_SetupMod_Item; + + f1ap_drb_setup_t *drb = &drbs[i]; + drb->id = it->dRBID; + if (it->lCID) + _F1_MALLOC(drb->lcid, *it->lCID); + + drb->up_dl_tnl_len = it->dLUPTNLInformation_ToBeSetup_List.list.count; + _F1_EQ_CHECK_GENERIC(drb->up_dl_tnl_len > 0 && drb->up_dl_tnl_len <= 2, "%d", drb->up_dl_tnl_len, 1); + for (int j = 0; j < drb->up_dl_tnl_len; ++j) { + F1AP_DLUPTNLInformation_ToBeSetup_Item_t *it_tnl = it->dLUPTNLInformation_ToBeSetup_List.list.array[j]; + _F1_CHECK_EXP(decode_up_tnl(&it_tnl->dLUPTNLInformation, &drb->up_dl_tnl[j])); + } + } + + return true; +} + +static f1ap_drb_setup_t cp_drb_setup(const f1ap_drb_setup_t *orig) +{ + f1ap_drb_setup_t cp = { + .id = orig->id, + .up_dl_tnl_len = orig->up_dl_tnl_len, + .up_dl_tnl[0] = cp_up_tnl(&orig->up_dl_tnl[0]), + .up_dl_tnl[1] = cp_up_tnl(&orig->up_dl_tnl[1]), + }; + if (orig->lcid) + _F1_MALLOC(cp.lcid, *orig->lcid); + return cp; +} + +static bool eq_drb_setup(const f1ap_drb_setup_t *a, const f1ap_drb_setup_t *b) +{ + _F1_EQ_CHECK_INT(a->id, b->id); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, lcid, _F1_EQ_CHECK_INT); + _F1_EQ_CHECK_INT(a->up_dl_tnl_len, b->up_dl_tnl_len); + for (int i = 0; i < a->up_dl_tnl_len; ++i) + _F1_CHECK_EXP(eq_up_tnl(&a->up_dl_tnl[i], &b->up_dl_tnl[i])); + return true; +} + +static void free_drb_setup(f1ap_drb_setup_t *drb) +{ + free(drb->lcid); +} + +static F1AP_DRBs_ToBeReleased_List_t encode_drbs_to_release(int n, const f1ap_drb_to_release_t *drbs) +{ + F1AP_DRBs_ToBeReleased_List_t list = {0}; + for (int i = 0; i < n; i++) { + asn1cSequenceAdd(list, F1AP_DRBs_ToBeReleased_ItemIEs_t, itie); + itie->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item; + itie->criticality = F1AP_Criticality_reject; + itie->value.present = F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item; + itie->value.choice.DRBs_ToBeReleased_Item.dRBID = drbs[i].id; + } + return list; +} + +static bool decode_drbs_to_release(const F1AP_DRBs_ToBeReleased_List_t *f1ap, int *n, f1ap_drb_to_release_t **out) +{ + DevAssert(out != NULL); + *out = NULL; + int count = *n = f1ap->list.count; + if (count == 0) + return true; + + f1ap_drb_to_release_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs)); + for (int i = 0; i < count; ++i) { + const F1AP_DRBs_ToBeReleased_ItemIEs_t *itie = (F1AP_DRBs_ToBeReleased_ItemIEs_t *)f1ap->list.array[i]; + _F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item); + _F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item); + drbs[i].id = itie->value.choice.DRBs_ToBeReleased_Item.dRBID; + } + + return true; +} + +static f1ap_drb_to_release_t cp_drb_to_release(const f1ap_drb_to_release_t *orig) +{ + f1ap_drb_to_release_t cp = { + .id = orig->id, + }; + return cp; +} + +static bool eq_drb_to_release(const f1ap_drb_to_release_t *a, const f1ap_drb_to_release_t *b) +{ + _F1_EQ_CHECK_INT(a->id, b->id); + return true; +} + +static void free_drb_to_release(f1ap_drb_to_release_t *drb) +{ + // nothing to free +} + +/** + * @brief Encode F1 UE context setup request to ASN.1 + */ +F1AP_F1AP_PDU_t *encode_ue_context_setup_req(const f1ap_ue_context_setup_req_t *req) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_UEContextSetup; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextSetupRequest; + F1AP_UEContextSetupRequest_t *out = &tmp->value.choice.UEContextSetupRequest; + + /* mandatory: GNB_CU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_UEContextSetupRequestIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = req->gNB_CU_ue_id; + + /* optional: GNB_DU_UE_F1AP_ID */ + if (req->gNB_DU_ue_id) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie); + ie->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie->criticality = F1AP_Criticality_ignore; + ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie->value.choice.GNB_DU_UE_F1AP_ID = *req->gNB_DU_ue_id; + } + + /* mandatory: SpCell ID/NRCGI */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_SpCell_ID; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_UEContextSetupRequestIEs__value_PR_NRCGI; + F1AP_NRCGI_t *nrcgi = &ie3->value.choice.NRCGI; + const plmn_id_t *plmn = &req->plmn; + MCC_MNC_TO_PLMNID(plmn->mcc,plmn->mnc,plmn->mnc_digit_length, &nrcgi->pLMN_Identity); + NR_CELL_ID_TO_BIT_STRING(req->nr_cellid, &nrcgi->nRCellIdentity); + + /* mandatory: ServCellIndox */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_ServCellIndex; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_UEContextSetupRequestIEs__value_PR_ServCellIndex; + ie4->value.choice.ServCellIndex = req->servCellIndex; + + /* mandatory: CUtoDURRCInformation */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie6); + ie6->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation; + ie6->criticality = F1AP_Criticality_reject; + ie6->value.present = F1AP_UEContextSetupRequestIEs__value_PR_CUtoDURRCInformation; + ie6->value.choice.CUtoDURRCInformation = encode_cu_to_du_rrc_info(&req->cu_to_du_rrc_info); + + /* optional: SRB to be setup list */ + if (req->srbs_len > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie); + ie->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List; + ie->criticality = F1AP_Criticality_reject; + ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_SRBs_ToBeSetup_List; + ie->value.choice.SRBs_ToBeSetup_List = encode_srbs_to_setup(req->srbs_len, req->srbs); + } + + /* optional: DRB to be setup list */ + if (req->drbs_len > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie); + ie->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List; + ie->criticality = F1AP_Criticality_reject; + ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List; + ie->value.choice.DRBs_ToBeSetup_List = encode_drbs_to_setup(req->drbs_len, req->drbs); + } + + /* optional: RRC container */ + if (req->rrc_container) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie); + ie->id = F1AP_ProtocolIE_ID_id_RRCContainer; + ie->criticality = F1AP_Criticality_ignore; + ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_RRCContainer; + OCTET_STRING_fromBuf(&ie->value.choice.RRCContainer, (const char *)req->rrc_container->buf, req->rrc_container->len); + } + + /* conditional if DRB setup list: gNB-DU UE Aggregate Maximum Bit Rate Uplink */ + if (req->gnb_du_ue_agg_mbr_ul) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie); + ie->id = F1AP_ProtocolIE_ID_id_GNB_DU_UE_AMBR_UL; + ie->criticality = F1AP_Criticality_ignore; + ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_BitRate; + asn_long2INTEGER(&ie->value.choice.BitRate, *req->gnb_du_ue_agg_mbr_ul); + } + + return pdu; +} + +/** + * @brief Decode F1 UE Context Setup Request + */ +bool decode_ue_context_setup_req(const F1AP_F1AP_PDU_t *pdu, f1ap_ue_context_setup_req_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + F1AP_UEContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.UEContextSetupRequest; + F1AP_UEContextSetupRequestIEs_t *ie; + + F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_SpCell_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_ServCellIndex, true); + F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_CUtoDURRCInformation, true); + + for (int i = 0; i < in->protocolIEs.list.count; ++i) { + ie = in->protocolIEs.list.array[i]; + AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_GNB_CU_UE_F1AP_ID); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_GNB_DU_UE_F1AP_ID); + _F1_MALLOC(out->gNB_DU_ue_id, ie->value.choice.GNB_DU_UE_F1AP_ID); + break; + case F1AP_ProtocolIE_ID_id_SpCell_ID: { + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_NRCGI); + const F1AP_NRCGI_t *nrcgi = &ie->value.choice.NRCGI; + PLMNID_TO_MCC_MNC(&nrcgi->pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length); + BIT_STRING_TO_NR_CELL_IDENTITY(&nrcgi->nRCellIdentity, out->nr_cellid); + } break; + case F1AP_ProtocolIE_ID_id_ServCellIndex: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_ServCellIndex); + out->servCellIndex = ie->value.choice.ServCellIndex; + break; + case F1AP_ProtocolIE_ID_id_CUtoDURRCInformation: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_CUtoDURRCInformation); + _F1_CHECK_EXP(decode_cu_to_du_rrc_info(&out->cu_to_du_rrc_info, &ie->value.choice.CUtoDURRCInformation)); + break; + case F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_SRBs_ToBeSetup_List); + _F1_CHECK_EXP(decode_srbs_to_setup(&ie->value.choice.SRBs_ToBeSetup_List, &out->srbs_len, &out->srbs)); + break; + case F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List); + { + // gNB-DU UE Aggregate Maximum Bit Rate Uplink is C-ifDRBSetup + // below, check that gNB-DU UE AMBR UL IE is present if we have DRB + // setup, as required by the spec, or return false otherwise (like in + // the beginning of the function) + F1AP_UEContextSetupRequestIEs_t *check_ie; + F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, check_ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_GNB_DU_UE_AMBR_UL, true); + } + _F1_CHECK_EXP(decode_drbs_to_setup(&ie->value.choice.DRBs_ToBeSetup_List, &out->drbs_len, &out->drbs)); + break; + case F1AP_ProtocolIE_ID_id_RRCContainer: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_RRCContainer); + out->rrc_container = malloc_or_fail(sizeof(*out->rrc_container)); + { + OCTET_STRING_t *os = &ie->value.choice.RRCContainer; + *out->rrc_container = create_byte_array(os->size, os->buf); + } + break; + case F1AP_ProtocolIE_ID_id_GNB_DU_UE_AMBR_UL: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_BitRate); + out->gnb_du_ue_agg_mbr_ul = malloc_or_fail(sizeof(*out->gnb_du_ue_agg_mbr_ul)); + asn_INTEGER2uint64(&ie->value.choice.BitRate, out->gnb_du_ue_agg_mbr_ul); + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief F1 UE Context Setup Request deep copy + */ +f1ap_ue_context_setup_req_t cp_ue_context_setup_req(const f1ap_ue_context_setup_req_t *orig) +{ + /* copy all mandatory fields that are not dynamic memory */ + f1ap_ue_context_setup_req_t cp = { + .gNB_CU_ue_id = orig->gNB_CU_ue_id, + .plmn = orig->plmn, + .nr_cellid = orig->nr_cellid, + .servCellIndex = orig->servCellIndex, + .cu_to_du_rrc_info = cp_cu_to_du_rrc_info(&orig->cu_to_du_rrc_info), + }; + if (orig->gNB_DU_ue_id) + _F1_MALLOC(cp.gNB_DU_ue_id, *orig->gNB_DU_ue_id); + if (orig->srbs_len > 0 && orig->srbs) { + cp.srbs = calloc_or_fail(orig->srbs_len, sizeof(*cp.srbs)); + cp.srbs_len = orig->srbs_len; + for (int i = 0; i < cp.srbs_len; ++i) + cp.srbs[i] = cp_srb_to_setup(&orig->srbs[i]); + } + if (orig->drbs_len > 0 && orig->drbs) { + cp.drbs = calloc_or_fail(orig->drbs_len, sizeof(*cp.drbs)); + cp.drbs_len = orig->drbs_len; + for (int i = 0; i < cp.drbs_len; ++i) + cp.drbs[i] = cp_drb_to_setup(&orig->drbs[i]); + } + CP_OPT_BYTE_ARRAY(cp.rrc_container, orig->rrc_container); + if (orig->gnb_du_ue_agg_mbr_ul) + _F1_MALLOC(cp.gnb_du_ue_agg_mbr_ul, *orig->gnb_du_ue_agg_mbr_ul); + return cp; +} + +/** + * @brief F1 UE Context Setup Request equality check + */ +bool eq_ue_context_setup_req(const f1ap_ue_context_setup_req_t *a, const f1ap_ue_context_setup_req_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, gNB_DU_ue_id, _F1_EQ_CHECK_INT); + _F1_CHECK_EXP(eq_f1ap_plmn(&a->plmn, &b->plmn)); + _F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid); + _F1_EQ_CHECK_INT(a->servCellIndex, b->servCellIndex); + _F1_CHECK_EXP(eq_cu_to_du_rrc_info(&a->cu_to_du_rrc_info, &b->cu_to_du_rrc_info)); + + _F1_EQ_CHECK_INT(a->srbs_len, b->srbs_len); + _F1_CHECK_EXP(a->srbs_len == 0 || (a->srbs && b->srbs)); + for (int i = 0; i < a->srbs_len; ++i) + _F1_CHECK_EXP(eq_srb_to_setup(&a->srbs[i], &b->srbs[i])); + + _F1_EQ_CHECK_INT(a->drbs_len, b->drbs_len); + _F1_CHECK_EXP(a->drbs_len == 0 || (a->drbs && b->drbs)); + for (int i = 0; i < a->drbs_len; ++i) + _F1_CHECK_EXP(eq_drb_to_setup(&a->drbs[i], &b->drbs[i])); + + _F1_EQ_CHECK_OPTIONAL_IE(a, b, rrc_container, eq_ba); + + _F1_EQ_CHECK_OPTIONAL_IE(a, b, gnb_du_ue_agg_mbr_ul, _F1_EQ_CHECK_LONG); + return true; +} + +/** + * @brief Free Allocated F1 UE Context Setup Request + */ +void free_ue_context_setup_req(f1ap_ue_context_setup_req_t *req) +{ + free(req->gNB_DU_ue_id); + free_cu_to_du_rrc_info(&req->cu_to_du_rrc_info); + for (int i = 0; i < req->srbs_len; ++i) + free_srb_to_setup(&req->srbs[i]); + free(req->srbs); + for (int i = 0; i < req->drbs_len; ++i) + free_drb_to_setup(&req->drbs[i]); + free(req->drbs); + FREE_OPT_BYTE_ARRAY(req->rrc_container); + free(req->gnb_du_ue_agg_mbr_ul); +} + +/** + * @brief Encode F1 UE context setup response to ASN.1 + */ +F1AP_F1AP_PDU_t *encode_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_UEContextSetup; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextSetupResponse; + F1AP_UEContextSetupResponse_t *out = &tmp->value.choice.UEContextSetupResponse; + + /* mandatory: GNB_CU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_UEContextSetupResponseIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id; + + /* mandatory: GNB_DU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_UEContextSetupResponseIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id; + + /* mandatory: DUtoCURRCInformation */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation; + ie3->value.choice.DUtoCURRCInformation = encode_du_to_cu_rrc_info(&msg->du_to_cu_rrc_info); + + /* optional: C-RNTI */ + if (msg->crnti) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_C_RNTI; + ie4->criticality = F1AP_Criticality_ignore; + ie4->value.present = F1AP_UEContextSetupResponseIEs__value_PR_C_RNTI; + ie4->value.choice.C_RNTI = *msg->crnti; + } + + /* optional: DRB Setup List */ + if (msg->drbs_len > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie7); + ie7->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_List; + ie7->criticality = F1AP_Criticality_ignore; + ie7->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DRBs_Setup_List; + ie7->value.choice.DRBs_Setup_List = encode_drbs_setup(msg->drbs_len, msg->drbs); + } + + /* optional: SRB Setup List */ + if (msg->srbs_len > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie11); + ie11->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_List; + ie11->criticality = F1AP_Criticality_ignore; + ie11->value.present = F1AP_UEContextSetupResponseIEs__value_PR_SRBs_Setup_List; + ie11->value.choice.SRBs_Setup_List = encode_srbs_setup(msg->srbs_len, msg->srbs); + } + + return pdu; +} + +/** + * @brief Decode F1 UE Context Setup Response + */ +bool decode_ue_context_setup_resp(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_setup_resp_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + F1AP_UEContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.UEContextSetupResponse; + F1AP_UEContextSetupResponseIEs_t *ie; + + F1AP_LIB_FIND_IE(F1AP_UEContextSetupResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextSetupResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextSetupResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, true); + + for (int i = 0; i < in->protocolIEs.list.count; ++i) { + ie = in->protocolIEs.list.array[i]; + AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_GNB_CU_UE_F1AP_ID); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_GNB_DU_UE_F1AP_ID); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_DUtoCURRCInformation: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation); + _F1_CHECK_EXP(decode_du_to_cu_rrc_info(&out->du_to_cu_rrc_info, &ie->value.choice.DUtoCURRCInformation)); + break; + case F1AP_ProtocolIE_ID_id_C_RNTI: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_C_RNTI); + _F1_MALLOC(out->crnti, ie->value.choice.C_RNTI); + break; + case F1AP_ProtocolIE_ID_id_DRBs_Setup_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_DRBs_Setup_List); + _F1_CHECK_EXP(decode_drbs_setup(&ie->value.choice.DRBs_Setup_List, &out->drbs_len, &out->drbs)); + break; + case F1AP_ProtocolIE_ID_id_SRBs_Setup_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_SRBs_Setup_List); + _F1_CHECK_EXP(decode_srbs_setup(&ie->value.choice.SRBs_Setup_List, &out->srbs_len, &out->srbs)); + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief F1 UE Context Setup Response deep copy + */ +f1ap_ue_context_setup_resp_t cp_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *orig) +{ + f1ap_ue_context_setup_resp_t cp = { + .gNB_CU_ue_id = orig->gNB_CU_ue_id, + .gNB_DU_ue_id = orig->gNB_DU_ue_id, + .du_to_cu_rrc_info = cp_du_to_cu_rrc_info(&orig->du_to_cu_rrc_info), + // crnti below + .drbs_len = orig->drbs_len, + // drbs below + .srbs_len = orig->srbs_len, + // srbs below + }; + if (orig->crnti) + _F1_MALLOC(cp.crnti, *orig->crnti); + if (orig->drbs_len > 0 && orig->drbs) { + cp.drbs = calloc_or_fail(orig->drbs_len, sizeof(*cp.drbs)); + cp.drbs_len = orig->drbs_len; + for (int i = 0; i < cp.drbs_len; ++i) + cp.drbs[i] = cp_drb_setup(&orig->drbs[i]); + } + if (orig->srbs_len > 0 && orig->srbs) { + cp.srbs = calloc_or_fail(orig->srbs_len, sizeof(*cp.srbs)); + cp.srbs_len = orig->srbs_len; + for (int i = 0; i < cp.srbs_len; ++i) + cp.srbs[i] = cp_srb_setup(&orig->srbs[i]); + } + return cp; +} + +/** + * @brief F1 UE Context Setup Response equality check + */ +bool eq_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *a, const f1ap_ue_context_setup_resp_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + _F1_CHECK_EXP(eq_du_to_cu_rrc_info(&a->du_to_cu_rrc_info, &b->du_to_cu_rrc_info)); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, crnti, _F1_EQ_CHECK_INT); + + _F1_EQ_CHECK_INT(a->drbs_len, b->drbs_len); + _F1_CHECK_EXP(a->drbs_len == 0 || (a->drbs && b->drbs)); + for (int i = 0; i < a->drbs_len; ++i) + _F1_CHECK_EXP(eq_drb_setup(&a->drbs[i], &b->drbs[i])); + + _F1_EQ_CHECK_INT(a->srbs_len, b->srbs_len); + _F1_CHECK_EXP(a->srbs_len == 0 || (a->srbs && b->srbs)); + for (int i = 0; i < a->srbs_len; ++i) + _F1_CHECK_EXP(eq_srb_setup(&a->srbs[i], &b->srbs[i])); + + return true; +} + +/** + * @brief Free Allocated F1 UE Context Setup Response + */ +void free_ue_context_setup_resp(f1ap_ue_context_setup_resp_t *resp) +{ + free_du_to_cu_rrc_info(&resp->du_to_cu_rrc_info); + free(resp->crnti); + for (int i = 0; i < resp->drbs_len; ++i) + free_drb_setup(&resp->drbs[i]); + free(resp->drbs); + for (int i = 0; i < resp->srbs_len; ++i) + free_srb_setup(&resp->srbs[i]); + free(resp->srbs); +} + +/** + * @brief Encode F1 UE context modification request to ASN.1 + */ +F1AP_F1AP_PDU_t *encode_ue_context_mod_req(const f1ap_ue_context_mod_req_t *req) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_UEContextModification; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextModificationRequest; + F1AP_UEContextModificationRequest_t *out = &tmp->value.choice.UEContextModificationRequest; + + /* mandatory: GNB_CU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_UEContextModificationRequestIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = req->gNB_CU_ue_id; + + /* mandatory: GNB_DU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_UEContextModificationRequestIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie2->value.choice.GNB_DU_UE_F1AP_ID = req->gNB_DU_ue_id; + + /* optional: SpCellID/NRCGI */ + if (req->plmn) { + DevAssert(req->nr_cellid); + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_SpCell_ID; + ie3->criticality = F1AP_Criticality_ignore; + ie3->value.present = F1AP_UEContextModificationRequestIEs__value_PR_NRCGI; + F1AP_NRCGI_t *nrcgi = &ie3->value.choice.NRCGI; + const plmn_id_t *plmn = req->plmn; + MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &nrcgi->pLMN_Identity); + NR_CELL_ID_TO_BIT_STRING(*req->nr_cellid, &nrcgi->nRCellIdentity); + } + + /* optional: ServCellIndex */ + if (req->servCellIndex) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_ServCellIndex; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_UEContextModificationRequestIEs__value_PR_ServCellIndex; + ie4->value.choice.ServCellIndex = *req->servCellIndex; + } + + /* optional: CUtoDURRCInformation */ + if (req->cu_to_du_rrc_info) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie6); + ie6->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation; + ie6->criticality = F1AP_Criticality_reject; + ie6->value.present = F1AP_UEContextModificationRequestIEs__value_PR_CUtoDURRCInformation; + ie6->value.choice.CUtoDURRCInformation = encode_cu_to_du_rrc_info(req->cu_to_du_rrc_info); + } + + /* optional: TransmissionActionIndicator */ + if (req->transm_action_ind) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie7); + ie7->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator; + ie7->criticality = F1AP_Criticality_ignore; + ie7->value.present = F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator; + ie7->value.choice.TransmissionActionIndicator = *req->transm_action_ind; + // Stop is guaranteed to be 0, by restart might be different from 1 + static_assert((int)F1AP_TransmissionActionIndicator_restart == (int)TransmActionInd_RESTART, + "mismatch of ASN.1 and internal representation\n"); + } + + /* optional: RRCRconfigurationCompleteIndicator */ + if (req->reconfig_compl) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie71); + ie71->id = F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator; + ie71->criticality = F1AP_Criticality_ignore; + ie71->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCReconfigurationCompleteIndicator; + ie71->value.choice.RRCReconfigurationCompleteIndicator = *req->reconfig_compl == RRCreconf_success + ? F1AP_RRCReconfigurationCompleteIndicator_true + : F1AP_RRCReconfigurationCompleteIndicator_failure; + } + + /* optional: RRC container */ + if (req->rrc_container) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie81); + ie81->id = F1AP_ProtocolIE_ID_id_RRCContainer; + ie81->criticality = F1AP_Criticality_ignore; + ie81->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer; + OCTET_STRING_fromBuf(&ie81->value.choice.RRCContainer, (const char *)req->rrc_container->buf, req->rrc_container->len); + } + + /* optional: SRBs_ToBeSetupMod */ + if (req->srbs_len > 0) { + DevAssert(req->srbs); + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie11); + ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List; + ie11->criticality = F1AP_Criticality_reject; + ie11->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeSetupMod_List; + ie11->value.choice.SRBs_ToBeSetupMod_List = encode_srbs_to_setupmod(req->srbs_len, req->srbs); + } + + /* optional: DRBs_ToBeSetupMod */ + if (req->drbs_len > 0) { + DevAssert(req->drbs); + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie12); + ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List; + ie12->criticality = F1AP_Criticality_reject; + ie12->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List; + ie12->value.choice.DRBs_ToBeSetupMod_List = encode_drbs_to_setupmod(req->drbs_len, req->drbs); + } + + /* optional: DRBs_ToBeReleased */ + if (req->drbs_rel_len > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie15); + ie15->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List; + ie15->criticality = F1AP_Criticality_reject; + ie15->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List; + ie15->value.choice.DRBs_ToBeReleased_List = encode_drbs_to_release(req->drbs_rel_len, req->drbs_rel); + } + + /* optional: Lower Layer Presence Status Change */ + if (req->status) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie17); + ie17->id = F1AP_ProtocolIE_ID_id_LowerLayerPresenceStatusChange; + ie17->criticality = F1AP_Criticality_ignore; + ie17->value.present = F1AP_UEContextModificationRequestIEs__value_PR_LowerLayerPresenceStatusChange; + ie17->value.choice.LowerLayerPresenceStatusChange = *req->status == LOWER_LAYERS_SUSPEND + ? F1AP_LowerLayerPresenceStatusChange_suspend_lower_layers + : F1AP_LowerLayerPresenceStatusChange_resume_lower_layers; + } + return pdu; +} + +/** + * @brief Decode F1 UE Context Modification Request + */ +bool decode_ue_context_mod_req(const F1AP_F1AP_PDU_t *pdu, f1ap_ue_context_mod_req_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + F1AP_UEContextModificationRequest_t *in = &pdu->choice.initiatingMessage->value.choice.UEContextModificationRequest; + F1AP_UEContextModificationRequestIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_UEContextModificationRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextModificationRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + + for (int i = 0; i < in->protocolIEs.list.count; ++i) { + ie = in->protocolIEs.list.array[i]; + AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_GNB_CU_UE_F1AP_ID); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_GNB_DU_UE_F1AP_ID); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_SpCell_ID: { + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_NRCGI); + const F1AP_NRCGI_t *nrcgi = &ie->value.choice.NRCGI; + out->plmn = malloc_or_fail(sizeof(*out->plmn)); + PLMNID_TO_MCC_MNC(&nrcgi->pLMN_Identity, out->plmn->mcc, out->plmn->mnc, out->plmn->mnc_digit_length); + out->nr_cellid = malloc_or_fail(sizeof(*out->nr_cellid)); + BIT_STRING_TO_NR_CELL_IDENTITY(&nrcgi->nRCellIdentity, *out->nr_cellid); + } break; + case F1AP_ProtocolIE_ID_id_ServCellIndex: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_ServCellIndex); + _F1_MALLOC(out->servCellIndex, ie->value.choice.ServCellIndex); + break; + case F1AP_ProtocolIE_ID_id_CUtoDURRCInformation: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_CUtoDURRCInformation); + out->cu_to_du_rrc_info = calloc(1, sizeof(*out->cu_to_du_rrc_info)); + _F1_CHECK_EXP(decode_cu_to_du_rrc_info(out->cu_to_du_rrc_info, &ie->value.choice.CUtoDURRCInformation)); + break; + case F1AP_ProtocolIE_ID_id_TransmissionActionIndicator: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator); + { + TransmActionInd_t v = ie->value.choice.TransmissionActionIndicator == F1AP_TransmissionActionIndicator_stop + ? TransmActionInd_STOP + : TransmActionInd_RESTART; + _F1_MALLOC(out->transm_action_ind, v); + } + break; + case F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_RRCReconfigurationCompleteIndicator); + { + ReconfigurationCompl_t v = + ie->value.choice.RRCReconfigurationCompleteIndicator == F1AP_RRCReconfigurationCompleteIndicator_true + ? RRCreconf_success + : RRCreconf_failure; + _F1_MALLOC(out->reconfig_compl, v); + } + break; + case F1AP_ProtocolIE_ID_id_RRCContainer: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer); + out->rrc_container = malloc_or_fail(sizeof(*out->rrc_container)); + { + OCTET_STRING_t *os = &ie->value.choice.RRCContainer; + *out->rrc_container = create_byte_array(os->size, os->buf); + } + break; + case F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeSetupMod_List); + _F1_CHECK_EXP(decode_srbs_to_setupmod(&ie->value.choice.SRBs_ToBeSetupMod_List, &out->srbs_len, &out->srbs)); + break; + case F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List); + _F1_CHECK_EXP(decode_drbs_to_setupmod(&ie->value.choice.DRBs_ToBeSetupMod_List, &out->drbs_len, &out->drbs)); + break; + case F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List); + _F1_CHECK_EXP(decode_drbs_to_release(&ie->value.choice.DRBs_ToBeReleased_List, &out->drbs_rel_len, &out->drbs_rel)); + break; + case F1AP_ProtocolIE_ID_id_LowerLayerPresenceStatusChange: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_LowerLayerPresenceStatusChange); + { + lower_layer_status_t v = ie->value.choice.LowerLayerPresenceStatusChange == F1AP_LowerLayerPresenceStatusChange_suspend_lower_layers + ? LOWER_LAYERS_SUSPEND : LOWER_LAYERS_RESUME; + _F1_MALLOC(out->status, v); + } + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief F1 UE Context Modification Request deep copy + */ +f1ap_ue_context_mod_req_t cp_ue_context_mod_req(const f1ap_ue_context_mod_req_t *orig) +{ + f1ap_ue_context_mod_req_t cp = { + .gNB_CU_ue_id = orig->gNB_CU_ue_id, + .gNB_DU_ue_id = orig->gNB_DU_ue_id, + // .plmn, .nr_cellid, .servCellIndex below + // .cu_to_du_rrc_info below + // .transm_action_ind below + // .reconfig_compl below + // .rrc_container below + .srbs_len = orig->srbs_len, + // .srbs below + .drbs_len = orig->drbs_len, + // .drbs below + // .status below + }; + + if (orig->plmn) + _F1_MALLOC(cp.plmn, *orig->plmn); + if (orig->nr_cellid) + _F1_MALLOC(cp.nr_cellid, *orig->nr_cellid); + if (orig->servCellIndex) + _F1_MALLOC(cp.servCellIndex, *orig->servCellIndex); + if (orig->cu_to_du_rrc_info) + _F1_MALLOC(cp.cu_to_du_rrc_info, cp_cu_to_du_rrc_info(orig->cu_to_du_rrc_info)); + if (orig->transm_action_ind) + _F1_MALLOC(cp.transm_action_ind, *orig->transm_action_ind); + if (orig->reconfig_compl) + _F1_MALLOC(cp.reconfig_compl, *orig->reconfig_compl); + CP_OPT_BYTE_ARRAY(cp.rrc_container, orig->rrc_container); + if (orig->srbs_len > 0) { + DevAssert(orig->srbs); + cp.srbs = calloc_or_fail(orig->srbs_len, sizeof(*cp.srbs)); + cp.srbs_len = orig->srbs_len; + for (int i = 0; i < cp.srbs_len; ++i) + cp.srbs[i] = cp_srb_to_setup(&orig->srbs[i]); + } + if (orig->drbs_len > 0) { + DevAssert(orig->drbs); + cp.drbs = calloc_or_fail(orig->drbs_len, sizeof(*cp.drbs)); + cp.drbs_len = orig->drbs_len; + for (int i = 0; i < cp.drbs_len; ++i) + cp.drbs[i] = cp_drb_to_setup(&orig->drbs[i]); + } + if (orig->drbs_rel_len > 0) { + DevAssert(orig->drbs_rel); + cp.drbs_rel = calloc_or_fail(orig->drbs_rel_len, sizeof(*cp.drbs_rel)); + cp.drbs_rel_len = orig->drbs_rel_len; + for (int i = 0; i < cp.drbs_rel_len; ++i) + cp.drbs_rel[i] = cp_drb_to_release(&orig->drbs_rel[i]); + } + if (orig->status) + _F1_MALLOC(cp.status, *orig->status); + return cp; +} + +/** + * @brief F1 UE Context Modification Request equality check + */ +bool eq_ue_context_mod_req(const f1ap_ue_context_mod_req_t *a, const f1ap_ue_context_mod_req_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + _F1_CHECK_EXP((a->plmn && b->plmn) || (!a->plmn && !b->plmn)); + _F1_CHECK_EXP(!a->plmn || eq_f1ap_plmn(a->plmn, b->plmn)); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, nr_cellid, _F1_EQ_CHECK_LONG); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, servCellIndex, _F1_EQ_CHECK_INT); + _F1_CHECK_EXP((a->cu_to_du_rrc_info && b->cu_to_du_rrc_info) || (!a->cu_to_du_rrc_info && !b->cu_to_du_rrc_info)); + _F1_CHECK_EXP(!a->cu_to_du_rrc_info || eq_cu_to_du_rrc_info(a->cu_to_du_rrc_info, b->cu_to_du_rrc_info)); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, transm_action_ind, _F1_EQ_CHECK_INT); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, reconfig_compl, _F1_EQ_CHECK_INT); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, rrc_container, eq_ba); + + _F1_EQ_CHECK_INT(a->srbs_len, b->srbs_len); + _F1_CHECK_EXP(a->srbs_len == 0 || (a->srbs && b->srbs)); + for (int i = 0; i < a->srbs_len; ++i) + _F1_CHECK_EXP(eq_srb_to_setup(&a->srbs[i], &b->srbs[i])); + + _F1_EQ_CHECK_INT(a->drbs_len, b->drbs_len); + _F1_CHECK_EXP(a->drbs_len == 0 || (a->drbs && b->drbs)); + for (int i = 0; i < a->drbs_len; ++i) + _F1_CHECK_EXP(eq_drb_to_setup(&a->drbs[i], &b->drbs[i])); + + _F1_EQ_CHECK_INT(a->drbs_rel_len, b->drbs_rel_len); + _F1_CHECK_EXP(a->drbs_rel_len == 0 || (a->drbs_rel_len && b->drbs_rel_len)); + for (int i = 0; i < a->drbs_rel_len; ++i) + _F1_CHECK_EXP(eq_drb_to_release(&a->drbs_rel[i], &b->drbs_rel[i])); + + _F1_EQ_CHECK_OPTIONAL_IE(a, b, status, _F1_EQ_CHECK_INT); + return true; +} + +/** + * @brief Free Allocated F1 UE Context Modification Request + */ +void free_ue_context_mod_req(f1ap_ue_context_mod_req_t *req) +{ + free(req->plmn); + free(req->nr_cellid); + free(req->servCellIndex); + if (req->cu_to_du_rrc_info) + free_cu_to_du_rrc_info(req->cu_to_du_rrc_info); + free(req->cu_to_du_rrc_info); + free(req->transm_action_ind); + free(req->reconfig_compl); + FREE_OPT_BYTE_ARRAY(req->rrc_container); + for (int i = 0; i < req->srbs_len; ++i) + free_srb_to_setup(&req->srbs[i]); + free(req->srbs); + for (int i = 0; i < req->drbs_len; ++i) + free_drb_to_setup(&req->drbs[i]); + free(req->drbs); + for (int i = 0; i < req->drbs_rel_len; ++i) + free_drb_to_release(&req->drbs_rel[i]); + free(req->drbs_rel); + free(req->status); +} + +/** + * @brief Encode F1 UE context modification response to ASN.1 + */ +F1AP_F1AP_PDU_t *encode_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_UEContextModification; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextModificationResponse; + F1AP_UEContextModificationResponse_t *out = &tmp->value.choice.UEContextModificationResponse; + + /* mandatory: GNB_CU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_UEContextModificationResponseIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id; + + /* mandatory: GNB_DU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_UEContextModificationResponseIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id; + + /* optional: DUtoCURRCInformation */ + if (msg->du_to_cu_rrc_info != NULL) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DUtoCURRCInformation; + ie4->value.choice.DUtoCURRCInformation = encode_du_to_cu_rrc_info(msg->du_to_cu_rrc_info); + } + + /* optional: DRBs_Setup_List */ + if (msg->drbs_len > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie5); + ie5->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List; + ie5->criticality = F1AP_Criticality_ignore; + ie5->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_SetupMod_List; + ie5->value.choice.DRBs_SetupMod_List = encode_drbs_setupmod(msg->drbs_len, msg->drbs); + } + + if (msg->srbs_len > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie12); + ie12->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List; + ie12->criticality = F1AP_Criticality_ignore; + ie12->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_SetupMod_List; + ie12->value.choice.SRBs_SetupMod_List = encode_srbs_setupmod(msg->srbs_len, msg->srbs); + } + + return pdu; +} + +/** + * @brief Decode F1 UE Context modification Response + */ +bool decode_ue_context_mod_resp(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_mod_resp_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + F1AP_UEContextModificationResponse_t *in = &pdu->choice.successfulOutcome->value.choice.UEContextModificationResponse; + F1AP_UEContextModificationResponseIEs_t *ie; + + F1AP_LIB_FIND_IE(F1AP_UEContextModificationResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextModificationResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + + for (int i = 0; i < in->protocolIEs.list.count; ++i) { + ie = in->protocolIEs.list.array[i]; + AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_GNB_CU_UE_F1AP_ID); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_GNB_DU_UE_F1AP_ID); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_DUtoCURRCInformation: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_DUtoCURRCInformation); + out->du_to_cu_rrc_info = calloc(1, sizeof(*out->du_to_cu_rrc_info)); + _F1_CHECK_EXP(decode_du_to_cu_rrc_info(out->du_to_cu_rrc_info, &ie->value.choice.DUtoCURRCInformation)); + break; + case F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_DRBs_SetupMod_List); + _F1_CHECK_EXP(decode_drbs_setupmod(&ie->value.choice.DRBs_SetupMod_List, &out->drbs_len, &out->drbs)); + break; + case F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_SRBs_SetupMod_List); + _F1_CHECK_EXP(decode_srbs_setupmod(&ie->value.choice.SRBs_SetupMod_List, &out->srbs_len, &out->srbs)); + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief F1 UE Context modification Response deep copy + */ +f1ap_ue_context_mod_resp_t cp_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *orig) +{ + f1ap_ue_context_mod_resp_t cp = { + .gNB_CU_ue_id = orig->gNB_CU_ue_id, + .gNB_DU_ue_id = orig->gNB_DU_ue_id, + // du_to_cu_rrc_info + .drbs_len = orig->drbs_len, + // drbs below + .srbs_len = orig->srbs_len, + // srbs below + }; + + if (orig->du_to_cu_rrc_info) { + f1ap_du_to_cu_rrc_info_t du2cu = cp_du_to_cu_rrc_info(orig->du_to_cu_rrc_info); + _F1_MALLOC(cp.du_to_cu_rrc_info, du2cu); + } + + if (orig->drbs_len > 0) { + DevAssert(orig->drbs); + cp.drbs = calloc_or_fail(orig->drbs_len, sizeof(*cp.drbs)); + cp.drbs_len = orig->drbs_len; + for (int i = 0; i < cp.drbs_len; ++i) + cp.drbs[i] = cp_drb_setup(&orig->drbs[i]); + } + + if (orig->srbs_len > 0) { + DevAssert(orig->srbs); + cp.srbs = calloc_or_fail(orig->srbs_len, sizeof(*cp.srbs)); + cp.srbs_len = orig->srbs_len; + for (int i = 0; i < cp.srbs_len; ++i) + cp.srbs[i] = cp_srb_setup(&orig->srbs[i]); + } + + return cp; +} + +/** + * @brief F1 UE Context modification Response equality check + */ +bool eq_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *a, const f1ap_ue_context_mod_resp_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + //_F1_EQ_CHECK_OPTIONAL_IE(a, b, du_to_cu_rrc_info, eq_du_to_cu_rrc_info); + _F1_CHECK_EXP((a->du_to_cu_rrc_info && b->du_to_cu_rrc_info) || (!a->du_to_cu_rrc_info && !b->du_to_cu_rrc_info)); + _F1_CHECK_EXP(!a->du_to_cu_rrc_info || eq_du_to_cu_rrc_info(a->du_to_cu_rrc_info, b->du_to_cu_rrc_info)); + + _F1_CHECK_EXP(a->drbs_len == 0 || (a->drbs && b->drbs)); + for (int i = 0; i < a->drbs_len; ++i) + _F1_CHECK_EXP(eq_drb_setup(&a->drbs[i], &b->drbs[i])); + + _F1_EQ_CHECK_INT(a->srbs_len, b->srbs_len); + _F1_CHECK_EXP(a->srbs_len == 0 || (a->srbs && b->srbs)); + for (int i = 0; i < a->srbs_len; ++i) + _F1_CHECK_EXP(eq_srb_setup(&a->srbs[i], &b->srbs[i])); + + return true; +} + +/** + * @brief Free Allocated F1 UE Context modification Response + */ +void free_ue_context_mod_resp(f1ap_ue_context_mod_resp_t *resp) +{ + if (resp->du_to_cu_rrc_info) + free_du_to_cu_rrc_info(resp->du_to_cu_rrc_info); + free(resp->du_to_cu_rrc_info); + for (int i = 0; i < resp->drbs_len; ++i) + free_drb_setup(&resp->drbs[i]); + free(resp->drbs); + for (int i = 0; i < resp->srbs_len; ++i) + free_srb_setup(&resp->srbs[i]); + free(resp->srbs); +} + +/* + * @brief Encode F1 UE context release request to ASN.1 + */ +struct F1AP_F1AP_PDU *encode_ue_context_rel_req(const f1ap_ue_context_rel_req_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_UEContextReleaseRequest; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextReleaseRequest; + F1AP_UEContextReleaseRequest_t *out = &tmp->value.choice.UEContextReleaseRequest; + + /* mandatory: GNB_CU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id; + + /* mandatory: GNB_DU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id; + + /* mandatory: Cause */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_Cause; + ie3->criticality = F1AP_Criticality_ignore; + ie3->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_Cause; + ie3->value.choice.Cause = encode_f1ap_cause(msg->cause, msg->cause_value); + + return pdu; +} + +/** + * @brief Decode F1 UE Context Release Request + */ +bool decode_ue_context_rel_req(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_req_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + F1AP_UEContextReleaseRequest_t *in = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseRequest; + F1AP_UEContextReleaseRequestIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_Cause, true); + + for (int i = 0; i < in->protocolIEs.list.count; ++i) { + ie = in->protocolIEs.list.array[i]; + AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseRequestIEs__value_PR_GNB_CU_UE_F1AP_ID); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseRequestIEs__value_PR_GNB_DU_UE_F1AP_ID); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_Cause: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseRequestIEs__value_PR_Cause); + _F1_CHECK_EXP(decode_f1ap_cause(ie->value.choice.Cause, &out->cause, &out->cause_value)); + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief F1 UE Context Release Request deep copy + */ +f1ap_ue_context_rel_req_t cp_ue_context_rel_req(const f1ap_ue_context_rel_req_t *orig) +{ + f1ap_ue_context_rel_req_t cp = { + .gNB_CU_ue_id = orig->gNB_CU_ue_id, + .gNB_DU_ue_id = orig->gNB_DU_ue_id, + .cause = orig->cause, + .cause_value = orig->cause_value, + }; + return cp; +} + +/** + * @brief F1 UE Context Release Request equality check + */ +bool eq_ue_context_rel_req(const f1ap_ue_context_rel_req_t *a, const f1ap_ue_context_rel_req_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + _F1_EQ_CHECK_INT(a->cause, b->cause); + _F1_EQ_CHECK_LONG(a->cause_value, b->cause_value); + return true; +} + +/** + * @brief Free Allocated F1 UE Context Release Request + */ +void free_ue_context_rel_req(f1ap_ue_context_rel_req_t *req) +{ + // nothing to free +} + +/* + * @brief Encode F1 UE context release command to ASN.1 + */ +struct F1AP_F1AP_PDU *encode_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *cmd) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_UEContextRelease; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextReleaseCommand; + F1AP_UEContextReleaseCommand_t *out = &tmp->value.choice.UEContextReleaseCommand; + + /* mandatory: GNB_CU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = cmd->gNB_CU_ue_id; + + /* mandatory: GNB_DU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie2->value.choice.GNB_DU_UE_F1AP_ID = cmd->gNB_DU_ue_id; + + /* mandatory: Cause */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_Cause; + ie3->criticality = F1AP_Criticality_ignore; + ie3->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_Cause; + ie3->value.choice.Cause = encode_f1ap_cause(cmd->cause, cmd->cause_value); + + /* optional: RRC Container */ + if (cmd->rrc_container != NULL) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer; + ie4->criticality = F1AP_Criticality_ignore; + ie4->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_RRCContainer; + const byte_array_t *ba = cmd->rrc_container; + OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, (const char *)ba->buf, ba->len); + + // conditionally have SRBID if RRC Container + AssertFatal(cmd->srb_id != NULL, "UEContextReleaseCommand SRB-ID C-ifRRCContainer violated\n"); + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie5); + ie5->id = F1AP_ProtocolIE_ID_id_SRBID; + ie5->criticality = F1AP_Criticality_ignore; + ie5->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_SRBID; + ie5->value.choice.SRBID = *cmd->srb_id; + } + + if (cmd->old_gNB_DU_ue_id != NULL) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie5); + ie5->id = F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID; + ie5->criticality = F1AP_Criticality_ignore; + ie5->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID_1; + ie5->value.choice.GNB_DU_UE_F1AP_ID_1 = *cmd->old_gNB_DU_ue_id; + } + + return pdu; +} + +/** + * @brief Decode F1 UE Context Release Command + */ +bool decode_ue_context_rel_cmd(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_cmd_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + F1AP_UEContextReleaseCommand_t *in = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseCommand; + F1AP_UEContextReleaseCommandIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCommandIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCommandIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCommandIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_Cause, true); + + for (int i = 0; i < in->protocolIEs.list.count; ++i) { + ie = in->protocolIEs.list.array[i]; + AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_GNB_CU_UE_F1AP_ID); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_Cause: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_Cause); + _F1_CHECK_EXP(decode_f1ap_cause(ie->value.choice.Cause, &out->cause, &out->cause_value)); + break; + case F1AP_ProtocolIE_ID_id_RRCContainer: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_RRCContainer); + out->rrc_container = malloc_or_fail(sizeof(*out->rrc_container)); + { + OCTET_STRING_t *os = &ie->value.choice.RRCContainer; + *out->rrc_container = create_byte_array(os->size, os->buf); + } + break; + case F1AP_ProtocolIE_ID_id_SRBID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_SRBID); + { + // SRB-ID + F1AP_UEContextReleaseCommandIEs_t *check_ie; + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCommandIEs_t, check_ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_RRCContainer, true); + } + _F1_MALLOC(out->srb_id, ie->value.choice.SRBID); + break; + case F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID_1); + _F1_MALLOC(out->old_gNB_DU_ue_id, ie->value.choice.GNB_DU_UE_F1AP_ID_1); + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief F1 UE Context Release Command deep copy + */ +f1ap_ue_context_rel_cmd_t cp_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *orig) +{ + f1ap_ue_context_rel_cmd_t cp = { + .gNB_CU_ue_id = orig->gNB_CU_ue_id, + .gNB_DU_ue_id = orig->gNB_DU_ue_id, + .cause = orig->cause, + .cause_value = orig->cause_value, + }; + CP_OPT_BYTE_ARRAY(cp.rrc_container, orig->rrc_container); + if (orig->rrc_container) { + AssertFatal(orig->srb_id != NULL, "UEContextReleaseCommand SRB-ID C-ifRRCContainer violated\n"); + _F1_MALLOC(cp.srb_id, *orig->srb_id); + } + if (orig->old_gNB_DU_ue_id) + _F1_MALLOC(cp.old_gNB_DU_ue_id, *orig->old_gNB_DU_ue_id); + return cp; +} + +/** + * @brief F1 UE Context Release Command equality check + */ +bool eq_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *a, const f1ap_ue_context_rel_cmd_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + _F1_EQ_CHECK_INT(a->cause, b->cause); + _F1_EQ_CHECK_LONG(a->cause_value, b->cause_value); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, rrc_container, eq_ba); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, srb_id, _F1_EQ_CHECK_INT); + _F1_EQ_CHECK_OPTIONAL_IE(a, b, old_gNB_DU_ue_id, _F1_EQ_CHECK_INT); + return true; +} + +/** + * @brief Free Allocated F1 UE Context Release Command + */ +void free_ue_context_rel_cmd(f1ap_ue_context_rel_cmd_t *cmd) +{ + FREE_OPT_BYTE_ARRAY(cmd->rrc_container); + free(cmd->srb_id); + free(cmd->old_gNB_DU_ue_id); +} + +/* + * @brief Encode F1 UE context release complete to ASN.1 + */ +struct F1AP_F1AP_PDU *encode_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *cplt) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_UEContextRelease; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextReleaseComplete; + F1AP_UEContextReleaseComplete_t *out = &tmp->value.choice.UEContextReleaseComplete; + + /* mandatory: GNB_CU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCompleteIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = cplt->gNB_CU_ue_id; + + /* mandatory: GNB_DU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCompleteIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie2->value.choice.GNB_DU_UE_F1AP_ID = cplt->gNB_DU_ue_id; + + return pdu; +} + +/** + * @brief Decode F1 UE Context Release Complete + */ +bool decode_ue_context_rel_cplt(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_cplt_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + F1AP_UEContextReleaseComplete_t *in = &pdu->choice.successfulOutcome->value.choice.UEContextReleaseComplete; + F1AP_UEContextReleaseCompleteIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCompleteIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCompleteIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + + for (int i = 0; i < in->protocolIEs.list.count; ++i) { + ie = in->protocolIEs.list.array[i]; + AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_CU_UE_F1AP_ID); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_DU_UE_F1AP_ID); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + break; + default: + PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief F1 UE Context Release Complete deep copy + */ +f1ap_ue_context_rel_cplt_t cp_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *orig) +{ + f1ap_ue_context_rel_cplt_t cp = { + .gNB_CU_ue_id = orig->gNB_CU_ue_id, + .gNB_DU_ue_id = orig->gNB_DU_ue_id, + }; + return cp; +} + +/** + * @brief F1 UE Context Release Complete equality check + */ +bool eq_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *a, const f1ap_ue_context_rel_cplt_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + return true; +} + +/** + * @brief Free Allocated F1 UE Context Release Complete + */ +void free_ue_context_rel_cplt(f1ap_ue_context_rel_cplt_t *cplt) +{ + // nothing to free +} diff --git a/openair2/F1AP/lib/f1ap_ue_context.h b/openair2/F1AP/lib/f1ap_ue_context.h new file mode 100644 index 0000000000..0e82e82a85 --- /dev/null +++ b/openair2/F1AP/lib/f1ap_ue_context.h @@ -0,0 +1,72 @@ +/* + * 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 F1AP_UE_CONTEXT_SETUP_REQ_H_ +#define F1AP_UE_CONTEXT_SETUP_REQ_H_ + +#include +#include "f1ap_messages_types.h" + +struct F1AP_F1AP_PDU; + +struct F1AP_F1AP_PDU *encode_ue_context_setup_req(const f1ap_ue_context_setup_req_t *msg); +bool decode_ue_context_setup_req(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_setup_req_t *out); +f1ap_ue_context_setup_req_t cp_ue_context_setup_req(const f1ap_ue_context_setup_req_t *orig); +bool eq_ue_context_setup_req(const f1ap_ue_context_setup_req_t *a, const f1ap_ue_context_setup_req_t *b); +void free_ue_context_setup_req(f1ap_ue_context_setup_req_t *req); + +struct F1AP_F1AP_PDU *encode_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *msg); +bool decode_ue_context_setup_resp(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_setup_resp_t *out); +f1ap_ue_context_setup_resp_t cp_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *orig); +bool eq_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *a, const f1ap_ue_context_setup_resp_t *b); +void free_ue_context_setup_resp(f1ap_ue_context_setup_resp_t *resp); + +struct F1AP_F1AP_PDU *encode_ue_context_mod_req(const f1ap_ue_context_mod_req_t *msg); +bool decode_ue_context_mod_req(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_mod_req_t *out); +f1ap_ue_context_mod_req_t cp_ue_context_mod_req(const f1ap_ue_context_mod_req_t *orig); +bool eq_ue_context_mod_req(const f1ap_ue_context_mod_req_t *a, const f1ap_ue_context_mod_req_t *b); +void free_ue_context_mod_req(f1ap_ue_context_mod_req_t *req); + +struct F1AP_F1AP_PDU *encode_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *msg); +bool decode_ue_context_mod_resp(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_mod_resp_t *out); +f1ap_ue_context_mod_resp_t cp_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *orig); +bool eq_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *a, const f1ap_ue_context_mod_resp_t *b); +void free_ue_context_mod_resp(f1ap_ue_context_mod_resp_t *resp); + +struct F1AP_F1AP_PDU *encode_ue_context_rel_req(const f1ap_ue_context_rel_req_t *msg); +bool decode_ue_context_rel_req(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_req_t *out); +f1ap_ue_context_rel_req_t cp_ue_context_rel_req(const f1ap_ue_context_rel_req_t *orig); +bool eq_ue_context_rel_req(const f1ap_ue_context_rel_req_t *a, const f1ap_ue_context_rel_req_t *b); +void free_ue_context_rel_req(f1ap_ue_context_rel_req_t *req); + +struct F1AP_F1AP_PDU *encode_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *msg); +bool decode_ue_context_rel_cmd(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_cmd_t *out); +f1ap_ue_context_rel_cmd_t cp_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *orig); +bool eq_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *a, const f1ap_ue_context_rel_cmd_t *b); +void free_ue_context_rel_cmd(f1ap_ue_context_rel_cmd_t *cmd); + +struct F1AP_F1AP_PDU *encode_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *msg); +bool decode_ue_context_rel_cplt(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_cplt_t *out); +f1ap_ue_context_rel_cplt_t cp_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *orig); +bool eq_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *a, const f1ap_ue_context_rel_cplt_t *b); +void free_ue_context_rel_cplt(f1ap_ue_context_rel_cplt_t *cplt); + +#endif /* F1AP_UE_CONTEXT_SETUP_REQ_H_ */ diff --git a/openair2/F1AP/tests/CMakeLists.txt b/openair2/F1AP/tests/CMakeLists.txt index a73334051a..396e86d513 100644 --- a/openair2/F1AP/tests/CMakeLists.txt +++ b/openair2/F1AP/tests/CMakeLists.txt @@ -1,6 +1,6 @@ add_executable(f1ap_lib_test f1ap_lib_test.c) add_dependencies(tests f1ap_lib_test) add_test(NAME f1ap_lib_test COMMAND f1ap_lib_test) -target_link_libraries(f1ap_lib_test PRIVATE f1ap_lib) +target_link_libraries(f1ap_lib_test PRIVATE f1ap_lib ds) target_link_libraries(f1ap_lib_test PRIVATE asn1_f1ap) target_include_directories(f1ap_lib_test PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index cbb5955fe9..72ea809245 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "common/utils/assertions.h" #include "common/utils/utils.h" @@ -38,8 +39,10 @@ #include "f1ap_messages_types.h" #include "F1AP_F1AP-PDU.h" -#include "f1ap_lib_extern.h" +#include "lib/f1ap_lib_common.h" +#include "lib/f1ap_rrc_message_transfer.h" #include "lib/f1ap_interface_management.h" +#include "lib/f1ap_ue_context.h" void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) { @@ -718,6 +721,553 @@ static void test_f1ap_cu_configuration_update_acknowledge(void) // No free needed } +static byte_array_t get_test_ba(const char *s) +{ + byte_array_t ba = { + .len = strlen(s) + 1, /* binary data: needs to include null-byte of strdup() */ + .buf = (uint8_t *) strdup(s), + }; + return ba; +} + +static byte_array_t *get_malloced_test_ba(const char *s) +{ + byte_array_t *ba = calloc_or_fail(1, sizeof(*ba)); + *ba = get_test_ba(s); + return ba; +} + +static void test_f1ap_ue_context_setup_request() +{ + plmn_id_t plmn = { .mcc = 001, .mnc = 01, .mnc_digit_length = 2 }; + f1ap_ue_context_setup_req_t orig = { + .gNB_CU_ue_id = 12, + //.gNB_DU_ue_id below + .plmn = plmn, + .nr_cellid = 132, + .servCellIndex = 1, + //.cu_to_du_rrc_info below + //.srbs below + //.drbs below + //gnb_du_ue_agg_mbr_ul below + }; + _F1_MALLOC(orig.gNB_DU_ue_id, 13); + orig.cu_to_du_rrc_info.cg_configinfo = get_malloced_test_ba("CG-CONFIGINFO"); + orig.cu_to_du_rrc_info.ue_cap = get_malloced_test_ba("UE CAP"); + orig.cu_to_du_rrc_info.meas_config = get_malloced_test_ba("UE MEASUREMENT CONFIGURATION"); + orig.cu_to_du_rrc_info.meas_timing_config = get_malloced_test_ba("MEASUREMENT TIMING CONFIGURATION"); + orig.cu_to_du_rrc_info.ho_prep_info = get_malloced_test_ba("PREPARATION DATA FOR HANDOVER"); + orig.srbs_len = 2; + orig.srbs = calloc_or_fail(orig.srbs_len, sizeof(*orig.srbs)); + for (int i = 0; i < orig.srbs_len; ++i) + orig.srbs[i].id = 1 + i; + + orig.drbs_len = 2; + orig.drbs = calloc_or_fail(orig.drbs_len, sizeof(*orig.drbs)); + f1ap_drb_to_setup_t *drb1 = &orig.drbs[0]; + drb1->id = 4; + drb1->qos_choice = F1AP_QOS_CHOICE_NR; + f1ap_arp_t arp = { 1, MAY_TRIGGER_PREEMPTION, PREEMPTABLE, }; + drb1->nr.drb_qos.qos_type = NON_DYNAMIC; + drb1->nr.drb_qos.nondyn.fiveQI = 3; + drb1->nr.drb_qos.arp = arp; + drb1->nr.nssai = (nssai_t) {.sst = 1, .sd = 123}; + drb1->nr.flows_len = 1; + f1ap_drb_flows_mapped_t *flow = drb1->nr.flows = calloc_or_fail(drb1->nr.flows_len, sizeof(*flow)); + flow->qfi = 2; + flow->param.qos_type = NON_DYNAMIC; + flow->param.nondyn.fiveQI = 3; + flow->param.arp = arp; + drb1->up_ul_tnl_len = 1; + inet_pton(AF_INET, "192.168.40.23", &drb1->up_ul_tnl[0].tl_address); + drb1->up_ul_tnl[0].teid = 0x11223344; + drb1->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; + _F1_MALLOC(drb1->dl_pdcp_sn_len, F1AP_PDCP_SN_18B); + _F1_MALLOC(drb1->ul_pdcp_sn_len, F1AP_PDCP_SN_18B); + + f1ap_drb_to_setup_t *drb2 = &orig.drbs[1]; + drb2->id = 12; + drb2->qos_choice = F1AP_QOS_CHOICE_NR; + drb2->nr.drb_qos.qos_type = DYNAMIC; + f1ap_dynamic_5qi_t *dyn = &drb2->nr.drb_qos.dyn; + dyn->prio = 4; + dyn->pdb = 1000; + dyn->per.scalar = 4; + dyn->per.exponent = 8; + _F1_MALLOC(dyn->delay_critical, true); + _F1_MALLOC(dyn->avg_win, 3000); + f1ap_arp_t arp2 = { 13, SHALL_NOT_TRIGGER_PREEMPTION, NOT_PREEMPTABLE, }; + drb2->nr.drb_qos.arp = arp2; + drb2->nr.nssai = (nssai_t) {.sst = 2, .sd = 0xffffff}; + drb2->nr.flows_len = 2; + f1ap_drb_flows_mapped_t *flow2 = drb2->nr.flows = calloc_or_fail(drb2->nr.flows_len, sizeof(*flow2)); + flow2[0].qfi = 4; + flow2[0].param.qos_type = DYNAMIC; + flow2[0].param.dyn.prio = 4; + flow2[0].param.dyn.pdb = 999; + flow2[0].param.dyn.per.scalar = 4; + flow2[0].param.dyn.per.exponent = 8; + flow2[0].param.arp = arp2; + flow2[1].qfi = 5; + flow2[1].param.qos_type = NON_DYNAMIC; + flow2[1].param.nondyn.fiveQI = 3; + flow2[1].param.arp = arp; + drb2->up_ul_tnl_len = 2; + inet_pton(AF_INET, "10.0.0.2", &drb2->up_ul_tnl[0].tl_address); + drb2->up_ul_tnl[0].teid = 0x1234; + inet_pton(AF_INET, "10.0.0.2", &drb2->up_ul_tnl[1].tl_address); + drb2->up_ul_tnl[1].teid = 0x1235; + drb2->rlc_mode = F1AP_RLC_MODE_AM; + _F1_MALLOC(drb2->dl_pdcp_sn_len, F1AP_PDCP_SN_12B); + _F1_MALLOC(drb2->ul_pdcp_sn_len, F1AP_PDCP_SN_12B); + + orig.rrc_container = get_malloced_test_ba("RRC container"); + + _F1_MALLOC(orig.gnb_du_ue_agg_mbr_ul, 5LL * 1000 * 1000 * 1000); + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_setup_req(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_setup_req_t decoded = {0}; + bool ret = decode_ue_context_setup_req(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_setup_req(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_setup_req(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_setup_req(): decoded message doesn't match\n"); + char ip_ret[100]; + inet_ntop(AF_INET, &decoded.drbs[0].up_ul_tnl[0].tl_address, ip_ret, sizeof(ip_ret)); + printf("%s\n", ip_ret); + inet_ntop(AF_INET, &decoded.drbs[1].up_ul_tnl[0].tl_address, ip_ret, sizeof(ip_ret)); + printf("%s\n", ip_ret); + free_ue_context_setup_req(&decoded); + + f1ap_ue_context_setup_req_t cp = cp_ue_context_setup_req(&orig); + ret = eq_ue_context_setup_req(&orig, &cp); + AssertFatal(ret, "eq_ue_context_setup_req(): copied message doesn't match\n"); + free_ue_context_setup_req(&orig); + free_ue_context_setup_req(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_setup_request_simple() +{ + plmn_id_t plmn = { .mcc = 001, .mnc = 01, .mnc_digit_length = 2 }; + f1ap_ue_context_setup_req_t orig = { + .gNB_CU_ue_id = 12, + .plmn = plmn, + .nr_cellid = 132, + .servCellIndex = 1, + //.cu_to_du_rrc_info: all fields optional, intentionally left empty + // rest is optional and intentionally left empty + // .gnb_du_ue_agg_mbr_ul is C-ifDRBSetup => no DRB => no IE + }; + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_setup_req(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_setup_req_t decoded = {0}; + bool ret = decode_ue_context_setup_req(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_setup_req(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_setup_req(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_setup_req(): decoded message doesn't match\n"); + free_ue_context_setup_req(&decoded); + + f1ap_ue_context_setup_req_t cp = cp_ue_context_setup_req(&orig); + ret = eq_ue_context_setup_req(&orig, &cp); + AssertFatal(ret, "eq_ue_context_setup_req(): copied message doesn't match\n"); + free_ue_context_setup_req(&orig); + free_ue_context_setup_req(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_setup_response() +{ + f1ap_ue_context_setup_resp_t orig = { + .gNB_CU_ue_id = 12, + .gNB_DU_ue_id = 13, + //.du_to_cu_rrc_info below + //.crnti below + //.drbs below + //.srbs below + }; + + orig.du_to_cu_rrc_info.cell_group_config = get_test_ba("CELL GROUP CONFIG"); + orig.du_to_cu_rrc_info.meas_gap_config = get_malloced_test_ba("MGC"); + + _F1_MALLOC(orig.crnti, 0x1234); + + orig.drbs_len = 2; + orig.drbs = calloc_or_fail(orig.drbs_len, sizeof(*orig.drbs)); + f1ap_drb_setup_t *drb1 = &orig.drbs[0]; + drb1->id = 12; + _F1_MALLOC(drb1->lcid, 12); + drb1->up_dl_tnl_len = 2; + inet_pton(AF_INET, "192.168.40.23", &drb1->up_dl_tnl[0].tl_address); + drb1->up_dl_tnl[0].teid = 0x11223344; + inet_pton(AF_INET, "192.168.40.23", &drb1->up_dl_tnl[1].tl_address); + drb1->up_dl_tnl[1].teid = 0x11223345; + f1ap_drb_setup_t *drb2 = &orig.drbs[1]; + drb2->id = 13; + _F1_MALLOC(drb2->lcid, 13); + drb2->up_dl_tnl_len = 2; + inet_pton(AF_INET, "192.168.50.23", &drb2->up_dl_tnl[0].tl_address); + drb2->up_dl_tnl[0].teid = 0x21223354; + inet_pton(AF_INET, "192.168.50.23", &drb2->up_dl_tnl[1].tl_address); + drb2->up_dl_tnl[1].teid = 0x21223355; + + orig.srbs_len = 2; + orig.srbs = calloc_or_fail(orig.srbs_len, sizeof(*orig.srbs)); + for (int i = 0; i < orig.srbs_len; ++i) { + orig.srbs[i].id = 1 + i; + orig.srbs[i].lcid = 1+i+10; + } + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_setup_resp(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_setup_resp_t decoded = {0}; + bool ret = decode_ue_context_setup_resp(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_setup_resp(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_setup_resp(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_setup_resp(): decoded message doesn't match\n"); + free_ue_context_setup_resp(&decoded); + + f1ap_ue_context_setup_resp_t cp = cp_ue_context_setup_resp(&orig); + ret = eq_ue_context_setup_resp(&orig, &cp); + AssertFatal(ret, "eq_ue_context_setup_resp(): copied message doesn't match\n"); + free_ue_context_setup_resp(&orig); + free_ue_context_setup_resp(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_setup_response_simple() +{ + f1ap_ue_context_setup_resp_t orig = { + .gNB_CU_ue_id = 12, + .gNB_DU_ue_id = 13, + .du_to_cu_rrc_info.cell_group_config = get_test_ba("small cg"), + // rest is optional and intentionally left empty + }; + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_setup_resp(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_setup_resp_t decoded = {0}; + bool ret = decode_ue_context_setup_resp(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_setup_resp(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_setup_resp(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_setup_resp(): decoded message doesn't match\n"); + free_ue_context_setup_resp(&decoded); + + f1ap_ue_context_setup_resp_t cp = cp_ue_context_setup_resp(&orig); + ret = eq_ue_context_setup_resp(&orig, &cp); + AssertFatal(ret, "eq_ue_context_setup_resp(): copied message doesn't match\n"); + free_ue_context_setup_resp(&orig); + free_ue_context_setup_resp(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_modification_request() +{ + f1ap_ue_context_mod_req_t orig = { + .gNB_CU_ue_id = 1111, + .gNB_DU_ue_id = 2222, + // rest below + }; + plmn_id_t plmn = { .mcc = 999, .mnc = 101, .mnc_digit_length = 3 }; + _F1_MALLOC(orig.plmn, plmn); + _F1_MALLOC(orig.nr_cellid, 1532); + _F1_MALLOC(orig.servCellIndex, 3); + + f1ap_cu_to_du_rrc_info_t cu2du = { + .cg_configinfo = get_malloced_test_ba("Modified"), + .ue_cap = get_malloced_test_ba("UE forgot to send earlier"), + .meas_config = get_malloced_test_ba("with updates from another cell"), + .meas_timing_config = get_malloced_test_ba("measurement timing configuration"), + .ho_prep_info = get_malloced_test_ba("prepare to ho soon!"), + }; + _F1_MALLOC(orig.cu_to_du_rrc_info, cu2du); + + orig.rrc_container = get_malloced_test_ba("important RRC message!!"); + + orig.srbs_len = 1; + orig.srbs = calloc_or_fail(orig.srbs_len, sizeof(*orig.srbs)); + orig.srbs[0].id = 1; + + orig.drbs_len = 1; + orig.drbs = calloc_or_fail(orig.drbs_len, sizeof(*orig.drbs)); + f1ap_drb_to_setup_t *drb1 = &orig.drbs[0]; + drb1->id = 4; + drb1->qos_choice = F1AP_QOS_CHOICE_NR; + f1ap_arp_t arp = { 2, SHALL_NOT_TRIGGER_PREEMPTION, NOT_PREEMPTABLE, }; + drb1->nr.drb_qos.qos_type = NON_DYNAMIC; + drb1->nr.drb_qos.nondyn.fiveQI = 8; + drb1->nr.drb_qos.arp = arp; + drb1->nr.nssai = (nssai_t) {.sst = 2, .sd = 0xffffff}; + drb1->nr.flows_len = 1; + f1ap_drb_flows_mapped_t *flow = drb1->nr.flows = calloc_or_fail(drb1->nr.flows_len, sizeof(*flow)); + flow->qfi = 2; + flow->param.qos_type = NON_DYNAMIC; + flow->param.nondyn.fiveQI = 9; + flow->param.arp = arp; + drb1->up_ul_tnl_len = 1; + inet_pton(AF_INET, "8.8.8.8", &drb1->up_ul_tnl[0].tl_address); + drb1->up_ul_tnl[0].teid = 0x9876541; + drb1->rlc_mode = F1AP_RLC_MODE_AM; + _F1_MALLOC(drb1->dl_pdcp_sn_len, F1AP_PDCP_SN_12B); + _F1_MALLOC(drb1->ul_pdcp_sn_len, F1AP_PDCP_SN_18B); + + orig.drbs_rel_len = 3; + orig.drbs_rel = calloc_or_fail(orig.drbs_rel_len, sizeof(*orig.drbs_rel)); + orig.drbs_rel[0].id = 13; + orig.drbs_rel[1].id = 4; + orig.drbs_rel[2].id = 19; + + _F1_MALLOC(orig.status, LOWER_LAYERS_RESUME); + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_mod_req(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_mod_req_t decoded = {0}; + bool ret = decode_ue_context_mod_req(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_mod_req(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_mod_req(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_mod_req(): decoded message doesn't match\n"); + free_ue_context_mod_req(&decoded); + + f1ap_ue_context_mod_req_t cp = cp_ue_context_mod_req(&orig); + ret = eq_ue_context_mod_req(&orig, &cp); + AssertFatal(ret, "eq_ue_context_mod_req(): copied message doesn't match\n"); + free_ue_context_mod_req(&orig); + free_ue_context_mod_req(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_modification_request_simple() +{ + f1ap_ue_context_mod_req_t orig = { + .gNB_CU_ue_id = 1111, + .gNB_DU_ue_id = 2222, + // rest is optional and intentionally left out + }; + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_mod_req(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_mod_req_t decoded = {0}; + bool ret = decode_ue_context_mod_req(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_mod_req(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_mod_req(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_mod_req(): decoded message doesn't match\n"); + free_ue_context_mod_req(&decoded); + + f1ap_ue_context_mod_req_t cp = cp_ue_context_mod_req(&orig); + ret = eq_ue_context_mod_req(&orig, &cp); + AssertFatal(ret, "eq_ue_context_mod_req(): copied message doesn't match\n"); + free_ue_context_mod_req(&orig); + free_ue_context_mod_req(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_modification_response() +{ + f1ap_ue_context_mod_resp_t orig = { + .gNB_CU_ue_id = 9876, + .gNB_DU_ue_id = 5432, + // rest below + }; + + f1ap_du_to_cu_rrc_info_t cu2du = { + .cell_group_config = get_test_ba("update for the cellgroupconfig, extra long"), + .meas_gap_config = get_malloced_test_ba("new and shiny MeAs GaP cOnFiG"), + }; + _F1_MALLOC(orig.du_to_cu_rrc_info, cu2du); + + orig.drbs_len = 1; + orig.drbs = calloc_or_fail(orig.drbs_len, sizeof(*orig.drbs)); + f1ap_drb_setup_t *drb1 = &orig.drbs[0]; + drb1->id = 4; + _F1_MALLOC(drb1->lcid, 7); + drb1->up_dl_tnl_len = 1; + inet_pton(AF_INET, "127.0.0.1", &drb1->up_dl_tnl[0].tl_address); + drb1->up_dl_tnl[0].teid = 0xcafe; + + orig.srbs_len = 2; + orig.srbs = calloc_or_fail(orig.srbs_len, sizeof(*orig.srbs)); + orig.srbs[0].id = 1; + orig.srbs[0].lcid = 1; + orig.srbs[1].id = 2; + orig.srbs[1].lcid = 2; + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_mod_resp(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_mod_resp_t decoded = {0}; + bool ret = decode_ue_context_mod_resp(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_mod_resp(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_mod_resp(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_mod_resp(): decoded message doesn't match\n"); + free_ue_context_mod_resp(&decoded); + + f1ap_ue_context_mod_resp_t cp = cp_ue_context_mod_resp(&orig); + ret = eq_ue_context_mod_resp(&orig, &cp); + AssertFatal(ret, "eq_ue_context_mod_resp(): copied message doesn't match\n"); + free_ue_context_mod_resp(&orig); + free_ue_context_mod_resp(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_modification_response_simple() +{ + f1ap_ue_context_mod_resp_t orig = { + .gNB_CU_ue_id = 9876, + .gNB_DU_ue_id = 5432, + // rest is optional and intentionally left out + }; + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_mod_resp(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_mod_resp_t decoded = {0}; + bool ret = decode_ue_context_mod_resp(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_mod_resp(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_mod_resp(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_mod_resp(): decoded message doesn't match\n"); + free_ue_context_mod_resp(&decoded); + + f1ap_ue_context_mod_resp_t cp = cp_ue_context_mod_resp(&orig); + ret = eq_ue_context_mod_resp(&orig, &cp); + AssertFatal(ret, "eq_ue_context_mod_resp(): copied message doesn't match\n"); + free_ue_context_mod_resp(&orig); + free_ue_context_mod_resp(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_release_request() +{ + f1ap_ue_context_rel_req_t orig = { + .gNB_CU_ue_id = 1111, + .gNB_DU_ue_id = 2222, + .cause = F1AP_CAUSE_MISC, + .cause_value = 3, + }; + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_rel_req(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_rel_req_t decoded = {0}; + bool ret = decode_ue_context_rel_req(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_rel_req(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_rel_req(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_rel_req(): decoded message doesn't match\n"); + free_ue_context_rel_req(&decoded); + + f1ap_ue_context_rel_req_t cp = cp_ue_context_rel_req(&orig); + ret = eq_ue_context_rel_req(&orig, &cp); + AssertFatal(ret, "eq_ue_context_rel_req(): copied message doesn't match\n"); + free_ue_context_rel_req(&orig); + free_ue_context_rel_req(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_release_command() +{ + f1ap_ue_context_rel_cmd_t orig = { + .gNB_CU_ue_id = 1111, + .gNB_DU_ue_id = 2222, + .cause = F1AP_CAUSE_RADIO_NETWORK, + .cause_value = 2, + }; + + orig.rrc_container = get_malloced_test_ba("some reject message"); + _F1_MALLOC(orig.srb_id, 1); + _F1_MALLOC(orig.old_gNB_DU_ue_id, 3333); + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_rel_cmd(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_rel_cmd_t decoded = {0}; + bool ret = decode_ue_context_rel_cmd(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_rel_cmd(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_rel_cmd(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_rel_cmd(): decoded message doesn't match\n"); + free_ue_context_rel_cmd(&decoded); + + f1ap_ue_context_rel_cmd_t cp = cp_ue_context_rel_cmd(&orig); + ret = eq_ue_context_rel_cmd(&orig, &cp); + AssertFatal(ret, "eq_ue_context_rel_cmd(): copied message doesn't match\n"); + free_ue_context_rel_cmd(&orig); + free_ue_context_rel_cmd(&cp); + + printf("%s() successful\n", __func__); +} + +static void test_f1ap_ue_context_release_complete() +{ + f1ap_ue_context_rel_cplt_t orig = { + .gNB_CU_ue_id = 1111, + .gNB_DU_ue_id = 2222, + }; + + F1AP_F1AP_PDU_t *f1enc = encode_ue_context_rel_cplt(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ue_context_rel_cplt_t decoded = {0}; + bool ret = decode_ue_context_rel_cplt(f1dec, &decoded); + AssertFatal(ret, "decode_ue_context_rel_cplt(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ue_context_rel_cplt(&orig, &decoded); + AssertFatal(ret, "eq_ue_context_rel_cplt(): decoded message doesn't match\n"); + free_ue_context_rel_cplt(&decoded); + + f1ap_ue_context_rel_cplt_t cp = cp_ue_context_rel_cplt(&orig); + ret = eq_ue_context_rel_cplt(&orig, &cp); + AssertFatal(ret, "eq_ue_context_rel_cplt(): copied message doesn't match\n"); + free_ue_context_rel_cplt(&orig); + free_ue_context_rel_cplt(&cp); + + printf("%s() successful\n", __func__); +} + int main() { test_initial_ul_rrc_message_transfer(); @@ -733,5 +1283,16 @@ int main() test_f1ap_cu_configuration_update(); test_f1ap_cu_configuration_update_acknowledge(); test_f1ap_du_configuration_update_acknowledge(); + test_f1ap_ue_context_setup_request(); + test_f1ap_ue_context_setup_request_simple(); + test_f1ap_ue_context_setup_response(); + test_f1ap_ue_context_setup_response_simple(); + test_f1ap_ue_context_modification_request(); + test_f1ap_ue_context_modification_request_simple(); + test_f1ap_ue_context_modification_response(); + test_f1ap_ue_context_modification_response_simple(); + test_f1ap_ue_context_release_request(); + test_f1ap_ue_context_release_command(); + test_f1ap_ue_context_release_complete(); return 0; } diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index c1382d7b70..a6299b10cc 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -141,7 +141,7 @@ {CONFIG_STRING_MACRLC_LOCAL_N_ADDRESS_F1U, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \ {CONFIG_STRING_MACRLC_TRANSPORT_S_SHM_PREFIX, NULL, 0, .strptr=NULL, .defstrval="nvipc", TYPE_STRING, 0}, \ {CONFIG_STRING_MACRLC_TRANSPORT_S_POLL_CORE, NULL, 0, .i8ptr=NULL, .defintval=-1, TYPE_INT8, 0}, \ - {CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING, HLP_MACRLC_AB, PARAMFLAG_BOOL, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \ + {CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING, HLP_MACRLC_AB, 0, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \ diff --git a/openair2/GNB_APP/RRC_nr_paramsvalues.h b/openair2/GNB_APP/RRC_nr_paramsvalues.h index c7b74be8b0..28d5f71ff9 100644 --- a/openair2/GNB_APP/RRC_nr_paramsvalues.h +++ b/openair2/GNB_APP/RRC_nr_paramsvalues.h @@ -124,6 +124,7 @@ #define GNB_CONFIG_STRING_NROFUPLINKSYMBOLS2 "nrofUplinkSymbols2" #define GNB_CONFIG_STRING_SSPBCHBLOCKPOWER "ssPBCH_BlockPower" +#define GNB_CONFIG_STRING_ULSYNCVALIDITYDURATION "ntn-UlSyncValidityDuration-r17" #define GNB_CONFIG_STRING_CELLSPECIFICKOFFSET "cellSpecificKoffset_r17" #define GNB_CONFIG_STRING_EPHEMERIS_POSITION_X "positionX-r17" #define GNB_CONFIG_STRING_EPHEMERIS_POSITION_Y "positionY-r17" @@ -135,53 +136,6 @@ #define GNB_CONFIG_STRING_TA_COMMONDRIFT "ta-CommonDrift-r17" #define CARRIERBANDWIDTH_OKVALUES {11,18,24,25,31,32,38,51,52,65,66,78,79,93,106,107,121,132,133,135,160,162,189,216,217,245,264,270,273} - -/* Serving Cell Config Dedicated */ -#define GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED "servingCellConfigDedicated" -#define GNB_CONFIG_STRING_DLPTRSFREQDENSITY0_0 "dl_ptrsFreqDensity0_0" -#define GNB_CONFIG_STRING_DLPTRSFREQDENSITY1_0 "dl_ptrsFreqDensity1_0" -#define GNB_CONFIG_STRING_DLPTRSTIMEDENSITY0_0 "dl_ptrsTimeDensity0_0" -#define GNB_CONFIG_STRING_DLPTRSTIMEDENSITY1_0 "dl_ptrsTimeDensity1_0" -#define GNB_CONFIG_STRING_DLPTRSTIMEDENSITY2_0 "dl_ptrsTimeDensity2_0" -#define GNB_CONFIG_STRING_DLPTRSEPRERATIO_0 "dl_ptrsEpreRatio_0" -#define GNB_CONFIG_STRING_DLPTRSREOFFSET_0 "dl_ptrsReOffset_0" -#define GNB_CONFIG_STRING_ULPTRSFREQDENSITY0_0 "ul_ptrsFreqDensity0_0" -#define GNB_CONFIG_STRING_ULPTRSFREQDENSITY1_0 "ul_ptrsFreqDensity1_0" -#define GNB_CONFIG_STRING_ULPTRSTIMEDENSITY0_0 "ul_ptrsTimeDensity0_0" -#define GNB_CONFIG_STRING_ULPTRSTIMEDENSITY1_0 "ul_ptrsTimeDensity1_0" -#define GNB_CONFIG_STRING_ULPTRSTIMEDENSITY2_0 "ul_ptrsTimeDensity2_0" -#define GNB_CONFIG_STRING_ULPTRSREOFFSET_0 "ul_ptrsReOffset_0" -#define GNB_CONFIG_STRING_ULPTRSMAXPORTS_0 "ul_ptrsMaxPorts_0" -#define GNB_CONFIG_STRING_ULPTRSPOWER_0 "ul_ptrsPower_0" - -#define GNB_CONFIG_STRING_DLBWP1_ID "dl_bwp-Id_1" -#define GNB_CONFIG_STRING_DLBWP2_ID "dl_bwp-Id_2" -#define GNB_CONFIG_STRING_DLBWP3_ID "dl_bwp-Id_3" -#define GNB_CONFIG_STRING_DLBWP4_ID "dl_bwp-Id_4" -#define GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_DLBWP1 "dl_bwp1_locationAndBandwidth" -#define GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_DLBWP2 "dl_bwp2_locationAndBandwidth" -#define GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_DLBWP3 "dl_bwp3_locationAndBandwidth" -#define GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_DLBWP4 "dl_bwp4_locationAndBandwidth" -#define GNB_CONFIG_STRING_SCS_DLBWP1 "dl_bwp1_subcarrierSpacing" -#define GNB_CONFIG_STRING_SCS_DLBWP2 "dl_bwp2_subcarrierSpacing" -#define GNB_CONFIG_STRING_SCS_DLBWP3 "dl_bwp3_subcarrierSpacing" -#define GNB_CONFIG_STRING_SCS_DLBWP4 "dl_bwp4_subcarrierSpacing" -#define GNB_CONFIG_STRING_FIRSTACTIVEDLBWP_ID "firstActiveDownlinkBWP-Id" -#define GNB_CONFIG_STRING_DEFAULTDLBWP_ID "defaultDownlinkBWP-Id" -#define GNB_CONFIG_STRING_ULBWP1_ID "ul_bwp-Id_1" -#define GNB_CONFIG_STRING_ULBWP2_ID "ul_bwp-Id_2" -#define GNB_CONFIG_STRING_ULBWP3_ID "ul_bwp-Id_3" -#define GNB_CONFIG_STRING_ULBWP4_ID "ul_bwp-Id_4" -#define GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_ULBWP1 "ul_bwp1_locationAndBandwidth" -#define GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_ULBWP2 "ul_bwp2_locationAndBandwidth" -#define GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_ULBWP3 "ul_bwp3_locationAndBandwidth" -#define GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_ULBWP4 "ul_bwp4_locationAndBandwidth" -#define GNB_CONFIG_STRING_SCS_ULBWP1 "ul_bwp1_subcarrierSpacing" -#define GNB_CONFIG_STRING_SCS_ULBWP2 "ul_bwp2_subcarrierSpacing" -#define GNB_CONFIG_STRING_SCS_ULBWP3 "ul_bwp3_subcarrierSpacing" -#define GNB_CONFIG_STRING_SCS_ULBWP4 "ul_bwp4_subcarrierSpacing" -#define GNB_CONFIG_STRING_FIRSTACTIVEULBWP_ID "firstActiveUplinkBWP-Id" - /*--------------------------------------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ @@ -227,7 +181,7 @@ {GNB_CONFIG_STRING_PREAMBLERECEIVEDTARGETPOWER,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower,.defint64val=-118,TYPE_INT64,0/*75*/},\ {GNB_CONFIG_STRING_PREAMBLETRANSMAX,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleTransMax,.defint64val=NR_RACH_ConfigGeneric__preambleTransMax_n10,TYPE_INT64,0/*76*/},\ {GNB_CONFIG_STRING_POWERRAMPINGSTEP,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.powerRampingStep,.defint64val=NR_RACH_ConfigGeneric__powerRampingStep_dB2,TYPE_INT64,0/*77*/},\ -{GNB_CONFIG_STRING_RARESPONSEWINDOW,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow,.defint64val=NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20,TYPE_INT64,0/*78*/},\ +{GNB_CONFIG_STRING_RARESPONSEWINDOW,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow,.defint64val=-1,TYPE_INT64,0/*78*/},\ {GNB_CONFIG_STRING_SSBPERRACHOCCASIONANDCBPREAMBLESPERSSBPR,NULL,0,.uptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present,.defuintval=NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one,TYPE_UINT,0/*79*/},\ {GNB_CONFIG_STRING_SSBPERRACHOCCASIONANDCBPREAMBLESPERSSB,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.one,.defint64val=NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB__one_n64,TYPE_INT64,0 /*80*/}, \ {GNB_CONFIG_STRING_RACONTENTIONRESOLUTIONTIMER,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer,.defint64val=NR_RACH_ConfigCommon__ra_ContentionResolutionTimer_sf64,TYPE_INT64,0/*81*/},\ @@ -250,6 +204,7 @@ {GNB_CONFIG_STRING_NROFUPLINKSLOTS,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots,.defint64val=2,TYPE_INT64,0},\ {GNB_CONFIG_STRING_NROFUPLINKSYMBOLS,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols,.defint64val=4,TYPE_INT64,0},\ {GNB_CONFIG_STRING_SSPBCHBLOCKPOWER,NULL,0,.i64ptr=&scc->ss_PBCH_BlockPower,.defint64val=20,TYPE_INT64,0}, \ +{GNB_CONFIG_STRING_ULSYNCVALIDITYDURATION,NULL,0,.i64ptr=scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17,.defint64val=0,TYPE_INT64,0}, \ {GNB_CONFIG_STRING_CELLSPECIFICKOFFSET,NULL,0,.i64ptr=scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17,.defint64val=0,TYPE_INT64,0}, \ {GNB_CONFIG_STRING_EPHEMERIS_POSITION_X,NULL,0,.i64ptr=&scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionX_r17,.defint64val=LONG_MAX,TYPE_INT64,0}, \ {GNB_CONFIG_STRING_EPHEMERIS_POSITION_Y,NULL,0,.i64ptr=&scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionY_r17,.defint64val=LONG_MAX,TYPE_INT64,0}, \ @@ -270,53 +225,6 @@ {GNB_CONFIG_STRING_NROFUPLINKSLOTS2,NULL, 0,.i64ptr=&pattern2.nrofUplinkSlots,.defint64val=-1,TYPE_INT64,0},\ {GNB_CONFIG_STRING_NROFUPLINKSYMBOLS2,NULL, 0,.i64ptr=&pattern2.nrofUplinkSymbols,.defint64val=-1,TYPE_INT64,0}} -/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* Serving Cell Config Dedicated configuration parameters */ -/*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ - -#define SCDPARAMS_DESC(scd) { \ -{GNB_CONFIG_STRING_DLPTRSFREQDENSITY0_0,NULL,0,.i64ptr=scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->frequencyDensity->list.array[0],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLPTRSFREQDENSITY1_0,NULL,0,.i64ptr=scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->frequencyDensity->list.array[1],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLPTRSTIMEDENSITY0_0,NULL,0,.i64ptr=scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->timeDensity->list.array[0],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLPTRSTIMEDENSITY1_0,NULL,0,.i64ptr=scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->timeDensity->list.array[1],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLPTRSTIMEDENSITY2_0,NULL,0,.i64ptr=scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->timeDensity->list.array[2],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLPTRSEPRERATIO_0,NULL,0,.i64ptr=scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->epre_Ratio,.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLPTRSREOFFSET_0,NULL,0,.i64ptr=scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS->choice.setup->resourceElementOffset,.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULPTRSFREQDENSITY0_0,NULL,0,.i64ptr=scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[0],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULPTRSFREQDENSITY1_0,NULL,0,.i64ptr=scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[1],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULPTRSTIMEDENSITY0_0,NULL,0,.i64ptr=scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[0],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULPTRSTIMEDENSITY1_0,NULL,0,.i64ptr=scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[1],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULPTRSTIMEDENSITY2_0,NULL,0,.i64ptr=scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[2],.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULPTRSREOFFSET_0,NULL,0,.i64ptr=scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset,.defint64val=-1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULPTRSMAXPORTS_0,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->maxNrofPorts,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULPTRSPOWER_0,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup->transformPrecoderDisabled->ptrs_Power,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_FIRSTACTIVEDLBWP_ID,NULL,0,.i64ptr=scd->firstActiveDownlinkBWP_Id,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_FIRSTACTIVEULBWP_ID,NULL,0,.i64ptr=scd->uplinkConfig->firstActiveUplinkBWP_Id,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLBWP1_ID,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Id,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLBWP2_ID,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[1]->bwp_Id,.defint64val=2,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLBWP3_ID,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[2]->bwp_Id,.defint64val=3,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DLBWP4_ID,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[3]->bwp_Id,.defint64val=4,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_SCS_DLBWP1,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.subcarrierSpacing,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_SCS_DLBWP2,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[1]->bwp_Common->genericParameters.subcarrierSpacing,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_SCS_DLBWP3,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[2]->bwp_Common->genericParameters.subcarrierSpacing,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_SCS_DLBWP4,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[3]->bwp_Common->genericParameters.subcarrierSpacing,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_DLBWP1,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.locationAndBandwidth,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_DLBWP2,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[1]->bwp_Common->genericParameters.locationAndBandwidth,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_DLBWP3,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[2]->bwp_Common->genericParameters.locationAndBandwidth,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_DLBWP4,NULL,0,.i64ptr=&scd->downlinkBWP_ToAddModList->list.array[3]->bwp_Common->genericParameters.locationAndBandwidth,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULBWP1_ID,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Id,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULBWP2_ID,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[1]->bwp_Id,.defint64val=2,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULBWP3_ID,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[2]->bwp_Id,.defint64val=3,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_ULBWP4_ID,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[3]->bwp_Id,.defint64val=4,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_SCS_ULBWP1,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.subcarrierSpacing,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_SCS_ULBWP2,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[1]->bwp_Common->genericParameters.subcarrierSpacing,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_SCS_ULBWP3,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[2]->bwp_Common->genericParameters.subcarrierSpacing,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_SCS_ULBWP4,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[3]->bwp_Common->genericParameters.subcarrierSpacing,.defint64val=1,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_ULBWP1,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.locationAndBandwidth,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_ULBWP2,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[1]->bwp_Common->genericParameters.locationAndBandwidth,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_ULBWP3,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[2]->bwp_Common->genericParameters.locationAndBandwidth,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_LOCATIONANDBANDWIDTH_ULBWP4,NULL,0,.i64ptr=&scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[3]->bwp_Common->genericParameters.locationAndBandwidth,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_DEFAULTDLBWP_ID,NULL,0,.i64ptr=scd->defaultDownlinkBWP_Id,.defint64val=0,TYPE_INT64,0}} /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /* Serving Cell Config Common configuration parameters to apply in RA 2-Step */ diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c index e90a83d3bc..3b97dfe515 100644 --- a/openair2/GNB_APP/gnb_app.c +++ b/openair2/GNB_APP/gnb_app.c @@ -212,6 +212,11 @@ void *gNB_app_task(void *args_p) LOG_I(GNB_APP, " Received %s: timer_id %ld\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id); break; + case GNB_SAT_POSITION_UPDATE: + LOG_I(GNB_APP, " Received GNB_SAT_POSITION_UPDATE message\n"); + nr_update_sib19(&GNB_SAT_POSITION_UPDATE(msg_p)); + break; + default: LOG_E(GNB_APP, "Received unexpected message %s\n", msg_name); break; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 0ddd097ca6..45532572cd 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -78,9 +78,7 @@ #include "uper_encoder.h" #include "utils.h" #include "x2ap_messages_types.h" -#ifdef ENABLE_AERIAL -#include "nfapi/oai_integration/aerial/fapi_vnf_p5.h" -#endif + static int DEFBANDS[] = {7}; static int DEFENBS[] = {0}; @@ -216,15 +214,23 @@ void prepare_scc(NR_ServingCellConfigCommon_t *scc) scc->ext2 = calloc_or_fail(1, sizeof(*scc->ext2)); scc->ext2->ntn_Config_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17)); + scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 = calloc_or_fail(1, sizeof(long)); scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17)); scc->ext2->ntn_Config_r17->ephemerisInfo_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17)); scc->ext2->ntn_Config_r17->ta_Info_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ta_Info_r17)); + scc->ext2->ntn_Config_r17->ta_Info_r17->ta_Common_r17 = -1; scc->ext2->ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17)); scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present = NR_EphemerisInfo_r17_PR_positionVelocity_r17; scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17 = calloc_or_fail(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17)); + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionX_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionY_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->positionZ_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->velocityVX_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->velocityVY_r17 = LONG_MAX; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->velocityVZ_r17 = LONG_MAX; } void prepare_msgA_scc(NR_ServingCellConfigCommon_t *scc) { NR_BWP_UplinkCommon_t *initialUplinkBWP = scc->uplinkConfigCommon->initialUplinkBWP; @@ -465,6 +471,40 @@ static void fix_tdd_pattern(NR_ServingCellConfigCommon_t *scc) } } +static int get_ulsyncvalidityduration_enum_value(int val) +{ + int retval = -1; + + switch (val) { + case 5: + case 10: + case 15: + case 20: + case 25: + case 30: + case 35: + case 40: + case 45: + case 50: + case 55: + retval = val / 5 - 1; + break; + case 60: + case 120: + case 180: + case 240: + retval = 10 + val / 60; + break; + case 900: + retval = 15; + break; + default: + AssertFatal(1 == 0, "ulsyncvalidityDuration in SIB19 set to invalid value in Conf file\n"); + break; + } + return retval; +} + void fix_scc(NR_ServingCellConfigCommon_t *scc, uint64_t ssbmap) { scc->ssb_PositionsInBurst->present = get_ssb_len(scc); @@ -535,6 +575,14 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc, uint64_t ssbmap) rach_ConfigCommon->msg3_transformPrecoder = NULL; } + // by default, select ra_ResponseWindow automatically + if (rach_ConfigCommon->rach_ConfigGeneric.ra_ResponseWindow < 0) { + int mu = *scc->ssbSubcarrierSpacing; + // will select: mu=0 => 4 (10 slots), mu=1 => 5 (20 slots), mu>=3 => 7 (80 slots) + rach_ConfigCommon->rach_ConfigGeneric.ra_ResponseWindow = min(NR_RACH_ConfigGeneric__ra_ResponseWindow_sl80, NR_RACH_ConfigGeneric__ra_ResponseWindow_sl10 + mu); + } + DevAssert(rach_ConfigCommon->rach_ConfigGeneric.ra_ResponseWindow >= 0); + // prepare DL Allocation lists nr_rrc_config_dl_tda(dlcc->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList, frame_type, @@ -572,6 +620,13 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc, uint64_t ssbmap) AssertFatal(*scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon < 2, "pucch_ResourceConfig should be 0 or 1 for now\n"); + if (*scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 == 0) { + free(scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17); + scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 = NULL; + } else { + int val = get_ulsyncvalidityduration_enum_value(*scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17); + *scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 = val; + } if (*scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 == 0) { free(scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17); scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 = NULL; @@ -596,241 +651,16 @@ void fix_scc(NR_ServingCellConfigCommon_t *scc, uint64_t ssbmap) scc->ext2->ntn_Config_r17->ephemerisInfo_r17 = NULL; } - if (!scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 && !scc->ext2->ntn_Config_r17->ta_Info_r17 - && !scc->ext2->ntn_Config_r17->ephemerisInfo_r17) { + if (!scc->ext2->ntn_Config_r17->ntn_UlSyncValidityDuration_r17 && + !scc->ext2->ntn_Config_r17->cellSpecificKoffset_r17 && + !scc->ext2->ntn_Config_r17->ta_Info_r17 && + !scc->ext2->ntn_Config_r17->ephemerisInfo_r17) { free(scc->ext2->ntn_Config_r17); free(scc->ext2); scc->ext2 = NULL; } } -/* Function to allocate dedicated serving cell config strutures */ -void prepare_scd(NR_ServingCellConfig_t *scd) { - // Allocate downlink structures - scd->downlinkBWP_ToAddModList = calloc_or_fail(1, sizeof(*scd->downlinkBWP_ToAddModList)); - scd->uplinkConfig = calloc_or_fail(1, sizeof(*scd->uplinkConfig)); - scd->uplinkConfig->uplinkBWP_ToAddModList = calloc_or_fail(1, sizeof(*scd->uplinkConfig->uplinkBWP_ToAddModList)); - scd->bwp_InactivityTimer = calloc_or_fail(1, sizeof(*scd->bwp_InactivityTimer)); - scd->uplinkConfig->firstActiveUplinkBWP_Id = calloc_or_fail(1, sizeof(*scd->uplinkConfig->firstActiveUplinkBWP_Id)); - scd->firstActiveDownlinkBWP_Id = calloc_or_fail(1, sizeof(*scd->firstActiveDownlinkBWP_Id)); - *scd->firstActiveDownlinkBWP_Id = 1; - *scd->uplinkConfig->firstActiveUplinkBWP_Id = 1; - scd->defaultDownlinkBWP_Id = calloc_or_fail(1, sizeof(*scd->defaultDownlinkBWP_Id)); - *scd->defaultDownlinkBWP_Id = 0; - - for (int j = 0; j < NR_MAX_NUM_BWP; j++) { - - // Downlink bandwidth part - NR_BWP_Downlink_t *bwp = calloc_or_fail(1, sizeof(*bwp)); - bwp->bwp_Id = j+1; - - // Allocate downlink dedicated bandwidth part and PDSCH structures - bwp->bwp_Common = calloc_or_fail(1, sizeof(*bwp->bwp_Common)); - bwp->bwp_Common->pdcch_ConfigCommon = calloc_or_fail(1, sizeof(*bwp->bwp_Common->pdcch_ConfigCommon)); - bwp->bwp_Common->pdsch_ConfigCommon = calloc_or_fail(1, sizeof(*bwp->bwp_Common->pdsch_ConfigCommon)); - bwp->bwp_Dedicated = calloc_or_fail(1, sizeof(*bwp->bwp_Dedicated)); - bwp->bwp_Dedicated->pdsch_Config = calloc_or_fail(1, sizeof(*bwp->bwp_Dedicated->pdsch_Config)); - struct NR_SetupRelease_PDSCH_Config *pdsch_Config = bwp->bwp_Dedicated->pdsch_Config; - pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup; - pdsch_Config->choice.setup = calloc_or_fail(1, sizeof(*pdsch_Config->choice.setup)); - struct NR_PDSCH_Config *pc_setup = pdsch_Config->choice.setup; - pc_setup->dmrs_DownlinkForPDSCH_MappingTypeA = calloc_or_fail(1, sizeof(*pc_setup->dmrs_DownlinkForPDSCH_MappingTypeA)); - struct NR_SetupRelease_DMRS_DownlinkConfig *typeA = pc_setup->dmrs_DownlinkForPDSCH_MappingTypeA; - typeA->present = NR_SetupRelease_DMRS_DownlinkConfig_PR_setup; - - // Allocate DL DMRS and PTRS configuration - typeA->choice.setup = calloc_or_fail(1, sizeof(*typeA->choice.setup)); - NR_DMRS_DownlinkConfig_t *NR_DMRS_DownlinkCfg = typeA->choice.setup; - NR_DMRS_DownlinkCfg->phaseTrackingRS = calloc_or_fail(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS)); - NR_DMRS_DownlinkCfg->phaseTrackingRS->present = NR_SetupRelease_PTRS_DownlinkConfig_PR_setup; - NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup = - calloc_or_fail(1, sizeof(*NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup)); - NR_PTRS_DownlinkConfig_t *NR_PTRS_DownlinkCfg = NR_DMRS_DownlinkCfg->phaseTrackingRS->choice.setup; - NR_PTRS_DownlinkCfg->frequencyDensity = calloc_or_fail(1, sizeof(*NR_PTRS_DownlinkCfg->frequencyDensity)); - for (int i=0;i<2;i++) { - long *a = calloc_or_fail(1, sizeof(*a)); - asn1cSeqAdd(&NR_PTRS_DownlinkCfg->frequencyDensity->list, a); - } - NR_PTRS_DownlinkCfg->timeDensity = calloc_or_fail(1, sizeof(*NR_PTRS_DownlinkCfg->timeDensity)); - for (int i=0;i<3;i++) { - long *dl_mcs = calloc_or_fail(1, sizeof(*dl_mcs)); - asn1cSeqAdd(&NR_PTRS_DownlinkCfg->timeDensity->list, dl_mcs); - } - NR_PTRS_DownlinkCfg->epre_Ratio = calloc_or_fail(1, sizeof(*NR_PTRS_DownlinkCfg->epre_Ratio)); - NR_PTRS_DownlinkCfg->resourceElementOffset = calloc_or_fail(1, sizeof(*NR_PTRS_DownlinkCfg->resourceElementOffset)); - *NR_PTRS_DownlinkCfg->resourceElementOffset = 0; - asn1cSeqAdd(&scd->downlinkBWP_ToAddModList->list,bwp); - - // Allocate uplink structures - - NR_PUSCH_Config_t *pusch_Config = calloc_or_fail(1, sizeof(*pusch_Config)); - - // Allocate UL DMRS and PTRS structures - pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB = calloc_or_fail(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB)); - pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->present = NR_SetupRelease_DMRS_UplinkConfig_PR_setup; - pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = - calloc_or_fail(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup)); - NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; - NR_DMRS_UplinkConfig->phaseTrackingRS = calloc_or_fail(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS)); - NR_DMRS_UplinkConfig->phaseTrackingRS->present = NR_SetupRelease_PTRS_UplinkConfig_PR_setup; - NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup = - calloc_or_fail(1, sizeof(*NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup)); - NR_PTRS_UplinkConfig_t *NR_PTRS_UplinkConfig = NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup; - NR_PTRS_UplinkConfig->transformPrecoderDisabled = calloc_or_fail(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled)); - NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity = - calloc_or_fail(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity)); - for (int i=0;i<2;i++) { - long *n_rbs = calloc_or_fail(1, sizeof(*n_rbs)); - asn1cSeqAdd(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->frequencyDensity->list, n_rbs); - } - NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity = - calloc_or_fail(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity)); - for (int i = 0; i < 3; i++) { - long *ptrs_mcs = calloc_or_fail(1, sizeof(*ptrs_mcs)); - asn1cSeqAdd(&NR_PTRS_UplinkConfig->transformPrecoderDisabled->timeDensity->list, ptrs_mcs); - } - NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = - calloc_or_fail(1, sizeof(*NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset)); - *NR_PTRS_UplinkConfig->transformPrecoderDisabled->resourceElementOffset = 0; - - // UL bandwidth part - NR_BWP_Uplink_t *ubwp = calloc_or_fail(1, sizeof(*ubwp)); - ubwp->bwp_Id = j+1; - ubwp->bwp_Common = calloc_or_fail(1, sizeof(*ubwp->bwp_Common)); - ubwp->bwp_Dedicated = calloc_or_fail(1, sizeof(*ubwp->bwp_Dedicated)); - - ubwp->bwp_Dedicated->pusch_Config = calloc_or_fail(1, sizeof(*ubwp->bwp_Dedicated->pusch_Config)); - ubwp->bwp_Dedicated->pusch_Config->present = NR_SetupRelease_PUSCH_Config_PR_setup; - ubwp->bwp_Dedicated->pusch_Config->choice.setup = pusch_Config; - - asn1cSeqAdd(&scd->uplinkConfig->uplinkBWP_ToAddModList->list,ubwp); - } -} - -/* This function checks dedicated serving cell configuration and performs fixes as needed */ -void fix_scd(NR_ServingCellConfig_t *scd) { - - // Remove unused BWPs - int b = 0; - while (bdownlinkBWP_ToAddModList->list.count) { - if (scd->downlinkBWP_ToAddModList->list.array[b]->bwp_Common->genericParameters.locationAndBandwidth == 0) { - ASN_STRUCT_FREE(asn_DEF_NR_BWP_Downlink, scd->downlinkBWP_ToAddModList->list.array[b]); - asn_sequence_del(&scd->downlinkBWP_ToAddModList->list,b,1); - } else { - b++; - } - } - - b = 0; - while (buplinkConfig->uplinkBWP_ToAddModList->list.count) { - if (scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[b]->bwp_Common->genericParameters.locationAndBandwidth == 0) { - ASN_STRUCT_FREE(asn_DEF_NR_BWP_Uplink, scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[b]); - asn_sequence_del(&scd->uplinkConfig->uplinkBWP_ToAddModList->list,b,1); - } else { - b++; - } - } - - // Check for DL PTRS parameters validity - for (int bwp_i = 0 ; bwp_idownlinkBWP_ToAddModList->list.count; bwp_i++) { - - NR_DMRS_DownlinkConfig_t *dmrs_dl_config = scd->downlinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pdsch_Config->choice.setup->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup; - - if (dmrs_dl_config->phaseTrackingRS) { - // If any of the frequencyDensity values are not set or are out of bounds, PTRS is assumed to be not present - for (int i = dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.count - 1; i >= 0; i--) { - if ((*dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] < 1) - || (*dmrs_dl_config->phaseTrackingRS->choice.setup->frequencyDensity->list.array[i] > 276)) { - LOG_I(GNB_APP, "DL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i); - free(dmrs_dl_config->phaseTrackingRS); - dmrs_dl_config->phaseTrackingRS = NULL; - break; - } - } - } - - if (dmrs_dl_config->phaseTrackingRS) { - // If any of the timeDensity values are not set or are out of bounds, PTRS is assumed to be not present - for (int i = dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.count - 1; i >= 0; i--) { - if ((*dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.array[i] < 0) - || (*dmrs_dl_config->phaseTrackingRS->choice.setup->timeDensity->list.array[i] > 29)) { - LOG_I(GNB_APP, "DL PTRS timeDensity %d not set. Assuming PTRS not present! \n", i); - free(dmrs_dl_config->phaseTrackingRS); - dmrs_dl_config->phaseTrackingRS = NULL; - break; - } - } - } - - if (dmrs_dl_config->phaseTrackingRS) { - if (*dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset > 2) { - LOG_I(GNB_APP, "Freeing DL PTRS resourceElementOffset \n"); - free(dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset); - dmrs_dl_config->phaseTrackingRS->choice.setup->resourceElementOffset = NULL; - } - if (*dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio > 1) { - LOG_I(GNB_APP, "Freeing DL PTRS epre_Ratio \n"); - free(dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio); - dmrs_dl_config->phaseTrackingRS->choice.setup->epre_Ratio = NULL; - } - } - } - - // Check for UL PTRS parameters validity - for (int bwp_i = 0 ; bwp_iuplinkConfig->uplinkBWP_ToAddModList->list.count; bwp_i++) { - - NR_DMRS_UplinkConfig_t *dmrs_ul_config = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_i]->bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; - - if (dmrs_ul_config->phaseTrackingRS) { - // If any of the frequencyDensity values are not set or are out of bounds, PTRS is assumed to be not present - for (int i = dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.count-1; i >= 0; i--) { - if ((*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] < 1) - || (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->frequencyDensity->list.array[i] > 276)) { - LOG_I(GNB_APP, "UL PTRS frequencyDensity %d not set. Assuming PTRS not present! \n", i); - free(dmrs_ul_config->phaseTrackingRS); - dmrs_ul_config->phaseTrackingRS = NULL; - break; - } - } - } - - if (dmrs_ul_config->phaseTrackingRS) { - // If any of the timeDensity values are not set or are out of bounds, PTRS is assumed to be not present - for (int i = dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.count-1; i >= 0; i--) { - if ((*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] < 0) - || (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->timeDensity->list.array[i] > 29)) { - LOG_I(GNB_APP, "UL PTRS timeDensity %d not set. Assuming PTRS not present! \n", i); - free(dmrs_ul_config->phaseTrackingRS); - dmrs_ul_config->phaseTrackingRS = NULL; - break; - } - } - } - - if (dmrs_ul_config->phaseTrackingRS) { - // Check for UL PTRS parameters validity - if (*dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset > 2) { - LOG_I(GNB_APP, "Freeing UL PTRS resourceElementOffset \n"); - free(dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset); - dmrs_ul_config->phaseTrackingRS->choice.setup->transformPrecoderDisabled->resourceElementOffset = NULL; - } - } - - } - - if (scd->downlinkBWP_ToAddModList->list.count == 0) { - free(scd->downlinkBWP_ToAddModList->list.array); - free(scd->downlinkBWP_ToAddModList); - scd->downlinkBWP_ToAddModList = NULL; - } - - if (scd->uplinkConfig->uplinkBWP_ToAddModList->list.count == 0) { - free(scd->uplinkConfig->uplinkBWP_ToAddModList->list.array); - free(scd->uplinkConfig->uplinkBWP_ToAddModList); - scd->uplinkConfig->uplinkBWP_ToAddModList = NULL; - } -} - static void verify_gnb_param_notset(paramdef_t *params, int paramidx, const char *paramname) { char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; @@ -892,6 +722,8 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".[0]", GNB_CONFIG_STRING_AMF_IP_ADDRESS); verify_section_notset(cfg, NULL, CONFIG_STRING_SECURITY); verify_section_notset(cfg, NULL, CONFIG_STRING_NR_PDCP_LIST); + verify_section_notset(cfg, NULL, GNB_CONFIG_STRING_NEIGHBOUR_LIST); + verify_section_notset(cfg, NULL, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION); } // else nothing to be checked /* other possible verifications: PNF, VNF, CU-CP, CU-UP, ...? */ @@ -1108,7 +940,7 @@ bool is_pattern2_config(paramdef_t *param) return true; } -static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cfg, int minRXTXTIME) +static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cfg, int minRXTXTIME, int do_SRS) { NR_ServingCellConfigCommon_t *scc = calloc_or_fail(1, sizeof(*scc)); uint64_t ssb_bitmap=0xff; @@ -1149,10 +981,6 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf struct NR_TDD_UL_DL_ConfigCommon *tdd = scc->tdd_UL_DL_ConfigurationCommon; tdd->pattern2 = calloc_or_fail(1, sizeof(*tdd->pattern2)); *scc->tdd_UL_DL_ConfigurationCommon->pattern2 = p2; - AssertFatal(p2.nrofUplinkSlots ^ scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots, - "UL slots in pattern1 (%ld) and pattern2 (%ld) are mutually exclusive (e.g. DDDFUU DDDD, DDDD DDDFUU)\n", - scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots, - p2.nrofUplinkSlots); } struct NR_FrequencyInfoDL *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL; LOG_I(RRC, @@ -1174,7 +1002,7 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf check_ssb_raster(ssb_freq, *frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing); fix_scc(scc, ssb_bitmap); } - nr_rrc_config_ul_tda(scc, minRXTXTIME); + nr_rrc_config_ul_tda(scc, minRXTXTIME, do_SRS); // the gNB uses the servingCellConfigCommon everywhere, even when it should use the servingCellConfigCommonSIB. // previously (before this commit), the following fields were indirectly populated through get_SIB1_NR(). @@ -1188,15 +1016,9 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf // TODO: Make CSS aggregation levels configurable int css_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; css_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; - if (get_softmodem_params()->usim_test) { - css_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; - css_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1; - css_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n1; - } else { - css_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; - css_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n2; - css_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; - } + css_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; + css_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n2; + css_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; css_num_agg_level_candidates[PDCCH_AGG_LEVEL16] = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; NR_SearchSpace_t *ss1 = rrc_searchspace_config(true, 1, 0, css_num_agg_level_candidates); @@ -1214,39 +1036,6 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf return scc; } -static NR_ServingCellConfig_t *get_scd_config(configmodule_interface_t *cfg) -{ - NR_ServingCellConfig_t *scd = calloc(1, sizeof(*scd)); - prepare_scd(scd); - - char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - GET_PARAMS_LIST(SCDsParamList, SCDsParams, SCDPARAMS_DESC(scd), GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, aprefix); - - if (SCDsParamList.numelt > 0) { - snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, 0); - GET_PARAMS(SCDsParams, SCDPARAMS_DESC(scd), aprefix); - const NR_BWP_UplinkDedicated_t *bwp_Dedicated = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated; - const NR_PTRS_UplinkConfig_t *setup = - bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup; - LOG_I(RRC, - "Read in ServingCellConfigDedicated UL (FreqDensity_0 %ld, FreqDensity_1 %ld, TimeDensity_0 %ld, TimeDensity_1 %ld, " - "TimeDensity_2 %ld, RE offset %ld, First_active_BWP_ID %ld SCS %ld, LocationandBW %ld\n", - *setup->transformPrecoderDisabled->frequencyDensity->list.array[0], - *setup->transformPrecoderDisabled->frequencyDensity->list.array[1], - *setup->transformPrecoderDisabled->timeDensity->list.array[0], - *setup->transformPrecoderDisabled->timeDensity->list.array[1], - *setup->transformPrecoderDisabled->timeDensity->list.array[2], - *setup->transformPrecoderDisabled->resourceElementOffset, - *scd->firstActiveDownlinkBWP_Id, - scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.subcarrierSpacing, - scd->downlinkBWP_ToAddModList->list.array[0]->bwp_Common->genericParameters.locationAndBandwidth); - } - fix_scd(scd); - - return scd; -} - static int read_du_cell_info(configmodule_interface_t *cfg, bool separate_du, uint32_t *gnb_id, @@ -1418,6 +1207,49 @@ static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id, return req; } +static nr_ptrs_config_t *get_ptrs_config(int gnb_idx) +{ + char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; + snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + GET_PARAMS_LIST(ptrs_ParamsList, ptrs_Params, GNB_PTRS_PARAMS_DESC, GNB_CONFIG_STRING_PTRS, aprefix); + if (ptrs_ParamsList.numelt == 0) { + LOG_I(GNB_APP, "No PTRS configuration found\n"); + return NULL; + } + nr_ptrs_config_t *ptrs = calloc_or_fail(1, sizeof(*ptrs)); + ptrs->dl_FreqDensity0_0 = *ptrs_ParamsList.paramarray[0][GNB_DLPTRSFREQDENSITY0_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: dl_FreqDensity0_0 %d\n", ptrs->dl_FreqDensity0_0); + ptrs->dl_FreqDensity1_0 = *ptrs_ParamsList.paramarray[0][GNB_DLPTRSFREQDENSITY1_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: dl_FreqDensity1_0 %d\n", ptrs->dl_FreqDensity1_0); + ptrs->dl_TimeDensity0_0 = *ptrs_ParamsList.paramarray[0][GNB_DLPTRSTIMEDENSITY0_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: dl_TimeDensity0_0 %d\n", ptrs->dl_TimeDensity0_0); + ptrs->dl_TimeDensity1_0 = *ptrs_ParamsList.paramarray[0][GNB_DLPTRSTIMEDENSITY1_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: dl_TimeDensity1_0 %d\n", ptrs->dl_TimeDensity1_0); + ptrs->dl_TimeDensity2_0 = *ptrs_ParamsList.paramarray[0][GNB_DLPTRSTIMEDENSITY2_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: dl_TimeDensity2_0 %d\n", ptrs->dl_TimeDensity2_0); + ptrs->dl_EpreRatio_0 = *ptrs_ParamsList.paramarray[0][GNB_DLPTRSEPRERATIO_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: dl_EpreRatio_0 %d\n", ptrs->dl_EpreRatio_0); + ptrs->dl_ReOffset_0 = *ptrs_ParamsList.paramarray[0][GNB_DLPTRSREOFFSET_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: dl_ReOffset_0 %d\n", ptrs->dl_ReOffset_0); + ptrs->ul_FreqDensity0_0 = *ptrs_ParamsList.paramarray[0][GNB_ULPTRSFREQDENSITY0_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: ul_FreqDensity0_0 %d\n", ptrs->ul_FreqDensity0_0); + ptrs->ul_FreqDensity1_0 = *ptrs_ParamsList.paramarray[0][GNB_ULPTRSFREQDENSITY1_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: ul_FreqDensity1_0 %d\n", ptrs->ul_FreqDensity1_0); + ptrs->ul_TimeDensity0_0 = *ptrs_ParamsList.paramarray[0][GNB_ULPTRSTIMEDENSITY0_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: ul_TimeDensity0_0 %d\n", ptrs->ul_TimeDensity0_0); + ptrs->ul_TimeDensity1_0 = *ptrs_ParamsList.paramarray[0][GNB_ULPTRSTIMEDENSITY1_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: ul_TimeDensity1_0 %d\n", ptrs->ul_TimeDensity1_0); + ptrs->ul_TimeDensity2_0 = *ptrs_ParamsList.paramarray[0][GNB_ULPTRSTIMEDENSITY2_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: ul_TimeDensity2_0 %d\n", ptrs->ul_TimeDensity2_0); + ptrs->ul_ReOffset_0 = *ptrs_ParamsList.paramarray[0][GNB_ULPTRSREOFFSET_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: ul_ReOffset_0 %d\n", ptrs->ul_ReOffset_0); + ptrs->ul_MaxPorts_0 = *ptrs_ParamsList.paramarray[0][GNB_ULPTRSMAXPORTS_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: ul_MaxPorts_0 %d\n", ptrs->ul_MaxPorts_0); + ptrs->ul_Power_0 = *ptrs_ParamsList.paramarray[0][GNB_ULPTRSPOWER_0_IDX].iptr; + LOG_I(GNB_APP, "PTRS configuration: ul_Power_0 %d\n", ptrs->ul_Power_0); + return ptrs; +} + static nr_redcap_config_t *get_redcap_config(int gnb_idx) { paramdef_t RedCap_Params[] = GNB_REDCAP_PARAMS_DESC; @@ -1432,7 +1264,7 @@ static nr_redcap_config_t *get_redcap_config(int gnb_idx) // Check for default/non-existing values in configuration file if (*RedCap_Params[GNB_REDCAP_CELL_BARRED_REDCAP1_RX_R17_IDX].i8ptr == -1 || *RedCap_Params[GNB_REDCAP_CELL_BARRED_REDCAP2_RX_R17_IDX].i8ptr == -1) { - LOG_I(NR_MAC, "No RedCap configuration found\n"); + LOG_I(GNB_APP, "No RedCap configuration found\n"); return NULL; } @@ -1454,7 +1286,8 @@ static seq_arr_t *fill_du_sibs(paramdef_t *GNBparamarray) if (NODE_IS_DU(get_node_type())) AssertFatal(GNBparamarray[GNB_CU_SIBS_IDX].numelt == 0, "This is DU, do not input CU SIBs\n"); - if (!config_isparamset(GNBparamarray, GNB_DU_SIBS_IDX)) + // TODO config_isparamset doesn't seem to work for array types, checking numelt instead + if (GNBparamarray[GNB_DU_SIBS_IDX].numelt == 0) return NULL; seq_arr_t *du_SIBs = malloc(sizeof(seq_arr_t)); @@ -1511,7 +1344,7 @@ void config_rlc(configmodule_interface_t *cfg, nr_rlc_configuration_t *rlc_confi rlc_config->drb_um.sn_field_length = config_get_processedint(cfg, &rlc_drb_um_params[CONFIG_NR_RLC_DRB_UM_SN_FIELD_LENGTH_IDX]); } -void config_pdcp(configmodule_interface_t *cfg, nr_pdcp_configuration_t *pdcp_config) +static void config_pdcp(configmodule_interface_t *cfg, nr_pdcp_configuration_t *pdcp_config) { /* DRB configuration */ paramdef_t pdcp_params[] = NR_PDCP_DRB_GLOBALPARAMS_DESC; @@ -1523,6 +1356,31 @@ void config_pdcp(configmodule_interface_t *cfg, nr_pdcp_configuration_t *pdcp_co pdcp_config->drb.discard_timer = config_get_processedint(cfg, &pdcp_params[CONFIG_NR_PDCP_DRB_DISCARD_TIMER_IDX]); } +static void get_bwp_config(nr_mac_config_t *configuration) +{ + char path[MAX_OPTNAME_SIZE * 2 + 8]; + snprintf(path, sizeof(path), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + GET_PARAMS_LIST(BWPParamList, BWPParams, GNBBWPPARAMS_DESC, GNB_CONFIG_STRING_BWP_LIST, path, BWPPARAMS_CHECK); + configuration->num_additional_bwps = BWPParamList.numelt; + AssertFatal(configuration->num_additional_bwps >= 0 && configuration->num_additional_bwps <= 4, + "Invalid number of additional BWPs %d\n", + configuration->num_additional_bwps); + for (int i = 0; i < configuration->num_additional_bwps; i++) { + configuration->bwp_config[i].id = i + 1; + int bwp_start = *BWPParamList.paramarray[i][GNB_BWP_START_IDX].iptr; + int bwp_size = *BWPParamList.paramarray[i][GNB_BWP_SIZE_IDX].iptr; + configuration->bwp_config[i].location_and_bw = PRBalloc_to_locationandbandwidth(bwp_size, bwp_start); + configuration->bwp_config[i].scs = *BWPParamList.paramarray[i][GNB_BWP_SCS_IDX].iptr; + LOG_I(GNB_APP, + "BWP %d, start PRB %d size %d locationandbandwidth %d, scs %d\n", + configuration->bwp_config[i].id, + bwp_start, + bwp_size, + configuration->bwp_config[i].location_and_bw, + configuration->bwp_config[i].scs); + } +} + void RCconfig_nr_macrlc(configmodule_interface_t *cfg) { int j = 0; @@ -1548,6 +1406,12 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.pdsch_AntennaPorts.XP, config.pusch_AntennaPorts); + // BWP + get_bwp_config(&config); + AssertFatal(config.num_additional_bwps <= 4, "Impossible to configure more than 4 additional BWPs\n"); + config.first_active_bwp = *GNBParamList.paramarray[0][GNB_1ST_ACTIVE_BWP_IDX].iptr; + AssertFatal(config.first_active_bwp <= config.num_additional_bwps, "1st active BWP does not belog to the configured BWPs\n"); + // RU GET_PARAMS_LIST(RUParamList, RUParams, RUPARAMS_DESC, CONFIG_STRING_RU_LIST, NULL); int num_tx = 0; @@ -1556,8 +1420,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) num_tx += *(RUParamList.paramarray[i][RU_NB_TX_IDX].uptr); AssertFatal(num_tx >= config.pdsch_AntennaPorts.XP * config.pdsch_AntennaPorts.N1 * config.pdsch_AntennaPorts.N2, "Number of logical antenna ports (set in config file with pdsch_AntennaPorts) cannot be larger than physical antennas (nb_tx)\n"); - } - else { + } else { // TODO temporary solution for 3rd party RU or nFAPI, in which case we don't have RU section present in the config file num_tx = config.pdsch_AntennaPorts.XP * config.pdsch_AntennaPorts.N1 * config.pdsch_AntennaPorts.N2; LOG_E(GNB_APP, "RU information not present in config file. Assuming physical antenna ports equal to logical antenna ports %d\n", num_tx); @@ -1568,6 +1431,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) LOG_I(GNB_APP, "SIB1 TDA %d\n", config.sib1_tda); config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr; config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr; + config.max_num_rsrp = *GNBParamList.paramarray[0][GNB_LIMIT_RSRP_REPORT_IDX].iptr; config.do_SINR = *GNBParamList.paramarray[0][GNB_DO_SINR_IDX].iptr; config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr; config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr; @@ -1593,6 +1457,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) AssertFatal(config.maxMIMO_layers != 0 && config.maxMIMO_layers <= tot_ant, "Invalid maxMIMO_layers %d\n", config.maxMIMO_layers); config.redcap = get_redcap_config(0); + config.ptrs = get_ptrs_config(0); char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_TIMERS_CONFIG); @@ -1625,15 +1490,9 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) // Construct default aggragation level list or read from config int uess_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; uess_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; - if (get_softmodem_params()->usim_test) { - uess_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; - uess_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1; - uess_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n1; - } else { - uess_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n2; - uess_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n0; - uess_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; - } + uess_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n2; + uess_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n0; + uess_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; uess_num_agg_level_candidates[PDCCH_AGG_LEVEL16] = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; int* agg_level_list = uess_num_agg_level_candidates; int num_agg_levels = 5; @@ -1650,9 +1509,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.num_agg_level_candidates[PDCCH_AGG_LEVEL8], config.num_agg_level_candidates[PDCCH_AGG_LEVEL16]); - NR_ServingCellConfigCommon_t *scc = get_scc_config(cfg, config.minRXTXTIME); + NR_ServingCellConfigCommon_t *scc = get_scc_config(cfg, config.minRXTXTIME, config.do_SRS); //xer_fprint(stdout, &asn_DEF_NR_ServingCellConfigCommon, scc); - NR_ServingCellConfig_t *scd = get_scd_config(cfg); if (MacRLC_ParamList.numelt > 0) { /* NR RLC config is needed by mac_top_init_gNB() */ @@ -1660,7 +1518,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config_rlc(cfg, &default_rlc_config); ngran_node_t node_type = get_node_type(); - mac_top_init_gNB(node_type, scc, scd, &config, &default_rlc_config); + mac_top_init_gNB(node_type, scc, &config, &default_rlc_config); RC.nb_nr_mac_CC = (int *)malloc(RC.nb_nr_macrlc_inst * sizeof(int)); for (j = 0; j < RC.nb_nr_macrlc_inst; j++) { @@ -1708,15 +1566,15 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) RC.nrmac[j]->eth_params_s.remote_portd = *(MacRLC_ParamList.paramarray[j][MACRLC_REMOTE_S_PORTD_IDX].iptr); RC.nrmac[j]->eth_params_s.transp_preference = ETH_UDP_MODE; - configure_nr_nfapi_vnf( - RC.nrmac[j]->eth_params_s.my_addr, RC.nrmac[j]->eth_params_s.my_portc, RC.nrmac[j]->eth_params_s.remote_addr, RC.nrmac[j]->eth_params_s.remote_portd, RC.nrmac[j]->eth_params_s.my_portd); + configure_nr_nfapi_vnf(RC.nrmac[j]->eth_params_s); } else if(strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "aerial") == 0){ #ifdef ENABLE_AERIAL RC.nrmac[j]->nvipc_params_s.nvipc_shm_prefix = strdup(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_SHM_PREFIX].strptr)); RC.nrmac[j]->nvipc_params_s.nvipc_poll_core = *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_POLL_CORE].i8ptr); LOG_I(GNB_APP, "Configuring VNF for Aerial connection with prefix %s\n", RC.nrmac[j]->eth_params_s.local_if_name); - aerial_configure_nr_fapi_vnf(); + configure_nr_nfapi_vnf(RC.nrmac[j]->eth_params_s); + #endif } else { // other midhaul AssertFatal(1 == 0, "MACRLC %d: %s unknown southbound midhaul\n", j, *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); @@ -1749,22 +1607,27 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) LOG_I(NR_PHY, "Copying %d blacklisted PRB to L1 context\n", num_ulprbbl); memcpy(RC.nrmac[j]->ulprbbl, prbbl, MAX_BWP_SIZE * sizeof(prbbl[0])); } - bool ab = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMFORMING_IDX].u8ptr; - if (ab) { - AssertFatal(NFAPI_MODE == NFAPI_MONOLITHIC, "Analog beamforming only supported for monolithic scenario\n"); + int ab = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMFORMING_IDX].u8ptr; + if (ab > 0) { + if (ab == 1) + AssertFatal(NFAPI_MODE == NFAPI_MONOLITHIC, "Analog beamforming only supported for monolithic scenario\n"); NR_beam_info_t *beam_info = &RC.nrmac[j]->beam_info; int beams_per_period = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMS_PERIOD_IDX].u8ptr; beam_info->beam_allocation = malloc16(beams_per_period * sizeof(int *)); beam_info->beam_duration = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAM_DURATION_IDX].u8ptr; beam_info->beams_per_period = beams_per_period; beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration + beam_info->beam_mode = ab == 1 ? PRECONFIGURED_BEAM_IDX : LOPHY_BEAM_IDX; + } else { + RC.nrmac[j]->beam_info.beam_mode = NO_BEAM_MODE; } - if (config_isparamset(MacRLC_ParamList.paramarray[j], MACRLC_BEAMWEIGHTS_IDX)) { + // TODO config_isparamset doesn't seem to work for array types, checking numelt instead + int n = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].numelt; + if (n > 0) { if (NFAPI_MODE == NFAPI_MONOLITHIC) { GET_PARAMS_LIST(L1_ParamList, L1_Params, L1PARAMS_DESC, CONFIG_STRING_L1_LIST, NULL); AssertFatal(*(L1_ParamList.paramarray[j][L1_ANALOG_DAS].uptr) == 0, "No need to set beam weights in case of DAS\n"); } - int n = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].numelt; int num_beam = n; if (!ab) { AssertFatal(n % num_tx == 0, "Error! Number of beam input needs to be multiple of TX antennas\n"); @@ -1949,7 +1812,8 @@ static seq_arr_t *fill_cu_sibs(paramdef_t *GNBparamarray) if (NODE_IS_CU(get_node_type())) AssertFatal(GNBparamarray[GNB_DU_SIBS_IDX].numelt == 0, "This is CU, do not input DU SIBs\n"); - if (!config_isparamset(GNBparamarray, GNB_CU_SIBS_IDX)) + // TODO config_isparamset doesn't seem to work for array types, checking numelt instead + if (GNBparamarray[GNB_CU_SIBS_IDX].numelt == 0) return NULL; seq_arr_t *SIBs = malloc(sizeof(seq_arr_t)); @@ -1997,20 +1861,21 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNBNEIGHBOURCELLPARAMS_DESC, GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, neighbourpath); - LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell.nr_cell_id, NeighbourCellParamList.numelt); + LOG_I(GNB_APP, "Cell %ld has %d neighbours\n", cell.nr_cell_id, NeighbourCellParamList.numelt); if (NeighbourCellParamList.numelt < 1) continue; cell.neighbour_cells = malloc_or_fail(sizeof(seq_arr_t)); seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_cell_t)); for (int l = 0; l < NeighbourCellParamList.numelt; ++l) { - nr_neighbour_cell_t neighbourCell = {0}; - neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); - neighbourCell.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); - neighbourCell.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; - neighbourCell.subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr; - neighbourCell.absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr; - neighbourCell.tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; + nr_neighbour_cell_t n = {0}; + n.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); + n.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); + n.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; + n.subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr; + n.band = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_BAND_IDX].uptr; + n.absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr; + n.tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; char neighbour_plmn_path[CONFIG_MAXOPTLENGTH]; snprintf(neighbour_plmn_path, @@ -2022,10 +1887,22 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNB_CONFIG_STRING_NEIGHBOUR_PLMN); GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path); - neighbourCell.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - neighbourCell.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; - neighbourCell.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; - seq_arr_push_back(cell.neighbour_cells, &neighbourCell, sizeof(neighbourCell)); + n.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + n.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; + n.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; + seq_arr_push_back(cell.neighbour_cells, &n, sizeof(n)); + LOG_I(GNB_APP, + " [%d] neighbor ID %d cellId %ld PCI %d SCS %d SSB ARFCN %u TAC %u PLMN %03u.%0*u\n", + l, + n.gNB_ID, + n.nrcell_id, + n.physicalCellId, + n.subcarrierSpacing, + n.absoluteFrequencySSB, + n.tac, + n.plmn.mcc, + n.plmn.mnc_digit_length, + n.plmn.mnc); } seq_arr_push_back(rrc->neighbour_cell_configuration, &cell, sizeof(cell)); } diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index db04c5a8da..e4e4bc3d2a 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -49,9 +49,6 @@ #define GNB_CONF_STRING_OTG_APP_TYPE "app_type" #define GNB_CONF_STRING_OTG_BG_TRAFFIC "bg_traffic" -extern int asn_debug; -extern int asn1_xer_print; - #ifdef LIBCONFIG_LONG #define libconfig_int long #else @@ -141,6 +138,8 @@ typedef enum { #define GNB_CONFIG_STRING_CU_SIB_LIST "cu_sibs" #define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs" #define GNB_CONFIG_STRING_DOSINR "do_SINR" +#define GNB_CONFIG_STRING_1ST_ACTIVE_BWP "first_active_bwp" +#define GNB_CONFIG_STRING_LIMIT_RSRP_REPORT "max_num_RSRP_reported" #define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n" #define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support" @@ -156,6 +155,7 @@ typedef enum { #define GNB_CONFIG_HLP_DU_SIBS "List of DU generated SIBs to be transmitted" #define GNB_CONFIG_HLP_DOSINR "Enable CSI feedback using SINR measurements on SSB" + /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* cell configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -202,6 +202,8 @@ typedef enum { {GNB_CONFIG_STRING_CU_SIB_LIST, GNB_CONFIG_HLP_CU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_DU_SIB_LIST, GNB_CONFIG_HLP_DU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_DOSINR, GNB_CONFIG_HLP_DOSINR, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_1ST_ACTIVE_BWP, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_LIMIT_RSRP_REPORT, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ } // clang-format on @@ -245,6 +247,8 @@ typedef enum { #define GNB_CU_SIBS_IDX 36 #define GNB_DU_SIBS_IDX 37 #define GNB_DO_SINR_IDX 38 +#define GNB_1ST_ACTIVE_BWP_IDX 39 +#define GNB_LIMIT_RSRP_REPORT_IDX 40 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32} @@ -290,9 +294,34 @@ typedef enum { { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ + +#define GNB_CONFIG_STRING_BWP_LIST "bwp_list" + +#define GNB_CONFIG_STRING_BWP_SCS "scs" +#define GNB_CONFIG_STRING_BWP_START "bwpStart" +#define GNB_CONFIG_STRING_BWP_SIZE "bwpSize" + +#define GNB_BWP_SCS_IDX 0 +#define GNB_BWP_START_IDX 1 +#define GNB_BWP_SIZE_IDX 2 + +#define GNBBWPPARAMS_DESC { \ + {GNB_CONFIG_STRING_BWP_SCS, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INT, 0}, \ + {GNB_CONFIG_STRING_BWP_START, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INT, 0}, \ + {GNB_CONFIG_STRING_BWP_SIZE, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INT, 0}, \ +} + +#define BWPPARAMS_CHECK { \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ +} + /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ /* Neighbour Cell Configurations*/ @@ -311,6 +340,7 @@ typedef enum { #define GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID "physical_cellId" #define GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB "absoluteFrequencySSB" #define GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS "subcarrierSpacing" +#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_BAND "band" #define GNB_CONFIG_STRING_NEIGHBOUR_TRACKING_ARE_CODE "tracking_area_code" #define GNB_CONFIG_STRING_NEIGHBOUR_PLMN "plmn" @@ -319,7 +349,8 @@ typedef enum { #define GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX 2 #define GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX 3 #define GNB_CONFIG_N_CELL_SCS_IDX 4 -#define GNB_CONFIG_N_CELL_TAC_IDX 5 +#define GNB_CONFIG_N_CELL_BAND_IDX 5 +#define GNB_CONFIG_N_CELL_TAC_IDX 6 // clang-format off #define GNBNEIGHBOURCELLPARAMS_DESC { \ /* optname helpstr paramflags XXXptr def val type numelt */ \ @@ -328,6 +359,7 @@ typedef enum { {GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID, "neighbour cell physical id", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ {GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB, "neighbour cell abs freq ssb", PARAMFLAG_MANDATORY, .i64ptr=NULL, .defint64val=0, TYPE_INT64, 0}, \ {GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS, "neighbour cell scs", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_CELL_BAND, "neighbour cell band", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=78, TYPE_UINT, 0}, \ {GNB_CONFIG_STRING_NEIGHBOUR_TRACKING_ARE_CODE, "neighbour cell tracking area", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ } // clang-format on @@ -519,6 +551,60 @@ typedef enum { #define GNB_REDCAP_CELL_BARRED_REDCAP2_RX_R17_IDX 1 #define GNB_REDCAP_INTRA_FREQ_RESELECTION_REDCAP_R17_IDX 2 +/*-------------------------------------------------------------------------------------------------------------------------------------*/ +/* PTRS configuration parameters */ +/*-------------------------------------------------------------------------------------------------------------------------------------*/ + +#define GNB_CONFIG_STRING_PTRS "phaseTrackingRS" +#define GNB_CONFIG_STRING_DLPTRSFREQDENSITY0_0 "dl_ptrsFreqDensity0_0" +#define GNB_CONFIG_STRING_DLPTRSFREQDENSITY1_0 "dl_ptrsFreqDensity1_0" +#define GNB_CONFIG_STRING_DLPTRSTIMEDENSITY0_0 "dl_ptrsTimeDensity0_0" +#define GNB_CONFIG_STRING_DLPTRSTIMEDENSITY1_0 "dl_ptrsTimeDensity1_0" +#define GNB_CONFIG_STRING_DLPTRSTIMEDENSITY2_0 "dl_ptrsTimeDensity2_0" +#define GNB_CONFIG_STRING_DLPTRSEPRERATIO_0 "dl_ptrsEpreRatio_0" +#define GNB_CONFIG_STRING_DLPTRSREOFFSET_0 "dl_ptrsReOffset_0" +#define GNB_CONFIG_STRING_ULPTRSFREQDENSITY0_0 "ul_ptrsFreqDensity0_0" +#define GNB_CONFIG_STRING_ULPTRSFREQDENSITY1_0 "ul_ptrsFreqDensity1_0" +#define GNB_CONFIG_STRING_ULPTRSTIMEDENSITY0_0 "ul_ptrsTimeDensity0_0" +#define GNB_CONFIG_STRING_ULPTRSTIMEDENSITY1_0 "ul_ptrsTimeDensity1_0" +#define GNB_CONFIG_STRING_ULPTRSTIMEDENSITY2_0 "ul_ptrsTimeDensity2_0" +#define GNB_CONFIG_STRING_ULPTRSREOFFSET_0 "ul_ptrsReOffset_0" +#define GNB_CONFIG_STRING_ULPTRSMAXPORTS_0 "ul_ptrsMaxPorts_0" +#define GNB_CONFIG_STRING_ULPTRSPOWER_0 "ul_ptrsPower_0" + +#define GNB_PTRS_PARAMS_DESC { \ +{GNB_CONFIG_STRING_DLPTRSFREQDENSITY0_0, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_DLPTRSFREQDENSITY1_0, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_DLPTRSTIMEDENSITY0_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_DLPTRSTIMEDENSITY1_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_DLPTRSTIMEDENSITY2_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_DLPTRSEPRERATIO_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_DLPTRSREOFFSET_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPTRSFREQDENSITY0_0, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPTRSFREQDENSITY1_0, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPTRSTIMEDENSITY0_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPTRSTIMEDENSITY1_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPTRSTIMEDENSITY2_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPTRSREOFFSET_0, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPTRSMAXPORTS_0, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ +{GNB_CONFIG_STRING_ULPTRSPOWER_0, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}} + +#define GNB_DLPTRSFREQDENSITY0_0_IDX 0 +#define GNB_DLPTRSFREQDENSITY1_0_IDX 1 +#define GNB_DLPTRSTIMEDENSITY0_0_IDX 2 +#define GNB_DLPTRSTIMEDENSITY1_0_IDX 3 +#define GNB_DLPTRSTIMEDENSITY2_0_IDX 4 +#define GNB_DLPTRSEPRERATIO_0_IDX 5 +#define GNB_DLPTRSREOFFSET_0_IDX 6 +#define GNB_ULPTRSFREQDENSITY0_0_IDX 7 +#define GNB_ULPTRSFREQDENSITY1_0_IDX 8 +#define GNB_ULPTRSTIMEDENSITY0_0_IDX 9 +#define GNB_ULPTRSTIMEDENSITY1_0_IDX 10 +#define GNB_ULPTRSTIMEDENSITY2_0_IDX 11 +#define GNB_ULPTRSREOFFSET_0_IDX 12 +#define GNB_ULPTRSMAXPORTS_0_IDX 13 +#define GNB_ULPTRSPOWER_0_IDX 14 + /*---------------------------------------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------------------------------------*/ /* SCTP configuration parameters section name */ diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c index 216ab788d3..1fe2b6967b 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c @@ -1635,6 +1635,7 @@ schedule_ulsch_rnti(module_id_t module_idP, T_INT(subframeP), T_INT(harq_pid), T_INT(mcs), + T_INT(UE_template_ptr->pre_first_nb_rb_ul), T_INT(rb_table[rb_table_index]), T_INT(UE_template_ptr->TBS_UL[harq_pid]), T_INT(ndi)); diff --git a/openair2/LAYER2/MAC/main_ue.c b/openair2/LAYER2/MAC/main_ue.c index bed2aa5b09..324668b981 100644 --- a/openair2/LAYER2/MAC/main_ue.c +++ b/openair2/LAYER2/MAC/main_ue.c @@ -46,8 +46,6 @@ #include #include "executables/softmodem-common.h" -extern void openair_rrc_top_init_ue( int eMBMS_active, char *uecap_xer, uint8_t cba_group_active, uint8_t HO_active); - void dl_phy_sync_success(module_id_t module_idP, frame_t frameP, unsigned char eNB_index, uint8_t first_sync) { //init as MR LOG_D(MAC, "[UE %d] Frame %d: PHY Sync to eNB_index %d successful \n", module_idP, frameP, eNB_index); diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index fced846a3c..69beaa7281 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -2460,8 +2460,7 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP, && (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { // Workaround for issue in OAI eNB or EPC which are not able to process SRB2 message multiplexed with SRB1 on the same MAC PDU - if (( get_softmodem_params()->usim_test == 0) && (lcid == DCCH1) - && (lcid_rlc_pdu_count == 0) && (num_sdus)) { + if ((lcid == DCCH1) && (lcid_rlc_pdu_count == 0) && (num_sdus)) { // Skip SRB2 multiplex if at least one SRB1 SDU is already multiplexed break; } diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c index 96819378f0..1643d4e732 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c @@ -59,6 +59,11 @@ uint32_t nr_compute_tbs(uint16_t Qm, tb_scaling, Nl); + if (Qm == 0 || R == 0 || nb_rb == 0 || Nl == 0) { + LOG_E(NR_MAC, "Error in compute TBS with a NULL input, returning NULL TBS\n"); + return 0; + } + const int nb_subcarrier_per_rb = 12; const uint32_t nbp_re = nb_subcarrier_per_rb * nb_symb_sch - nb_dmrs_prb - nb_rb_oh; const uint32_t nb_re = min(156, nbp_re) * nb_rb; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 68182ab9ec..6e73a0f855 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -320,35 +320,6 @@ typedef struct { uint8_t nbits; } dci_field_t; -typedef struct { - /* The active harq sfn/slot field was created to save the - scheduled SFN/Slot transmission for the ACK/NAK. If we - do not save it, then we have to calculate it again as the - NRUE MAC layer already does in get_downlink_ack(). */ - int active_dl_harq_sfn; - int active_dl_harq_slot; - int active_ul_harq_sfn; - int active_ul_harq_slot; - bool active; -} emul_l1_harq_t; - -typedef struct { - bool expected_sib; - bool index_has_sib[NR_MAX_HARQ_PROCESSES]; - bool expected_rar; - bool index_has_rar[NR_MAX_HARQ_PROCESSES]; - bool expected_dci; - bool index_has_dci[NR_MAX_HARQ_PROCESSES]; - emul_l1_harq_t harq[NR_MAX_HARQ_PROCESSES]; - int active_uci_sfn_slot; - int num_srs; - int num_harqs; - int num_csi_reports; - uint8_t pmi; - uint8_t ri; - uint8_t cqi; -} nr_emulated_l1_t; - typedef struct { uint8_t format_indicator; //1 bit diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index b435e9e265..1a5431bdd2 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -1972,49 +1972,6 @@ static const int32_t table_6_4_1_1_3_4_pusch_dmrs_positions_l[12][8] = { {0, 3072, -1, -1, 3, 1539, -1, -1}, // 14 // (DMRS l' position) }; -// TS 38.212 -static const uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; -static const uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, - 25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55}; -static const uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59}; -static const uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61}; -static const uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25}; -static const uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32}; -static const uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33}; -static const uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35}; -static const uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22}; -static const uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29}; -static const uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15}; -static const uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6}; -static const uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8}; -static const uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3}; -static const uint16_t table_7_3_1_1_2_28[3][15] = { - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -}; -static const uint16_t table_7_3_1_1_2_29[3][15] = { - {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0}, -}; -static const uint16_t table_7_3_1_1_2_30[3][15] = { - {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0}, -}; -static const uint16_t table_7_3_1_1_2_31[3][15] = { - {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, -}; -static const uint16_t table_7_3_1_1_2_32[3][15] = { - {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -}; - // the following tables contain 10 times the value reported in 214 (in line with SCF specification and to avoid fractional values) //Table 5.1.3.1-1 of 38.214 static const uint16_t Table_51311[32][2] = {{2, 1200}, {2, 1570}, {2, 1930}, {2, 2510}, {2, 3080}, {2, 3790}, {2, 4490}, {2, 5260}, @@ -2503,61 +2460,61 @@ static int binomial(int n, int k) return c; } +int srs_codebook_nb_res(NR_SRS_Config_t *srs_config) +{ + int count = 0; + for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) { + if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook) + count++; + } + return count; +} + +int srs_non_codebook_nb_res(NR_SRS_Config_t *srs_config) +{ + int count = 0; + for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) { + if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook) + count++; + } + return count; +} + +int srs_binomial_sum(int count, int Lmax) +{ + int lmin = 0; + int lsum = 0; + lmin = count < Lmax ? count : Lmax; + for (int k = 1; k <= lmin; k++) + lsum += binomial(count, k); + return lsum; +} + // #define DEBUG_SRS_RESOURCE_IND -uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers, - NR_PUSCH_Config_t *pusch_Config, - NR_SRS_Config_t *srs_config, - nr_srs_feedback_t *srs_feedback, - uint32_t *val) + +static uint8_t compute_srs_resource_indicator_size(long *maxMIMO_Layers, NR_PUSCH_Config_t *pusch_Config, NR_SRS_Config_t *srs_config) { uint8_t nbits = 0; - - // SRI occupies a number of bits which is dependent upon the uplink transmission scheme, and it is used to determine - // the antenna ports and uplink transmission beam to use for PUSCH transmission. In the case of codebook based - // transmission, the SRI is used to select between SRS Resources belonging to different antenna panels - // (kind of directional antenna). There can be up to 2 SRS Resources (2 antenna panels). In the case of non-codebook - // based transmission, the SRI is used to select one or more SRS Resources from a set of N_SRS resources. The number - // of SRS Resources selected corresponds to the number of layers (rank) to be transmitted. - if (val) { - *val = 0; - } - if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) { - if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) { - #ifdef DEBUG_SRS_RESOURCE_IND LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_codebook\n"); #endif - // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to // Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook, // where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer // parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook. - int count = 0; - for (int i=0; isrs_ResourceSetToAddModList->list.count; i++) { - if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_codebook) { - count++; - } - } - if (count>0) { + int count = srs_codebook_nb_res(srs_config); + if (count > 0) nbits = ceil(log2(count)); - if (val && srs_feedback && count > 1) { - *val = table_7_3_1_1_2_32[count-2][srs_feedback->sri]; - } - } - #ifdef DEBUG_SRS_RESOURCE_IND LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count); LOG_I(NR_MAC, "count = %i\n", count); #endif - } else { - #ifdef DEBUG_SRS_RESOURCE_IND LOG_I(NR_MAC, "*pusch_Config->txConfig = NR_PUSCH_Config__txConfig_nonCodebook\n"); #endif - // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k)))) // bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where // N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter @@ -2572,68 +2529,29 @@ uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers, if (maxMIMO_Layers != NULL) Lmax = *maxMIMO_Layers; else - AssertFatal(1 == 0, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); - int lmin = 0; - int lsum = 0; - int count = 0; - for (int i = 0; i < srs_config->srs_ResourceSetToAddModList->list.count; i++) { - if (srs_config->srs_ResourceSetToAddModList->list.array[i]->usage == NR_SRS_ResourceSet__usage_nonCodebook) { - count++; - } - } - lmin = count < Lmax ? count : Lmax; - for (int k=1;k<=lmin;k++) { - lsum += binomial(count,k); - } - if (lsum>0) { + AssertFatal(false, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); + int count = srs_non_codebook_nb_res(srs_config); + int lsum = srs_binomial_sum(count, Lmax); + if (lsum > 0) nbits = ceil(log2(lsum)); - if (val && srs_feedback && nbits > 0) { - switch(Lmax) { - case 1: - *val = table_7_3_1_1_2_28[count-2][srs_feedback->sri]; - break; - case 2: - *val = table_7_3_1_1_2_29[count-2][srs_feedback->sri]; - break; - case 3: - *val = table_7_3_1_1_2_30[count-2][srs_feedback->sri]; - break; - case 4: - *val = table_7_3_1_1_2_31[count-2][srs_feedback->sri]; - break; - default: - LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax); - } - } - } - #ifdef DEBUG_SRS_RESOURCE_IND LOG_I(NR_MAC, "srs_config->srs_ResourceSetToAddModList->list.count = %i\n", srs_config->srs_ResourceSetToAddModList->list.count); LOG_I(NR_MAC, "count = %i\n", count); LOG_I(NR_MAC, "Lmax = %i\n", Lmax); LOG_I(NR_MAC, "lsum = %i\n", lsum); #endif - } } - return nbits; } -uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, - NR_SRS_Config_t *srs_config, - dci_field_t srs_resource_indicator, - nr_srs_feedback_t *srs_feedback, - const uint8_t *nrOfLayers, - int *tpmi, - uint32_t *val) +static uint8_t compute_precoding_info_size(NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + dci_field_t srs_resource_indicator) { // It is only applicable to codebook based transmission. This field occupies 0 bits for non-codebook based // transmission. It also occupies 0 bits for codebook based transmission using a single antenna port. uint8_t nbits = 0; - if (val) { - *val = 0; - } uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator); if (!pusch_Config @@ -2645,7 +2563,6 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, long max_rank = *pusch_Config->maxRank; long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL; long *codebookSubset = pusch_Config->codebookSubset; - int ul_tpmi = tpmi ? *tpmi : srs_feedback ? srs_feedback->tpmi : -1; if (pusch_antenna_ports == 2) { @@ -2658,23 +2575,11 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, // of higher layer parameter codebookSubset; if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { nbits = 2; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 2,"TPMI %d is invalid!\n", ul_tpmi); - *val = ul_tpmi; - } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 1; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 1,"TPMI %d is invalid!\n", ul_tpmi); - *val = ul_tpmi; - } } else { nbits = 3; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 5,"TPMI %d is invalid!\n", ul_tpmi); - *val = ul_tpmi; - } } } } else { @@ -2685,27 +2590,11 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, // fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent; if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { nbits = 2; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 2) || (*nrOfLayers==2 && ul_tpmi == 0), - "TPMI %d is invalid!\n", ul_tpmi); - *val = *nrOfLayers==1 ? table_7_3_1_1_2_4A_1layer[ul_tpmi] : 2; - } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 2; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 1) || (*nrOfLayers==2 && ul_tpmi == 0), - "TPMI %d is invalid!\n", ul_tpmi); - *val = *nrOfLayers==1 ? ul_tpmi : 2; - } } else { nbits = 4; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 5) || (*nrOfLayers==2 && ul_tpmi <= 2), - "TPMI %d is invalid!\n", ul_tpmi); - *val = *nrOfLayers==1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[ul_tpmi] : - table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[ul_tpmi]; - } } } } @@ -2722,37 +2611,16 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 3; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 3 || ul_tpmi == 13, "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 4; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 15, "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - *val = table_7_3_1_1_2_3A[ul_tpmi]; } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 2; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 3, "TPMI %d is invalid!\n", ul_tpmi); - } } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { nbits = 4; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 11, "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 5; - if (val && srs_feedback) { - AssertFatal(ul_tpmi <= 27, "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - *val = ul_tpmi; } } } else { @@ -2769,99 +2637,26 @@ uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, if (max_rank == 2) { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 4; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && (ul_tpmi <= 3 || ul_tpmi==13)) || (*nrOfLayers==2 && ul_tpmi <= 6), - "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 5; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 15) || (*nrOfLayers==2 && ul_tpmi <= 13), - "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - *val = *nrOfLayers==1 ? table_7_3_1_1_2_2A_1layer[ul_tpmi] : table_7_3_1_1_2_2A_2layers[ul_tpmi]; } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 4; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && (ul_tpmi <= 3 || ul_tpmi == 13)) || (*nrOfLayers==2 && ul_tpmi <= 6) || - (*nrOfLayers==3 && ul_tpmi <= 1) || (*nrOfLayers==4 && ul_tpmi == 0), - "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 6; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 15) || (*nrOfLayers==2 && ul_tpmi <= 13) || - (*nrOfLayers==3 && ul_tpmi <= 2) || (*nrOfLayers==4 && ul_tpmi <= 2), - "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - switch (*nrOfLayers) { - case 1: - *val = table_7_3_1_1_2_2B_1layer[ul_tpmi]; - break; - case 2: - *val = table_7_3_1_1_2_2B_2layers[ul_tpmi]; - break; - case 3: - *val = table_7_3_1_1_2_2B_3layers[ul_tpmi]; - break; - case 4: - *val = table_7_3_1_1_2_2B_4layers[ul_tpmi]; - break; - default: - LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); - } } } } else { if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { nbits = 4; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 3) || (*nrOfLayers==2 && ul_tpmi <= 5) || - (*nrOfLayers==3 && ul_tpmi == 0) || (*nrOfLayers==4 && ul_tpmi == 0), - "TPMI %d is invalid!\n", ul_tpmi); - } } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { nbits = 5; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 11) || (*nrOfLayers==2 && ul_tpmi <= 13) || - (*nrOfLayers==3 && ul_tpmi <= 2) || (*nrOfLayers==4 && ul_tpmi <= 2), - "TPMI %d is invalid!\n", ul_tpmi); - } } else { nbits = 6; - if (val && srs_feedback) { - AssertFatal((*nrOfLayers==1 && ul_tpmi <= 28) || (*nrOfLayers==2 && ul_tpmi <= 22) || - (*nrOfLayers==3 && ul_tpmi <= 7) || (*nrOfLayers==4 && ul_tpmi <= 5), - "TPMI %d is invalid!\n", ul_tpmi); - } - } - if (val && srs_feedback) { - switch (*nrOfLayers) { - case 1: - *val = table_7_3_1_1_2_2_1layer[ul_tpmi]; - break; - case 2: - *val = table_7_3_1_1_2_2_2layers[ul_tpmi]; - break; - case 3: - *val = table_7_3_1_1_2_2_3layers[ul_tpmi]; - break; - case 4: - *val = table_7_3_1_1_2_2_4layers[ul_tpmi]; - break; - default: - LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); - } } } } - } return nbits; } @@ -3100,12 +2895,11 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP, } // SRS resource indicator dci_pdu->srs_resource_indicator.nbits = - compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH, pusch_Config, srs_config, NULL, NULL); + compute_srs_resource_indicator_size(sc_info->maxMIMO_Layers_PUSCH, pusch_Config, srs_config); size += dci_pdu->srs_resource_indicator.nbits; LOG_D(NR_MAC, "dci_pdu->srs_resource_indicator.nbits %d\n", dci_pdu->srs_resource_indicator.nbits); // Precoding info and number of layers - dci_pdu->precoding_information.nbits = - compute_precoding_information(pusch_Config, srs_config, dci_pdu->srs_resource_indicator, NULL, NULL, NULL, NULL); + dci_pdu->precoding_information.nbits = compute_precoding_info_size(pusch_Config, srs_config, dci_pdu->srs_resource_indicator); size += dci_pdu->precoding_information.nbits; LOG_D(NR_MAC, "dci_pdu->precoding_informaiton.nbits=%d\n", dci_pdu->precoding_information.nbits); // Antenna ports @@ -4480,7 +4274,7 @@ static uint8_t compute_ri_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, if (codebookConfig == NULL) { csi_report->csi_meas_bitlen.ri_bitlen = 0; - return 0; + return 1; } struct NR_CodebookConfig__codebookType__type1__subType__typeI_SinglePanel *type1single = NULL; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 84284f0c48..f76f54b158 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -35,11 +35,55 @@ #include "NR_CellGroupConfig.h" #include "NR_UE-NR-Capability.h" #include "nr_mac.h" +#include "nr_prach_config.h" #include "common/utils/nr/nr_common.h" #define NB_SRS_PERIOD (18) static const uint16_t srs_period[NB_SRS_PERIOD] = { 0, 1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, 80, 160, 320, 640, 1280, 2560}; +// TS 38.212 +static const uint16_t table_7_3_1_1_2_2_1layer[28] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; +static const uint16_t table_7_3_1_1_2_2_2layers[22] = {4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, + 25, 26, 27, 48, 49, 50, 51, 52, 53, 54, 55}; +static const uint16_t table_7_3_1_1_2_2_3layers[7] = {10, 28, 29, 56, 57, 58, 59}; +static const uint16_t table_7_3_1_1_2_2_4layers[5] = {11, 30, 31, 60, 61}; +static const uint16_t table_7_3_1_1_2_2B_1layer[16] = {0, 1, 2, 3, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 24, 25}; +static const uint16_t table_7_3_1_1_2_2B_2layers[14] = {4, 5, 6, 7, 8, 9, 13, 26, 27, 28, 29, 30, 31, 32}; +static const uint16_t table_7_3_1_1_2_2B_3layers[3] = {10, 14, 33}; +static const uint16_t table_7_3_1_1_2_2B_4layers[3] = {11, 34, 35}; +static const uint16_t table_7_3_1_1_2_2A_1layer[16] = {0, 1, 2, 3, 12, 13, 14, 15, 16, 17, 18, 19, 20, 10, 21, 22}; +static const uint16_t table_7_3_1_1_2_2A_2layers[14] = {4, 5, 6, 7, 8, 9, 11, 23, 24, 25, 26, 27, 28, 29}; +static const uint16_t table_7_3_1_1_2_3A[16] = {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 14, 15}; +static const uint16_t table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[6] = {0, 1, 3, 4, 5, 6}; +static const uint16_t table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[3] = {2, 7, 8}; +static const uint16_t table_7_3_1_1_2_4A_1layer[3] = {0, 1, 3}; +static const uint16_t table_7_3_1_1_2_28[3][15] = { + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; +static const uint16_t table_7_3_1_1_2_29[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0}, +}; +static const uint16_t table_7_3_1_1_2_30[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0}, +}; +static const uint16_t table_7_3_1_1_2_31[3][15] = { + {0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 3, 4, 0, 5, 0, 0, 6, 0, 0, 0, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, +}; +static const uint16_t table_7_3_1_1_2_32[3][15] = { + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + typedef enum { pusch_dmrs_pos0 = 0, pusch_dmrs_pos1 = 1, @@ -52,20 +96,6 @@ typedef enum { pusch_len2 = 2 } pusch_maxLength_t; -typedef struct { - uint32_t format; - uint32_t start_symbol; - uint32_t N_t_slot; - uint32_t N_dur; - uint32_t N_RA_slot; - uint32_t N_RA_sfn; - uint32_t max_association_period; - int x; - int y; - int y2; - uint64_t s_map; -} nr_prach_info_t; - typedef struct { uint16_t bwpStart; uint16_t bwpSize; @@ -89,25 +119,11 @@ bool is_dl_slot(const slot_t slot, const frame_structure_t *fs); bool is_mixed_slot(const slot_t slot, const frame_structure_t *fs); int get_tdd_period_idx(NR_TDD_UL_DL_ConfigCommon_t *tdd); void config_frame_structure(int mu, - NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, + const NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, uint8_t tdd_period, uint8_t frame_type, frame_structure_t *fs); -uint8_t compute_srs_resource_indicator(long *maxMIMO_Layers, - NR_PUSCH_Config_t *pusch_Config, - NR_SRS_Config_t *srs_config, - nr_srs_feedback_t *srs_feedback, - uint32_t *val); - -uint8_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, - NR_SRS_Config_t *srs_config, - dci_field_t srs_resource_indicator, - nr_srs_feedback_t *srs_feedback, - const uint8_t *nrOfLayers, - int *tpmi, - uint32_t *val); - NR_PDSCH_TimeDomainResourceAllocationList_t *get_dl_tdalist(const NR_UE_DL_BWP_t *DL_BWP, int controlResourceSetId, int ss_type, @@ -161,8 +177,6 @@ void find_aggregation_candidates(uint8_t *aggregation_level, const NR_SearchSpace_t *ss, int maxL); -uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired); - bool get_nr_prach_sched_from_info(nr_prach_info_t info, int config_index, int frame, @@ -172,8 +186,6 @@ bool get_nr_prach_sched_from_info(nr_prach_info_t info, uint16_t *RA_sfn_index, uint8_t unpaired); -nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_range_t freq_range, uint8_t unpaired); - uint8_t get_pusch_mcs_table(long *mcs_Table, int is_tp, int dci_format, @@ -190,8 +202,6 @@ int ul_ant_bits(NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig, long transformPrec uint8_t get_pdsch_mcs_table(long *mcs_Table, int dci_format, int rnti_type, int ss_type); -int get_format0(uint8_t index, uint8_t unpaired, frequency_range_t frequency_range); - uint16_t get_NCS(uint8_t index, uint16_t format, uint8_t restricted_set_config); int compute_pucch_crc_size(int O_uci); uint8_t get_l0_ul(uint8_t mapping_type, uint8_t dmrs_typeA_position); @@ -216,7 +226,9 @@ uint32_t nr_get_code_rate_dl(uint8_t Imcs, uint8_t table_idx); /** \brief Computes Q based on I_MCS PDSCH and table_idx for uplink. Implements MCS Tables from 38.214. */ uint8_t nr_get_Qm_ul(uint8_t Imcs, uint8_t table_idx); uint32_t nr_get_code_rate_ul(uint8_t Imcs, uint8_t table_idx); - +int srs_binomial_sum(int count, int Lmax); +int srs_codebook_nb_res(NR_SRS_Config_t *srs_config); +int srs_non_codebook_nb_res(NR_SRS_Config_t *srs_config); uint16_t get_nr_srs_offset(NR_SRS_PeriodicityAndOffset_t periodicityAndOffset); void get_monitoring_period_offset(const NR_SearchSpace_t *ss, int *period, int *offset); diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common_tdd.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common_tdd.c index 8720cbce8b..922a0153d9 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common_tdd.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common_tdd.c @@ -98,7 +98,7 @@ int get_tdd_period_idx(NR_TDD_UL_DL_ConfigCommon_t *tdd) * * @return Number of slots in the configured TDD period */ -static uint8_t set_tdd_bmap_period(NR_TDD_UL_DL_Pattern_t *pattern, tdd_period_config_t *pc, int8_t curr_total_slot) +static uint8_t set_tdd_bmap_period(const NR_TDD_UL_DL_Pattern_t *pattern, tdd_period_config_t *pc, int8_t curr_total_slot) { int8_t n_dl_slot = pattern->nrofDownlinkSlots; int8_t n_ul_slot = pattern->nrofUplinkSlots; @@ -138,6 +138,10 @@ static uint8_t set_tdd_bmap_period(NR_TDD_UL_DL_Pattern_t *pattern, tdd_period_c n_ul_slot, n_dl_symbols, n_ul_symbols); + AssertFatal(n_dl_symbols + n_ul_symbols < 14, + "number of mixed slot symbols must be smaller than 14: DL %d, UL %d\n", + n_dl_symbols, + n_ul_symbols); return total_slot; } @@ -154,7 +158,7 @@ static uint8_t set_tdd_bmap_period(NR_TDD_UL_DL_Pattern_t *pattern, tdd_period_c * * @return void */ -static void config_tdd_patterns(NR_TDD_UL_DL_ConfigCommon_t *tdd, frame_structure_t *fs) +static void config_tdd_patterns(const NR_TDD_UL_DL_ConfigCommon_t *tdd, frame_structure_t *fs) { int num_of_patterns = 1; uint8_t nb_slots_p2 = 0; @@ -174,6 +178,11 @@ static void config_tdd_patterns(NR_TDD_UL_DL_ConfigCommon_t *tdd, frame_structur num_of_patterns, nb_slots_p1, nb_slots_p2); + AssertFatal(nb_slots_p1 + nb_slots_p2 == fs->numb_slots_period, + "total number of slots must equal to %d: p1 %d + p2 %d\n", + fs->numb_slots_period, + nb_slots_p1, + nb_slots_p2); } /** @@ -188,7 +197,7 @@ static void config_tdd_patterns(NR_TDD_UL_DL_ConfigCommon_t *tdd, frame_structur * @param fs pointer to the frame structure to update */ void config_frame_structure(int mu, - NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, + const NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, uint8_t tdd_period, uint8_t frame_type, frame_structure_t *fs) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h b/openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h new file mode 100644 index 0000000000..1b6aa0bfb7 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h @@ -0,0 +1,75 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h +* \brief Tools to query the PRACH configuration tables +* \author Romain beurdouche +* \date Jul. 2025 +* \version 0.1 +* \company Eurecom +* \email romain.beurdouche@eurecom.fr +* \note The PRACH configuration tables are used in the MAC layer for scheduling and beyond. +* For example the PRACH duration is requested in the O-RAN 7.2 FrontHaul Interface +*/ + +/** + * @brief Fetch PRACH format (format only) from PRACH configuration tables + * + * @param index PRACH configuration index + * @param unpaired Duplex mode TDD or FDD + * @param freq_range Frequency range FR1 or FR2 + * @return PRACH format (format only) + */ +int get_format0(uint8_t index, uint8_t unpaired, frequency_range_t frequency_range); + +typedef struct { + uint32_t format; + uint32_t start_symbol; + uint32_t N_t_slot; + uint32_t N_dur; + uint32_t N_RA_slot; + uint32_t N_RA_sfn; + uint32_t max_association_period; + int x; + int y; + int y2; + uint64_t s_map; +} nr_prach_info_t; + +/** + * @brief Fetch PRACH occasion info from PRACH configuration tables + * + * @param index PRACH configuration index + * @param freq_range Frequency range FR1 or FR2 + * @param unpaired Duplex mode TDD or FDD + * @return PRACH occasion information + */ +nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_range_t freq_range, uint8_t unpaired); + +/** + * @brief Fetch PRACH format (format concatenated with format2) from PRACH configuration tables + * + * @param index PRACH configuration index + * @param pointa Point A ARFCN to determine the Frequency range FR1 or FR2 + * @param unpaired Duplex mode TDD or FDD + * @return PRACH format (format concatenated with format2) + */ +uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired); diff --git a/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt b/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt index aa583c8598..8a7fec829e 100644 --- a/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt +++ b/openair2/LAYER2/NR_MAC_UE/CMakeLists.txt @@ -1,7 +1,7 @@ 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) +target_link_libraries(nr_ue_power_procedures PUBLIC asn1_nr_rrc log_headers MAC_NR_COMMON nr_common) add_library(nr_ue_ra_procedures nr_ra_procedures.c) -target_link_libraries(nr_ue_ra_procedures PUBLIC asn1_nr_rrc asn1_lte_rrc_hdrs ${T_LIB} MAC_NR_COMMON nr_common) +target_link_libraries(nr_ue_ra_procedures PUBLIC asn1_nr_rrc asn1_lte_rrc_hdrs log_headers MAC_NR_COMMON nr_common) if (ENABLE_TESTS) add_subdirectory(tests) endif() diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 3a5d5e5640..f592423c5a 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -267,59 +267,117 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo } // computes round-trip-time between ue and sat based on SIB19 ephemeris data -static double calculate_ue_sat_ta(const position_t *position_params, NR_PositionVelocity_r17_t *sat_pos) +static void calculate_ue_sat_ta(const position_t *position_params, + const NR_PositionVelocity_r17_t *sat_pos, + ntn_timing_advance_componets_t *ntn_ta) { // get UE position coordinates - double posx = position_params->positionX; - double posy = position_params->positionY; - double posz = position_params->positionZ; + const position_t pos_ue = *position_params; // get sat position coordinates - double posx_0 = (double)sat_pos->positionX_r17 * 1.3; - double posy_0 = (double)sat_pos->positionY_r17 * 1.3; - double posz_0 = (double)sat_pos->positionZ_r17 * 1.3; + const position_t pos_sat = {sat_pos->positionX_r17 * 1.3, sat_pos->positionY_r17 * 1.3, sat_pos->positionZ_r17 * 1.3}; - double distance = 2 * sqrt(pow(posx - posx_0, 2) + pow(posy - posy_0, 2) + pow(posz - posz_0, 2)); - double ta_ms = (distance / SPEED_OF_LIGHT) * 1000; + // calculate directional vector from SAT to UE + const position_t dir_sat_ue = {pos_ue.X - pos_sat.X, pos_ue.Y - pos_sat.Y, pos_ue.Z - pos_sat.Z}; - return ta_ms; + // calculate distance between SAT and UE + double distance = sqrt(dir_sat_ue.X * dir_sat_ue.X + dir_sat_ue.Y * dir_sat_ue.Y + dir_sat_ue.Z * dir_sat_ue.Z); + + // get sat velocity vector + const position_t vel_sat = {sat_pos->velocityVX_r17 * 0.06, sat_pos->velocityVY_r17 * 0.06, sat_pos->velocityVZ_r17 * 0.06}; + + // calculate SAT velocity towards UE + double velocity = (vel_sat.X * dir_sat_ue.X + vel_sat.Y * dir_sat_ue.Y + vel_sat.Z * dir_sat_ue.Z) / distance; + + // calculate SAT acceleration towards UE + const double radius_2 = pos_sat.X * pos_sat.X + pos_sat.Y * pos_sat.Y + pos_sat.Z * pos_sat.Z; + const double vel_sat_2 = vel_sat.X * vel_sat.X + vel_sat.Y * vel_sat.Y + vel_sat.Z * vel_sat.Z; + const double acceleration = + -(pos_sat.X * dir_sat_ue.X + pos_sat.Y * dir_sat_ue.Y + pos_sat.Z * dir_sat_ue.Z) * vel_sat_2 / (radius_2 * distance); + + LOG_D(NR_MAC, "Satellite velocity towards UE: %f m/s, acceleration towards UE: %f m/s²\n", velocity, acceleration); + + ntn_ta->N_UE_TA_adj = (2 * distance / SPEED_OF_LIGHT) * 1e3; // in ms + ntn_ta->N_UE_TA_drift = (2 * -velocity / SPEED_OF_LIGHT) * 1e6; // in µs/s + ntn_ta->N_UE_TA_drift_variant = (2 * acceleration / SPEED_OF_LIGHT) * 1e6; // in µs/s² } // populate ntn_ta structure from mac -void configure_ntn_ta(module_id_t module_id, ntn_timing_advance_componets_t *ntn_ta, NR_NTN_Config_r17_t *ntn_Config_r17) +static void configure_ntn_ta(module_id_t module_id, + ntn_timing_advance_componets_t *ntn_ta, + const NR_NTN_Config_r17_t *ntn_Config_r17) { + if (!ntn_Config_r17) + return; + position_t position_params = {0}; get_position_coordinates(module_id, &position_params); - // if ephemerisInfo_r17 present in SIB19 - NR_EphemerisInfo_r17_t *ephemeris_info = ntn_Config_r17->ephemerisInfo_r17; + // epochTime_r17 must be present (this is assured by function `eval_epoch_time()`) + const NR_EpochTime_r17_t *epoch_time_r17 = ntn_Config_r17->epochTime_r17; + AssertFatal(epoch_time_r17, "epoch_time_r17 should not be NULL here\n"); + ntn_ta->epoch_sfn = epoch_time_r17->sfn_r17; + ntn_ta->epoch_subframe = epoch_time_r17->subFrameNR_r17; + + // handle ephemerisInfo_r17 + const NR_EphemerisInfo_r17_t *ephemeris_info = ntn_Config_r17->ephemerisInfo_r17; if (ephemeris_info) { - NR_PositionVelocity_r17_t *position_velocity = ephemeris_info->choice.positionVelocity_r17; - if (position_velocity - && (position_velocity->positionX_r17 != 0 || position_velocity->positionY_r17 != 0 - || position_velocity->positionZ_r17 != 0)) { - ntn_ta->N_UE_TA_adj = calculate_ue_sat_ta(&position_params, position_velocity); + if (ephemeris_info->present == NR_EphemerisInfo_r17_PR_positionVelocity_r17) { + const NR_PositionVelocity_r17_t *position_velocity = ephemeris_info->choice.positionVelocity_r17; + AssertFatal(position_velocity, "position_velocity should not be NULL here\n"); + calculate_ue_sat_ta(&position_params, position_velocity, ntn_ta); + } else { + LOG_W(NR_MAC, "NR UE currently supports only ephemerisInfo_r17 of type positionVelocity_r17\n"); + ntn_ta->N_UE_TA_adj = 0; + ntn_ta->N_UE_TA_drift = 0; + ntn_ta->N_UE_TA_drift_variant = 0; } + } else { // Need R - Release if not present + ntn_ta->N_UE_TA_adj = 0; + ntn_ta->N_UE_TA_drift = 0; + ntn_ta->N_UE_TA_drift_variant = 0; } - // if cellSpecificKoffset_r17 is present - if (ntn_Config_r17->cellSpecificKoffset_r17) { + + // handle cellSpecificKoffset_r17 + if (ntn_Config_r17->cellSpecificKoffset_r17) ntn_ta->cell_specific_k_offset = *ntn_Config_r17->cellSpecificKoffset_r17; - } - // Check if ta_Info_r17 is present and convert directly ta_Common_r17 (is in units of 4.072e-3 µs) + else // Need R - Release if not present + ntn_ta->cell_specific_k_offset = 0; + + // Check if ta_Info_r17 is present and convert the time units if (ntn_Config_r17->ta_Info_r17) { + // ta_Common_r17 (is in units of 4.072e-3 µs) ntn_ta->N_common_ta_adj = ntn_Config_r17->ta_Info_r17->ta_Common_r17 * 4.072e-6; // ta_CommonDrift_r17 (is in units of 0.2e-3 µs/s) if (ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17) - ntn_ta->ntn_ta_commondrift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; + ntn_ta->N_common_ta_drift = *ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17 * 0.2e-3; + else // Need R - Release if not present + ntn_ta->N_common_ta_drift = 0; + // ta_CommonDriftVariant_r17 (is in units of 0.2e-4 µs/s²) + if (ntn_Config_r17->ta_Info_r17->ta_CommonDriftVariant_r17) + ntn_ta->N_common_ta_drift_variant = *ntn_Config_r17->ta_Info_r17->ta_CommonDriftVariant_r17 * 0.2e-4; + else // Need R - Release if not present + ntn_ta->N_common_ta_drift_variant = 0; + } else { // Need R - Release if not present + ntn_ta->N_common_ta_adj = 0; + ntn_ta->N_common_ta_drift = 0; + ntn_ta->N_common_ta_drift_variant = 0; } + ntn_ta->ntn_params_changed = true; LOG_D(NR_MAC, - "SIB19 Rxd. k_offset:%ld, N_Common_Ta:%f,drift:%f,N_UE_TA:%f \n", + "SIB19 Rxd. Epoch SFN: %d, Epoch Subframe: %d, k_offset: %ldms, N_Common_Ta: %fms, drift: %fµs/s, variant %fµs/s², " + "N_UE_TA: %fms, drift: %fµs/s, variant %fµs/s²\n", + ntn_ta->epoch_sfn, + ntn_ta->epoch_subframe, ntn_ta->cell_specific_k_offset, ntn_ta->N_common_ta_adj, - ntn_ta->ntn_ta_commondrift, - ntn_ta->N_UE_TA_adj); + ntn_ta->N_common_ta_drift, + ntn_ta->N_common_ta_drift_variant, + ntn_ta->N_UE_TA_adj, + ntn_ta->N_UE_TA_drift, + ntn_ta->N_UE_TA_drift_variant); } static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t *scc, int cc_idP) @@ -503,7 +561,7 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t } } -void release_common_ss_cset(NR_BWP_PDCCH_t *pdcch) +static void release_common_ss_cset(NR_BWP_PDCCH_t *pdcch) { pdcch->otherSI_SS_id = -1; pdcch->ra_SS_id = -1; @@ -642,8 +700,11 @@ static void modlist_coreset(NR_ControlResourceSet_t *source, NR_ControlResourceS if (id == *target->tci_StatesPDCCH_ToAddList->list.array[j]) break; } - if (j == target->tci_StatesPDCCH_ToAddList->list.count) - ASN_SEQUENCE_ADD(&target->tci_StatesPDCCH_ToAddList->list, source->tci_StatesPDCCH_ToAddList->list.array[i]); + if (j == target->tci_StatesPDCCH_ToAddList->list.count) { + long *tci_id = calloc(1, sizeof(*tci_id)); + *tci_id = id; + ASN_SEQUENCE_ADD(&target->tci_StatesPDCCH_ToAddList->list, tci_id); + } } } else UPDATE_IE(target->tci_StatesPDCCH_ToAddList, @@ -811,7 +872,7 @@ static uint32_t get_lc_bucket_size(long prioritisedBitRate, long bucketSizeDurat } // default configuration as per 38.331 section 9.2.1 -static void set_default_logicalchannelconfig(nr_lcordered_info_t *lc_info, NR_SRB_Identity_t srb_id) +static void set_default_logicalchannelconfig(nr_lcordered_info_t *lc_info, int srb_id) { lc_info->lcid = srb_id; lc_info->priority = srb_id == 2 ? 3 : 1; @@ -822,12 +883,14 @@ static void set_default_logicalchannelconfig(nr_lcordered_info_t *lc_info, NR_SR static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac, nr_lcordered_info_t *lc_info, NR_LogicalChannelConfig_t *mac_lc_config, - NR_SRB_Identity_t srb_id) + nr_lcid_rb_t rb) { NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lc_info->lcid); - if (srb_id > 0 && !mac_lc_config->ul_SpecificParameters) { + lc_info->rb = rb; + lc_info->rb_suspended = false; + if (rb.type == NR_LCID_SRB && !mac_lc_config->ul_SpecificParameters) { // release configuration and reset to default - set_default_logicalchannelconfig(lc_info, srb_id); + set_default_logicalchannelconfig(lc_info, rb.choice.srb_id); // invalid LCGID to signal it is absent in the configuration lc_sched_info->LCGID = NR_INVALID_LCGID; return; @@ -848,6 +911,25 @@ static void nr_configure_lc_config(NR_UE_MAC_INST_t *mac, nr_timer_start(bjt); } +static nr_lcid_rb_t configure_lcid_rb(NR_RLC_BearerConfig_t *rlc_bearer) +{ + nr_lcid_rb_t rb; + if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) { + rb.type = NR_LCID_SRB; + rb.choice.srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity; + return rb; + } + + if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity) { + rb.type = NR_LCID_DRB; + rb.choice.drb_id = rlc_bearer->servedRadioBearer->choice.drb_Identity; + return rb; + } + LOG_E(NR_MAC, "Error. RLC should be linked to either DRB or SRB.\n"); + rb.type = NR_LCID_NONE; + return rb; +} + static void configure_logicalChannelBearer(NR_UE_MAC_INST_t *mac, struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_toadd_list, struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_torelease_list) @@ -870,6 +952,9 @@ static void configure_logicalChannelBearer(NR_UE_MAC_INST_t *mac, if (rlc_toadd_list) { for (int i = 0; i < rlc_toadd_list->list.count; i++) { NR_RLC_BearerConfig_t *rlc_bearer = rlc_toadd_list->list.array[i]; + nr_lcid_rb_t rb = configure_lcid_rb(rlc_bearer); + if (rb.type == NR_LCID_NONE) + continue; int lc_identity = rlc_bearer->logicalChannelIdentity; NR_LogicalChannelConfig_t *mac_lc_config = rlc_bearer->mac_LogicalChannelConfig; int j; @@ -879,14 +964,9 @@ static void configure_logicalChannelBearer(NR_UE_MAC_INST_t *mac, } if (j < mac->lc_ordered_list.count) { LOG_D(NR_MAC, "Logical channel %d is already established, Reconfiguring now\n", lc_identity); - if (mac_lc_config != NULL) { - NR_SRB_Identity_t srb_id = 0; - if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) - srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity; - nr_configure_lc_config(mac, mac->lc_ordered_list.array[j], mac_lc_config, srb_id); - } - } - else { + if (mac_lc_config != NULL) + nr_configure_lc_config(mac, mac->lc_ordered_list.array[j], mac_lc_config, rb); + } else { /* setup of new LCID*/ nr_lcordered_info_t *lc_info = calloc(1, sizeof(*lc_info)); lc_info->lcid = lc_identity; @@ -895,12 +975,12 @@ static void configure_logicalChannelBearer(NR_UE_MAC_INST_t *mac, if (rlc_bearer->servedRadioBearer->present == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity) { /* SRB */ NR_SRB_Identity_t srb_id = rlc_bearer->servedRadioBearer->choice.srb_Identity; if (mac_lc_config != NULL) - nr_configure_lc_config(mac, lc_info, mac_lc_config, srb_id); + nr_configure_lc_config(mac, lc_info, mac_lc_config, rb); else set_default_logicalchannelconfig(lc_info, srb_id); } else { /* DRB */ AssertFatal(mac_lc_config, "When establishing a DRB, LogicalChannelConfig should be mandatorily present\n"); - nr_configure_lc_config(mac, lc_info, mac_lc_config, 0); + nr_configure_lc_config(mac, lc_info, mac_lc_config, rb); } ASN_SEQUENCE_ADD(&mac->lc_ordered_list, lc_info); } @@ -936,7 +1016,13 @@ static void update_mib_conf(NR_MIB_t *target, NR_MIB_t *source) target->intraFreqReselection = source->intraFreqReselection; } -void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mib, int sched_sib) +static bool is_cset0_present(frequency_range_t const fr, uint8_t const kssb) +{ + // TS 38.213 4.1 defines if CORESET 0 is present or not based on Kssb + return (fr == FR1) ? (kssb < 24) : (kssb < 12); +} + +void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mib, int sched_sib, bool barred) { NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); int ret = pthread_mutex_lock(&mac->if_mutex); @@ -944,14 +1030,35 @@ void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mib, AssertFatal(mib, "MIB should not be NULL\n"); if (!mac->mib) mac->mib = calloc(1, sizeof(*mac->mib)); + if (barred) + mac->state = UE_BARRED; + else if (mac->state == UE_BARRED) { + // it is synched as we received MIB + // nr_ue_decode_mib is transitionining to the correct state + mac->state = UE_NOT_SYNC; + } update_mib_conf(mac->mib, mib); mac->phy_config.Mod_id = module_id; mac->phy_config.CC_id = cc_idP; - if (sched_sib == 1) - mac->get_sib1 = true; - else if (sched_sib > 1) - mac->get_otherSI[sched_sib - 2] = true; + nr_ue_decode_mib(mac, cc_idP); + + if (sched_sib == 1) { + bool const is_c0 = is_cset0_present(mac->frequency_range, mac->ssb_subcarrier_offset); + mac->get_sib1 = is_c0; + AssertFatal(is_c0, "RRC scheduling SIB1 reception but MIB indicates no SIB1 present in current cell\n"); + } else if (sched_sib > 1) + mac->get_otherSI[sched_sib - 2] = true; + + if (get_softmodem_params()->phy_test) + mac->state = UE_CONNECTED; + else if (mac->state == UE_NOT_SYNC) { + if (IS_SA_MODE(get_softmodem_params()) && mac->get_sib1) + mac->state = UE_RECEIVING_SIB; + else + mac->state = UE_PERFORMING_RA; + } + ret = pthread_mutex_unlock(&mac->if_mutex); AssertFatal(!ret, "mutex failed %d\n", ret); } @@ -1706,11 +1813,23 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t reset_mac_inst(mac); mac->state = UE_PERFORMING_RA; // still in sync but need to restart RA break; + case REJECT: + reset_ra(mac, false); + reset_mac_inst(mac); + mac->state = UE_BARRED; + break; case RE_ESTABLISHMENT: reset_mac_inst(mac); nr_ue_mac_default_configs(mac); nr_ue_reset_sync_state(mac); release_mac_configuration(mac, cause); + // suspend all RBs except SRB0 + for (int j = 0; j < mac->lc_ordered_list.count; j++) { + nr_lcordered_info_t *lc = mac->lc_ordered_list.array[j]; + if (lc->rb.type == NR_LCID_SRB && lc->rb.choice.srb_id == 0) + continue; + lc->rb_suspended = true; + } // apply the timeAlignmentTimerCommon included in SIB1 configure_timeAlignmentTimer(&mac->time_alignment_timer, mac->timeAlignmentTimerCommon, mac->current_UL_BWP->scs); // new sync with old cell ID (re-establishment on the same cell) @@ -1718,6 +1837,15 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t sync_req.ssb_bw_scan = false; nr_ue_send_synch_request(mac, module_id, 0, &sync_req); break; + case RRC_SETUP_REESTAB_RESUME: + release_mac_configuration(mac, cause); + nr_ue_mac_default_configs(mac); + break; + case UL_SYNC_LOST_T430_EXPIRED: + // TS 38.331 Section 5.2.2.6, TS 38.321 Section 5.2a + // Flush all HARQ buffers and Stop UL transmissions + handle_ulsync_loss(mac); + break; default: AssertFatal(false, "Invalid MAC reset cause %d\n", cause); } @@ -1725,6 +1853,29 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t AssertFatal(!ret, "mutex failed %d\n", ret); } +bool is_lcid_suspended(NR_UE_MAC_INST_t *mac, int lcid) +{ + for (int j = 0; j < mac->lc_ordered_list.count; j++) { + nr_lcordered_info_t *lc = mac->lc_ordered_list.array[j]; + if (lc->lcid == lcid) + return lc->rb_suspended; + } + LOG_E(NR_MAC, "LCID %d not found in the MAC list\n", lcid); + return false; +} + +void nr_rrc_mac_resume_rb(module_id_t module_id, bool is_srb, int rb_id) +{ + NR_UE_MAC_INST_t *mac = get_mac_inst(module_id); + for (int j = 0; j < mac->lc_ordered_list.count; j++) { + nr_lcordered_info_t *lc = mac->lc_ordered_list.array[j]; + if (is_srb && lc->rb.type == NR_LCID_SRB && lc->rb.choice.srb_id == rb_id) + lc->rb_suspended = false; + if (!is_srb && lc->rb.type == NR_LCID_DRB && lc->rb.choice.drb_id == rb_id) + lc->rb_suspended = false; + } +} + static void configure_si_schedulingInfo(NR_UE_MAC_INST_t *mac, NR_SI_SchedulingInfo_t *si_SchedulingInfo, NR_SI_SchedulingInfo_v1700_t *si_SchedulingInfo_v1700) @@ -1791,8 +1942,7 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *si if (mac->state == UE_RECEIVING_SIB && can_start_ra) mac->state = UE_PERFORMING_RA; - if (!get_softmodem_params()->emulate_l1) - mac->if_module->phy_config_request(&mac->phy_config); + mac->if_module->phy_config_request(&mac->phy_config); ret = pthread_mutex_unlock(&mac->if_mutex); AssertFatal(!ret, "mutex failed %d\n", ret); } @@ -1805,10 +1955,8 @@ void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19, b if (sib19) { // update ntn_Config_r17 with received values - NR_NTN_Config_r17_t *ntn_Config_r17 = mac->sc_info.ntn_Config_r17; - UPDATE_IE(ntn_Config_r17, sib19->ntn_Config_r17, NR_NTN_Config_r17_t); - - configure_ntn_ta(mac->ue_id, &mac->ntn_ta, ntn_Config_r17); + UPDATE_IE(mac->sc_info.ntn_Config_r17, sib19->ntn_Config_r17, NR_NTN_Config_r17_t); + configure_ntn_ta(mac->ue_id, &mac->ntn_ta, mac->sc_info.ntn_Config_r17); } if (mac->state == UE_RECEIVING_SIB && can_start_ra) mac->state = UE_PERFORMING_RA; @@ -1853,13 +2001,11 @@ static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac, ra->ra_state = nrRA_UE_IDLE; nr_ue_mac_default_configs(mac); - if (!get_softmodem_params()->emulate_l1) { - mac->synch_request.Mod_id = mac->ue_id; - mac->synch_request.CC_id = cc_idP; - mac->synch_request.synch_req.target_Nid_cell = mac->physCellId; - mac->if_module->synch_request(&mac->synch_request); - mac->if_module->phy_config_request(&mac->phy_config); - } + mac->synch_request.Mod_id = mac->ue_id; + mac->synch_request.CC_id = cc_idP; + mac->synch_request.synch_req.target_Nid_cell = mac->physCellId; + mac->if_module->synch_request(&mac->synch_request); + mac->if_module->phy_config_request(&mac->phy_config); } static void configure_physicalcellgroup(NR_UE_MAC_INST_t *mac, @@ -2531,8 +2677,8 @@ static void configure_BWPs(NR_UE_MAC_INST_t *mac, NR_ServingCellConfig_t *scd) if (scd->downlinkBWP_ToReleaseList) { for (int i = 0; i < scd->downlinkBWP_ToReleaseList->list.count; i++) { for (int j = 0; j < mac->dl_BWPs.count; j++) { - if (*scd->downlinkBWP_ToReleaseList->list.array[i] == mac->dl_BWPs.array[i]->bwp_id) - release_dl_BWP(mac, i); + if (*scd->downlinkBWP_ToReleaseList->list.array[i] == mac->dl_BWPs.array[j]->bwp_id) + release_dl_BWP(mac, j); } } } @@ -2553,8 +2699,8 @@ static void configure_BWPs(NR_UE_MAC_INST_t *mac, NR_ServingCellConfig_t *scd) if (scd->uplinkConfig->uplinkBWP_ToReleaseList) { for (int i = 0; i < scd->uplinkConfig->uplinkBWP_ToReleaseList->list.count; i++) { for (int j = 0; j < mac->ul_BWPs.count; j++) { - if (*scd->uplinkConfig->uplinkBWP_ToReleaseList->list.array[i] == mac->ul_BWPs.array[i]->bwp_id) - release_ul_BWP(mac, i); + if (*scd->uplinkConfig->uplinkBWP_ToReleaseList->list.array[i] == mac->ul_BWPs.array[j]->bwp_id) + release_ul_BWP(mac, j); } } } diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index b3ca280f86..b7ebd5a651 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -148,6 +148,7 @@ // Define the UE L2 states with X-Macro #define NR_UE_L2_STATES \ UE_STATE(UE_NOT_SYNC) \ + UE_STATE(UE_BARRED) \ UE_STATE(UE_RECEIVING_SIB) \ UE_STATE(UE_PERFORMING_RA) \ UE_STATE(UE_CONNECTED) \ @@ -196,7 +197,10 @@ typedef enum { GO_TO_IDLE, DETACH, T300_EXPIRY, - RE_ESTABLISHMENT + RE_ESTABLISHMENT, + RRC_SETUP_REESTAB_RESUME, + UL_SYNC_LOST_T430_EXPIRED, + REJECT, } NR_UE_MAC_reset_cause_t; typedef struct { @@ -299,6 +303,26 @@ typedef struct { uint32_t prach_mask; } NR_pdcch_order_config_t; +typedef struct { + NR_PUCCH_Resource_t *pucch_resource; + uint32_t ack_payload; + uint8_t sr_payload; + uint32_t csi_part1_payload; + uint32_t csi_part2_payload; + int n_sr; + int n_csi; + int n_harq; + int n_CCE; + int N_CCE; + int initial_pucch_id; +} PUCCH_sched_t; + +typedef struct { + int sched_frame; + int sched_slot; + PUCCH_sched_t pucch_sched; +} RA_PUCCH_SCHED_t; + typedef struct { // pointer to RACH config dedicated NR_RACH_ConfigDedicated_t *rach_ConfigDedicated; @@ -350,6 +374,8 @@ typedef struct { int preambleRxTargetPower; int msg3_deltaPreamble; int preambleReceivedTargetPower_config; + RA_PUCCH_SCHED_t *ra_pucch; + /// Random-access Contention Resolution Timer NR_timer_t contention_resolution_timer; /// Transmitted UE Contention Resolution Identifier @@ -400,23 +426,8 @@ typedef struct { } RAR_grant_t; typedef struct { - NR_PUCCH_Resource_t *pucch_resource; - uint32_t ack_payload; - uint8_t sr_payload; - uint32_t csi_part1_payload; - uint32_t csi_part2_payload; - int n_sr; - int n_csi; - int n_harq; - int n_CCE; - int N_CCE; - int initial_pucch_id; -} PUCCH_sched_t; - -typedef struct { - uint32_t ssb_index; /// SSB RSRP in dBm - short ssb_rsrp_dBm; + int ssb_rsrp_dBm; float_t ssb_sinr_dB; } NR_SSB_meas_t; @@ -450,6 +461,8 @@ typedef struct nr_lcordered_info_s { uint32_t bucket_size; bool sr_DelayTimerApplied; bool lc_SRMask; + nr_lcid_rb_t rb; + bool rb_suspended; } nr_lcordered_info_t; typedef struct { @@ -467,8 +480,8 @@ typedef struct { } NR_BWP_PDCCH_t; typedef struct csi_payload { - uint32_t part1_payload; - uint32_t part2_payload; + uint64_t part1_payload; + uint64_t part2_payload; int p1_bits; int p2_bits; } csi_payload_t; @@ -522,12 +535,21 @@ typedef struct { } si_schedInfo_t; typedef struct ntn_timing_advance_components { + int epoch_sfn; + int epoch_subframe; + // N_common_ta_adj represents common round-trip-time between gNB and SAT received in SIB19 (ms) double N_common_ta_adj; + // drift rate of common ta in µs/s + double N_common_ta_drift; + // change rate of common ta drift in µs/s² + double N_common_ta_drift_variant; // N_UE_TA_adj calculated round-trip-time between UE and SAT (ms) double N_UE_TA_adj; - // drift rate of common ta in µs/s - double ntn_ta_commondrift; + // drift rate of N_UE_TA in µs/s + double N_UE_TA_drift; + // change rate of N_UE_TA drift in µs/s² + double N_UE_TA_drift_variant; // cell scheduling offset expressed in terms of 15kHz SCS long cell_specific_k_offset; @@ -579,8 +601,8 @@ typedef struct NR_UE_MAC_INST_s { nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG]; - /// measurements from CSI-RS - fapi_nr_csirs_measurements_t csirs_measurements; + /// measurements from SS or CSI-RS + fapi_nr_l1_measurements_t l1_measurements; //// FAPI-like interface message fapi_nr_ul_config_request_t *ul_config_request; @@ -610,7 +632,7 @@ typedef struct NR_UE_MAC_INST_s { uint8_t ssb_subcarrier_offset; int ssb_start_subcarrier; - NR_SSB_meas_t ssb_measurements; + NR_SSB_meas_t ssb_measurements[MAX_NB_SSB]; dci_pdu_rel15_t def_dci_pdu_rel15[NR_MAX_SLOTS_PER_FRAME][8]; @@ -624,8 +646,6 @@ typedef struct NR_UE_MAC_INST_s { NR_TimeAlignmentTimer_t timeAlignmentTimerCommon; NR_timer_t time_alignment_timer; - nr_emulated_l1_t nr_ue_emul_l1; - pthread_mutex_t mutex_dl_info; //SIDELINK MAC PARAMETERS @@ -639,6 +659,7 @@ typedef struct NR_UE_MAC_INST_s { bool msg3_C_RNTI; pthread_mutex_t if_mutex; ue_mac_stats_t stats; + notifiedFIFO_t input_nf; } NR_UE_MAC_INST_t; static inline int GET_NTN_UE_K_OFFSET(const ntn_timing_advance_componets_t *ntn_ta, int scs) @@ -646,15 +667,25 @@ static inline int GET_NTN_UE_K_OFFSET(const ntn_timing_advance_componets_t *ntn_ return (int)ntn_ta->cell_specific_k_offset << scs; } -static inline double GET_COMPLETE_TIME_ADVANCE_MS(const ntn_timing_advance_componets_t *ntn_ta) -{ - return ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj; -} - static inline long GET_DURATION_RX_TO_TX(const ntn_timing_advance_componets_t *ntn_ta, int scs) { return NR_UE_CAPABILITY_SLOT_RX_TO_TX + (ntn_ta->cell_specific_k_offset << scs); } +static inline double get_total_TA_ms(const ntn_timing_advance_componets_t *ntn_ta) +{ + return ntn_ta->N_common_ta_adj + ntn_ta->N_UE_TA_adj; +} + +static inline double get_total_TA_drift(const ntn_timing_advance_componets_t *ntn_ta) +{ + return ntn_ta->N_common_ta_drift + ntn_ta->N_UE_TA_drift; +} + +static inline double get_total_TA_drift_variant(const ntn_timing_advance_componets_t *ntn_ta) +{ + return ntn_ta->N_common_ta_drift_variant + ntn_ta->N_UE_TA_drift_variant; +} + /*@}*/ #endif /*__LAYER2_MAC_DEFS_H__ */ diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h index b058f6e681..4897a8fab8 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h @@ -59,21 +59,22 @@ void nr_ue_mac_default_configs(NR_UE_MAC_INST_t *mac); void nr_ue_decode_mib(NR_UE_MAC_INST_t *mac, int cc_id); -void release_common_ss_cset(NR_BWP_PDCCH_t *pdcch); - /**\brief decode SIB1 and other SIs pdus in NR_UE, from if_module dl_ind \param mac pointer to MAC instance \param cc_id component carrier id \param gNB_index gNB index \param sibs_mask sibs mask \param pduP pointer to pdu - \param pdu_length length of pdu */ + \param pdu_length length of pdu + \param frame,slot Received TTI*/ void nr_ue_decode_BCCH_DL_SCH(NR_UE_MAC_INST_t *mac, int cc_id, unsigned int gNB_index, uint8_t ack_nack, uint8_t *pduP, - uint32_t pdu_len); + uint32_t pdu_len, + int frame, + int slot); void release_dl_BWP(NR_UE_MAC_INST_t *mac, int index); void release_ul_BWP(NR_UE_MAC_INST_t *mac, int index); @@ -84,16 +85,13 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id, NR_CellGroupConfig_t *cell_group_config, NR_UE_NR_Capability_t *ue_Capability); -void nr_rrc_mac_config_req_mib(module_id_t module_id, - int cc_idP, - NR_MIB_t *mibP, - int sched_sib1); +void nr_rrc_mac_config_req_mib(module_id_t module_id, int cc_idP, NR_MIB_t *mibP, int sched_sib1, bool barred); void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *sib1, bool can_start_ra); struct position; /* forward declaration */ void nr_rrc_mac_config_other_sib(module_id_t module_id, NR_SIB19_r17_t *sib19_r17, bool can_start_ra); - +void nr_rrc_mac_resume_rb(module_id_t module_id, bool is_srb, int rb_id); void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t cause); /**\brief initialization NR UE MAC instance(s)*/ @@ -117,18 +115,10 @@ void nr_ue_dl_scheduler(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info csi_payload_t nr_ue_aperiodic_csi_reporting(NR_UE_MAC_INST_t *mac, dci_field_t csi_request, int tda, long *K2); -/*! \fn int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id); - \brief This function schedules a positive or negative SR for schedulingRequestID sr_id - depending on the presence of any active SR and the prohibit timer. - If the max number of retransmissions is reached, it triggers a new RA */ -int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id); - nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci); -int8_t nr_ue_process_csirs_measurements(NR_UE_MAC_INST_t *mac, - frame_t frame, - int slot, - fapi_nr_csirs_measurements_t *csirs_measurements); +void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements); + void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger, int frame, int slot); bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, @@ -138,30 +128,11 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch); -csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig); - -csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig, - CSI_mapping_t mapping_type); - -csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - const NR_CSI_MeasConfig_t *csi_MeasConfig); - csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, int csi_report_id, CSI_mapping_t mapping_type, NR_CSI_MeasConfig_t *csi_MeasConfig); -uint8_t get_rsrp_index(int rsrp); -uint8_t get_rsrp_diff_index(int best_rsrp,int current_rsrp); - /* \brief Get payload (MAC PDU) from UE PHY @param dl_info pointer to dl indication @param ul_time_alignment pointer to timing advance parameters @@ -170,8 +141,6 @@ uint8_t get_rsrp_diff_index(int best_rsrp,int current_rsrp); */ void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id); -void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac,nr_downlink_indication_t *dl_info, int pdu_id); - typedef struct { union { NR_BSR_SHORT s; @@ -187,28 +156,12 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce, const type_bsr_t *bsr, uint8_t *mac_ce_end); -void config_dci_pdu(NR_UE_MAC_INST_t *mac, - fapi_nr_dl_config_request_t *dl_config, - const int rnti_type, - const int slot, - const NR_SearchSpace_t *ss); - void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl_config, const frame_t frame, const int slot); void set_precoding_information_parameters(nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, int n_antenna_port, long transformPrecoder, int precoding_information, NR_PUSCH_Config_t *pusch_Config); -void set_harq_status(NR_UE_MAC_INST_t *mac, - uint8_t pucch_id, - uint8_t harq_id, - int8_t delta_pucch, - uint16_t data_toul_fb, - uint8_t dai, - int n_CCE, - int N_CCE, - frame_t frame, - int slot); bool get_downlink_ack(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch); initial_pucch_resource_t get_initial_pucch_resource(const int idx); @@ -285,15 +238,13 @@ and fills the PRACH PDU per each FD occasion. @param slotP Slot index @returns void */ -void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, int slotP); -void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot); -void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot); + void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - NR_CSI_RS_ResourceMapping_t *resourceMapping, + const NR_CSI_RS_ResourceMapping_t *resourceMapping, uint32_t bwp_size, uint32_t bwp_start); - +bool is_lcid_suspended(NR_UE_MAC_INST_t *mac, int lcid); void nr_ra_contention_resolution_failed(NR_UE_MAC_INST_t *mac); void nr_ra_succeeded(NR_UE_MAC_INST_t *mac, const uint8_t gNB_index, const frame_t frame, const int slot); void nr_ra_backoff_setting(RA_config_t *ra); @@ -320,6 +271,7 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *pdcch_order); void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS_max); void handle_time_alignment_timer_expired(NR_UE_MAC_INST_t *mac); +void handle_ulsync_loss(NR_UE_MAC_INST_t *mac); int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu, fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu, NR_PDSCH_Config_t *pdsch_Config, @@ -337,7 +289,7 @@ void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu); fapi_nr_ul_config_request_pdu_t *fapiLockIterator(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx); void release_ul_config(fapi_nr_ul_config_request_pdu_t *pdu, bool clearIt); -int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm); +int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac); // PUSCH scheduler: // - Calculate the slot in which ULSCH should be scheduled. This is current slot + K2, diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c index 6a6c7633bf..1f35df5c4b 100644 --- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c +++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c @@ -38,7 +38,7 @@ #include "nr_rlc/nr_rlc_oai_api.h" #include "RRC/NR_UE/rrc_proto.h" #include -static NR_UE_MAC_INST_t *nr_ue_mac_inst; +static NR_UE_MAC_INST_t *nr_ue_mac_inst[MAX_NUM_NR_UE_INST] = {0}; void send_srb0_rrc(int ue_id, const uint8_t *sdu, sdu_size_t sdu_len, void *data) { @@ -70,12 +70,18 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac) mac->p_Max_alt = INT_MIN; mac->msg3_C_RNTI = false; mac->ntn_ta.ntn_params_changed = false; + initNotifiedFIFO(&mac->input_nf); reset_mac_inst(mac); // need to inizialize because might not been setup (optional timer) nr_timer_stop(&mac->scheduling_info.sr_DelayTimer); memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements)); + for (int i = 0; i < MAX_NB_SSB; i++) { + mac->ssb_measurements[i].ssb_rsrp_dBm = INT_MIN; + mac->ssb_measurements[i].ssb_sinr_dB = INT_MIN; + } + memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment)); memset(&mac->ssb_list, 0, sizeof(mac->ssb_list)); @@ -124,37 +130,38 @@ NR_UE_L2_STATE_t nr_ue_get_sync_state(module_id_t mod_id) return mac->state; } -NR_UE_MAC_INST_t *nr_l2_init_ue(int nb_inst) +NR_UE_MAC_INST_t *nr_l2_init_ue(int instance_id) { - //init mac here - nr_ue_mac_inst = (NR_UE_MAC_INST_t *)calloc(nb_inst, sizeof(NR_UE_MAC_INST_t)); - AssertFatal(nr_ue_mac_inst, "Couldn't allocate %d instances of MAC module\n", nb_inst); + AssertFatal(instance_id < MAX_NUM_NR_UE_INST, "instance_id %d is out of range\n", instance_id); + AssertFatal(nr_ue_mac_inst[instance_id] == NULL, "MAC instance %d already initialized\n", instance_id); + nr_ue_mac_inst[instance_id] = calloc_or_fail(1, sizeof(NR_UE_MAC_INST_t)); - for (int j = 0; j < nb_inst; j++) { - NR_UE_MAC_INST_t *mac = &nr_ue_mac_inst[j]; - mac->ue_id = j; - nr_ue_init_mac(mac); - int ret = pthread_mutex_init(&mac->if_mutex, NULL); - AssertFatal(ret == 0, "Mutex init failed\n"); - nr_ue_mac_default_configs(mac); - if (IS_SA_MODE(get_softmodem_params())) - ue_init_config_request(mac, get_slots_per_frame_from_scs(get_softmodem_params()->numerology)); + NR_UE_MAC_INST_t *mac = nr_ue_mac_inst[instance_id]; + mac->ue_id = instance_id; + nr_ue_init_mac(mac); + int ret = pthread_mutex_init(&mac->if_mutex, NULL); + AssertFatal(ret == 0, "Mutex init failed\n"); + nr_ue_mac_default_configs(mac); + if (IS_SA_MODE(get_softmodem_params())) + ue_init_config_request(mac, get_slots_per_frame_from_scs(get_softmodem_params()->numerology)); + + static bool initialized = false; + if (!initialized) { + int rc = nr_rlc_module_init(NR_RLC_OP_MODE_UE); + AssertFatal(rc == 0, "Could not initialize RLC layer\n"); + initialized = true; } - int rc = nr_rlc_module_init(NR_RLC_OP_MODE_UE); - AssertFatal(rc == 0, "Could not initialize RLC layer\n"); + nr_rlc_activate_srb0(instance_id, NULL, send_srb0_rrc); - for (int j = 0; j < nb_inst; j++) { - nr_rlc_activate_srb0(j, NULL, send_srb0_rrc); - } - - return (nr_ue_mac_inst); + return nr_ue_mac_inst[instance_id]; } NR_UE_MAC_INST_t *get_mac_inst(module_id_t module_id) { - NR_UE_MAC_INST_t *mac = &nr_ue_mac_inst[(int)module_id]; - AssertFatal(mac, "Couldn't get MAC inst %d\n", module_id); + AssertFatal(module_id < MAX_NUM_NR_UE_INST, "module_id %d is out of range\n", module_id); + NR_UE_MAC_INST_t *mac = nr_ue_mac_inst[module_id]; + if (mac == NULL) return NULL; AssertFatal(mac->ue_id == module_id, "MAC ID %d doesn't match with input %d\n", mac->ue_id, module_id); return mac; } @@ -196,6 +203,7 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac) // stop any ongoing RACH procedure if (nr_mac->ra.RA_active) { + nr_mac->msg3_C_RNTI = false; nr_mac->ra.ra_state = nrRA_UE_IDLE; nr_mac->ra.RA_active = false; } @@ -271,7 +279,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, NR_UE_MAC_reset_cause_t ca // in case of re-establishment we don't need to release initial BWP config common int first_bwp_rel = 0; // first BWP to release - if (cause == RE_ESTABLISHMENT) { + if (cause == RE_ESTABLISHMENT || cause == RRC_SETUP_REESTAB_RESUME) { first_bwp_rel = 1; // release dedicated BWP0 config NR_UE_DL_BWP_t *bwp = mac->dl_BWPs.array[0]; @@ -299,7 +307,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, NR_UE_MAC_reset_cause_t ca release_ul_BWP(mac, i); memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements)); - memset(&mac->csirs_measurements, 0, sizeof(mac->csirs_measurements)); + memset(&mac->l1_measurements, 0, sizeof(mac->l1_measurements)); memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment)); for (int i = mac->TAG_list.count; i > 0 ; i--) asn_sequence_del(&mac->TAG_list, i - 1, 1); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index 2f717a7466..0dae34eda7 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -42,7 +42,7 @@ int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac) { RA_config_t *ra = &mac->ra; - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int16_t pathloss = compute_nr_SSB_PL(mac); int16_t ra_preamble_rx_power = (int16_t)(ra->prach_resources.ra_preamble_rx_target_power + pathloss); return min(ra->prach_resources.Pc_max, ra_preamble_rx_power); } @@ -177,7 +177,7 @@ static void select_preamble_group(NR_UE_MAC_INST_t *mac) // – preambleReceivedTargetPower – msg3-DeltaPreamble – messagePowerOffsetGroupB int groupB_pow_offset = get_messagePowerOffsetGroupB(groupB->messagePowerOffsetGroupB); int PLThreshold = ra->prach_resources.Pc_max - ra->preambleRxTargetPower - ra->msg3_deltaPreamble - groupB_pow_offset; - int pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int pathloss = compute_nr_SSB_PL(mac); // TODO if the Random Access procedure was initiated for the CCCH logical channel and the CCCH SDU size // plus MAC subheader is greater than ra-Msg3SizeGroupA if (ra->Msg3_size > get_Msg3SizeGroupA(groupB->ra_Msg3SizeGroupA) && pathloss < PLThreshold) @@ -818,7 +818,7 @@ static void setup_ra_response_window(RA_config_t *ra, int ta_Common_slots = 0; if (ntn_Config_r17) { - const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(ntn_ta); + const double ta_Common_ms = get_total_TA_ms(ntn_ta); ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_frame / 10); } @@ -835,34 +835,7 @@ bool init_RA(NR_UE_MAC_INST_t *mac, int frame) // TODO this piece of code is required to compute MSG3_size that is used by ra_preambles_config function // Not a good implementation, it needs improvements - int size_sdu = 0; - - // Concerning the C-RNTI MAC CE, - // it has to be included if the UL transmission (Msg3) is not being made for the CCCH logical channel. - // Therefore it has been assumed that this event only occurs only when RA is done and it is not SA mode. - if (get_softmodem_params()->nsa) { - - uint8_t mac_sdus[34 * 1056]; - uint16_t sdu_lengths[NB_RB_MAX] = {0}; - int TBS_bytes = 848; - int mac_ce_len = 0; - unsigned short post_padding = 1; - - // fill ulsch_buffer with random data - for (int i = 0; i < TBS_bytes; i++) { - mac_sdus[i] = (unsigned char)(rand()&0xff); - } - // Sending SDUs with size 1 - // Initialize elements of sdu_lengths - sdu_lengths[0] = TBS_bytes - 3 - post_padding - mac_ce_len; - size_sdu += sdu_lengths[0]; - - if (size_sdu > 0) { - memcpy(ra->cont_res_id, mac_sdus, sizeof(uint8_t) * 6); - ra->Msg3_size = size_sdu + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT); - } - - } else if (!IS_SA_MODE(get_softmodem_params())) + if (!IS_SA_MODE(get_softmodem_params())) ra->Msg3_size = sizeof(uint16_t) + sizeof(NR_MAC_SUBHEADER_FIXED); // Random acces procedure initialization @@ -879,23 +852,23 @@ bool init_RA(NR_UE_MAC_INST_t *mac, int frame) // set POWER_OFFSET_2STEP_RA to 0 dB prach_resources->power_offset_2step = 0; - const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; // perform the BWP operation as specified in clause 5.15 // if PRACH occasions are not configured for the active UL BWP - if (!current_UL_BWP->rach_ConfigCommon) { + if (!mac->current_UL_BWP->rach_ConfigCommon) { // switch the active UL BWP to BWP indicated by initialUplinkBWP - current_UL_BWP = get_ul_bwp_structure(mac, 0, false); + mac->current_UL_BWP = get_ul_bwp_structure(mac, 0, false); // if the Serving Cell is an SpCell // switch the active DL BWP to BWP indicated by initialDownlinkBWP mac->current_DL_BWP = get_dl_bwp_structure(mac, 0, false); } else { // if the active DL BWP does not have the same bwp-Id as the active UL BWP - if (current_UL_BWP->bwp_id != mac->current_DL_BWP->bwp_id) { + if (mac->current_UL_BWP->bwp_id != mac->current_DL_BWP->bwp_id) { // switch the active DL BWP to the DL BWP with the same bwp-Id as the active UL BWP mac->current_DL_BWP = get_dl_bwp_structure(mac, 0, false); } } + const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = current_UL_BWP->rach_ConfigCommon; AssertFatal(nr_rach_ConfigCommon, "rach-ConfigCommon should be configured here\n"); // stop the bwp-InactivityTimer associated with the active DL BWP of this Serving Cell, if running @@ -971,7 +944,7 @@ bool init_RA(NR_UE_MAC_INST_t *mac, int frame) "msgA_RSRP_Threshold_r16 is mandatory present if both 2-step and 4-step random access types are configured\n"); // For thresholds the RSRP value is (IE value – 156) dBm except for the IE 127 in which case the actual value is infinity int rsrp_msga_thr = *twostep_conf->msgA_RSRP_Threshold_r16 - 156; - if (*twostep_conf->msgA_RSRP_Threshold_r16 != 127 && mac->ssb_measurements.ssb_rsrp_dBm > rsrp_msga_thr) + if (*twostep_conf->msgA_RSRP_Threshold_r16 != 127 && mac->ssb_measurements[mac->mib_ssb].ssb_rsrp_dBm > rsrp_msga_thr) twostep = true; } else { // if the BWP selected for Random Access procedure is only configured with 2-step RA type Random Access @@ -1066,7 +1039,7 @@ void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, s { RA_config_t *ra = &mac->ra; NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon; - const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(&mac->ntn_ta); + const double ta_Common_ms = get_total_TA_ms(&mac->ntn_ta); const int slots_per_ms = mac->frame_structure.numb_slots_frame / 10; // start contention resolution timer @@ -1141,7 +1114,7 @@ void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS *(NR_MAC_SUBHEADER_FIXED *)pdu = (NR_MAC_SUBHEADER_FIXED){.LCID = UL_SCH_LCID_PADDING}; pdu += sizeof(NR_MAC_SUBHEADER_FIXED); } - ra->Msg3_buffer = calloc(TBS_max, sizeof(uint8_t)); + ra->Msg3_buffer = calloc_or_fail(TBS_max, sizeof(uint8_t)); memcpy(ra->Msg3_buffer, buf, sizeof(uint8_t) * TBS_max); } @@ -1193,7 +1166,9 @@ void nr_ra_contention_resolution_failed(NR_UE_MAC_INST_t *mac) ra->t_crnti = 0; // flush MSG3 buffer free_and_zero(ra->Msg3_buffer); - nr_mac_rrc_msg3_ind(mac->ue_id, 0, true); + // MSG3 with C-RNTI is a L2 procedure, we shouldn't send any indication to RRC + if (!mac->msg3_C_RNTI) + nr_mac_rrc_msg3_ind(mac->ue_id, 0, true); NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources; prach_resources->preamble_tx_counter++; if (prach_resources->preamble_tx_counter == ra->preambleTransMax + 1) { @@ -1251,25 +1226,18 @@ void prepare_msg4_msgb_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack) NR_UE_DL_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[pid]; int sched_slot = current_harq->ul_slot; int sched_frame = current_harq->ul_frame; - mac->nr_ue_emul_l1.num_harqs = 1; PUCCH_sched_t pucch = {.n_CCE = current_harq->n_CCE, .N_CCE = current_harq->N_CCE, .ack_payload = ack_nack, .n_harq = 1}; current_harq->active = false; current_harq->ack_received = false; - if (get_softmodem_params()->emulate_l1) { - mac->nr_ue_emul_l1.harq[pid].active = true; - mac->nr_ue_emul_l1.harq[pid].active_dl_harq_sfn = sched_frame; - mac->nr_ue_emul_l1.harq[pid].active_dl_harq_slot = sched_slot; - } - fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_PUCCH); - if (!pdu) - return; - int ret = nr_ue_configure_pucch(mac, sched_slot, sched_frame, mac->ra.t_crnti, &pucch, &pdu->pucch_config_pdu); - if (ret != 0) - remove_ul_config_last_item(pdu); - release_ul_config(pdu, false); + + RA_config_t *ra = &mac->ra; + ra->ra_pucch = calloc_or_fail(1, sizeof(*ra->ra_pucch)); + ra->ra_pucch->pucch_sched = pucch; + ra->ra_pucch->sched_frame = sched_frame; + ra->ra_pucch->sched_slot = sched_slot; } void reset_ra(NR_UE_MAC_INST_t *nr_mac, bool free_prach) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index 7a2e9c6ed9..218a513ec7 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -104,11 +104,11 @@ NR_ControlResourceSet_t *ue_get_coreset(const NR_BWP_PDCCH_t *config, const int return coreset; } -void config_dci_pdu(NR_UE_MAC_INST_t *mac, - fapi_nr_dl_config_request_t *dl_config, - const int rnti_type, - const int slot, - const NR_SearchSpace_t *ss) +static void config_dci_pdu(NR_UE_MAC_INST_t *mac, + fapi_nr_dl_config_request_t *dl_config, + const int rnti_type, + const int slot, + const NR_SearchSpace_t *ss) { const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP; const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP; @@ -385,12 +385,14 @@ bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac, return false; } -bool is_window_valid(NR_UE_MAC_INST_t *mac, int window_slots, int abs_slot) +static bool is_window_valid(NR_UE_MAC_INST_t *mac, int window_slots, int abs_slot, int slots_per_frame) { if (mac->si_SchedInfo.si_window_start == -1) { // out of window return false; - } else if (abs_slot > mac->si_SchedInfo.si_window_start + window_slots) { + } else if ((abs_slot - mac->si_SchedInfo.si_window_start + MAX_FRAME_NUMBER * slots_per_frame) + % (MAX_FRAME_NUMBER * slots_per_frame) + >= window_slots) { // window expired mac->si_SchedInfo.si_window_start = -1; return false; @@ -407,33 +409,18 @@ static bool monitor_dci_for_other_SI(NR_UE_MAC_INST_t *mac, { // according to 5.2.2.3.2 in 331 const int abs_slot = frame * slots_per_frame + slot; + const si_schedinfo_config_t *config = mac->si_SchedInfo.si_SchedInfo_list.array[si_idx]; + const int window_slots = 5 << mac->si_SchedInfo.si_WindowLength; + const int x = (config->si_WindowPosition - 1) * window_slots; + const int T = 8 << config->si_Periodicity; // radio frame periodicity - si_schedinfo_config_t *config = mac->si_SchedInfo.si_SchedInfo_list.array[si_idx]; - int window_slots = 5 << mac->si_SchedInfo.si_WindowLength; - int x = (config->si_WindowPosition - 1) * window_slots; - int T = 8 << config->si_Periodicity; // radio frame periodicity - bool check_valid; - switch (config->type) { - case NR_SI_INFO : - if (mac->si_SchedInfo.si_window_start == -1) { - if ((frame % T) == (x / slots_per_frame) && (x % slots_per_frame == 0)) - mac->si_SchedInfo.si_window_start = abs_slot; // in terms of absolute slot number - } - check_valid = is_window_valid(mac, window_slots, abs_slot); - if (check_valid && search_space_monitoring_ocasion_other_si(mac, ss, abs_slot, frame, slot, slots_per_frame)) - return true; - break; - case NR_SI_INFO_v1700 : - if (mac->si_SchedInfo.si_window_start == -1) { - if ((frame % T == floor(x / slots_per_frame)) && (slot == x % slots_per_frame)) - mac->si_SchedInfo.si_window_start = abs_slot; - } - if (is_window_valid(mac, window_slots, abs_slot)) - return search_space_monitoring_ocasion_other_si(mac, ss, abs_slot, frame, slot, slots_per_frame); - break; - default : - AssertFatal(false, "Invalid SI-SchedulingInfo case\n"); + if (mac->si_SchedInfo.si_window_start == -1) { + if ((frame % T) == (x / slots_per_frame) && (slot == x % slots_per_frame)) + mac->si_SchedInfo.si_window_start = abs_slot; // in terms of absolute slot number } + if (is_window_valid(mac, window_slots, abs_slot, slots_per_frame)) + return search_space_monitoring_ocasion_other_si(mac, ss, abs_slot, frame, slot, slots_per_frame); + return false; } @@ -502,19 +489,42 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl config_dci_pdu(mac, dl_config, rnti_type, slot, ra_SS); } } else if (mac->state == UE_CONNECTED) { + /* + In RRC Connected state, the UE monitors for fallback DCI with C-RNTI in common and UE-specific SS. + First the UE check all UE specific SS. If no fallback DCI is configured, it configures one of following + common SS with the shown priority + 1. RA SS + 2. Other SI SS + 3. Paging SS + 4. SIB1 SS + + There is a possibility that gNB could configure multiple UE-specific SS for fallback DCI or/and common SS, + and in a given slot more than one SS become active. For the moment, we assume such configuration wouldn't happen + and hence don't handle it for the sake of implementation simplicity. + */ + bool configured_fallback_dci = false; for (int i = 0; i < pdcch_config->list_SS.count; i++) { NR_SearchSpace_t *ss = pdcch_config->list_SS.array[i]; - if (is_ss_monitor_occasion(frame, slot, slots_per_frame, ss)) + if (is_ss_monitor_occasion(frame, slot, slots_per_frame, ss)) { config_dci_pdu(mac, dl_config, TYPE_C_RNTI_, slot, ss); + configured_fallback_dci |= (ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common); + } } - const NR_SearchSpace_t *ra_SS = get_common_search_space(mac, pdcch_config->ra_SS_id); - if (pdcch_config->list_SS.count == 0 && ra_SS) { - // If the UE has not been provided a Type3-PDCCH CSS set or a USS set and - // the UE has received a C-RNTI and has been provided a Type1-PDCCH CSS set, - // the UE monitors PDCCH candidates for DCI format 0_0 and DCI format 1_0 - // with CRC scrambled by the C-RNTI in the Type1-PDCCH CSS set - if (is_ss_monitor_occasion(frame, slot, slots_per_frame, ra_SS)) - config_dci_pdu(mac, dl_config, TYPE_C_RNTI_, slot, ra_SS); + const NR_SearchSpace_t *css = NULL; + if (!configured_fallback_dci) { +#define CSS_VALID_CUR_SLOT(CSS) \ + ((CSS > -1) && is_ss_monitor_occasion(frame, slot, slots_per_frame, get_common_search_space(mac, CSS))) + if (CSS_VALID_CUR_SLOT(pdcch_config->ra_SS_id)) + css = get_common_search_space(mac, pdcch_config->ra_SS_id); + else if (CSS_VALID_CUR_SLOT(pdcch_config->otherSI_SS_id)) + css = get_common_search_space(mac, pdcch_config->otherSI_SS_id); + else if (CSS_VALID_CUR_SLOT(pdcch_config->paging_SS_id)) + css = get_common_search_space(mac, pdcch_config->paging_SS_id); +#undef CSS_VALID_CUR_SLOT + else + css = mac->search_space_zero; + AssertFatal(css, "Atleast one CSS should be present in connected state\n"); + config_dci_pdu(mac, dl_config, TYPE_C_RNTI_, slot, css); } } } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c index 1efa0f1f12..860089165f 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -358,7 +358,7 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac, 1, start_prb); float P_CMIN = current_UL_BWP->P_CMIN; - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int16_t pathloss = compute_nr_SSB_PL(mac); if (power_config->twoPUCCH_PC_AdjustmentStates && *power_config->twoPUCCH_PC_AdjustmentStates > 1) { LOG_E(MAC,"PUCCH power control adjustment states with 2 states not yet implemented\n"); @@ -427,20 +427,23 @@ static int get_deltatf(uint16_t nb_of_prbs, // - 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) +int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac) { + // getting the maximum SSB RSRP from the SSB measurements + int max_ssb_rsrp_dBm = mac->ssb_measurements[mac->mib_ssb].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); + int16_t pathloss = (int16_t)(referenceSignalPower - max_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)); + max_ssb_rsrp_dBm, + pow(10, max_ssb_rsrp_dBm/10)); return pathloss; } @@ -557,8 +560,8 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac, DELTA_TF = 10 * log10(pow(2, BPRE * 1.25f) * beta_offset); } - // TODO: compute pathoss using correct reference - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + // TODO: compute pathloss using correct reference + int16_t pathloss = compute_nr_SSB_PL(mac); int P_CMIN = mac->current_UL_BWP->P_CMIN; float pusch_power_without_f_b_f_c = P_O_PUSCH + M_pusch_component + alpha * pathloss + DELTA_TF; @@ -626,7 +629,7 @@ int get_srs_tx_power_ue(NR_UE_MAC_INST_t *mac, get_m_srs(srs_resource->freqHopping.c_SRS, srs_resource->freqHopping.b_SRS), 0); // TODO: Determine SRS start RB - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int16_t pathloss = compute_nr_SSB_PL(mac); int srs_power_without_h_b_f_c = P_0_SRS + alpha * pathloss + m_srs_component; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 5d3102c07d..7818b08362 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -78,6 +78,12 @@ const uint16_t table_7_2_1[16] = { 1920, // row index 13 }; +typedef struct { + uint32_t ssb_index; + short ssb_rsrp_dBm; + float_t ssb_sinr_dB; +} NR_RSRP_meas_t; + /* TS 36.213 Table 9.2.3-3: Mapping of values for one HARQ-ACK bit to sequences */ static const int sequence_cyclic_shift_1_harq_ack_bit[2] /* HARQ-ACK Value 0 1 */ @@ -113,6 +119,42 @@ random-access procedure */ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id); +/*! \fn int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id); + \brief This function schedules a positive or negative SR for schedulingRequestID sr_id + depending on the presence of any active SR and the prohibit timer. + If the max number of retransmissions is reached, it triggers a new RA */ +static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id); + +static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig); + +static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig, + CSI_mapping_t mapping_type); +static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + const NR_CSI_MeasConfig_t *csi_MeasConfig); + +static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp); + +static void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id); + +static void set_harq_status(NR_UE_MAC_INST_t *mac, + uint8_t pucch_id, + uint8_t harq_id, + int8_t delta_pucch, + uint16_t data_toul_fb, + uint8_t dai, + int n_CCE, + int N_CCE, + frame_t frame, + int slot); + int get_pucch0_mcs(const int O_ACK, const int O_SR, const int ack_payload, const int sr_payload) { int mcs = 0; @@ -238,37 +280,31 @@ void nr_ue_decode_mib(NR_UE_MAC_INST_t *mac, int cc_id) mac->ssb_subcarrier_offset = ssb_subcarrier_offset; mac->dmrs_TypeA_Position = mac->mib->dmrs_TypeA_Position; - if (get_softmodem_params()->phy_test) - mac->state = UE_CONNECTED; - else if (mac->state == UE_NOT_SYNC) { - if (IS_SA_MODE(get_softmodem_params()) && mac->get_sib1) - mac->state = UE_RECEIVING_SIB; - else - mac->state = UE_PERFORMING_RA; - } } static void configure_ratematching_csi(fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_pdu, - fapi_nr_dl_config_request_t *dl_config, + const fapi_nr_dl_config_request_t *dl_config, int rnti_type, int frame, int slot, int mu, int slots_per_frame, - NR_PDSCH_Config_t *pdsch_config) + const NR_PDSCH_Config_t *pdsch_config, + NR_CSI_MeasConfig_t *csi_MeasConfig) { // only for C-RNTI, MCS-C-RNTI, CS-RNTI (and only C-RNTI is supported for now) if (rnti_type != TYPE_C_RNTI_) return; if (pdsch_config && pdsch_config->zp_CSI_RS_ResourceToAddModList) { - for (int i = 0; i < pdsch_config->zp_CSI_RS_ResourceToAddModList->list.count; i++) { - NR_ZP_CSI_RS_Resource_t *zp_res = pdsch_config->zp_CSI_RS_ResourceToAddModList->list.array[i]; - NR_ZP_CSI_RS_ResourceId_t id = zp_res->zp_CSI_RS_ResourceId; - NR_SetupRelease_ZP_CSI_RS_ResourceSet_t *zp_set = pdsch_config->p_ZP_CSI_RS_ResourceSet; - AssertFatal(zp_set && zp_set->choice.setup, "Only periodic ZP resource set is implemented\n"); - bool found = false; - for (int j = 0; j < zp_set->choice.setup->zp_CSI_RS_ResourceIdList.list.count; j++) { + bool found = false; + const NR_SetupRelease_ZP_CSI_RS_ResourceSet_t *zp_set = pdsch_config->p_ZP_CSI_RS_ResourceSet; + AssertFatal(zp_set && zp_set->choice.setup, "Only periodic ZP resource set is implemented\n"); + const NR_ZP_CSI_RS_Resource_t *zp_res = NULL; + for (int j = 0; j < zp_set->choice.setup->zp_CSI_RS_ResourceIdList.list.count; j++) { + for (int i = 0; i < pdsch_config->zp_CSI_RS_ResourceToAddModList->list.count; i++) { + zp_res = pdsch_config->zp_CSI_RS_ResourceToAddModList->list.array[i]; + NR_ZP_CSI_RS_ResourceId_t id = zp_res->zp_CSI_RS_ResourceId; if (*zp_set->choice.setup->zp_CSI_RS_ResourceIdList.list.array[j] == id) { found = true; break; @@ -289,9 +325,28 @@ static void configure_ratematching_csi(fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsc } } + // Handle NZP CSI-RS for rate matching + if (csi_MeasConfig && csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList) { + for (int i = 0; i < csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList->list.count; i++) { + NR_NZP_CSI_RS_Resource_t *nzp_res = csi_MeasConfig->nzp_CSI_RS_ResourceToAddModList->list.array[i]; + if (nzp_res->periodicityAndOffset) { + int period, offset; + csi_period_offset(NULL, nzp_res->periodicityAndOffset, &period, &offset); + if ((frame * slots_per_frame + slot - offset) % period != 0) + continue; + AssertFatal(dlsch_pdu->numCsiRsForRateMatching < NFAPI_MAX_NUM_CSI_RATEMATCH, "csiRsForRateMatching out of bounds\n"); + fapi_nr_dl_config_csirs_pdu_rel15_t *csi_pdu = &dlsch_pdu->csiRsForRateMatching[dlsch_pdu->numCsiRsForRateMatching]; + csi_pdu->csi_type = 1; // NZP CSI-RS + csi_pdu->subcarrier_spacing = mu; + configure_csi_resource_mapping(csi_pdu, &nzp_res->resourceMapping, dlsch_pdu->BWPSize, dlsch_pdu->BWPStart); + dlsch_pdu->numCsiRsForRateMatching++; + } + } + } + for (int i = 0; i < dl_config->number_pdus; i++) { // This assumes that CSI-RS are scheduled before this moment which is true in current implementation - fapi_nr_dl_config_request_pdu_t *csi_req = &dl_config->dl_config_list[i]; + const fapi_nr_dl_config_request_pdu_t *csi_req = &dl_config->dl_config_list[i]; if (csi_req->pdu_type == FAPI_NR_DL_CONFIG_TYPE_CSI_RS) { AssertFatal(dlsch_pdu->numCsiRsForRateMatching < NFAPI_MAX_NUM_CSI_RATEMATCH, "csiRsForRateMatching out of bounds\n"); dlsch_pdu->csiRsForRateMatching[dlsch_pdu->numCsiRsForRateMatching] = csi_req->csirs_config_pdu.csirs_config_rel15; @@ -305,17 +360,20 @@ void nr_ue_decode_BCCH_DL_SCH(NR_UE_MAC_INST_t *mac, unsigned int gNB_index, uint8_t ack_nack, uint8_t *pduP, - uint32_t pdu_len) + uint32_t pdu_len, + int frame, + int slot) { if(ack_nack) { LOG_D(NR_MAC, "Decoding NR-BCCH-DL-SCH-Message (SIB1 or SI)\n"); - nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, 0, 0, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, (uint8_t *) pduP, pdu_len); + nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, frame, slot, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, (uint8_t *) pduP, pdu_len); if (mac->get_sib1) mac->get_sib1 = false; for (int i = 0; i < MAX_SI_GROUPS; i++) { if (mac->get_otherSI[i]) mac->get_otherSI[i] = false; } + mac->si_SchedInfo.si_window_start = -1; T(T_NRUE_MAC_DL_PDU_WITH_DATA, T_INT(SI_RNTI), T_INT(-1 /* frame, unavailable here */), @@ -325,7 +383,7 @@ void nr_ue_decode_BCCH_DL_SCH(NR_UE_MAC_INST_t *mac, } else { LOG_E(NR_MAC, "Got NACK on NR-BCCH-DL-SCH-Message (%s)\n", mac->get_sib1 ? "SIB1" : "other SI"); - nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, 0, 0, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, NULL, 0); + nr_mac_rrc_data_ind_ue(mac->ue_id, cc_id, gNB_index, frame, slot, 0, mac->physCellId, 0, NR_BCCH_DL_SCH, NULL, 0); } } @@ -722,8 +780,13 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, dlsch_pdu->SubcarrierSpacing = mac->mib->subCarrierSpacingCommon + 2; } else { dlsch_pdu->SubcarrierSpacing = current_DL_BWP->scs; - if (nr_timer_is_active(&mac->ra.response_window_timer) && rnti_type == TYPE_RA_RNTI_) { - dl_conf_req->pdu_type = FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH; + if (rnti_type == TYPE_RA_RNTI_) { + if (nr_timer_is_active(&mac->ra.response_window_timer)) { + dl_conf_req->pdu_type = FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH; + } else { + // Discard the DCI + return -1; + } } else { dl_conf_req->pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH; } @@ -731,8 +794,15 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, dlsch_pdu->numCsiRsForRateMatching = 0; int slots_frame = mac->frame_structure.numb_slots_frame; - configure_ratematching_csi(dlsch_pdu, dl_config, rnti_type, frame, slot, dlsch_pdu->SubcarrierSpacing, slots_frame, pdsch_config); - + configure_ratematching_csi(dlsch_pdu, + dl_config, + rnti_type, + frame, + slot, + dlsch_pdu->SubcarrierSpacing, + slots_frame, + pdsch_config, + mac->sc_info.csi_MeasConfig); /* IDENTIFIER_DCI_FORMATS */ /* FREQ_DOM_RESOURCE_ASSIGNMENT_DL */ @@ -748,10 +818,7 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac, return -1; } - dlsch_pdu->rb_offset = dlsch_pdu->start_rb + dlsch_pdu->BWPStart; - - if (mac->get_sib1) - dlsch_pdu->rb_offset -= dlsch_pdu->BWPStart; + dlsch_pdu->refPoint = mac->get_sib1 ? 1 : 0; /* TIME_DOM_RESOURCE_ASSIGNMENT */ int dmrs_typeA_pos = mac->dmrs_TypeA_Position; @@ -1067,7 +1134,15 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, nr_rnti_type_t rnti_type = get_rnti_type(mac, dci_ind->rnti); dlsch_pdu->numCsiRsForRateMatching = 0; int slots_frame = mac->frame_structure.numb_slots_frame; - configure_ratematching_csi(dlsch_pdu, dl_config, rnti_type, frame, slot, current_DL_BWP->scs, slots_frame, pdsch_Config); + configure_ratematching_csi(dlsch_pdu, + dl_config, + rnti_type, + frame, + slot, + current_DL_BWP->scs, + slots_frame, + pdsch_Config, + mac->sc_info.csi_MeasConfig); /* IDENTIFIER_DCI_FORMATS */ /* CARRIER_IND */ @@ -1085,7 +1160,7 @@ static int nr_ue_process_dci_dl_11(NR_UE_MAC_INST_t *mac, LOG_W(MAC, "[%d.%d] Invalid frequency_domain_assignment. Possibly due to false DCI. Ignoring DCI!\n", frame, slot); return -1; } - dlsch_pdu->rb_offset = dlsch_pdu->start_rb + dlsch_pdu->BWPStart; + dlsch_pdu->refPoint = 0; /* TIME_DOM_RESOURCE_ASSIGNMENT */ int dmrs_typeA_pos = mac->dmrs_TypeA_Position; int mux_pattern = 1; @@ -1431,25 +1506,34 @@ nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t return format; } -int8_t nr_ue_process_csirs_measurements(NR_UE_MAC_INST_t *mac, - frame_t frame, - int slot, - fapi_nr_csirs_measurements_t *csirs_measurements) { - LOG_D(NR_MAC,"(%d.%d) Received CSI-RS measurements\n", frame, slot); - memcpy(&mac->csirs_measurements, csirs_measurements, sizeof(*csirs_measurements)); - return 0; +void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements) +{ + LOG_D(NR_MAC, "(%d.%d) Received CSI-RS measurements\n", frame, slot); + memcpy(&mac->l1_measurements, l1_measurements, sizeof(*l1_measurements)); + bool csi_meas = l1_measurements->meas_type == NFAPI_NR_CSI_MEAS; + if (!csi_meas && !l1_measurements->is_neighboring_cell) { + int ssb_index = l1_measurements->ssb_index; + mac->ssb_measurements[ssb_index].ssb_rsrp_dBm = l1_measurements->rsrp_dBm; + mac->ssb_measurements[ssb_index].ssb_sinr_dB = l1_measurements->sinr_dB; + } + nr_mac_rrc_meas_ind_ue(mac->ue_id, + l1_measurements->gNB_index, + l1_measurements->Nid_cell, + csi_meas, + l1_measurements->is_neighboring_cell, + l1_measurements->rsrp_dBm); } -void set_harq_status(NR_UE_MAC_INST_t *mac, - uint8_t pucch_id, - uint8_t harq_id, - int8_t delta_pucch, - uint16_t data_toul_fb, - uint8_t dai, - int n_CCE, - int N_CCE, - frame_t frame, - int slot) +static void set_harq_status(NR_UE_MAC_INST_t *mac, + uint8_t pucch_id, + uint8_t harq_id, + int8_t delta_pucch, + uint16_t data_toul_fb, + uint8_t dai, + int n_CCE, + int N_CCE, + frame_t frame, + int slot) { NR_UE_DL_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[harq_id]; current_harq->active = true; @@ -2332,11 +2416,6 @@ bool get_downlink_ack(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sche dl_harq_pid, current_harq->ul_frame, current_harq->ul_slot); /* check if current tx slot should transmit downlink acknowlegment */ if (current_harq->ul_frame == frame && current_harq->ul_slot == slot) { - if (get_softmodem_params()->emulate_l1) { - mac->nr_ue_emul_l1.harq[dl_harq_pid].active = true; - mac->nr_ue_emul_l1.harq[dl_harq_pid].active_dl_harq_sfn = frame; - mac->nr_ue_emul_l1.harq[dl_harq_pid].active_dl_harq_slot = slot; - } if (res_ind != -1 && res_ind != current_harq->pucch_resource_indicator) LOG_E(NR_MAC, "Value of pucch_resource_indicator %d not matching with what set before %d (Possibly due to a false DCI) \n", @@ -2525,7 +2604,7 @@ bool trigger_periodic_scheduling_request(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *p return sr_count > 0; } -int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id) +static int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_SchedulingRequestId_t sr_id) { // no UL-SCH resources available for this tti && UE has a valid PUCCH resources for SR configuration for this tti NR_UE_SCHEDULING_INFO *si = &mac->scheduling_info; @@ -2682,6 +2761,14 @@ static uint8_t get_sinr_diff_index(float best_sinr, float current_sinr) return diff; } +// Comparison function for sorting SSB SINR measurements in descending order +static int compare_ssb_sinr(const void *a, const void *b) +{ + const NR_RSRP_meas_t *ma = (const NR_RSRP_meas_t *)a; + const NR_RSRP_meas_t *mb = (const NR_RSRP_meas_t *)b; + return mb->ssb_sinr_dB - ma->ssb_sinr_dB; +} + static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, struct NR_CSI_ReportConfig *csi_reportconfig, NR_CSI_ResourceConfigId_t csi_ResourceConfigId, @@ -2690,7 +2777,7 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, int nb_ssb = 0; // nb of ssb in the resource int nb_meas = 0; // nb of ssb to report measurements on int bits = 0; - uint32_t temp_payload = 0; + uint64_t temp_payload = 0; for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; @@ -2715,51 +2802,55 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, } AssertFatal(nb_ssb > 0, "No SSB found in the resource set\n"); - AssertFatal(nb_meas == 1, "PHY currently reports only the strongest SSB to MAC. Can't report more than 1 RSRP\n"); + AssertFatal(nb_meas <= 4,"Can't report more than 4 RSRPs\n"); int ssbri_bits = ceil(log2(nb_ssb)); - int ssb_index[nb_meas]; // the array contains index and RSRP of each SSB to be reported (nb_meas highest RSRPs) - float ssb_sinr[nb_meas]; - - // TODO replace the following 2 lines with a function to order the nb_meas highest SSB RSRPs - for (int i = 0; i < nb_ssb; i++) { - ssb_index[i] = -1;//Invalid index - if (*SSB_resource.list.array[i] == mac->mib_ssb) { - ssb_index[0] = i; - break; + // map SSB index to SSB resource table index, copy measurements, sort in descending order + NR_RSRP_meas_t sorted_sinr_measurements[nb_ssb]; + int sorted_idx = 0; + for (int measured_ssb_idx = 0; measured_ssb_idx < MAX_NB_SSB; measured_ssb_idx++) { + // searching for the SSB index in the SSB resource table + for (int ssb_resource = 0; ssb_resource < nb_ssb; ssb_resource++) { + if (*SSB_resource.list.array[ssb_resource] == measured_ssb_idx) { + sorted_sinr_measurements[sorted_idx].ssb_index = ssb_resource; + sorted_sinr_measurements[sorted_idx].ssb_rsrp_dBm = mac->ssb_measurements[measured_ssb_idx].ssb_rsrp_dBm; + sorted_sinr_measurements[sorted_idx].ssb_sinr_dB = mac->ssb_measurements[measured_ssb_idx].ssb_sinr_dB; + sorted_idx++; + break; + } } } - AssertFatal(ssb_index[0] >= 0, "Couldn't find corresponding SSB in csi_SSB_ResourceList\n"); - ssb_sinr[0] = mac->ssb_measurements.ssb_sinr_dB; + qsort(sorted_sinr_measurements, nb_ssb, sizeof(NR_RSRP_meas_t), compare_ssb_sinr); uint8_t ssbi; // TS38.212 v16.5.0: Table 6.3.1.1.2-8A if (ssbri_bits > 0) { - ssbi = ssb_index[0]; + ssbi = sorted_sinr_measurements[0].ssb_index; temp_payload = reverse_bits(ssbi, ssbri_bits); bits += ssbri_bits; } - uint8_t sinr_idx = get_sinr_index(ssb_sinr[0]); + uint8_t sinr_idx = get_sinr_index(sorted_sinr_measurements[0].ssb_sinr_dB); temp_payload |= (reverse_bits(sinr_idx, 7) << bits); bits += 7; // 7 bits for highest SINR // from the second SSB, differential report for (int i = 1; i < nb_meas; i++) { - ssbi = ssb_index[i]; - temp_payload = reverse_bits(ssbi, ssbri_bits); + ssbi = sorted_sinr_measurements[i].ssb_index; + temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits); bits += ssbri_bits; - sinr_idx = get_sinr_diff_index(ssb_sinr[0], ssb_sinr[i]); + sinr_idx = get_sinr_diff_index(sorted_sinr_measurements[0].ssb_sinr_dB, sorted_sinr_measurements[i].ssb_sinr_dB); temp_payload |= (reverse_bits(sinr_idx, 4) << bits); - bits += 4; // 7 bits for highest SINR + bits += 4; // 4 bits for differential SINR } break; // resource found } } - AssertFatal(bits <= 32, "Not supporting CSI report with more than 32 bits\n"); - csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = bits, csi.p2_bits = 0}; + int max_bits = sizeof(((csi_payload_t *)0)->part1_payload) * 8; + AssertFatal(bits <= max_bits, "Not supporting CSI report with more than %d bits (payload: %d bits)\n", max_bits, bits); + csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, csi.p2_bits = 0}; return csi; } @@ -2809,16 +2900,24 @@ csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, return csi; } +// Comparison function for sorting SSB RSRP measurements in descending order +static int compare_ssb_rsrp(const void *a, const void *b) +{ + const NR_RSRP_meas_t *ma = (const NR_RSRP_meas_t *)a; + const NR_RSRP_meas_t *mb = (const NR_RSRP_meas_t *)b; + return mb->ssb_rsrp_dBm - ma->ssb_rsrp_dBm; +} -csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig) + +static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig) { int nb_ssb = 0; // nb of ssb in the resource int nb_meas = 0; // nb of ssb to report measurements on int bits = 0; - uint32_t temp_payload = 0; + uint64_t temp_payload = 0; for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; @@ -2826,7 +2925,7 @@ csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, if (csi_reportconfig->groupBasedBeamReporting.present == NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled) { if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS != NULL) - nb_meas = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS)+1; + nb_meas = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + 1; else nb_meas = 1; } else @@ -2843,58 +2942,64 @@ csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac, } } - AssertFatal(nb_ssb>0,"No SSB found in the resource set\n"); - AssertFatal(nb_meas==1,"PHY currently reports only the strongest SSB to MAC. Can't report more than 1 RSRP\n"); + AssertFatal(nb_ssb > 0,"No SSB found in the resource set\n"); + AssertFatal(nb_meas <= 4,"Can't report more than 4 RSRPs\n"); int ssbri_bits = ceil(log2(nb_ssb)); - int ssb_rsrp[2][nb_meas]; // the array contains index and RSRP of each SSB to be reported (nb_meas highest RSRPs) - memset(ssb_rsrp, 0, sizeof(ssb_rsrp)); - - //TODO replace the following 2 lines with a function to order the nb_meas highest SSB RSRPs - for (int i=0; imib_ssb) { - ssb_rsrp[0][0] = i; - break; + // map SSB index to SSB resource table index, copy measurements, sort in descending order + NR_RSRP_meas_t sorted_rsrp_measurements[nb_ssb]; + int sorted_idx = 0; + for (int measured_ssb_idx = 0; measured_ssb_idx < MAX_NB_SSB; measured_ssb_idx++) { + // searching for the SSB index in the SSB resource table + for (int ssb_resource = 0; ssb_resource < nb_ssb; ssb_resource++) { + if (*SSB_resource.list.array[ssb_resource] == measured_ssb_idx) { + sorted_rsrp_measurements[sorted_idx].ssb_index = ssb_resource; + sorted_rsrp_measurements[sorted_idx].ssb_rsrp_dBm = mac->ssb_measurements[measured_ssb_idx].ssb_rsrp_dBm; + sorted_rsrp_measurements[sorted_idx].ssb_sinr_dB = mac->ssb_measurements[measured_ssb_idx].ssb_sinr_dB; + sorted_idx++; + break; + } } } - AssertFatal(*SSB_resource.list.array[ssb_rsrp[0][0]] == mac->mib_ssb, "Couldn't find corresponding SSB in csi_SSB_ResourceList\n"); - ssb_rsrp[1][0] = mac->ssb_measurements.ssb_rsrp_dBm; + qsort(sorted_rsrp_measurements, nb_ssb, sizeof(NR_RSRP_meas_t), compare_ssb_rsrp); - uint8_t ssbi; + uint32_t ssbi; if (ssbri_bits > 0) { - ssbi = ssb_rsrp[0][0]; + ssbi = sorted_rsrp_measurements[0].ssb_index; temp_payload = reverse_bits(ssbi, ssbri_bits); bits += ssbri_bits; } - uint8_t rsrp_idx = get_rsrp_index(ssb_rsrp[1][0]); + uint8_t rsrp_idx = get_rsrp_index(sorted_rsrp_measurements[0].ssb_rsrp_dBm); temp_payload |= (reverse_bits(rsrp_idx, 7) << bits); bits += 7; // 7 bits for highest RSRP // from the second SSB, differential report - for (int i=1; ipart1_payload) * 8; + AssertFatal(bits <= max_bits, "Not supporting CSI report with more than %d bits (payload: %d bits)\n", max_bits, bits); + + csi_payload_t csi = {.part1_payload = temp_payload, .part2_payload = 0, .p1_bits = bits, .p2_bits = 0}; return csi; } -csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - NR_CSI_MeasConfig_t *csi_MeasConfig, - CSI_mapping_t mapping_type) +static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig, + CSI_mapping_t mapping_type) { int p1_bits = 0; int p2_bits = 0; @@ -2921,40 +3026,28 @@ csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, AssertFatal(csi_report, "Couldn't find CSI report with ID %ld\n", csi_reportconfig->reportConfigId); int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->csirs_measurements.rank_indicator]; - int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->csirs_measurements.rank_indicator]; - int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->csirs_measurements.rank_indicator]; - - if (get_softmodem_params()->emulate_l1) { - static const uint8_t mcs_to_cqi[] = {0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, - 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15}; - CHECK_INDEX(nr_bler_data, NR_NUM_MCS - 1); - int mcs = get_mcs_from_sinr(nr_bler_data, (mac->nr_ue_emul_l1.cqi - 640) * 0.1); - CHECK_INDEX(mcs_to_cqi, mcs); - mac->csirs_measurements.rank_indicator = mac->nr_ue_emul_l1.ri; - mac->csirs_measurements.i1 = mac->nr_ue_emul_l1.pmi; - mac->csirs_measurements.cqi = mcs_to_cqi[mcs]; - } - + int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->l1_measurements.rank_indicator]; + int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->l1_measurements.rank_indicator]; + int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->l1_measurements.rank_indicator]; int padding_bitlen = 0; // TODO: Improvements will be needed to cri_bitlen>0 and pmi_x1_bitlen>0 if (mapping_type == ON_PUSCH) { p1_bits = cri_bitlen + ri_bitlen + cqi_bitlen; p2_bits = pmi_x1_bitlen + pmi_x2_bitlen; temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + ri_bitlen)) | - (mac->csirs_measurements.rank_indicator << cqi_bitlen) | - (mac->csirs_measurements.cqi); - temp_payload_2 = (mac->csirs_measurements.i1 << pmi_x2_bitlen) | - mac->csirs_measurements.i2; + (mac->l1_measurements.rank_indicator << cqi_bitlen) | + (mac->l1_measurements.cqi); + temp_payload_2 = (mac->l1_measurements.i1 << pmi_x2_bitlen) | + mac->l1_measurements.i2; } else { p1_bits = nr_get_csi_bitlen(csi_report); padding_bitlen = p1_bits - (cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen); temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen + ri_bitlen)) | - (mac->csirs_measurements.rank_indicator << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) | - (mac->csirs_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) | - (mac->csirs_measurements.i2 << (cqi_bitlen)) | - (mac->csirs_measurements.cqi); + (mac->l1_measurements.rank_indicator << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) | + (mac->l1_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) | + (mac->l1_measurements.i2 << (cqi_bitlen)) | + (mac->l1_measurements.cqi); } temp_payload_1 = reverse_bits(temp_payload_1, p1_bits); @@ -2978,10 +3071,10 @@ csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac, return csi; } -csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, - struct NR_CSI_ReportConfig *csi_reportconfig, - NR_CSI_ResourceConfigId_t csi_ResourceConfigId, - const NR_CSI_MeasConfig_t *csi_MeasConfig) +static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + const NR_CSI_MeasConfig_t *csi_MeasConfig) { int n_bits = 0; uint64_t temp_payload = 0; @@ -3013,25 +3106,14 @@ csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, } // TODO: Improvements will be needed to cri_ssbri_bitlen>0 - // TS 38.133 - Table 10.1.6.1-1 - int rsrp_dBm = mac->csirs_measurements.rsrp_dBm; - if (rsrp_dBm < -140) { - temp_payload = 16; - } else if (rsrp_dBm > -44) { - temp_payload = 113; - } else { - temp_payload = mac->csirs_measurements.rsrp_dBm + 157; - } - + temp_payload = get_rsrp_index(mac->l1_measurements.rsrp_dBm); temp_payload = reverse_bits(temp_payload, n_bits); LOG_D(NR_MAC, "cri_ssbri_bitlen = %d\n", cri_ssbri_bitlen); LOG_D(NR_MAC, "rsrp_bitlen = %d\n", rsrp_bitlen); LOG_D(NR_MAC, "diff_rsrp_bitlen = %d\n", diff_rsrp_bitlen); - LOG_D(NR_MAC, "n_bits = %d\n", n_bits); LOG_D(NR_MAC, "csi_part1_payload = 0x%lx\n", temp_payload); - break; } } @@ -3042,31 +3124,15 @@ csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac, return csi; } -// returns index from RSRP -// according to Table 10.1.6.1-1 in 38.133 - -uint8_t get_rsrp_index(int rsrp) { - - int index = rsrp + 157; - if (rsrp>-44) - index = 113; - if (rsrp<-140) - index = 16; - - return index; -} - - // returns index from differential RSRP // according to Table 10.1.6.1-2 in 38.133 -uint8_t get_rsrp_diff_index(int best_rsrp,int current_rsrp) { - +static uint8_t get_rsrp_diff_index(int best_rsrp, int current_rsrp) +{ int diff = best_rsrp-current_rsrp; if (diff>30) return 15; else return (diff>>1); - } void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) @@ -3695,7 +3761,7 @@ static int nr_ue_validate_successrar(uint8_t *pduP, // F: lenght of L is 0:8 or 1:16 bits wide // R: Reserved bit, set to zero. //////////////////////////////// -void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) +static void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) { frame_t frameP = dl_info->frame; int slot = dl_info->slot; @@ -3734,7 +3800,7 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i LOG_D(MAC, "[UE] LCID %d, PDU length %d\n", rx_lcid, pdu_len); bool ret; - switch(rx_lcid){ + switch (rx_lcid) { // MAC CE case DL_SCH_LCID_CCCH: // MSG4 RRC Setup 38.331 @@ -3871,6 +3937,11 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i case 1 ... 32: if (!get_mac_len(pduP, pdu_len, &mac_len, &mac_subheader_len)) return; + // discard the received subPDU if RB is suspended + if (is_lcid_suspended(mac, rx_lcid)) { + LOG_W(NR_MAC, "Received PDU for a suspended RB, corresponding to LCID %d. Dropping it.\n", rx_lcid); + break; + } LOG_D(NR_MAC, "%4d.%2d : DLSCH -> LCID %d %d bytes\n", frameP, slot, rx_lcid, mac_len); nr_mac_rlc_data_ind(mac->ue_id, mac->ue_id, false, rx_lcid, (char *)(pduP + mac_subheader_len), mac_len); break; @@ -3878,8 +3949,8 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i LOG_W(MAC, "unknown lcid %02x\n", rx_lcid); break; } - pduP += ( mac_subheader_len + mac_len ); - pdu_len -= ( mac_subheader_len + mac_len ); + pduP += (mac_subheader_len + mac_len); + pdu_len -= (mac_subheader_len + mac_len); if (pdu_len < 0) LOG_E(MAC, "[UE %d][%d.%d] nr_ue_process_mac_pdu, residual mac pdu length %d < 0!\n", mac->ue_id, frameP, slot, pdu_len); } @@ -4185,21 +4256,6 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d handle_rar_reception(mac, rar, frame, slot); if (ra->cfra) nr_ra_succeeded(mac, dl_info->gNB_index, frame, slot); - if (get_softmodem_params()->emulate_l1) { - /* When we are emulating L1 with multiple UEs, the rx_indication will have - multiple RAR PDUs. The code would previously handle each of these PDUs, - but it should only be handling the single RAR that matches the current - UE. */ - LOG_I(NR_MAC, "RAR PDU found for our UE with PDU index %d\n", pdu_id); - dl_info->rx_ind->number_pdus = 1; - if (pdu_id != 0) { - memcpy(&dl_info->rx_ind->rx_indication_body[0], - &dl_info->rx_ind->rx_indication_body[pdu_id], - sizeof(fapi_nr_rx_indication_body_t)); - } - mac->nr_ue_emul_l1.expected_rar = false; - memset(mac->nr_ue_emul_l1.index_has_rar, 0, sizeof(mac->nr_ue_emul_l1.index_has_rar)); - } break; } if (rarh->E == 0) { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index b810bf8de6..3825a49fd2 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -78,6 +78,10 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, int P_MAX, bool *BSRsent); +static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, int slotP); +static void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot); +static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot); + static void clear_ul_config_request(NR_UE_MAC_INST_t *mac) { int slots = mac->frame_structure.numb_slots_frame; @@ -182,6 +186,27 @@ void handle_time_alignment_timer_expired(NR_UE_MAC_INST_t *mac) // TODO not sure what to do here } +void handle_ulsync_loss(NR_UE_MAC_INST_t *mac) +{ + // flush all HARQ buffers for all Serving Cells + for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) { + memset(&mac->dl_harq_info[k], 0, sizeof(*mac->dl_harq_info)); + memset(&mac->ul_harq_info[k], 0, sizeof(*mac->ul_harq_info)); + mac->dl_harq_info[k].last_ndi = -1; // initialize to invalid value + mac->ul_harq_info[k].last_ndi = -1; // initialize to invalid value + } + // clear any configured downlink assignments and uplink grants; + if (mac->dl_config_request) + memset(mac->dl_config_request, 0, sizeof(*mac->dl_config_request)); + if (mac->ul_config_request) + clear_ul_config_request(mac); + + // Need to receive SIB19 again after loosing UL SYNC + mac->state = UE_RECEIVING_SIB; + // gNB needs to send PDCCH ORDER triggering RA after detecting ULSYNC LOSS + LOG_W(NR_MAC, "Wait for PDCCH ORDER, RACH needs to performed to obtain ULSYNC.\n"); +} + void update_mac_dl_timers(NR_UE_MAC_INST_t *mac) { bool ra_window_expired = nr_timer_tick(&mac->ra.response_window_timer); @@ -235,7 +260,7 @@ void update_mac_ul_timers(NR_UE_MAC_INST_t *mac) if (phr_info->is_configured) { bool prohibit_expired = nr_timer_tick(&phr_info->prohibitPHR_Timer); if (prohibit_expired) { - int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + int16_t pathloss = compute_nr_SSB_PL(mac); if (abs(pathloss - phr_info->PathlossLastValue) > phr_info->PathlossChange_db) { phr_info->phr_reporting |= (1 << phr_cause_prohibit_timer); } @@ -373,7 +398,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->nrOfLayers = 1; pusch_config_pdu->Tpmi = 0; pusch_config_pdu->rnti = rnti; - + pusch_config_pdu->dmrs_ports = 1; pusch_dmrs_AdditionalPosition_t add_pos = pusch_dmrs_pos2; int dmrslength = 1; NR_PUSCH_Config_t *pusch_Config = current_UL_BWP->pusch_Config; @@ -410,7 +435,6 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->rb_size = msgA_PUSCH_Resource->nrofPRBs_PerMsgA_PO_r16; pusch_config_pdu->mcs_table = 0; pusch_config_pdu->frequency_hopping = msgA_PUSCH_Resource->msgA_IntraSlotFrequencyHopping_r16 ? *msgA_PUSCH_Resource->msgA_IntraSlotFrequencyHopping_r16 : 0; - pusch_config_pdu->dmrs_ports = 1; // is in SIB1 nrofDMRS_Sequences_r16? pusch_config_pdu->pusch_data.new_data_indicator = 1; // new data pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; pusch_config_pdu->ul_dmrs_symb_pos = get_l_prime(3, 0, pusch_dmrs_pos2, pusch_len1, 10, mac->dmrs_TypeA_Position); @@ -504,7 +528,6 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, // DM-RS configuration according to 6.2.2 UE DM-RS transmission procedure in 38.214 pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2; - pusch_config_pdu->dmrs_ports = 1; // DMRS sequence initialization [TS 38.211, sec 6.4.1.1.1]. // Should match what is sent in DCI 0_1, otherwise set to 0. @@ -776,12 +799,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, int start_symbol = pusch_config_pdu->start_symbol_index; int number_of_symbols = pusch_config_pdu->nr_of_symbols; - int number_dmrs_symbols = 0; - for (int i = start_symbol; i < start_symbol + number_of_symbols; i++) { - if ((pusch_config_pdu->ul_dmrs_symb_pos >> i) & 0x01) - number_dmrs_symbols += 1; - } - + int number_dmrs_symbols = count_bits64_with_mask(pusch_config_pdu->ul_dmrs_symb_pos, start_symbol, number_of_symbols); int nb_dmrs_re_per_rb = ((pusch_config_pdu->dmrs_config_type == pusch_dmrs_type1) ? 6 : 4) * pusch_config_pdu->num_dmrs_cdm_grps_no_data; @@ -1266,10 +1284,11 @@ static void nr_update_rlc_buffers_status(NR_UE_MAC_INST_t *mac, frame_t frameP, { for (int i = 0; i < mac->lc_ordered_list.count; i++) { nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; + if (lc_info->rb_suspended) + continue; int lcid = lc_info->lcid; NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid); mac_rlc_status_resp_t rlc_status = nr_mac_rlc_status_ind(mac->ue_id, frameP, lcid); - if (rlc_status.bytes_in_buffer > 0) { LOG_D(NR_MAC, "[UE %d] LCID %d has %d bytes to transmit at sfn %d.%d\n", @@ -1278,8 +1297,8 @@ static void nr_update_rlc_buffers_status(NR_UE_MAC_INST_t *mac, frame_t frameP, rlc_status.bytes_in_buffer, frameP, slotP); - lc_sched_info->LCID_buffer_remain = rlc_status.bytes_in_buffer; } + lc_sched_info->LCID_buffer_remain = rlc_status.bytes_in_buffer; } } @@ -1310,6 +1329,8 @@ static void nr_update_bsr(NR_UE_MAC_INST_t *mac, uint32_t *LCG_bytes) bool bsr_regular_triggered = mac->scheduling_info.BSR_reporting_active & NR_BSR_TRIGGER_REGULAR; for (int i = 0; i < mac->lc_ordered_list.count; i++) { nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; + if (lc_info->rb_suspended) + continue; int lcid = lc_info->lcid; NR_LC_SCHEDULING_INFO *lc_sched_info = get_scheduling_info_from_lcid(mac, lcid); int lcgid = lc_sched_info->LCGID; @@ -1692,71 +1713,71 @@ static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac, return mux_done; } -void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, int slotP) +static void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frame, int slot) { PUCCH_sched_t pucch[3] = {0}; // TODO the size might change in the future in case of multiple SR or multiple CSI in a slot - - mac->nr_ue_emul_l1.num_srs = 0; - mac->nr_ue_emul_l1.num_harqs = 0; - mac->nr_ue_emul_l1.num_csi_reports = 0; int num_res = 0; - // SR - if (mac->state == UE_CONNECTED && trigger_periodic_scheduling_request(mac, &pucch[0], frameP, slotP)) { - num_res++; - // TODO check if the PUCCH resource for the SR transmission occasion overlap with a UL-SCH resource + if (mac->ra.ra_pucch) { + // scheduling PUCCH prepared in advance for MSG4 + RA_PUCCH_SCHED_t *ra_pucch = mac->ra.ra_pucch; + if (ra_pucch->sched_frame == frame && ra_pucch->sched_slot == slot) { + pucch[0] = ra_pucch->pucch_sched; + num_res++; + free_and_zero(mac->ra.ra_pucch); + } + } else { + // SR + if (mac->state == UE_CONNECTED && trigger_periodic_scheduling_request(mac, &pucch[0], frame, slot)) { + num_res++; + // TODO check if the PUCCH resource for the SR transmission occasion overlap with a UL-SCH resource + } + + // CSI + int csi_res = 0; + if (mac->state == UE_CONNECTED) + csi_res = nr_get_csi_measurements(mac, frame, slot, &pucch[num_res]); + if (csi_res > 0) { + num_res += csi_res; + } + + // ACKNACK + bool any_harq = get_downlink_ack(mac, frame, slot, &pucch[num_res]); + if (any_harq) + num_res++; + + if (num_res == 0) + return; + // do no transmit pucch if only SR scheduled and it is negative + if (num_res == 1 && pucch[0].n_sr > 0 && pucch[0].sr_payload == 0) + return; + + if (num_res > 1) + multiplex_pucch_resource(mac, pucch, num_res); } - // CSI - int csi_res = 0; - if (mac->state == UE_CONNECTED) - csi_res = nr_get_csi_measurements(mac, frameP, slotP, &pucch[num_res]); - if (csi_res > 0) { - num_res += csi_res; - } - - // ACKNACK - bool any_harq = get_downlink_ack(mac, frameP, slotP, &pucch[num_res]); - if (any_harq) - num_res++; - - if (num_res == 0) - return; - // do no transmit pucch if only SR scheduled and it is negative - if (num_res == 1 && pucch[0].n_sr > 0 && pucch[0].sr_payload == 0) - return; - - if (num_res > 1) - multiplex_pucch_resource(mac, pucch, num_res); - for (int j = 0; j < num_res; j++) { if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].n_csi != 0) { LOG_D(NR_MAC, "%d.%d configure pucch, O_ACK %d, O_SR %d, O_CSI %d\n", - frameP, - slotP, + frame, + slot, pucch[j].n_harq, pucch[j].n_sr, pucch[j].n_csi); - mac->nr_ue_emul_l1.num_srs = pucch[j].n_sr; - mac->nr_ue_emul_l1.num_harqs = pucch[j].n_harq; - mac->nr_ue_emul_l1.num_csi_reports = pucch[j].n_csi; // checking if we need to schedule pucch[j] on PUSCH - if (schedule_uci_on_pusch(mac, frameP, slotP, &pucch[j], mac->current_UL_BWP)) + if (schedule_uci_on_pusch(mac, frame, slot, &pucch[j], mac->current_UL_BWP)) continue; - fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PUCCH); + fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame, slot, FAPI_NR_UL_CONFIG_TYPE_PUCCH); if (!pdu) { LOG_E(NR_MAC, "Error in pucch allocation\n"); return; } - DevAssert(mac->current_DL_BWP != NULL); - int mu = mac->current_DL_BWP->scs; - mac->nr_ue_emul_l1.active_uci_sfn_slot = NFAPI_SFNSLOT2DEC(mu, frameP, slotP); int ret = nr_ue_configure_pucch(mac, - slotP, - frameP, + slot, + frame, mac->crnti, // FIXME not sure this is valid for all pucch instances &pucch[j], &pdu->pucch_config_pdu); @@ -1767,7 +1788,7 @@ void nr_ue_pucch_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, int slotP) } } -void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot) +static void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot) { if (!mac->sc_info.csi_MeasConfig) return; @@ -1902,7 +1923,7 @@ uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI } void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu, - NR_CSI_RS_ResourceMapping_t *resourceMapping, + const NR_CSI_RS_ResourceMapping_t *resourceMapping, uint32_t bwp_size, uint32_t bwp_start) { @@ -2008,7 +2029,7 @@ void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_c } } -void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot) +static void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot) { if (!mac->sc_info.csi_MeasConfig) return; @@ -2354,7 +2375,7 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, int short_bsr_sz = sizeof(NR_BSR_SHORT) + sizeof(NR_MAC_SUBHEADER_FIXED); int num_lcg_id_with_data = 0; for (int lcg_id = 0; lcg_id < NR_MAX_NUM_LCGID; lcg_id++) - num_lcg_id_with_data += LCG_bytes > 0; + num_lcg_id_with_data += LCG_bytes[lcg_id] > 0; int long_bsr_sz = num_lcg_id_with_data + sizeof(NR_BSR_LONG) + sizeof(NR_MAC_SUBHEADER_SHORT); if (num_lcg_id_with_data < 2 && padding_len >= short_bsr_sz) { mac_ce_p->bsr.type_bsr = b_short; @@ -2444,13 +2465,13 @@ static void nr_ue_get_sdu_mac_ce_post(NR_UE_MAC_INST_t *mac, mac_ce_p->cur_ptr += size; } -uint32_t get_count_lcids_same_priority(uint8_t start, uint8_t total_active_lcids, nr_lcordered_info_t *lcid_ordered_array) +static uint32_t get_count_lcids_same_priority(uint8_t start, uint8_t total_active_lcids, nr_lcordered_info_t *lcid_ordered_array[]) { // count number of logical channels with same priority as curr_lcid uint8_t same_priority_count = 0; - uint8_t curr_lcid = lcid_ordered_array[start].lcid; + uint8_t curr_lcid = lcid_ordered_array[start]->lcid; for (uint8_t index = start; index < total_active_lcids; index++) { - if (lcid_ordered_array[start].priority == lcid_ordered_array[index].priority) { + if (lcid_ordered_array[start]->priority == lcid_ordered_array[index]->priority) { same_priority_count++; } } @@ -2492,17 +2513,22 @@ static long get_num_bytes_to_reqlc(NR_UE_MAC_INST_t *mac, } } AssertFatal(num_remaining_bytes >= 0 && num_bytes_requested <= buflen_remain, - "the total number of bytes allocated until target length is greater than expected\n"); + "the total number of bytes allocated until target length is greater than expected: num_bytes_requested %ld, " + "buflen_remain %d\n", + num_bytes_requested, + buflen_remain); LOG_D(NR_MAC, "number of bytes requested for lcid %d is %li\n", lc_num, num_bytes_requested); return num_bytes_requested; } -bool get_dataavailability_buffers(uint8_t total_active_lcids, nr_lcordered_info_t *lcid_ordered_array, bool *data_status_lcbuffers) +static bool get_dataavailability_buffers(uint8_t total_active_lcids, + nr_lcordered_info_t *lcid_ordered_array[], + bool *data_status_lcbuffers) { // check whether there is any data in the rlc buffer corresponding to active lcs for (uint8_t id = 0; id < total_active_lcids; id++) { - int lcid = lcid_ordered_array[id].lcid; + int lcid = lcid_ordered_array[id]->lcid; if (data_status_lcbuffers[lcid_buffer_index(lcid)]) { return true; } @@ -2510,17 +2536,20 @@ bool get_dataavailability_buffers(uint8_t total_active_lcids, nr_lcordered_info_ return false; } -static uint select_logical_channels(NR_UE_MAC_INST_t *mac, nr_lcordered_info_t *active_lcids) +static uint select_logical_channels(NR_UE_MAC_INST_t *mac, nr_lcordered_info_t *active_lcids[]) { // (TODO: selection of logical channels for logical channel prioritization procedure as per 5.4.3.1.2 Selection of logical // channels, TS38.321) int nb = 0; // selection of logical channels with Bj > 0 for (int i = 0; i < mac->lc_ordered_list.count; i++) { - int lcid = mac->lc_ordered_list.array[i]->lcid; + nr_lcordered_info_t *lc_info = mac->lc_ordered_list.array[i]; + if (lc_info->rb_suspended) + continue; + int lcid = lc_info->lcid; NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); if (sched_info->Bj > 0) { - active_lcids[nb++] = *mac->lc_ordered_list.array[i]; + active_lcids[nb++] = lc_info; LOG_D(NR_MAC, "The available lcid is %d with total active channels count = %d\n", lcid, nb); } } @@ -2553,6 +2582,8 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac, lcid_remain_buffer, lcid); + if (is_lcid_suspended(mac, lcid)) + return false; if (mac_ce_p->end_for_tailer - mac_ce_p->cur_ptr < sizeof(NR_MAC_SUBHEADER_LONG)) // We can't add one byte after the header return false; @@ -2707,7 +2738,7 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, LOG_E(NR_MAC, "Failed to init lcids_bj_pos: mac->lc_ordered_list.count = 0\n"); return 0; } - nr_lcordered_info_t lcids_bj_pos[mac->lc_ordered_list.count]; + nr_lcordered_info_t *lcids_bj_pos[mac->lc_ordered_list.count]; int avail_lcids_count = select_logical_channels(mac, lcids_bj_pos); // multiplex in the order of highest priority @@ -2728,7 +2759,7 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, still space availble in the MAC PDU, then from the next run all the remaining data from the higher priority logical channel is placed in the MAC PDU before going on to next high priority logical channel */ - int lcid = lcids_bj_pos[id].lcid; + int lcid = lcids_bj_pos[id]->lcid; int idx = lcid_buffer_index(lcid); // skip the logical channel if no data in the buffer initially or the data in the buffer was zero because it was written in to // MAC PDU @@ -2751,11 +2782,9 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, remain); if (num_lcids_same_priority == count_same_priority_lcids) { - buflen_ep = (remain - (count_same_priority_lcids * sizeof(NR_MAC_SUBHEADER_LONG))) / count_same_priority_lcids; - /* after serving equal priority LCIDs in the first round, buflen_remain could be > 0 and < (count_same_priority_lcids * sh_size) - if above division yeilds a remainder. hence the following sets buflen_ep to 0 if there is not enough buffer left for subsequent rounds - */ - buflen_ep = buflen_ep < 0 ? 0 : buflen_ep; + buflen_ep = remain < count_same_priority_lcids * sizeof(NR_MAC_SUBHEADER_LONG) + ? 0 + : (remain - (count_same_priority_lcids * sizeof(NR_MAC_SUBHEADER_LONG))) / count_same_priority_lcids; } while (mac_ce_info.end_for_tailer - mac_ce_info.cur_ptr > 0) { @@ -2819,11 +2848,14 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, static void schedule_ntn_config_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MAC_INST_t *mac) { fapi_nr_dl_ntn_config_command_pdu *ntn_config_command_pdu = &dl_config->dl_config_list[dl_config->number_pdus].ntn_config_command_pdu; + + ntn_config_command_pdu->epoch_sfn = mac->ntn_ta.epoch_sfn; + ntn_config_command_pdu->epoch_subframe = mac->ntn_ta.epoch_subframe; ntn_config_command_pdu->cell_specific_k_offset = mac->ntn_ta.cell_specific_k_offset; - ntn_config_command_pdu->ntn_ta_commondrift = mac->ntn_ta.ntn_ta_commondrift; - ntn_config_command_pdu->N_common_ta_adj = mac->ntn_ta.N_common_ta_adj; - ntn_config_command_pdu->N_UE_TA_adj = mac->ntn_ta.N_UE_TA_adj; - ntn_config_command_pdu->ntn_total_time_advance_ms = mac->ntn_ta.N_common_ta_adj + mac->ntn_ta.N_UE_TA_adj; + ntn_config_command_pdu->ntn_total_time_advance_ms = get_total_TA_ms(&mac->ntn_ta); + ntn_config_command_pdu->ntn_total_time_advance_drift = get_total_TA_drift(&mac->ntn_ta); + ntn_config_command_pdu->ntn_total_time_advance_drift_variant = get_total_TA_drift_variant(&mac->ntn_ta); + dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_NTN_CONFIG_PARAMS; dl_config->number_pdus += 1; } @@ -2873,7 +2905,7 @@ static void nr_ue_fill_phr(NR_UE_MAC_INST_t *mac, headroom, tx_power); - phr_info->PathlossLastValue = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm); + phr_info->PathlossLastValue = compute_nr_SSB_PL(mac); // Restart both timers according to 38.321 nr_timer_start(&phr_info->periodicPHR_Timer); nr_timer_start(&phr_info->prohibitPHR_Timer); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index f87b4024b9..a0637ac107 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -61,13 +61,7 @@ c16_t convert_precoder_weight(double complex c_in) { - double cr = creal(c_in) * 32768 + 0.5; - if (cr < 0) - cr -= 1; - double ci = cimag(c_in) * 32768 + 0.5; - if (ci < 0) - ci -= 1; - return (c16_t) {.r = (short)cr, .i = (short)ci}; + return (c16_t) {.r = round(SHRT_MAX*creal(c_in)), .i = round(SHRT_MAX*cimag(c_in))}; } void get_K1_K2(int N1, int N2, int *K1, int *K2, int layers) @@ -142,8 +136,7 @@ int precoding_weigths_generation(nfapi_nr_pm_list_t *mat, nfapi_nr_pm_weights_t *weights = &mat->pmi_pdu[pmiq].weights[j_col][i_rows]; res_code = sqrt(1 / (double)L) * v_lm[llc][mmc][i_rows]; c16_t precoder_weight = convert_precoder_weight(res_code); - weights->precoder_weight_Re = precoder_weight.r; - weights->precoder_weight_Im = precoder_weight.i; + *weights = precoder_weight; LOG_D(PHY, "%d Layer Precoding Matrix[pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n", L, @@ -152,15 +145,14 @@ int precoding_weigths_generation(nfapi_nr_pm_list_t *mat, j_col, creal(res_code), cimag(res_code), - weights->precoder_weight_Re, - weights->precoder_weight_Im); + weights->r, + weights->i); } for (int i_rows = N1 * N2; i_rows < 2 * N1 * N2; i_rows++) { nfapi_nr_pm_weights_t *weights = &mat->pmi_pdu[pmiq].weights[j_col][i_rows]; res_code = sqrt(1 / (double)L) * (phase_sign)*theta_n[nn] * v_lm[llc][mmc][i_rows - N1 * N2]; c16_t precoder_weight = convert_precoder_weight(res_code); - weights->precoder_weight_Re = precoder_weight.r; - weights->precoder_weight_Im = precoder_weight.i; + *weights = precoder_weight; LOG_D(PHY, "%d Layer Precoding Matrix[pmi %d][antPort %d][layerIdx %d]= %f+j %f -> Fixed Point %d+j %d \n", L, @@ -169,8 +161,8 @@ int precoding_weigths_generation(nfapi_nr_pm_list_t *mat, j_col, creal(res_code), cimag(res_code), - weights->precoder_weight_Re, - weights->precoder_weight_Im); + weights->r, + weights->i); } } pmiq++; @@ -399,9 +391,7 @@ int get_ul_slot_offset(const frame_structure_t *fs, int idx, bool count_mixed) return ul_slot_idxs[ul_slot_idx_in_period] + period_idx * fs->numb_slots_period; } -static void config_common(gNB_MAC_INST *nrmac, - const nr_mac_config_t *config, - NR_ServingCellConfigCommon_t *scc) +static void config_common(gNB_MAC_INST *nrmac, const nr_mac_config_t *config, NR_ServingCellConfigCommon_t *scc) { nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0]; nrmac->common_channels[0].ServingCellConfigCommon = scc; @@ -719,7 +709,7 @@ static void config_common(gNB_MAC_INST *nrmac, cfg->pmi_list = init_DL_MIMO_codebook(nrmac, pdsch_AntennaPorts); int nb_beams = config->nb_bfw[1]; // number of beams - if (nrmac->beam_info.beam_allocation) { + if (nrmac->beam_info.beam_mode == PRECONFIGURED_BEAM_IDX) { LOG_I(NR_MAC, "Configuring analog beamforming in config_request message\n"); cfg->analog_beamforming_ve.num_beams_period_vendor_ext.tl.tag = NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.num_beams_period_vendor_ext.value = nrmac->beam_info.beams_per_period; @@ -742,11 +732,44 @@ static void config_common(gNB_MAC_INST *nrmac, cfg->num_tlv++; } } + + if (IS_SA_MODE(get_softmodem_params())) { + int bw = frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; + uint64_t bw_khz = (12 * bw) * (15 << mu); + uint64_t carr_dl = (cfg->carrier_config.dl_frequency.value + bw_khz / 2) * 1000; + uint64_t carr_ul = (cfg->carrier_config.uplink_frequency.value + bw_khz / 2) * 1000; + int prb_offset = (frequency_range == FR1) ? + cfg->ssb_table.ssb_offset_point_a.value >> scs : + cfg->ssb_table.ssb_offset_point_a.value >> (scs - 2); + int sc_offset = (frequency_range == FR1) ? + cfg->ssb_table.ssb_subcarrier_offset.value >> scs : + cfg->ssb_table.ssb_subcarrier_offset.value; + if (cfg->carrier_config.dl_frequency.value != cfg->carrier_config.uplink_frequency.value) { + LOG_I(NR_MAC, + "Command line parameters for OAI UE: -C %lu --CO %ld -r %d --numerology %d --band %ld --ssb %d %s\n", + carr_dl, + carr_ul - carr_dl, + bw, + mu, + band, + 12 * prb_offset + sc_offset, + get_softmodem_params()->threequarter_fs ? "-E" : ""); + } else { + LOG_I(NR_MAC, + "Command line parameters for OAI UE: -C %lu -r %d --numerology %d --band %ld --ssb %d %s\n", + carr_dl, + bw, + mu, + band, + 12 * prb_offset + sc_offset, + get_softmodem_params()->threequarter_fs ? "-E" : ""); + } + } } static void initialize_beam_information(NR_beam_info_t *beam_info, int mu, int slots_per_frame) { - if (!beam_info->beam_allocation) + if (beam_info->beam_mode == NO_BEAM_MODE) return; int size = mu == 0 ? slots_per_frame << 1 : slots_per_frame; @@ -807,6 +830,28 @@ static void config_sched_ctrlCommon(gNB_MAC_INST *nr_mac) nr_mac->cset0_bwp_size = type0_PDCCH_CSS_config.num_rbs; } +/** + * \brief Initializes the UL TDA information at the scheduler, as used for + * every UE in UL. This just copies the information from the SCC into a smaller + * list. Note that this list should not be modified, as get_num_ul_tda() and + * nr_rrc_config_ul_tda() are designed to work in sync (get_num_ul_tda() + * assumes an ordering, output by nr_rrc_config_ul_tda()). + */ +static void init_ul_tda_info(const NR_PUSCH_TimeDomainResourceAllocationList_t *l, seq_arr_t *sa_tda) +{ + DevAssert(l->list.count > 0 && l->list.count <= 16); + DevAssert(seq_arr_size(sa_tda) == 0); + + for (int i = 0; i < l->list.count; ++i) { + NR_PUSCH_TimeDomainResourceAllocation_t *t = l->list.array[i]; + DevAssert(t->k2); + NR_tda_info_t tda = { .mapping_type = typeB, .k2 = *t->k2, .valid_tda = true }; + SLIV2SL(t->startSymbolAndLength, &tda.startSymbolIndex, &tda.nrOfSymbols); + LOG_I(NR_MAC, "TDA index %d: start %d length %d k2 %ld\n", i, tda.startSymbolIndex, tda.nrOfSymbols, tda.k2); + seq_arr_push_back(sa_tda, &tda, sizeof(tda)); + } +} + void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config) { DevAssert(nrmac != NULL); @@ -823,7 +868,7 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c nrmac->vrb_map_UL_size = size; int num_beams = 1; - if(nrmac->beam_info.beam_allocation) + if(nrmac->beam_info.beam_mode != NO_BEAM_MODE) num_beams = nrmac->beam_info.beams_per_period; for (int i = 0; i < num_beams; i++) { nrmac->common_channels[0].vrb_map_UL[i] = calloc(size * MAX_BWP_SIZE, sizeof(uint16_t)); @@ -840,7 +885,7 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c LOG_D(NR_MAC, "Configuring common parameters from NR ServingCellConfig\n"); config_common(nrmac, config, scc); - fapi_beam_index_allocation(scc, nrmac); + fapi_beam_index_allocation(scc, config, nrmac); if (NFAPI_MODE == NFAPI_MONOLITHIC) { // nothing to be sent in the other cases @@ -853,6 +898,9 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c if (IS_SA_MODE(get_softmodem_params())) config_sched_ctrlCommon(nrmac); + + seq_arr_init(&nrmac->ul_tda, sizeof(NR_tda_info_t)); + init_ul_tda_info(scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList, &nrmac->ul_tda); } bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_sib_msg_t cu_sib[num_cu_sib]) @@ -927,6 +975,96 @@ bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_ return true; } +bool nr_update_sib19(const gnb_sat_position_update_t *sat_position) +{ + gNB_MAC_INST *nrmac = RC.nrmac[0]; + NR_COMMON_channels_t *cc = &nrmac->common_channels[0]; + NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; + + if (!scc || !scc->ext2 || !scc->ext2->ntn_Config_r17) + return false; + + const vector_t *pos = &sat_position->position; + const vector_t *vel = &sat_position->velocity; + + LOG_D(NR_MAC, "SFN = %d, SubFrame = %d\n", sat_position->sfn, sat_position->subframe); + LOG_D(NR_MAC, "TA_Common: value %d, %f msec\n", sat_position->delay, sat_position->delay * 4.072e-6); + LOG_D(NR_MAC, "TA_CommonDrift: value %d, = %f µsec/sec\n", sat_position->drift, sat_position->drift * 0.2e-3); + LOG_D(NR_MAC, "TA_CommonDriftVariant: value %d, %f µsec/sec^2\n", sat_position->accel, sat_position->accel * 0.2e-4); + LOG_D(NR_MAC, "SAT Position: values %d/%d/%d, %.3f/%3f/%3f metres in X/Y/Z\n", pos->X, pos->Y, pos->Z, pos->X * 1.3, pos->Y * 1.3, pos->Z * 1.3); + LOG_D(NR_MAC, "SAT Velocity: values %d/%d/%d, %.3f/%3f/%3f m/s in X/Y/Z\n", vel->X, vel->Y, vel->Z, vel->X * 0.06, vel->Y * 0.06, vel->Z * 0.06); + + NR_SCHED_LOCK(&nrmac->sched_lock); + + if (!scc->ext2->ntn_Config_r17->epochTime_r17) + scc->ext2->ntn_Config_r17->epochTime_r17 = calloc (1, sizeof(*scc->ext2->ntn_Config_r17->epochTime_r17)); + + NR_EpochTime_r17_t *epoch_time_r17 = scc->ext2->ntn_Config_r17->epochTime_r17; + epoch_time_r17->sfn_r17 = sat_position->sfn; + epoch_time_r17->subFrameNR_r17 = sat_position->subframe; + + if (!scc->ext2->ntn_Config_r17->ta_Info_r17) + scc->ext2->ntn_Config_r17->ta_Info_r17 = calloc(1, sizeof(*scc->ext2->ntn_Config_r17->ta_Info_r17)); + + NR_TA_Info_r17_t *sib19_ta_info = scc->ext2->ntn_Config_r17->ta_Info_r17; + + // SIB19 provides Round trip delay on feeder link (between gNB and SAT). + sib19_ta_info->ta_Common_r17 = sat_position->delay; + + if (sat_position->drift) { + if (!sib19_ta_info->ta_CommonDrift_r17) + sib19_ta_info->ta_CommonDrift_r17 = calloc(1, sizeof(*sib19_ta_info->ta_CommonDrift_r17)); + *sib19_ta_info->ta_CommonDrift_r17 = sat_position->drift; + } else + free_and_zero(sib19_ta_info->ta_CommonDrift_r17); + + if (sat_position->accel) { + if (!sib19_ta_info->ta_CommonDriftVariant_r17) + sib19_ta_info->ta_CommonDriftVariant_r17 = calloc(1, sizeof(*sib19_ta_info->ta_CommonDriftVariant_r17)); + *sib19_ta_info->ta_CommonDriftVariant_r17 = sat_position->accel; + } else + free_and_zero(sib19_ta_info->ta_CommonDriftVariant_r17); + + // Currently PositionVelocity is supported and not yet the OrbitalParams + if (!scc->ext2->ntn_Config_r17->ephemerisInfo_r17) { + scc->ext2->ntn_Config_r17->ephemerisInfo_r17 = calloc(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17)); + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present = NR_EphemerisInfo_r17_PR_NOTHING; + } + if (scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present == NR_EphemerisInfo_r17_PR_orbital_r17) { + ASN_STRUCT_FREE(asn_DEF_NR_Orbital_r17, scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.orbital_r17); + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.orbital_r17 = NULL; + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present = NR_EphemerisInfo_r17_PR_NOTHING; + } + if (!scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17) + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17 = + calloc(1, sizeof(*scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17)); + + scc->ext2->ntn_Config_r17->ephemerisInfo_r17->present = NR_EphemerisInfo_r17_PR_positionVelocity_r17; + NR_PositionVelocity_r17_t *sib19_PosVel = scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17; + + sib19_PosVel->positionX_r17 = pos->X; + sib19_PosVel->positionY_r17 = pos->Y; + sib19_PosVel->positionZ_r17 = pos->Z; + sib19_PosVel->velocityVX_r17 = vel->X; + sib19_PosVel->velocityVY_r17 = vel->Y; + sib19_PosVel->velocityVZ_r17 = vel->Z; + + NR_SystemInformation_IEs_t *sysInfov17 = calloc(1, sizeof(*sysInfov17)); // for othersibs + struct NR_SystemInformation_IEs__sib_TypeAndInfo__Member *type_du = calloc(1, sizeof(*type_du)); + type_du->present = NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib19_v1700; + NR_SIB19_r17_t *sib19 = get_SIB19_NR(cc->ServingCellConfigCommon); + type_du->choice.sib19_v1700 = sib19; + add_sib_to_systeminformation(sysInfov17, type_du); + + cc->other_sib_bcch_length[1] = encode_sysinfo_ie(sysInfov17, cc->other_sib_bcch_pdu[1], sizeof(cc->other_sib_bcch_pdu[1])); + AssertFatal(cc->other_sib_bcch_length[1] > 0, "could not encode SIB19\n"); + ASN_STRUCT_FREE(asn_DEF_NR_SystemInformation_IEs, sysInfov17); + + NR_SCHED_UNLOCK(&nrmac->sched_lock); + + return true; +} + void prepare_du_configuration_update(gNB_MAC_INST *mac, f1ap_served_cell_info_t *info, NR_BCCH_BCH_Message_t *mib, @@ -971,7 +1109,7 @@ bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t NR_SCHED_LOCK(&nrmac->sched_lock); NR_UE_info_t *UE = get_new_nr_ue_inst(&nrmac->UE_info.uid_allocator, rnti, CellGroup); - DevAssert(UE != NULL); // test-mode: we assume we can always create a UE + DevAssert(UE->uid < MAX_MOBILES_PER_GNB); // test-mode: we assume we can always create a UE free_and_zero(UE->ra); // test-mode (sims, phy-test): UE will not do RA bool res = add_connected_nr_ue(nrmac, UE); if (!res) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index dfe4cfeea2..46ad8069da 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -108,7 +108,7 @@ static void clear_beam_information(NR_beam_info_t *beam_info, int frame, int slo { // for now we use the same logic of UL_tti_req_ahead // reset after 1 frame with the exception of 15kHz - if(!beam_info->beam_allocation) + if (beam_info->beam_mode == NO_BEAM_MODE) return; // initialization done only once AssertFatal(beam_info->beam_allocation_size >= 0, "Beam information not initialized\n"); @@ -174,12 +174,12 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo clear_beam_information(&gNB->beam_info, frame, slot, slots_frame); gNB->frame = frame; - start_meas(&gNB->eNB_scheduler); + start_meas(&gNB->gNB_scheduler); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN); for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { int num_beams = 1; - if(gNB->beam_info.beam_allocation) + if(gNB->beam_info.beam_mode != NO_BEAM_MODE) num_beams = gNB->beam_info.beams_per_period; // clear vrb_maps for (int i = 0; i < num_beams; i++) @@ -195,12 +195,13 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo } bool wait_prach_completed = gNB->num_scheduled_prach_rx >= NUM_PRACH_RX_FOR_NOISE_ESTIMATE; - if (wait_prach_completed && (slot == 0) && (frame & 127) == 0) { + if ((wait_prach_completed || get_softmodem_params()->phy_test) && (slot == 0) && (frame & 127) == 0) { char stats_output[32656] = {0}; dump_mac_stats(gNB, stats_output, sizeof(stats_output), true); LOG_I(NR_MAC, "Frame.Slot %d.%d\n%s\n", frame, slot, stats_output); } + nr_measgap_scheduling(gNB, frame, slot); nr_mac_update_timers(module_idP, frame, slot); if (wait_prach_completed || get_softmodem_params()->phy_test) { @@ -244,7 +245,9 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo } // This schedules the DCI for Uplink and subsequently PUSCH + start_meas(&gNB->schedule_ulsch); nr_schedule_ulsch(module_idP, frame, slot, &sched_info->UL_dci_req); + stop_meas(&gNB->schedule_ulsch); // This schedules the DCI for Downlink and PDSCH start_meas(&gNB->schedule_dlsch); @@ -262,7 +265,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo const int current_index = ul_buffer_index(frame, slot, slots_frame, gNB->UL_tti_req_ahead_size); copy_ul_tti_req(&sched_info->UL_tti_req, &gNB->UL_tti_req_ahead[0][current_index]); - stop_meas(&gNB->eNB_scheduler); + stop_meas(&gNB->gNB_scheduler); NR_SCHED_UNLOCK(&gNB->sched_lock); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_OUT); } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index e398da1eaf..5e9cd47a79 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -46,16 +46,6 @@ #include -// forward declaration of functions used in this file -static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, - NR_ServingCellConfigCommon_t *scc, - NR_UE_info_t *UE, - int startSymbolAndLength, - int scs, - int bwp_size, - int bwp_start, - int mappingtype, - int fh); static void nr_fill_rar(uint8_t Mod_idP, NR_UE_info_t *UE, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu); static const float ssb_per_rach_occasion[8] = {0.125, 0.25, 0.5, 1, 2, 4, 8}; @@ -303,9 +293,7 @@ static void schedule_nr_MsgA_pusch(NR_UplinkConfigCommon_t *uplinkConfigCommon, pusch_pdu->mcs_index = msgA_PUSCH_Resource->msgA_MCS_r16; pusch_pdu->qam_mod_order = nr_get_Qm_dl(pusch_pdu->mcs_index, pusch_pdu->mcs_table); - int num_dmrs_symb = 0; - for (int i = 10; i < 10 + 3; i++) - num_dmrs_symb += (pusch_pdu->ul_dmrs_symb_pos >> i) & 1; + int num_dmrs_symb = count_bits64_with_mask(pusch_pdu->ul_dmrs_symb_pos, 10, 3); AssertFatal(pusch_pdu->mcs_index <= 28, "Exceeding MCS limit for MsgA PUSCH\n"); int R = nr_get_code_rate_ul(pusch_pdu->mcs_index, pusch_pdu->mcs_table); pusch_pdu->target_code_rate = R; @@ -380,6 +368,8 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4 uint16_t RA_sfn_index = -1; frequency_range_t freq_range = get_freq_range_from_arfcn(scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); + const int mu_pusch = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; + const int16_t n_ra_rb = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch); if (get_nr_prach_sched_from_info(cc->prach_info, config_index, frameP, slotP, mu, freq_range, &RA_sfn_index, cc->frame_type)) { uint16_t format0 = cc->prach_info.format & 0xff; // first column of format from table uint16_t format1 = (cc->prach_info.format >> 8) & 0xff; // second column of format from table @@ -517,8 +507,8 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) } } prach_pdu->num_prach_ocas = num_td_occ; - prach_pdu->beamforming.num_prgs = 0; - prach_pdu->beamforming.prg_size = 0; + prach_pdu->beamforming.num_prgs = 1; + prach_pdu->beamforming.prg_size = n_ra_rb; prach_pdu->beamforming.dig_bf_interface = num_td_occ; prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[num_td_occ - 1].beam_idx = beam_index; @@ -539,8 +529,6 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) } // block resources in vrb_map_UL - const int mu_pusch = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; - const int16_t n_ra_rb = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch); // mark PRBs as occupied for current and future slots if prach extends beyond current slot int total_prach_slots; uint32_t N_dur = cc->prach_info.N_dur; @@ -727,11 +715,6 @@ void nr_initiate_ra_proc(module_id_t module_idP, } UE = get_new_nr_ue_inst(&nr_mac->UE_info.uid_allocator, rnti, NULL); - if (!UE) { - LOG_E(NR_MAC, "FAILURE: %4d.%2d cannot create UE context, ignoring RA because RRC Reject not implemented yet\n", frame, slot); - NR_SCHED_UNLOCK(&nr_mac->sched_lock); - return; - } if (!add_new_UE_RA(nr_mac, UE)) { LOG_E(NR_MAC, "FAILURE: %4d.%2d initiating RA procedure for preamble index %d: no free RA process\n", frame, slot, preamble_index); delete_nr_ue_data(UE, NULL, &nr_mac->UE_info.uid_allocator); @@ -807,15 +790,22 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info; + NR_SearchSpace_t *ss = UE->UE_sched_ctrl.search_space; + NR_ControlResourceSet_t *coreset = UE->UE_sched_ctrl.coreset; + AssertFatal(coreset, "Coreset cannot be null for RA-Msg3 retransmission\n"); + const int coresetid = coreset->controlResourceSetId; + NR_tda_info_t tda_info = get_ul_tda_info(ul_bwp, + coresetid, + NR_SearchSpace__searchSpaceType_PR_common, + TYPE_TC_RNTI_, + ra->Msg3_tda_id); - NR_PUSCH_TimeDomainResourceAllocationList_t *pusch_TimeDomainAllocationList = ul_bwp->tdaList_Common; - int mu = ul_bwp->scs; int slots_frame = nr_mac->frame_structure.numb_slots_frame; - uint16_t K2 = *pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->k2 + get_NTN_Koffset(scc); + uint16_t K2 = tda_info.k2 + get_NTN_Koffset(scc); const int sched_frame = (frame + (slot + K2) / slots_frame) % MAX_FRAME_NUMBER; const int sched_slot = (slot + K2) % slots_frame; - if (is_ul_slot(sched_slot, &nr_mac->frame_structure)) { + if (is_dl_slot(slot, &nr_mac->frame_structure) && is_ul_slot(sched_slot, &nr_mac->frame_structure)) { NR_beam_alloc_t beam_ul = beam_allocation_procedure(&nr_mac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_frame); if (beam_ul.idx < 0) return; @@ -824,30 +814,54 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_frame, beam_ul.new_beam); return; } - int fh = 0; - int startSymbolAndLength = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->startSymbolAndLength; - int StartSymbolIndex, NrOfSymbols; - SLIV2SL(startSymbolAndLength, &StartSymbolIndex, &NrOfSymbols); - int mappingtype = pusch_TimeDomainAllocationList->list.array[ra->Msg3_tda_id]->mappingType; - int buffer_index = ul_buffer_index(sched_frame, sched_slot, slots_frame, nr_mac->vrb_map_UL_size); uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[beam_ul.idx][buffer_index * MAX_BWP_SIZE]; - const int BWPSize = sc_info->initial_ul_BWPSize; - const int BWPStart = sc_info->initial_ul_BWPStart; + NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc, ul_bwp, &tda_info, 1); + int num_dmrs_symb = count_bits64_with_mask(dmrs_info.ul_dmrs_symb_pos, tda_info.startSymbolIndex, tda_info.nrOfSymbols); + int TBS = 0, mcsindex = 0, R = 0, Qm = 0; + while(TBS < 7) { // TBS for msg3 is 7 bytes (except for RRCResumeRequest1 currently not implemented) + mcsindex++; + AssertFatal(mcsindex <= 28, "Exceeding MCS limit for Msg3\n"); + R = nr_get_code_rate_ul(mcsindex, ul_bwp->mcs_table); + Qm = nr_get_Qm_ul(mcsindex, ul_bwp->mcs_table); + TBS = nr_compute_tbs(Qm, + R, + ra->msg3_nb_rb, + tda_info.nrOfSymbols, + num_dmrs_symb * 12, // nb dmrs set for no data in dmrs symbol + 0, //nb_rb_oh + 0, // to verify tb scaling + 1) >> 3; + } + + NR_sched_pusch_t sched_pusch = { + .bwp_info = get_pusch_bwp_start_size(UE), + .tb_size = TBS, + .rbSize = ra->msg3_nb_rb, + .R = R, + .Qm = Qm, + .mcs = mcsindex, + .nrOfLayers = 1, + .tda_info = tda_info, + .dmrs_info = dmrs_info, + }; int rbStart = 0; - for (int i = 0; (i < ra->msg3_nb_rb) && (rbStart <= (BWPSize - ra->msg3_nb_rb)); i++) { - if (vrb_map_UL[rbStart + BWPStart + i]&SL_to_bitmap(StartSymbolIndex, NrOfSymbols)) { + for (int i = 0; (i < ra->msg3_nb_rb) && (rbStart <= (sched_pusch.bwp_info.bwpSize - ra->msg3_nb_rb)); i++) { + if (vrb_map_UL[rbStart + sched_pusch.bwp_info.bwpStart + i] & SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)) { rbStart += i; i = 0; } } - if (rbStart > (BWPSize - ra->msg3_nb_rb)) { + if (rbStart > (sched_pusch.bwp_info.bwpSize - ra->msg3_nb_rb)) { // cannot find free vrb_map for msg3 retransmission in this slot + reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_frame, beam_ul.new_beam); + reset_beam_status(&nr_mac->beam_info, frame, slot, UE->UE_beam_index, slots_frame, beam_dci.new_beam); return; } + sched_pusch.rbStart = rbStart; LOG_I(NR_MAC, "%4d%2d: RA RNTI %04x CC_id %d Scheduling retransmission of Msg3 in (%d,%d)\n", frame, @@ -871,18 +885,18 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, "Invalid future_ul_tti_req->n_pdus %d\n", future_ul_tti_req->n_pdus); future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE; future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t); - nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu; - memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); - - fill_msg3_pusch_pdu(pusch_pdu, scc, UE, startSymbolAndLength, mu, BWPSize, BWPStart, mappingtype, fh); + nfapi_nr_pusch_pdu_t *pusch_pdu = prepare_pusch_pdu(future_ul_tti_req, + UE, + scc, + &sched_pusch, + get_transformPrecoding(ul_bwp, NR_UL_DCI_FORMAT_0_0, 0), + 0, + ra->msg3_round, + ul_bwp->pusch_Config && ul_bwp->pusch_Config->frequencyHopping, + UE->rnti); future_ul_tti_req->n_pdus += 1; // generation of DCI 0_0 to schedule msg3 retransmission - NR_SearchSpace_t *ss = UE->UE_sched_ctrl.search_space; - NR_ControlResourceSet_t *coreset = UE->UE_sched_ctrl.coreset; - AssertFatal(coreset, "Coreset cannot be null for RA-Msg3 retransmission\n"); - - const int coresetid = coreset->controlResourceSetId; nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15 = nr_mac->pdcch_pdu_idx[CC_id][coresetid]; if (!pdcch_pdu_rel15) { nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &ul_dci_req->ul_dci_pdu_list[ul_dci_req->numPdus]; @@ -903,32 +917,26 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, ss, coreset, &UE->UE_sched_ctrl.sched_pdcch, - true, 0); if (CCEIndex < 0) { LOG_E(NR_MAC, "UE %04x cannot find free CCE!\n", UE->rnti); + reset_beam_status(&nr_mac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_frame, beam_ul.new_beam); + reset_beam_status(&nr_mac->beam_info, frame, slot, UE->UE_beam_index, slots_frame, beam_dci.new_beam); return; } // Fill PDCCH DL DCI PDU - nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, + scc, + ss, + coreset, + aggregation_level, + CCEIndex, + UE->UE_beam_index, + UE->rnti); pdcch_pdu_rel15->numDlDci++; - dci_pdu->RNTI = UE->rnti; - dci_pdu->ScramblingId = *scc->physCellId; - dci_pdu->ScramblingRNTI = 0; - dci_pdu->AggregationLevel = aggregation_level; - dci_pdu->CceIndex = CCEIndex; - dci_pdu->beta_PDCCH_1_0 = 0; - dci_pdu->powerControlOffsetSS = 1; - - dci_pdu->precodingAndBeamforming.num_prgs = 0; - dci_pdu->precodingAndBeamforming.prg_size = 0; - dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; - dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; - - dci_pdu_rel15_t uldci_payload={0}; + dci_pdu_rel15_t uldci_payload = {0}; config_uldci(sc_info, pusch_pdu, &uldci_payload, @@ -966,7 +974,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, beam_dci.idx); for (int rb = 0; rb < ra->msg3_nb_rb; rb++) { - vrb_map_UL[rbStart + BWPStart + rb] |= SL_to_bitmap(StartSymbolIndex, NrOfSymbols); + vrb_map_UL[rbStart + sched_pusch.bwp_info.bwpStart + rb] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); } // Restart RA contention resolution timer in Msg3 retransmission slot (current slot + K2) @@ -1008,18 +1016,10 @@ static bool get_feasible_msg3_tda(const NR_ServingCellConfigCommon_t *scc, if (fs->frame_type == TDD && !is_ul_slot(temp_slot, fs)) continue; - const tdd_bitmap_t *tdd_slot_bitmap = fs->period_cfg.tdd_slot_bitmap; int s = get_slot_idx_in_period(temp_slot, fs); - // check if enough symbols in case of mixed slot + const tdd_bitmap_t *bm = &fs->period_cfg.tdd_slot_bitmap[s]; bool is_mixed = is_mixed_slot(s, fs); - // if the mixed slot has not enough symbols, skip - if (is_mixed && tdd_slot_bitmap[s].num_ul_symbols < 3) - continue; - - uint16_t slot_mask = - is_mixed ? SL_to_bitmap(NR_NUMBER_OF_SYMBOLS_PER_SLOT - tdd_slot_bitmap[s].num_ul_symbols, - tdd_slot_bitmap[s].num_ul_symbols) - : 0x3fff; + uint16_t slot_mask = is_mixed ? SL_to_bitmap(NR_NUMBER_OF_SYMBOLS_PER_SLOT - bm->num_ul_symbols, bm->num_ul_symbols) : 0x3fff; long startSymbolAndLength = tda_list->list.array[i]->startSymbolAndLength; int start, nr; SLIV2SL(startSymbolAndLength, &start, &nr); @@ -1107,102 +1107,6 @@ static bool nr_get_Msg3alloc(gNB_MAC_INST *mac, int CC_id, int current_slot, fra return true; } -static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, - NR_ServingCellConfigCommon_t *scc, - NR_UE_info_t *UE, - int startSymbolAndLength, - int scs, - int bwp_size, - int bwp_start, - int mappingtype, - int fh) -{ - int start_symbol_index,nr_of_symbols; - SLIV2SL(startSymbolAndLength, &start_symbol_index, &nr_of_symbols); - int mcsindex = -1; // init value - const NR_RA_t *ra = UE->ra; - pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; - pusch_pdu->rnti = UE->rnti; - pusch_pdu->handle = 0; - pusch_pdu->bwp_start = bwp_start; - pusch_pdu->bwp_size = bwp_size; - pusch_pdu->subcarrier_spacing = scs; - pusch_pdu->cyclic_prefix = 0; - pusch_pdu->mcs_table = 0; - if (scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder == NULL) - pusch_pdu->transform_precoding = 1; // disabled - else { - pusch_pdu->transform_precoding = 0; // enabled - pusch_pdu->dfts_ofdm.low_papr_group_number = *scc->physCellId % 30; - pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0; - if (scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->groupHoppingEnabledTransformPrecoding) - AssertFatal(1==0,"Hopping mode is not supported in transform precoding\n"); - } - pusch_pdu->data_scrambling_id = *scc->physCellId; - pusch_pdu->nrOfLayers = 1; - pusch_pdu->ul_dmrs_symb_pos = get_l_prime(nr_of_symbols,mappingtype,pusch_dmrs_pos2,pusch_len1,start_symbol_index, scc->dmrs_TypeA_Position); - LOG_D(NR_MAC, "MSG3 start_sym:%d NR Symb:%d mappingtype:%d, ul_dmrs_symb_pos:%x\n", start_symbol_index, nr_of_symbols, mappingtype, pusch_pdu->ul_dmrs_symb_pos); - pusch_pdu->dmrs_config_type = 0; - pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; //If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id. - pusch_pdu->pusch_identity = *scc->physCellId; //If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id. - pusch_pdu->scid = 0; //DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]. Should match what is sent in DCI 0_1, otherwise set to 0. - pusch_pdu->dmrs_ports = 1; // 6.2.2 in 38.214 only port 0 to be used - pusch_pdu->num_dmrs_cdm_grps_no_data = nr_of_symbols <= 2 ? 1 : 2; // no data in dmrs symbols as in 6.2.2 in 38.214 - pusch_pdu->resource_alloc = 1; //type 1 - memset(pusch_pdu->rb_bitmap, 0, sizeof(pusch_pdu->rb_bitmap)); - pusch_pdu->rb_start = ra->msg3_first_rb; - if (ra->msg3_nb_rb > pusch_pdu->bwp_size) - AssertFatal(false, "MSG3 allocated number of RBs exceed the BWP size\n"); - else - pusch_pdu->rb_size = ra->msg3_nb_rb; - pusch_pdu->vrb_to_prb_mapping = 0; - - pusch_pdu->frequency_hopping = fh; - //pusch_pdu->tx_direct_current_location; - //The uplink Tx Direct Current location for the carrier. Only values in the value range of this field between 0 and 3299, - //which indicate the subcarrier index within the carrier corresponding 1o the numerology of the corresponding uplink BWP and value 3300, - //which indicates "Outside the carrier" and value 3301, which indicates "Undetermined position within the carrier" are used. [TS38.331, UplinkTxDirectCurrentBWP IE] - pusch_pdu->uplink_frequency_shift_7p5khz = 0; - //Resource Allocation in time domain - pusch_pdu->start_symbol_index = start_symbol_index; - pusch_pdu->nr_of_symbols = nr_of_symbols; - //Optional Data only included if indicated in pduBitmap - pusch_pdu->pusch_data.rv_index = nr_get_rv(ra->msg3_round % 4); - pusch_pdu->pusch_data.harq_process_id = 0; - pusch_pdu->pusch_data.new_data_indicator = (ra->msg3_round == 0) ? 1 : 0;; - pusch_pdu->pusch_data.num_cb = 0; - - // Beamforming - pusch_pdu->beamforming.num_prgs = 0; - pusch_pdu->beamforming.prg_size = 0; // bwp_size; - pusch_pdu->beamforming.dig_bf_interface = 1; - pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; - - int num_dmrs_symb = 0; - for(int i = start_symbol_index; i < start_symbol_index+nr_of_symbols; i++) - num_dmrs_symb += (pusch_pdu->ul_dmrs_symb_pos >> i) & 1; - int TBS = 0; - while(TBS<7) { // TBS for msg3 is 7 bytes (except for RRCResumeRequest1 currently not implemented) - mcsindex++; - AssertFatal(mcsindex <= 28, "Exceeding MCS limit for Msg3\n"); - int R = nr_get_code_rate_ul(mcsindex,pusch_pdu->mcs_table); - pusch_pdu->target_code_rate = R; - pusch_pdu->qam_mod_order = nr_get_Qm_ul(mcsindex,pusch_pdu->mcs_table); - TBS = nr_compute_tbs(pusch_pdu->qam_mod_order, - R, - pusch_pdu->rb_size, - pusch_pdu->nr_of_symbols, - num_dmrs_symb*12, // nb dmrs set for no data in dmrs symbol - 0, //nb_rb_oh - 0, // to verify tb scaling - pusch_pdu->nrOfLayers)>>3; - - pusch_pdu->mcs_index = mcsindex; - pusch_pdu->pusch_data.tb_size = TBS; - pusch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(TBS<<3,R); - } -} - static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_t slotP, NR_UE_info_t *UE, uint8_t *RAR_pdu) { gNB_MAC_INST *mac = RC.nrmac[module_idP]; @@ -1241,13 +1145,39 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ ra->Msg3_slot); future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE; future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t); - nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu; - memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); - const int ibwp_size = sc_info->initial_ul_BWPSize; - const int fh = (ul_bwp->pusch_Config && ul_bwp->pusch_Config->frequencyHopping) ? 1 : 0; - const int startSymbolAndLength = ul_bwp->tdaList_Common->list.array[ra->Msg3_tda_id]->startSymbolAndLength; - const int mappingtype = ul_bwp->tdaList_Common->list.array[ra->Msg3_tda_id]->mappingType; + NR_tda_info_t tda_info = get_ul_tda_info(ul_bwp, 0, NR_SearchSpace__searchSpaceType_PR_common, TYPE_TC_RNTI_, ra->Msg3_tda_id); + NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc, ul_bwp, &tda_info, 1); + int num_dmrs_symb = count_bits64_with_mask(dmrs_info.ul_dmrs_symb_pos, tda_info.startSymbolIndex, tda_info.nrOfSymbols); + int TBS = 0, mcsindex = 0, R = 0, Qm = 0; + while(TBS < 7) { // TBS for msg3 is 7 bytes (except for RRCResumeRequest1 currently not implemented) + mcsindex++; + AssertFatal(mcsindex <= 28, "Exceeding MCS limit for Msg3\n"); + R = nr_get_code_rate_ul(mcsindex, ul_bwp->mcs_table); + Qm = nr_get_Qm_ul(mcsindex, ul_bwp->mcs_table); + TBS = nr_compute_tbs(Qm, + R, + ra->msg3_nb_rb, + tda_info.nrOfSymbols, + num_dmrs_symb * 12, // nb dmrs set for no data in dmrs symbol + 0, //nb_rb_oh + 0, // to verify tb scaling + 1) >> 3; + } + + NR_sched_pusch_t sched_pusch = { + .bwp_info.bwpSize = sc_info->initial_ul_BWPSize, + .bwp_info.bwpStart = ra->msg3_bwp_start, + .rbSize = ra->msg3_nb_rb, + .rbStart = ra->msg3_first_rb, + .tb_size = TBS, + .R = R, + .Qm = Qm, + .mcs = mcsindex, + .nrOfLayers = 1, + .tda_info = tda_info, + .dmrs_info = dmrs_info + }; LOG_D(NR_MAC, "UE %04x: %d.%d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d)\n", @@ -1260,7 +1190,15 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_ ra->msg3_first_rb, ra->msg3_round); - fill_msg3_pusch_pdu(pusch_pdu, scc, UE, startSymbolAndLength, ul_bwp->scs, ibwp_size, ra->msg3_bwp_start, mappingtype, fh); + nfapi_nr_pusch_pdu_t *pusch_pdu = prepare_pusch_pdu(future_ul_tti_req, + UE, + scc, + &sched_pusch, + get_transformPrecoding(ul_bwp, NR_UL_DCI_FORMAT_0_0, 0), + 0, + 0, + ul_bwp->pusch_Config && ul_bwp->pusch_Config->frequencyHopping, + UE->rnti); future_ul_tti_req->n_pdus += 1; // calling function to fill rar message @@ -1342,29 +1280,19 @@ static bool msg2_in_response_window(int rach_frame, static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE, + NR_sched_pdsch_t *sched_pdsch, nfapi_nr_dl_tti_request_body_t *dl_req, NR_sched_pucch_t *pucch, - NR_pdsch_dmrs_t dmrs_info, - NR_tda_info_t tda, nr_rnti_type_t rnti_type, int aggregation_level, int CCEIndex, - int tb_size, int ndi, - int tpc, - int delta_PRI, int current_harq_pid, - int time_domain_assignment, int CC_id, int rnti, int round, - int mcsIndex, int tb_scaling, - int pduindex, - long BWPStart, - long BWPSize, - int rbStart, - int rbSize) + int pduindex) { // look up the PDCCH PDU for this CC, BWP, and CORESET. If it does not exist, create it. This is especially // important if we have multiple RAs, and the DLSCH has to reuse them, so we need to mark them @@ -1388,90 +1316,43 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdsch_pdu)); dl_req->nPDUs += 1; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; - int mcsTableIdx = dl_bwp->mcsTableIdx; - - pdsch_pdu_rel15->pduBitmap = 0; - pdsch_pdu_rel15->rnti = rnti; - pdsch_pdu_rel15->pduIndex = pduindex; - pdsch_pdu_rel15->BWPSize = BWPSize; - pdsch_pdu_rel15->BWPStart = BWPStart; - pdsch_pdu_rel15->SubcarrierSpacing = dl_bwp->scs; - pdsch_pdu_rel15->CyclicPrefix = 0; - pdsch_pdu_rel15->NrOfCodewords = 1; - int R = nr_get_code_rate_dl(mcsIndex, mcsTableIdx); - pdsch_pdu_rel15->targetCodeRate[0] = R; - int Qm = nr_get_Qm_dl(mcsIndex, mcsTableIdx); - pdsch_pdu_rel15->qamModOrder[0] = Qm; - pdsch_pdu_rel15->TBSize[0] = tb_size; - pdsch_pdu_rel15->mcsIndex[0] = mcsIndex; - pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx; - pdsch_pdu_rel15->rvIndex[0] = nr_get_rv(round % 4); - pdsch_pdu_rel15->dataScramblingId = *scc->physCellId; - pdsch_pdu_rel15->nrOfLayers = 1; - pdsch_pdu_rel15->transmissionScheme = 0; - pdsch_pdu_rel15->refPoint = 0; - pdsch_pdu_rel15->dmrsConfigType = dmrs_info.dmrsConfigType; - pdsch_pdu_rel15->dlDmrsScramblingId = *scc->physCellId; - pdsch_pdu_rel15->SCID = 0; - pdsch_pdu_rel15->numDmrsCdmGrpsNoData = dmrs_info.numDmrsCdmGrpsNoData; - pdsch_pdu_rel15->dmrsPorts = 1; - pdsch_pdu_rel15->resourceAlloc = 1; - pdsch_pdu_rel15->rbStart = rbStart; - pdsch_pdu_rel15->rbSize = rbSize; - pdsch_pdu_rel15->VRBtoPRBMapping = 0; - pdsch_pdu_rel15->StartSymbolIndex = tda.startSymbolIndex; - pdsch_pdu_rel15->NrOfSymbols = tda.nrOfSymbols; - pdsch_pdu_rel15->dlDmrsSymbPos = dmrs_info.dl_dmrs_symb_pos; - pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(mcsTableIdx, UE->sc_info.dl_bw_tbslbrm, 1); - pdsch_pdu_rel15->maintenance_parms_v3.ldpcBaseGraph = get_BG(tb_size << 3, R); - - pdsch_pdu_rel15->precodingAndBeamforming.num_prgs = 1; - pdsch_pdu_rel15->precodingAndBeamforming.prg_size = 275; - pdsch_pdu_rel15->precodingAndBeamforming.dig_bf_interfaces = 1; - pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = prepare_pdsch_pdu(dl_tti_pdsch_pdu, + nr_mac, + UE, + sched_pdsch, + dl_bwp->pdsch_Config, + false, + round, + rnti, + UE->UE_beam_index, + 1, + pduindex); /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, + scc, + sched_ctrl->search_space, + coreset, + aggregation_level, + CCEIndex, + UE->UE_beam_index, + rnti); pdcch_pdu_rel15->numDlDci++; - dci_pdu->RNTI = rnti; - dci_pdu->ScramblingId = *scc->physCellId; - dci_pdu->ScramblingRNTI = 0; - dci_pdu->AggregationLevel = aggregation_level; - dci_pdu->CceIndex = CCEIndex; - dci_pdu->beta_PDCCH_1_0 = 0; - dci_pdu->powerControlOffsetSS = 1; - dci_pdu->precodingAndBeamforming.num_prgs = 0; - dci_pdu->precodingAndBeamforming.prg_size = 0; - dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; - dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; - - dci_pdu_rel15_t dci_payload; - dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu_rel15->rbSize, - pdsch_pdu_rel15->rbStart, - BWPSize); - - dci_payload.time_domain_assignment.val = time_domain_assignment; - dci_payload.vrb_to_prb_mapping.val = 0; - dci_payload.mcs = pdsch_pdu_rel15->mcsIndex[0]; - dci_payload.tb_scaling = tb_scaling; - if (rnti_type == TYPE_TC_RNTI_) { - dci_payload.format_indicator = 1; - dci_payload.rv = pdsch_pdu_rel15->rvIndex[0]; - dci_payload.harq_pid.val = current_harq_pid; - dci_payload.ndi = ndi; - dci_payload.dai[0].val = pucch ? (pucch->dai_c-1) & 3 : 0; - dci_payload.tpc = tpc; // TPC for PUCCH: table 7.2.1-1 in 38.213 - dci_payload.pucch_resource_indicator = delta_PRI; // This is delta_PRI from 9.2.1 in 38.213 - dci_payload.pdsch_to_harq_feedback_timing_indicator.val = pucch ? pucch->timing_indicator : 0; - } + dci_pdu_rel15_t dci_payload = prepare_dci_dl_payload(nr_mac, + UE, + rnti_type, + sched_ctrl->search_space->searchSpaceType->present, + pdsch_pdu_rel15, + sched_pdsch, + pucch, + current_harq_pid, + tb_scaling, + false); LOG_D(NR_MAC, "DCI 1_0 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d pucchres %d harqtiming %d\n", @@ -1489,7 +1370,7 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, LOG_D(NR_MAC, "DCI params: rnti 0x%x, rnti_type %d, dci_format %d coreset params: FreqDomainResource %llx, start_symbol %d " "n_symb %d, BWPsize %d\n", - pdcch_pdu_rel15->dci_pdu[0].RNTI, + dci_pdu->RNTI, rnti_type, NR_DL_DCI_FORMAT_1_0, (unsigned long long)pdcch_pdu_rel15->FreqDomainResource, @@ -1500,7 +1381,7 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, fill_dci_pdu_rel15(&UE->sc_info, dl_bwp, &UE->current_UL_BWP, - &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], + dci_pdu, &dci_payload, NR_DL_DCI_FORMAT_1_0, rnti_type, @@ -1544,7 +1425,6 @@ static void nr_generate_Msg2(module_id_t module_idP, NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id]; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; - NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; NR_RA_t *ra = UE->ra; long rrc_ra_ResponseWindow = @@ -1585,23 +1465,14 @@ static void nr_generate_Msg2(module_id_t module_idP, int mcsIndex = -1; // initialization value int rbStart = 0; int rbSize = 8; - long BWPStart = 0; - long BWPSize = 0; - NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; - if (*ss->controlResourceSetId != 0) { - BWPStart = dl_bwp->BWPStart; - BWPSize = sc_info->initial_dl_BWPSize; - } else { - type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[cc->ssb_index[UE->UE_beam_index]]; - BWPStart = type0_PDCCH_CSS_config->cset_start_rb; - BWPSize = type0_PDCCH_CSS_config->num_rbs; - } - + bwp_info_t bwp_info = get_pdsch_bwp_start_size(nr_mac, UE); NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; AssertFatal(coreset, "Coreset cannot be null for RA-Msg2\n"); const int coresetid = coreset->controlResourceSetId; // Calculate number of symbols int time_domain_assignment = get_dl_tda(nr_mac, slotP); + + NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[cc->ssb_index[UE->UE_beam_index]]; int mux_pattern = type0_PDCCH_CSS_config ? type0_PDCCH_CSS_config->type0_pdcch_ss_mux_pattern : 1; NR_tda_info_t tda_info = get_dl_tda_info(dl_bwp, ss->searchSpaceType->present, @@ -1615,14 +1486,14 @@ static void nr_generate_Msg2(module_id_t module_idP, return; uint16_t *vrb_map = cc[CC_id].vrb_map[beam.idx]; - for (int i = 0; (i < rbSize) && (rbStart <= (BWPSize - rbSize)); i++) { - if (vrb_map[BWPStart + rbStart + i] & SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)) { + for (int i = 0; (i < rbSize) && (rbStart <= (bwp_info.bwpSize - rbSize)); i++) { + if (vrb_map[bwp_info.bwpStart + rbStart + i] & SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)) { rbStart += i; i = 0; } } - if (rbStart > (BWPSize - rbSize)) { + if (rbStart > (bwp_info.bwpSize - rbSize)) { LOG_W(NR_MAC, "Cannot find free vrb_map for RA RNTI %04x!\n", ra->RA_rnti); reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, UE->UE_beam_index, n_slots_frame, ra->Msg3_beam.new_beam); reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); @@ -1639,7 +1510,7 @@ static void nr_generate_Msg2(module_id_t module_idP, } uint8_t aggregation_level; - int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &sched_ctrl->sched_pdcch, true, 0); + int CCEIndex = get_cce_index(nr_mac, CC_id, slotP, 0, &aggregation_level, beam.idx, ss, coreset, &sched_ctrl->sched_pdcch, 0); if (CCEIndex < 0) { LOG_W(NR_MAC, "UE %04x: %d.%d cannot find free CCE for Msg2!\n", UE->rnti, frameP, slotP); @@ -1683,11 +1554,9 @@ static void nr_generate_Msg2(module_id_t module_idP, NR_pdsch_dmrs_t dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, &tda_info, 1); - uint8_t tb_scaling = 0; int R, Qm; uint32_t TBS = 0; - while (TBS < 9) { // min TBS for RAR is 9 bytes mcsIndex++; R = nr_get_code_rate_dl(mcsIndex, mcsTableIdx); @@ -1703,31 +1572,35 @@ static void nr_generate_Msg2(module_id_t module_idP, >> 3; // layers } + NR_sched_pdsch_t sched_pdsch = { + .R = R, + .Qm = Qm, + .mcs = mcsIndex, + .time_domain_allocation = time_domain_assignment, + .nrOfLayers = 1, + .dmrs_parms = dmrs_parms, + .tda_info = tda_info, + .pm_index = 0, + .tb_size = TBS, + .bwp_info = bwp_info, + .rbStart = rbStart, + .rbSize = rbSize + }; prepare_dl_pdus(nr_mac, UE, + &sched_pdsch, dl_req, NULL, - dmrs_parms, - tda_info, TYPE_RA_RNTI_, aggregation_level, CCEIndex, - TBS, 0, 0, - 0, - 0, - time_domain_assignment, CC_id, ra->RA_rnti, 0, - mcsIndex, tb_scaling, - pduindex, - BWPStart, - BWPSize, - rbStart, - rbSize); + pduindex); // DL TX request nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[TX_req->Number_of_PDUs]; @@ -1774,7 +1647,7 @@ static void nr_generate_Msg2(module_id_t module_idP, // Mark the corresponding symbols RBs as used fill_pdcch_vrb_map(nr_mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, aggregation_level, beam.idx); for (int rb = 0; rb < rbSize; rb++) { - vrb_map[BWPStart + rb + rbStart] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); + vrb_map[bwp_info.bwpStart + rb + rbStart] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); } ra->ra_state = nrRA_WAIT_Msg3; @@ -1828,18 +1701,6 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, if (beam.idx < 0) return; - long BWPStart = 0; - long BWPSize = 0; - NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = NULL; - if(*ss->controlResourceSetId!=0) { - BWPStart = dl_bwp->BWPStart; - BWPSize = dl_bwp->BWPSize; - } else { - type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[cc->ssb_index[UE->UE_beam_index]]; - BWPStart = type0_PDCCH_CSS_config->cset_start_rb; - BWPSize = type0_PDCCH_CSS_config->num_rbs; - } - // get CCEindex, needed also for PUCCH and then later for PDCCH uint8_t aggregation_level; int CCEIndex = get_cce_index(nr_mac, @@ -1849,7 +1710,6 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, ss, coreset, &sched_ctrl->sched_pdcch, - true, 0); if (CCEIndex < 0) { @@ -1867,6 +1727,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } uint8_t time_domain_assignment = get_dl_tda(nr_mac, slotP); + NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config = &nr_mac->type0_PDCCH_CSS_config[cc->ssb_index[UE->UE_beam_index]]; int mux_pattern = type0_PDCCH_CSS_config ? type0_PDCCH_CSS_config->type0_pdcch_ss_mux_pattern : 1; NR_tda_info_t msg4_tda = get_dl_tda_info(dl_bwp, ss->searchSpaceType->present, @@ -1876,11 +1737,13 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, TYPE_TC_RNTI_, coreset->controlResourceSetId, false); - if (!msg4_tda.valid_tda) + if (!msg4_tda.valid_tda) { + reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; + } NR_pdsch_dmrs_t dmrs_info = get_dl_dmrs_params(scc, dl_bwp, &msg4_tda, 1); - + bwp_info_t bwp_info = get_pdsch_bwp_start_size(nr_mac, UE); uint8_t mcsTableIdx = dl_bwp->mcsTableIdx; uint8_t mcsIndex = 0; int rbStart = 0; @@ -1892,8 +1755,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, NR_UE_harq_t *harq = &sched_ctrl->harq_processes[current_harq_pid]; DevAssert(!harq->is_waiting); pdu_length = harq->tb_size; - } - else { + } else { uint8_t subheader_len = (mac_sdu_length < 256) ? sizeof(NR_MAC_SUBHEADER_SHORT) : sizeof(NR_MAC_SUBHEADER_LONG); pdu_length = mac_sdu_length + subheader_len + 13; // 13 is contention resolution length of msgB. It is divided into 3 parts: // BI MAC subheader (1 Oct) + SuccessRAR MAC subheader (1 Oct) + SuccessRAR (11 Oct) @@ -1901,22 +1763,26 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, // increase PRBs until we get to BWPSize or TBS is bigger than MAC PDU size do { - if(rbSize < BWPSize) + if(rbSize < bwp_info.bwpSize) rbSize++; else mcsIndex++; LOG_D(NR_MAC,"Calling nr_compute_tbs with N_PRB_DMRS %d, N_DMRS_SLOT %d\n",dmrs_info.N_PRB_DMRS,dmrs_info.N_DMRS_SLOT); tb_size = nr_compute_tbs(nr_get_Qm_dl(mcsIndex, mcsTableIdx), - nr_get_code_rate_dl(mcsIndex, mcsTableIdx), - rbSize, msg4_tda.nrOfSymbols, dmrs_info.N_PRB_DMRS * dmrs_info.N_DMRS_SLOT, 0, tb_scaling,1) >> 3; + nr_get_code_rate_dl(mcsIndex, mcsTableIdx), + rbSize, + msg4_tda.nrOfSymbols, + dmrs_info.N_PRB_DMRS * dmrs_info.N_DMRS_SLOT, + 0, + tb_scaling,1) >> 3; } while (tb_size < pdu_length && mcsIndex<=28); AssertFatal(tb_size >= pdu_length, "Cannot allocate %s\n", ra_type_str); int i = 0; uint16_t *vrb_map = cc[CC_id].vrb_map[beam.idx]; - while ((i < rbSize) && (rbStart + rbSize <= BWPSize)) { - if (vrb_map[BWPStart + rbStart + i]&SL_to_bitmap(msg4_tda.startSymbolIndex, msg4_tda.nrOfSymbols)) { + while ((i < rbSize) && (rbStart + rbSize <= bwp_info.bwpSize)) { + if (vrb_map[bwp_info.bwpStart + rbStart + i]&SL_to_bitmap(msg4_tda.startSymbolIndex, msg4_tda.nrOfSymbols)) { rbStart += i+1; i = 0; } else { @@ -1924,15 +1790,14 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } } - if (rbStart > (BWPSize - rbSize)) { + if (rbStart > (bwp_info.bwpSize - rbSize)) { LOG_E(NR_MAC, "Cannot find free vrb_map for RNTI %04x!\n", UE->rnti); reset_beam_status(&nr_mac->beam_info, frameP, slotP, UE->UE_beam_index, n_slots_frame, beam.new_beam); return; } - const int delta_PRI = 0; int r_pucch = nr_get_pucch_resource(coreset, UE->current_UL_BWP.pucch_Config, CCEIndex); - LOG_D(NR_MAC, "Msg4 r_pucch %d (CCEIndex %d, delta_PRI %d)\n", r_pucch, CCEIndex, delta_PRI); + LOG_D(NR_MAC, "Msg4 r_pucch %d CCEIndex %d\n", r_pucch, CCEIndex); int alloc = nr_acknack_scheduling(nr_mac, UE, frameP, slotP, UE->UE_beam_index, r_pucch, 1); if (alloc < 0) { LOG_D(NR_MAC,"Couldn't find a pucch allocation for ack nack (msg4) in frame %d slot %d\n", frameP, slotP); @@ -2000,33 +1865,36 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } rnti_t rnti = ra->ra_type == RA_4_STEP ? UE->rnti : ra->MsgB_rnti; - + NR_sched_pdsch_t sched_pdsch = { + .R = nr_get_code_rate_dl(mcsIndex, mcsTableIdx), + .Qm = nr_get_Qm_dl(mcsIndex, mcsTableIdx), + .mcs = mcsIndex, + .time_domain_allocation = time_domain_assignment, + .nrOfLayers = 1, + .dmrs_parms = dmrs_info, + .tda_info = msg4_tda, + .pm_index = 0, + .tb_size = tb_size, + .bwp_info = bwp_info, + .rbStart = rbStart, + .rbSize = rbSize + }; const int pduindex = nr_mac->pdu_index[CC_id]++; prepare_dl_pdus(nr_mac, UE, + &sched_pdsch, dl_req, pucch, - dmrs_info, - msg4_tda, TYPE_TC_RNTI_, aggregation_level, CCEIndex, - tb_size, harq->ndi, - sched_ctrl->tpc1, - delta_PRI, current_harq_pid, - time_domain_assignment, CC_id, rnti, harq->round, - mcsIndex, tb_scaling, - pduindex, - BWPStart, - BWPSize, - rbStart, - rbSize); + pduindex); // Reset TPC to 0 dB to not request new gain multiple times before computing new value for SNR sched_ctrl->tpc1 = 1; @@ -2063,7 +1931,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, aggregation_level, beam.idx); for (int rb = 0; rb < rbSize; rb++) { - vrb_map[BWPStart + rb + rbStart] |= SL_to_bitmap(msg4_tda.startSymbolIndex, msg4_tda.nrOfSymbols); + vrb_map[bwp_info.bwpStart + rb + rbStart] |= SL_to_bitmap(msg4_tda.startSymbolIndex, msg4_tda.nrOfSymbols); } ra->ra_state = nrRA_WAIT_Msg4_MsgB_ACK; @@ -2077,7 +1945,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP, } } -void nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, NR_UE_info_t *UE, bool success) +bool nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, NR_UE_info_t *UE, bool success) { NR_RA_t *ra = UE->ra; const char *ra_type_str = ra->ra_type == RA_2_STEP ? "MsgB" : "Msg4"; @@ -2092,10 +1960,21 @@ void nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, N if (success) { gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon; - // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration - configure_UE_BWP(nr_mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); - transition_ra_connected_nr_ue(nr_mac, UE); - LOG_A(NR_MAC, "%4d.%2d UE %04x: Received Ack of %s. CBRA procedure succeeded!\n", frame, slot, UE->rnti, ra_type_str); + LOG_A(NR_MAC, + "%4d.%2d UE %04x: Received Ack of %s. CBRA procedure succeeded (%s)\n", + frame, + slot, + UE->rnti, + ra_type_str, + UE->CellGroup ? "UE Connected" : "UE Rejected"); + if (UE->CellGroup) { + // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration + configure_UE_BWP(nr_mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); + transition_ra_connected_nr_ue(nr_mac, UE); + } else { // in case of UE reject + nr_release_ra_UE(nr_mac, UE->rnti); + return true; + } } else { LOG_I(NR_MAC, "%4d.%2d UE %04x: RA Procedure failed at %s!\n", frame, slot, UE->rnti, ra_type_str); nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs); @@ -2108,6 +1987,7 @@ void nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, N LOG_I(NR_MAC, "(UE %04x) Received Nack in %s, preparing retransmission!\n", UE->rnti, ra_type_str); ra->ra_state = ra->ra_type == RA_4_STEP ? nrRA_Msg4 : nrRA_MsgB; } + return false; } ///////////////////////////////////// @@ -2242,7 +2122,7 @@ void nr_release_ra_UE(gNB_MAC_INST *mac, rnti_t rnti) if (UE) { delete_nr_ue_data(UE, mac->common_channels, &UE_info->uid_allocator); } else { - LOG_W(NR_MAC,"Call to del rnti %04x, but not existing\n", rnti); + LOG_W(NR_MAC,"Call to release RA UE with rnti %04x, but not existing\n", rnti); } } @@ -2269,7 +2149,9 @@ void nr_schedule_RA(module_id_t module_idP, ra->contention_resolution_timer--; if (ra->contention_resolution_timer == 0) { LOG_W(NR_MAC, "(%d.%d) RA Contention Resolution timer expired for UE 0x%04x, RA procedure failed...\n", frameP, slotP, UE->rnti); - bool requested = nr_mac_request_release_ue(mac, UE->rnti); + bool requested = false; + if (UE->CellGroup) // request if we did not reject the UE + requested = nr_mac_request_release_ue(mac, UE->rnti); if (!requested) nr_release_ra_UE(mac, UE->rnti); continue; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index bb8aea43fe..8a81d8ae4f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -79,7 +79,7 @@ static void schedule_ssb(frame_t frame, dl_config_pdu->ssb_pdu.ssb_pdu_rel15.bchPayloadFlag = 1; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.bchPayload = payload; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.num_prgs = 1; - dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.prg_size = 275; //1 PRG of max size for analogue beamforming + dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.prg_size = 20; //SSB is always 20RBs dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.dig_bf_interfaces = 1; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.prgs_list[0].pm_idx = 0; dl_config_pdu->ssb_pdu.ssb_pdu_rel15.precoding_and_beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; @@ -274,8 +274,7 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi } } -static uint32_t get_tbs_bch(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config, - NR_sched_pdsch_t *pdsch, +static uint32_t get_tbs_bch(NR_sched_pdsch_t *pdsch, uint32_t num_total_bytes, uint16_t *vrb_map) { @@ -287,8 +286,8 @@ static uint32_t get_tbs_bch(NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config, int mcsTableIdx = 0; uint32_t TBS = 0; const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); - int bwpSize = type0_PDCCH_CSS_config->num_rbs; - int bwpStart = type0_PDCCH_CSS_config->cset_start_rb; + int bwpSize = pdsch->bwp_info.bwpSize; + int bwpStart = pdsch->bwp_info.bwpStart; int rbStop = bwpSize - 1; int rbStart = 0; uint16_t rbSize = 0; @@ -357,9 +356,12 @@ static uint32_t schedule_control_sib1(gNB_MAC_INST *gNB_mac, NR_COMMON_channels_t *cc = &gNB_mac->common_channels[CC_id]; uint16_t *vrb_map = cc->vrb_map[beam]; NR_sched_pdsch_t *pdsch = &gNB_mac->sched_ctrlCommon->sched_pdsch; + pdsch->bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL); pdsch->time_domain_allocation = time_domain_allocation; pdsch->dmrs_parms = *dmrs_parms; pdsch->tda_info = *tda_info; + pdsch->nrOfLayers = 1; + pdsch->pm_index = 0; pdsch->mcs = 0; // starting from mcs 0 gNB_mac->sched_ctrlCommon->num_total_bytes = num_total_bytes; @@ -381,11 +383,13 @@ static uint32_t schedule_control_sib1(gNB_MAC_INST *gNB_mac, AssertFatal(gNB_mac->sched_ctrlCommon->cce_index >= 0, "Could not find CCE for coreset0\n"); - uint32_t TBS = get_tbs_bch(type0_PDCCH_CSS_config, - &gNB_mac->sched_ctrlCommon->sched_pdsch, + uint32_t TBS = get_tbs_bch(&gNB_mac->sched_ctrlCommon->sched_pdsch, gNB_mac->sched_ctrlCommon->num_total_bytes, vrb_map); + pdsch->R = nr_get_code_rate_dl(pdsch->mcs, 0); + pdsch->Qm = nr_get_Qm_dl(pdsch->mcs, 0); + // Mark the corresponding RBs as used fill_pdcch_vrb_map(gNB_mac, CC_id, @@ -409,15 +413,11 @@ static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac, nfapi_nr_dl_tti_request_body_t *dl_req, int pdu_index, NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config, - uint32_t TBS, - int StartSymbolIndex, - int NrOfSymbols, bool is_sib1, int beam_index) { NR_COMMON_channels_t *cc = gNB_mac->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - int mcsTableIdx = 0; nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; memset(dl_tti_pdcch_pdu, 0, sizeof(*dl_tti_pdcch_pdu)); @@ -432,50 +432,18 @@ static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac, dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; dl_tti_pdsch_pdu->PDUSize = (uint16_t)(4+sizeof(nfapi_nr_dl_tti_pdsch_pdu)); dl_req->nPDUs += 1; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; - - pdsch_pdu_rel15->precodingAndBeamforming.num_prgs = 0; - pdsch_pdu_rel15->precodingAndBeamforming.prg_size = 0; - pdsch_pdu_rel15->precodingAndBeamforming.dig_bf_interfaces = 1; - pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; - - pdcch_pdu_rel15->CoreSetType = NFAPI_NR_CSET_CONFIG_MIB_SIB1; - - pdsch_pdu_rel15->pduBitmap = 0; - pdsch_pdu_rel15->rnti = SI_RNTI; - pdsch_pdu_rel15->pduIndex = pdu_index; - - pdsch_pdu_rel15->BWPSize = type0_PDCCH_CSS_config->num_rbs; - pdsch_pdu_rel15->BWPStart = type0_PDCCH_CSS_config->cset_start_rb; - - pdsch_pdu_rel15->SubcarrierSpacing = type0_PDCCH_CSS_config->scs_pdcch; - pdsch_pdu_rel15->CyclicPrefix = 0; - - pdsch_pdu_rel15->NrOfCodewords = 1; - pdsch_pdu_rel15->targetCodeRate[0] = nr_get_code_rate_dl(pdsch->mcs, mcsTableIdx); - pdsch_pdu_rel15->qamModOrder[0] = nr_get_Qm_dl(pdsch->mcs, mcsTableIdx); - pdsch_pdu_rel15->mcsIndex[0] = pdsch->mcs; - pdsch_pdu_rel15->mcsTable[0] = mcsTableIdx; - pdsch_pdu_rel15->rvIndex[0] = nr_get_rv(0); - pdsch_pdu_rel15->dataScramblingId = *scc->physCellId; - pdsch_pdu_rel15->nrOfLayers = 1; - pdsch_pdu_rel15->transmissionScheme = 0; - pdsch_pdu_rel15->refPoint = is_sib1; - pdsch_pdu_rel15->dmrsConfigType = 0; - pdsch_pdu_rel15->dlDmrsScramblingId = *scc->physCellId; - pdsch_pdu_rel15->SCID = 0; - pdsch_pdu_rel15->numDmrsCdmGrpsNoData = pdsch->dmrs_parms.numDmrsCdmGrpsNoData; - pdsch_pdu_rel15->dmrsPorts = 1; - pdsch_pdu_rel15->resourceAlloc = 1; - pdsch_pdu_rel15->rbStart = pdsch->rbStart; - pdsch_pdu_rel15->rbSize = pdsch->rbSize; - pdsch_pdu_rel15->VRBtoPRBMapping = 0; - pdsch_pdu_rel15->TBSize[0] = TBS; - pdsch_pdu_rel15->StartSymbolIndex = StartSymbolIndex; - pdsch_pdu_rel15->NrOfSymbols = NrOfSymbols; - pdsch_pdu_rel15->dlDmrsSymbPos = pdsch->dmrs_parms.dl_dmrs_symb_pos; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = prepare_pdsch_pdu(dl_tti_pdsch_pdu, + gNB_mac, + NULL, + pdsch, + NULL, + is_sib1, + 0, + SI_RNTI, + beam_index, + 1, + pdu_index); LOG_D(NR_MAC, "OtherSI:bwpStart %d, bwpSize %d, rbStart %d, rbSize %d, dlDmrsSymbPos = 0x%x\n", pdsch_pdu_rel15->BWPStart, @@ -484,58 +452,35 @@ static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac, pdsch_pdu_rel15->rbSize, pdsch_pdu_rel15->dlDmrsSymbPos); - pdsch_pdu_rel15->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(0, - pdsch_pdu_rel15->BWPSize, - 1); - pdsch_pdu_rel15->maintenance_parms_v3.ldpcBaseGraph = get_BG(TBS<<3,pdsch_pdu_rel15->targetCodeRate[0]); - /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci]; + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu_rel15, + scc, + search_space, + coreset, + aggregation_level, + cce_index, + beam_index, + SI_RNTI); pdcch_pdu_rel15->numDlDci++; - dci_pdu->RNTI = SI_RNTI; - dci_pdu->ScramblingId = *scc->physCellId; - dci_pdu->ScramblingRNTI = 0; - dci_pdu->AggregationLevel = aggregation_level; - dci_pdu->CceIndex = cce_index; - dci_pdu->beta_PDCCH_1_0 = 0; - dci_pdu->powerControlOffsetSS = 1; - - dci_pdu->precodingAndBeamforming.num_prgs = 0; - dci_pdu->precodingAndBeamforming.prg_size = 0; - dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; - dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; /* DCI payload */ - dci_pdu_rel15_t dci_payload; - memset(&dci_payload, 0, sizeof(dci_pdu_rel15_t)); - - dci_payload.bwp_indicator.val = 0; - - // frequency domain assignment - dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0( - pdsch_pdu_rel15->rbSize, pdsch_pdu_rel15->rbStart, type0_PDCCH_CSS_config->num_rbs); - - dci_payload.time_domain_assignment.val = pdsch->time_domain_allocation; - dci_payload.mcs = pdsch->mcs; - dci_payload.rv = pdsch_pdu_rel15->rvIndex[0]; - dci_payload.harq_pid.val = 0; - dci_payload.ndi = 0; - dci_payload.dai[0].val = 0; - dci_payload.tpc = 0; // table 7.2.1-1 in 38.213 - dci_payload.pucch_resource_indicator = 0; - dci_payload.pdsch_to_harq_feedback_timing_indicator.val = 0; - dci_payload.antenna_ports.val = 0; - dci_payload.dmrs_sequence_initialization.val = pdsch_pdu_rel15->SCID; - dci_payload.system_info_indicator = is_sib1 ? 0 : 1; - int dci_format = NR_DL_DCI_FORMAT_1_0; int rnti_type = TYPE_SI_RNTI_; + dci_pdu_rel15_t dci_payload = prepare_dci_dl_payload(gNB_mac, + NULL, + rnti_type, + NR_SearchSpace__searchSpaceType_PR_common, + pdsch_pdu_rel15, + pdsch, + NULL, + 0, + 0, + is_sib1); fill_dci_pdu_rel15(NULL, NULL, NULL, - &pdcch_pdu_rel15->dci_pdu[pdcch_pdu_rel15->numDlDci - 1], + dci_pdu, &dci_payload, dci_format, rnti_type, @@ -644,6 +589,7 @@ void schedule_nr_sib1(module_id_t module_idP, beam.idx, cc->sib1_bcch_length); + gNB_mac->sched_ctrlCommon->sched_pdsch.tb_size = TBS; nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body; int pdu_index = gNB_mac->pdu_index[0]++; nr_fill_nfapi_dl_SIB_pdu(gNB_mac, @@ -656,9 +602,6 @@ void schedule_nr_sib1(module_id_t module_idP, dl_req, pdu_index, type0_PDCCH_CSS_config, - TBS, - tda_info.startSymbolIndex, - tda_info.nrOfSymbols, true, beam_index); @@ -743,7 +686,8 @@ static void other_sib_sched_control(module_id_t module_idP, } AssertFatal(nr_of_candidates > 0, "nr_of_candidates is 0\n"); - NR_ControlResourceSet_t *coreset = get_coreset(gNB_mac, scc, NULL, ss, NR_SearchSpace__searchSpaceType_PR_common); + AssertFatal(ss->controlResourceSetId, "ss->controlResourceSetId is NULL\n"); + NR_ControlResourceSet_t *coreset = get_coreset(gNB_mac, scc, NULL, *ss->controlResourceSetId); if (!gNB_mac->sched_pdcch_otherSI) { gNB_mac->sched_pdcch_otherSI = calloc(1, sizeof(*gNB_mac->sched_pdcch_otherSI)); *gNB_mac->sched_pdcch_otherSI = set_pdcch_structure(gNB_mac, ss, coreset, scc, NULL, type0_PDCCH_CSS_config); @@ -764,14 +708,19 @@ static void other_sib_sched_control(module_id_t module_idP, NR_sched_pdsch_t sched_pdsch_otherSI = {0}; sched_pdsch_otherSI.time_domain_allocation = time_domain_allocation; + sched_pdsch_otherSI.bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL); sched_pdsch_otherSI.dmrs_parms = dmrs_parms; sched_pdsch_otherSI.tda_info = tda_info; + sched_pdsch_otherSI.nrOfLayers = 1; + sched_pdsch_otherSI.pm_index = 0; sched_pdsch_otherSI.mcs = 0; // starting from mcs 0 uint16_t *vrb_map = cc->vrb_map[beam.idx]; uint8_t *sib_bcch_pdu = cc->other_sib_bcch_pdu[payload_idx]; int num_total_bytes = cc->other_sib_bcch_length[payload_idx]; - uint32_t TBS = get_tbs_bch(type0_PDCCH_CSS_config, &sched_pdsch_otherSI, num_total_bytes, vrb_map); + sched_pdsch_otherSI.tb_size = get_tbs_bch(&sched_pdsch_otherSI, num_total_bytes, vrb_map); + sched_pdsch_otherSI.R = nr_get_code_rate_dl(sched_pdsch_otherSI.mcs, 0); + sched_pdsch_otherSI.Qm = nr_get_Qm_dl(sched_pdsch_otherSI.mcs, 0); for (int rb = 0; rb < sched_pdsch_otherSI.rbSize; rb++) { vrb_map[rb + type0_PDCCH_CSS_config->cset_start_rb] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); @@ -789,9 +738,6 @@ static void other_sib_sched_control(module_id_t module_idP, dl_req, pdu_index, type0_PDCCH_CSS_config, - TBS, - tda_info.startSymbolIndex, - tda_info.nrOfSymbols, false, beam_index); @@ -799,12 +745,12 @@ static void other_sib_sched_control(module_id_t module_idP, nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[ntx_req]; // Data to be transmitted - memcpy(tx_req->TLVs[0].value.direct, sib_bcch_pdu, TBS); + memcpy(tx_req->TLVs[0].value.direct, sib_bcch_pdu, sched_pdsch_otherSI.tb_size); - tx_req->PDU_length = TBS; + tx_req->PDU_length = sched_pdsch_otherSI.tb_size; tx_req->PDU_index = pdu_index; tx_req->num_TLV = 1; - tx_req->TLVs[0].length = TBS + 2; + tx_req->TLVs[0].length = sched_pdsch_otherSI.tb_size + 2; TX_req->Number_of_PDUs++; TX_req->SFN = frame; TX_req->Slot = slot; @@ -829,7 +775,7 @@ static bool test_other_sib_sched_occasion(int window_pos, int rel_frame, int rel_slot) { - int x = window_pos * window_len; + int x = (window_pos - 1) * window_len; int T = 8 << period; int test_frame = (frame - rel_frame) % MAX_FRAME_NUMBER; int si_slot = (x % n_slots_frame) + rel_slot; @@ -902,7 +848,7 @@ void schedule_nr_other_sib(module_id_t module_idP, for (int ssb = 0; ssb < num_ssb; ssb++) { for (int i = 0; i < schedInfo->schedulingInfoList.list.count; i++) { NR_SchedulingInfo_t *schedulingInfo = schedInfo->schedulingInfoList.list.array[i]; - if (test_other_sib_sched_occasion(i, + if (test_other_sib_sched_occasion(i + 1, window_length_sl, schedulingInfo->si_Periodicity, n_slots_frame, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 4328fd1ac2..8b1fdbc9ea 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -339,9 +339,7 @@ static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, slot_t s continue; if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt)) continue; - start_meas(&RC.nrmac[module_id]->rlc_status_ind); sched_ctrl->rlc_status[lcid] = nr_mac_rlc_status_ind(rnti, frame, lcid); - stop_meas(&RC.nrmac[module_id]->rlc_status_ind); if (sched_ctrl->rlc_status[lcid].bytes_in_buffer == 0) continue; @@ -383,12 +381,16 @@ void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid) UE->mac_stats.dl.errors++; } -static bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) +bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) { + bwp_info_t bwp_info; + if (!UE) { + bwp_info.bwpStart = nr_mac->cset0_bwp_start; + bwp_info.bwpSize = nr_mac->cset0_bwp_size; + return bwp_info; + } NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - bwp_info_t bwp_info; - // 3GPP TS 38.214 Section 5.1.2.2 Resource allocation in frequency domain // For a PDSCH scheduled with a DCI format 1_0 in any type of PDCCH common search space, regardless of which bandwidth part is the // active bandwidth part, RB numbering starts from the lowest RB of the CORESET in which the DCI was received; otherwise RB @@ -548,9 +550,9 @@ static bool allocate_dl_retransmission(module_id_t module_id, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, - false, sched_ctrl->pdcch_cl_adjust); if (CCEIndex<0) { + sched_ctrl->dl_cce_fail++; LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI retransmission\n", UE->rnti, frame, slot); return false; } @@ -574,6 +576,7 @@ static bool allocate_dl_retransmission(module_id_t module_id, sched_ctrl->sched_pdsch = *retInfo; sched_ctrl->sched_pdsch.rbStart = rbStart - bwp_info.bwpStart; sched_ctrl->sched_pdsch.pucch_allocation = alloc; + sched_ctrl->sched_pdsch.bwp_info = bwp_info; /* retransmissions: directly allocate */ *n_rb_sched -= sched_ctrl->sched_pdsch.rbSize; @@ -589,8 +592,15 @@ typedef struct UEsched_s { NR_UE_info_t * UE; } UEsched_t; -static int comparator(const void *p, const void *q) { - return ((UEsched_t*)p)->coef < ((UEsched_t*)q)->coef; +static int comparator(const void *p, const void *q) +{ + const UEsched_t *pp = p; + const UEsched_t *qq = q; + if (pp->coef < qq->coef) + return 1; + else if (pp->coef > qq->coef) + return -1; + return 0; } static void pf_dl(module_id_t module_id, @@ -608,7 +618,7 @@ static void pf_dl(module_id_t module_id, int remainUEs[num_beams]; for (int i = 0; i < num_beams; i++) remainUEs[i] = max_num_ue; - int curUE = 0; + int numUE = 0; int CC_id = 0; int slots_per_frame = mac->frame_structure.numb_slots_frame; @@ -617,13 +627,14 @@ static void pf_dl(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; - if (sched_ctrl->ul_failure) + if (!nr_mac_ue_is_active(UE)) continue; const NR_mac_dir_stats_t *stats = &UE->mac_stats.dl; NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; /* get the PID of a HARQ process awaiting retrnasmission, or -1 otherwise */ sched_pdsch->dl_harq_pid = sched_ctrl->retrans_dl_harq.head; + /* Calculate Throughput */ const float a = 0.01f; const uint32_t b = UE->mac_stats.dl.current_bytes; @@ -671,7 +682,8 @@ static void pf_dl(module_id_t module_id, const int max_mcs_table = current_BWP->mcsTableIdx == 1 ? 27 : 28; const int max_mcs = min(sched_ctrl->dl_max_mcs, max_mcs_table); if (bo->harq_round_max == 1) { - sched_pdsch->mcs = min(bo->max_mcs, max_mcs); + int new_mcs = min(bo->max_mcs, max_mcs); + sched_pdsch->mcs = max(bo->min_mcs, new_mcs); sched_ctrl->dl_bler_stats.mcs = sched_pdsch->mcs; } else sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame); @@ -698,13 +710,13 @@ static void pf_dl(module_id_t module_id, tbs, coeff_ue); /* Create UE_sched list for UEs eligible for new transmission*/ - UE_sched[curUE].coef=coeff_ue; - UE_sched[curUE].UE=UE; - curUE++; + UE_sched[numUE].coef = coeff_ue; + UE_sched[numUE].UE = UE; + numUE++; } } - qsort(UE_sched, sizeofArray(UE_sched), sizeof(UEsched_t), comparator); + qsort(UE_sched, numUE, sizeof(UEsched_t), comparator); UEsched_t *iterator = UE_sched; const int min_rbSize = 10; @@ -763,10 +775,10 @@ static void pf_dl(module_id_t module_id, const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); uint16_t *rballoc_mask = mac->common_channels[CC_id].vrb_map[beam.idx]; - bwp_info_t bwp_info = get_pdsch_bwp_start_size(mac, iterator->UE); + sched_pdsch->bwp_info = get_pdsch_bwp_start_size(mac, iterator->UE); int rbStart = 0; // WRT BWP start - int rbStop = bwp_info.bwpSize - 1; - int bwp_start = bwp_info.bwpStart; + int rbStop = sched_pdsch->bwp_info.bwpSize - 1; + int bwp_start = sched_pdsch->bwp_info.bwpStart; // Freq-demain allocation while (rbStart < rbStop && (rballoc_mask[rbStart + bwp_start] & slbitmap)) rbStart++; @@ -785,6 +797,7 @@ static void pf_dl(module_id_t module_id, rbStart, max_rbSize, rbStop); + reset_beam_status(&mac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam); iterator++; continue; } @@ -798,9 +811,9 @@ static void pf_dl(module_id_t module_id, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, - false, sched_ctrl->pdcch_cl_adjust); if (CCEIndex < 0) { + sched_ctrl->dl_cce_fail++; LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI\n", rnti, frame, slot); reset_beam_status(&mac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam); iterator++; @@ -919,6 +932,84 @@ nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id) { return nr_dlsch_preprocessor; } +nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu, + const gNB_MAC_INST *mac, + const NR_UE_info_t *UE, + const NR_sched_pdsch_t *sched_pdsch, + const NR_PDSCH_Config_t *pdsch_Config, + bool is_sib1, + int harq_round, + int rnti, + int beam_index, + int nl_tbslbrm, + int pdu_index) +{ + const NR_UE_DL_BWP_t *dl_bwp = UE ? &UE->current_DL_BWP : NULL; + const NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; + pdsch_pdu->pduBitmap = 0; + pdsch_pdu->rnti = rnti; + pdsch_pdu->pduIndex = pdu_index; + pdsch_pdu->BWPSize = sched_pdsch->bwp_info.bwpSize; + pdsch_pdu->BWPStart = sched_pdsch->bwp_info.bwpStart; + pdsch_pdu->SubcarrierSpacing = dl_bwp ? dl_bwp->scs : *scc->ssbSubcarrierSpacing; + pdsch_pdu->CyclicPrefix = dl_bwp && dl_bwp->cyclicprefix ? *dl_bwp->cyclicprefix : 0; + // Codeword information + pdsch_pdu->NrOfCodewords = 1; + pdsch_pdu->targetCodeRate[0] = sched_pdsch->R; + pdsch_pdu->qamModOrder[0] = sched_pdsch->Qm; + pdsch_pdu->mcsIndex[0] = sched_pdsch->mcs; + pdsch_pdu->mcsTable[0] = dl_bwp ? dl_bwp->mcsTableIdx : 0; + pdsch_pdu->rvIndex[0] = nr_get_rv(harq_round % 4); + pdsch_pdu->TBSize[0] = sched_pdsch->tb_size; + pdsch_pdu->dataScramblingId = pdsch_Config && pdsch_Config->dataScramblingIdentityPDSCH ? *pdsch_Config->dataScramblingIdentityPDSCH : *scc->physCellId; + pdsch_pdu->nrOfLayers = sched_pdsch->nrOfLayers; + pdsch_pdu->transmissionScheme = 0; + pdsch_pdu->refPoint = is_sib1; + // DMRS + const NR_pdsch_dmrs_t *dmrs_parms = &sched_pdsch->dmrs_parms; + pdsch_pdu->dlDmrsSymbPos = dmrs_parms->dl_dmrs_symb_pos; + pdsch_pdu->dmrsConfigType = dmrs_parms->dmrsConfigType; + pdsch_pdu->SCID = dmrs_parms->n_scid; + pdsch_pdu->dlDmrsScramblingId = dmrs_parms->scrambling_id; + pdsch_pdu->numDmrsCdmGrpsNoData = dmrs_parms->numDmrsCdmGrpsNoData; + pdsch_pdu->dmrsPorts = (1 << sched_pdsch->nrOfLayers) - 1; // FIXME with a better implementation + // Pdsch Allocation in frequency domain + pdsch_pdu->resourceAlloc = 1; + pdsch_pdu->rbStart = sched_pdsch->rbStart; + pdsch_pdu->rbSize = sched_pdsch->rbSize; + pdsch_pdu->VRBtoPRBMapping = 0; // non-interleaved + // Resource Allocation in time domain + const NR_tda_info_t *tda_info = &sched_pdsch->tda_info; + pdsch_pdu->StartSymbolIndex = tda_info->startSymbolIndex; + pdsch_pdu->NrOfSymbols = tda_info->nrOfSymbols; + /* Check and validate PTRS values */ + if (dmrs_parms->phaseTrackingRS) { + bool valid_ptrs_setup = set_dl_ptrs_values(dmrs_parms->phaseTrackingRS, + pdsch_pdu->rbSize, + pdsch_pdu->mcsIndex[0], + pdsch_pdu->mcsTable[0], + &pdsch_pdu->PTRSFreqDensity, + &pdsch_pdu->PTRSTimeDensity, + &pdsch_pdu->PTRSPortIndex, + &pdsch_pdu->nEpreRatioOfPDSCHToPTRS, + &pdsch_pdu->PTRSReOffset, + pdsch_pdu->NrOfSymbols); + if (valid_ptrs_setup) + pdsch_pdu->pduBitmap |= 0x1; // Bit 0: pdschPtrs - Indicates PTRS included (FR2) + } + int dl_bw_tbslbrm = UE ? UE->sc_info.dl_bw_tbslbrm : sched_pdsch->bwp_info.bwpSize; + pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(pdsch_pdu->mcsTable[0], dl_bw_tbslbrm, nl_tbslbrm); + pdsch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(sched_pdsch->tb_size << 3, sched_pdsch->R); + // Precoding and beamforming + pdsch_pdu->precodingAndBeamforming.num_prgs = 1; + pdsch_pdu->precodingAndBeamforming.prg_size = pdsch_pdu->rbSize; + pdsch_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; + pdsch_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = sched_pdsch->pm_index; + pdsch_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; + return pdsch_pdu; +} + void nr_schedule_ue_spec(module_id_t module_id, frame_t frame, slot_t slot, @@ -947,7 +1038,7 @@ void nr_schedule_ue_spec(module_id_t module_id, NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP; - if (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) + if (!nr_mac_ue_is_active(UE) && !get_softmodem_params()->phy_test) continue; NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; @@ -970,8 +1061,6 @@ void nr_schedule_ue_spec(module_id_t module_id, /* POST processing */ const uint8_t nrOfLayers = sched_pdsch->nrOfLayers; - const uint16_t R = sched_pdsch->R; - const uint8_t Qm = sched_pdsch->Qm; const uint32_t TBS = sched_pdsch->tb_size; int8_t current_harq_pid = sched_pdsch->dl_harq_pid; @@ -1055,160 +1144,62 @@ void nr_schedule_ue_spec(module_id_t module_id, nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu = &dl_req->dl_tti_pdu_list[dl_req->nPDUs]; memset(dl_tti_pdsch_pdu, 0, sizeof(nfapi_nr_dl_tti_request_pdu_t)); dl_tti_pdsch_pdu->PDUType = NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE; - dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdsch_pdu)); + dl_tti_pdsch_pdu->PDUSize = (uint8_t)(2 + sizeof(nfapi_nr_dl_tti_pdsch_pdu)); dl_req->nPDUs += 1; - nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; - pdsch_pdu->pduBitmap = 0; - pdsch_pdu->rnti = rnti; /* SCF222: PDU index incremented for each PDSCH PDU sent in TX control * message. This is used to associate control information to data and is * reset every slot. */ const int pduindex = gNB_mac->pdu_index[CC_id]++; - pdsch_pdu->pduIndex = pduindex; - - bwp_info_t bwp_info = get_pdsch_bwp_start_size(gNB_mac, UE); - pdsch_pdu->BWPSize = bwp_info.bwpSize; - pdsch_pdu->BWPStart = bwp_info.bwpStart; - - pdsch_pdu->SubcarrierSpacing = current_BWP->scs; - pdsch_pdu->CyclicPrefix = current_BWP->cyclicprefix ? *current_BWP->cyclicprefix : 0; - // Codeword information - pdsch_pdu->NrOfCodewords = 1; - //number of information bits per 1024 coded bits expressed in 0.1 bit units - pdsch_pdu->targetCodeRate[0] = R; - pdsch_pdu->qamModOrder[0] = Qm; - pdsch_pdu->mcsIndex[0] = sched_pdsch->mcs; - pdsch_pdu->mcsTable[0] = current_BWP->mcsTableIdx; - // NVIDIA: Workaround for MCSTableIdx mismatch error - if (nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx) != R) { - pdsch_pdu->mcsTable[0] = 0; - } - AssertFatal(harq->round < gNB_mac->dl_bler.harq_round_max,"%d", harq->round); - pdsch_pdu->rvIndex[0] = nr_get_rv(harq->round % 4); - pdsch_pdu->TBSize[0] = TBS; - pdsch_pdu->dataScramblingId = *scc->physCellId; - pdsch_pdu->nrOfLayers = nrOfLayers; - pdsch_pdu->transmissionScheme = 0; - pdsch_pdu->refPoint = 0; // Point A - // DMRS - pdsch_pdu->dlDmrsSymbPos = dmrs_parms->dl_dmrs_symb_pos; - pdsch_pdu->dmrsConfigType = dmrs_parms->dmrsConfigType; - pdsch_pdu->dlDmrsScramblingId = *scc->physCellId; - pdsch_pdu->SCID = 0; - pdsch_pdu->numDmrsCdmGrpsNoData = dmrs_parms->numDmrsCdmGrpsNoData; - pdsch_pdu->dmrsPorts = (1<resourceAlloc = 1; - pdsch_pdu->rbStart = sched_pdsch->rbStart; - pdsch_pdu->rbSize = sched_pdsch->rbSize; - pdsch_pdu->VRBtoPRBMapping = 1; // non-interleaved, check if this is ok for initialBWP - // Resource Allocation in time domain - pdsch_pdu->StartSymbolIndex = tda_info->startSymbolIndex; - pdsch_pdu->NrOfSymbols = tda_info->nrOfSymbols; - // Precoding - pdsch_pdu->precodingAndBeamforming.num_prgs = 0; - pdsch_pdu->precodingAndBeamforming.prg_size = pdsch_pdu->rbSize; - pdsch_pdu->precodingAndBeamforming.dig_bf_interfaces = 0; - pdsch_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = sched_pdsch->pm_index; - pdsch_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; - // TBS_LBRM according to section 5.4.2.1 of 38.212 // TODO: verify the case where maxMIMO_Layers is NULL, in which case // in principle maxMIMO_layers should be given by the maximum number of layers // for PDSCH supported by the UE for the serving cell (5.4.2.1 of 38.212) long maxMIMO_Layers = UE->sc_info.maxMIMO_Layers_PDSCH ? *UE->sc_info.maxMIMO_Layers_PDSCH : 1; const int nl_tbslbrm = min(maxMIMO_Layers, 4); - // Maximum number of PRBs across all configured DL BWPs - pdsch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = - nr_compute_tbslbrm(current_BWP->mcsTableIdx, UE->sc_info.dl_bw_tbslbrm, nl_tbslbrm); - pdsch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(TBS<<3,R); + nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = prepare_pdsch_pdu(dl_tti_pdsch_pdu, + gNB_mac, + UE, + sched_pdsch, + current_BWP->pdsch_Config, + false, + harq->round, + rnti, + UE->UE_beam_index, + nl_tbslbrm, + pduindex); - NR_PDSCH_Config_t *pdsch_Config = current_BWP->pdsch_Config; - - /* Check and validate PTRS values */ - struct NR_SetupRelease_PTRS_DownlinkConfig *phaseTrackingRS = - pdsch_Config ? pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->phaseTrackingRS : NULL; - - if (phaseTrackingRS) { - bool valid_ptrs_setup = set_dl_ptrs_values(phaseTrackingRS->choice.setup, - pdsch_pdu->rbSize, - pdsch_pdu->mcsIndex[0], - pdsch_pdu->mcsTable[0], - &pdsch_pdu->PTRSFreqDensity, - &pdsch_pdu->PTRSTimeDensity, - &pdsch_pdu->PTRSPortIndex, - &pdsch_pdu->nEpreRatioOfPDSCHToPTRS, - &pdsch_pdu->PTRSReOffset, - pdsch_pdu->NrOfSymbols); - - if (valid_ptrs_setup) - pdsch_pdu->pduBitmap |= 0x1; // Bit 0: pdschPtrs - Indicates PTRS included (FR2) - } LOG_D(NR_MAC,"Configuring DCI/PDCCH in %d.%d at CCE %d, rnti %x\n", frame,slot,sched_ctrl->cce_index,rnti); /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu->dci_pdu[pdcch_pdu->numDlDci]; + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu, + scc, + sched_ctrl->search_space, + sched_ctrl->coreset, + sched_ctrl->aggregation_level, + sched_ctrl->cce_index, + UE->UE_beam_index, + rnti); pdcch_pdu->numDlDci++; - dci_pdu->RNTI = rnti; - - if (sched_ctrl->coreset && - sched_ctrl->search_space && - sched_ctrl->coreset->pdcch_DMRS_ScramblingID && - sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { - dci_pdu->ScramblingId = *sched_ctrl->coreset->pdcch_DMRS_ScramblingID; - dci_pdu->ScramblingRNTI = rnti; - } else { - dci_pdu->ScramblingId = *scc->physCellId; - dci_pdu->ScramblingRNTI = 0; - } - - dci_pdu->AggregationLevel = sched_ctrl->aggregation_level; - dci_pdu->CceIndex = sched_ctrl->cce_index; - dci_pdu->beta_PDCCH_1_0 = 0; - dci_pdu->powerControlOffsetSS = 1; - - dci_pdu->precodingAndBeamforming.num_prgs = 0; - dci_pdu->precodingAndBeamforming.prg_size = 0; - dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 0; - dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; /* DCI payload */ - dci_pdu_rel15_t dci_payload; - memset(&dci_payload, 0, sizeof(dci_pdu_rel15_t)); - // bwp indicator - // as per table 7.3.1.1.2-1 in 38.212 - dci_payload.bwp_indicator.val = UE->sc_info.n_dl_bwp < 4 ? bwp_id : bwp_id - 1; + const int rnti_type = TYPE_C_RNTI_; + dci_pdu_rel15_t dci_payload = prepare_dci_dl_payload(gNB_mac, + UE, + rnti_type, + sched_ctrl->search_space->searchSpaceType->present, + pdsch_pdu, + sched_pdsch, + pucch, + current_harq_pid, + 0, + false); - AssertFatal(pdsch_Config == NULL || pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, - "Only frequency resource allocation type 1 is currently supported\n"); - - // 3GPP TS 38.214 Section 5.1.2.2.2 Downlink resource allocation type 1 - uint16_t riv_bwp_size = pdsch_pdu->BWPSize; - if (current_BWP->dci_format == NR_DL_DCI_FORMAT_1_0 - && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common) { - if (gNB_mac->cset0_bwp_size > 0) { - riv_bwp_size = gNB_mac->cset0_bwp_size; - } else { - riv_bwp_size = UE->sc_info.initial_dl_BWPSize; - } - } - dci_payload.frequency_domain_assignment.val = - PRBalloc_to_locationandbandwidth0(pdsch_pdu->rbSize, pdsch_pdu->rbStart, riv_bwp_size); - - dci_payload.format_indicator = 1; - dci_payload.time_domain_assignment.val = sched_pdsch->time_domain_allocation; - dci_payload.mcs = sched_pdsch->mcs; - dci_payload.rv = pdsch_pdu->rvIndex[0]; - dci_payload.harq_pid.val = current_harq_pid; - dci_payload.ndi = harq->ndi; - dci_payload.dai[0].val = pucch ? (pucch->dai_c-1)&3 : 0; - dci_payload.tpc = sched_ctrl->tpc1; // TPC for PUCCH: table 7.2.1-1 in 38.213 // Reset TPC to 0 dB to not request new gain multiple times before computing new value for SNR sched_ctrl->tpc1 = 1; - dci_payload.pucch_resource_indicator = pucch ? pucch->resource_indicator : 0; - dci_payload.pdsch_to_harq_feedback_timing_indicator.val = pucch ? pucch->timing_indicator : 0; // PDSCH to HARQ TI - dci_payload.antenna_ports.val = dmrs_parms->dmrs_ports_id; - dci_payload.dmrs_sequence_initialization.val = pdsch_pdu->SCID; + NR_PDSCH_Config_t *pdsch_Config = current_BWP->pdsch_Config; + AssertFatal(pdsch_Config == NULL + || pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1, + "Only frequency resource allocation type 1 is currently supported\n"); + LOG_D(NR_MAC, "%4d.%2d DCI type 1 payload: freq_alloc %d (%d,%d,%d), " "nrOfLayers %d, time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d tpc %d ti %d\n", @@ -1228,7 +1219,6 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_payload.tpc, pucch ? pucch->timing_indicator : 0); - const int rnti_type = TYPE_C_RNTI_; fill_dci_pdu_rel15(&UE->sc_info, current_BWP, &UE->current_UL_BWP, @@ -1260,10 +1250,16 @@ void nr_schedule_ue_spec(module_id_t module_id, current_harq_pid, harq->round, harq->ndi); - AssertFatal(harq->sched_pdsch.tb_size == TBS, - "UE %04x mismatch between scheduled TBS and buffered TB for HARQ PID %d\n", - UE->rnti, - current_harq_pid); + if (!get_softmodem_params()->phy_test) + AssertFatal(harq->sched_pdsch.tb_size == TBS, + "UE %04x mismatch between scheduled TBS and buffered TB for HARQ PID %d\n", + UE->rnti, + current_harq_pid); + else if (harq->sched_pdsch.tb_size != TBS) + LOG_E(NR_MAC, + "Mismatch between scheduled TBS and buffered TB for HARQ PID %d. No RTX control in phy-test mode. " + "Possible causes: presence of CSI-RS or DLSCH scheduled in the mixed slot.\n", + current_harq_pid); T(T_GNB_MAC_RETRANSMISSION_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->transportBlock.buf, TBS)); UE->mac_stats.dl.total_rbs_retx += sched_pdsch->rbSize; @@ -1324,6 +1320,7 @@ void nr_schedule_ue_spec(module_id_t module_id, if (len == 0) break; + T(T_GNB_MAC_LCID_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(lcid), T_INT(len * 8), T_INT(nr_rlc_tx_list_occupancy(rnti, lcid))); header->R = 0; header->F = 1; header->LCID = lcid; @@ -1398,6 +1395,7 @@ void nr_schedule_ue_spec(module_id_t module_id, T(T_GNB_MAC_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_BUFFER(harq->transportBlock.buf, TBS)); + T(T_GNB_MAC_DL, T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(sched_pdsch->mcs), T_INT(TBS)); } const int ntx_req = TX_req->Number_of_PDUs; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index bc7b40937f..5ec7bf781d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -139,7 +139,6 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot) sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, - false, 0); AssertFatal(CCEIndex >= 0, "Could not find CCE for UE %04x\n", UE->rnti); @@ -173,7 +172,7 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot) sched_pdsch->pucch_allocation = alloc; sched_pdsch->rbStart = rbStart; sched_pdsch->rbSize = rbSize; - + sched_pdsch->bwp_info = get_pdsch_bwp_start_size(mac, UE); sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, &tda_info, @@ -208,9 +207,11 @@ uint32_t target_ul_mcs = 9; uint32_t target_ul_bw = 50; uint32_t target_ul_Nl = 1; uint64_t ulsch_slot_bitmap = (1 << 8); -bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot) +void nr_ul_preprocessor_phytest(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch) { - gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; + int frame = pp_pusch->frame; + int slot = pp_pusch->slot; + /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ NR_COMMON_channels_t *cc = nr_mac->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; @@ -219,7 +220,7 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slo AssertFatal(nr_mac->UE_info.connected_ue_list[1] == NULL, "cannot handle more than one UE\n"); if (UE == NULL) - return false; + return; const int CC_id = 0; @@ -229,72 +230,54 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slo /* return if all UL HARQ processes wait for feedback */ if (sched_ctrl->retrans_ul_harq.head == -1 && sched_ctrl->available_ul_harq.head == -1) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UE has no free UL HARQ process, skipping\n", UE->rnti, frame, slot); - return false; + return; } - NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = get_ul_tdalist(ul_bwp, - sched_ctrl->coreset->controlResourceSetId, - sched_ctrl->search_space->searchSpaceType->present, - TYPE_C_RNTI_); - const int temp_tda = get_ul_tda(nr_mac, frame, slot); - if (temp_tda < 0) - return false; - AssertFatal(temp_tda < tdaList->list.count, "time domain assignment %d >= %d\n", temp_tda, tdaList->list.count); - const int mu = ul_bwp->scs; - int K2 = get_K2(tdaList, temp_tda, mu, scc); - int slots_frame = nr_mac->frame_structure.numb_slots_frame; - const int sched_frame = (frame + (slot + K2) / slots_frame) % MAX_FRAME_NUMBER; - const int sched_slot = (slot + K2) % slots_frame; - const int tda = get_ul_tda(nr_mac, sched_frame, sched_slot); - if (tda < 0) - return false; - AssertFatal(tda < tdaList->list.count, - "time domain assignment %d >= %d\n", - tda, - tdaList->list.count); - /* check if slot is UL, and that slot is 8 (assuming K2=6 because of UE - * limitations). Note that if K2 or the TDD configuration is changed, below - * conditions might exclude each other and never be true */ - int slot_period = sched_slot % nr_mac->frame_structure.numb_slots_period; - if (!is_xlsch_in_slot(ulsch_slot_bitmap, slot_period)) - return false; - - uint16_t rbStart = 0; - uint16_t rbSize; - const int bw = ul_bwp->BWPSize; const int BWPStart = ul_bwp->BWPStart; + uint16_t rbStart = 0; + uint16_t rbSize = min(bw, target_ul_bw); - if (target_ul_bw>bw) - rbSize = bw; - else - rbSize = target_ul_bw; - + DevAssert(seq_arr_size(&nr_mac->ul_tda) > 0); + const int tda = 0; NR_tda_info_t tda_info = get_ul_tda_info(ul_bwp, sched_ctrl->coreset->controlResourceSetId, sched_ctrl->search_space->searchSpaceType->present, TYPE_C_RNTI_, tda); - if (!tda_info.valid_tda) - return false; - sched_ctrl->sched_pusch.tda_info = tda_info; - sched_ctrl->sched_pusch.time_domain_allocation = tda; + DevAssert(tda_info.valid_tda); + + int K2 = tda_info.k2 + get_NTN_Koffset(scc); + int slots_frame = nr_mac->frame_structure.numb_slots_frame; + const int sched_frame = (frame + (slot + K2) / slots_frame) % MAX_FRAME_NUMBER; + const int sched_slot = (slot + K2) % slots_frame; + + /* check if slot is UL, and that slot is 8 (assuming K2=6 because of UE + * limitations). Note that if K2 or the TDD configuration is changed, below + * conditions might exclude each other and never be true */ + int slot_period = sched_slot % nr_mac->frame_structure.numb_slots_period; + if (!is_xlsch_in_slot(ulsch_slot_bitmap, slot_period)) + return; // TODO implement beam procedures for phy-test mode int beam = 0; + const NR_tda_info_t *tda_p; + const int n_tda = get_num_ul_tda(nr_mac, sched_slot, tda_info.k2, &tda_p); + DevAssert(n_tda > 0); + /* check only the first TDA: we are only interested in finding out if this TDA fits completely */ + int rb_s = rbStart, rb_l = rbSize; + get_best_ul_tda(nr_mac, beam, tda_p, 1, sched_frame, sched_slot, &rb_s, &rb_l); + DevAssert(rb_s == rbStart && rb_l == rbSize); const int buffer_index = ul_buffer_index(sched_frame, sched_slot, slots_frame, nr_mac->vrb_map_UL_size); uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[beam][buffer_index * MAX_BWP_SIZE]; for (int i = rbStart; i < rbStart + rbSize; ++i) { if ((vrb_map_UL[i+BWPStart] & SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols)) != 0) { LOG_E(MAC, "%4d.%2d RB %d is already reserved, cannot schedule UE\n", frame, slot, i); - return false; + return; } } - sched_ctrl->sched_pusch.slot = sched_slot; - sched_ctrl->sched_pusch.frame = sched_frame; - int CCEIndex = get_cce_index(nr_mac, CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, @@ -302,49 +285,53 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slo sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, - false, 0); if (CCEIndex < 0) { LOG_E(MAC, "%s(): CCE list not empty, couldn't schedule PUSCH\n", __func__); - return false; + return; } sched_ctrl->cce_index = CCEIndex; - const int mcs = target_ul_mcs; - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; - sched_pusch->mcs = mcs; - sched_ctrl->ul_bler_stats.mcs = mcs; /* for logging output */ - sched_pusch->rbStart = rbStart; - sched_pusch->rbSize = rbSize; - /* get the PID of a HARQ process awaiting retransmission, or -1 for "any new" */ - sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; + NR_sched_pusch_t sched = { + .frame = sched_frame, + .slot = sched_slot, + .rbSize = rbSize, + .rbStart = rbStart, + .mcs = target_ul_mcs, + // R, Qm, tb_size set further below + // PID of a HARQ process awaiting retransmission, or -1 for "any new" + .ul_harq_pid = sched_ctrl->retrans_ul_harq.head, + .nrOfLayers = target_ul_Nl, + // tpmi in post-process + .time_domain_allocation = tda, + .tda_info = tda_info, + .dmrs_info = get_ul_dmrs_params(scc, ul_bwp, &tda_info, target_ul_Nl), + .bwp_info = get_pusch_bwp_start_size(UE), + }; + sched_ctrl->ul_bler_stats.mcs = sched.mcs; /* for logging output */ /* Calculate TBS from MCS */ - sched_pusch->nrOfLayers = target_ul_Nl; - sched_pusch->R = nr_get_code_rate_ul(mcs, ul_bwp->mcs_table); - sched_pusch->Qm = nr_get_Qm_ul(mcs, ul_bwp->mcs_table); + sched.R = nr_get_code_rate_ul(sched.mcs, ul_bwp->mcs_table); + sched.Qm = nr_get_Qm_ul(sched.mcs, ul_bwp->mcs_table); if (ul_bwp->pusch_Config->tp_pi2BPSK - && ((ul_bwp->mcs_table == 3 && mcs < 2) || (ul_bwp->mcs_table == 4 && mcs < 6))) { - sched_pusch->R >>= 1; - sched_pusch->Qm <<= 1; + && ((ul_bwp->mcs_table == 3 && sched.mcs < 2) || (ul_bwp->mcs_table == 4 && sched.mcs < 6))) { + sched.R >>= 1; + sched.Qm <<= 1; } - NR_pusch_dmrs_t dmrs = get_ul_dmrs_params(scc, - ul_bwp, - &tda_info, - sched_pusch->nrOfLayers); - sched_ctrl->sched_pusch.dmrs_info = dmrs; + sched.tb_size = nr_compute_tbs(sched.Qm, + sched.R, + sched.rbSize, + tda_info.nrOfSymbols, + sched.dmrs_info.N_PRB_DMRS * sched.dmrs_info.num_dmrs_symb, + 0, // nb_rb_oh + 0, + sched.nrOfLayers /* NrOfLayers */) + >> 3; - sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm, - sched_pusch->R, - sched_pusch->rbSize, - tda_info.nrOfSymbols, - dmrs.N_PRB_DMRS * dmrs.num_dmrs_symb, - 0, // nb_rb_oh - 0, - sched_pusch->nrOfLayers /* NrOfLayers */) - >> 3; + /* save allocation to FAPI structures */ + post_process_ulsch(nr_mac, pp_pusch, UE, &sched); /* mark the corresponding RBs as used */ fill_pdcch_vrb_map(nr_mac, @@ -356,5 +343,4 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slo for (int rb = rbStart; rb < rbStart + rbSize; rb++) vrb_map_UL[rb+BWPStart] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); - return true; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index a447d9f91c..4e55941420 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -248,6 +248,38 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac, } } +// look-up table for AMC. Based on BLER vs SNR curves from the nr_dlsim simulation +// command line: nr_dlsim -n 10000 -m 0 -R 25 -b 25 -e MCS -s START_SNR -t 99.99 +// SNR Thresholds for MCS=[0,...,28]; START_SNR=chosen values with a resolution of 0.2dB to maintain a BLER of 10^-3 +static const int SINRx10_MCS_mapping[29] = { + -10, -4, 6, 16, 24, 34, 42, 50, 56, 62, // 0..9 + 86, 92, 98, 104, 112, 118, 124, 140, 146, 154, // 10..19 + 162, 170, 178, 186, 194, 202, 212, 220, 245 // 20..28 +}; + +int get_mcs_from_SINRx10(int mcs_table, int SINRx10, int Nl) +{ + if (mcs_table != 0) { + LOG_E(MAC, "mcs_table = %d, but get_mcs_from_SINRx10() only supports MCS table 0 (TS 38.214 - Table 5.1.3.1-1)\n", mcs_table); + return 28; + } + + int MIMO_SNRx10 = 0; + if (Nl == 2) + MIMO_SNRx10 = 40; + else if (Nl == 4) + MIMO_SNRx10 = 70; + + for (int i = 28; i >= 0; i--) { + if (SINRx10 >= SINRx10_MCS_mapping[i] + MIMO_SNRx10) + return i; + } + + LOG_W(MAC, "SINR (%d.%d dB) too low, no MCS possible to achieve BLER of 10^-3\n", SINRx10 / 10, SINRx10 % 10); + + return 0; +} + uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx) { if (cqi_idx <= 0) { @@ -300,8 +332,7 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc, if (dci_format == NR_DL_DCI_FORMAT_1_0) { dmrs.numDmrsCdmGrpsNoData = tda_info->nrOfSymbols <= 2 ? 1 : 2; dmrs.dmrs_ports_id = 0; - } - else { + } else { //TODO first basic implementation of dmrs port selection // only vaild for a single codeword // for now it assumes a selection of Nl consecutive dmrs ports @@ -312,23 +343,13 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc, switch (Layers) { case 1: -#ifdef ENABLE_AERIAL - dmrs.dmrs_ports_id = 3; - dmrs.numDmrsCdmGrpsNoData = 2; -#else dmrs.dmrs_ports_id = 0; dmrs.numDmrsCdmGrpsNoData = 1; -#endif frontloaded_symb = 1; break; case 2: -#ifdef ENABLE_AERIAL - dmrs.dmrs_ports_id = 7; - dmrs.numDmrsCdmGrpsNoData = 2; -#else dmrs.dmrs_ports_id = 2; dmrs.numDmrsCdmGrpsNoData = 1; -#endif frontloaded_symb = 1; break; case 3: @@ -346,16 +367,21 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc, } } + dmrs.n_scid = 0; + long *scramblingID = NULL; NR_PDSCH_Config_t *pdsch_Config = dl_bwp ? dl_bwp->pdsch_Config : NULL; if (pdsch_Config) { - if (tda_info->mapping_type == typeB) - dmrs.dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup->dmrs_Type != NULL; - else - dmrs.dmrsConfigType = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup->dmrs_Type != NULL; - } - else + NR_DMRS_DownlinkConfig_t *dmrs_Config = tda_info->mapping_type == typeB ? + pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup : + pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup; + dmrs.phaseTrackingRS = dmrs_Config->phaseTrackingRS ? dmrs_Config->phaseTrackingRS->choice.setup : NULL; + dmrs.dmrsConfigType = dmrs_Config->dmrs_Type != NULL; + scramblingID = dmrs.n_scid ? dmrs_Config->scramblingID1 : dmrs_Config->scramblingID0; + } else { dmrs.dmrsConfigType = NFAPI_NR_DMRS_TYPE1; - + dmrs.phaseTrackingRS = NULL; + } + dmrs.scrambling_id = scramblingID ? *scramblingID : *scc->physCellId; dmrs.N_PRB_DMRS = dmrs.numDmrsCdmGrpsNoData * (dmrs.dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4); dmrs.dl_dmrs_symb_pos = fill_dmrs_mask(pdsch_Config, dci_format, scc->dmrs_TypeA_Position, tda_info->nrOfSymbols, tda_info->startSymbolIndex, tda_info->mapping_type, frontloaded_symb); dmrs.N_DMRS_SLOT = get_num_dmrs(dmrs.dl_dmrs_symb_pos); @@ -365,64 +391,80 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc, NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, - void *bwp, - NR_SearchSpace_t *ss, - NR_SearchSpace__searchSpaceType_PR ss_type) { - - NR_ControlResourceSetId_t coreset_id = *ss->controlResourceSetId; - - if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) { // common search space - NR_ControlResourceSet_t *coreset; - if(coreset_id == 0) { - coreset = nrmac->sched_ctrlCommon->coreset; // this is coreset 0 - } else if (bwp) { - coreset = ((NR_BWP_Downlink_t*)bwp)->bwp_Common->pdcch_ConfigCommon->choice.setup->commonControlResourceSet; - } else if (scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet) { - coreset = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet; - } else { - coreset = NULL; - } - - if (coreset) AssertFatal(coreset_id == coreset->controlResourceSetId, - "ID of common ss coreset does not correspond to id set in the " - "search space\n"); - return coreset; - } else { - const int n = ((NR_BWP_DownlinkDedicated_t*)bwp)->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.count; + NR_BWP_DownlinkDedicated_t *bwp_dedicated, + NR_ControlResourceSetId_t coreset_id) +{ + if (coreset_id == 0) { + return nrmac->sched_ctrlCommon->coreset; // this is coreset 0 + } + if (bwp_dedicated) { + const int n = bwp_dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.count; for (int i = 0; i < n; i++) { - NR_ControlResourceSet_t *coreset = - ((NR_BWP_DownlinkDedicated_t*)bwp)->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[i]; - if (coreset_id == coreset->controlResourceSetId) { + NR_ControlResourceSet_t *coreset = bwp_dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list.array[i]; + if (coreset->controlResourceSetId == coreset_id) { return coreset; } } - AssertFatal(0, "Couldn't find coreset with id %ld\n", coreset_id); + AssertFatal(false, "Couldn't find CORESET with id %ld in BWP_DownlinkDedicated\n", coreset_id); } + if (scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet) { + NR_ControlResourceSet_t *coreset = + scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonControlResourceSet; + if (coreset->controlResourceSetId == coreset_id) { + return coreset; + } + AssertFatal(false, "Couldn't find CORESET with id %ld in commonControlResourceSet\n", coreset_id); + } + AssertFatal(false, "Couldn't find coreset with id %ld\n", coreset_id); } static NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc, - NR_BWP_DownlinkDedicated_t *bwp_Dedicated, + NR_BWP_DownlinkDedicated_t *bwp_dedicated, NR_SearchSpace__searchSpaceType_PR target_ss) { - int n = 0; - if(bwp_Dedicated) - n = bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count; - else - n = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.count; + if (bwp_dedicated) { + const int n = bwp_dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count; + for (int i = 0; i < n; i++) { + NR_SearchSpace_t *ss = bwp_dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i]; + if (ss->searchSpaceType->present == target_ss) { + AssertFatal(ss->controlResourceSetId, "searchSpaceId %ld has a NULL controlResourceSetId\n", ss->searchSpaceId); + return ss; + } + } + AssertFatal(false, "Couldn't find an adequate SearchSpace for target SearchSpace %d in BWP_DownlinkDedicated\n", target_ss); + } - for (int i=0;ipdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i]; - else - ss = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.array[i]; - AssertFatal(ss->controlResourceSetId != NULL, "ss->controlResourceSetId is null\n"); - AssertFatal(ss->searchSpaceType != NULL, "ss->searchSpaceType is null\n"); + const int n = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.count; + for (int i = 0; i < n; i++) { + NR_SearchSpace_t *ss = + scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list.array[i]; if (ss->searchSpaceType->present == target_ss) { + AssertFatal(ss->controlResourceSetId, "searchSpaceId %ld has a NULL controlResourceSetId\n", ss->searchSpaceId); return ss; } } - AssertFatal(0, "Couldn't find an adequate searchspace bwp_Dedicated %p\n",bwp_Dedicated); + AssertFatal(false, "Couldn't find an adequate SearchSpace for target SearchSpace %d in ServingCellConfigCommon\n", target_ss); +} + +/// @brief Get CORESET resource block parameters from frequency domain resources bitmap. +/// @param coreset Pointer to the CORESET configuratio +/// @param n_rb Output parameter for total # of RBs in the CORESET +/// @param rb_start Output parameter for the starting resource block index of the CORESET +static void get_coreset_rb_params(const NR_ControlResourceSet_t *coreset, uint16_t *n_rb, uint16_t *rb_start) +{ + *n_rb = 0; + *rb_start = 0; + + for (int i = 0; i < 6; i++) { + for (int t = 0; t < 8; t++) { + if ((coreset->frequencyDomainResources.buf[i] >> (7 - t)) & 1) { + if (*n_rb == 0) { + *rb_start = 48 * i + t * 6; + } + *n_rb += 6; // Each bit represents 6 RBs + } + } + } } NR_sched_pdcch_t set_pdcch_structure(gNB_MAC_INST *gNB_mac, @@ -430,32 +472,28 @@ NR_sched_pdcch_t set_pdcch_structure(gNB_MAC_INST *gNB_mac, NR_ControlResourceSet_t *coreset, NR_ServingCellConfigCommon_t *scc, NR_BWP_t *bwp, - NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) { - - int sps; - NR_sched_pdcch_t pdcch; - + NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config) +{ AssertFatal(*ss->controlResourceSetId == coreset->controlResourceSetId, "coreset id in SS %ld does not correspond to the one in coreset %ld", *ss->controlResourceSetId, coreset->controlResourceSetId); + int sps; + NR_sched_pdcch_t pdcch; if (bwp) { // This is not for SIB1 - if(coreset->controlResourceSetId == 0){ - pdcch.BWPSize = gNB_mac->cset0_bwp_size; + if(coreset->controlResourceSetId == 0) { + pdcch.BWPSize = gNB_mac->cset0_bwp_size; pdcch.BWPStart = gNB_mac->cset0_bwp_start; - } - else { - pdcch.BWPSize = NRRIV2BW(bwp->locationAndBandwidth, MAX_BWP_SIZE); + } else { + pdcch.BWPSize = NRRIV2BW(bwp->locationAndBandwidth, MAX_BWP_SIZE); pdcch.BWPStart = NRRIV2PRBOFFSET(bwp->locationAndBandwidth, MAX_BWP_SIZE); } pdcch.SubcarrierSpacing = bwp->subcarrierSpacing; - pdcch.CyclicPrefix = (bwp->cyclicPrefix==NULL) ? 0 : *bwp->cyclicPrefix; - + pdcch.CyclicPrefix = (bwp->cyclicPrefix == NULL) ? 0 : *bwp->cyclicPrefix; //AssertFatal(pdcch_scs==kHz15, "PDCCH SCS above 15kHz not allowed if a symbol above 2 is monitored"); sps = bwp->cyclicPrefix == NULL ? 14 : 12; - } - else { - AssertFatal(type0_PDCCH_CSS_config!=NULL,"type0_PDCCH_CSS_config is null,bwp %p\n",bwp); + } else { + AssertFatal(type0_PDCCH_CSS_config != NULL, "type0_PDCCH_CSS_config is null,bwp %p\n", bwp); pdcch.BWPSize = type0_PDCCH_CSS_config->num_rbs; pdcch.BWPStart = type0_PDCCH_CSS_config->cset_start_rb; pdcch.SubcarrierSpacing = type0_PDCCH_CSS_config->scs_pdcch; @@ -463,16 +501,16 @@ NR_sched_pdcch_t set_pdcch_structure(gNB_MAC_INST *gNB_mac, sps = 14; } - AssertFatal(ss->monitoringSymbolsWithinSlot!=NULL,"ss->monitoringSymbolsWithinSlot is null\n"); - AssertFatal(ss->monitoringSymbolsWithinSlot->buf!=NULL,"ss->monitoringSymbolsWithinSlot->buf is null\n"); + AssertFatal(ss->monitoringSymbolsWithinSlot != NULL, "ss->monitoringSymbolsWithinSlot is null\n"); + BIT_STRING_t *symbolsInSlot = ss->monitoringSymbolsWithinSlot; + AssertFatal(symbolsInSlot->buf != NULL, "ss->monitoringSymbolsWithinSlot->buf is null\n"); // for SPS=14 8 MSBs in positions 13 downto 6 - uint16_t monitoringSymbolsWithinSlot = (ss->monitoringSymbolsWithinSlot->buf[0]<<(sps-8)) | - (ss->monitoringSymbolsWithinSlot->buf[1]>>(16-sps)); + int monitoringSymbolsWithinSlot = (symbolsInSlot->buf[0] << (sps - 8)) | (symbolsInSlot->buf[1] >> (16 - sps)); - for (int i=0; i>(sps-1-i))&1) { - pdcch.StartSymbolIndex=i; + for (int i = 0; i < sps; i++) { + if ((monitoringSymbolsWithinSlot >> (sps - 1 - i)) & 1) { + pdcch.StartSymbolIndex = ss->searchSpaceId == 0 ? i + type0_PDCCH_CSS_config->first_symbol_index : i; break; } } @@ -497,21 +535,7 @@ NR_sched_pdcch_t set_pdcch_structure(gNB_MAC_INST *gNB_mac, pdcch.ShiftIndex = 0; } - uint16_t N_rb = 0; // nb of rbs of coreset per symbol - uint16_t rb_start = 0; - for (int i = 0; i < 6; i++) { - for (int t = 0; t < 8; t++) { - if (coreset->frequencyDomainResources.buf[i] >> (7 - t) & 1) { - if (N_rb == 0) { - rb_start = 48 * i + t * 6; - } - N_rb++; - } - } - } - - pdcch.rb_start = rb_start; - pdcch.n_rb = N_rb *= 6; // each bit of frequencyDomainResources represents 6 PRBs + get_coreset_rb_params(coreset, &pdcch.n_rb, &pdcch.rb_start); return pdcch; } @@ -570,10 +594,9 @@ int get_cce_index(const gNB_MAC_INST *nrmac, const NR_SearchSpace_t *ss, const NR_ControlResourceSet_t *coreset, NR_sched_pdcch_t *sched_pdcch, - bool is_common, float pdcch_cl_adjust) { - const uint32_t Y = is_common ? 0 : get_Y(ss, slot, rnti); + const uint32_t Y = get_Y(ss, slot, rnti); uint8_t nr_of_candidates; int agg_level_search_order[NUM_PDCCH_AGG_LEVELS]; @@ -640,8 +663,7 @@ bool nr_find_nb_rb(uint16_t Qm, uint16_t *nb_rb) { // for transform precoding only RB = 2^a_2 * 3^a_3 * 5^a_5 is allowed with a non-negative - while(transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled && - !multiple_2_3_5(nb_rb_max)) + while (transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled && !multiple_2_3_5(nb_rb_max)) nb_rb_max--; /* is the maximum (not even) enough? */ @@ -702,26 +724,44 @@ const NR_DMRS_UplinkConfig_t *get_DMRS_UplinkConfig(const NR_PUSCH_Config_t *pus NR_pusch_dmrs_t get_ul_dmrs_params(const NR_ServingCellConfigCommon_t *scc, const NR_UE_UL_BWP_t *ul_bwp, const NR_tda_info_t *tda_info, - const int Layers) { - + const int Layers) +{ NR_pusch_dmrs_t dmrs = {0}; - // TODO setting of cdm groups with no data to be redone for MIMO - if(NFAPI_MODE == NFAPI_MODE_AERIAL) { + if (ul_bwp->transform_precoding && Layers < 3) + dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols <= 2 ? 1 : 2; + else dmrs.num_dmrs_cdm_grps_no_data = 2; + + const NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = get_DMRS_UplinkConfig(ul_bwp->pusch_Config, tda_info); + dmrs.ptrsConfig = NR_DMRS_UplinkConfig + && NR_DMRS_UplinkConfig->phaseTrackingRS ? + NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup : NULL; + + dmrs.pusch_identity = *scc->physCellId; + dmrs.dmrs_scrambling_id = *scc->physCellId; + dmrs.scid = 0; + if (ul_bwp->transform_precoding) { // transform precoding disabled + long *scramblingid = NULL; + if (NR_DMRS_UplinkConfig && dmrs.scid == 0) + scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0; + else if (NR_DMRS_UplinkConfig) + scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1; + if (scramblingid) + dmrs.dmrs_scrambling_id = *scramblingid; } else { - if (ul_bwp->transform_precoding && Layers < 3) - dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols <= 2 ? 1 : 2; - else - dmrs.num_dmrs_cdm_grps_no_data = 2; + if (NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->transformPrecodingEnabled) { + if (NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity) + dmrs.pusch_identity = *NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity; + if ((!NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceGroupHopping + && !NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceHopping) + && !scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->groupHoppingEnabledTransformPrecoding) + dmrs.low_papr_sequence_number = 0; + else + AssertFatal(false, "Hopping mode is not supported in transform precoding\n"); + } } - NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = ul_bwp->pusch_Config ? - (tda_info->mapping_type == typeA ? - ul_bwp->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup : - ul_bwp->pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup) : NULL; - dmrs.dmrs_config_type = NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->dmrs_Type ? 1 : 0; - const pusch_dmrs_AdditionalPosition_t additional_pos = (NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->dmrs_AdditionalPosition) ? (*NR_DMRS_UplinkConfig->dmrs_AdditionalPosition == NR_DMRS_UplinkConfig__dmrs_AdditionalPosition_pos3 ? @@ -735,10 +775,7 @@ NR_pusch_dmrs_t get_ul_dmrs_params(const NR_ServingCellConfigCommon_t *scc, tda_info->startSymbolIndex, scc->dmrs_TypeA_Position); - uint8_t num_dmrs_symb = 0; - for(int i = tda_info->startSymbolIndex; i < tda_info->startSymbolIndex + tda_info->nrOfSymbols; i++) - num_dmrs_symb += (dmrs.ul_dmrs_symb_pos >> i) & 1; - dmrs.num_dmrs_symb = num_dmrs_symb; + dmrs.num_dmrs_symb = count_bits64_with_mask(dmrs.ul_dmrs_symb_pos, tda_info->startSymbolIndex, tda_info->nrOfSymbols); dmrs.N_PRB_DMRS = dmrs.num_dmrs_cdm_grps_no_data * (dmrs.dmrs_config_type == 0 ? 6 : 4); return dmrs; } @@ -782,6 +819,356 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, return new_mcs; } +nfapi_nr_dl_dci_pdu_t *prepare_dci_pdu(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, + const NR_ServingCellConfigCommon_t *scc, + const NR_SearchSpace_t *ss, + const NR_ControlResourceSet_t *coreset, + int aggregation_level, + int cce_index, + int beam_index, + int rnti) +{ + nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu->dci_pdu[pdcch_pdu->numDlDci]; + dci_pdu->RNTI = rnti; + dci_pdu->AggregationLevel = aggregation_level; + dci_pdu->CceIndex = cce_index; + if (coreset->pdcch_DMRS_ScramblingID && + ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { + dci_pdu->ScramblingId = *coreset->pdcch_DMRS_ScramblingID; + dci_pdu->ScramblingRNTI = rnti; + } else { + dci_pdu->ScramblingId = *scc->physCellId; + dci_pdu->ScramblingRNTI = 0; + } + + uint16_t N_rb = 0; + uint16_t rb_start = 0; + get_coreset_rb_params(coreset, &N_rb, &rb_start); + + dci_pdu->beta_PDCCH_1_0 = 0; + dci_pdu->powerControlOffsetSS = 1; + dci_pdu->precodingAndBeamforming.num_prgs = 1; + dci_pdu->precodingAndBeamforming.prg_size = N_rb; + dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; + dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; + dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; + return dci_pdu; +} + +dci_pdu_rel15_t prepare_dci_dl_payload(const gNB_MAC_INST *gNB_mac, + const NR_UE_info_t *UE, + nr_rnti_type_t rnti_type, + NR_SearchSpace__searchSpaceType_PR ss_type, + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu, + const NR_sched_pdsch_t *sched_pdsch, + const NR_sched_pucch_t *pucch, + int harq_pid, + int tb_scaling, + bool is_sib1) +{ + const NR_UE_DL_BWP_t *dl_BWP = UE ? &UE->current_DL_BWP : NULL; + dci_pdu_rel15_t dci_payload = {0}; + dci_payload.format_indicator = 1; + dci_payload.time_domain_assignment.val = sched_pdsch->time_domain_allocation; + dci_payload.mcs = sched_pdsch->mcs; + dci_payload.rv = pdsch_pdu->rvIndex[0]; + dci_payload.vrb_to_prb_mapping.val = 0; + int riv_bwp = pdsch_pdu->BWPSize; + if (!UE) + riv_bwp = gNB_mac->cset0_bwp_size; + else if (dl_BWP->dci_format == NR_DL_DCI_FORMAT_1_0 && ss_type == NR_SearchSpace__searchSpaceType_PR_common) { + if (gNB_mac->cset0_bwp_size > 0) + riv_bwp = gNB_mac->cset0_bwp_size; + else + riv_bwp = UE->sc_info.initial_dl_BWPSize; + } + dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu->rbSize, pdsch_pdu->rbStart, riv_bwp); + if (rnti_type == TYPE_SI_RNTI_) { + dci_payload.system_info_indicator = !is_sib1; + return dci_payload; + } + if (rnti_type == TYPE_RA_RNTI_) { + dci_payload.tb_scaling = tb_scaling; + return dci_payload; + } + + const NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + dci_payload.dmrs_sequence_initialization.val = pdsch_pdu->SCID; + dci_payload.antenna_ports.val = sched_pdsch->dmrs_parms.dmrs_ports_id; + dci_payload.tpc = sched_ctrl->tpc1; + const NR_UE_harq_t *harq = &sched_ctrl->harq_processes[harq_pid]; + AssertFatal(harq, "HARQ process should be available for DCI with RNTI %s\n", rnti_types(rnti_type)); + dci_payload.harq_pid.val = harq_pid; + dci_payload.ndi = harq->ndi; + dci_payload.pucch_resource_indicator = pucch ? pucch->resource_indicator : 0; + dci_payload.pdsch_to_harq_feedback_timing_indicator.val = pucch ? pucch->timing_indicator : 0; // PDSCH to HARQ TI + dci_payload.dai[0].val = pucch ? (pucch->dai_c - 1) & 3 : 0; + // bwp indicator + // as per table 7.3.1.1.2-1 in 38.212 + if (dl_BWP) + dci_payload.bwp_indicator.val = UE->sc_info.n_dl_bwp < 4 ? dl_BWP->bwp_id : dl_BWP->bwp_id - 1; + return dci_payload; +} + +static uint32_t compute_srs_resource_indicator(long *maxMIMO_Layers, + NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + nr_srs_feedback_t *srs_feedback) +{ + uint32_t val = 0; + if (srs_config && pusch_Config && pusch_Config->txConfig != NULL) { + if (*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook) { + + // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(N_SRS)) bits according to + // Tables 7.3.1.1.2-32, 7.3.1.1.2-32A and 7.3.1.1.2-32B if the higher layer parameter txConfig = codebook, + // where N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer + // parameter srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value codeBook. + int count = srs_codebook_nb_res(srs_config); + if (count > 1) + val = table_7_3_1_1_2_32[count - 2][srs_feedback->sri]; + } else { + // TS 38.212 - Section 7.3.1.1.2: SRS resource indicator has ceil(log2(sum(k = 1 until min(Lmax,N_SRS) of binomial(N_SRS,k)))) + // bits according to Tables 7.3.1.1.2-28/29/30/31 if the higher layer parameter txConfig = nonCodebook, where + // N_SRS is the number of configured SRS resources in the SRS resource set configured by higher layer parameter + // srs-ResourceSetToAddModList, and associated with the higher layer parameter usage of value nonCodeBook and: + // + // - if UE supports operation with maxMIMO-Layers and the higher layer parameter maxMIMO-Layers of + // PUSCH-ServingCellConfig of the serving cell is configured, Lmax is given by that parameter; + // + // - otherwise, Lmax is given by the maximum number of layers for PUSCH supported by the UE for the serving cell + // for non-codebook based operation. + int Lmax = 0; + if (maxMIMO_Layers != NULL) + Lmax = *maxMIMO_Layers; + else + AssertFatal(false, "MIMO on PUSCH not supported, maxMIMO_Layers needs to be set to 1\n"); + int count = srs_non_codebook_nb_res(srs_config); + int lsum = srs_binomial_sum(count, Lmax); + if (lsum > 0 && ceil(log2(lsum)) > 0) { + switch(Lmax) { + case 1: + val = table_7_3_1_1_2_28[count-2][srs_feedback->sri]; + break; + case 2: + val = table_7_3_1_1_2_29[count-2][srs_feedback->sri]; + break; + case 3: + val = table_7_3_1_1_2_30[count-2][srs_feedback->sri]; + break; + case 4: + val = table_7_3_1_1_2_31[count-2][srs_feedback->sri]; + break; + default: + LOG_E(NR_MAC, "%s (%d) - Invalid Lmax %d\n", __FUNCTION__, __LINE__, Lmax); + } + } + } + } + return val; +} + +static uint32_t compute_precoding_information(NR_PUSCH_Config_t *pusch_Config, + NR_SRS_Config_t *srs_config, + dci_field_t srs_resource_indicator, + nr_srs_feedback_t *srs_feedback, + const uint8_t *nrOfLayers, + int *tpmi) +{ + uint32_t val = 0; + + uint8_t pusch_antenna_ports = get_pusch_nb_antenna_ports(pusch_Config, srs_config, srs_resource_indicator); + if (!pusch_Config + || (pusch_Config->txConfig != NULL && *pusch_Config->txConfig == NR_PUSCH_Config__txConfig_nonCodebook) + || pusch_antenna_ports == 1) { + return val; + } + + long max_rank = *pusch_Config->maxRank; + long *ul_FullPowerTransmission = pusch_Config->ext1 ? pusch_Config->ext1->ul_FullPowerTransmission_r16 : NULL; + long *codebookSubset = pusch_Config->codebookSubset; + int ul_tpmi = tpmi ? *tpmi : srs_feedback ? srs_feedback->tpmi : -1; + + if (pusch_antenna_ports == 2) { + + if (max_rank == 1) { + // - 1 or 3 bits according to Table 7.3.1.1.2-5 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset; + // - 2 bits according to Table 7.3.1.1.2-5A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values + // of higher layer parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + AssertFatal(ul_tpmi <= 2,"TPMI %d is invalid!\n", ul_tpmi); + val = ul_tpmi; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal(ul_tpmi <= 1,"TPMI %d is invalid!\n", ul_tpmi); + val = ul_tpmi; + } else { + AssertFatal(ul_tpmi <= 5,"TPMI %d is invalid!\n", ul_tpmi); + val = ul_tpmi; + } + } + } else { + // - 2 or 4 bits according to Table 7.3.1.1.2-4 for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank and codebookSubset; + // - 2 bits according to Table 7.3.1.1.2-4A for 2 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, transform precoder is disabled, maxRank=2, and codebookSubset=nonCoherent; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + AssertFatal((*nrOfLayers==1 && ul_tpmi <= 2) + || (*nrOfLayers==2 && ul_tpmi == 0), + "TPMI %d is invalid!\n", + ul_tpmi); + val = *nrOfLayers == 1 ? table_7_3_1_1_2_4A_1layer[ul_tpmi] : 2; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal((*nrOfLayers==1 && ul_tpmi <= 1) + || (*nrOfLayers==2 && ul_tpmi == 0), + "TPMI %d is invalid!\n", + ul_tpmi); + val = *nrOfLayers == 1 ? ul_tpmi : 2; + } else { + AssertFatal((*nrOfLayers==1 && ul_tpmi <= 5) + || (*nrOfLayers==2 && ul_tpmi <= 2), + "TPMI %d is invalid!\n", + ul_tpmi); + val = *nrOfLayers == 1 ? table_7_3_1_1_2_4_1layer_fullyAndPartialAndNonCoherent[ul_tpmi] : + table_7_3_1_1_2_4_2layers_fullyAndPartialAndNonCoherent[ul_tpmi]; + } + } + } + + } else if (pusch_antenna_ports == 4) { + + if (max_rank == 1) { + // - 2, 4, or 5 bits according to Table 7.3.1.1.2-3 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset; + // - 3 or 4 bits according to Table 7.3.1.1.2-3A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=1, and according to whether transform precoder is enabled or disabled, and the values + // of higher layer parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal(ul_tpmi <= 3 || ul_tpmi == 13, "TPMI %d is invalid!\n", ul_tpmi); + } else { + AssertFatal(ul_tpmi <= 15, "TPMI %d is invalid!\n", ul_tpmi); + } + val = table_7_3_1_1_2_3A[ul_tpmi]; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal(ul_tpmi <= 3, "TPMI %d is invalid!\n", ul_tpmi); + } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { + AssertFatal(ul_tpmi <= 11, "TPMI %d is invalid!\n", ul_tpmi); + } else { + AssertFatal(ul_tpmi <= 27, "TPMI %d is invalid!\n", ul_tpmi); + } + val = ul_tpmi; + } + } else { + // - 4, 5, or 6 bits according to Table 7.3.1.1.2-2 for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission + // is not configured or configured to fullpowerMode2 or configured to fullpower, and according to whether transform + // precoder is enabled or disabled, and the values of higher layer parameters maxRank, and codebookSubset; + // - 4 or 5 bits according to Table 7.3.1.1.2-2A for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=2, transform precoder is disabled, and according to the values of higher layer parameter + // codebookSubset; + // - 4 or 6 bits according to Table 7.3.1.1.2-2B for 4 antenna ports, if txConfig = codebook, ul-FullPowerTransmission = + // fullpowerMode1, maxRank=3 or 4, transform precoder is disabled, and according to the values of higher layer + // parameter codebookSubset; + if (ul_FullPowerTransmission && *ul_FullPowerTransmission == NR_PUSCH_Config__ext1__ul_FullPowerTransmission_r16_fullpowerMode1) { + if (max_rank == 2) { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal((*nrOfLayers==1 + && (ul_tpmi <= 3 || ul_tpmi == 13)) + || (*nrOfLayers == 2 && ul_tpmi <= 6), + "TPMI %d is invalid!\n", + ul_tpmi); + } else { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 15) + || (*nrOfLayers == 2 && ul_tpmi <= 13), + "TPMI %d is invalid!\n", + ul_tpmi); + } + val = *nrOfLayers == 1 ? table_7_3_1_1_2_2A_1layer[ul_tpmi] : table_7_3_1_1_2_2A_2layers[ul_tpmi]; + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal((*nrOfLayers == 1 + && (ul_tpmi <= 3 || ul_tpmi == 13)) + || (*nrOfLayers == 2 && ul_tpmi <= 6) + || (*nrOfLayers == 3 && ul_tpmi <= 1) + || (*nrOfLayers == 4 && ul_tpmi == 0), + "TPMI %d is invalid!\n", + ul_tpmi); + } else { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 15) + || (*nrOfLayers == 2 && ul_tpmi <= 13) + || (*nrOfLayers == 3 && ul_tpmi <= 2) + || (*nrOfLayers == 4 && ul_tpmi <= 2), + "TPMI %d is invalid!\n", + ul_tpmi); + } + switch (*nrOfLayers) { + case 1: + val = table_7_3_1_1_2_2B_1layer[ul_tpmi]; + break; + case 2: + val = table_7_3_1_1_2_2B_2layers[ul_tpmi]; + break; + case 3: + val = table_7_3_1_1_2_2B_3layers[ul_tpmi]; + break; + case 4: + val = table_7_3_1_1_2_2B_4layers[ul_tpmi]; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } + } else { + if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_nonCoherent) { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 3) + || (*nrOfLayers == 2 && ul_tpmi <= 5) + || (*nrOfLayers == 3 && ul_tpmi == 0) + || (*nrOfLayers == 4 && ul_tpmi == 0), + "TPMI %d is invalid!\n", + ul_tpmi); + } else if (codebookSubset && *codebookSubset == NR_PUSCH_Config__codebookSubset_partialAndNonCoherent) { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 11) + || (*nrOfLayers == 2 && ul_tpmi <= 13) + || (*nrOfLayers == 3 && ul_tpmi <= 2) + || (*nrOfLayers == 4 && ul_tpmi <= 2), + "TPMI %d is invalid!\n", + ul_tpmi); + } else { + AssertFatal((*nrOfLayers == 1 && ul_tpmi <= 28) + || (*nrOfLayers == 2 && ul_tpmi <= 22) + || (*nrOfLayers == 3 && ul_tpmi <= 7) + || (*nrOfLayers == 4 && ul_tpmi <= 5), + "TPMI %d is invalid!\n", + ul_tpmi); + } + switch (*nrOfLayers) { + case 1: + val = table_7_3_1_1_2_2_1layer[ul_tpmi]; + break; + case 2: + val = table_7_3_1_1_2_2_2layers[ul_tpmi]; + break; + case 3: + val = table_7_3_1_1_2_2_3layers[ul_tpmi]; + break; + case 4: + val = table_7_3_1_1_2_2_4layers[ul_tpmi]; + break; + default: + LOG_E(NR_MAC,"Number of layers %d is invalid!\n", *nrOfLayers); + } + } + } + } + return val; +} + void config_uldci(const NR_UE_ServingCell_Info_t *sc_info, const nfapi_nr_pusch_pdu_t *pusch_pdu, dci_pdu_rel15_t *dci_pdu_rel15, @@ -827,28 +1214,24 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info, // bwp indicator as per table 7.3.1.1.2-1 in 38.212 dci_pdu_rel15->bwp_indicator.val = sc_info->n_ul_bwp < 4 ? bwp_id : bwp_id - 1; // SRS resource indicator - if (pusch_Config && - pusch_Config->txConfig != NULL) { + if (pusch_Config && pusch_Config->txConfig != NULL) { AssertFatal(*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook, "Non Codebook configuration non supported\n"); - compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH, - pusch_Config, - ul_bwp->srs_Config, - srs_feedback, - &dci_pdu_rel15->srs_resource_indicator.val); + dci_pdu_rel15->srs_resource_indicator.val = compute_srs_resource_indicator(sc_info->maxMIMO_Layers_PUSCH, + pusch_Config, + ul_bwp->srs_Config, + srs_feedback); } - compute_precoding_information(pusch_Config, - ul_bwp->srs_Config, - dci_pdu_rel15->srs_resource_indicator, - srs_feedback, - &pusch_pdu->nrOfLayers, - tpmi, - &dci_pdu_rel15->precoding_information.val); + dci_pdu_rel15->precoding_information.val = compute_precoding_information(pusch_Config, + ul_bwp->srs_Config, + dci_pdu_rel15->srs_resource_indicator, + srs_feedback, + &pusch_pdu->nrOfLayers, + tpmi); // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4 // Antenna Ports - - dci_pdu_rel15->antenna_ports.val = NFAPI_MODE == NFAPI_MODE_AERIAL ? 2 : 0; + dci_pdu_rel15->antenna_ports.val = 0; // DMRS sequence initialization dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid; @@ -1144,9 +1527,9 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, pucch_pdu->prb_size=1; } // Beamforming - pucch_pdu->beamforming.num_prgs = 0; - pucch_pdu->beamforming.prg_size = 0; // pucch_pdu->prb_size; - pucch_pdu->beamforming.dig_bf_interface = 0; + pucch_pdu->beamforming.num_prgs = 1; + pucch_pdu->beamforming.prg_size = pucch_pdu->prb_size; + pucch_pdu->beamforming.dig_bf_interface = 1; pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; } @@ -1175,11 +1558,11 @@ void set_r_pucch_parms(int rsetindex, *start_symbol_index = default_pucch_firstsymb[rsetindex]; } -void prepare_dci(const NR_UE_ServingCell_Info_t *servingCellInfo, - const NR_UE_DL_BWP_t *current_BWP, - const NR_ControlResourceSet_t *coreset, - dci_pdu_rel15_t *dci_pdu_rel15, - nr_dci_format_t format) +static void prepare_dci_X1(const NR_UE_ServingCell_Info_t *servingCellInfo, + const NR_UE_DL_BWP_t *current_BWP, + const NR_ControlResourceSet_t *coreset, + dci_pdu_rel15_t *dci_pdu_rel15, + nr_dci_format_t format) { const NR_PDSCH_Config_t *pdsch_Config = current_BWP ? current_BWP->pdsch_Config : NULL; @@ -1326,7 +1709,7 @@ void fill_dci_pdu_rel15(const NR_UE_ServingCell_Info_t *servingCellInfo, pdcch_dci_pdu->PayloadSizeBits = dci_size; AssertFatal(dci_size <= 64, "DCI sizes above 64 bits not yet supported"); if (dci_format == NR_DL_DCI_FORMAT_1_1 || dci_format == NR_UL_DCI_FORMAT_0_1) - prepare_dci(servingCellInfo, current_DL_BWP, coreset, dci_pdu_rel15, dci_format); + prepare_dci_X1(servingCellInfo, current_DL_BWP, coreset, dci_pdu_rel15, dci_format); /// Payload generation switch (dci_format) { @@ -2149,7 +2532,7 @@ void set_max_fb_time(NR_UE_UL_BWP_t *UL_BWP, const NR_UE_DL_BWP_t *DL_BWP) { UL_BWP->max_fb_time = 8; // default value // take the maximum in dl_DataToUL_ACK list - if (DL_BWP->dci_format != NR_DL_DCI_FORMAT_1_0 && UL_BWP->pucch_Config) { + if (UL_BWP->pucch_Config) { const struct NR_PUCCH_Config__dl_DataToUL_ACK *fb_times = UL_BWP->pucch_Config->dl_DataToUL_ACK; for (int i = 0; i < fb_times->list.count; i++) { if(*fb_times->list.array[i] > UL_BWP->max_fb_time) @@ -2318,8 +2701,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, AssertFatal(dl_bwp_switch == ul_bwp_switch, "Different UL and DL BWP not supported\n"); DL_BWP->bwp_id = dl_bwp_switch; UL_BWP->bwp_id = ul_bwp_switch; - } - else { + } else { // (re)configuring BWP // TODO BWP switching not via RRC reconfiguration // via RRC if firstActiveXlinkBWP_Id is NULL, MAC stays on the same BWP as before @@ -2368,8 +2750,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, UL_BWP->pusch_Config = ubwpd->pusch_Config->choice.setup; UL_BWP->pucch_Config = ubwpd->pucch_Config->choice.setup; UL_BWP->srs_Config = ubwpd->srs_Config->choice.setup; - } - else { + } else { DL_BWP->bwp_id = 0; UL_BWP->bwp_id = 0; DL_BWP->pdsch_Config = NULL; @@ -2378,11 +2759,6 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, UL_BWP->configuredGrantConfig = NULL; } - if (old_dl_bwp_id != DL_BWP->bwp_id) - LOG_I(NR_MAC, "Switching to DL-BWP %li\n", DL_BWP->bwp_id); - if (old_ul_bwp_id != UL_BWP->bwp_id) - LOG_I(NR_MAC, "Switching to UL-BWP %li\n", UL_BWP->bwp_id); - // TDA lists if (DL_BWP->bwp_id>0) DL_BWP->tdaList_Common = dl_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; @@ -2422,7 +2798,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); sc_info->dl_bw_tbslbrm = get_dlbw_tbslbrm(sc_info->initial_dl_BWPSize, servingCellConfig); - sc_info->dl_bw_tbslbrm = get_ulbw_tbslbrm(sc_info->initial_ul_BWPSize, servingCellConfig); + sc_info->ul_bw_tbslbrm = get_ulbw_tbslbrm(sc_info->initial_ul_BWPSize, servingCellConfig); if (UL_BWP->bwp_id > 0) { UL_BWP->pucch_ConfigCommon = ul_bwp->bwp_Common->pucch_ConfigCommon ? ul_bwp->bwp_Common->pucch_ConfigCommon->choice.setup : NULL; @@ -2432,6 +2808,19 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, UL_BWP->rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; } + // if PRACH occasions are not configured for the active UL BWP + // switch the active UL BWP to BWP indicated by initialUplinkBWP + // as described in 5.15 of 38.321 + if (is_RA && !UL_BWP->rach_ConfigCommon) { + LOG_I(NR_MAC, "Cannot perform RA in current BWP, switching to initial BWP\n"); + configure_UE_BWP(nr_mac, scc, UE, is_RA, target_ss, 0, 0); + return; + } + if (old_dl_bwp_id != DL_BWP->bwp_id) + LOG_I(NR_MAC, "Switching to DL-BWP %li\n", DL_BWP->bwp_id); + if (old_ul_bwp_id != UL_BWP->bwp_id) + LOG_I(NR_MAC, "Switching to UL-BWP %li\n", UL_BWP->bwp_id); + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; // Reset required fields in sched_ctrl (e.g. ul_ri and tpmi) reset_sched_ctrl(sched_ctrl); @@ -2481,7 +2870,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, // setting PDCCH related structures for sched_ctrl sched_ctrl->search_space = get_searchspace(scc, bwpd, target_ss); - sched_ctrl->coreset = get_coreset(nr_mac, scc, bwpd, sched_ctrl->search_space, target_ss); + sched_ctrl->coreset = get_coreset(nr_mac, scc, bwpd, *sched_ctrl->search_space->controlResourceSetId); sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac, sched_ctrl->search_space, @@ -2522,7 +2911,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, } AssertFatal(sched_ctrl->search_space != NULL, "SearchSpace cannot be null for RA\n"); - sched_ctrl->coreset = get_coreset(nr_mac, scc, dl_bwp, sched_ctrl->search_space, NR_SearchSpace__searchSpaceType_PR_common); + sched_ctrl->coreset = get_coreset(nr_mac, scc, bwpd, *sched_ctrl->search_space->controlResourceSetId); NR_COMMON_channels_t *cc = &nr_mac->common_channels[0]; int ssb_index = cc->ssb_index[UE->UE_beam_index]; sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac, @@ -2577,26 +2966,16 @@ static void init_bler_stats(const NR_bler_options_t *bler_options, NR_bler_stats * error handling). Remove with delete_nr_ue_data(). */ NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup) { - uid_t uid = uid_linear_allocator_new(uia); - /* if the UE list is full, we should reject the UE with an RRC reject - * message, but we do not have this functionality. To keep it simple, do not - * create a UE context here, so we can print an error message. */ - if (uid >= MAX_MOBILES_PER_GNB) { - uid_linear_allocator_free(uia, uid); - return NULL; - } - NR_UE_info_t *UE = calloc_or_fail(1, sizeof(NR_UE_info_t)); + UE->uid = uid_linear_allocator_new(uia); UE->rnti = rnti; UE->CellGroup = CellGroup; - UE->uid = uid; UE->ra = calloc(1, sizeof(*UE->ra)); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; sched_ctrl->ta_update = 31; /* set illegal time domain allocation to force recomputation of all fields */ sched_ctrl->sched_pdsch.time_domain_allocation = -1; - sched_ctrl->sched_pusch.time_domain_allocation = -1; /* Set default BWPs */ AssertFatal(UE->sc_info.n_ul_bwp <= NR_MAX_NUM_BWP, "uplinkBWP_ToAddModList has %d BWP!\n", UE->sc_info.n_ul_bwp); @@ -2621,6 +3000,8 @@ NR_UE_info_t *remove_UE_from_list(int list_size, NR_UE_info_t *list[list_size], { for (int i = 0; i < list_size; i++) { NR_UE_info_t *curr_UE = list[i]; + if (!curr_UE) + break; /* reached the end of the list */ if (curr_UE->rnti != rnti) continue; @@ -2629,7 +3010,6 @@ NR_UE_info_t *remove_UE_from_list(int list_size, NR_UE_info_t *list[list_size], list[list_size - 1] = NULL; return curr_UE; } - LOG_E(NR_MAC, "UE %04x to be removed not found in list\n", rnti); return NULL; } @@ -2670,8 +3050,6 @@ bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */ - sched_ctrl->sched_srs.frame = -1; - sched_ctrl->sched_srs.slot = -1; sched_ctrl->pdcch_cl_adjust = 0; reset_srs_stats(UE); @@ -2735,8 +3113,10 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti) NR_SCHED_LOCK(&UE_info->mutex); NR_UE_info_t *UE = remove_UE_from_list(MAX_MOBILES_PER_GNB + 1, UE_info->connected_ue_list, rnti); NR_SCHED_UNLOCK(&UE_info->mutex); - - delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); + if (UE) + delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); + else + nr_release_ra_UE(nr_mac, rnti); } // all values passed to this function are in dB x10 @@ -3051,13 +3431,86 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt } } +void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot) +{ + NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock); + + NR_UEs_t *UE_info = &nr_mac->UE_info; + UE_iterator(UE_info->connected_ue_list, UE) { + measgap_config_t *mgc = &UE->measgap_config; + if (!mgc->enable) + continue; + + const int slots_frame = nr_mac->frame_structure.numb_slots_frame; + const frame_t f = (frame + (slot + mgc->n_slots_advance) / slots_frame) % 1024; + const slot_t s = (slot + mgc->n_slots_advance) % slots_frame; + + // TS 38 331 - Section 5.5.2.9 Measurement gap configuration + if (!(((f % (mgc->mgrp_ms / 10)) == (mgc->gapOffset / 10)) && (s == mgc->gapOffset % 10))) + continue; + + NR_timer_t *t = &UE->UE_sched_ctrl.transm_interrupt; + // start a timer to stop scheduling UE during MeasGap, or extend timer for + // duration of measGap with existing follow-up action + if (!nr_timer_is_active(t) || nr_timer_remaining_time(t) < mgc->mgl_slots) { + nr_mac_interrupt_ue_transmission(nr_mac, UE, mgc->mgl_slots); + } + } +} + +void clean_bwp_structures(NR_SpCellConfig_t *spCellConfig) +{ + NR_ServingCellConfig_t *spCellConfigDedicated = spCellConfig->spCellConfigDedicated; + if (spCellConfigDedicated->downlinkBWP_ToReleaseList) { + struct NR_ServingCellConfig__downlinkBWP_ToReleaseList *rel_dl = spCellConfigDedicated->downlinkBWP_ToReleaseList; + struct NR_ServingCellConfig__downlinkBWP_ToAddModList *add_dl = spCellConfigDedicated->downlinkBWP_ToAddModList; + int num_rel = rel_dl->list.count; + int num_add = add_dl->list.count; + for (int i = 0; i < num_rel; i++) { + NR_BWP_Id_t *rel_id = rel_dl->list.array[i]; + for (int j = 0; j < num_add; j++) { + NR_BWP_Downlink_t *dl_bwp = add_dl->list.array[j]; + if (*rel_id == dl_bwp->bwp_Id) { + asn_sequence_del(&add_dl->list, j, 1); + } + } + asn_sequence_del(&rel_dl->list, i, 1); + } + if (rel_dl->list.count == 0) + free_and_zero(rel_dl); + if (add_dl->list.count == 0) + free_and_zero(add_dl); + } + if (spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList) { + struct NR_UplinkConfig__uplinkBWP_ToReleaseList *rel_ul = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList; + struct NR_UplinkConfig__uplinkBWP_ToAddModList *add_ul = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList; + int num_rel = rel_ul->list.count; + int num_add = add_ul->list.count; + for (int i = 0; i < num_rel; i++) { + NR_BWP_Id_t *rel_id = rel_ul->list.array[i]; + for (int j = 0; j < num_add; j++) { + NR_BWP_Uplink_t *ul_bwp = add_ul->list.array[j]; + if (*rel_id == ul_bwp->bwp_Id) { + asn_sequence_del(&add_ul->list, j, 1); + } + } + asn_sequence_del(&rel_ul->list, i, 1); + } + if (rel_ul->list.count == 0) + free_and_zero(rel_ul); + if (add_ul->list.count == 0) + free_and_zero(add_ul); + } +} + void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) { DevAssert(cell_group != NULL); + NR_SpCellConfig_t *spCellConfig = cell_group->spCellConfig; /* remove a reconfigurationWithSync, we don't need it anymore */ - if (cell_group->spCellConfig && cell_group->spCellConfig->reconfigurationWithSync != NULL) { - ASN_STRUCT_FREE(asn_DEF_NR_ReconfigurationWithSync, cell_group->spCellConfig->reconfigurationWithSync); - cell_group->spCellConfig->reconfigurationWithSync = NULL; + if (spCellConfig && spCellConfig->reconfigurationWithSync != NULL) { + ASN_STRUCT_FREE(asn_DEF_NR_ReconfigurationWithSync, spCellConfig->reconfigurationWithSync); + spCellConfig->reconfigurationWithSync = NULL; } /* remove the rlc_BearerToReleaseList, we don't need it anymore */ if (cell_group->rlc_BearerToReleaseList != NULL) { @@ -3069,6 +3522,8 @@ void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) /* remove reestablishRLC, we don't need it anymore */ for (int i = 0; i < cell_group->rlc_BearerToAddModList->list.count; ++i) free_and_zero(cell_group->rlc_BearerToAddModList->list.array[i]->reestablishRLC); + /* clean BWP structures */ + clean_bwp_structures(spCellConfig); } int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs) @@ -3082,7 +3537,7 @@ int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs) return (delay_ms << scs) + sl_ahead; } -int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots) +int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots) { DevAssert(mac != NULL); DevAssert(UE != NULL); @@ -3090,7 +3545,6 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interr nr_timer_setup(&UE->UE_sched_ctrl.transm_interrupt, slots, 1); nr_timer_start(&UE->UE_sched_ctrl.transm_interrupt); - UE->interrupt_action = action; // it might happen that timing advance command should be sent during the UE // inactivity time. To prevent this, set a variable as if we would have just @@ -3098,14 +3552,27 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interr // frames, after the inactivity of the UE. UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024; - LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots) action %d\n", UE->rnti, slots, UE->interrupt_action); + LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots)\n", UE->rnti, slots); return 0; } +static void nr_mac_ue_transmission_timeout(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots) +{ + DevAssert(mac != NULL); + DevAssert(UE != NULL); + NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); + + nr_timer_setup(&UE->UE_sched_ctrl.transm_timeout, slots, 1); + nr_timer_start(&UE->UE_sched_ctrl.transm_timeout); + + LOG_I(NR_MAC, "UE %04x: Timeout for UE transmission (%d slots)\n", UE->rnti, slots); + return; +} + int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info) { int delay = nr_mac_get_reconfig_delay_slots(UE_info->current_DL_BWP.scs); - nr_mac_interrupt_ue_transmission(mac, UE_info, FOLLOW_OUTOFSYNC, delay); + nr_mac_ue_transmission_timeout(mac, UE_info, delay); LOG_I(NR_MAC, "gNB-DU received the TransmissionActionIndicator with Stop value for UE %04x\n", UE_info->rnti); return 0; } @@ -3124,7 +3591,7 @@ void nr_mac_trigger_release_complete(gNB_MAC_INST *mac, int rnti) // du_remove_f1_ue_data() (and also while sending the message to RRC) NR_SCHED_UNLOCK(&mac->sched_lock); f1_ue_data_t ue_data = du_get_f1_ue_data(rnti); - f1ap_ue_context_release_complete_t complete = { + f1ap_ue_context_rel_cplt_t complete = { .gNB_CU_ue_id = ue_data.secondary_ue, .gNB_DU_ue_id = rnti, }; @@ -3164,13 +3631,21 @@ void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot) } /* check if UL failure and trigger release request if necessary */ - nr_mac_check_ul_failure(mac, UE->rnti, sched_ctrl); + bool released = nr_mac_check_ul_failure(mac, UE->rnti, sched_ctrl); + if (released) { + // go back to examine the next UE, which is at the position the current UE was + UE--; + continue; + } if (nr_timer_tick(&sched_ctrl->transm_interrupt)) { /* expired */ nr_timer_stop(&sched_ctrl->transm_interrupt); - if (UE->interrupt_action == FOLLOW_OUTOFSYNC) - nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs); + } + if (nr_timer_tick(&sched_ctrl->transm_timeout)) { + nr_timer_stop(&sched_ctrl->transm_timeout); + LOG_W(NR_MAC, "UE %04x UL failure after transmission timeout\n", UE->rnti); + nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs); } } } @@ -3207,8 +3682,10 @@ int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx) // TODO this is a placeholder for a possibly more complex function // for now the fapi beam index is the number of SSBs transmitted before ssb_index i -void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, gNB_MAC_INST *mac) +void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac) { + if (mac->beam_info.beam_mode == NO_BEAM_MODE) + return; int len = 0; uint8_t* buf = NULL; switch (scc->ssb_PositionsInBurst->present) { @@ -3227,11 +3704,13 @@ void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, gNB_MAC_INST default : AssertFatal(false, "Invalid configuration\n"); } - int fapi_index = 0; + int index = 0; for (int i = 0; i < len; ++i) { - if ((buf[i / 8] >> (7 - i % 8)) & 0x1) - mac->fapi_beam_index[i] = fapi_index++; - else + if ((buf[i / 8] >> (7 - i % 8)) & 0x1) { + int fapi_index = mac->beam_info.beam_mode == LOPHY_BEAM_IDX ? config->bw_list[index] : index; + mac->fapi_beam_index[i] = fapi_index; + index++; + } else mac->fapi_beam_index[i] = -1; } } @@ -3244,7 +3723,7 @@ static inline int get_beam_index(const NR_beam_info_t *beam_info, int frame, int NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame) { // if no beam allocation for analog beamforming we always return beam index 0 (no multiple beams) - if (!beam_info->beam_allocation) + if (beam_info->beam_mode == NO_BEAM_MODE) return (NR_beam_alloc_t) {.new_beam = false, .idx = 0}; const int index = get_beam_index(beam_info, frame, slot, slots_per_frame); @@ -3278,7 +3757,7 @@ void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_ void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE) { // do not perform beam procedures if there is no beam information - if (!mac->beam_info.beam_allocation) + if (mac->beam_info.beam_mode == NO_BEAM_MODE) return; RSRP_report_t *rsrp_report = &UE->UE_sched_ctrl.CSI_report.ssb_rsrp_report; // simple beam switching algorithm -> we select beam with highest RSRP from CSI report @@ -3297,7 +3776,9 @@ void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_le NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); uint8_t du2cu[1024]; - int encoded = encode_cellGroupConfig(UE->CellGroup, du2cu, sizeof(du2cu)); + int encoded_len = 0; + if (UE->CellGroup) + encoded_len = encode_cellGroupConfig(UE->CellGroup, du2cu, sizeof(du2cu)); DevAssert(mac->f1_config.setup_req != NULL); AssertFatal(mac->f1_config.setup_req->num_cells_available == 1, "can handle only one cell\n"); @@ -3308,8 +3789,8 @@ void send_initial_ul_rrc_message(int rnti, const uint8_t *sdu, sdu_size_t sdu_le .crnti = rnti, .rrc_container = (uint8_t *) sdu, .rrc_container_length = sdu_len, - .du2cu_rrc_container = (uint8_t *) du2cu, - .du2cu_rrc_container_length = encoded + .du2cu_rrc_container = encoded_len ? (uint8_t *) du2cu : NULL, + .du2cu_rrc_container_length = encoded_len }; mac->mac_rrc.initial_ul_rrc_message_transfer(0, &ul_rrc_msg); } @@ -3322,21 +3803,35 @@ bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE) if (!nr_rlc_activate_srb0(UE->rnti, UE, send_initial_ul_rrc_message)) return false; + if (UE->uid >= MAX_MOBILES_PER_GNB) { + // verifying if any UE left in the meantime and it is possible to get a valid UID + uid_linear_allocator_free(&mac->UE_info.uid_allocator, UE->uid); + UE->uid = uid_linear_allocator_new(&mac->UE_info.uid_allocator); + if (UE->uid >= MAX_MOBILES_PER_GNB) { + // if the UE list is full, we should reject the UE with an RRC reject message + // to signal the upper layers to send a reject we send an empty CellGroup information element + UE->CellGroup = NULL; + LOG_W(NR_MAC, "Maximum number of UE alllowed at DU reached. Cannot serve UE %04x", UE->rnti); + return true; + } + } + /* create this UE's initial CellGroup */ int CC_id = 0; int srb_id = 1; const NR_ServingCellConfigCommon_t *scc = mac->common_channels[CC_id].ServingCellConfigCommon; - const NR_ServingCellConfig_t *sccd = UE->is_redcap ? NULL : mac->common_channels[CC_id].pre_ServingCellConfig; - NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config, &mac->rlc_config); + NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, &mac->radio_config, &mac->rlc_config); ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = cellGroupConfig; + if (!cellGroupConfig) + return true; + /* the cellGroup sent to CU specifies there is SRB1, so create it */ DevAssert(cellGroupConfig->rlc_BearerToAddModList->list.count == 1); const NR_RLC_BearerConfig_t *bearer = cellGroupConfig->rlc_BearerToAddModList->list.array[0]; DevAssert(bearer->servedRadioBearer->choice.srb_Identity == srb_id); nr_rlc_add_srb(UE->rnti, bearer->servedRadioBearer->choice.srb_Identity, bearer); - int priority = bearer->mac_LogicalChannelConfig->ul_SpecificParameters->priority; nr_lc_config_t c = {.lcid = bearer->logicalChannelIdentity, .priority = priority}; nr_mac_add_lcid(&UE->UE_sched_ctrl, &c); @@ -3357,6 +3852,19 @@ bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti) return sched_ctrl->release_timer == 0; } +bool nr_mac_ue_is_active(const NR_UE_info_t *ue) +{ + /* pass NR_UE_info_t, so that later we could adapt, e.g., for DRX */ + const NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl; + if (sched_ctrl->ul_failure) + return false; + if (nr_timer_is_active(&sched_ctrl->transm_interrupt)) + return false; + return true; +} + +#define UL_FAILURE_REQ_GRACE 10000 +#define UL_FAILURE_TIMEOUT 30000 void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing) { if (sched_ctrl->ul_failure) { @@ -3364,8 +3872,9 @@ void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpac return; } sched_ctrl->ul_failure = true; - // 30 seconds till triggering release request - sched_ctrl->ul_failure_timer = 30000 << subcarrier_spacing; + // UL_FAILURE_TIMEOUT ms till triggering release request + // UL_FAILURE_REQ_GRACE ms till automatically released after request + sched_ctrl->ul_failure_timer = (UL_FAILURE_REQ_GRACE + UL_FAILURE_TIMEOUT) << subcarrier_spacing; } void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl) @@ -3385,7 +3894,7 @@ bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti) return false; } f1_ue_data_t ue_data = du_get_f1_ue_data(rnti); - f1ap_ue_context_release_req_t request = { + f1ap_ue_context_rel_req_t request = { .gNB_CU_ue_id = ue_data.secondary_ue, .gNB_DU_ue_id = rnti, .cause = F1AP_CAUSE_RADIO_NETWORK, @@ -3395,27 +3904,52 @@ bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti) return true; } -void nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl) +bool nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl) { if (!sched_ctrl->ul_failure) - return; + return false; if (sched_ctrl->ul_failure_timer > 0) sched_ctrl->ul_failure_timer--; - /* to trigger only once: trigger when ul_failure_timer == 1, but timer will - * stop at 0 and we wait for a UE release command from upper layers */ - if (sched_ctrl->ul_failure_timer == 1) { + /* trigger once: trigger when ul_failure_timer == UL_FAILURE_REQ_GRACE( we + * wait for a UE release command from upper layers), and UE is automatically + * released when no answer after UL_FAILURE_REQ_GRACE */ + if (sched_ctrl->ul_failure_timer == UL_FAILURE_REQ_GRACE) { LOG_W(MAC, "UE %04x: request release after UL failure timer expiry\n", rnti); bool requested = nr_mac_request_release_ue(nrmac, rnti); if (!requested) - nr_mac_release_ue(nrmac, rnti); + sched_ctrl->ul_failure_timer = 0; /* force expiry */ } + if (sched_ctrl->ul_failure_timer == 0) { + LOG_W(NR_MAC, "UE %04x: no answer for release request, dropping UE\n", rnti); + nr_mac_release_ue(nrmac, rnti); + return true; + } + return false; } -void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE) +void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE, int new_bwp_id) { DevAssert(UE->CellGroup != NULL); + NR_CellGroupConfig_t *cellGroup_for_UE = NULL; + if (new_bwp_id >= 0) { + AssertFatal(UE->current_DL_BWP.bwp_id == UE->current_UL_BWP.bwp_id, "We only support same BWP for UL and DL\n"); + if (new_bwp_id == UE->current_DL_BWP.bwp_id) + LOG_E(NR_MAC, "Source BWP ID and target BWP ID are the same, can't perform switch\n"); + else + cellGroup_for_UE = update_cellGroupConfig_for_BWP_switch(UE->CellGroup, + &nrmac->radio_config, + UE->capability, + nrmac->common_channels[0].ServingCellConfigCommon, + UE->uid, + UE->current_DL_BWP.bwp_id, + new_bwp_id); + } uint8_t buf[2048]; - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, UE->CellGroup, buf, sizeof(buf)); + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, + NULL, + cellGroup_for_UE ? cellGroup_for_UE : UE->CellGroup, + buf, + sizeof(buf)); AssertFatal(enc_rval.encoded > 0, "ASN1 encoding of CellGroupConfig failed, failed type %s\n", enc_rval.failed_type->name); du_to_cu_rrc_information_t du2cu = { .cellGroupConfig = buf, @@ -3430,6 +3964,8 @@ void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_ .cause_value = F1AP_CauseRadioNetwork_action_desirable_for_radio_reasons, }; nrmac->mac_rrc.ue_context_modification_required(&required); + if (cellGroup_for_UE) + free_cellGroupConfig(cellGroup_for_UE); } /* \brief add bearers from CellGroupConfig. diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c index c3ebb5ab9b..cf58252ed9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_srs.c @@ -462,18 +462,30 @@ static void nr_configure_srs(gNB_MAC_INST *nrmac, srs_pdu->srs_parameters_v4.iq_representation = 1; srs_pdu->srs_parameters_v4.prg_size = 1; srs_pdu->srs_parameters_v4.num_total_ue_antennas = 1 << srs_pdu->num_ant_ports; + /* For srs usage: codebook, this is a bitmask of the antenna ports that should be used for data. + * num_ant_ports num_total_ue_antennas sampled_ue_antennas + * 0 1 1 + * 1 2 3 + * 2 4 15 */ + srs_pdu->srs_parameters_v4.sampled_ue_antennas = (2 << srs_pdu->num_ant_ports) - 1; if (srs_resource_set->usage == NR_SRS_ResourceSet__usage_beamManagement) { srs_pdu->beamforming.trp_scheme = 0; srs_pdu->beamforming.num_prgs = m_SRS[srs_pdu->config_index]; - srs_pdu->beamforming.prg_size = 1; + srs_pdu->beamforming.prg_size = srs_pdu->srs_parameters_v4.srs_bandwidth_size; } srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, frame, slot, UE->UE_beam_index, slots_per_frame); AssertFatal(beam.idx >= 0, "Cannot allocate SRS in any available beam\n"); uint16_t *vrb_map_UL = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][buffer_index * MAX_BWP_SIZE]; - uint64_t mask = SL_to_bitmap(srs_pdu->time_start_position, srs_pdu->num_symbols); - for (int i = 0; i < srs_pdu->bwp_size; ++i) - vrb_map_UL[i + srs_pdu->bwp_start] |= mask; + uint16_t num = 1 << srs_pdu->num_symbols; // 0,1,2 means 1,2,4 symbols, see 222.10.04 table 3-105 + uint16_t mask = SL_to_bitmap(srs_pdu->time_start_position, num); + DevAssert(mask != 0); + for (int i = 0; i < srs_pdu->bwp_size; ++i) { + int rb = i + srs_pdu->bwp_start; + uint16_t alloc = vrb_map_UL[rb] & mask; + AssertFatal(nrmac->ulprbbl[rb] != 0 || alloc == 0, "RB %d not free for SRS: alloc 0x%02x for mask 0x%02x\n", rb, alloc, mask); + vrb_map_UL[rb] |= mask; + } } static void nr_fill_nfapi_srs(gNB_MAC_INST *nrmac, @@ -512,9 +524,7 @@ static void nr_fill_nfapi_srs(gNB_MAC_INST *nrmac, *********************************************************************/ void nr_schedule_srs(int module_id, frame_t frame, int slot) { - const int CC_id = 0; gNB_MAC_INST *nrmac = RC.nrmac[module_id]; - const NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon; /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock); @@ -523,16 +533,9 @@ void nr_schedule_srs(int module_id, frame_t frame, int slot) UE_iterator(UE_info->connected_ue_list, UE) { const int CC_id = 0; - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; - if(sched_ctrl->sched_srs.srs_scheduled && sched_ctrl->sched_srs.frame == frame && sched_ctrl->sched_srs.slot == slot) { - sched_ctrl->sched_srs.frame = -1; - sched_ctrl->sched_srs.slot = -1; - sched_ctrl->sched_srs.srs_scheduled = false; - } - - if ((sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) || nr_timer_is_active(&sched_ctrl->transm_interrupt)) { + if (!nr_mac_ue_is_active(UE) && !get_softmodem_params()->phy_test) { continue; } @@ -566,34 +569,20 @@ void nr_schedule_srs(int module_id, frame_t frame, int slot) continue; } - NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = get_ul_tdalist(current_BWP, - sched_ctrl->coreset->controlResourceSetId, - sched_ctrl->search_space->searchSpaceType->present, - TYPE_C_RNTI_); - const int num_tda = tdaList->list.count; - int max_k2 = 0; - // avoid last one in the list (for msg3) - for (int i = 0; i < num_tda - 1; i++) { - int k2 = get_K2(tdaList, i, current_BWP->scs, scc); - max_k2 = k2 > max_k2 ? k2 : max_k2; - } - // we are sheduling SRS max_k2 slot in advance for the presence of SRS to be taken into account when scheduling PUSCH const int n_slots_frame = nrmac->frame_structure.numb_slots_frame; - const int sched_slot = (slot + max_k2) % n_slots_frame; - const int sched_frame = (frame + (slot + max_k2) / n_slots_frame) % MAX_FRAME_NUMBER; + const int n_ahead = n_slots_frame - 1 + get_NTN_Koffset(nrmac->common_channels[0].ServingCellConfigCommon); + const int sched_slot = (slot + n_ahead) % n_slots_frame; + const int sched_frame = (frame + (slot + n_ahead) / n_slots_frame) % MAX_FRAME_NUMBER; const uint16_t period = srs_period[srs_resource->resourceType.choice.periodic->periodicityAndOffset_p.present]; const uint16_t offset = get_nr_srs_offset(srs_resource->resourceType.choice.periodic->periodicityAndOffset_p); // Check if UE will transmit the SRS in this frame - if ((sched_frame * n_slots_frame + sched_slot - offset) % period == 0) { - LOG_D(NR_MAC," %d.%d Scheduling SRS reception for %d.%d\n", frame, slot, sched_frame, sched_slot); - nr_fill_nfapi_srs(nrmac, CC_id, UE, sched_frame, sched_slot, srs_resource_set, srs_resource); - sched_ctrl->sched_srs.frame = sched_frame; - sched_ctrl->sched_srs.slot = sched_slot; - sched_ctrl->sched_srs.srs_scheduled = true; - } + if ((sched_frame * n_slots_frame + sched_slot - offset) % period != 0) + continue; + LOG_D(NR_MAC," %d.%d Scheduling SRS reception for %d.%d\n", frame, slot, sched_frame, sched_slot); + nr_fill_nfapi_srs(nrmac, CC_id, UE, sched_frame, sched_slot, srs_resource_set, srs_resource); } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 29ff27d38e..f3de970683 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -236,7 +236,7 @@ void nr_csi_meas_reporting(int Mod_idP,frame_t frame, slot_t slot) NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; const int n_slots_frame = nrmac->frame_structure.numb_slots_frame; - if (nr_timer_is_active(&sched_ctrl->transm_interrupt) || (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)) { + if (!nr_mac_ue_is_active(UE) && !get_softmodem_params()->phy_test) { continue; } const NR_CSI_MeasConfig_t *csi_measconfig = UE->sc_info.csi_MeasConfig; @@ -414,6 +414,25 @@ static void handle_dl_harq(NR_UE_info_t * UE, } } +// Referred Table 10.1.16.1-1 in 38.133 V16.7.0. +static int get_measured_sinr(int index) +{ + if (index < 0 || index > 127) + return INT_MAX; + + return -235 + index * 5; +} + +// Referred Table 10.1.16.1-2 in 38.133 V16.7.0. +static int get_diff_sinr(int index, int best_SINRx10) +{ + if (index <= 0) + return best_SINRx10; + if (index >= 15) + return best_SINRx10 - 150; + return best_SINRx10 - index * 10; +} + //returns the measured RSRP value (upper limit) static bool get_measured_rsrp(uint8_t index, int *rsrp) { @@ -498,22 +517,33 @@ static void evaluate_sinr_report(gNB_MAC_INST *nrmac, } curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); - sinr_report->SINR_index[0] = curr_payload & 0x7f; + int sinr_index = curr_payload & 0x7f; *cumul_bits += 7; csi_report->nb_of_csi_ssb_report++; - if (sinr_report->SINR_index[0] < 0 || sinr_report->SINR_index[0] > 127) { - LOG_E(NR_MAC, "UE %04x: reported SINR index %d invalid\n", UE->rnti, sinr_report->SINR_index[0]); + int SINRx10 = get_measured_sinr(sinr_index); + if (SINRx10 == INT_MAX) { + LOG_E(NR_MAC, "UE %04x: reported SINR index %d invalid\n", UE->rnti, sinr_index); return; } + sinr_report->SINRx10[0] = SINRx10; for (int i = 1; i < sinr_report->nr_reports; i++) { curr_payload = pickandreverse_bits(payload, 4, *cumul_bits); - sinr_report->SINR_index[i] = curr_payload & 0x0f; + sinr_report->SINRx10[i] = get_diff_sinr(curr_payload & 0x0f, sinr_report->SINRx10[0]); *cumul_bits += 4; } - LOG_D(MAC, "Reported SSB-SINR index = %d\n", sinr_report->SINR_index[0]); + NR_mac_stats_t *stats = &UE->mac_stats; + // including ssb SINR in mac stats + stats->cumul_sinrx10 += sinr_report->SINRx10[0]; + stats->num_sinr_meas++; + + const int mcs_table = UE->current_DL_BWP.mcsTableIdx; + const int nrOfLayers = get_dl_nrOfLayers(sched_ctrl, UE->current_DL_BWP.dci_format); + sched_ctrl->dl_max_mcs = get_mcs_from_SINRx10(mcs_table, sinr_report->SINRx10[0], nrOfLayers); + + LOG_D(MAC, "Reported SSB-SINR = %d.%d, dl_max_mcs %d\n", sinr_report->SINRx10[0] / 10, sinr_report->SINRx10[0] % 10, sched_ctrl->dl_max_mcs); } static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, @@ -558,29 +588,31 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, } rsrp_report->nr_reports = csi_report->CSI_report_bitlen.nb_ssbri_cri; - uint16_t curr_payload; - for (int i = 0; i < rsrp_report->nr_reports; i++) { - int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; - curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); - rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); - LOG_D(MAC,"SSB/CSI-RS index = %d\n", rsrp_report->resource_id[i]); - *cumul_bits += bitlen; - } + int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; + uint8_t curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); + rsrp_report->resource_id[0] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); + *cumul_bits += bitlen; curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); - int rsrp_index = curr_payload & 0x7f; + int rsrp = curr_payload & 0x7f; *cumul_bits += 7; - csi_report->nb_of_csi_ssb_report++; - bool valid = get_measured_rsrp(rsrp_index, &rsrp_report->RSRP[0]); + bool valid = get_measured_rsrp(rsrp, &rsrp_report->RSRP[0]); + LOG_D(NR_MAC, "SSB/CSI-RS index %d RSRP %d\n", rsrp_report->resource_id[0], rsrp_report->RSRP[0]); if (!valid) { - LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp_index); + LOG_E(NR_MAC, "UE %04x: reported RSRP index %d invalid\n", UE->rnti, rsrp); return; } for (int i = 1; i < rsrp_report->nr_reports; i++) { + curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); + rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); + *cumul_bits += bitlen; + curr_payload = pickandreverse_bits(payload, 4, *cumul_bits); + csi_report->nb_of_csi_ssb_report++; rsrp_report->RSRP[i] = get_diff_rsrp(curr_payload & 0x0f, rsrp_report->RSRP[0]); + LOG_D(NR_MAC, "SSB/CSI-RS index %d RSRP %d\n", rsrp_report->resource_id[i], rsrp_report->RSRP[i]); *cumul_bits += 4; } @@ -899,8 +931,13 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con nr_mac_update_pdcch_closed_loop_adjust(sched_ctrl, harq_confidence != 0); bool success = harq_value == 0 && harq_confidence == 0; handle_dl_harq(UE, pid, success, nrmac->dl_bler.harq_round_max); - if (is_ra) - nr_check_Msg4_MsgB_Ack(mod_id, frame, slot, UE, success); + if (is_ra) { + bool ue_rejected = nr_check_Msg4_MsgB_Ack(mod_id, frame, slot, UE, success); + if (ue_rejected) { + NR_SCHED_UNLOCK(&nrmac->sched_lock); + return; + } + } if (harq_confidence == 1) UE->mac_stats.pucch0_DTX++; } @@ -1245,7 +1282,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, slot_t slot) NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; const int n_slots_frame = nrmac->frame_structure.numb_slots_frame; - if (sched_ctrl->ul_failure || nr_timer_is_active(&sched_ctrl->transm_interrupt)) + if (!nr_mac_ue_is_active(UE)) continue; NR_PUCCH_Config_t *pucch_Config = ul_bwp->pucch_Config; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 2561b618f2..5ec7522492 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -38,34 +38,120 @@ //#define SRS_IND_DEBUG -int get_ul_tda(gNB_MAC_INST *nrmac, int frame, int slot) +/* \brief Get the number of UL TDAs that could be used in slot, reachable + * via specific k2. The output parameter first_idx is a pointer to the first + * suitable TDA, and the function returns the number of suitable TDAs, or 0. */ +int get_num_ul_tda(gNB_MAC_INST *nrmac, int slot, int k2, const NR_tda_info_t **first_idx) { /* we assume that this function is mutex-protected from outside */ NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock); - /* there is a mixed slot only when in TDD */ - frame_structure_t *fs = &nrmac->frame_structure; + const frame_structure_t *fs = &nrmac->frame_structure; + const int slot_period = slot % fs->numb_slots_period; + const tdd_bitmap_t *bm = &fs->period_cfg.tdd_slot_bitmap[slot_period]; + /* For some reason, we only store the number of symbols if it's mixed */ + const int num_ul_symbols = bm->slot_type == TDD_NR_MIXED_SLOT ? bm->num_ul_symbols : 14; + const uint16_t ul_bitmap = SL_to_bitmap(14 - num_ul_symbols, num_ul_symbols); - if (fs->frame_type == TDD) { - // if there is uplink symbols in mixed slot - int s = get_slot_idx_in_period(slot, fs); - tdd_bitmap_t *tdd_slot_bitmap = fs->period_cfg.tdd_slot_bitmap; - if ((tdd_slot_bitmap[s].num_ul_symbols > 1) && is_mixed_slot(s, fs)) { - return 2; + *first_idx = NULL; + FOR_EACH_SEQ_ARR(NR_tda_info_t *, tda, &nrmac->ul_tda) { + DevAssert(tda->valid_tda); + // nr_rrc_config_ul_tda() orders by k2, so skip smaller and return for + // bigger ones + if (tda->k2 < k2) + continue; + if (tda->k2 > k2) + break; // there won't be a suitable k2 anymore + + uint16_t tda_bitmap = SL_to_bitmap(tda->startSymbolIndex, tda->nrOfSymbols); + // nr_rrc_config_ul_tda() assures TDAs are from largest to smallest symbol number. + // check that this TDA fits entirely into this slot's mask (slot might be + // smaller in mixed slots)., A mixed slot TDA would be checked last, so a + // full slot TDA will be used for a full UL slot. + if ((tda_bitmap & ul_bitmap) == tda_bitmap) { // if TDA fits entiry + *first_idx = tda; + break; } } + if (*first_idx == NULL) /* nothing fit */ + return 0; - // Avoid slots with the SRS - UE_iterator(nrmac->UE_info.connected_ue_list, UE) { - NR_sched_srs_t sched_srs = UE->UE_sched_ctrl.sched_srs; - if(sched_srs.srs_scheduled && sched_srs.frame == frame && sched_srs.slot == slot) - return 1; + NR_tda_info_t *end_it = seq_arr_next(&nrmac->ul_tda, *first_idx); + while (end_it != seq_arr_end(&nrmac->ul_tda) && end_it->k2 == k2) { + /* the following TDAs should all fit as long as the k2 is the same */ + uint16_t tda_bitmap = SL_to_bitmap(end_it->startSymbolIndex, end_it->nrOfSymbols); + AssertFatal((tda_bitmap & ul_bitmap) == tda_bitmap, + "TDA should fit inside slot, but is not the case for k2 %ld bitmap 0x%04x\n", + end_it->k2, + tda_bitmap); + end_it = seq_arr_next(&nrmac->ul_tda, end_it); } - return 0; // if FDD or not mixed slot in TDD, for now use default TDA (TODO handle CSI-RS slots) + ptrdiff_t diff = seq_arr_dist(&nrmac->ul_tda, *first_idx, end_it); + AssertFatal(diff > 0 && diff <= seq_arr_size(&nrmac->ul_tda), "dist %ld\n", diff); + return diff; } -static bwp_info_t get_pusch_bwp_start_size(NR_UE_info_t *UE) +static void get_max_rb_range(const uint16_t *vrb_map_ul, const uint16_t *ulprbbl, uint16_t mask, int *rb_start, int *rb_len) +{ + int best_start = *rb_start; + int best_len = 0; + int current_start = *rb_start; + int current_len = 0; + for (int rb = *rb_start; rb < *rb_len; ++rb) { + if (ulprbbl[rb] == 0 && (mask & vrb_map_ul[rb]) == 0) { + current_len++; + continue; + } + + /* this RB is blocked for UL, or already in use */ + if (current_len > best_len) { + best_start = current_start; + best_len = current_len; + } + current_start = rb + 1; /* will start in next RB, or updated later */ + current_len = 0; + } + if (current_len > best_len) { + best_start = current_start; + best_len = current_len; + } + *rb_start = best_start; + *rb_len = best_len; +} + +const NR_tda_info_t *get_best_ul_tda(const gNB_MAC_INST *nrmac, int beam, const NR_tda_info_t *tdas, int n_tda, int frame, int slot, int *rb_start, int *rb_len) +{ + /* there is a mixed slot only when in TDD */ + const frame_structure_t *fs = &nrmac->frame_structure; + const int index = ul_buffer_index(frame, slot, fs->numb_slots_frame, nrmac->vrb_map_UL_size); + uint16_t *vrb_map_UL = &nrmac->common_channels[0].vrb_map_UL[beam][index * MAX_BWP_SIZE]; + + DevAssert(n_tda <= 16); + const NR_tda_info_t *best_tda = tdas; + uint64_t score = 0; + int check_rb_start = *rb_start; + int check_rb_len = *rb_len; + + for (int i = 0; i < n_tda; ++i, tdas++) { + int start = check_rb_start; + int len = check_rb_len; + uint16_t tda_mask = SL_to_bitmap(tdas->startSymbolIndex, tdas->nrOfSymbols); + get_max_rb_range(vrb_map_UL, nrmac->ulprbbl, tda_mask, &start, &len); + uint64_t s = (uint64_t)tdas->nrOfSymbols * len; + if (s > score) { + best_tda = tdas; + score = s; + *rb_start = start; + *rb_len = len; + } + LOG_D(NR_MAC, "%4d.%2d tda k2 %ld mask 0x%04x has PRB start/len %d/%d score %ld\n", frame, slot, tdas->k2, tda_mask, start, len, s); + } + + return best_tda; +} + +bwp_info_t get_pusch_bwp_start_size(NR_UE_info_t *UE) { NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; @@ -269,7 +355,7 @@ static rnti_t lcid_crnti_lookahead(uint8_t *pdu, uint32_t pdu_len) if (lcid == UL_SCH_LCID_C_RNTI) { // Extract C-RNTI value rnti_t crnti = ((pdu[1] & 0xFF) << 8) | (pdu[2] & 0xFF); - LOG_D(NR_MAC, "Received a MAC CE for C-RNTI with %04x\n", crnti); + LOG_A(NR_MAC, "Received a MAC CE for C-RNTI with %04x\n", crnti); return crnti; } else if (lcid == UL_SCH_LCID_PADDING) { // End of MAC PDU, can ignore the remaining bytes @@ -399,6 +485,7 @@ static int nr_process_mac_pdu(instance_t module_idP, UE->mac_stats.ul.total_sdu_bytes += mac_len; UE->mac_stats.ul.lc_bytes[lcid] += mac_len; } + T(T_GNB_MAC_LCID_UL, T_INT(UE->rnti), T_INT(frameP), T_INT(slot), T_INT(lcid), T_INT(mac_len * 8)); break; case UL_SCH_LCID_DTCH ...(UL_SCH_LCID_DTCH + 28): @@ -426,6 +513,7 @@ static int nr_process_mac_pdu(instance_t module_idP, else sched_ctrl->estimated_ul_buffer = 0; } + T(T_GNB_MAC_LCID_UL, T_INT(UE->rnti), T_INT(frameP), T_INT(slot), T_INT(lcid), T_INT(mac_len * 8)); break; case UL_SCH_LCID_RECOMMENDED_BITRATE_QUERY: @@ -507,6 +595,7 @@ static int nr_process_mac_pdu(instance_t module_idP, /* Extract short BSR value */ ce_ptr = &pduP[mac_subheader_len]; sched_ctrl->estimated_ul_buffer = estimate_ul_buffer_short_bsr((NR_BSR_SHORT *)ce_ptr); + sched_ctrl->sched_ul_bytes = 0; LOG_D(NR_MAC, "SHORT BSR at %4d.%2d, est buf %d\n", frameP, slot, sched_ctrl->estimated_ul_buffer); break; @@ -515,6 +604,7 @@ static int nr_process_mac_pdu(instance_t module_idP, /* Extract long BSR value */ ce_ptr = &pduP[mac_subheader_len]; sched_ctrl->estimated_ul_buffer = estimate_ul_buffer_long_bsr((NR_BSR_LONG *)ce_ptr); + sched_ctrl->sched_ul_bytes = 0; LOG_D(NR_MAC, "LONG BSR at %4d.%2d, estim buf %d\n", frameP, slot, sched_ctrl->estimated_ul_buffer); break; @@ -660,6 +750,7 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, rnti_t rnti, uint8_t *sdu, const uint32_t sdu_len, + uint8_t harq_pid, const uint16_t timing_advance, const uint8_t ul_cqi, const uint16_t rssi) @@ -725,9 +816,11 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frame, slot, rnti); NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl; + DevAssert(harq_pid >= 0 && harq_pid < 8); if (ul_cqi != 0xff) { - UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30, UE_scheduling_control->sched_pusch.phr_txpower_calc); - UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - UE_scheduling_control->sched_pusch.phr_txpower_calc * 10; + NR_UE_ul_harq_t *harq = &UE_scheduling_control->ul_harq_processes[harq_pid]; + UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30, harq->sched_pusch.phr_txpower_calc); + UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - harq->sched_pusch.phr_txpower_calc * 10; } if (timing_advance != 0xffff) UE_scheduling_control->ta_update = timing_advance; @@ -783,26 +876,33 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, // Reset HARQ processes reset_dl_harq_list(&old_UE->UE_sched_ctrl); reset_ul_harq_list(&old_UE->UE_sched_ctrl); - // Trigger RRC Reconfiguration - LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti); - nr_mac_trigger_reconfiguration(mac, old_UE); + + // Only trigger RRCReconfiguration if UE is not performing RRCReestablishment + // The RRCReconfiguration will be triggered by the RRCReestablishmentComplete + if (!old_UE->reconfigSpCellConfig) { + LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti); + // Trigger RRCReconfiguration + nr_mac_trigger_reconfiguration(mac, old_UE, -1); + // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration + configure_UE_BWP(mac, scc, old_UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); + } nr_release_ra_UE(mac, rnti); - LOG_A(NR_MAC, "%4d.%2d UE %04x: RA with C-RNTI complete\n", frame, slot, crnti); - // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration - configure_UE_BWP(mac, scc, old_UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); - // TODO do we actually need to still process the PDU? + LOG_A(NR_MAC, "%4d.%2d RA with C-RNTI %04x complete\n", frame, slot, crnti); + + // Decode the entire MAC PDU + // It may have multiple MAC subPDUs, for example, a MAC subPDU with LCID 1 caring a RRCReestablishmentComplete nr_process_mac_pdu(mod_id, old_UE, CC_id, frame, slot, sdu, sdu_len, -1); return; - } else { - // UE Contention Resolution Identity - // Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4 - // First byte corresponds to R/LCID MAC sub-header - memcpy(ra->cont_res_id, &sdu[1], sizeof(uint8_t) * 6); } - // Decode MAC PDU for the correct UE, after checking for MAC CE for C-RNTI - // harq_pid set a non valid value because it is not used in this call + // UE Contention Resolution Identity + // Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4 + // First byte corresponds to R/LCID MAC sub-header + memcpy(ra->cont_res_id, &sdu[1], sizeof(uint8_t) * 6); + + // Decode MAC PDU // the function is only called to decode the contention resolution sub-header + // harq_pid set a non-valid value because it is not used in this call nr_process_mac_pdu(mod_id, UE, CC_id, frame, slot, sdu, sdu_len, -1); LOG_I(NR_MAC, @@ -928,7 +1028,9 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, if (!get_softmodem_params()->phy_test && UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt >= pusch_failure_thres) { LOG_W(NR_MAC, - "UE %04x: Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", + "%4d.%2d UE %04x: Detected UL Failure on PUSCH after %d PUSCH DTX, stopping scheduling\n", + frameP, + slotP, UE->rnti, UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt); nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); @@ -936,7 +1038,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, } handle_nr_ul_harq(gNB_mac, UE, frameP, slotP, current_rnti, harq_pid, sduP == NULL); } else { - nr_rx_ra_sdu(gnb_mod_idP, CC_idP, frameP, slotP, current_rnti, sduP, sdu_lenP, timing_advance, ul_cqi, rssi); + nr_rx_ra_sdu(gnb_mod_idP, CC_idP, frameP, slotP, current_rnti, sduP, sdu_lenP, harq_pid, timing_advance, ul_cqi, rssi); } } @@ -954,7 +1056,9 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP, { gNB_MAC_INST *gNB_mac = RC.nrmac[gnb_mod_idP]; NR_SCHED_LOCK(&gNB_mac->sched_lock); + start_meas(&gNB_mac->rx_ulsch_sdu); _nr_rx_sdu(gnb_mod_idP, CC_idP, frameP, slotP, rntiP, sduP, sdu_lenP, harq_pid, timing_advance, ul_cqi, rssi); + stop_meas(&gNB_mac->rx_ulsch_sdu); NR_SCHED_UNLOCK(&gNB_mac->sched_lock); } @@ -1400,8 +1504,17 @@ void handle_nr_srs_measurements(const module_id_t module_id, nfapi_nr_srs_indication_pdu_t *srs_ind) { gNB_MAC_INST *nrmac = RC.nrmac[module_id]; - NR_SCHED_LOCK(&nrmac->sched_lock); LOG_D(NR_MAC, "(%d.%d) Received SRS indication for UE %04x\n", frame, slot, srs_ind->rnti); + if (srs_ind->report_type == 0) { + //SCF 222.10.04 Table 3-129 Report type = 0 means a null report, we can skip unpacking it + return; + } + + if (srs_ind->timing_advance_offset == 0xFFFF) { + LOG_W(NR_MAC, "Invalid timing advance offset for RNTI %04x\n", srs_ind->rnti); + return; + } + NR_SCHED_LOCK(&nrmac->sched_lock); #ifdef SRS_IND_DEBUG LOG_I(NR_MAC, "frame = %i\n", frame); @@ -1420,12 +1533,6 @@ void handle_nr_srs_measurements(const module_id_t module_id, return; } - if (srs_ind->timing_advance_offset == 0xFFFF) { - LOG_W(NR_MAC, "Invalid timing advance offset for RNTI %04x\n", srs_ind->rnti); - NR_SCHED_UNLOCK(&nrmac->sched_lock); - return; - } - gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; NR_mac_stats_t *stats = &UE->mac_stats; nfapi_srs_report_tlv_t *report_tlv = &srs_ind->report_tlv; @@ -1546,25 +1653,6 @@ void handle_nr_srs_measurements(const module_id_t module_id, NR_SCHED_UNLOCK(&nrmac->sched_lock); } -long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList, - int time_domain_assignment, - int mu, - const NR_ServingCellConfigCommon_t *scc) -{ - /* we assume that this function is mutex-protected from outside */ - NR_PUSCH_TimeDomainResourceAllocation_t *tda = tdaList->list.array[time_domain_assignment]; - const int NTN_gNB_Koffset = get_NTN_Koffset(scc); - - if (tda->k2) - return *tda->k2 + NTN_gNB_Koffset; - else if (mu < 2) - return 1 + NTN_gNB_Koffset; - else if (mu == 2) - return 2 + NTN_gNB_Koffset; - else - return 3 + NTN_gNB_Koffset; -} - static bool nr_UE_is_to_be_scheduled(const frame_structure_t *fs, NR_UE_info_t *UE, frame_t frame, @@ -1688,19 +1776,23 @@ static void nr_ue_max_mcs_min_rb(int mu, } static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, - frame_t frame, - slot_t slot, - uint16_t *rballoc_mask, - int *n_rb_sched, - int dci_beam_idx, - NR_UE_info_t* UE, - int harq_pid, - const NR_ServingCellConfigCommon_t *scc, - const int tda) + post_process_pusch_t *pp_pusch, + uint16_t *rballoc_mask, + int *n_rb_sched, + int dci_beam_idx, + NR_UE_info_t *UE, + int harq_pid, + const NR_ServingCellConfigCommon_t *scc, + const int tda, + const NR_tda_info_t *tda_info) { const int CC_id = 0; + int frame = pp_pusch->frame; + int slot = pp_pusch->slot; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_sched_pusch_t *retInfo = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch; + /* Get previous PUSCH field info */ + const NR_sched_pusch_t *retInfo = &sched_ctrl->ul_harq_processes[harq_pid].sched_pusch; + NR_sched_pusch_t new_sched = *retInfo; // potential new allocation NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; int rbStart = 0; // wrt BWP start @@ -1709,16 +1801,15 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, const uint32_t bwpStart = bwp_info.bwpStart; const uint8_t nrOfLayers = retInfo->nrOfLayers; LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda); - LOG_D(NR_MAC,"tbs %d\n",retInfo->tb_size); - NR_tda_info_t tda_info = get_ul_tda_info(ul_bwp, - sched_ctrl->coreset->controlResourceSetId, - sched_ctrl->search_space->searchSpaceType->present, - TYPE_C_RNTI_, - tda); - if (!tda_info.valid_tda) - return false; - bool reuse_old_tda = (retInfo->tda_info.startSymbolIndex == tda_info.startSymbolIndex) && (retInfo->tda_info.nrOfSymbols <= tda_info.nrOfSymbols); + /* mark when retransmission will happen */ + int slots_frame = nrmac->frame_structure.numb_slots_frame; + new_sched.frame = (frame + (slot + tda_info->k2 + get_NTN_Koffset(scc)) / slots_frame) % MAX_FRAME_NUMBER; + new_sched.slot = (slot + tda_info->k2 + get_NTN_Koffset(scc)) % slots_frame; + new_sched.bwp_info = bwp_info; + DevAssert(new_sched.ul_harq_pid == harq_pid); + + bool reuse_old_tda = retInfo->time_domain_allocation == tda; if (reuse_old_tda && nrOfLayers == retInfo->nrOfLayers) { /* Check the resource is enough for retransmission */ const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols); @@ -1734,12 +1825,13 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, bwpSize); return false; } + new_sched.rbStart = rbStart; LOG_D(NR_MAC, "Retransmission keeping TDA %d and TBS %d\n", tda, retInfo->tb_size); } else { - NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc, ul_bwp, &tda_info, nrOfLayers); + NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc, ul_bwp, tda_info, nrOfLayers); /* the retransmission will use a different time domain allocation, check * that we have enough resources */ - const uint16_t slbitmap = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols); + const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap)) rbStart++; int rbSize = 0; @@ -1751,7 +1843,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, retInfo->R, UE->current_UL_BWP.transform_precoding, nrOfLayers, - tda_info.nrOfSymbols, + tda_info->nrOfSymbols, dmrs_info.N_PRB_DMRS * dmrs_info.num_dmrs_symb, retInfo->tb_size, 1, /* minimum of 1RB: need to find exact TBS, don't preclude any number */ @@ -1770,11 +1862,12 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, LOG_D(NR_MAC, "Retransmission with TDA %d->%d and TBS %d -> %d\n", retInfo->time_domain_allocation, tda, retInfo->tb_size, new_tbs); /* we can allocate it. Overwrite the time_domain_allocation, the number * of RBs, and the new TB size. The rest is done below */ - retInfo->tb_size = new_tbs; - retInfo->rbSize = new_rbSize; - retInfo->time_domain_allocation = tda; - retInfo->dmrs_info = dmrs_info; - retInfo->tda_info = tda_info; + new_sched.rbSize = new_rbSize; + new_sched.rbStart = rbStart; + new_sched.tb_size = new_tbs; + new_sched.time_domain_allocation = tda; + new_sched.tda_info = *tda_info; + new_sched.dmrs_info = dmrs_info; } /* Find a free CCE */ @@ -1787,91 +1880,110 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, - false, sched_ctrl->pdcch_cl_adjust); if (CCEIndex<0) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for retransmission UL DCI UE\n", UE->rnti, frame, slot); + sched_ctrl->ul_cce_fail++; return false; } sched_ctrl->cce_index = CCEIndex; fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, dci_beam_idx); - int slots_frame = nrmac->frame_structure.numb_slots_frame; - retInfo->frame = (frame + (slot + tda_info.k2) / slots_frame) % MAX_FRAME_NUMBER; - retInfo->slot = (slot + tda_info.k2) % slots_frame; - /* Get previous PSUCH field info */ - sched_ctrl->sched_pusch = *retInfo; - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; + // signal new allocation + DevAssert(new_sched.time_domain_allocation == tda); + post_process_ulsch(nrmac, pp_pusch, UE, &new_sched); LOG_D(NR_MAC, "%4d.%2d Allocate UL retransmission RNTI %04x sched %4d.%2d (%d RBs)\n", frame, slot, UE->rnti, - sched_pusch->frame, - sched_pusch->slot, - sched_pusch->rbSize); - - sched_pusch->rbStart = rbStart; - /* no need to recompute the TBS, it will be the same */ + new_sched.frame, + new_sched.slot, + new_sched.rbSize); /* Mark the corresponding RBs as used */ - n_rb_sched -= sched_pusch->rbSize; - for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); + n_rb_sched -= new_sched.rbSize; + for (int rb = bwpStart; rb < new_sched.rbSize; rb++) + rballoc_mask[rb + new_sched.rbStart] |= SL_to_bitmap(new_sched.tda_info.startSymbolIndex, new_sched.tda_info.nrOfSymbols); return true; } static uint32_t ul_pf_tbs[5][29]; // pre-computed, approximate TBS values for PF coefficient typedef struct UEsched_s { float coef; + bool sched_inactive; NR_UE_info_t * UE; + int selected_mcs; } UEsched_t; -static int comparator(const void *p, const void *q) { - return ((UEsched_t*)p)->coef < ((UEsched_t*)q)->coef; +static int comparator(const void *p, const void *q) +{ + const UEsched_t *pp = p; + const UEsched_t *qq = q; + if (pp->sched_inactive && qq->sched_inactive) + return 0; + else if (pp->sched_inactive) + return -1; + else if (qq->sched_inactive) + return 1; + /* both UEs are !sched_inactive */ + if (pp->coef < qq->coef) + return 1; + else if (pp->coef > qq->coef) + return -1; + return 0; } -static void pf_ul(module_id_t module_id, - frame_t frame, - int slot, - frame_t sched_frame, - int sched_slot, +static int pf_ul(gNB_MAC_INST *nrmac, + post_process_pusch_t *pp_pusch, + int tda, + const NR_tda_info_t *tda_info, NR_UE_info_t *UE_list[], int max_num_ue, int num_beams, int n_rb_sched[num_beams]) { const int CC_id = 0; - gNB_MAC_INST *nrmac = RC.nrmac[module_id]; + int frame = pp_pusch->frame; + int slot = pp_pusch->slot; NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon; int slots_per_frame = nrmac->frame_structure.numb_slots_frame; + DevAssert(tda_info->valid_tda); + const int k2 = tda_info->k2 + get_NTN_Koffset(scc); + const int sched_frame = (frame + (slot + k2) / slots_per_frame) % MAX_FRAME_NUMBER; + const int sched_slot = (slot + k2) % slots_per_frame; + DevAssert(is_ul_slot(sched_slot, &nrmac->frame_structure)); + const int min_rb = nrmac->min_grant_prb; // UEs that could be scheduled UEsched_t UE_sched[MAX_MOBILES_PER_GNB + 1] = {0}; int remainUEs[num_beams]; for (int i = 0; i < num_beams; i++) remainUEs[i] = max_num_ue; - int curUE = 0; + int numUE = 0; + bool scheduled_something = false; /* Loop UE_list to calculate throughput and coeff */ UE_iterator(UE_list, UE) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - if (sched_ctrl->ul_failure) + if (!nr_mac_ue_is_active(UE)) continue; LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti); NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; - const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul; + NR_mac_dir_stats_t *stats = &UE->mac_stats.ul; /* Calculate throughput */ const float a = 0.01f; const uint32_t b = stats->current_bytes; UE->ul_thr_ue = (1 - a) * UE->ul_thr_ue + a * b; + stats->current_bytes = 0; + stats->current_rbs = 0; + int total_rem_ues = 0; for (int i = 0; i < num_beams; i++) total_rem_ues += remainUEs[i]; @@ -1894,21 +2006,20 @@ static void pf_ul(module_id_t module_id, uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; /* Check if retransmission is necessary */ - sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head; - LOG_D(NR_MAC,"pf_ul: UE %04x harq_pid %d\n", UE->rnti, sched_pusch->ul_harq_pid); - if (sched_pusch->ul_harq_pid >= 0) { + int ul_harq_pid = sched_ctrl->retrans_ul_harq.head; + LOG_D(NR_MAC,"pf_ul: UE %04x harq_pid %d\n", UE->rnti, ul_harq_pid); + if (ul_harq_pid >= 0) { /* Allocate retransmission*/ - const int tda = get_ul_tda(nrmac, sched_frame, sched_slot); bool r = allocate_ul_retransmission(nrmac, - frame, - slot, + pp_pusch, rballoc_mask, &n_rb_sched[beam.idx], dci_beam.idx, UE, - sched_pusch->ul_harq_pid, + ul_harq_pid, scc, - tda); + tda, + tda_info); if (!r) { LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UL retransmission could not be allocated\n", UE->rnti, frame, slot); reset_beam_status(&nrmac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_per_frame, beam.new_beam); @@ -1920,8 +2031,10 @@ static void pf_ul(module_id_t module_id, /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ remainUEs[beam.idx]--; + scheduled_something = true; continue; } + DevAssert(ul_harq_pid == -1); // all other allocations must be new ones /* skip this UE if there are no free HARQ processes. This can happen e.g. * if the UE disconnected in L2sim, in which case the gNB is not notified @@ -1951,141 +2064,46 @@ static void pf_ul(module_id_t module_id, const NR_bler_options_t *bo = &nrmac->ul_bler; const int max_mcs_table = (current_BWP->mcs_table == 0 || current_BWP->mcs_table == 2) ? 28 : 27; const int max_mcs = min(bo->max_mcs, max_mcs_table); /* no per-user maximum MCS yet */ + int selected_mcs; if (bo->harq_round_max == 1) { - sched_pusch->mcs = max_mcs; - sched_ctrl->ul_bler_stats.mcs = sched_pusch->mcs; + int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); + selected_mcs = get_mcs_from_SINRx10(current_BWP->mcs_table, sched_ctrl->pusch_snrx10, nrOfLayers); + selected_mcs = min(max_mcs, selected_mcs); + selected_mcs = max(bo->min_mcs, selected_mcs); + sched_ctrl->ul_bler_stats.mcs = selected_mcs; } else { - sched_pusch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->ul_bler_stats, max_mcs, frame); - LOG_D(NR_MAC, "%d.%d starting mcs %d bler %f\n", frame, slot, sched_pusch->mcs, sched_ctrl->ul_bler_stats.bler); - } - /* Schedule UE on SR or UL inactivity and no data (otherwise, will be scheduled - * based on data to transmit) */ - if (B == 0 && do_sched) { - /* if no data, pre-allocate 5RB */ - /* Find a free CCE */ - int CCEIndex = get_cce_index(nrmac, - CC_id, slot, UE->rnti, - &sched_ctrl->aggregation_level, - dci_beam.idx, - sched_ctrl->search_space, - sched_ctrl->coreset, - &sched_ctrl->sched_pdcch, - false, - sched_ctrl->pdcch_cl_adjust); - if (CCEIndex < 0) { - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI (BSR 0)\n", UE->rnti, frame, slot); - reset_beam_status(&nrmac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_per_frame, beam.new_beam); - reset_beam_status(&nrmac->beam_info, frame, slot, UE->UE_beam_index, slots_per_frame, dci_beam.new_beam); - continue; - } - - sched_pusch->nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); - sched_pusch->time_domain_allocation = get_ul_tda(nrmac, sched_frame, sched_slot); - sched_pusch->tda_info = get_ul_tda_info(current_BWP, - sched_ctrl->coreset->controlResourceSetId, - sched_ctrl->search_space->searchSpaceType->present, - TYPE_C_RNTI_, - sched_pusch->time_domain_allocation); - AssertFatal(sched_pusch->tda_info.valid_tda, "Invalid TDA from get_ul_tda_info\n"); - sched_pusch->dmrs_info = get_ul_dmrs_params(scc, current_BWP, &sched_pusch->tda_info, sched_pusch->nrOfLayers); - - int rbStart = 0; // wrt BWP start - LOG_D(NR_MAC, - "Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n", - min_rb, - rbStart, - sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data); - bwp_info_t bwp_info = get_pusch_bwp_start_size(UE); - const uint32_t bwpStart = bwp_info.bwpStart; - const uint32_t bwpSize = bwp_info.bwpSize; - const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); - while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap)) - rbStart++; - if (rbStart + min_rb > bwpSize) { - LOG_D(NR_MAC, - "[UE %04x][%4d.%2d] could not allocate continuous UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n", - UE->rnti, - frame, - slot, - rbStart, - min_rb, - bwpSize); - reset_beam_status(&nrmac->beam_info, sched_frame, sched_slot, UE->UE_beam_index, slots_per_frame, beam.new_beam); - reset_beam_status(&nrmac->beam_info, frame, slot, UE->UE_beam_index, slots_per_frame, dci_beam.new_beam); - continue; - } - - sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, dci_beam.idx); - - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; - update_ul_ue_R_Qm(sched_pusch->mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched_pusch->R, &sched_pusch->Qm); - sched_pusch->rbStart = rbStart; - sched_pusch->rbSize = min_rb; - sched_pusch->frame = sched_frame; - sched_pusch->slot = sched_slot; - sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm, - sched_pusch->R, - sched_pusch->rbSize, - sched_pusch->tda_info.nrOfSymbols, - sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb, - 0, // nb_rb_oh - 0, - sched_pusch->nrOfLayers) >> 3; - long *deltaMCS = current_BWP->pusch_Config ? current_BWP->pusch_Config->pusch_PowerControl->deltaMCS : NULL; - - sched_pusch->phr_txpower_calc = compute_ph_factor(current_BWP->scs, - sched_pusch->tb_size << 3, - sched_pusch->rbSize, - sched_pusch->nrOfLayers, - sched_pusch->tda_info.nrOfSymbols, - sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb, - deltaMCS, - false); - LOG_D(NR_MAC, - "pf_ul %d.%d UE %x Scheduling PUSCH (no data) nrb %d mcs %d tbs %d bits phr_txpower %d\n", - frame, - slot, - UE->rnti, - sched_pusch->rbSize, - sched_pusch->mcs, - sched_pusch->tb_size << 3, - sched_pusch->phr_txpower_calc); - - /* Mark the corresponding RBs as used */ - n_rb_sched[beam.idx] -= sched_pusch->rbSize; - for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap; - - remainUEs[beam.idx]--; - continue; + selected_mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->ul_bler_stats, max_mcs, frame); + LOG_D(NR_MAC, "%d.%d starting mcs %d bler %f\n", frame, slot, selected_mcs, sched_ctrl->ul_bler_stats.bler); } /* Create UE_sched for UEs eligibale for new data transmission*/ /* Calculate coefficient*/ - const uint32_t tbs = ul_pf_tbs[current_BWP->mcs_table][sched_pusch->mcs]; + const uint32_t tbs = ul_pf_tbs[current_BWP->mcs_table][selected_mcs]; float coeff_ue = (float) tbs / UE->ul_thr_ue; - LOG_D(NR_MAC, "[UE %04x][%4d.%2d] b %d, ul_thr_ue %f, tbs %d, coeff_ue %f\n", + bool sched_inactive = B == 0 && do_sched; + LOG_D(NR_MAC, "[UE %04x][%4d.%2d] b %d, ul_thr_ue %f, tbs %d, coeff_ue %f, sched_inactive %d\n", UE->rnti, frame, slot, b, UE->ul_thr_ue, tbs, - coeff_ue); - UE_sched[curUE].coef = coeff_ue; - UE_sched[curUE].UE = UE; - curUE++; + coeff_ue, + sched_inactive); + UE_sched[numUE].coef = coeff_ue; + UE_sched[numUE].sched_inactive = sched_inactive; + UE_sched[numUE].UE = UE; + UE_sched[numUE].selected_mcs = selected_mcs; + numUE++; } - qsort(UE_sched, sizeofArray(UE_sched), sizeof(UEsched_t), comparator); + qsort(UE_sched, numUE, sizeof(UEsched_t), comparator); UEsched_t *iterator=UE_sched; /* Loop UE_sched to find max coeff and allocate transmission */ while (iterator->UE != NULL) { NR_UE_UL_BWP_t *current_BWP = &iterator->UE->current_UL_BWP; NR_UE_sched_ctrl_t *sched_ctrl = &iterator->UE->UE_sched_ctrl; - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; NR_beam_alloc_t beam = beam_allocation_procedure(&nrmac->beam_info, sched_frame, sched_slot, iterator->UE->UE_beam_index, slots_per_frame); if (beam.idx < 0) { @@ -2115,10 +2133,10 @@ static void pf_ul(module_id_t module_id, sched_ctrl->search_space, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, - false, sched_ctrl->pdcch_cl_adjust); if (CCEIndex < 0) { + sched_ctrl->ul_cce_fail++; reset_beam_status(&nrmac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, dci_beam.new_beam); reset_beam_status(&nrmac->beam_info, sched_frame, sched_slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam); LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for UL DCI\n", iterator->UE->rnti, frame, slot); @@ -2128,34 +2146,24 @@ static void pf_ul(module_id_t module_id, else LOG_D(NR_MAC, "%4d.%2d free CCE for UL DCI UE %04x\n", frame, slot, iterator->UE->rnti); - - - sched_pusch->nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); - sched_pusch->time_domain_allocation = get_ul_tda(nrmac, sched_frame, sched_slot); - sched_pusch->tda_info = get_ul_tda_info(current_BWP, - sched_ctrl->coreset->controlResourceSetId, - sched_ctrl->search_space->searchSpaceType->present, - TYPE_C_RNTI_, - sched_pusch->time_domain_allocation); - AssertFatal(sched_pusch->tda_info.valid_tda, "Invalid TDA from get_ul_tda_info\n"); - sched_pusch->dmrs_info = get_ul_dmrs_params(scc, current_BWP, &sched_pusch->tda_info, sched_pusch->nrOfLayers); - const int index = ul_buffer_index(sched_frame, sched_slot, slots_per_frame, nrmac->vrb_map_UL_size); uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[beam.idx][index * MAX_BWP_SIZE]; + /* find maximum amount of RBs that we can schedule starting from first free RB */ int rbStart = 0; - const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols); - bwp_info_t bwp_info = get_pusch_bwp_start_size(iterator->UE); - const uint32_t bwpStart = bwp_info.bwpStart; - const uint32_t bwpSize = bwp_info.bwpSize; - while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap)) + const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols); + bwp_info_t bi = get_pusch_bwp_start_size(iterator->UE); + while (rbStart < bi.bwpSize && (rballoc_mask[rbStart + bi.bwpStart] & slbitmap)) rbStart++; - sched_pusch->rbStart = rbStart; - uint16_t max_rbSize = 10; // used to be 1 - /* while (rbStart + max_rbSize < bwpSize && !(rballoc_mask[rbStart + bwpStart + max_rbSize] & slbitmap)) */ - /* max_rbSize++; */ + /* if it's for inactivity, min_grant_prb is enough, otherwise check what + * would be the maximum */ + /* uint16_t max_rbSize = iterator->sched_inactive ? min_rb : bi.bwpSize; */ + uint16_t max_rbSize = 10; + uint16_t available_rb = 1; + while (rbStart + available_rb < bi.bwpSize && !(rballoc_mask[rbStart + bi.bwpStart + available_rb] & slbitmap) && available_rb < max_rbSize) + available_rb++; - if (rbStart + min_rb > bwpSize || max_rbSize < min_rb) { + if (rbStart + min_rb > bi.bwpSize || available_rb < min_rb) { reset_beam_status(&nrmac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, dci_beam.new_beam); reset_beam_status(&nrmac->beam_info, sched_frame, sched_slot, iterator->UE->UE_beam_index, slots_per_frame, beam.new_beam); LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n", @@ -2164,121 +2172,534 @@ static void pf_ul(module_id_t module_id, slot, rbStart, min_rb, - bwpSize); + bi.bwpSize); iterator++; continue; } else LOG_D(NR_MAC, - "allocating UL data for RNTI %04x (rbStart %d, min_rb %d, max_rbSize %d, bwpSize %d)\n", + "allocating UL data for RNTI %04x (rbStart %d, min_rb %d, available_rb %d, bwpSize %d)\n", iterator->UE->rnti, rbStart, min_rb, - max_rbSize, - bwpSize); + available_rb, + bi.bwpSize); + + int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format); + NR_sched_pusch_t sched = { + .frame = sched_frame, + .slot = sched_slot, + // rbSize set further below + .rbStart = rbStart, + .mcs = iterator->selected_mcs, + // R, Qm, tb_size set further below + .ul_harq_pid = -1, // new transmission + .nrOfLayers = nrOfLayers, + // tpmi in post-process + .time_domain_allocation = tda, + .tda_info = *tda_info, + .dmrs_info = get_ul_dmrs_params(scc, current_BWP, tda_info, nrOfLayers), + .bwp_info = bi, + // phr_txpower_calc below + }; /* Calculate the current scheduling bytes */ const int B = cmax(sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, 0); - /* adjust rbSize and MCS according to PHR and BPRE */ - if(sched_ctrl->pcmax != 0 || sched_ctrl->ph != 0) // verify if the PHR related parameter have been initialized - nr_ue_max_mcs_min_rb(current_BWP->scs, sched_ctrl->ph, sched_pusch, current_BWP, min_rb, B, &max_rbSize, &sched_pusch->mcs); + /* adjust rbSize and MCS according to PHR and BPRE, only if there is data */ + if((sched_ctrl->pcmax != 0 || sched_ctrl->ph != 0) && B > 0) + nr_ue_max_mcs_min_rb(current_BWP->scs, sched_ctrl->ph, &sched, current_BWP, min_rb, B, &available_rb, &sched.mcs); - if (sched_pusch->mcs < sched_ctrl->ul_bler_stats.mcs) - sched_ctrl->ul_bler_stats.mcs = sched_pusch->mcs; /* force estimated MCS down */ + if (sched.mcs < sched_ctrl->ul_bler_stats.mcs) + sched_ctrl->ul_bler_stats.mcs = sched.mcs; /* force estimated MCS down */ - update_ul_ue_R_Qm(sched_pusch->mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched_pusch->R, &sched_pusch->Qm); - uint16_t rbSize = 0; - uint32_t TBS = 0; - nr_find_nb_rb(sched_pusch->Qm, - sched_pusch->R, - current_BWP->transform_precoding, - sched_pusch->nrOfLayers, - sched_pusch->tda_info.nrOfSymbols, - sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb, - B, - min_rb, - max_rbSize, - &TBS, - &rbSize); + update_ul_ue_R_Qm(sched.mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched.R, &sched.Qm); + if (!iterator->sched_inactive) { + // this UE has data, find optimal number of RB for data and in range + // [min_rb,available_rb] + nr_find_nb_rb(sched.Qm, + sched.R, + current_BWP->transform_precoding, + sched.nrOfLayers, + sched.tda_info.nrOfSymbols, + sched.dmrs_info.N_PRB_DMRS * sched.dmrs_info.num_dmrs_symb, + B, + min_rb, + available_rb, + &sched.tb_size, + &sched.rbSize); + } else { + // this UE is scheduled due to SR or inactivity and no data + sched.rbSize = min_rb; + sched.tb_size = nr_compute_tbs(sched.Qm, + sched.R, + sched.rbSize, + sched.tda_info.nrOfSymbols, + sched.dmrs_info.N_PRB_DMRS * sched.dmrs_info.num_dmrs_symb, + 0, // nb_rb_oh + 0, + sched.nrOfLayers) + >> 3; + } // Calacualte the normalized tx_power for PHR long *deltaMCS = current_BWP->pusch_Config ? current_BWP->pusch_Config->pusch_PowerControl->deltaMCS : NULL; - int tbs_bits = TBS << 3; + int tbs_bits = sched.tb_size << 3; - sched_pusch->phr_txpower_calc = compute_ph_factor(current_BWP->scs, - tbs_bits, - rbSize, - sched_pusch->nrOfLayers, - sched_pusch->tda_info.nrOfSymbols, - sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb, - deltaMCS, - false); + sched.phr_txpower_calc = compute_ph_factor(current_BWP->scs, + tbs_bits, + sched.rbSize, + sched.nrOfLayers, + sched.tda_info.nrOfSymbols, + sched.dmrs_info.N_PRB_DMRS * sched.dmrs_info.num_dmrs_symb, + deltaMCS, + false); - sched_pusch->rbSize = rbSize; - sched_pusch->tb_size = TBS; - sched_pusch->frame = sched_frame; - sched_pusch->slot = sched_slot; LOG_D(NR_MAC, - "rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", - rbSize, - max_rbSize, - sched_pusch->tb_size, + "rbSize %d (available_rb %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n", + sched.rbSize, + available_rb, + sched.tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B, sched_ctrl->cce_index, - sched_pusch->dmrs_info.num_dmrs_symb, - sched_pusch->dmrs_info.N_PRB_DMRS); + sched.dmrs_info.num_dmrs_symb, + sched.dmrs_info.N_PRB_DMRS); /* Mark the corresponding RBs as used */ sched_ctrl->cce_index = CCEIndex; fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, dci_beam.idx); - n_rb_sched[beam.idx] -= sched_pusch->rbSize; - for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++) - rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap; + /* save allocation to FAPI structures */ + post_process_ulsch(nrmac, pp_pusch, iterator->UE, &sched); + + n_rb_sched[beam.idx] -= sched.rbSize; + for (int rb = bi.bwpStart; rb < sched.rbSize; rb++) + rballoc_mask[rb + sched.rbStart] |= slbitmap; /* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */ remainUEs[beam.idx]--; iterator++; + scheduled_something = true; + } + int num_ue_sched = num_beams * max_num_ue; + for (int i = 0; i < num_beams; i++) + num_ue_sched -= remainUEs[i]; + DevAssert((num_ue_sched == 0 && !scheduled_something) || (num_ue_sched > 0 && scheduled_something)); + return num_ue_sched; +} + +nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti_req, + const NR_UE_info_t *UE, + const NR_ServingCellConfigCommon_t *scc, + const NR_sched_pusch_t *sched_pusch, + int transform_precoding, + int harq_id, + int harq_round, + int fh, + int rnti) +{ + nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu; + memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); + const NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; + + pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; + pusch_pdu->rnti = rnti; + pusch_pdu->handle = 0; //not yet used + pusch_pdu->bwp_size = sched_pusch->bwp_info.bwpSize; + pusch_pdu->bwp_start = sched_pusch->bwp_info.bwpStart; + pusch_pdu->subcarrier_spacing = ul_bwp->scs; + pusch_pdu->cyclic_prefix = 0; + pusch_pdu->target_code_rate = sched_pusch->R; + pusch_pdu->qam_mod_order = sched_pusch->Qm; + pusch_pdu->mcs_index = sched_pusch->mcs; + pusch_pdu->mcs_table = ul_bwp->mcs_table; + pusch_pdu->transform_precoding = transform_precoding; + if (ul_bwp->pusch_Config && ul_bwp->pusch_Config->dataScramblingIdentityPUSCH) + pusch_pdu->data_scrambling_id = *ul_bwp->pusch_Config->dataScramblingIdentityPUSCH; + else + pusch_pdu->data_scrambling_id = *scc->physCellId; + pusch_pdu->nrOfLayers = sched_pusch->nrOfLayers; + // DMRS + pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data; + pusch_pdu->dmrs_ports = ((1 << sched_pusch->nrOfLayers) - 1); + pusch_pdu->ul_dmrs_symb_pos = sched_pusch->dmrs_info.ul_dmrs_symb_pos; + pusch_pdu->dmrs_config_type = sched_pusch->dmrs_info.dmrs_config_type; + pusch_pdu->scid = sched_pusch->dmrs_info.scid; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1] + pusch_pdu->pusch_identity = sched_pusch->dmrs_info.pusch_identity; + pusch_pdu->ul_dmrs_scrambling_id = sched_pusch->dmrs_info.dmrs_scrambling_id; + /* Allocation in frequency domain */ + pusch_pdu->resource_alloc = 1; //type 1 + pusch_pdu->rb_start = sched_pusch->rbStart; + pusch_pdu->rb_size = sched_pusch->rbSize; + pusch_pdu->vrb_to_prb_mapping = 0; + pusch_pdu->frequency_hopping = fh; + /* Resource Allocation in time domain */ + pusch_pdu->start_symbol_index = sched_pusch->tda_info.startSymbolIndex; + pusch_pdu->nr_of_symbols = sched_pusch->tda_info.nrOfSymbols; + /* PUSCH PDU */ + pusch_pdu->pusch_data.rv_index = nr_get_rv(harq_round % 4); + pusch_pdu->pusch_data.harq_process_id = harq_id; + pusch_pdu->pusch_data.new_data_indicator = (harq_round == 0) ? 1 : 0; // not NDI but indicator for new transmission + pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size; + pusch_pdu->pusch_data.num_cb = 0; // CBG not supported + // Beamforming + pusch_pdu->beamforming.num_prgs = 1; + pusch_pdu->beamforming.prg_size = pusch_pdu->bwp_size; + pusch_pdu->beamforming.dig_bf_interface = 1; + pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; + /* TRANSFORM PRECODING --------------------------------------------------------*/ + if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled) { + // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled + pusch_pdu->dfts_ofdm.low_papr_group_number = sched_pusch->dmrs_info.pusch_identity % 30; + pusch_pdu->dfts_ofdm.low_papr_sequence_number = sched_pusch->dmrs_info.low_papr_sequence_number; + } + + + pusch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(sched_pusch->tb_size << 3, sched_pusch->R); + pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = 0; + if (UE->sc_info.rateMatching_PUSCH) { + // TBS_LBRM according to section 5.4.2.1 of 38.212 + long *maxMIMO_Layers = UE->sc_info.maxMIMO_Layers_PUSCH; + if (!maxMIMO_Layers && ul_bwp && ul_bwp->pusch_Config) + maxMIMO_Layers = ul_bwp->pusch_Config->maxRank; + AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); + pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(ul_bwp->mcs_table, + UE->sc_info.ul_bw_tbslbrm, + *maxMIMO_Layers); + } + /* PUSCH PTRS */ + if (sched_pusch->dmrs_info.ptrsConfig) { + bool valid_ptrs_setup = false; + pusch_pdu->pusch_ptrs.ptrs_ports_list = calloc_or_fail(2, sizeof(nfapi_nr_ptrs_ports_t)); + valid_ptrs_setup = set_ul_ptrs_values(sched_pusch->dmrs_info.ptrsConfig, + pusch_pdu->rb_size, + pusch_pdu->mcs_index, + pusch_pdu->mcs_table, + &pusch_pdu->pusch_ptrs.ptrs_freq_density, + &pusch_pdu->pusch_ptrs.ptrs_time_density, + &pusch_pdu->pusch_ptrs.ptrs_ports_list->ptrs_re_offset, + &pusch_pdu->pusch_ptrs.num_ptrs_ports, + &pusch_pdu->pusch_ptrs.ul_ptrs_power, + pusch_pdu->nr_of_symbols); + if (valid_ptrs_setup == true) + pusch_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS; // enable PUSCH PTRS + } else + pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS + return pusch_pdu; +} + +void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE_info_t *UE, NR_sched_pusch_t *sched_pusch) +{ + frame_t frame = pusch->frame; + slot_t slot = pusch->slot; + + NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon; + NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; + NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; + + /* the UE now has the grant for the request */ + sched_ctrl->SR = false; + + int8_t harq_id = sched_pusch->ul_harq_pid; + if (harq_id < 0) { + /* PP has not selected a specific HARQ Process, get a new one */ + harq_id = sched_ctrl->available_ul_harq.head; + AssertFatal(harq_id >= 0, "no free HARQ process available for UE %04x\n", UE->rnti); + remove_front_nr_list(&sched_ctrl->available_ul_harq); + sched_pusch->ul_harq_pid = harq_id; + } else { + /* PP selected a specific HARQ process. Check whether it will be a new + * transmission or a retransmission, and remove from the corresponding + * list */ + if (sched_ctrl->ul_harq_processes[harq_id].round == 0) + remove_nr_list(&sched_ctrl->available_ul_harq, harq_id); + else + remove_nr_list(&sched_ctrl->retrans_ul_harq, harq_id); + } + NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[harq_id]; + DevAssert(!cur_harq->is_waiting); + if (nr_mac->radio_config.disable_harq) { + finish_nr_ul_harq(sched_ctrl, harq_id); + } else { + add_tail_nr_list(&sched_ctrl->feedback_ul_harq, harq_id); + cur_harq->feedback_slot = sched_pusch->slot; + cur_harq->is_waiting = true; + } + + /* Statistics */ + AssertFatal(cur_harq->round < nr_mac->ul_bler.harq_round_max, "Indexing ulsch_rounds[%d] is out of bounds\n", cur_harq->round); + UE->mac_stats.ul.rounds[cur_harq->round]++; + /* Save information on MCS, TBS etc for the current initial transmission + * so we have access to it when retransmitting */ + cur_harq->sched_pusch = *sched_pusch; + if (cur_harq->round == 0) { + UE->mac_stats.ulsch_total_bytes_scheduled += sched_pusch->tb_size; + sched_ctrl->sched_ul_bytes += sched_pusch->tb_size; + UE->mac_stats.ul.total_rbs += sched_pusch->rbSize; + + } else { + UE->mac_stats.ul.total_rbs_retx += sched_pusch->rbSize; + } + UE->mac_stats.ul.current_bytes = sched_pusch->tb_size; + UE->mac_stats.ul.current_rbs = sched_pusch->rbSize; + sched_ctrl->last_ul_frame = sched_pusch->frame; + sched_ctrl->last_ul_slot = sched_pusch->slot; + + LOG_D(NR_MAC, + "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d TDA %2d dmrs_pos %x MCS " + "Table %2d MCS %2d nrOfLayers %2d num_dmrs_cdm_grps_no_data %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched " + "%6d est BSR %6d TPC %d\n", + frame, + slot, + UE->rnti, + sched_pusch->frame, + sched_pusch->slot, + sched_ctrl->aggregation_level, + sched_pusch->rbStart, + sched_pusch->rbSize, + sched_pusch->time_domain_allocation, + sched_pusch->dmrs_info.ul_dmrs_symb_pos, + current_BWP->mcs_table, + sched_pusch->mcs, + sched_pusch->nrOfLayers, + sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data, + sched_pusch->tb_size, + harq_id, + cur_harq->round, + nr_get_rv(cur_harq->round % 4), + cur_harq->ndi, + sched_ctrl->estimated_ul_buffer, + sched_ctrl->sched_ul_bytes, + sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, + sched_ctrl->tpc0); + + T(T_GNB_MAC_UL, T_INT(UE->rnti), T_INT(frame), T_INT(slot), T_INT(sched_pusch->mcs), T_INT(sched_pusch->tb_size)); + + /* PUSCH in a later slot, but corresponding DCI now! */ + const int index = ul_buffer_index(sched_pusch->frame, + sched_pusch->slot, + nr_mac->frame_structure.numb_slots_frame, + nr_mac->UL_tti_req_ahead_size); + nfapi_nr_ul_tti_request_t *req = &nr_mac->UL_tti_req_ahead[0][index]; + if (req->SFN != sched_pusch->frame || req->Slot != sched_pusch->slot) + LOG_W(NR_MAC, + "%d.%d future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n", + frame, + slot, + req->SFN, + req->Slot, + sched_pusch->frame, + sched_pusch->slot); + AssertFatal(req->n_pdus < sizeof(req->pdus_list) / sizeof(req->pdus_list[0]), + "Invalid UL_tti_req_ahead->n_pdus %d\n", + req->n_pdus); + + req->pdus_list[req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE; + req->pdus_list[req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t); + nfapi_nr_pusch_pdu_t *pusch_pdu = prepare_pusch_pdu(req, + UE, + scc, + sched_pusch, + current_BWP->transform_precoding, + harq_id, + cur_harq->round, + current_BWP->pusch_Config && current_BWP->pusch_Config->frequencyHopping, + UE->rnti); + req->n_pdus += 1; + + // Calculate the normalized tx_power for PHR + long *deltaMCS = current_BWP->pusch_Config ? current_BWP->pusch_Config->pusch_PowerControl->deltaMCS : NULL; + int tbs_bits = pusch_pdu->pusch_data.tb_size << 3; + sched_pusch->phr_txpower_calc = compute_ph_factor(current_BWP->scs, + tbs_bits, + sched_pusch->rbSize, + sched_pusch->nrOfLayers, + sched_pusch->tda_info.nrOfSymbols, + sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb, + deltaMCS, + false); + + /* a PDCCH PDU groups DCIs per BWP and CORESET. Save a pointer to each + * allocated PDCCH so we can easily allocate UE's DCIs independent of any + * CORESET order */ + NR_SearchSpace_t *ss = sched_ctrl->search_space; + NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; + const int coresetid = coreset->controlResourceSetId; + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = pusch->pdcch_pdu_coreset[coresetid]; + if (!pdcch_pdu) { + nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &pusch->ul_dci_req->ul_dci_pdu_list[pusch->ul_dci_req->numPdus]; + memset(ul_dci_request_pdu, 0, sizeof(nfapi_nr_ul_dci_request_pdus_t)); + ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; + ul_dci_request_pdu->PDUSize = (uint8_t)(4 + sizeof(nfapi_nr_dl_tti_pdcch_pdu)); + pdcch_pdu = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; + pusch->ul_dci_req->numPdus += 1; + nr_configure_pdcch(pdcch_pdu, coreset, &sched_ctrl->sched_pdcch); + pusch->pdcch_pdu_coreset[coresetid] = pdcch_pdu; + } + + LOG_D(NR_MAC, "Configuring ULDCI/PDCCH in %d.%d at CCE %d, rnti %04x\n", frame, slot, sched_ctrl->cce_index, UE->rnti); + + /* Fill PDCCH DL DCI PDU */ + nfapi_nr_dl_dci_pdu_t *dci_pdu = prepare_dci_pdu(pdcch_pdu, + scc, + ss, + coreset, + sched_ctrl->aggregation_level, + sched_ctrl->cce_index, + UE->UE_beam_index, + UE->rnti); + pdcch_pdu->numDlDci++; + + dci_pdu_rel15_t uldci_payload; + memset(&uldci_payload, 0, sizeof(uldci_payload)); + if (current_BWP->dci_format == NR_UL_DCI_FORMAT_0_1) + LOG_D(NR_MAC_DCI, + "add ul dci harq %d for %d.%d %d.%d round %d\n", + harq_id, + frame, + slot, + sched_pusch->frame, + sched_pusch->slot, + sched_ctrl->ul_harq_processes[harq_id].round); + + // If nrOfLayers is the same as in srs_feedback, we use the best TPMI, i.e. the one in srs_feedback. + // Otherwise, we use the valid TPMI that we saved in the first transmission. + int *tpmi = NULL; + if (pusch_pdu->nrOfLayers != (sched_ctrl->srs_feedback.ul_ri + 1)) + tpmi = &sched_pusch->tpmi; + config_uldci(&UE->sc_info, + pusch_pdu, + &uldci_payload, + &sched_ctrl->srs_feedback, + tpmi, + sched_pusch->time_domain_allocation, + UE->UE_sched_ctrl.tpc0, + cur_harq->ndi, + current_BWP, + ss->searchSpaceType->present); + + // Reset TPC to 0 dB to not request new gain multiple times before computing new value for SNR + UE->UE_sched_ctrl.tpc0 = 1; + + fill_dci_pdu_rel15(&UE->sc_info, + &UE->current_DL_BWP, + current_BWP, + dci_pdu, + &uldci_payload, + current_BWP->dci_format, + TYPE_C_RNTI_, + current_BWP->bwp_id, + ss, + coreset, + UE->pdsch_HARQ_ACK_Codebook, + nr_mac->cset0_bwp_size); +} + +fsn_t fs_add_delta(const frame_structure_t *fs, uint32_t delta, fsn_t fsn) +{ + const int slots_frame = fs->numb_slots_frame; + fsn_t res = { + .f = (fsn.f + (fsn.s + delta) / slots_frame) % MAX_FRAME_NUMBER, + .s = (fsn.s + delta) % slots_frame, + }; + return res; +} +int fs_get_diff(const frame_structure_t *fs, fsn_t a, fsn_t b) +{ + const int slots_frame = fs->numb_slots_frame; + int diff = (a.f * slots_frame + a.s) - (b.f * slots_frame + b.s); + if (diff < -512 * slots_frame) + diff += 1024 * slots_frame; + else if (diff > 512 * slots_frame) + diff -= 1024 * slots_frame; + return diff; +} +fsn_t fs_get_max(const frame_structure_t *fs, fsn_t a, fsn_t b) +{ + if (fs_get_diff(fs, a, b) <= 0) { + return b; + } else { + return a; } } -static bool nr_ulsch_preprocessor(module_id_t module_id, frame_t frame, slot_t slot) +static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch) { - gNB_MAC_INST *nr_mac = RC.nrmac[module_id]; - // no UEs - if (nr_mac->UE_info.connected_ue_list[0] == NULL) - return false; + int frame = pp_pusch->frame; + int slot = pp_pusch->slot; NR_COMMON_channels_t *cc = nr_mac->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL; - NR_ServingCellConfigCommonSIB_t *scc_sib1 = sib1 ? sib1->servingCellConfigCommon : NULL; - AssertFatal(scc || scc_sib1, "We need one serving cell config common\n"); - const int slots_frame = nr_mac->frame_structure.numb_slots_frame; - // TODO we assume the same K2 for all UEs - const int K2 = nr_mac->radio_config.minRXTXTIME + get_NTN_Koffset(scc); - const int sched_frame = (frame + (slot + K2) / slots_frame) % MAX_FRAME_NUMBER; - const int sched_slot = (slot + K2) % slots_frame; - if (!is_ul_slot(sched_slot, &nr_mac->frame_structure)) - return false; + AssertFatal(scc, "We need one serving cell config common\n"); + const frame_structure_t *fs = &nr_mac->frame_structure; + + // we assume the same K2 for all UEs + const int koffset = get_NTN_Koffset(scc); + const int min_rxtx = nr_mac->radio_config.minRXTXTIME + koffset; int num_beams = nr_mac->beam_info.beam_allocation ? nr_mac->beam_info.beams_per_period : 1; int bw = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; - int len[num_beams]; - for (int i = 0; i < num_beams; i++) - len[i] = bw; int average_agg_level = 4; // TODO find a better estimation - int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE); + int max_dci = bw / (average_agg_level * NR_NB_REG_PER_CCE); // FAPI cannot handle more than MAX_DCI_CORESET DCIs - max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET); + max_dci = min(max_dci, MAX_DCI_CORESET); - /* proportional fair scheduling algorithm */ - pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.connected_ue_list, max_sched_ues, num_beams, len); - return true; + fsn_t current = {frame, slot}; + fsn_t min_next = fs_add_delta(fs, min_rxtx, current); + /* if it's the last DL slot, we should try all TDAs to make sure that the + * scheduler can reach e.g. the next mixed slot. Otherwise, if we don't, we + * might starve HARQ processes that need a retransmission in a specific slot + * but we might not necessarily reach it */ + bool last_dl = (current.s % fs->numb_slots_period) == (fs->period_cfg.num_dl_slots - 1); + fsn_t *next = &nr_mac->ul_next; + while (max_dci > 0) { + /* go to the next UL slot, skipping DL if necessary */ + *next = fs_get_max(fs, *next, min_next); + while (!is_ul_slot(next->s, fs)) + *next = fs_add_delta(fs, 1, *next); + if (!is_dl_slot(current.s, fs)) // if current slot is not DL, nothing to do + break; + + /* get a TDA so that next UL scheduling slot can be reached from current, + * and exit if there is no such TDA. Remove koffset, as it is + * "cell-specific", i.e., the UE will add it on the computation. */ + int k2 = fs_get_diff(fs, *next, current) - koffset; + DevAssert(k2 > 0); + // we assume that all beams have the same symbol utilization in all RBs for + // simplification (but this might not be true). Otherwise, we would need to + // check it separately for all beams and give a list of TDAs (one for each + // beam) in pf_ul(), which is complex. We should rewrite pf_ul() to + // schedule for one beam only instead (and for one BWP). + int beam = 0; + const NR_tda_info_t *tda_info = NULL; + int n_tda = get_num_ul_tda(nr_mac, next->s, k2, &tda_info); + if (n_tda == 0) /* no TDA fulfills this */ + break; + int rb_start = 0; + int rb_len = bw; + tda_info = get_best_ul_tda(nr_mac, beam, tda_info, n_tda, next->f, next->s, &rb_start, &rb_len); + DevAssert(tda_info->valid_tda); + int tda = seq_arr_dist(&nr_mac->ul_tda, seq_arr_front(&nr_mac->ul_tda), tda_info); + AssertFatal(tda >= 0 && tda < 16, "illegal TDA index %d\n", tda); + + int len[num_beams]; + for (int i = 0; i < num_beams; i++) + len[i] = rb_len; + /* proportional fair scheduling algorithm */ + int sched = pf_ul(nr_mac, pp_pusch, tda, tda_info, nr_mac->UE_info.connected_ue_list, max_dci, num_beams, len); + LOG_D(NR_MAC, "run pf_ul() at %4d.%2d with tda %d k2 %d (ULSCH at %4d.%2d) scheduled %d last_dl %d\n", frame, slot, tda, k2, next->f, next->s, sched, last_dl); + /* if we did not schedule anything, and it's not the last slot, break. In + * the case we did schedule or it's the last slot (see above!), continue + * advancing till there is no TDA anymore */ + if (sched == 0 && !last_dl) + break; + max_dci -= sched; + + *next = fs_add_delta(fs, 1, *next); + } } nr_pp_impl_ul nr_init_ulsch_preprocessor(int CC_id) @@ -2318,403 +2739,9 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, slot_t slot, nfapi_ /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock); - /* Uplink data ONLY can be scheduled when the current slot is downlink slot, - * because we have to schedule the DCI0 first before schedule uplink data */ - if (!is_dl_slot(slot, &nr_mac->frame_structure)) { - LOG_D(NR_MAC, "Current slot %d is NOT DL slot, cannot schedule DCI0 for UL data\n", slot); - return; - } - bool do_sched = nr_mac->pre_processor_ul(module_id, frame, slot); - if (!do_sched) - return; - ul_dci_req->SFN = frame; ul_dci_req->Slot = slot; - /* a PDCCH PDU groups DCIs per BWP and CORESET. Save a pointer to each - * allocated PDCCH so we can easily allocate UE's DCIs independent of any - * CORESET order */ - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_coreset[MAX_NUM_CORESET] = {0}; + post_process_pusch_t pusch = { .frame = frame, .slot = slot, .ul_dci_req = ul_dci_req, .pdcch_pdu_coreset = {NULL}, }; - - NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon; - NR_UEs_t *UE_info = &nr_mac->UE_info; - UE_iterator(UE_info->connected_ue_list, UE) { - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - if (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) - continue; - - NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP; - - UE->mac_stats.ul.current_bytes = 0; - UE->mac_stats.ul.current_rbs = 0; - - /* dynamic PUSCH values (RB alloc, MCS, hence R, Qm, TBS) that change in - * every TTI are pre-populated by the preprocessor and used below */ - NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch; - LOG_D(NR_MAC,"UE %04x : sched_pusch->rbSize %d\n",UE->rnti,sched_pusch->rbSize); - if (sched_pusch->rbSize <= 0) - continue; - - uint16_t rnti = UE->rnti; - sched_ctrl->SR = false; - int *tpmi = NULL; - - int8_t harq_id = sched_pusch->ul_harq_pid; - if (harq_id < 0) { - /* PP has not selected a specific HARQ Process, get a new one */ - harq_id = sched_ctrl->available_ul_harq.head; - AssertFatal(harq_id >= 0, - "no free HARQ process available for UE %04x\n", - UE->rnti); - remove_front_nr_list(&sched_ctrl->available_ul_harq); - sched_pusch->ul_harq_pid = harq_id; - } else { - /* PP selected a specific HARQ process. Check whether it will be a new - * transmission or a retransmission, and remove from the corresponding - * list */ - if (sched_ctrl->ul_harq_processes[harq_id].round == 0) - remove_nr_list(&sched_ctrl->available_ul_harq, harq_id); - else - remove_nr_list(&sched_ctrl->retrans_ul_harq, harq_id); - } - NR_UE_ul_harq_t *cur_harq = &sched_ctrl->ul_harq_processes[harq_id]; - DevAssert(!cur_harq->is_waiting); - if (nr_mac->radio_config.disable_harq) { - finish_nr_ul_harq(sched_ctrl, harq_id); - } else { - add_tail_nr_list(&sched_ctrl->feedback_ul_harq, harq_id); - cur_harq->feedback_slot = sched_pusch->slot; - cur_harq->is_waiting = true; - } - - /* Statistics */ - AssertFatal(cur_harq->round < nr_mac->ul_bler.harq_round_max, "Indexing ulsch_rounds[%d] is out of bounds\n", cur_harq->round); - UE->mac_stats.ul.rounds[cur_harq->round]++; - if (cur_harq->round == 0) { - UE->mac_stats.ulsch_total_bytes_scheduled += sched_pusch->tb_size; - /* Save information on MCS, TBS etc for the current initial transmission - * so we have access to it when retransmitting */ - cur_harq->sched_pusch = *sched_pusch; - /* save which time allocation and nrOfLayers have been used, to be used on - * retransmissions */ - cur_harq->sched_pusch.time_domain_allocation = sched_pusch->time_domain_allocation; - cur_harq->sched_pusch.nrOfLayers = sched_pusch->nrOfLayers; - cur_harq->sched_pusch.tpmi = sched_pusch->tpmi; - sched_ctrl->sched_ul_bytes += sched_pusch->tb_size; - UE->mac_stats.ul.total_rbs += sched_pusch->rbSize; - - } else { - LOG_D(NR_MAC, - "%d.%2d UL retransmission RNTI %04x sched %d.%2d HARQ PID %d round %d NDI %d\n", - frame, - slot, - rnti, - sched_pusch->frame, - sched_pusch->slot, - harq_id, - cur_harq->round, - cur_harq->ndi); - UE->mac_stats.ul.total_rbs_retx += sched_pusch->rbSize; - } - UE->mac_stats.ul.current_bytes = sched_pusch->tb_size; - UE->mac_stats.ul.current_rbs = sched_pusch->rbSize; - sched_ctrl->last_ul_frame = sched_pusch->frame; - sched_ctrl->last_ul_slot = sched_pusch->slot; - - LOG_D(NR_MAC, - "ULSCH/PUSCH: %4d.%2d RNTI %04x UL sched %4d.%2d DCI L %d start %2d RBS %3d startSymbol %2d nb_symbol %2d dmrs_pos %x MCS Table %2d MCS %2d nrOfLayers %2d num_dmrs_cdm_grps_no_data %2d TBS %4d HARQ PID %2d round %d RV %d NDI %d est %6d sched %6d est BSR %6d TPC %d\n", - frame, - slot, - rnti, - sched_pusch->frame, - sched_pusch->slot, - sched_ctrl->aggregation_level, - sched_pusch->rbStart, - sched_pusch->rbSize, - sched_pusch->tda_info.startSymbolIndex, - sched_pusch->tda_info.nrOfSymbols, - sched_pusch->dmrs_info.ul_dmrs_symb_pos, - current_BWP->mcs_table, - sched_pusch->mcs, - sched_pusch->nrOfLayers, - sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data, - sched_pusch->tb_size, - harq_id, - cur_harq->round, - nr_get_rv(cur_harq->round % 4), - cur_harq->ndi, - sched_ctrl->estimated_ul_buffer, - sched_ctrl->sched_ul_bytes, - sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, - sched_ctrl->tpc0); - - /* PUSCH in a later slot, but corresponding DCI now! */ - const int index = ul_buffer_index(sched_pusch->frame, - sched_pusch->slot, - nr_mac->frame_structure.numb_slots_frame, - nr_mac->UL_tti_req_ahead_size); - nfapi_nr_ul_tti_request_t *future_ul_tti_req = &nr_mac->UL_tti_req_ahead[0][index]; - if (future_ul_tti_req->SFN != sched_pusch->frame || future_ul_tti_req->Slot != sched_pusch->slot) - LOG_W(NR_MAC, - "%d.%d future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n", - frame, slot, - future_ul_tti_req->SFN, - future_ul_tti_req->Slot, - sched_pusch->frame, - sched_pusch->slot); - AssertFatal(future_ul_tti_req->n_pdus < - sizeof(future_ul_tti_req->pdus_list) / sizeof(future_ul_tti_req->pdus_list[0]), - "Invalid future_ul_tti_req->n_pdus %d\n", future_ul_tti_req->n_pdus); - - future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE; - future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t); - nfapi_nr_pusch_pdu_t *pusch_pdu = &future_ul_tti_req->pdus_list[future_ul_tti_req->n_pdus].pusch_pdu; - memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t)); - future_ul_tti_req->n_pdus += 1; - - LOG_D(NR_MAC, - "%4d.%2d Scheduling UE specific PUSCH for sched %d.%d, ul_tti_req %d.%d\n", - frame, - slot, - sched_pusch->frame, - sched_pusch->slot, - future_ul_tti_req->SFN, - future_ul_tti_req->Slot); - - pusch_pdu->pdu_bit_map = PUSCH_PDU_BITMAP_PUSCH_DATA; - pusch_pdu->rnti = rnti; - pusch_pdu->handle = 0; //not yet used - - /* FAPI: BWP */ - - pusch_pdu->bwp_size = current_BWP->BWPSize; - pusch_pdu->bwp_start = current_BWP->BWPStart; - pusch_pdu->subcarrier_spacing = current_BWP->scs; - pusch_pdu->cyclic_prefix = 0; - - /* FAPI: PUSCH information always included */ - pusch_pdu->target_code_rate = sched_pusch->R; - pusch_pdu->qam_mod_order = sched_pusch->Qm; - pusch_pdu->mcs_index = sched_pusch->mcs; - pusch_pdu->mcs_table = current_BWP->mcs_table; - pusch_pdu->transform_precoding = current_BWP->transform_precoding; - if (current_BWP->pusch_Config && current_BWP->pusch_Config->dataScramblingIdentityPUSCH) - pusch_pdu->data_scrambling_id = *current_BWP->pusch_Config->dataScramblingIdentityPUSCH; - else - pusch_pdu->data_scrambling_id = *scc->physCellId; - pusch_pdu->nrOfLayers = sched_pusch->nrOfLayers; - // If nrOfLayers is the same as in srs_feedback, we use the best TPMI, i.e. the one in srs_feedback. - // Otherwise, we use the valid TPMI that we saved in the first transmission. - if (pusch_pdu->nrOfLayers != (sched_ctrl->srs_feedback.ul_ri + 1)) - tpmi = &sched_pusch->tpmi; - pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data; - - /* FAPI: DMRS */ - pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data; - pusch_pdu->dmrs_ports = ((1<nrOfLayers) - 1); - pusch_pdu->ul_dmrs_symb_pos = sched_pusch->dmrs_info.ul_dmrs_symb_pos; - pusch_pdu->dmrs_config_type = sched_pusch->dmrs_info.dmrs_config_type; - pusch_pdu->scid = 0; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1] - const NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = get_DMRS_UplinkConfig(current_BWP->pusch_Config, &sched_pusch->tda_info); - if (pusch_pdu->transform_precoding) { // transform precoding disabled - long *scramblingid=NULL; - pusch_pdu->pusch_identity = *scc->physCellId; - if (NR_DMRS_UplinkConfig && pusch_pdu->scid == 0) - scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0; - else if (NR_DMRS_UplinkConfig) - scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID1; - if (scramblingid == NULL) - pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; - else - pusch_pdu->ul_dmrs_scrambling_id = *scramblingid; - } - else { - pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; - if (NR_DMRS_UplinkConfig && - NR_DMRS_UplinkConfig->transformPrecodingEnabled && - NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity != NULL) - pusch_pdu->pusch_identity = *NR_DMRS_UplinkConfig->transformPrecodingEnabled->nPUSCH_Identity; - else if (NR_DMRS_UplinkConfig) - pusch_pdu->pusch_identity = *scc->physCellId; - } - pusch_pdu->scid = 0; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1] - pusch_pdu->dmrs_ports = ((1<nrOfLayers) - 1); - - /* FAPI: Pusch Allocation in frequency domain */ - pusch_pdu->resource_alloc = 1; //type 1 - pusch_pdu->rb_start = sched_pusch->rbStart; - pusch_pdu->rb_size = sched_pusch->rbSize; - pusch_pdu->vrb_to_prb_mapping = 0; - if (current_BWP->pusch_Config==NULL || current_BWP->pusch_Config->frequencyHopping==NULL) - pusch_pdu->frequency_hopping = 0; - else - pusch_pdu->frequency_hopping = 1; - - /* FAPI: Resource Allocation in time domain */ - pusch_pdu->start_symbol_index = sched_pusch->tda_info.startSymbolIndex; - pusch_pdu->nr_of_symbols = sched_pusch->tda_info.nrOfSymbols; - - /* PUSCH PDU */ - AssertFatal(cur_harq->round < nr_mac->ul_bler.harq_round_max, - "RV index %d is out of bounds\n", - cur_harq->round % 4); - pusch_pdu->pusch_data.rv_index = nr_get_rv(cur_harq->round % 4); - pusch_pdu->pusch_data.harq_process_id = harq_id; - pusch_pdu->pusch_data.new_data_indicator = (cur_harq->round == 0) ? 1 : 0; // not NDI but indicator for new transmission - pusch_pdu->pusch_data.tb_size = sched_pusch->tb_size; - pusch_pdu->pusch_data.num_cb = 0; //CBG not supported - - // Beamforming - pusch_pdu->beamforming.num_prgs = 0; - pusch_pdu->beamforming.prg_size = 0; // bwp_size; - pusch_pdu->beamforming.dig_bf_interface = 1; - pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; - - pusch_pdu->maintenance_parms_v3.ldpcBaseGraph = get_BG(sched_pusch->tb_size<<3,sched_pusch->R); - - // Calacualte the normalized tx_power for PHR - long *deltaMCS = current_BWP->pusch_Config ? current_BWP->pusch_Config->pusch_PowerControl->deltaMCS : NULL; - int tbs_bits = pusch_pdu->pusch_data.tb_size << 3; - - sched_pusch->phr_txpower_calc = compute_ph_factor(current_BWP->scs, - tbs_bits, - sched_pusch->rbSize, - sched_pusch->nrOfLayers, - sched_pusch->tda_info.nrOfSymbols, - sched_pusch->dmrs_info.N_PRB_DMRS * sched_pusch->dmrs_info.num_dmrs_symb, - deltaMCS, - false); - - NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info; - if (sc_info->rateMatching_PUSCH) { - // TBS_LBRM according to section 5.4.2.1 of 38.212 - long *maxMIMO_Layers = sc_info->maxMIMO_Layers_PUSCH; - if (!maxMIMO_Layers) - maxMIMO_Layers = current_BWP->pusch_Config->maxRank; - AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n"); - pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = - nr_compute_tbslbrm(current_BWP->mcs_table, sc_info->ul_bw_tbslbrm, *maxMIMO_Layers); - } else - pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = 0; - - LOG_D(NR_MAC,"PUSCH PDU : data_scrambling_identity %x, dmrs_scrambling_id %x\n",pusch_pdu->data_scrambling_id,pusch_pdu->ul_dmrs_scrambling_id); - /* TRANSFORM PRECODING --------------------------------------------------------*/ - - if (pusch_pdu->transform_precoding == NR_PUSCH_Config__transformPrecoder_enabled){ - - // U as specified in section 6.4.1.1.1.2 in 38.211, if sequence hopping and group hopping are disabled - pusch_pdu->dfts_ofdm.low_papr_group_number = pusch_pdu->pusch_identity % 30; - - // V as specified in section 6.4.1.1.1.2 in 38.211 V = 0 if sequence hopping and group hopping are disabled - if ((!NR_DMRS_UplinkConfig || - !NR_DMRS_UplinkConfig->transformPrecodingEnabled || - (!NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceGroupHopping && !NR_DMRS_UplinkConfig->transformPrecodingEnabled->sequenceHopping)) && - !scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->groupHoppingEnabledTransformPrecoding) - pusch_pdu->dfts_ofdm.low_papr_sequence_number = 0; - else - AssertFatal(1==0,"Hopping mode is not supported in transform precoding\n"); - - LOG_D(NR_MAC,"TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d MCS table: %d\n", pusch_pdu->num_dmrs_cdm_grps_no_data, pusch_pdu->dfts_ofdm.low_papr_group_number, current_BWP->mcs_table); - } - - /*-----------------------------------------------------------------------------*/ - - /* PUSCH PTRS */ - if (NR_DMRS_UplinkConfig && NR_DMRS_UplinkConfig->phaseTrackingRS != NULL) { - bool valid_ptrs_setup = false; - pusch_pdu->pusch_ptrs.ptrs_ports_list = (nfapi_nr_ptrs_ports_t *) malloc(2*sizeof(nfapi_nr_ptrs_ports_t)); - valid_ptrs_setup = set_ul_ptrs_values(NR_DMRS_UplinkConfig->phaseTrackingRS->choice.setup, - pusch_pdu->rb_size, pusch_pdu->mcs_index, pusch_pdu->mcs_table, - &pusch_pdu->pusch_ptrs.ptrs_freq_density,&pusch_pdu->pusch_ptrs.ptrs_time_density, - &pusch_pdu->pusch_ptrs.ptrs_ports_list->ptrs_re_offset,&pusch_pdu->pusch_ptrs.num_ptrs_ports, - &pusch_pdu->pusch_ptrs.ul_ptrs_power, pusch_pdu->nr_of_symbols); - if (valid_ptrs_setup==true) { - pusch_pdu->pdu_bit_map |= PUSCH_PDU_BITMAP_PUSCH_PTRS; // enable PUSCH PTRS - } - } - else{ - pusch_pdu->pdu_bit_map &= ~PUSCH_PDU_BITMAP_PUSCH_PTRS; // disable PUSCH PTRS - } - - /* look up the PDCCH PDU for this BWP and CORESET. If it does not exist, - * create it */ - NR_SearchSpace_t *ss = sched_ctrl->search_space; - NR_ControlResourceSet_t *coreset = sched_ctrl->coreset; - const int coresetid = coreset->controlResourceSetId; - nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu = pdcch_pdu_coreset[coresetid]; - if (!pdcch_pdu) { - nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &ul_dci_req->ul_dci_pdu_list[ul_dci_req->numPdus]; - memset(ul_dci_request_pdu, 0, sizeof(nfapi_nr_ul_dci_request_pdus_t)); - ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; - ul_dci_request_pdu->PDUSize = (uint8_t)(4+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); - pdcch_pdu = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; - ul_dci_req->numPdus += 1; - nr_configure_pdcch(pdcch_pdu, coreset, &sched_ctrl->sched_pdcch); - pdcch_pdu_coreset[coresetid] = pdcch_pdu; - } - - LOG_D(NR_MAC,"Configuring ULDCI/PDCCH in %d.%d at CCE %d, rnti %04x\n", frame,slot,sched_ctrl->cce_index,rnti); - - /* Fill PDCCH DL DCI PDU */ - nfapi_nr_dl_dci_pdu_t *dci_pdu = &pdcch_pdu->dci_pdu[pdcch_pdu->numDlDci]; - pdcch_pdu->numDlDci++; - dci_pdu->RNTI = rnti; - if (coreset->pdcch_DMRS_ScramblingID && - ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific) { - dci_pdu->ScramblingId = *coreset->pdcch_DMRS_ScramblingID; - dci_pdu->ScramblingRNTI = rnti; - } else { - dci_pdu->ScramblingId = *scc->physCellId; - dci_pdu->ScramblingRNTI = 0; - } - dci_pdu->AggregationLevel = sched_ctrl->aggregation_level; - dci_pdu->CceIndex = sched_ctrl->cce_index; - dci_pdu->beta_PDCCH_1_0 = 0; - dci_pdu->powerControlOffsetSS = 1; - dci_pdu->precodingAndBeamforming.num_prgs = 0; - dci_pdu->precodingAndBeamforming.prg_size = 0; - dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 1; - dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; - dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = UE->UE_beam_index; - - dci_pdu_rel15_t uldci_payload; - memset(&uldci_payload, 0, sizeof(uldci_payload)); - if (current_BWP->dci_format == NR_UL_DCI_FORMAT_0_1) - LOG_D(NR_MAC_DCI, - "add ul dci harq %d for %d.%d %d.%d round %d\n", - harq_id, - frame, - slot, - sched_pusch->frame, - sched_pusch->slot, - sched_ctrl->ul_harq_processes[harq_id].round); - config_uldci(&UE->sc_info, - pusch_pdu, - &uldci_payload, - &sched_ctrl->srs_feedback, - tpmi, - sched_pusch->time_domain_allocation, - UE->UE_sched_ctrl.tpc0, - cur_harq->ndi, - current_BWP, - ss->searchSpaceType->present); - - // Reset TPC to 0 dB to not request new gain multiple times before computing new value for SNR - UE->UE_sched_ctrl.tpc0 = 1; - - fill_dci_pdu_rel15(&UE->sc_info, - &UE->current_DL_BWP, - current_BWP, - dci_pdu, - &uldci_payload, - current_BWP->dci_format, - TYPE_C_RNTI_, - current_BWP->bwp_id, - ss, - coreset, - UE->pdsch_HARQ_ACK_Codebook, - nr_mac->cset0_bwp_size); - - memset(sched_pusch, 0, sizeof(*sched_pusch)); - } + nr_mac->pre_processor_ul(nr_mac, &pusch); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_config.h b/openair2/LAYER2/NR_MAC_gNB/mac_config.h new file mode 100644 index 0000000000..1fdbe62115 --- /dev/null +++ b/openair2/LAYER2/NR_MAC_gNB/mac_config.h @@ -0,0 +1,46 @@ +/* + * 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 __LAYER2_NR_MAC_CONFIG_H__ +#define __LAYER2_NR_MAC_CONFIG_H__ + +#include + +typedef struct vector_s { + int X; + int Y; + int Z; +} vector_t; + +// Format similar to values sent in SIB19 +typedef struct gnb_sat_position_update_s { + int sfn; + int subframe; + uint32_t delay; + int drift; + uint32_t accel; + vector_t position; + vector_t velocity; +} gnb_sat_position_update_t; + +bool nr_update_sib19(const gnb_sat_position_update_t *sat_position); + +#endif /*__LAYER2_NR_MAC_CONFIG_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 6acf4ae1d8..f04b28b8da 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -52,7 +52,6 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_alloca void mac_top_init_gNB(ngran_node_t node_type, NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfig_t *scd, const nr_mac_config_t *conf, const nr_rlc_configuration_t *default_rlc_config); void mac_top_destroy_gNB(gNB_MAC_INST *mac); @@ -66,7 +65,7 @@ void nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, NR_UE_info_t *UE); bool add_new_UE_RA(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs); -int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots); +int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots); int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info); void clear_nr_nfapi_information(gNB_MAC_INST *gNB, @@ -149,7 +148,7 @@ uint16_t nr_mac_compute_RIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs); void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot); /* \brief UL preprocessor for phytest: schedules UE_id 0 with fixed MCS on a * fixed set of resources */ -bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot); +void nr_ul_preprocessor_phytest(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch); void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, @@ -170,6 +169,24 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info, uint8_t ndi, NR_UE_UL_BWP_t *ul_bwp, NR_SearchSpace__searchSpaceType_PR ss_type); +dci_pdu_rel15_t prepare_dci_dl_payload(const gNB_MAC_INST *gNB_mac, + const NR_UE_info_t *UE, + nr_rnti_type_t rnti_type, + NR_SearchSpace__searchSpaceType_PR ss_type, + const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu, + const NR_sched_pdsch_t *sched_pdsch, + const NR_sched_pucch_t *pucch, + int harq_pid, + int tb_scaling, + bool is_sib1); +nfapi_nr_dl_dci_pdu_t *prepare_dci_pdu(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu, + const NR_ServingCellConfigCommon_t *scc, + const NR_SearchSpace_t *ss, + const NR_ControlResourceSet_t *coreset, + int aggregation_level, + int cce_index, + int beam_index, + int rnti); void nr_schedule_pucch(gNB_MAC_INST *nrmac, frame_t frameP, slot_t slotP); @@ -185,6 +202,8 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt void nr_csi_meas_reporting(int Mod_idP, frame_t frameP, slot_t slotP); +void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot); + int nr_acknack_scheduling(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frameP, @@ -252,12 +271,6 @@ void fill_dci_pdu_rel15(const NR_UE_ServingCell_Info_t *servingCellInfo, long pdsch_HARQ_ACK_Codebook, uint16_t cset0_bwp_size); -void prepare_dci(const NR_UE_ServingCell_Info_t *servingCellInfo, - const NR_UE_DL_BWP_t *current_BWP, - const NR_ControlResourceSet_t *coreset, - dci_pdu_rel15_t *dci_pdu_rel15, - nr_dci_format_t format); - void set_r_pucch_parms(int rsetindex, int r_pucch, int bwp_size, @@ -269,14 +282,8 @@ void set_r_pucch_parms(int rsetindex, /* find coreset within the search space */ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, - void *bwp, - NR_SearchSpace_t *ss, - NR_SearchSpace__searchSpaceType_PR ss_type); - -long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList, - int time_domain_assignment, - int mu, - const NR_ServingCellConfigCommon_t *scc); + NR_BWP_DownlinkDedicated_t *bwp_dedicated, + NR_ControlResourceSetId_t coreset_id); const NR_DMRS_UplinkConfig_t *get_DMRS_UplinkConfig(const NR_PUSCH_Config_t *pusch_Config, const NR_tda_info_t *tda_info); @@ -319,11 +326,30 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, bool transition_ra_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); -void nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, NR_UE_info_t *UE, bool success); +bool nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, NR_UE_info_t *UE, bool success); void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti); NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup); int nr_get_default_pucch_res(int pucch_ResourceCommon); - +nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti_req, + const NR_UE_info_t *UE, + const NR_ServingCellConfigCommon_t *scc, + const NR_sched_pusch_t *sched_pusch, + int transform_precoding, + int harq_id, + int harq_round, + int fh, + int rnti); +nfapi_nr_dl_tti_pdsch_pdu_rel15_t *prepare_pdsch_pdu(nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu, + const gNB_MAC_INST *mac, + const NR_UE_info_t *UE, + const NR_sched_pdsch_t *sched_pdsch, + const NR_PDSCH_Config_t *pdsch_Config, + bool is_sib1, + int harq_round, + int rnti, + int beam_index, + int nl_tbslbrm, + int pdu_index); int nr_write_ce_dlsch_pdu(module_id_t module_idP, const NR_UE_sched_ctrl_t *ue_sched_ctl, unsigned char *mac_pdu, @@ -376,6 +402,7 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac, int layers, int xp_pdsch_antenna_ports); +int get_mcs_from_SINRx10(int mcs_table, int SINRx10, int Nl); uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx); uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format); @@ -385,7 +412,15 @@ void free_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl); bool add_UE_to_list(int list_size, NR_UE_info_t *list[list_size], NR_UE_info_t *UE); NR_UE_info_t *remove_UE_from_list(int list_size, NR_UE_info_t *list[list_size], rnti_t rnti); int get_dl_tda(const gNB_MAC_INST *nrmac, int slot); -int get_ul_tda(gNB_MAC_INST *nrmac, int frame, int slot); +int get_num_ul_tda(gNB_MAC_INST *nrmac, int slot, int k2, const NR_tda_info_t **first_idx); +const NR_tda_info_t *get_best_ul_tda(const gNB_MAC_INST *nrmac, + int beam, + const NR_tda_info_t *tdas, + int n_tda, + int frame, + int slot, + int *rb_start, + int *rb_len); int get_cce_index(const gNB_MAC_INST *nrmac, const int CC_id, @@ -396,7 +431,6 @@ int get_cce_index(const gNB_MAC_INST *nrmac, const NR_SearchSpace_t *ss, const NR_ControlResourceSet_t *coreset, NR_sched_pdcch_t *sched_pdcch, - bool is_common, float pdcch_cl_adjust); bool nr_find_nb_rb(uint16_t Qm, @@ -419,13 +453,14 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options, int ul_buffer_index(int frame, int slot, int slots_per_frame, int size); void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP); -void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, gNB_MAC_INST *mac); +void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *config, gNB_MAC_INST *mac); int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx); NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame); void reset_beam_status(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame, bool new_beam); void beam_selection_procedures(gNB_MAC_INST *mac, NR_UE_info_t *UE); void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t frameP, slot_t slotP); - +bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE); +bwp_info_t get_pusch_bwp_start_size(NR_UE_info_t *UE); size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp); long get_lcid_from_drbid(int drb_id); @@ -442,12 +477,15 @@ bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti); void nr_mac_trigger_release_complete(gNB_MAC_INST *mac, int rnti); void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti); bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti); +void clean_bwp_structures(NR_SpCellConfig_t *spCellConfig); + +bool nr_mac_ue_is_active(const NR_UE_info_t *ue); void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing); void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl); -void nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl); +bool nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl); -void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE); +void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE, int new_bwp_id); void process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl, const struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod); @@ -465,4 +503,6 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac, const NR_BCCH_DL_SCH_Message_t *sib1); void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group); + +void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE_info_t *UE, NR_sched_pusch_t *sched_pusch); #endif /*__LAYER2_NR_MAC_PROTO_H__*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 5d7642c815..debc0d5530 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -31,7 +31,9 @@ #include "NR_CG-ConfigInfo.h" #include "openair3/ocp-gtpu/gtp_itf.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" +#include "lib/f1ap_rrc_message_transfer.h" #include "lib/f1ap_interface_management.h" +#include "lib/f1ap_ue_context.h" #include "executables/softmodem-common.h" @@ -92,7 +94,7 @@ bool DURecvCb(protocol_ctxt_t *ctxt_pP, // The buffer comes from the stack in gtp-u thread, we have a make a separate buffer to enqueue in a inter-thread message queue uint8_t *sdu = malloc16(sdu_buffer_sizeP); memcpy(sdu, sdu_buffer_pP, sdu_buffer_sizeP); - du_rlc_data_req(ctxt_pP, srb_flagP, rb_idP, muiP, confirmP, sdu_buffer_sizeP, sdu); + nr_rlc_data_req(ctxt_pP, srb_flagP, rb_idP, muiP, sdu_buffer_sizeP, sdu); return true; } @@ -221,19 +223,19 @@ void gnb_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_upd LOG_I(MAC, "received gNB-DU configuration update acknowledge\n"); } -static NR_RLC_BearerConfig_t *get_bearerconfig_from_srb(const f1ap_srb_to_be_setup_t *srb, +static NR_RLC_BearerConfig_t *get_bearerconfig_from_srb(const f1ap_srb_to_setup_t *srb, const nr_rlc_configuration_t *rlc_config) { - long priority = srb->srb_id == 2 ? 3 : 1; // see 38.331 sec 9.2.1 + long priority = srb->id == 2 ? 3 : 1; // see 38.331 sec 9.2.1 e_NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration bucket = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms5; - return get_SRB_RLC_BearerConfig(get_lcid_from_srbid(srb->srb_id), priority, bucket, rlc_config); + return get_SRB_RLC_BearerConfig(get_lcid_from_srbid(srb->id), priority, bucket, rlc_config); } static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, int srbs_len, - const f1ap_srb_to_be_setup_t *req_srbs, - f1ap_srb_to_be_setup_t **resp_srbs, + const f1ap_srb_to_setup_t *req_srbs, + f1ap_srb_setup_t **resp_srbs, NR_CellGroupConfig_t *cellGroupConfig, const nr_rlc_configuration_t *rlc_config) { @@ -242,15 +244,15 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, *resp_srbs = calloc(srbs_len, sizeof(**resp_srbs)); AssertFatal(*resp_srbs != NULL, "out of memory\n"); for (int i = 0; i < srbs_len; i++) { - const f1ap_srb_to_be_setup_t *srb = &req_srbs[i]; + const f1ap_srb_to_setup_t *srb = &req_srbs[i]; NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_srb(srb, rlc_config); - nr_rlc_add_srb(UE->rnti, srb->srb_id, rlc_BearerConfig); + nr_rlc_add_srb(UE->rnti, srb->id, rlc_BearerConfig); int priority = rlc_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->priority; nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .priority = priority}; nr_mac_add_lcid(&UE->UE_sched_ctrl, &c); - (*resp_srbs)[i].srb_id = srb->srb_id; + (*resp_srbs)[i].id = srb->id; (*resp_srbs)[i].lcid = c.lcid; if (rlc_BearerConfig->logicalChannelIdentity == 1) { @@ -267,12 +269,12 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, return srbs_len; } -static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_be_setup_t *drb, +static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_setup_t *drb, const nr_rlc_configuration_t *rlc_config) { const NR_RLC_Config_PR rlc_conf = drb->rlc_mode == F1AP_RLC_MODE_AM ? NR_RLC_Config_PR_am : NR_RLC_Config_PR_um_Bi_Directional; long priority = 13; // hardcoded for the moment - return get_DRB_RLC_BearerConfig(get_lcid_from_drbid(drb->drb_id), drb->drb_id, rlc_conf, priority, rlc_config); + return get_DRB_RLC_BearerConfig(get_lcid_from_drbid(drb->id), drb->id, rlc_conf, priority, rlc_config); } static int get_non_dynamic_priority(int fiveqi) @@ -284,20 +286,20 @@ static int get_non_dynamic_priority(int fiveqi) return 0; } -static NR_QoS_config_t get_qos_config(const f1ap_qos_characteristics_t *qos_char) +static NR_QoS_config_t get_qos_config(const f1ap_qos_flow_param_t *qos) { NR_QoS_config_t qos_c = {0}; - switch (qos_char->qos_type) { + switch (qos->qos_type) { case DYNAMIC: - qos_c.priority = qos_char->dynamic.qos_priority_level; - qos_c.fiveQI = qos_char->dynamic.fiveqi > 0 ? qos_char->dynamic.fiveqi : 0; + qos_c.priority = qos->dyn.prio; + qos_c.fiveQI = 0; // does not exist for non-dynamic break; case NON_DYNAMIC: - qos_c.fiveQI = qos_char->non_dynamic.fiveqi; - qos_c.priority = get_non_dynamic_priority(qos_char->non_dynamic.fiveqi); + qos_c.fiveQI = qos->nondyn.fiveQI; + qos_c.priority = get_non_dynamic_priority(qos_c.fiveQI); break; default: - AssertFatal(false, "illegal QoS type %d\n", qos_char->qos_type); + AssertFatal(false, "illegal QoS type %d\n", qos->qos_type); break; } return qos_c; @@ -305,8 +307,8 @@ static NR_QoS_config_t get_qos_config(const f1ap_qos_characteristics_t *qos_char static int handle_ue_context_drbs_setup(NR_UE_info_t *UE, int drbs_len, - const f1ap_drb_to_be_setup_t *req_drbs, - f1ap_drb_to_be_setup_t **resp_drbs, + const f1ap_drb_to_setup_t *req_drbs, + f1ap_drb_setup_t **resp_drbs, NR_CellGroupConfig_t *cellGroupConfig, const nr_rlc_configuration_t *rlc_config) { @@ -318,32 +320,41 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE, *resp_drbs = calloc(drbs_len, sizeof(**resp_drbs)); AssertFatal(*resp_drbs != NULL, "out of memory\n"); for (int i = 0; i < drbs_len; i++) { - const f1ap_drb_to_be_setup_t *drb = &req_drbs[i]; - f1ap_drb_to_be_setup_t *resp_drb = &(*resp_drbs)[i]; + const f1ap_drb_to_setup_t *drb = &req_drbs[i]; + AssertFatal(drb->qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS supported\n"); + f1ap_drb_setup_t *resp_drb = &(*resp_drbs)[i]; NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_drb(drb, rlc_config); - nr_rlc_add_drb(UE->rnti, drb->drb_id, rlc_BearerConfig); + if (UE->capability && UE->capability->rlc_Parameters && UE->capability->rlc_Parameters->ext2 + && UE->capability->rlc_Parameters->ext2->am_WithLongSN_RedCap_r17 == NULL) { + *rlc_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size12; + *rlc_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size12; + } - nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .nssai = drb->nssai}; + nr_rlc_add_drb(UE->rnti, drb->id, rlc_BearerConfig); + + nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .nssai = drb->nr.nssai}; int prio = 100; - for (int q = 0; q < drb->drb_info.flows_to_be_setup_length; ++q) { - c.qos_config[q] = get_qos_config(&drb->drb_info.flows_mapped_to_drb[q].qos_params.qos_characteristics); + for (int q = 0; q < drb->nr.flows_len; ++q) { + c.qos_config[q] = get_qos_config(&drb->nr.flows[q].param); prio = min(prio, c.qos_config[q].priority); } c.priority = prio; nr_mac_add_lcid(&UE->UE_sched_ctrl, &c); - *resp_drb = *drb; + resp_drb->id = drb->id; + resp_drb->lcid = malloc_or_fail(sizeof(*resp_drb->lcid)); + *resp_drb->lcid = c.lcid; // just put same number of tunnels in DL as in UL - DevAssert(drb->up_ul_tnl_length == 1); - resp_drb->up_dl_tnl_length = drb->up_ul_tnl_length; + DevAssert(drb->up_ul_tnl_len == 1); + resp_drb->up_dl_tnl_len = drb->up_ul_tnl_len; if (f1inst >= 0) { // we actually use F1-U int qfi = -1; // don't put PDU session marker in GTP gtpv1u_gnb_create_tunnel_resp_t resp_f1 = {0}; int ret = drb_gtpu_create(f1inst, UE->rnti, - drb->drb_id, - drb->drb_id, + drb->id, + drb->id, qfi, drb->up_ul_tnl[0].tl_address, drb->up_ul_tnl[0].teid, @@ -365,7 +376,7 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE, static int handle_ue_context_drbs_release(NR_UE_info_t *UE, int drbs_len, - const f1ap_drb_to_be_released_t *req_drbs, + const f1ap_drb_to_release_t *req_drbs, NR_CellGroupConfig_t *cellGroupConfig) { DevAssert(req_drbs != NULL && cellGroupConfig != NULL); @@ -377,9 +388,9 @@ static int handle_ue_context_drbs_release(NR_UE_info_t *UE, /* Note: the actual GTP tunnels are already removed in the F1AP message * decoding */ for (int i = 0; i < drbs_len; i++) { - const f1ap_drb_to_be_released_t *drb = &req_drbs[i]; + const f1ap_drb_to_release_t *drb = &req_drbs[i]; - long lcid = get_lcid_from_drbid(drb->rb_id); + long lcid = get_lcid_from_drbid(drb->id); int idx = 0; while (idx < cellGroupConfig->rlc_BearerToAddModList->list.count) { const NR_RLC_BearerConfig_t *bc = cellGroupConfig->rlc_BearerToAddModList->list.array[idx]; @@ -391,7 +402,7 @@ static int handle_ue_context_drbs_release(NR_UE_info_t *UE, nr_mac_remove_lcid(&UE->UE_sched_ctrl, lcid); nr_rlc_release_entity(UE->rnti, lcid); if (f1inst >= 0) - newGtpuDeleteOneTunnel(f1inst, UE->rnti, drb->rb_id); + newGtpuDeleteOneTunnel(f1inst, UE->rnti, drb->id); asn_sequence_del(&cellGroupConfig->rlc_BearerToAddModList->list, idx, 1); long *plcid = malloc(sizeof(*plcid)); AssertFatal(plcid, "out of memory\n"); @@ -553,20 +564,19 @@ static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id, const NR_C DevAssert(success); NR_UE_info_t *UE = get_new_nr_ue_inst(&mac->UE_info.uid_allocator, rnti, NULL); - AssertFatal(UE != NULL, "cannot create UE context, UE context setup failure not implemented\n"); + AssertFatal(UE->uid < MAX_MOBILES_PER_GNB, "cannot create UE context, UE context setup failure not implemented\n"); NR_CellGroupConfig_t *cellGroupConfig = NULL; NR_COMMON_channels_t *cc = &mac->common_channels[CC_id]; const NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - const NR_ServingCellConfig_t *sccd = cc->pre_ServingCellConfig; const nr_mac_config_t *configuration = &mac->radio_config; if (is_SA) { - cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config, &mac->rlc_config); - cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc); + cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, &mac->radio_config, &mac->rlc_config); + cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc, mac->frame); } else { NR_UE_NR_Capability_t *cap = get_ue_nr_cap_from_cg_config_info(cgci); - cellGroupConfig = get_default_secondaryCellGroup(scc, sccd, cap, 1, 1, configuration, UE->uid); - cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc); + cellGroupConfig = get_default_secondaryCellGroup(scc, cap, 1, 1, configuration, UE->uid); + cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc, mac->frame); // TODO: in NSA we assign capabilities here, otherwise outside => not logic UE->capability = cap; } @@ -599,34 +609,31 @@ static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id, const NR_C return UE; } -void ue_context_setup_request(const f1ap_ue_context_setup_t *req) +void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req) { const bool is_SA = IS_SA_MODE(get_softmodem_params()); gNB_MAC_INST *mac = RC.nrmac[0]; - /* response has same type as request... */ - f1ap_ue_context_setup_t resp = { + + f1ap_ue_context_setup_resp_t resp = { .gNB_CU_ue_id = req->gNB_CU_ue_id, - .gNB_DU_ue_id = req->gNB_DU_ue_id, }; - /* gNB-DU UE ID is optional. As of now, the F1AP module fills -1 (on uint, so - * 0xffffffff), but the DU uses the RNTI, so check if it's a legal RNTI in - * which case we consider; if not, assume no DU UE ID given */ - bool ue_id_provided = resp.gNB_DU_ue_id > 0 && resp.gNB_DU_ue_id < 0xffff; + bool ue_id_provided = req->gNB_DU_ue_id != NULL; - NR_UE_NR_Capability_t *ue_cap = NULL; + const f1ap_cu_to_du_rrc_info_t *cu2du = &req->cu_to_du_rrc_info; NR_CG_ConfigInfo_t *cg_configinfo = NULL; - if (req->cu_to_du_rrc_information != NULL) { - const cu_to_du_rrc_information_t *cu2du = req->cu_to_du_rrc_information; - if (cu2du->cG_ConfigInfo != NULL) - cg_configinfo = get_cg_config_info(cu2du->cG_ConfigInfo, cu2du->cG_ConfigInfo_length); - if (cu2du->handoverPreparationInfo != NULL) { - ue_cap = get_ue_nr_cap_from_ho_prep_info(cu2du->handoverPreparationInfo, cu2du->handoverPreparationInfo_length); - } else if (cu2du->uE_CapabilityRAT_ContainerList != NULL) { - ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id, cu2du->uE_CapabilityRAT_ContainerList, cu2du->uE_CapabilityRAT_ContainerList_length); - } - AssertFatal(cu2du->measConfig == NULL, "MeasConfig not handled\n"); + if (cu2du->cg_configinfo != NULL) + cg_configinfo = get_cg_config_info(cu2du->cg_configinfo->buf, cu2du->cg_configinfo->len); + NR_UE_NR_Capability_t *ue_cap = NULL; + if (cu2du->ho_prep_info != NULL) { + ue_cap = get_ue_nr_cap_from_ho_prep_info(cu2du->ho_prep_info->buf, cu2du->ho_prep_info->len); + } else if (cu2du->ue_cap != NULL) { + ue_cap = get_ue_nr_cap(*req->gNB_DU_ue_id, cu2du->ue_cap->buf, cu2du->ue_cap->len); } + NR_MeasurementTimingConfiguration_t *mtc = NULL; + if (cu2du->meas_timing_config != NULL) + mtc = get_nr_mtc(cu2du->meas_timing_config->buf, cu2du->meas_timing_config->len); + /* 38.473: "For DC operation, the CG-ConfigInfo IE shall be included in the CU * to DU RRC Information IE at the gNB acting as secondary node" As of now, * we only handle NSA => we check we have CG-ConfigInfo if not SA or have SA @@ -639,40 +646,34 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) if (!ue_id_provided) { UE = create_new_UE(mac, req->gNB_CU_ue_id, cg_configinfo); resp.gNB_DU_ue_id = UE->rnti; - resp.crnti = &UE->rnti; + resp.crnti = malloc_or_fail(sizeof(*resp.crnti)); + *resp.crnti = UE->rnti; } else { DevAssert(is_SA); - UE = find_nr_UE(&mac->UE_info, req->gNB_DU_ue_id); + UE = find_nr_UE(&mac->UE_info, *req->gNB_DU_ue_id); } AssertFatal(UE, "no UE found or could not be created, but UE Context Setup Failed not implemented\n"); + resp.gNB_DU_ue_id = UE->rnti; NR_CellGroupConfig_t *new_CellGroup = clone_CellGroupConfig(UE->CellGroup); + // Needed for DRB Setup (e.g., RLC might reduce SN size) + UE->capability = ue_cap; - if (req->srbs_to_be_setup_length > 0) { - resp.srbs_to_be_setup_length = handle_ue_context_srbs_setup(UE, - req->srbs_to_be_setup_length, - req->srbs_to_be_setup, - &resp.srbs_to_be_setup, - new_CellGroup, - &mac->rlc_config); + if (req->srbs_len > 0) { + resp.srbs_len = handle_ue_context_srbs_setup(UE, req->srbs_len, req->srbs, &resp.srbs, new_CellGroup, &mac->rlc_config); } - if (req->drbs_to_be_setup_length > 0) { - resp.drbs_to_be_setup_length = handle_ue_context_drbs_setup(UE, - req->drbs_to_be_setup_length, - req->drbs_to_be_setup, - &resp.drbs_to_be_setup, - new_CellGroup, - &mac->rlc_config); + if (req->drbs_len > 0) { + resp.drbs_len = + handle_ue_context_drbs_setup(UE, req->drbs_len, req->drbs, &resp.drbs, new_CellGroup, &mac->rlc_config); } if (req->rrc_container != NULL) { logical_chan_id_t id = 1; - nr_rlc_srb_recv_sdu(req->gNB_DU_ue_id, id, req->rrc_container, req->rrc_container_length); + nr_rlc_srb_recv_sdu(UE->rnti, id, req->rrc_container->buf, req->rrc_container->len); } NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; - UE->capability = ue_cap; if (ue_cap != NULL && cg_configinfo == NULL) { // store the new UE capabilities, and update the cellGroupConfig // only to be done if we did not already update through the cg_configinfo @@ -691,51 +692,53 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) } } - resp.du_to_cu_rrc_information = calloc(1, sizeof(du_to_cu_rrc_information_t)); - AssertFatal(resp.du_to_cu_rrc_information != NULL, "out of memory\n"); - resp.du_to_cu_rrc_information->cellGroupConfig = calloc(1,1024); - AssertFatal(resp.du_to_cu_rrc_information->cellGroupConfig != NULL, "out of memory\n"); + byte_array_t cgc = { .buf = calloc_or_fail(1,1024) }; asn_enc_rval_t enc_rval = - uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, new_CellGroup, resp.du_to_cu_rrc_information->cellGroupConfig, 1024); + uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, new_CellGroup, cgc.buf, 1024); AssertFatal(enc_rval.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval.failed_type->name); - resp.du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded + 7) >> 3; + cgc.len = (enc_rval.encoded + 7) >> 3; + resp.du_to_cu_rrc_info.cell_group_config = cgc; ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = new_CellGroup; int ss_type = cg_configinfo ? NR_SearchSpace__searchSpaceType_PR_ue_Specific: NR_SearchSpace__searchSpaceType_PR_common; configure_UE_BWP(mac, scc, UE, false, ss_type, -1, -1); + if (mtc) { + /* creates a suitable measGap config to be used in the gNB */ + UE->measgap_config = create_measgap_config(mtc, UE->current_DL_BWP.scs, mac->radio_config.minRXTXTIME); + /* encodes the measGapConfig created, if useful (or not!) */ + byte_array_t *mgc = calloc_or_fail(1, sizeof(*mgc)); + mgc->buf = calloc_or_fail(1, 1024); + mgc->len = encode_measgap_config(&UE->measgap_config, mgc->buf); + resp.du_to_cu_rrc_info.meas_gap_config = mgc; + } + NR_SCHED_UNLOCK(&mac->sched_lock); - /* some sanity checks, since we use the same type for request and response */ - DevAssert(resp.cu_to_du_rrc_information == NULL); - DevAssert(resp.du_to_cu_rrc_information != NULL); - DevAssert(resp.rrc_container == NULL && resp.rrc_container_length == 0); - - mac->mac_rrc.ue_context_setup_response(req, &resp); + mac->mac_rrc.ue_context_setup_response(&resp); /* free the memory we allocated above */ - free(resp.srbs_to_be_setup); - free(resp.drbs_to_be_setup); - free(resp.du_to_cu_rrc_information->cellGroupConfig); - free(resp.du_to_cu_rrc_information); + free_ue_context_setup_resp(&resp); + ASN_STRUCT_FREE(asn_DEF_NR_CG_ConfigInfo, cg_configinfo); + ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); } -void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) +void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req) { gNB_MAC_INST *mac = RC.nrmac[0]; - f1ap_ue_context_modif_resp_t resp = { + f1ap_ue_context_mod_resp_t resp = { .gNB_CU_ue_id = req->gNB_CU_ue_id, .gNB_DU_ue_id = req->gNB_DU_ue_id, }; NR_UE_NR_Capability_t *ue_cap = NULL; - if (req->cu_to_du_rrc_information != NULL) { - AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n"); - ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id, - req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, - req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length); - AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL, "MeasConfig not handled\n"); + if (req->cu_to_du_rrc_info != NULL) { + AssertFatal(req->cu_to_du_rrc_info->cg_configinfo == NULL, "CG-ConfigInfo not handled\n"); + if (req->cu_to_du_rrc_info->ue_cap) { + byte_array_t *b = req->cu_to_du_rrc_info->ue_cap; + ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id, b->buf, b->len); + } } NR_SCHED_LOCK(&mac->sched_lock); @@ -748,39 +751,28 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) NR_CellGroupConfig_t *new_CellGroup = clone_CellGroupConfig(UE->CellGroup); - if (req->srbs_to_be_setup_length > 0) { - resp.srbs_to_be_setup_length = handle_ue_context_srbs_setup(UE, - req->srbs_to_be_setup_length, - req->srbs_to_be_setup, - &resp.srbs_to_be_setup, - new_CellGroup, - &mac->rlc_config); + if (req->srbs_len > 0) { + resp.srbs_len = handle_ue_context_srbs_setup(UE, req->srbs_len, req->srbs, &resp.srbs, new_CellGroup, &mac->rlc_config); } - if (req->drbs_to_be_setup_length > 0) { - resp.drbs_to_be_setup_length = handle_ue_context_drbs_setup(UE, - req->drbs_to_be_setup_length, - req->drbs_to_be_setup, - &resp.drbs_to_be_setup, - new_CellGroup, - &mac->rlc_config); + if (req->drbs_len > 0) { + resp.drbs_len = handle_ue_context_drbs_setup(UE, req->drbs_len, req->drbs, &resp.drbs, new_CellGroup, &mac->rlc_config); } - if (req->drbs_to_be_released_length > 0) { - resp.drbs_to_be_released_length = - handle_ue_context_drbs_release(UE, req->drbs_to_be_released_length, req->drbs_to_be_released, new_CellGroup); + if (req->drbs_rel_len > 0) { + handle_ue_context_drbs_release(UE, req->drbs_rel_len, req->drbs_rel, new_CellGroup); } if (req->rrc_container != NULL) { logical_chan_id_t id = 1; - nr_rlc_srb_recv_sdu(req->gNB_DU_ue_id, id, req->rrc_container, req->rrc_container_length); + nr_rlc_srb_recv_sdu(req->gNB_DU_ue_id, id, req->rrc_container->buf, req->rrc_container->len); } NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; - if (req->ReconfigComplOutcome != RRCreconf_info_not_present && req->ReconfigComplOutcome != RRCreconf_success) { + if (req->reconfig_compl && *req->reconfig_compl != RRCreconf_success) { LOG_E(NR_MAC, "RRC reconfiguration outcome unsuccessful, but no rollback mechanism implemented to come back to old configuration\n"); - } else if (req->ReconfigComplOutcome == RRCreconf_success) { + } else if (req->reconfig_compl) { LOG_I(NR_MAC, "DU received confirmation of successful RRC Reconfiguration\n"); if (UE->reconfigSpCellConfig) { // in case of reestablishment, the spCellConfig had to be released @@ -794,8 +786,8 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) } } // we re-configure the BWP to apply the CellGroup and to use UE specific Search Space with DCIX1 - nr_mac_clean_cellgroup(UE->CellGroup); configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1); + nr_mac_clean_cellgroup(UE->CellGroup); } if (ue_cap != NULL) { @@ -806,19 +798,17 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc); } - if (req->srbs_to_be_setup_length > 0 || req->drbs_to_be_setup_length > 0 || req->drbs_to_be_released_length > 0 - || ue_cap != NULL) { - resp.du_to_cu_rrc_information = calloc(1, sizeof(du_to_cu_rrc_information_t)); - AssertFatal(resp.du_to_cu_rrc_information != NULL, "out of memory\n"); - resp.du_to_cu_rrc_information->cellGroupConfig = calloc(1, 1024); - AssertFatal(resp.du_to_cu_rrc_information->cellGroupConfig != NULL, "out of memory\n"); + if (req->srbs_len > 0 || req->drbs_len > 0 || req->drbs_rel_len > 0 || ue_cap != NULL) { + resp.du_to_cu_rrc_info = calloc_or_fail(1, sizeof(du_to_cu_rrc_information_t)); + byte_array_t cgc = { .buf = calloc_or_fail(1, 1024) }; asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, new_CellGroup, - resp.du_to_cu_rrc_information->cellGroupConfig, + cgc.buf, 1024); AssertFatal(enc_rval.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval.failed_type->name); - resp.du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded + 7) >> 3; + cgc.len = (enc_rval.encoded + 7) >> 3; + resp.du_to_cu_rrc_info->cell_group_config = cgc; ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = new_CellGroup; @@ -833,20 +823,10 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) } NR_SCHED_UNLOCK(&mac->sched_lock); - /* some sanity checks, since we use the same type for request and response */ - DevAssert(resp.cu_to_du_rrc_information == NULL); - // resp.du_to_cu_rrc_information can be either NULL or not - DevAssert(resp.rrc_container == NULL && resp.rrc_container_length == 0); - - mac->mac_rrc.ue_context_modification_response(req, &resp); + mac->mac_rrc.ue_context_modification_response(&resp); /* free the memory we allocated above */ - free(resp.srbs_to_be_setup); - free(resp.drbs_to_be_setup); - if (resp.du_to_cu_rrc_information != NULL) { - free(resp.du_to_cu_rrc_information->cellGroupConfig); - free(resp.du_to_cu_rrc_information); - } + free_ue_context_mod_resp(&resp); } void ue_context_modification_confirm(const f1ap_ue_context_modif_confirm_t *confirm) @@ -891,7 +871,7 @@ void ue_context_modification_refuse(const f1ap_ue_context_modif_refuse_t *refuse NR_SCHED_UNLOCK(&mac->sched_lock); - f1ap_ue_context_release_req_t request = { + f1ap_ue_context_rel_req_t request = { .gNB_CU_ue_id = refuse->gNB_CU_ue_id, .gNB_DU_ue_id = refuse->gNB_DU_ue_id, .cause = F1AP_CAUSE_RADIO_NETWORK, @@ -900,15 +880,16 @@ void ue_context_modification_refuse(const f1ap_ue_context_modif_refuse_t *refuse mac->mac_rrc.ue_context_release_request(&request); } -void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd) +void ue_context_release_command(const f1ap_ue_context_rel_cmd_t *cmd) { /* mark UE as to be deleted after PUSCH failure */ gNB_MAC_INST *mac = RC.nrmac[0]; NR_SCHED_LOCK(&mac->sched_lock); NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, cmd->gNB_DU_ue_id); + UE = UE ? UE : find_ra_UE(&mac->UE_info, cmd->gNB_DU_ue_id); if (UE == NULL) { NR_SCHED_UNLOCK(&mac->sched_lock); - f1ap_ue_context_release_complete_t complete = { + f1ap_ue_context_rel_cplt_t complete = { .gNB_CU_ue_id = cmd->gNB_CU_ue_id, .gNB_DU_ue_id = cmd->gNB_DU_ue_id, }; @@ -920,14 +901,15 @@ void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd) if (f1inst >= 0) newGtpuDeleteAllTunnels(f1inst, cmd->gNB_DU_ue_id); - if (UE->UE_sched_ctrl.ul_failure || cmd->rrc_container_length == 0) { + if (UE->UE_sched_ctrl.ul_failure || !cmd->rrc_container) { /* The UE is already not connected anymore or we have nothing to forward*/ nr_mac_release_ue(mac, cmd->gNB_DU_ue_id); nr_mac_trigger_release_complete(mac, cmd->gNB_DU_ue_id); - } else { + } else if (cmd->rrc_container && cmd->srb_id){ /* UE is in sync: forward release message and mark to be deleted * after UL failure */ - nr_rlc_srb_recv_sdu(cmd->gNB_DU_ue_id, cmd->srb_id, cmd->rrc_container, cmd->rrc_container_length); + byte_array_t *rrc_cont = cmd->rrc_container; + nr_rlc_srb_recv_sdu(cmd->gNB_DU_ue_id, *cmd->srb_id, rrc_cont->buf, rrc_cont->len); nr_mac_trigger_release_timer(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs); } NR_SCHED_UNLOCK(&mac->sched_lock); @@ -986,6 +968,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) UE->CellGroup = oldUE->CellGroup; oldUE->CellGroup = NULL; UE->mac_stats = oldUE->mac_stats; + UE->measgap_config = oldUE->measgap_config; /* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it * from the current configuration. It will be reapplied when the * reconfiguration has succeeded (indicated by the CU) */ diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h index e9aceb1192..1ba31f8e80 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h @@ -32,11 +32,11 @@ void f1_setup_response(const f1ap_setup_resp_t *resp); void f1_setup_failure(const f1ap_setup_failure_t *failure); void gnb_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_update_acknowledge_t *ack); NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig); -void ue_context_setup_request(const f1ap_ue_context_setup_t *req); -void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req); +void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req); +void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req); void ue_context_modification_confirm(const f1ap_ue_context_modif_confirm_t *confirm); void ue_context_modification_refuse(const f1ap_ue_context_modif_refuse_t *refuse); -void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd); +void ue_context_release_command(const f1ap_ue_context_rel_cmd_t *cmd); void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h index 1e416f01f9..23dda86dfb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul.h @@ -31,12 +31,11 @@ typedef void (*f1_reset_acknowledge_cu_initiated_func_t)(const f1ap_reset_ack_t typedef void (*f1_setup_request_func_t)(const f1ap_setup_req_t* req); typedef void (*gnb_du_configuration_update_t)(const f1ap_gnb_du_configuration_update_t *upd); -typedef void (*ue_context_setup_response_func_t)(const f1ap_ue_context_setup_t* req, const f1ap_ue_context_setup_t *resp); -typedef void (*ue_context_modification_response_func_t)(const f1ap_ue_context_modif_req_t *req, - const f1ap_ue_context_modif_resp_t *resp); +typedef void (*ue_context_setup_response_func_t)(const f1ap_ue_context_setup_resp_t *resp); +typedef void (*ue_context_modification_response_func_t)(const f1ap_ue_context_mod_resp_t *resp); typedef void (*ue_context_modification_required_func_t)(const f1ap_ue_context_modif_required_t *t); -typedef void (*ue_context_release_request_func_t)(const f1ap_ue_context_release_req_t* req); -typedef void (*ue_context_release_complete_func_t)(const f1ap_ue_context_release_complete_t *complete); +typedef void (*ue_context_release_request_func_t)(const f1ap_ue_context_rel_req_t* req); +typedef void (*ue_context_release_complete_func_t)(const f1ap_ue_context_rel_cplt_t *complete); typedef void (*initial_ul_rrc_message_transfer_func_t)(module_id_t module_id, const f1ap_initial_ul_rrc_message_t *ul_rrc); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index e687991a5e..deec619e3d 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -23,8 +23,9 @@ #include "intertask_interface.h" #include "mac_rrc_ul.h" -#include "f1ap_lib_extern.h" +#include "lib/f1ap_rrc_message_transfer.h" #include "lib/f1ap_interface_management.h" +#include "lib/f1ap_ue_context.h" static void f1_reset_du_initiated_direct(const f1ap_reset_t *reset) { @@ -58,96 +59,19 @@ static void gnb_du_configuration_update_direct(const f1ap_gnb_du_configuration_u itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } -static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) +static void ue_context_setup_response_direct(const f1ap_ue_context_setup_resp_t *resp) { - DevAssert(req->drbs_to_be_setup_length == resp->drbs_to_be_setup_length); - - (void) req; /* we don't need the request -- it is to set up GTP in F1 case */ MessageDef *msg = itti_alloc_new_message (TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_SETUP_RESP); msg->ittiMsgHeader.originInstance = -1; // means monolithic - f1ap_ue_context_setup_t *f1ap_msg = &F1AP_UE_CONTEXT_SETUP_RESP(msg); - /* copy all fields, but reallocate memory buffers! */ - *f1ap_msg = *resp; - - if (resp->srbs_to_be_setup_length > 0) { - DevAssert(resp->srbs_to_be_setup != NULL); - f1ap_msg->srbs_to_be_setup_length = resp->srbs_to_be_setup_length; - f1ap_msg->srbs_to_be_setup = calloc(f1ap_msg->srbs_to_be_setup_length, sizeof(*f1ap_msg->srbs_to_be_setup)); - for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) - f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; - } - if (resp->drbs_to_be_setup_length > 0) { - DevAssert(resp->drbs_to_be_setup != NULL); - f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; - f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); - for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) - f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; - } - - f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); - AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); - f1ap_msg->du_to_cu_rrc_information_length = resp->du_to_cu_rrc_information_length; - du_to_cu_rrc_information_t *du2cu = f1ap_msg->du_to_cu_rrc_information; - du2cu->cellGroupConfig_length = resp->du_to_cu_rrc_information->cellGroupConfig_length; - du2cu->cellGroupConfig = calloc(du2cu->cellGroupConfig_length, sizeof(*du2cu->cellGroupConfig)); - AssertFatal(du2cu->cellGroupConfig != NULL, "out of memory\n"); - memcpy(du2cu->cellGroupConfig, resp->du_to_cu_rrc_information->cellGroupConfig, du2cu->cellGroupConfig_length); - + F1AP_UE_CONTEXT_SETUP_RESP(msg) = cp_ue_context_setup_resp(resp); itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } -static void ue_context_modification_response_direct(const f1ap_ue_context_modif_req_t *req, - const f1ap_ue_context_modif_resp_t *resp) +static void ue_context_modification_response_direct(const f1ap_ue_context_mod_resp_t *resp) { - (void)req; /* we don't need the request -- it is to set up GTP in F1 case */ MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_MODIFICATION_RESP); msg->ittiMsgHeader.originInstance = -1; // means monolithic - f1ap_ue_context_modif_resp_t *f1ap_msg = &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg); - - f1ap_msg->gNB_CU_ue_id = resp->gNB_CU_ue_id; - f1ap_msg->gNB_DU_ue_id = resp->gNB_DU_ue_id; - f1ap_msg->plmn = resp->plmn; - f1ap_msg->nr_cellid = resp->nr_cellid; - f1ap_msg->servCellIndex = resp->servCellIndex; - AssertFatal(resp->cellULConfigured == NULL, "not handled\n"); - f1ap_msg->servCellId = resp->servCellId; - - DevAssert(resp->cu_to_du_rrc_information == NULL && resp->cu_to_du_rrc_information_length == 0); - if (resp->du_to_cu_rrc_information) { - f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); - AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); - f1ap_msg->du_to_cu_rrc_information_length = resp->du_to_cu_rrc_information_length; - du_to_cu_rrc_information_t *du2cu = f1ap_msg->du_to_cu_rrc_information; - du2cu->cellGroupConfig_length = resp->du_to_cu_rrc_information->cellGroupConfig_length; - du2cu->cellGroupConfig = calloc(du2cu->cellGroupConfig_length, sizeof(*du2cu->cellGroupConfig)); - AssertFatal(du2cu->cellGroupConfig != NULL, "out of memory\n"); - memcpy(du2cu->cellGroupConfig, resp->du_to_cu_rrc_information->cellGroupConfig, du2cu->cellGroupConfig_length); - } - - if (resp->drbs_to_be_setup_length > 0) { - DevAssert(resp->drbs_to_be_setup != NULL); - f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; - f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); - for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) - f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; - } - - DevAssert(resp->drbs_to_be_modified == NULL && resp->drbs_to_be_modified_length == 0); - f1ap_msg->QoS_information_type = resp->QoS_information_type; - AssertFatal(resp->drbs_failed_to_be_setup_length == 0 && resp->drbs_failed_to_be_setup == NULL, "not implemented yet\n"); - - if (resp->srbs_to_be_setup_length > 0) { - DevAssert(resp->srbs_to_be_setup != NULL); - f1ap_msg->srbs_to_be_setup_length = resp->srbs_to_be_setup_length; - f1ap_msg->srbs_to_be_setup = calloc(f1ap_msg->srbs_to_be_setup_length, sizeof(*f1ap_msg->srbs_to_be_setup)); - for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) - f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; - } - - AssertFatal(resp->srbs_failed_to_be_setup_length == 0 && resp->srbs_failed_to_be_setup == NULL, "not implemented yet\n"); - - DevAssert(resp->rrc_container == NULL && resp->rrc_container_length == 0); - + F1AP_UE_CONTEXT_MODIFICATION_RESP(msg) = cp_ue_context_mod_resp(resp); itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } @@ -169,7 +93,6 @@ static void ue_context_modification_required_direct(const f1ap_ue_context_modif_ du2cu->cellGroupConfig = malloc(du2cu->cellGroupConfig_length * sizeof(*du2cu->cellGroupConfig)); AssertFatal(du2cu->cellGroupConfig != NULL, "out of memory\n"); memcpy(du2cu->cellGroupConfig, required->du_to_cu_rrc_information->cellGroupConfig, du2cu->cellGroupConfig_length); - AssertFatal(required->du_to_cu_rrc_information->measGapConfig == NULL && required->du_to_cu_rrc_information->measGapConfig_length == 0, "not handled yet\n"); AssertFatal(required->du_to_cu_rrc_information->requestedP_MaxFR1 == NULL && required->du_to_cu_rrc_information->requestedP_MaxFR1_length == 0, "not handled yet\n"); } f1ap_msg->cause = required->cause; @@ -177,21 +100,19 @@ static void ue_context_modification_required_direct(const f1ap_ue_context_modif_ itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } -static void ue_context_release_request_direct(const f1ap_ue_context_release_req_t* req) +static void ue_context_release_request_direct(const f1ap_ue_context_rel_req_t* req) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_REQ); msg->ittiMsgHeader.originInstance = -1; // means monolithic - f1ap_ue_context_release_req_t *f1ap_msg = &F1AP_UE_CONTEXT_RELEASE_REQ(msg); - *f1ap_msg = *req; + F1AP_UE_CONTEXT_RELEASE_REQ(msg) = cp_ue_context_rel_req(req); itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } -static void ue_context_release_complete_direct(const f1ap_ue_context_release_complete_t *complete) +static void ue_context_release_complete_direct(const f1ap_ue_context_rel_cplt_t *complete) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_COMPLETE); msg->ittiMsgHeader.originInstance = -1; // means monolithic - f1ap_ue_context_release_complete_t *f1ap_msg = &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg); - *f1ap_msg = *complete; + F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg) = cp_ue_context_rel_cplt(complete); itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 81373e0bc9..c7e23ed702 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -29,8 +29,9 @@ #include "mac_rrc_ul.h" -#include "f1ap_lib_extern.h" +#include "lib/f1ap_rrc_message_transfer.h" #include "lib/f1ap_interface_management.h" +#include "lib/f1ap_ue_context.h" static f1ap_net_config_t read_DU_IP_config(const eth_params_t* f1_params, const char *f1u_ip_addr) { @@ -85,80 +86,17 @@ static void gnb_du_configuration_update_f1ap(const f1ap_gnb_du_configuration_upd itti_send_msg_to_task(TASK_DU_F1, 0, msg); } -static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) +static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_resp_t *resp) { - DevAssert(req->drbs_to_be_setup_length == resp->drbs_to_be_setup_length); - - DevAssert(req->srbs_to_be_setup_length == resp->srbs_to_be_setup_length); MessageDef *msg = itti_alloc_new_message (TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_SETUP_RESP); - f1ap_ue_context_setup_t *f1ap_msg = &F1AP_UE_CONTEXT_SETUP_RESP(msg); - /* copy all fields, but reallocate rrc_containers! */ - *f1ap_msg = *resp; - - if (resp->srbs_to_be_setup_length > 0) { - DevAssert(resp->srbs_to_be_setup != NULL); - f1ap_msg->srbs_to_be_setup_length = resp->srbs_to_be_setup_length; - f1ap_msg->srbs_to_be_setup = calloc(f1ap_msg->srbs_to_be_setup_length, sizeof(*f1ap_msg->srbs_to_be_setup)); - for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) - f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; - } - if (resp->drbs_to_be_setup_length > 0) { - DevAssert(resp->drbs_to_be_setup != NULL); - f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; - f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); - for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) - f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; - } - if (resp->crnti) { - f1ap_msg->crnti = calloc(1, sizeof(uint16_t)); - *f1ap_msg->crnti = *resp->crnti; - } - - f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); - AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); - f1ap_msg->du_to_cu_rrc_information_length = resp->du_to_cu_rrc_information_length; - du_to_cu_rrc_information_t *du2cu = f1ap_msg->du_to_cu_rrc_information; - du2cu->cellGroupConfig_length = resp->du_to_cu_rrc_information->cellGroupConfig_length; - du2cu->cellGroupConfig = calloc(du2cu->cellGroupConfig_length, sizeof(*du2cu->cellGroupConfig)); - AssertFatal(du2cu->cellGroupConfig != NULL, "out of memory\n"); - memcpy(du2cu->cellGroupConfig, resp->du_to_cu_rrc_information->cellGroupConfig, du2cu->cellGroupConfig_length); - + F1AP_UE_CONTEXT_SETUP_RESP(msg) = cp_ue_context_setup_resp(resp); itti_send_msg_to_task(TASK_DU_F1, 0, msg); } -static void ue_context_modification_response_f1ap(const f1ap_ue_context_modif_req_t *req, const f1ap_ue_context_modif_resp_t *resp) +static void ue_context_modification_response_f1ap(const f1ap_ue_context_mod_resp_t *resp) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_MODIFICATION_RESP); - f1ap_ue_context_modif_resp_t *f1ap_msg = &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg); - /* copy all fields, but reallocate rrc_containers! */ - *f1ap_msg = *resp; - - if (resp->srbs_to_be_setup_length > 0) { - DevAssert(resp->srbs_to_be_setup != NULL); - f1ap_msg->srbs_to_be_setup_length = resp->srbs_to_be_setup_length; - f1ap_msg->srbs_to_be_setup = calloc(f1ap_msg->srbs_to_be_setup_length, sizeof(*f1ap_msg->srbs_to_be_setup)); - for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) - f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; - } - if (resp->drbs_to_be_setup_length > 0) { - DevAssert(resp->drbs_to_be_setup != NULL); - f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; - f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); - for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) - f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; - } - - if (resp->du_to_cu_rrc_information != NULL) { - f1ap_msg->du_to_cu_rrc_information = calloc(1, sizeof(*resp->du_to_cu_rrc_information)); - AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); - f1ap_msg->du_to_cu_rrc_information_length = resp->du_to_cu_rrc_information_length; - du_to_cu_rrc_information_t *du2cu = f1ap_msg->du_to_cu_rrc_information; - du2cu->cellGroupConfig_length = resp->du_to_cu_rrc_information->cellGroupConfig_length; - du2cu->cellGroupConfig = calloc(du2cu->cellGroupConfig_length, sizeof(*du2cu->cellGroupConfig)); - AssertFatal(du2cu->cellGroupConfig != NULL, "out of memory\n"); - memcpy(du2cu->cellGroupConfig, resp->du_to_cu_rrc_information->cellGroupConfig, du2cu->cellGroupConfig_length); - } - + F1AP_UE_CONTEXT_MODIFICATION_RESP(msg) = cp_ue_context_mod_resp(resp); itti_send_msg_to_task(TASK_DU_F1, 0, msg); } @@ -179,7 +117,6 @@ static void ue_context_modification_required_f1ap(const f1ap_ue_context_modif_re du2cu->cellGroupConfig = malloc(du2cu->cellGroupConfig_length * sizeof(*du2cu->cellGroupConfig)); AssertFatal(du2cu->cellGroupConfig != NULL, "out of memory\n"); memcpy(du2cu->cellGroupConfig, required->du_to_cu_rrc_information->cellGroupConfig, du2cu->cellGroupConfig_length); - AssertFatal(required->du_to_cu_rrc_information->measGapConfig == NULL && required->du_to_cu_rrc_information->measGapConfig_length == 0, "not handled yet\n"); AssertFatal(required->du_to_cu_rrc_information->requestedP_MaxFR1 == NULL && required->du_to_cu_rrc_information->requestedP_MaxFR1_length == 0, "not handled yet\n"); } f1ap_msg->cause = required->cause; @@ -187,21 +124,19 @@ static void ue_context_modification_required_f1ap(const f1ap_ue_context_modif_re itti_send_msg_to_task(TASK_DU_F1, 0, msg); } -static void ue_context_release_request_f1ap(const f1ap_ue_context_release_req_t* req) +static void ue_context_release_request_f1ap(const f1ap_ue_context_rel_req_t* req) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_REQ); - f1ap_ue_context_release_req_t *f1ap_msg = &F1AP_UE_CONTEXT_RELEASE_REQ(msg); - *f1ap_msg = *req; + F1AP_UE_CONTEXT_RELEASE_REQ(msg) = cp_ue_context_rel_req(req); itti_send_msg_to_task(TASK_DU_F1, 0, msg); } -static void ue_context_release_complete_f1ap(const f1ap_ue_context_release_complete_t *complete) +static void ue_context_release_complete_f1ap(const f1ap_ue_context_rel_cplt_t *complete) { newGtpuDeleteAllTunnels(0, complete->gNB_DU_ue_id); MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_COMPLETE); - f1ap_ue_context_release_complete_t *f1ap_msg = &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg); - *f1ap_msg = *complete; + F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg) = cp_ue_context_rel_cplt(complete); itti_send_msg_to_task(TASK_DU_F1, 0, msg); } diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 0acc6fe0d2..fa66125bf7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -63,6 +63,7 @@ #include "nr_pdcp/nr_pdcp_oai_api.h" #include "nr_rlc/nr_rlc_oai_api.h" #include "openair2/F1AP/f1ap_ids.h" +#include "openair2/F1AP/lib/f1ap_interface_management.h" #include "seq_arr.h" #include "system.h" #include "time_meas.h" @@ -88,10 +89,12 @@ void *nrmac_stats_thread(void *arg) { p += dump_mac_stats(gNB, p, end - p, false); NR_SCHED_UNLOCK(&gNB->sched_lock); p += snprintf(p, end - p, "\n"); - p += print_meas_log(&gNB->eNB_scheduler, "DL & UL scheduling timing", NULL, NULL, p, end - p); + p += print_meas_log(&gNB->gNB_scheduler, "gNB_scheduler", NULL, NULL, p, end - p); + p += print_meas_log(&gNB->rx_ulsch_sdu, "rx_ulsch_sdu", NULL, NULL, p, end - p); p += print_meas_log(&gNB->schedule_dlsch, "dlsch scheduler", NULL, NULL, p, end - p); + p += print_meas_log(&gNB->schedule_ulsch, "ulsch scheduler", NULL, NULL, p, end - p); + p += print_meas_log(&gNB->schedule_ra, "RA scheduler", NULL, NULL, p, end - p); p += print_meas_log(&gNB->rlc_data_req, "rlc_data_req", NULL, NULL, p, end - p); - p += print_meas_log(&gNB->rlc_status_ind, "rlc_status_ind", NULL, NULL, p, end - p); p += print_meas_log(&gNB->nr_srs_ri_computation_timer, "UL-RI computation time", NULL, NULL, p, end - p); p += print_meas_log(&gNB->nr_srs_tpmi_computation_timer, "UL-TPMI computation time", NULL, NULL, p, end - p); fwrite(output, p - output, 1, file); @@ -123,24 +126,37 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_mac_stats_t *stats = &UE->mac_stats; const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0; + const int avg_sinrx10 = stats->num_sinr_meas > 0 ? stats->cumul_sinrx10 / stats->num_sinr_meas : 0; output += snprintf(output, end - output, "UE RNTI %04x CU-UE-ID ", UE->rnti); if (du_exists_f1_ue_data(UE->rnti)) { f1_ue_data_t ued = du_get_f1_ue_data(UE->rnti); output += snprintf(output, end - output, "%d", ued.secondary_ue); } else { - output += snprintf(output, end-output, "(none)"); + output += snprintf(output, end - output, "(none)"); } bool in_sync = !sched_ctrl->ul_failure; output += snprintf(output, end - output, - " %s PH %d dB PCMAX %d dBm, average RSRP %d (%d meas)\n", + " %s PH %d dB PCMAX %d dBm", in_sync ? "in-sync" : "out-of-sync", sched_ctrl->ph, - sched_ctrl->pcmax, - avg_rsrp, - stats->num_rsrp_meas); + sched_ctrl->pcmax); + + if (stats->num_rsrp_meas) + output += snprintf(output, end - output, ", average RSRP %d (%d meas)", avg_rsrp, stats->num_rsrp_meas); + + if (stats->num_sinr_meas) { + output += snprintf(output, + end - output, + ", average SINR %d.%d (%d meas)", + avg_sinrx10 / 10, + avg_sinrx10 % 10, + stats->num_sinr_meas); + } + + output += snprintf(output, end - output, "\n"); if(sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report) output += snprintf(output, @@ -165,15 +181,18 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset output += snprintf(output, end - output, - ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS (%d) %d\n", + ", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS (%d) %d CCE fail %d\n", stats->dl.errors, stats->pucch0_DTX, sched_ctrl->dl_bler_stats.bler, UE->current_DL_BWP.mcsTableIdx, - sched_ctrl->dl_bler_stats.mcs); + sched_ctrl->dl_bler_stats.mcs, + sched_ctrl->dl_cce_fail); if (reset_rsrp) { stats->num_rsrp_meas = 0; stats->cumul_rsrp = 0; + stats->num_sinr_meas = 0; + stats->cumul_sinrx10 = 0; } output += snprintf(output, end - output, @@ -184,7 +203,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset output += snprintf(output, end - output, - ", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d (Qm %d deltaMCS %d dB) NPRB %d SNR %d.%d dB\n", + ", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d (Qm %d deltaMCS %d dB) NPRB %d SNR %d.%d dB CCE fail %d\n", stats->ul.errors, stats->ulsch_DTX, sched_ctrl->ul_bler_stats.bler, @@ -194,7 +213,8 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset UE->mac_stats.deltaMCS, UE->mac_stats.NPRB, sched_ctrl->pusch_snrx10 / 10, - sched_ctrl->pusch_snrx10 % 10); + sched_ctrl->pusch_snrx10 % 10, + sched_ctrl->ul_cce_fail); output += snprintf(output, end - output, "UE %04x: MAC: TX %14"PRIu64" RX %14"PRIu64" bytes\n", @@ -235,13 +255,9 @@ static void mac_rrc_init(gNB_MAC_INST *mac, ngran_node_t node_type) void mac_top_init_gNB(ngran_node_t node_type, NR_ServingCellConfigCommon_t *scc, - NR_ServingCellConfig_t *scd, const nr_mac_config_t *config, const nr_rlc_configuration_t *default_rlc_config) { - module_id_t i; - gNB_MAC_INST *nrmac; - AssertFatal(RC.nb_nr_macrlc_inst == 1, "what is the point of calling %s() if you don't need exactly one MAC?\n", __func__); if (RC.nb_nr_macrlc_inst > 0) { @@ -252,7 +268,7 @@ void mac_top_init_gNB(ngran_node_t node_type, RC.nb_nr_macrlc_inst * sizeof(gNB_MAC_INST *), RC.nb_nr_macrlc_inst, sizeof(gNB_MAC_INST)); - for (i = 0; i < RC.nb_nr_macrlc_inst; i++) { + for (module_id_t i = 0; i < RC.nb_nr_macrlc_inst; i++) { RC.nrmac[i] = (gNB_MAC_INST *) malloc16(sizeof(gNB_MAC_INST)); @@ -269,14 +285,10 @@ void mac_top_init_gNB(ngran_node_t node_type, RC.nrmac[i]->tag = (NR_TAG_t*)malloc(sizeof(NR_TAG_t)); memset((void*)RC.nrmac[i]->tag,0,sizeof(NR_TAG_t)); - RC.nrmac[i]->ul_handle = 0; - RC.nrmac[i]->common_channels[0].ServingCellConfigCommon = scc; RC.nrmac[i]->radio_config = *config; RC.nrmac[i]->rlc_config = *default_rlc_config; - RC.nrmac[i]->common_channels[0].pre_ServingCellConfig = scd; - RC.nrmac[i]->first_MIB = true; RC.nrmac[i]->num_scheduled_prach_rx = 0; RC.nrmac[i]->common_channels[0].mib = get_new_MIB_NR(scc); @@ -309,16 +321,13 @@ void mac_top_init_gNB(ngran_node_t node_type, nr_rlc_op_mode_t mode = NODE_IS_MONOLITHIC(node_type) ? NR_RLC_OP_MODE_MONO_GNB : NR_RLC_OP_MODE_SPLIT_GNB; int success = nr_rlc_module_init(mode); AssertFatal(success == 0,"Could not initialize RLC layer\n"); - - // These should be out of here later - if (get_softmodem_params()->usim_test == 0 ) nr_pdcp_layer_init(); } else { RC.nrmac = NULL; } // Initialize Linked-List for Active UEs - for (i = 0; i < RC.nb_nr_macrlc_inst; i++) { - nrmac = RC.nrmac[i]; + for (module_id_t i = 0; i < RC.nb_nr_macrlc_inst; i++) { + gNB_MAC_INST *nrmac = RC.nrmac[i]; nrmac->if_inst = NR_IF_Module_init(i); memset(&nrmac->UE_info, 0, sizeof(nrmac->UE_info)); } @@ -333,7 +342,6 @@ void mac_top_destroy_gNB(gNB_MAC_INST *mac) NR_COMMON_channels_t *cc = &mac->common_channels[0]; ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, cc->mib); ASN_STRUCT_FREE(asn_DEF_NR_BCCH_DL_SCH_Message, cc->sib1); - ASN_STRUCT_FREE(asn_DEF_NR_ServingCellConfig, cc->pre_ServingCellConfig); ASN_STRUCT_FREE(asn_DEF_NR_ServingCellConfigCommon, cc->ServingCellConfigCommon); NR_UEs_t *UE_info = &mac->UE_info; for (int i = 0; i < sizeofArray(UE_info->connected_ue_list); ++i) @@ -342,6 +350,9 @@ void mac_top_destroy_gNB(gNB_MAC_INST *mac) for (int i = 0; i < sizeofArray(UE_info->access_ue_list); ++i) if (UE_info->access_ue_list[i]) delete_nr_ue_data(UE_info->access_ue_list[i], cc, &UE_info->uid_allocator); + if (mac->f1_config.setup_resp) + free_f1ap_setup_response(mac->f1_config.setup_resp); + free(mac->f1_config.setup_resp); } void nr_mac_send_f1_setup_req(void) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3918e0215c..026d8d563e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -88,6 +88,7 @@ /* MAC */ #include "LAYER2/NR_MAC_COMMON/nr_mac_common.h" +#include "LAYER2/NR_MAC_gNB/mac_config.h" #include "NR_TAG.h" /* Defs */ @@ -154,6 +155,30 @@ typedef struct nr_redcap_config { uint8_t intraFreqReselectionRedCap_r17; } nr_redcap_config_t; +typedef struct { +int dl_FreqDensity0_0; +int dl_FreqDensity1_0; +int dl_TimeDensity0_0; +int dl_TimeDensity1_0; +int dl_TimeDensity2_0; +int dl_EpreRatio_0; +int dl_ReOffset_0; +int ul_FreqDensity0_0; +int ul_FreqDensity1_0; +int ul_TimeDensity0_0; +int ul_TimeDensity1_0; +int ul_TimeDensity2_0; +int ul_ReOffset_0; +int ul_MaxPorts_0; +int ul_Power_0; +} nr_ptrs_config_t; + +typedef struct { + int id; + int scs; + int location_and_bw; +} nr_bwp_config_t; + typedef struct nr_mac_config_t { int sib1_tda; nr_pdsch_AntennaPorts_t pdsch_AntennaPorts; @@ -161,6 +186,7 @@ typedef struct nr_mac_config_t { int minRXTXTIME; int do_CSIRS; int do_SRS; + int max_num_rsrp; bool force_256qam_off; bool force_UL256qam_off; bool use_deltaMCS; @@ -171,11 +197,16 @@ typedef struct nr_mac_config_t { nr_mac_timers_t timer_config; int num_dlharq; int num_ulharq; + // BWP information + int num_additional_bwps; + int first_active_bwp; + nr_bwp_config_t bwp_config[4]; /// beamforming weight matrix size int nb_bfw[2]; int32_t *bw_list; int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; nr_redcap_config_t *redcap; + nr_ptrs_config_t *ptrs; bool do_SINR; } nr_mac_config_t; @@ -262,8 +293,6 @@ typedef struct { NR_BCCH_DL_SCH_Message_t *sib1; seq_arr_t *du_SIBs; NR_ServingCellConfigCommon_t *ServingCellConfigCommon; - /// pre-configured ServingCellConfig that is default for every UE - NR_ServingCellConfig_t *pre_ServingCellConfig; /// Outgoing MIB PDU for PHY uint8_t MIB_pdu[3]; /// Outgoing BCCH pdu for PHY @@ -392,12 +421,16 @@ typedef struct NR_pusch_dmrs { uint16_t ul_dmrs_symb_pos; uint8_t num_dmrs_cdm_grps_no_data; nfapi_nr_dmrs_type_e dmrs_config_type; + int dmrs_scrambling_id; + int pusch_identity; + int scid; + int low_papr_sequence_number; + NR_PTRS_UplinkConfig_t *ptrsConfig; } NR_pusch_dmrs_t; typedef struct NR_sched_pusch { int frame; int slot; - int mu; /// RB allocation within active uBWP uint16_t rbSize; @@ -413,7 +446,6 @@ typedef struct NR_sched_pusch { /// UL HARQ PID to use for this UE, or -1 for "any new" int8_t ul_harq_pid; - uint8_t nrOfLayers; int tpmi; @@ -421,22 +453,20 @@ typedef struct NR_sched_pusch { int time_domain_allocation; NR_tda_info_t tda_info; NR_pusch_dmrs_t dmrs_info; + bwp_info_t bwp_info; int phr_txpower_calc; } NR_sched_pusch_t; -typedef struct NR_sched_srs { - int frame; - int slot; - bool srs_scheduled; -} NR_sched_srs_t; - typedef struct NR_pdsch_dmrs { uint8_t dmrs_ports_id; uint8_t N_PRB_DMRS; uint8_t N_DMRS_SLOT; uint16_t dl_dmrs_symb_pos; uint8_t numDmrsCdmGrpsNoData; + uint32_t scrambling_id; + int n_scid; nfapi_nr_dmrs_type_e dmrsConfigType; + NR_PTRS_DownlinkConfig_t *phaseTrackingRS; } NR_pdsch_dmrs_t; typedef struct NR_sched_pdsch { @@ -460,7 +490,7 @@ typedef struct NR_sched_pdsch { uint16_t pm_index; uint8_t nrOfLayers; - + bwp_info_t bwp_info; NR_pdsch_dmrs_t dmrs_parms; // time_domain_allocation is the index of a list of tda int time_domain_allocation; @@ -519,8 +549,7 @@ typedef struct RSRP_report { uint8_t nr_reports; uint8_t resource_id[MAX_NR_OF_REPORTED_RS]; int RSRP[MAX_NR_OF_REPORTED_RS]; - // SINR index according to tables 10.1.16.1-1, 10.1.16.1-2 - int SINR_index[MAX_NR_OF_REPORTED_RS]; + int SINRx10[MAX_NR_OF_REPORTED_RS]; } RSRP_report_t; struct CSI_Report { @@ -583,6 +612,7 @@ typedef struct { /// corresponding to the sched_pusch/sched_pdsch structures below int cce_index; uint8_t aggregation_level; + uint32_t dl_cce_fail, ul_cce_fail; /// Array of PUCCH scheduling information /// Its size depends on TDD configuration and max feedback time @@ -590,12 +620,6 @@ typedef struct { NR_sched_pucch_t *sched_pucch; int sched_pucch_size; - /// Sched PUSCH: scheduling decisions, copied into HARQ and cleared every TTI - NR_sched_pusch_t sched_pusch; - - /// Sched SRS: scheduling decisions - NR_sched_srs_t sched_srs; - /// uplink bytes that are currently scheduled int sched_ul_bytes; /// estimation of the UL buffer size @@ -665,6 +689,10 @@ typedef struct { /// Timer for RRC processing procedures and transmission activity NR_timer_t transm_interrupt; + /// Timer for timeout before UE is set to UL failure (e.g., + /// "TransmissionActionIndicator" handling + NR_timer_t transm_timeout; + /// sri, ul_ri and tpmi based on SRS nr_srs_feedback_t srs_feedback; @@ -697,6 +725,8 @@ typedef struct NR_mac_stats { uint32_t pucch0_DTX; int cumul_rsrp; uint8_t num_rsrp_meas; + int cumul_sinrx10; + uint8_t num_sinr_meas; char srs_stats[50]; // Statistics may differ depending on SRS usage int pusch_snrx10; int deltaMCS; @@ -724,7 +754,18 @@ typedef struct nr_mac_rrc_ul_if_s { initial_ul_rrc_message_transfer_func_t initial_ul_rrc_message_transfer; } nr_mac_rrc_ul_if_t; -typedef enum interrupt_followup_action { FOLLOW_INSYNC, FOLLOW_INSYNC_RECONFIG, FOLLOW_OUTOFSYNC } interrupt_followup_action_t; +typedef struct measgap_config { + bool enable; + int mgrp_ms; + long mgrp; + long gapOffset; + long mgta; + int n_slots_mgta; + int n_slots_advance; + float mgl_ms; + long mgl; + int mgl_slots; +} measgap_config_t; /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ typedef struct { @@ -742,8 +783,8 @@ typedef struct { /// in case of reestablishment, old spCellConfig to apply after /// reconfiguration NR_SpCellConfig_t *reconfigSpCellConfig; - interrupt_followup_action_t interrupt_action; NR_UE_NR_Capability_t *capability; + measgap_config_t measgap_config; // UE selected beam index uint8_t UE_beam_index; float ul_thr_ue; @@ -764,18 +805,40 @@ typedef struct { uid_allocator_t uid_allocator; } NR_UEs_t; +typedef enum { + NO_BEAM_MODE, + PRECONFIGURED_BEAM_IDX, + LOPHY_BEAM_IDX, +} nr_beam_mode_t; + typedef struct { /// list of allocated beams per period int **beam_allocation; int beam_duration; // in slots int beams_per_period; int beam_allocation_size; + nr_beam_mode_t beam_mode; } NR_beam_info_t; #define UE_iterator(BaSe, VaR) NR_UE_info_t ** VaR##pptr=BaSe, *VaR; while ((VaR=*(VaR##pptr++))) +typedef struct { + /// current frame for DCI + frame_t frame; + /// current slot for DCI + slot_t slot; + /// FAPI UL_DCI.request in which allocations are to be made + nfapi_nr_ul_dci_request_t *ul_dci_req; + /// group PDCCH PDU per CORESET + nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_coreset[MAX_NUM_CORESET]; +} post_process_pusch_t; + +/* forward declaration to use in nr_pp_impl_dl */ +struct gNB_MAC_INST_s; +typedef struct gNB_MAC_INST_s gNB_MAC_INST; + typedef void (*nr_pp_impl_dl)(module_id_t mod_id, frame_t frame, slot_t slot); -typedef bool (*nr_pp_impl_ul)(module_id_t mod_id, frame_t frame, slot_t slot); +typedef void (*nr_pp_impl_ul)(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch); typedef struct f1_config_t { f1ap_setup_req_t *setup_req; @@ -793,6 +856,14 @@ typedef struct { uint64_t used_prb_aggregate; } mac_stats_t; +/// helper type to encapsulate a frame/slot combination in a single type. +/// Currently only used in the UL preprocessor. Note: if you use this type +/// further, please refactor it into a common type first. +typedef struct fsn { + frame_t f; + slot_t s; +} fsn_t; + /*! \brief top level eNB MAC structure */ typedef struct gNB_MAC_INST_s { /// Ethernet parameters for northbound midhaul interface @@ -848,39 +919,23 @@ typedef struct gNB_MAC_INST_s { NR_UEs_t UE_info; - /// UL handle - uint32_t ul_handle; - //UE_info_t UE_info; - // MAC function execution peformance profiler - /// processing time of eNB scheduler - time_stats_t eNB_scheduler; - /// processing time of eNB scheduler for SI - time_stats_t schedule_si; - /// processing time of eNB scheduler for Random access + /// processing time of gNB scheduler + time_stats_t gNB_scheduler; + /// processing time of gNB scheduler for Random access time_stats_t schedule_ra; - /// processing time of eNB ULSCH scheduler - time_stats_t schedule_ulsch; - /// processing time of eNB DCI generation - time_stats_t fill_DLSCH_dci; - /// processing time of eNB MAC preprocessor - time_stats_t schedule_dlsch_preprocessor; - /// processing time of eNB DLSCH scheduler + /// processing time of gNB DLSCH scheduler + time_stats_t schedule_ulsch; // include preprocessor + /// processing time of gNB DLSCH scheduler time_stats_t schedule_dlsch; // include rlc_data_req + MAC header + preprocessor /// processing time of rlc_data_req time_stats_t rlc_data_req; - /// processing time of rlc_status_ind - time_stats_t rlc_status_ind; /// processing time of nr_srs_ri_computation time_stats_t nr_srs_ri_computation_timer; /// processing time of nr_srs_tpmi_estimation time_stats_t nr_srs_tpmi_computation_timer; - /// processing time of eNB MCH scheduler - time_stats_t schedule_mch; - /// processing time of eNB ULSCH reception + /// processing time of gNB ULSCH reception time_stats_t rx_ulsch_sdu; // include rlc_data_ind - /// processing time of eNB PCH scheduler - time_stats_t schedule_pch; NR_beam_info_t beam_info; @@ -910,6 +965,12 @@ typedef struct gNB_MAC_INST_s { bool identity_pm; int precoding_matrix_size[NR_MAX_NB_LAYERS]; int fapi_beam_index[MAX_NUM_OF_SSB]; + + /// dedicate UL TDA, common for all UEs + seq_arr_t ul_tda; + /// next UL slot to schedule + fsn_t ul_next; + nr_mac_rrc_ul_if_t mac_rrc; f1_config_t f1_config; int16_t frame; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 41ace5014b..a2b7c26678 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -50,6 +50,11 @@ #define NR_MAX_SUPPORTED_DL_LAYERS 4 +/* Default values for measurement gap configuration */ +#define DEFAULT_MGRP NR_GapConfig__mgrp_ms160 +#define DEFAULT_MGTA NR_GapConfig__mgta_ms0dot5 +#define DEFAULT_MGL NR_GapConfig__mgl_ms6 + #define PUCCH2_SIZE 8 const uint8_t slotsperframe[5] = {10, 20, 40, 80, 160}; @@ -80,7 +85,6 @@ static NR_BWP_t clone_generic_parameters(const NR_BWP_t *gp) static void verify_agg_levels(int num_cce_in_coreset, const int in_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS], int coresetid, - int searchspaceid, int out_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]) { int agg_level_to_n_cces[] = {1, 2, 4, 8, 16}; @@ -94,10 +98,9 @@ static void verify_agg_levels(int num_cce_in_coreset, if (num_agg_level_candidates * agg_level_to_n_cces[i] > num_cce_in_coreset) { int new_agg_level_candidates = num_cce_in_coreset / agg_level_to_n_cces[i]; LOG_E(NR_RRC, - "Invalid configuration: Not enough CCEs in coreset %d, searchspace %d, agg_level %d, number of requested " + "Invalid configuration: Not enough CCEs in coreset %d, agg_level %d, number of requested " "candidates = %d, number of CCES in coreset %d. Aggregation level candidates limited to %d\n", coresetid, - searchspaceid, agg_level_to_n_cces[i], in_num_agg_level_candidates[i], num_cce_in_coreset, @@ -212,20 +215,6 @@ static NR_SetupRelease_PDSCH_ConfigCommon_t *clone_pdsch_configcommon(const NR_S return clone; } -static NR_PUSCH_Config_t *clone_pusch_config(const NR_PUSCH_Config_t *pc) -{ - if (pc == NULL) - return NULL; - - uint8_t buf[1024]; - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_PUSCH_Config, NULL, pc, buf, sizeof(buf)); - AssertFatal(enc_rval.encoded > 0 && enc_rval.encoded < sizeof(buf), "could not clone NR_PUSCH_Config: problem while encoding\n"); - NR_PUSCH_Config_t *clone = NULL; - asn_dec_rval_t dec_rval = uper_decode(NULL, &asn_DEF_NR_PUSCH_Config, (void **)&clone, buf, enc_rval.encoded, 0, 0); - AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed == enc_rval.encoded, "could not clone NR_PUSCH_Config: problem while decoding\n"); - return clone; -} - static int get_nb_pucch2_per_slot(const NR_ServingCellConfigCommon_t *scc, int bwp_size) { const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL; @@ -238,6 +227,7 @@ static int get_nb_pucch2_per_slot(const NR_ServingCellConfigCommon_t *scc, int b int nb_pucch2 = (max_csi_reports / (available_report_occasions + 1)) + 1; // in current implementation we need (nb_pucch2 * PUCCH2_SIZE) prbs for PUCCH2 // and MAX_MOBILES_PER_GNB prbs for PUCCH1 + // checked for validity in verify_radio_configuration AssertFatal((nb_pucch2 * PUCCH2_SIZE) + MAX_MOBILES_PER_GNB <= bwp_size, "Cannot allocate all required PUCCH resources for max number of %d UEs in BWP with %d PRBs\n", MAX_MOBILES_PER_GNB, bwp_size); @@ -402,6 +392,7 @@ static void set_csirs_periodicity(NR_NZP_CSI_RS_Resource_t *nzpcsi0, else { nzpcsi0->periodicityAndOffset->present = NR_CSI_ResourcePeriodicityAndOffset_PR_slots320; const int nb_dl_slots_period = get_full_dl_slots_per_period(fs); // full DL slots + // checked for validity in verify_radio_configuration AssertFatal(offset / 320 < nb_dl_slots_period, "Cannot allocate CSI-RS for BWP %d. Not enough resources for CSI-RS\n", id); nzpcsi0->periodicityAndOffset->choice.slots320 = (offset % 320) + (offset / 320); } @@ -661,7 +652,7 @@ static struct NR_SRS_Resource__resourceType__periodic *configure_periodic_srs(co { frame_structure_t *fs = &RC.nrmac[0]->frame_structure; int offset = get_ul_slot_offset(fs, uid, false); // only full UL slots for SRS - + // checked for validity in verify_radio_configuration AssertFatal(offset < 2560, "Cannot allocate SRS configuration for uid %d, not enough resources\n", uid); const int ideal_period = set_ideal_period(false); @@ -1048,91 +1039,134 @@ void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsc } } -static struct NR_PUSCH_TimeDomainResourceAllocation *set_TimeDomainResourceAllocation(const int k2, uint8_t index, int ul_symb) +static struct NR_PUSCH_TimeDomainResourceAllocation *set_TimeDomainResourceAllocation(const int k2, long sliv) { struct NR_PUSCH_TimeDomainResourceAllocation *puschTdrAlloc = calloc_or_fail(1, sizeof(*puschTdrAlloc)); puschTdrAlloc->k2 = calloc_or_fail(1, sizeof(*puschTdrAlloc->k2)); *puschTdrAlloc->k2 = k2; puschTdrAlloc->mappingType = NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeB; - switch (index) { - case 0: - puschTdrAlloc->startSymbolAndLength = get_SLIV(0, 13); - break; - case 1: - puschTdrAlloc->startSymbolAndLength = get_SLIV(0, 12); - break; - case 2: - // UL TDA index 2 for mixed slot (TDD) - puschTdrAlloc->startSymbolAndLength = - get_SLIV(NR_NUMBER_OF_SYMBOLS_PER_SLOT - ul_symb, ul_symb - 1); // starting in fist ul symbol til the last but one - break; - case 3: { - // UL TDA index 3 for msg3 in the mixed slot (TDD) - int no_mix_slot = ul_symb < 3 ? 1 : 0; // we need at least 2 symbols for scheduling Msg3 - *puschTdrAlloc->k2 += no_mix_slot; - if (no_mix_slot) - puschTdrAlloc->startSymbolAndLength = get_SLIV(0, 13); // full allocation if there is no mixed slot - else - puschTdrAlloc->startSymbolAndLength = - get_SLIV(NR_NUMBER_OF_SYMBOLS_PER_SLOT - ul_symb, ul_symb - 1); // starting in fist ul symbol til the last but one - } - break; - default: - break; - } + puschTdrAlloc->startSymbolAndLength = sliv; return puschTdrAlloc; } -void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay) +static int tda_cmp(const void *tda_a, const void *tda_b) { - //TODO change to accomodate for SRS + const NR_PUSCH_TimeDomainResourceAllocation_t *a = *(const NR_PUSCH_TimeDomainResourceAllocation_t **)tda_a; + const NR_PUSCH_TimeDomainResourceAllocation_t *b = *(const NR_PUSCH_TimeDomainResourceAllocation_t **)tda_b; + DevAssert(a->k2 && b->k2); + if (*a->k2 < *b->k2) + return -1; // smaller first + if (*a->k2 > *b->k2) + return 1; + // same k2: order from big to small TDA number + int as, al, bs, bl; + SLIV2SL(a->startSymbolAndLength, &as, &al); + SLIV2SL(b->startSymbolAndLength, &bs, &bl); + if (al < bl) + return 1; // bigger first + if (al > bl) + return -1; + return 0; +} - const NR_PUSCH_TimeDomainResourceAllocationList_t *tda = +/* \brief Set up a list of time domain allocations as suitable for the TDD + * pattern. This will be used by get_num_ul_tda(), which requires a specific + * ordering, hence we qsort() the list at the end according to tda_cmp(). */ +void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay, int do_SRS) +{ + NR_PUSCH_TimeDomainResourceAllocationList_t *tda_list = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; - AssertFatal(tda->list.count == 0, "already have pusch_TimeDomainAllocationList members\n"); + AssertFatal(tda_list->list.count == 0, "already have pusch_TimeDomainAllocationList members\n"); const int k2 = min_fb_delay; - int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; - struct NR_SetupRelease_PUSCH_ConfigCommon *pusch_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon; + const int mu = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; // UL TDA index 0 is basic slot configuration starting in symbol 0 til the last but one symbol - asn1cSeqAdd(&pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list, set_TimeDomainResourceAllocation(k2, 0, 0)); + NR_PUSCH_TimeDomainResourceAllocation_t *tda; + tda = set_TimeDomainResourceAllocation(k2, get_SLIV(0, 13)); + asn1cSeqAdd(&tda_list->list, tda); // UL TDA index 1 in case of SRS - asn1cSeqAdd(&pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list, set_TimeDomainResourceAllocation(k2, 1, 0)); + if (do_SRS) { + tda = set_TimeDomainResourceAllocation(k2, get_SLIV(0, 12)); + asn1cSeqAdd(&tda_list->list, tda); + } if (scc->tdd_UL_DL_ConfigurationCommon) { - int ul_symb = 0; NR_TDD_UL_DL_Pattern_t *p1 = &scc->tdd_UL_DL_ConfigurationCommon->pattern1; + int ul_symb = p1->nrofUplinkSymbols; NR_TDD_UL_DL_Pattern_t *p2 = scc->tdd_UL_DL_ConfigurationCommon->pattern2; if (p2 && p2->nrofUplinkSymbols) - AssertFatal(p2->nrofUplinkSymbols == p1->nrofUplinkSymbols, - "nrofDownlinkSymbols in pattern1 %ld and pattern2 %ld must be the same in current implementation\n", - p1->nrofUplinkSymbols, + AssertFatal(p2->nrofUplinkSymbols == ul_symb, + "nrofDownlinkSymbols in pattern1 %d and pattern2 %ld must be the same in current implementation\n", + ul_symb, p2->nrofUplinkSymbols); - if (p1->nrofUplinkSymbols) { - ul_symb = p1->nrofUplinkSymbols; - } else if (p2) { - ul_symb = p1->nrofUplinkSymbols; - } - if (ul_symb>1) { - // UL TDA index 2 for mixed slot (TDD) - asn1cSeqAdd(&pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list, - set_TimeDomainResourceAllocation(k2, 2, ul_symb)); - } - // UL TDA index 3 for msg3 in the mixed slot (TDD) + AssertFatal(!p2 || p2->nrofDownlinkSlots >= p2->nrofUplinkSlots, + "nrofDownlinkSlots must be larger than nrofUplinkSlots for pattern2 in current implementation\n"); + + int N_dl1 = p1->nrofDownlinkSlots; + int N_ul1 = p1->nrofUplinkSlots; + int N_dl2 = p2 ? p2->nrofDownlinkSlots : 0; + int N_ul2 = p2 ? p2->nrofUplinkSlots : 0; int tdd_period_idx = get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon); int nb_periods_per_frame = get_nb_periods_per_frame(tdd_period_idx); int nb_slots_per_period = ((1 << mu) * 10) / nb_periods_per_frame; - int k2_msg3 = nb_slots_per_period - get_delta_for_k2(mu); - struct NR_PUSCH_TimeDomainResourceAllocation *puschTdrAllocMsg3 = set_TimeDomainResourceAllocation(k2_msg3, 3, ul_symb); - if (*puschTdrAllocMsg3->k2 < min_fb_delay) - *puschTdrAllocMsg3->k2 += nb_slots_per_period; - AssertFatal(*puschTdrAllocMsg3->k2 < 33, - "Computed k2 for msg3 %ld is larger than the range allowed by RRC (0..32)\n", - *puschTdrAllocMsg3->k2); - asn1cSeqAdd(&pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList->list, puschTdrAllocMsg3); + + // make TDA for the mixed slot + long mixed_sliv = get_SLIV(NR_NUMBER_OF_SYMBOLS_PER_SLOT - ul_symb, ul_symb - 1); + int mixed_min_ul_symb = 3; // need at least two symbols PUSCH + PUCCH + bool has_ul_mixed = ul_symb >= mixed_min_ul_symb; + if (has_ul_mixed && (k2 <= N_dl1 || (p2 && N_ul2 == 0))) { + // UL TDA index 2 for mixed slot (TDD) (no pattern 2 and enough DL slots, or pattern2 only DL) + tda = set_TimeDomainResourceAllocation(k2, mixed_sliv); // to be reached from suitable DL slot + asn1cSeqAdd(&tda_list->list, tda); + } else if (has_ul_mixed && !p2 && k2 > N_dl1) { // k2 > N_Dl1 + // UL TDA for mixed slot without pattern 2 and less DL slots than k2 + tda = set_TimeDomainResourceAllocation(nb_slots_per_period, mixed_sliv); // to be reached from last DL (mixed) slot, if any + asn1cSeqAdd(&tda_list->list, tda); + } else if (has_ul_mixed && N_ul2 > 0 && k2 > N_dl1) { + // we have pattern 2 with UL, and less p1 DL slots than k2 + tda = set_TimeDomainResourceAllocation(N_dl1 + N_ul2 + 1, mixed_sliv); + asn1cSeqAdd(&tda_list->list, tda); + } else { + LOG_I(NR_RRC, "mixed slot has %d UL symbols, cannot create mixed slot TDA\n", ul_symb); + } + + // make TDA for UL slots that are not reachable within k2/min_rxtxtime + int N_ul = max(N_ul1, N_ul2); + if (N_ul > k2) { + // enforce that with k2, we could reach all but one slot (which is mixed + // and taken into account above + AssertFatal(N_dl1 >= k2 - 1, "cannot fulfil TDD pattern: N_dl1 %d, k2 %d\n", N_dl1, k2); + for (int i = k2 + 1; i <= N_ul; ++i) { + tda = set_TimeDomainResourceAllocation(i, get_SLIV(0, 13)); + asn1cSeqAdd(&tda_list->list, tda); + if (do_SRS) { + tda = set_TimeDomainResourceAllocation(i, get_SLIV(0, 12)); + asn1cSeqAdd(&tda_list->list, tda); + } + } + } + + // for Msg3, an additional get_delta_for_k2(mu) is added to k2. + // check that any UL slot is reachable under this condition + // the below is designed to only hit specific (known) cases + // examples: DDDSU (no TDA in S), + int N_dl = max(N_dl1, N_dl2); + int delta = get_delta_for_k2(mu); + int k2_msg3 = k2 + delta; + if (nb_slots_per_period % k2_msg3 == 0 /* see example above */ + && k2_msg3 > N_dl /* otherwise, can always have a D that reaches U */ + && k2_msg3 > N_ul /* otherwise, can always have a D that reaches U */ + && !has_ul_mixed /* if mixed slot, even for DDDSU would reach */) { + /* reach next UL from mixed slot in previous period */ + tda = set_TimeDomainResourceAllocation(k2_msg3, get_SLIV(0, 13)); + asn1cSeqAdd(&tda_list->list, tda); + } } + + AssertFatal(tda_list->list.count <= 16, "cannot reach all UL slots with current TDD configuration\n"); + qsort(tda_list->list.array, tda_list->list.count, sizeof(tda_list->list.array), tda_cmp); } static void set_dl_DataToUL_ACK(NR_PUCCH_Config_t *pucch_Config, int min_feedback_time, NR_SubcarrierSpacing_t subcarrierSpacing) @@ -1169,6 +1203,7 @@ static void config_pucch_resset0(NR_PUCCH_Config_t *pucch_Config, NR_PUCCH_Resource_t *pucchres0 = calloc(1,sizeof(*pucchres0)); pucchres0->pucch_ResourceId = *pucchid; pucchres0->startingPRB = (PUCCH2_SIZE * num_pucch2) + uid; + // checked for validity in verify_radio_configuration AssertFatal(pucchres0->startingPRB < curr_bwp, "Not enough resources in current BWP (size %d) to allocate uid %d\n", curr_bwp, uid); pucchres0->intraSlotFrequencyHopping = NULL; pucchres0->secondHopPRB = NULL; @@ -1419,15 +1454,61 @@ static void set_dl_mcs_table(int scs, bwp_Dedicated->pdsch_Config->choice.setup->mcs_Table = NULL; } -static struct NR_SetupRelease_PUSCH_Config *config_pusch(NR_PUSCH_Config_t *pusch_Config, - const bool use_deltaMCS, - const NR_ServingCellConfigCommon_t *scc, - const NR_UE_NR_Capability_t *uecap) +static NR_PTRS_UplinkConfig_t *config_ulptrs(const nr_ptrs_config_t *ptrs) { - struct NR_SetupRelease_PUSCH_Config *setup_puschconfig = calloc(1, sizeof(*setup_puschconfig)); + struct NR_PTRS_UplinkConfig__transformPrecoderDisabled *ptrs_config = calloc_or_fail(1, sizeof(*ptrs_config)); + AssertFatal(ptrs->ul_FreqDensity0_0 < 277, "Invalid ul_FreqDensity0_0 %d\n", ptrs->ul_FreqDensity0_0); + if (ptrs->ul_FreqDensity0_0 > 0) { + ptrs_config->frequencyDensity = calloc_or_fail(1, sizeof(*ptrs_config->frequencyDensity)); + asn1cSequenceAdd(ptrs_config->frequencyDensity->list, long, f0); + *f0 = ptrs->ul_FreqDensity0_0; + AssertFatal(ptrs->ul_FreqDensity1_0 < 277, "Invalid ul_FreqDensity1_0 %d\n", ptrs->ul_FreqDensity1_0); + if (ptrs->ul_FreqDensity1_0 > 0) { + asn1cSequenceAdd(ptrs_config->frequencyDensity->list, long, f1); + *f1 = ptrs->ul_FreqDensity1_0; + } + } + + AssertFatal(ptrs->ul_TimeDensity0_0 < 30, "Invalid ul_TimeDensity0_0 %d\n", ptrs->ul_TimeDensity0_0); + if (ptrs->ul_TimeDensity0_0 >= 0) { + ptrs_config->timeDensity = calloc_or_fail(1, sizeof(*ptrs_config->timeDensity)); + asn1cSequenceAdd(ptrs_config->timeDensity->list, long, t0); + *t0 = ptrs->ul_TimeDensity0_0; + AssertFatal(ptrs->ul_TimeDensity1_0 < 30, "Invalid ul_TimeDensity1_0 %d\n", ptrs->ul_TimeDensity1_0); + if (ptrs->ul_TimeDensity1_0 >= 0) { + asn1cSequenceAdd(ptrs_config->timeDensity->list, long, t1); + *t1 = ptrs->ul_TimeDensity1_0; + } + AssertFatal(ptrs->ul_TimeDensity2_0 < 30, "Invalid ul_TimeDensity2_0 %d\n", ptrs->ul_TimeDensity2_0); + if (ptrs->ul_TimeDensity2_0 >= 0) { + asn1cSequenceAdd(ptrs_config->timeDensity->list, long, t2); + *t2 = ptrs->ul_TimeDensity2_0; + } + } + + AssertFatal(ptrs->ul_ReOffset_0 < 3, "Invalid ul_ReOffset_0 %d\n", ptrs->ul_ReOffset_0); + if (ptrs->ul_ReOffset_0 >= 0) { + ptrs_config->resourceElementOffset = calloc_or_fail(1, sizeof(*ptrs_config->resourceElementOffset)); + *ptrs_config->resourceElementOffset = ptrs->ul_ReOffset_0; + } + AssertFatal(ptrs->ul_MaxPorts_0 == 0 || ptrs->ul_MaxPorts_0 == 1, "Invalid ul_MaxPorts_0 %d\n", ptrs->ul_MaxPorts_0); + ptrs_config->maxNrofPorts = ptrs->ul_MaxPorts_0; + AssertFatal(ptrs->ul_Power_0 >= 0 || ptrs->ul_Power_0 < 4, "Invalid ul_Power_0 %d\n", ptrs->ul_Power_0); + ptrs_config->ptrs_Power = ptrs->ul_Power_0; + + NR_PTRS_UplinkConfig_t *ulptrs = calloc_or_fail(1, sizeof(*ptrs_config)); + ulptrs->transformPrecoderDisabled = ptrs_config; + return ulptrs; +} + +static NR_SetupRelease_PUSCH_Config_t *config_pusch(const bool use_deltaMCS, + const NR_ServingCellConfigCommon_t *scc, + const NR_UE_NR_Capability_t *uecap, + const nr_ptrs_config_t *ptrs) +{ + NR_SetupRelease_PUSCH_Config_t *setup_puschconfig = calloc(1, sizeof(*setup_puschconfig)); setup_puschconfig->present = NR_SetupRelease_PUSCH_Config_PR_setup; - if (!pusch_Config) - pusch_Config = calloc(1, sizeof(*pusch_Config)); + NR_PUSCH_Config_t *pusch_Config = calloc(1, sizeof(*pusch_Config)); setup_puschconfig->choice.setup = pusch_Config; pusch_Config->dataScramblingIdentityPUSCH = NULL; @@ -1441,6 +1522,13 @@ static struct NR_SetupRelease_PUSCH_Config *config_pusch(NR_PUSCH_Config_t *pusc if (!pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup) pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = calloc(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup)); NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; + if (ptrs) { + NR_PTRS_UplinkConfig_t *ptrs_config = config_ulptrs(ptrs); + NR_SetupRelease_PTRS_UplinkConfig_t *phaseTrackingRS = calloc(1, sizeof(*phaseTrackingRS)); + phaseTrackingRS->present = NR_SetupRelease_PTRS_UplinkConfig_PR_setup; + phaseTrackingRS->choice.setup = ptrs_config; + NR_DMRS_UplinkConfig->phaseTrackingRS = phaseTrackingRS; + } NR_DMRS_UplinkConfig->dmrs_Type = NULL; NR_DMRS_UplinkConfig->dmrs_AdditionalPosition = NULL; NR_DMRS_UplinkConfig->phaseTrackingRS = NULL; @@ -1505,9 +1593,54 @@ static struct NR_SetupRelease_PUSCH_Config *config_pusch(NR_PUSCH_Config_t *pusc return setup_puschconfig; } -static struct NR_SetupRelease_PDSCH_Config *config_pdsch(uint64_t ssb_bitmap, int bwp_Id, int dl_antenna_ports) +static NR_PTRS_DownlinkConfig_t *config_dlptrs(const nr_ptrs_config_t *ptrs) { - struct NR_SetupRelease_PDSCH_Config *setup_pdsch_Config = calloc(1,sizeof(*setup_pdsch_Config)); + NR_PTRS_DownlinkConfig_t *ptrs_config = calloc_or_fail(1, sizeof(*ptrs_config)); + AssertFatal(ptrs->dl_FreqDensity0_0 < 277, "Invalid dl_FreqDensity0_0 %d\n", ptrs->dl_FreqDensity0_0); + if (ptrs->dl_FreqDensity0_0 > 0) { + ptrs_config->frequencyDensity = calloc_or_fail(1, sizeof(*ptrs_config->frequencyDensity)); + asn1cSequenceAdd(ptrs_config->frequencyDensity->list, long, f0); + *f0 = ptrs->dl_FreqDensity0_0; + AssertFatal(ptrs->dl_FreqDensity1_0 < 277, "Invalid dl_FreqDensity1_0 %d\n", ptrs->dl_FreqDensity1_0); + if (ptrs->dl_FreqDensity1_0 > 0) { + asn1cSequenceAdd(ptrs_config->frequencyDensity->list, long, f1); + *f1 = ptrs->dl_FreqDensity1_0; + } + } + + AssertFatal(ptrs->dl_TimeDensity0_0 < 30, "Invalid dl_TimeDensity0_0 %d\n", ptrs->dl_TimeDensity0_0); + if (ptrs->dl_TimeDensity0_0 >= 0) { + ptrs_config->timeDensity = calloc_or_fail(1, sizeof(*ptrs_config->timeDensity)); + asn1cSequenceAdd(ptrs_config->timeDensity->list, long, t0); + *t0 = ptrs->dl_TimeDensity0_0; + AssertFatal(ptrs->dl_TimeDensity1_0 < 30, "Invalid dl_TimeDensity1_0 %d\n", ptrs->dl_TimeDensity1_0); + if (ptrs->dl_TimeDensity1_0 >= 0) { + asn1cSequenceAdd(ptrs_config->timeDensity->list, long, t1); + *t1 = ptrs->dl_TimeDensity1_0; + } + AssertFatal(ptrs->dl_TimeDensity2_0 < 30, "Invalid dl_TimeDensity2_0 %d\n", ptrs->dl_TimeDensity2_0); + if (ptrs->dl_TimeDensity2_0 >= 0) { + asn1cSequenceAdd(ptrs_config->timeDensity->list, long, t2); + *t2 = ptrs->dl_TimeDensity2_0; + } + } + + AssertFatal(ptrs->dl_EpreRatio_0 < 4, "Invalid dl_EpreRatio_0 %d\n", ptrs->dl_EpreRatio_0); + if (ptrs->dl_EpreRatio_0 >= 0) { + ptrs_config->epre_Ratio = calloc_or_fail(1, sizeof(*ptrs_config->epre_Ratio)); + *ptrs_config->epre_Ratio = ptrs->dl_EpreRatio_0; + } + AssertFatal(ptrs->dl_ReOffset_0 < 3, "Invalid dl_ReOffset_0 %d\n", ptrs->dl_ReOffset_0); + if (ptrs->dl_ReOffset_0 >= 0) { + ptrs_config->resourceElementOffset = calloc_or_fail(1, sizeof(*ptrs_config->resourceElementOffset)); + *ptrs_config->resourceElementOffset = ptrs->dl_ReOffset_0; + } + return ptrs_config; +} + +static NR_SetupRelease_PDSCH_Config_t *config_pdsch(uint64_t ssb_bitmap, int bwp_Id, int dl_antenna_ports, nr_ptrs_config_t *ptrs) +{ + NR_SetupRelease_PDSCH_Config_t *setup_pdsch_Config = calloc(1,sizeof(*setup_pdsch_Config)); setup_pdsch_Config->present = NR_SetupRelease_PDSCH_Config_PR_setup; NR_PDSCH_Config_t *pdsch_Config = calloc(1, sizeof(*pdsch_Config)); setup_pdsch_Config->choice.setup = pdsch_Config; @@ -1515,6 +1648,13 @@ static struct NR_SetupRelease_PDSCH_Config *config_pdsch(uint64_t ssb_bitmap, in pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->present = NR_SetupRelease_DMRS_DownlinkConfig_PR_setup; pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup = calloc(1, sizeof(*pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup)); NR_DMRS_DownlinkConfig_t *dmrs_DownlinkForPDSCH_MappingTypeA = pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup; + if (ptrs) { + NR_PTRS_DownlinkConfig_t *ptrs_config = config_dlptrs(ptrs); + NR_SetupRelease_PTRS_DownlinkConfig_t *phaseTrackingRS = calloc(1, sizeof(*phaseTrackingRS)); + phaseTrackingRS->present = NR_SetupRelease_PTRS_DownlinkConfig_PR_setup; + phaseTrackingRS->choice.setup = ptrs_config; + dmrs_DownlinkForPDSCH_MappingTypeA->phaseTrackingRS = phaseTrackingRS; + } dmrs_DownlinkForPDSCH_MappingTypeA->dmrs_Type = NULL; dmrs_DownlinkForPDSCH_MappingTypeA->maxLength = NULL; dmrs_DownlinkForPDSCH_MappingTypeA->scramblingID0 = NULL; @@ -1548,24 +1688,22 @@ static struct NR_SetupRelease_PDSCH_Config *config_pdsch(uint64_t ssb_bitmap, in return setup_pdsch_Config; } -static void config_downlinkBWP(NR_BWP_Downlink_t *bwp, - const NR_ServingCellConfigCommon_t *scc, - const NR_ServingCellConfig_t *servingcellconfigdedicated, - const NR_UE_NR_Capability_t *uecap, - int dl_antenna_ports, - bool force_256qam_off, - int bwp_loop, - bool is_SA, - const int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]) +static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t *scc, + const NR_UE_NR_Capability_t *uecap, + int dl_antenna_ports, + bool force_256qam_off, + int bwp_loop, + bool is_SA, + const nr_mac_config_t *configuration) { + NR_BWP_Downlink_t *bwp = calloc_or_fail(1, sizeof(*bwp)); bwp->bwp_Common = calloc(1,sizeof(*bwp->bwp_Common)); - - if(servingcellconfigdedicated->downlinkBWP_ToAddModList && - bwp_loop < servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count) { - bwp->bwp_Id = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.array[bwp_loop]->bwp_Id; - bwp->bwp_Common->genericParameters.locationAndBandwidth = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.array[bwp_loop]->bwp_Common->genericParameters.locationAndBandwidth; - bwp->bwp_Common->genericParameters.subcarrierSpacing = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.array[bwp_loop]->bwp_Common->genericParameters.subcarrierSpacing; - bwp->bwp_Common->genericParameters.cyclicPrefix = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.array[bwp_loop]->bwp_Common->genericParameters.cyclicPrefix; + if(configuration->num_additional_bwps > 0) { + const nr_bwp_config_t *bwp_config = &configuration->bwp_config[bwp_loop]; + bwp->bwp_Id = bwp_config->id; + bwp->bwp_Common->genericParameters.locationAndBandwidth = bwp_config->location_and_bw; + bwp->bwp_Common->genericParameters.subcarrierSpacing = bwp_config->scs; + bwp->bwp_Common->genericParameters.cyclicPrefix = NULL; } else { bwp->bwp_Id=bwp_loop+1; bwp->bwp_Common->genericParameters.locationAndBandwidth = PRBalloc_to_locationandbandwidth(scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,0); @@ -1589,17 +1727,27 @@ static void config_downlinkBWP(NR_BWP_Downlink_t *bwp, bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList=calloc(1,sizeof(*bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList)); int searchspaceid = 5 + bwp->bwp_Id; - int rrc_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; - int num_cces = get_coreset_num_cces(coreset->frequencyDomainResources.buf, coreset->duration); - verify_agg_levels(num_cces, num_agg_level_candidates, coreset->controlResourceSetId, searchspaceid, rrc_num_agg_level_candidates); - NR_SearchSpace_t *ss = rrc_searchspace_config(true, searchspaceid, coreset->controlResourceSetId, rrc_num_agg_level_candidates); + int agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; + NR_SearchSpace_t *ss = NULL; + if (!is_SA) { + int num_cces = get_coreset_num_cces(coreset->frequencyDomainResources.buf, coreset->duration); + verify_agg_levels(num_cces, configuration->num_agg_level_candidates, coreset->controlResourceSetId, agg_level_candidates); + ss = rrc_searchspace_config(true, searchspaceid, coreset->controlResourceSetId, agg_level_candidates); + } else { + agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; + agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0; + agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1; + agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; + agg_level_candidates[PDCCH_AGG_LEVEL16] = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; + ss = rrc_searchspace_config(true, searchspaceid, 0, agg_level_candidates); + } asn1cSeqAdd(&bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list, ss); bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->searchSpaceSIB1=NULL; bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->searchSpaceOtherSystemInformation=NULL; bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->pagingSearchSpace=NULL; bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace=NULL; - if(is_SA == false) { + if(!is_SA) { bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace=calloc(1,sizeof(*bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace)); *bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->ra_SearchSpace=ss->searchSpaceId; } @@ -1627,39 +1775,44 @@ static void config_downlinkBWP(NR_BWP_Downlink_t *bwp, // frees NR_ControlResourceSet_t *coreset2 = get_coreset_config(bwp->bwp_Id, curr_bwp, ssb_bitmap); asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, coreset2); + int rrc_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; + int num_cces = get_coreset_num_cces(coreset2->frequencyDomainResources.buf, coreset2->duration); + verify_agg_levels(num_cces, configuration->num_agg_level_candidates, coreset2->controlResourceSetId, rrc_num_agg_level_candidates); searchspaceid = 10 + bwp->bwp_Id; - num_cces = get_coreset_num_cces(coreset2->frequencyDomainResources.buf, coreset2->duration); - verify_agg_levels(num_cces, num_agg_level_candidates, coreset->controlResourceSetId, searchspaceid, rrc_num_agg_level_candidates); - NR_SearchSpace_t *ss2 = - rrc_searchspace_config(false, searchspaceid, coreset2->controlResourceSetId, rrc_num_agg_level_candidates); + NR_SearchSpace_t *ss2 = rrc_searchspace_config(true, searchspaceid, is_SA ? 0 : coreset2->controlResourceSetId, agg_level_candidates); asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss2); + searchspaceid = 20 + bwp->bwp_Id; + NR_SearchSpace_t *ss3 = + rrc_searchspace_config(false, searchspaceid, coreset2->controlResourceSetId, rrc_num_agg_level_candidates); + asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss3); + bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToReleaseList = NULL; - bwp->bwp_Dedicated->pdsch_Config = config_pdsch(ssb_bitmap, bwp->bwp_Id, dl_antenna_ports); + bwp->bwp_Dedicated->pdsch_Config = config_pdsch(ssb_bitmap, bwp->bwp_Id, dl_antenna_ports, configuration->ptrs); set_dl_mcs_table(bwp->bwp_Common->genericParameters.subcarrierSpacing, force_256qam_off ? NULL : uecap, bwp->bwp_Dedicated, scc); + return bwp; } -static void config_uplinkBWP(NR_BWP_Uplink_t *ubwp, - long bwp_loop, - bool is_SA, - int uid, - const nr_mac_config_t *configuration, - const NR_ServingCellConfig_t *servingcellconfigdedicated, - const NR_ServingCellConfigCommon_t *scc, - const NR_UE_NR_Capability_t *uecap) +static NR_BWP_Uplink_t *config_uplinkBWP(long bwp_loop, + bool is_SA, + int uid, + int maxMIMO_Layers, + const nr_mac_config_t *configuration, + const NR_ServingCellConfigCommon_t *scc, + const NR_UE_NR_Capability_t *uecap) { - ubwp->bwp_Common = calloc(1,sizeof(*ubwp->bwp_Common)); - if(servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList && - bwp_loop < servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count) { - ubwp->bwp_Id = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_loop]->bwp_Id; - ubwp->bwp_Common->genericParameters.locationAndBandwidth = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_loop]->bwp_Common->genericParameters.locationAndBandwidth; - ubwp->bwp_Common->genericParameters.subcarrierSpacing = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_loop]->bwp_Common->genericParameters.subcarrierSpacing; - ubwp->bwp_Common->genericParameters.cyclicPrefix = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_loop]->bwp_Common->genericParameters.cyclicPrefix; + NR_BWP_Uplink_t *ubwp = calloc_or_fail(1, sizeof(*ubwp)); + ubwp->bwp_Common = calloc(1, sizeof(*ubwp->bwp_Common)); + if(configuration->num_additional_bwps > 0) { + ubwp->bwp_Id = configuration->bwp_config[bwp_loop].id; + ubwp->bwp_Common->genericParameters.locationAndBandwidth = configuration->bwp_config[bwp_loop].location_and_bw; + ubwp->bwp_Common->genericParameters.subcarrierSpacing = configuration->bwp_config[bwp_loop].scs; + ubwp->bwp_Common->genericParameters.cyclicPrefix = NULL; } else { ubwp->bwp_Id=bwp_loop+1; ubwp->bwp_Common->genericParameters.locationAndBandwidth = PRBalloc_to_locationandbandwidth(scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,0); @@ -1698,20 +1851,10 @@ static void config_uplinkBWP(NR_BWP_Uplink_t *ubwp, scheduling_request_config(scc, pucch_Config, ubwp->bwp_Common->genericParameters.subcarrierSpacing); set_dl_DataToUL_ACK(pucch_Config, configuration->minRXTXTIME, ubwp->bwp_Common->genericParameters.subcarrierSpacing); - NR_PUSCH_Config_t *pusch_Config = NULL; - if(servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList && - bwp_loop < servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count) { - pusch_Config = clone_pusch_config(servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_loop] - ->bwp_Dedicated->pusch_Config->choice.setup); - } - ubwp->bwp_Dedicated->pusch_Config = config_pusch(pusch_Config, configuration->use_deltaMCS, scc, configuration->force_UL256qam_off ? NULL : uecap); - - long maxMIMO_Layers = servingcellconfigdedicated && - servingcellconfigdedicated->uplinkConfig - && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig - && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 - && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers ? - *servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers : 1; + ubwp->bwp_Dedicated->pusch_Config = config_pusch(configuration->use_deltaMCS, + scc, + configuration->force_UL256qam_off ? NULL : uecap, + configuration->ptrs); ubwp->bwp_Dedicated->srs_Config = get_config_srs(scc, NULL, @@ -1724,6 +1867,7 @@ static void config_uplinkBWP(NR_BWP_Uplink_t *ubwp, ubwp->bwp_Dedicated->configuredGrantConfig = NULL; ubwp->bwp_Dedicated->beamFailureRecoveryConfig = NULL; + return ubwp; } static void set_phr_config(NR_MAC_CellGroupConfig_t *mac_CellGroupConfig) @@ -1745,13 +1889,11 @@ static void set_csi_meas_periodicity(const NR_ServingCellConfigCommon_t *scc, const int ideal_period = set_ideal_period(true); const int num_pucch2 = get_nb_pucch2_per_slot(scc, curr_bwp); const int idx = (uid * 2 / num_pucch2) + is_rsrp; - frame_structure_t *fs = &RC.nrmac[0]->frame_structure; int offset = get_ul_slot_offset(fs, idx, true); - LOG_D(NR_MAC, "set_csi_meas_periodicity: uid = %d, offset = %d, ideal_period = %d", uid, offset, ideal_period); + // checked for validity in verify_radio_configuration AssertFatal(offset < 320, "Not enough UL slots to accomodate all possible UEs. Need to rework the implementation\n"); - if (check_periodicity(4, ideal_period, fs)) { csirep->reportConfigType.choice.periodic->reportSlotConfig.present = NR_CSI_ReportPeriodicityAndOffset_PR_slots4; csirep->reportConfigType.choice.periodic->reportSlotConfig.choice.slots4 = offset; @@ -1957,21 +2099,52 @@ static void config_csi_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, asn1cSeqAdd(&csi_MeasConfig->csi_ReportConfigToAddModList->list, csirep); } +static long config_nrofReportedRS(const NR_UE_NR_Capability_t *uecap, + uint64_t ssb_bitmap, + const NR_ServingCellConfigCommon_t *scc, + int max_num_reported_rs) +{ + long nb_band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; + int num_supported_rs = 0; + if (uecap) { + for (int i = 0; i < uecap->rf_Parameters.supportedBandListNR.list.count; i++) { + NR_BandNR_t *band = uecap->rf_Parameters.supportedBandListNR.list.array[i]; + if (band->bandNR == nb_band) { + if (band->mimo_ParametersPerBand && band->mimo_ParametersPerBand->maxNumberNonGroupBeamReporting) { + int maxNumberNonGroupBeamReporting = 1 << *band->mimo_ParametersPerBand->maxNumberNonGroupBeamReporting; + if (num_supported_rs == 0 || num_supported_rs > maxNumberNonGroupBeamReporting) + num_supported_rs = maxNumberNonGroupBeamReporting; + } + } + } + } + int configured_rs = max_num_reported_rs > 0 ? min(num_supported_rs, max_num_reported_rs) : num_supported_rs; + uint32_t num_ssb = count_bits64(ssb_bitmap); + if (num_ssb == 1 || configured_rs < 2) + return NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n1; + if (num_ssb == 2 || configured_rs == 2) + return NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n2; + if (num_ssb == 3 || configured_rs == 3) + return NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n3; + return NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n4; +} + static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, + const NR_UE_NR_Capability_t *uecap, const NR_ServingCellConfigCommon_t *servingcellconfigcommon, NR_PUCCH_CSI_Resource_t *pucchcsires, - int do_csi, // if rsrp is based on CSI or SSB + const nr_mac_config_t *configuration, int rep_id, int uid, int curr_bwp, int num_antenna_ports, - bool do_sinr) + uint64_t ssb_bitmap) { int resource_id = -1; for (int csi_list = 0; csi_list < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_list++) { NR_CSI_ResourceConfig_t *csires = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_list]; if (csires->csi_RS_ResourceSetList.present == NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB) { - if (do_csi && num_antenna_ports < 4) { + if (configuration->do_CSIRS && num_antenna_ports < 4) { if (csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) resource_id = csires->csi_ResourceConfigId; } else { @@ -1993,13 +2166,13 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, csirep->reportConfigType.choice.periodic = calloc(1, sizeof(*csirep->reportConfigType.choice.periodic)); set_csi_meas_periodicity(servingcellconfigcommon, csirep, uid, curr_bwp, true); asn1cSeqAdd(&csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list, pucchcsires); - if (do_csi && num_antenna_ports < 4) { + if (configuration->do_CSIRS && num_antenna_ports < 4) { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP; csirep->reportQuantity.choice.cri_RSRP = (NULL_t)0; } else { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP; csirep->reportQuantity.choice.ssb_Index_RSRP = (NULL_t)0; - if (do_sinr) { + if (configuration->do_SINR) { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none; csirep->reportQuantity.choice.none = (NULL_t)0; csirep->ext2 = calloc(1, sizeof(*csirep->ext2)); @@ -2011,7 +2184,10 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, csirep->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled; csirep->groupBasedBeamReporting.choice.disabled = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled)); csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS)); - *csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS = NR_CSI_ReportConfig__groupBasedBeamReporting__disabled__nrofReportedRS_n1; + *csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS = config_nrofReportedRS(uecap, + ssb_bitmap, + servingcellconfigcommon, + configuration->max_num_rsrp); asn1cSeqAdd(&csi_MeasConfig->csi_ReportConfigToAddModList->list, csirep); } @@ -2404,9 +2580,7 @@ void update_SIB1_NR_SI(NR_BCCH_DL_SCH_Message_t *sib1_bcch, int num_sibs, int si schedulingInfo->si_BroadcastStatus = NR_SchedulingInfo__si_BroadcastStatus_broadcasting; schedulingInfo->si_Periodicity = NR_SchedulingInfo__si_Periodicity_rf16; bool reg_sib = false; - NR_SI_SchedulingInfo_v1700_t *si_schedulingInfo_v17 = NULL; NR_SchedulingInfo2_r17_t *schedulingInfo2_r17 = NULL; - bool v17_sib = false; for (int i = 0; i < num_sibs; i++) { int sib_num = sibs[i]; AssertFatal(sib_num > 1 && sib_num < 21, "other SIB invalid type\n"); @@ -2424,8 +2598,7 @@ void update_SIB1_NR_SI(NR_BCCH_DL_SCH_Message_t *sib1_bcch, int num_sibs, int si } asn1cSeqAdd(&schedulingInfo->sib_MappingInfo.list, mapping); } else { - if (v17_sib == false) { - si_schedulingInfo_v17 = calloc(1, sizeof(*si_schedulingInfo_v17)); + if (schedulingInfo2_r17 == NULL) { schedulingInfo2_r17 = calloc(1, sizeof(*schedulingInfo2_r17)); schedulingInfo2_r17->si_BroadcastStatus_r17 = NR_SchedulingInfo2_r17__si_BroadcastStatus_r17_broadcasting; schedulingInfo2_r17->si_Periodicity_r17 = NR_SchedulingInfo2_r17__si_Periodicity_r17_rf16; @@ -2444,7 +2617,8 @@ void update_SIB1_NR_SI(NR_BCCH_DL_SCH_Message_t *sib1_bcch, int num_sibs, int si AssertFatal(reg_sib, "At least 1 SIB from SchedulingInfo (SIB2 to SIB14 included) needs to be present\n"); asn1cSeqAdd(&info->schedulingInfoList.list, schedulingInfo); sib1->si_SchedulingInfo = info; - if (si_schedulingInfo_v17) { + if (schedulingInfo2_r17) { + NR_SI_SchedulingInfo_v1700_t *si_schedulingInfo_v17 = calloc_or_fail(1, sizeof(*si_schedulingInfo_v17)); asn1cSeqAdd(&si_schedulingInfo_v17->schedulingInfoList2_r17.list, schedulingInfo2_r17); NR_SIB1_v1610_IEs_t *sib1_v1610 = NULL; if (sib1->nonCriticalExtension) @@ -2951,7 +3125,7 @@ static NR_MAC_CellGroupConfig_t *configure_mac_cellgroup(const nr_mac_timers_t * NR_MAC_CellGroupConfig_t * mac_CellGroupConfig = calloc(1, sizeof(*mac_CellGroupConfig)); AssertFatal(mac_CellGroupConfig != NULL, "Couldn't allocate mac-CellGroupConfig. Out of memory!\n"); mac_CellGroupConfig->bsr_Config = calloc(1, sizeof(*mac_CellGroupConfig->bsr_Config)); - mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf10; + mac_CellGroupConfig->bsr_Config->periodicBSR_Timer = NR_BSR_Config__periodicBSR_Timer_sf5; mac_CellGroupConfig->bsr_Config->retxBSR_Timer = NR_BSR_Config__retxBSR_Timer_sf80; mac_CellGroupConfig->tag_Config = calloc(1, sizeof(*mac_CellGroupConfig->tag_Config)); mac_CellGroupConfig->tag_Config->tag_ToReleaseList = NULL; @@ -2988,16 +3162,28 @@ static NR_MAC_CellGroupConfig_t *configure_mac_cellgroup(const nr_mac_timers_t * return mac_CellGroupConfig; } -// Set HARQ related IEs according to the number of DL, UL harqprocesses configured -static void fill_harq_IEs(NR_ServingCellConfig_t *scc, int num_dlharq, int num_ulharq) +static void allocate_32_harq(NR_PDSCH_Config_t *pdsch_Config) { + if (!pdsch_Config->ext3) + pdsch_Config->ext3 = calloc(1, sizeof(*pdsch_Config->ext3)); + asn1cCallocOne(pdsch_Config->ext3->harq_ProcessNumberSizeDCI_1_1_r17, 5); +} - AssertFatal(scc && scc->pdsch_ServingCellConfig && - scc->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, +static void allocate_32_ul_harq(NR_PUSCH_Config_t *pusch_Config) +{ + if (!pusch_Config->ext2) + pusch_Config->ext2 = calloc(1, sizeof(*pusch_Config->ext2)); + asn1cCallocOne(pusch_Config->ext2->harq_ProcessNumberSizeDCI_0_1_r17, 5); +} + +// Set HARQ related IEs according to the number of DL, UL harqprocesses configured +static void fill_harq_IEs(NR_ServingCellConfig_t *scc, int num_dlharq, int num_ulharq, int bwp_id) +{ + AssertFatal(scc + && scc->pdsch_ServingCellConfig + && scc->pdsch_ServingCellConfig->present == NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup, "PDSCH_Servingcellconfig IEs NOT present\n"); - NR_PDSCH_ServingCellConfig_t *pdsch_scc = scc->pdsch_ServingCellConfig->choice.setup; - switch (num_dlharq) { case 2: *pdsch_scc->nrofHARQ_ProcessesForPDSCH = NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n2; @@ -3026,34 +3212,27 @@ static void fill_harq_IEs(NR_ServingCellConfig_t *scc, int num_dlharq, int num_u pdsch_scc->ext3 = calloc(1, sizeof(*pdsch_scc->ext3)); asn1cCallocOne(pdsch_scc->ext3->nrofHARQ_ProcessesForPDSCH_v1700, NR_PDSCH_ServingCellConfig__ext3__nrofHARQ_ProcessesForPDSCH_v1700_n32); - NR_BWP_DownlinkDedicated_t *dlbwp = scc->initialDownlinkBWP; - if (dlbwp && dlbwp->pdsch_Config && - dlbwp->pdsch_Config->present == NR_SetupRelease_PDSCH_Config_PR_setup) { - NR_PDSCH_Config_t *dlcfg = scc->initialDownlinkBWP->pdsch_Config->choice.setup; - if (!dlcfg->ext3) - dlcfg->ext3 = calloc(1, sizeof(*dlcfg->ext3)); - asn1cCallocOne(dlcfg->ext3->harq_ProcessNumberSizeDCI_1_1_r17, 5); - } - int num_dl_bwp = 0; - if (scc->downlinkBWP_ToAddModList) - num_dl_bwp = scc->downlinkBWP_ToAddModList->list.count; - for (int i = 0;i < num_dl_bwp; i++) { - dlbwp = scc->downlinkBWP_ToAddModList->list.array[i]->bwp_Dedicated; - if (dlbwp && dlbwp->pdsch_Config && - dlbwp->pdsch_Config->present == NR_SetupRelease_PDSCH_Config_PR_setup) { - NR_PDSCH_Config_t *dlcfg = dlbwp->pdsch_Config->choice.setup; - if (!dlcfg->ext3) - dlcfg->ext3 = calloc(1, sizeof(*dlcfg->ext3)); - asn1cCallocOne(dlcfg->ext3->harq_ProcessNumberSizeDCI_1_1_r17, 5); + NR_BWP_DownlinkDedicated_t *dlbwp = NULL; + if (bwp_id == 0) { + dlbwp = scc->initialDownlinkBWP; + if (dlbwp && dlbwp->pdsch_Config && dlbwp->pdsch_Config->present == NR_SetupRelease_PDSCH_Config_PR_setup) + allocate_32_harq(scc->initialDownlinkBWP->pdsch_Config->choice.setup); + } else { + for (int i = 0; i < scc->downlinkBWP_ToAddModList->list.count; i++) { + if (scc->downlinkBWP_ToAddModList->list.array[i]->bwp_Id != bwp_id) + continue; + dlbwp = scc->downlinkBWP_ToAddModList->list.array[i]->bwp_Dedicated; + if (dlbwp && dlbwp->pdsch_Config && dlbwp->pdsch_Config->present == NR_SetupRelease_PDSCH_Config_PR_setup) + allocate_32_harq(dlbwp->pdsch_Config->choice.setup); } } break; default: // Already IE should have been set to 16 harq processes + AssertFatal(false, "Invalid number of HARQ processes\n"); break; } - - AssertFatal(scc->uplinkConfig,"uplinkConfig IE NOT present\n"); + AssertFatal(scc->uplinkConfig, "uplinkConfig IE NOT present\n"); if (num_ulharq == 32) { if (!scc->uplinkConfig->pusch_ServingCellConfig) @@ -3066,50 +3245,31 @@ static void fill_harq_IEs(NR_ServingCellConfig_t *scc, int num_dlharq, int num_u pusch_scc->ext3 = calloc(1, sizeof(*pusch_scc->ext3)); asn1cCallocOne(pusch_scc->ext3->nrofHARQ_ProcessesForPUSCH_r17, NR_PUSCH_ServingCellConfig__ext3__nrofHARQ_ProcessesForPUSCH_r17_n32); - NR_BWP_UplinkDedicated_t *ulbwp = scc->uplinkConfig->initialUplinkBWP; - if (ulbwp && ulbwp->pusch_Config && - ulbwp->pusch_Config->present == NR_SetupRelease_PUSCH_Config_PR_setup) { - NR_PUSCH_Config_t *ulcfg = ulbwp->pusch_Config->choice.setup; - if (!ulcfg->ext2) - ulcfg->ext2 = calloc(1, sizeof(*ulcfg->ext2)); - asn1cCallocOne(ulcfg->ext2->harq_ProcessNumberSizeDCI_0_1_r17, 5); - } - int num_ul_bwp = 0; - if (scc->uplinkConfig->uplinkBWP_ToAddModList) - num_ul_bwp = scc->uplinkConfig->uplinkBWP_ToAddModList->list.count; - for (int i = 0;i < num_ul_bwp; i++) { - ulbwp = scc->uplinkConfig->uplinkBWP_ToAddModList->list.array[i]->bwp_Dedicated; - if (ulbwp && ulbwp->pusch_Config && - ulbwp->pusch_Config->present == NR_SetupRelease_PUSCH_Config_PR_setup) { - NR_PUSCH_Config_t *ulcfg = ulbwp->pusch_Config->choice.setup; - if (!ulcfg->ext2) - ulcfg->ext2 = calloc(1, sizeof(*ulcfg->ext2)); - asn1cCallocOne(ulcfg->ext2->harq_ProcessNumberSizeDCI_0_1_r17, 5); + NR_BWP_UplinkDedicated_t *ulbwp = NULL; + if (bwp_id == 0) { + ulbwp = scc->uplinkConfig->initialUplinkBWP; + if (ulbwp && ulbwp->pusch_Config && ulbwp->pusch_Config->present == NR_SetupRelease_PUSCH_Config_PR_setup) + allocate_32_ul_harq(ulbwp->pusch_Config->choice.setup); + } else { + for (int i = 0; i < scc->uplinkConfig->uplinkBWP_ToAddModList->list.count; i++) { + if (bwp_id != scc->uplinkConfig->uplinkBWP_ToAddModList->list.array[i]->bwp_Id) + continue; + ulbwp = scc->uplinkConfig->uplinkBWP_ToAddModList->list.array[i]->bwp_Dedicated; + if (ulbwp && ulbwp->pusch_Config && ulbwp->pusch_Config->present == NR_SetupRelease_PUSCH_Config_PR_setup) + allocate_32_ul_harq(ulbwp->pusch_Config->choice.setup); } } } } -static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, - const NR_ServingCellConfigCommon_t *scc, - const NR_ServingCellConfig_t *servingcellconfigdedicated, - const nr_mac_config_t *configuration) +static NR_BWP_UplinkDedicated_t *configure_initial_ul_bwp(const NR_ServingCellConfigCommon_t *scc, + const nr_mac_config_t *configuration, + int maxMIMO_Layers, + int id) { - const int pdsch_AntennaPorts = - configuration->pdsch_AntennaPorts.N1 * configuration->pdsch_AntennaPorts.N2 * configuration->pdsch_AntennaPorts.XP; - int curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - NR_SpCellConfig_t *SpCellConfig = calloc(1, sizeof(*SpCellConfig)); - SpCellConfig->servCellIndex = NULL; - SpCellConfig->reconfigurationWithSync = NULL; - SpCellConfig->rlmInSyncOutOfSyncThreshold = NULL; - SpCellConfig->rlf_TimersAndConstants = NULL; - - SpCellConfig->spCellConfigDedicated = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated)); - SpCellConfig->spCellConfigDedicated->uplinkConfig = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->uplinkConfig)); - NR_UplinkConfig_t *uplinkConfig = SpCellConfig->spCellConfigDedicated->uplinkConfig; - NR_BWP_UplinkDedicated_t *initialUplinkBWP = calloc(1, sizeof(*initialUplinkBWP)); - uplinkConfig->initialUplinkBWP = initialUplinkBWP; + NR_BWP_t *genericParameters = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + int curr_bwp = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); initialUplinkBWP->pucch_Config = calloc(1, sizeof(*initialUplinkBWP->pucch_Config)); initialUplinkBWP->pucch_Config->present = NR_SetupRelease_PUCCH_Config_PR_setup; NR_PUCCH_Config_t *pucch_Config = calloc(1, sizeof(*pucch_Config)); @@ -3119,44 +3279,35 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, pucch_Config->resourceToAddModList = calloc(1, sizeof(*pucch_Config->resourceToAddModList)); pucch_Config->resourceToReleaseList = NULL; int num_pucch2 = get_nb_pucch2_per_slot(scc, curr_bwp); - config_pucch_resset0(pucch_Config, uid, curr_bwp, num_pucch2, NULL); - config_pucch_resset1(pucch_Config, uid, num_pucch2, NULL); + config_pucch_resset0(pucch_Config, id, curr_bwp, num_pucch2, NULL); + config_pucch_resset1(pucch_Config, id, num_pucch2, NULL); set_pucch_power_config(pucch_Config, configuration->do_CSIRS); - initialUplinkBWP->pusch_Config = config_pusch(NULL, configuration->use_deltaMCS, scc, NULL); - - long maxMIMO_Layers = uplinkConfig && uplinkConfig->pusch_ServingCellConfig - && uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 - && uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers - ? *uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers - : 1; + initialUplinkBWP->pusch_Config = config_pusch(configuration->use_deltaMCS, scc, NULL, configuration->ptrs); // We are using do_srs = 0 here because the periodic SRS will only be enabled in update_cellGroupConfig() if do_srs == 1 - initialUplinkBWP->srs_Config = get_config_srs(scc, NULL, curr_bwp, uid, 0, maxMIMO_Layers, configuration->minRXTXTIME, 0); + initialUplinkBWP->srs_Config = get_config_srs(scc, NULL, curr_bwp, id, 0, maxMIMO_Layers, configuration->minRXTXTIME, 0); scheduling_request_config(scc, pucch_Config, scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing); + set_dl_DataToUL_ACK(pucch_Config, configuration->minRXTXTIME, genericParameters->subcarrierSpacing); + return initialUplinkBWP; +} - set_dl_DataToUL_ACK(pucch_Config, - configuration->minRXTXTIME, - scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing); - - SpCellConfig->spCellConfigDedicated->initialDownlinkBWP = - calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->initialDownlinkBWP)); - NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; +static NR_BWP_DownlinkDedicated_t *configure_initial_dl_bwp(const NR_ServingCellConfigCommon_t *scc, + const int pdsch_AntennaPorts, + uint64_t bitmap, + const nr_mac_config_t *configuration) +{ + NR_BWP_DownlinkDedicated_t *bwp_Dedicated = calloc(1, sizeof(*bwp_Dedicated)); bwp_Dedicated->pdcch_Config = calloc(1, sizeof(*bwp_Dedicated->pdcch_Config)); bwp_Dedicated->pdcch_Config->present = NR_SetupRelease_PDCCH_Config_PR_setup; - bwp_Dedicated->pdcch_Config->choice.setup = calloc(1, sizeof(*bwp_Dedicated->pdcch_Config->choice.setup)); - - bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList = - calloc(1, sizeof(*bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList)); - - bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList = - calloc(1, sizeof(*bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList)); - - uint64_t bitmap = get_ssb_bitmap(scc); + NR_PDCCH_Config_t *pdcch_Config = calloc(1, sizeof(*pdcch_Config)); + pdcch_Config->searchSpacesToAddModList = calloc(1, sizeof(*pdcch_Config->searchSpacesToAddModList)); + pdcch_Config->controlResourceSetToAddModList = calloc(1, sizeof(*pdcch_Config->controlResourceSetToAddModList)); + NR_BWP_t *genericParameters = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters; + int curr_bwp = NRRIV2BW(genericParameters->locationAndBandwidth, MAX_BWP_SIZE); NR_ControlResourceSet_t *coreset = get_coreset_config(0, curr_bwp, bitmap); - - asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, coreset); + asn1cSeqAdd(&pdcch_Config->controlResourceSetToAddModList->list, coreset); int css_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; css_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; @@ -3169,23 +3320,161 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, searchspaceid = 5; int rrc_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; int num_cces = get_coreset_num_cces(coreset->frequencyDomainResources.buf, coreset->duration); - verify_agg_levels(num_cces, - configuration->num_agg_level_candidates, - coreset->controlResourceSetId, - searchspaceid, - rrc_num_agg_level_candidates); + verify_agg_levels(num_cces, configuration->num_agg_level_candidates, coreset->controlResourceSetId, rrc_num_agg_level_candidates); NR_SearchSpace_t *ss2 = rrc_searchspace_config(false, searchspaceid, coreset->controlResourceSetId, rrc_num_agg_level_candidates); - asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss); - asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss2); + asn1cSeqAdd(&pdcch_Config->searchSpacesToAddModList->list, ss); + asn1cSeqAdd(&pdcch_Config->searchSpacesToAddModList->list, ss2); + bwp_Dedicated->pdcch_Config->choice.setup = pdcch_Config; - bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, pdsch_AntennaPorts); + bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, pdsch_AntennaPorts, configuration->ptrs); + return bwp_Dedicated; +} - SpCellConfig->spCellConfigDedicated->tag_Id = 0; - SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig = - calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig)); +static NR_CSI_MeasConfig_t *get_csiMeasConfig(const NR_ServingCellConfig_t *configDedicated, + const NR_UE_NR_Capability_t *uecap, + const NR_ServingCellConfigCommon_t *scc, + const nr_mac_config_t *configuration, + int uid, + int bwp_id, + uint64_t bitmap) +{ + NR_CSI_MeasConfig_t *csi_MeasConfig = calloc(1, sizeof(*csi_MeasConfig)); + csi_MeasConfig->csi_SSB_ResourceSetToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_SSB_ResourceSetToAddModList)); + csi_MeasConfig->csi_SSB_ResourceSetToReleaseList = NULL; + csi_MeasConfig->csi_ResourceConfigToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_ResourceConfigToAddModList)); + csi_MeasConfig->csi_ResourceConfigToReleaseList = NULL; + csi_MeasConfig->csi_ReportConfigToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_ReportConfigToAddModList)); + csi_MeasConfig->csi_ReportConfigToReleaseList = NULL; + + NR_CSI_SSB_ResourceSet_t *ssbresset0 = calloc(1, sizeof(*ssbresset0)); + ssbresset0->csi_SSB_ResourceSetId = 0; + + for (int i = 0; i < 64; i++) { + if ((bitmap >> (63 - i)) & 0x01) { + NR_SSB_Index_t *ssbres = NULL; + asn1cCallocOne(ssbres, i); + asn1cSeqAdd(&ssbresset0->csi_SSB_ResourceList.list, ssbres); + } + } + asn1cSeqAdd(&csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list, ssbresset0); + + int curr_bwp; + NR_SetupRelease_PDSCH_Config_t *pdsch_Config; + if (bwp_id == 0) { + pdsch_Config = configDedicated->initialDownlinkBWP->pdsch_Config; + curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + } else { + NR_BWP_Downlink_t *bwp = configDedicated->downlinkBWP_ToAddModList->list.array[0]; + pdsch_Config = bwp->bwp_Dedicated->pdsch_Config; + curr_bwp = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + AssertFatal(bwp_id == bwp->bwp_Id, "BWP ID doesn't match\n"); + } + + const int pdsch_AntennaPorts = + configuration->pdsch_AntennaPorts.N1 * configuration->pdsch_AntennaPorts.N2 * configuration->pdsch_AntennaPorts.XP; + config_csirs(scc, csi_MeasConfig, pdsch_AntennaPorts, curr_bwp, configuration->do_CSIRS, bwp_id); + config_csiim(configuration->do_CSIRS, pdsch_AntennaPorts, curr_bwp, csi_MeasConfig, bwp_id); + + NR_CSI_ResourceConfig_t *csires1 = calloc(1, sizeof(*csires1)); + csires1->csi_ResourceConfigId = bwp_id + 20; + csires1->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB; + csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = + calloc(1, sizeof(*csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); + csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList = + calloc(1, sizeof(*csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList)); + NR_CSI_SSB_ResourceSetId_t *ssbres00 = calloc(1, sizeof(*ssbres00)); + *ssbres00 = 0; + asn1cSeqAdd(&csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list, ssbres00); + csires1->bwp_Id = bwp_id; + csires1->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; + asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, csires1); + + int pucch_Resource = 2; + if (configuration->do_CSIRS) { + NR_CSI_ResourceConfig_t *csires0 = calloc(1, sizeof(*csires0)); + csires0->csi_ResourceConfigId = bwp_id; + csires0->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB; + csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = + calloc(1, sizeof(*csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); + csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList = + calloc(1, sizeof(*csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList)); + NR_NZP_CSI_RS_ResourceSetId_t *nzp0 = calloc(1, sizeof(*nzp0)); + *nzp0 = bwp_id; + asn1cSeqAdd(&csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list, nzp0); + csires0->bwp_Id = bwp_id; + csires0->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; + asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, csires0); + } + + if (configuration->do_CSIRS && pdsch_AntennaPorts > 1) { + NR_CSI_ResourceConfig_t *csires2 = calloc(1, sizeof(*csires2)); + csires2->csi_ResourceConfigId = bwp_id + 10; + csires2->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_csi_IM_ResourceSetList; + csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList = + calloc(1, sizeof(*csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList)); + NR_CSI_IM_ResourceSetId_t *csiim00 = calloc(1, sizeof(*csiim00)); + *csiim00 = bwp_id; + asn1cSeqAdd(&csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList->list, csiim00); + csires2->bwp_Id = bwp_id; + csires2->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; + asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, csires2); + + NR_PUCCH_CSI_Resource_t *pucchcsi = calloc(1, sizeof(*pucchcsi)); + pucchcsi->uplinkBandwidthPartId = bwp_id; + pucchcsi->pucch_Resource = pucch_Resource; + config_csi_meas_report(csi_MeasConfig, + scc, + pucchcsi, + pdsch_Config, + &configuration->pdsch_AntennaPorts, + *configDedicated->pdsch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers, + bwp_id, + uid, + curr_bwp); + } + NR_PUCCH_CSI_Resource_t *pucchrsrp = calloc(1, sizeof(*pucchrsrp)); + pucchrsrp->uplinkBandwidthPartId = bwp_id; + pucchrsrp->pucch_Resource = pucch_Resource; + config_rsrp_meas_report(csi_MeasConfig, + uecap, + scc, + pucchrsrp, + configuration, + bwp_id + 10, + uid, + curr_bwp, + pdsch_AntennaPorts, + bitmap); + return csi_MeasConfig; +} + +static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, + const NR_ServingCellConfigCommon_t *scc, + const nr_mac_config_t *configuration) +{ + const int pdsch_AntennaPorts = + configuration->pdsch_AntennaPorts.N1 * configuration->pdsch_AntennaPorts.N2 * configuration->pdsch_AntennaPorts.XP; + NR_SpCellConfig_t *SpCellConfig = calloc(1, sizeof(*SpCellConfig)); + SpCellConfig->servCellIndex = NULL; + SpCellConfig->reconfigurationWithSync = NULL; + SpCellConfig->rlmInSyncOutOfSyncThreshold = NULL; + SpCellConfig->rlf_TimersAndConstants = NULL; + + NR_ServingCellConfig_t *configDedicated = calloc(1, sizeof(*configDedicated)); + configDedicated->uplinkConfig = calloc(1, sizeof(*configDedicated->uplinkConfig)); + NR_UplinkConfig_t *uplinkConfig = configDedicated->uplinkConfig; + long maxMIMO_Layers = uplinkConfig + && uplinkConfig->pusch_ServingCellConfig + && uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 + && uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers + ? *uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers + : 1; + + configDedicated->tag_Id = 0; + configDedicated->pdsch_ServingCellConfig = calloc(1, sizeof(*configDedicated->pdsch_ServingCellConfig)); NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig = calloc(1, sizeof(*pdsch_servingcellconfig)); - SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->present = NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; - SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; + configDedicated->pdsch_ServingCellConfig->present = NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; + configDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; pdsch_servingcellconfig->xOverhead = NULL; @@ -3206,166 +3495,43 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, pdsch_servingcellconfig->ext3->downlinkHARQ_FeedbackDisabled_r17->choice.setup.buf[3] = 0xFF; } - // Downlink BWPs - int n_dl_bwp = 0; - if (servingcellconfigdedicated && servingcellconfigdedicated->downlinkBWP_ToAddModList - && servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count > 0) { - n_dl_bwp = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count; - } - int default_dl_bwp = 0; - int first_active_dl_bwp = 0; - if (n_dl_bwp > 0) { - SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList = - calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList)); - for (int bwp_loop = 0; bwp_loop < n_dl_bwp; bwp_loop++) { - NR_BWP_Downlink_t *bwp = calloc(1, sizeof(*bwp)); - config_downlinkBWP(bwp, scc, servingcellconfigdedicated, NULL, 0, false, bwp_loop, true, configuration->num_agg_level_candidates); - asn1cSeqAdd(&SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list, bwp); - } - const NR_BWP_Id_t *firstActiveDownlinkBWP_Id = servingcellconfigdedicated->firstActiveDownlinkBWP_Id; - first_active_dl_bwp = firstActiveDownlinkBWP_Id ? *firstActiveDownlinkBWP_Id : 1; - const NR_BWP_Id_t *defaultDownlinkBWP_Id = servingcellconfigdedicated->defaultDownlinkBWP_Id; - default_dl_bwp = defaultDownlinkBWP_Id ? *defaultDownlinkBWP_Id : 1; - } - asn1cCallocOne(SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id, first_active_dl_bwp); - asn1cCallocOne(SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id, default_dl_bwp); + uint64_t bitmap = get_ssb_bitmap(scc); + int first_active_bwp = 0; + if (configuration->num_additional_bwps > 0) + first_active_bwp = configuration->first_active_bwp; - // Uplink BWPs - int n_ul_bwp = 0; - if (servingcellconfigdedicated && servingcellconfigdedicated->uplinkConfig - && servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList - && servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count > 0) { - n_ul_bwp = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; - } - int first_active_ul_bwp = 0; - if (n_ul_bwp > 0) { + asn1cCallocOne(configDedicated->firstActiveDownlinkBWP_Id, first_active_bwp); + asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_bwp); + if (first_active_bwp == 0) { + uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, maxMIMO_Layers, uid); + configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, configuration); + } else { + configDedicated->downlinkBWP_ToAddModList = calloc(1, sizeof(*configDedicated->downlinkBWP_ToAddModList)); + NR_BWP_Downlink_t *bwp = config_downlinkBWP(scc, + NULL, + 0, + false, + first_active_bwp - 1, + true, + configuration); + asn1cSeqAdd(&configDedicated->downlinkBWP_ToAddModList->list, bwp); uplinkConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*uplinkConfig->uplinkBWP_ToAddModList)); - for (int bwp_loop = 0; bwp_loop < n_ul_bwp; bwp_loop++) { - NR_BWP_Uplink_t *ubwp = calloc(1, sizeof(*ubwp)); - config_uplinkBWP(ubwp, bwp_loop, true, uid, configuration, servingcellconfigdedicated, scc, NULL); - asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ubwp); - } - const NR_BWP_Id_t *firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id; - first_active_ul_bwp = firstActiveUplinkBWP_Id ? *firstActiveUplinkBWP_Id : 1; - } - asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_ul_bwp); - - SpCellConfig->spCellConfigDedicated->csi_MeasConfig = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig)); - SpCellConfig->spCellConfigDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; - - NR_CSI_MeasConfig_t *csi_MeasConfig = calloc(1, sizeof(*csi_MeasConfig)); - SpCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup = csi_MeasConfig; - - csi_MeasConfig->csi_SSB_ResourceSetToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_SSB_ResourceSetToAddModList)); - csi_MeasConfig->csi_SSB_ResourceSetToReleaseList = NULL; - csi_MeasConfig->csi_ResourceConfigToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_ResourceConfigToAddModList)); - csi_MeasConfig->csi_ResourceConfigToReleaseList = NULL; - csi_MeasConfig->csi_ReportConfigToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_ReportConfigToAddModList)); - csi_MeasConfig->csi_ReportConfigToReleaseList = NULL; - - NR_CSI_SSB_ResourceSet_t *ssbresset0 = calloc(1, sizeof(*ssbresset0)); - ssbresset0->csi_SSB_ResourceSetId = 0; - - for (int i = 0; i < 64; i++) { - if ((bitmap >> (63 - i)) & 0x01) { - NR_SSB_Index_t *ssbres = NULL; - asn1cCallocOne(ssbres, i); - asn1cSeqAdd(&ssbresset0->csi_SSB_ResourceList.list, ssbres); - } - } - asn1cSeqAdd(&csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list, ssbresset0); - - int bwp_loop_end = n_dl_bwp > 0 ? n_dl_bwp : 1; - for (int bwp_loop = 0; bwp_loop < bwp_loop_end; bwp_loop++) { - int curr_bwp, bwp_id; - struct NR_SetupRelease_PDSCH_Config *pdsch_Config; - if (n_dl_bwp == 0) { - pdsch_Config = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config; - curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - bwp_id = 0; - } else { - NR_BWP_Downlink_t *bwp = SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_loop]; - pdsch_Config = bwp->bwp_Dedicated->pdsch_Config; - curr_bwp = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - bwp_id = bwp->bwp_Id; - } - - config_csirs(scc, csi_MeasConfig, pdsch_AntennaPorts, curr_bwp, configuration->do_CSIRS, bwp_loop); - config_csiim(configuration->do_CSIRS, pdsch_AntennaPorts, curr_bwp, csi_MeasConfig, bwp_loop); - - NR_CSI_ResourceConfig_t *csires1 = calloc(1, sizeof(*csires1)); - csires1->csi_ResourceConfigId = bwp_id + 20; - csires1->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB; - csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = - calloc(1, sizeof(*csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); - csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList = - calloc(1, sizeof(*csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList)); - NR_CSI_SSB_ResourceSetId_t *ssbres00 = calloc(1, sizeof(*ssbres00)); - *ssbres00 = 0; - asn1cSeqAdd(&csires1->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list, ssbres00); - csires1->bwp_Id = bwp_id; - csires1->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, csires1); - - int pucch_Resource = 2; - - if (configuration->do_CSIRS) { - NR_CSI_ResourceConfig_t *csires0 = calloc(1, sizeof(*csires0)); - csires0->csi_ResourceConfigId = bwp_id; - csires0->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB; - csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = - calloc(1, sizeof(*csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); - csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList = - calloc(1, sizeof(*csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList)); - NR_NZP_CSI_RS_ResourceSetId_t *nzp0 = calloc(1, sizeof(*nzp0)); - *nzp0 = bwp_loop; - asn1cSeqAdd(&csires0->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list, nzp0); - csires0->bwp_Id = bwp_id; - csires0->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, csires0); - } - - if (configuration->do_CSIRS && pdsch_AntennaPorts > 1) { - NR_CSI_ResourceConfig_t *csires2 = calloc(1, sizeof(*csires2)); - csires2->csi_ResourceConfigId = bwp_id + 10; - csires2->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_csi_IM_ResourceSetList; - csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList = - calloc(1, sizeof(*csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList)); - NR_CSI_IM_ResourceSetId_t *csiim00 = calloc(1, sizeof(*csiim00)); - *csiim00 = bwp_loop; - asn1cSeqAdd(&csires2->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList->list, csiim00); - csires2->bwp_Id = bwp_id; - csires2->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, csires2); - - NR_PUCCH_CSI_Resource_t *pucchcsi = calloc(1, sizeof(*pucchcsi)); - pucchcsi->uplinkBandwidthPartId = bwp_id; - pucchcsi->pucch_Resource = pucch_Resource; - config_csi_meas_report(csi_MeasConfig, - scc, - pucchcsi, - pdsch_Config, - &configuration->pdsch_AntennaPorts, - *pdsch_servingcellconfig->ext1->maxMIMO_Layers, - bwp_id, - uid, - curr_bwp); - } - NR_PUCCH_CSI_Resource_t *pucchrsrp = calloc(1, sizeof(*pucchrsrp)); - pucchrsrp->uplinkBandwidthPartId = bwp_id; - pucchrsrp->pucch_Resource = pucch_Resource; - config_rsrp_meas_report(csi_MeasConfig, - scc, - pucchrsrp, - configuration->do_CSIRS, - bwp_id + 10, - uid, - curr_bwp, - pdsch_AntennaPorts, - configuration->do_SINR); + NR_BWP_Uplink_t *ubwp = config_uplinkBWP(first_active_bwp - 1, true, uid, maxMIMO_Layers, configuration, scc, NULL); + asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ubwp); } - fill_harq_IEs(SpCellConfig->spCellConfigDedicated, configuration->num_dlharq, configuration->num_ulharq); + configDedicated->csi_MeasConfig = calloc(1, sizeof(*configDedicated->csi_MeasConfig)); + configDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; + configDedicated->csi_MeasConfig->choice.setup = get_csiMeasConfig(configDedicated, + NULL, + scc, + configuration, + uid, + first_active_bwp, + bitmap); + + fill_harq_IEs(configDedicated, configuration->num_dlharq, configuration->num_ulharq, first_active_bwp); + SpCellConfig->spCellConfigDedicated = configDedicated; if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_SpCellConfig, SpCellConfig); @@ -3492,12 +3658,57 @@ NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, return rlc_BearerConfig; } +static bool verify_radio_configuration(int uid, const NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *configuration) +{ + frame_structure_t *fs = &RC.nrmac[0]->frame_structure; + int srs_offset = get_ul_slot_offset(fs, uid, false); + // see configure_periodic_srs + if (srs_offset >= 2560) { + LOG_E(NR_RRC, "UID %d, cannot allocate resources for SRS, rejecting UE\n", uid); + return false; + } + + int n_dl_bwp = 1 + configuration->num_additional_bwps; // initial + additional bwps + int csi_offset = fs->numb_slots_period * n_dl_bwp; + // see set_csirs_periodicity + if (csi_offset / 320 >= get_full_dl_slots_per_period(fs)) { + LOG_E(NR_RRC, "UID %d, cannot allocate resources for CSI-RS, rejecting UE\n", uid); + return false; // cannot allocate resources for CSI-RS + } + + int curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int num_pucch2 = get_nb_pucch2_per_slot(scc, curr_bwp); + int pucchres0_startingPRB = (PUCCH2_SIZE * num_pucch2) + uid; + // see config_pucch_resset0 + if (pucchres0_startingPRB >= curr_bwp) { + LOG_E(NR_RRC, "UID %d, cannot allocate resources for PUCCH0, rejecting UE\n", uid); + return false; // cannot allocate resources for PUCCH0 + } + // see get_nb_pucch2_per_slot + if ((num_pucch2 * PUCCH2_SIZE) + MAX_MOBILES_PER_GNB > curr_bwp) { + LOG_E(NR_RRC, "UID %d, cannot allocate resources for PUCCH2, rejecting UE\n", uid); + return false; // cannot allocate resources for PUCCH2 + } + const int idx = (uid * 2 / num_pucch2) + 1; + int offset = get_ul_slot_offset(fs, idx, true); + // see set_csi_meas_periodicity + if (offset >= 320) { + LOG_E(NR_RRC, "UID %d, cannot allocate resources for CSI reporting, rejecting UE\n", uid); + return false; // cannot allocate resources for CSI report + } + + return true; +} + NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, const NR_ServingCellConfigCommon_t *scc, - const NR_ServingCellConfig_t *servingcellconfigdedicated, const nr_mac_config_t *configuration, const nr_rlc_configuration_t *default_rlc_config) { + if (!verify_radio_configuration(uid, scc, configuration)) + return NULL; + + NR_SpCellConfig_t *spCellConfig = get_initial_SpCellConfig(uid, scc, configuration); NR_CellGroupConfig_t *cellGroupConfig = calloc(1, sizeof(*cellGroupConfig)); cellGroupConfig->cellGroupId = 0; @@ -3515,42 +3726,18 @@ NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, cellGroupConfig->physicalCellGroupConfig = configure_phy_cellgroup(); - cellGroupConfig->spCellConfig = get_initial_SpCellConfig(uid, scc, servingcellconfigdedicated, configuration); + cellGroupConfig->spCellConfig = spCellConfig; cellGroupConfig->sCellToAddModList = NULL; cellGroupConfig->sCellToReleaseList = NULL; return cellGroupConfig; } -void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, - const int uid, - NR_UE_NR_Capability_t *uecap, - const nr_mac_config_t *configuration, - const NR_ServingCellConfigCommon_t *scc) +static long set_ul_max_layers(const nr_mac_config_t *configuration, const NR_UE_NR_Capability_t *uecap) { - DevAssert(cellGroupConfig != NULL); - DevAssert(cellGroupConfig->spCellConfig != NULL); - DevAssert(configuration != NULL); - DevAssert(scc != NULL); - - NR_SpCellConfig_t *SpCellConfig = cellGroupConfig->spCellConfig; - - NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig = SpCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup; - set_dl_maxmimolayers(pdsch_servingcellconfig, scc, uecap, configuration->maxMIMO_layers); - - NR_CSI_MeasConfig_t *csi_MeasConfig = SpCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup; - for (int report = 0; report < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; report++) { - NR_CSI_ReportConfig_t *csirep = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[report]; - if(csirep->codebookConfig) - config_csi_codebook(&configuration->pdsch_AntennaPorts, *pdsch_servingcellconfig->ext1->maxMIMO_Layers, csirep->codebookConfig); - } - - int curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - NR_UplinkConfig_t *uplinkConfig = - SpCellConfig && SpCellConfig->spCellConfigDedicated ? SpCellConfig->spCellConfigDedicated->uplinkConfig : NULL; - - uint8_t ul_max_layers = 1; - if (uecap && uecap->featureSets && uecap->featureSets->featureSetsUplinkPerCC + long ul_max_layers = 1; + if (uecap && uecap->featureSets + && uecap->featureSets->featureSetsUplinkPerCC && uecap->featureSets->featureSetsUplinkPerCC->list.count > 0) { NR_FeatureSetUplinkPerCC_t *ul_feature_setup_per_cc = uecap->featureSets->featureSetsUplinkPerCC->list.array[0]; if (ul_feature_setup_per_cc->mimo_CB_PUSCH->maxNumberMIMO_LayersCB_PUSCH) { @@ -3566,88 +3753,187 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, } } ul_max_layers = min(ul_max_layers, configuration->pusch_AntennaPorts); - if (uplinkConfig->initialUplinkBWP->pusch_Config) { - NR_PUSCH_Config_t *pusch_Config = uplinkConfig->initialUplinkBWP->pusch_Config->choice.setup; - if (pusch_Config->maxRank == NULL) { - pusch_Config->maxRank = calloc(1, sizeof(*pusch_Config->maxRank)); - } - *pusch_Config->maxRank = ul_max_layers; + } + return ul_max_layers; +} + +NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_t *cellGroupConfig, + const nr_mac_config_t *configuration, + const NR_UE_NR_Capability_t *uecap, + const NR_ServingCellConfigCommon_t *scc, + int uid, + int old_bwp, + int new_bwp) +{ + NR_SpCellConfig_t *spCellConfig = cellGroupConfig->spCellConfig; + NR_ServingCellConfig_t *configDedicated = spCellConfig->spCellConfigDedicated; + *configDedicated->firstActiveDownlinkBWP_Id = new_bwp; + NR_UplinkConfig_t *uplinkConfig = configDedicated->uplinkConfig; + *uplinkConfig->firstActiveUplinkBWP_Id = new_bwp; + long ul_maxMIMO_Layers = set_ul_max_layers(configuration, uecap); + + // release old BWP + struct NR_ServingCellConfig__downlinkBWP_ToAddModList *dl_BWP_list = configDedicated->downlinkBWP_ToAddModList; + struct NR_UplinkConfig__uplinkBWP_ToAddModList *ul_BWP_list = uplinkConfig->uplinkBWP_ToAddModList; + if (old_bwp > 0) { // we need to remove old BWP only if it is not the initial + AssertFatal(dl_BWP_list, "Source BWP %d should be present in the list\n", old_bwp); + AssertFatal(ul_BWP_list, "Source BWP %d should be present in the list\n", old_bwp); + NR_BWP_Id_t id = dl_BWP_list->list.array[0]->bwp_Id; + if (!configDedicated->downlinkBWP_ToReleaseList) + configDedicated->downlinkBWP_ToReleaseList = calloc_or_fail(1, sizeof(*configDedicated->downlinkBWP_ToReleaseList)); + asn1cSequenceAdd(configDedicated->downlinkBWP_ToReleaseList->list, NR_BWP_Id_t, rel_id); + *rel_id = id; + AssertFatal(configDedicated->downlinkBWP_ToReleaseList->list.count == 1, + "logic error: there shouldn't be more than 1 BWP to release, but downlinkBWP_ToReleaseList has %d\n", + configDedicated->downlinkBWP_ToReleaseList->list.count); + + id = ul_BWP_list->list.array[0]->bwp_Id; + if (!uplinkConfig->uplinkBWP_ToReleaseList) + uplinkConfig->uplinkBWP_ToReleaseList = calloc_or_fail(1, sizeof(*uplinkConfig->uplinkBWP_ToReleaseList)); + asn1cSequenceAdd(uplinkConfig->uplinkBWP_ToReleaseList->list, NR_BWP_Id_t, ul_rel_id); + *ul_rel_id = id; + AssertFatal(uplinkConfig->uplinkBWP_ToReleaseList->list.count == 1, + "logic error: there shouldn't be more than 1 BWP to release, but uplinkBWP_ToReleaseList has %d\n", + uplinkConfig->uplinkBWP_ToReleaseList->list.count); + } + + uint64_t bitmap = get_ssb_bitmap(scc); + const int pdsch_AntennaPorts = + configuration->pdsch_AntennaPorts.N1 * configuration->pdsch_AntennaPorts.N2 * configuration->pdsch_AntennaPorts.XP; + // add new BWP + if (new_bwp == 0) { + if (!configDedicated->initialDownlinkBWP) + configDedicated->initialDownlinkBWP = calloc_or_fail(1, sizeof(*configDedicated->initialDownlinkBWP)); + if (!uplinkConfig->initialUplinkBWP) + uplinkConfig->initialUplinkBWP = calloc_or_fail(1, sizeof(*uplinkConfig->initialUplinkBWP)); + uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, ul_maxMIMO_Layers, uid); + configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, configuration); + } else { + if (!configDedicated->downlinkBWP_ToAddModList) + configDedicated->downlinkBWP_ToAddModList = calloc_or_fail(1, sizeof(*configDedicated->downlinkBWP_ToAddModList)); + NR_BWP_Downlink_t *dl_bwp = config_downlinkBWP(scc, + uecap, + pdsch_AntennaPorts, + configuration->force_256qam_off, + new_bwp - 1, + true, + configuration); + asn1cSeqAdd(&configDedicated->downlinkBWP_ToAddModList->list, dl_bwp); + + if (!uplinkConfig->uplinkBWP_ToAddModList) + uplinkConfig->uplinkBWP_ToAddModList = calloc_or_fail(1, sizeof(*uplinkConfig->uplinkBWP_ToAddModList)); + NR_BWP_Uplink_t *ul_bwp = config_uplinkBWP(new_bwp - 1, true, uid, ul_maxMIMO_Layers, configuration, scc, uecap); + asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ul_bwp); + } + + ASN_STRUCT_FREE(asn_DEF_NR_CSI_MeasConfig, configDedicated->csi_MeasConfig->choice.setup); + configDedicated->csi_MeasConfig->choice.setup = get_csiMeasConfig(configDedicated, + uecap, + scc, + configuration, + uid, + new_bwp, + bitmap); + + // we temporarily need to keep both the old and the new BWP in the CG used by the gNB + // while removing the old from the CG sent to the UE + if (old_bwp > 0) { + NR_CellGroupConfig_t *clone_cg = NULL; + const int copy_result = asn_copy(&asn_DEF_NR_CellGroupConfig, (void **)&clone_cg, cellGroupConfig); + AssertFatal(copy_result == 0, "unable to copy NR_CellGroupConfig for cloning\n"); + clean_bwp_structures(clone_cg->spCellConfig); + return clone_cg; + } + return NULL; +} + +void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, + const int uid, + const NR_UE_NR_Capability_t *uecap, + const nr_mac_config_t *configuration, + const NR_ServingCellConfigCommon_t *scc) +{ + DevAssert(cellGroupConfig != NULL); + DevAssert(cellGroupConfig->spCellConfig != NULL); + DevAssert(cellGroupConfig->spCellConfig->spCellConfigDedicated != NULL); + DevAssert(configuration != NULL); + DevAssert(scc != NULL); + + NR_SpCellConfig_t *SpCellConfig = cellGroupConfig->spCellConfig; + NR_ServingCellConfig_t *spCellConfigDedicated = SpCellConfig->spCellConfigDedicated; + NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig = spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup; + set_dl_maxmimolayers(pdsch_servingcellconfig, scc, uecap, configuration->maxMIMO_layers); + + NR_CSI_MeasConfig_t *csi_MeasConfig = spCellConfigDedicated->csi_MeasConfig->choice.setup; + for (int report = 0; report < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; report++) { + NR_CSI_ReportConfig_t *csirep = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[report]; + if(csirep->codebookConfig) + config_csi_codebook(&configuration->pdsch_AntennaPorts, *pdsch_servingcellconfig->ext1->maxMIMO_Layers, csirep->codebookConfig); + } + + NR_UplinkConfig_t *uplinkConfig = spCellConfigDedicated->uplinkConfig; + long maxMIMO_Layers = set_ul_max_layers(configuration, uecap); + if (!uplinkConfig->pusch_ServingCellConfig) + uplinkConfig->pusch_ServingCellConfig = calloc(1, sizeof(*uplinkConfig->pusch_ServingCellConfig)); + uplinkConfig->pusch_ServingCellConfig->present = NR_SetupRelease_PUSCH_ServingCellConfig_PR_setup; + if (!uplinkConfig->pusch_ServingCellConfig->choice.setup) + uplinkConfig->pusch_ServingCellConfig->choice.setup = calloc(1, sizeof(*uplinkConfig->pusch_ServingCellConfig->choice.setup)); + if (!uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1) + uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 = + calloc(1, sizeof(*uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1)); + asn1cCallocOne(uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers, maxMIMO_Layers); + + // Update UL BWP + NR_BWP_UplinkDedicated_t *ul_bwp_Dedicated = NULL; + int curr_bwp = 0; + int bwp_id = 0; + if (uplinkConfig && uplinkConfig->initialUplinkBWP) { + ul_bwp_Dedicated = uplinkConfig->initialUplinkBWP; + curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + } else if (uplinkConfig && uplinkConfig->uplinkBWP_ToAddModList) { + struct NR_UplinkConfig__uplinkBWP_ToAddModList *UL_BWP_list = uplinkConfig->uplinkBWP_ToAddModList; + AssertFatal(UL_BWP_list->list.count == 1, "We should only have 1 BWP configured at a given time\n"); + NR_BWP_Uplink_t *ul_bwp = UL_BWP_list->list.array[0]; + curr_bwp = NRRIV2BW(ul_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + ul_bwp_Dedicated = ul_bwp->bwp_Dedicated; + bwp_id = ul_bwp->bwp_Id; + } + if (ul_bwp_Dedicated) { + NR_PUSCH_Config_t *pusch_Config = ul_bwp_Dedicated->pusch_Config->choice.setup; + if (!pusch_Config->maxRank) + pusch_Config->maxRank = calloc(1, sizeof(*pusch_Config->maxRank)); + *pusch_Config->maxRank = maxMIMO_Layers; + if (configuration->do_SRS) { + ASN_STRUCT_FREE(asn_DEF_NR_SetupRelease_SRS_Config, ul_bwp_Dedicated->srs_Config); + ul_bwp_Dedicated->srs_Config = get_config_srs(scc, + uecap, + curr_bwp, + uid, + bwp_id, + maxMIMO_Layers, + configuration->minRXTXTIME, + configuration->do_SRS); } - if (!uplinkConfig->pusch_ServingCellConfig) - uplinkConfig->pusch_ServingCellConfig = calloc(1, sizeof(*uplinkConfig->pusch_ServingCellConfig)); - uplinkConfig->pusch_ServingCellConfig->present = NR_SetupRelease_PUSCH_ServingCellConfig_PR_setup; - if (!uplinkConfig->pusch_ServingCellConfig->choice.setup) - uplinkConfig->pusch_ServingCellConfig->choice.setup = calloc(1, sizeof(*uplinkConfig->pusch_ServingCellConfig->choice.setup)); - if (!uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1) - uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 = - calloc(1, sizeof(*uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1)); - asn1cCallocOne(uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers, ul_max_layers); + set_ul_mcs_table(configuration->force_UL256qam_off ? NULL : uecap, scc, pusch_Config); } - long maxMIMO_Layers = uplinkConfig && uplinkConfig->pusch_ServingCellConfig - && uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 - && uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers - ? *uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers - : 1; - - // UL and SRS configuration - if (configuration->do_SRS && uplinkConfig && uplinkConfig->initialUplinkBWP) { - ASN_STRUCT_FREE(asn_DEF_NR_SetupRelease_SRS_Config, uplinkConfig->initialUplinkBWP->srs_Config); - uplinkConfig->initialUplinkBWP->srs_Config = get_config_srs(scc, - uecap, - curr_bwp, - uid, - 0, - maxMIMO_Layers, - configuration->minRXTXTIME, - configuration->do_SRS); + // Update DL BWP + NR_BWP_DownlinkDedicated_t *bwp_Dedicated = NULL; + int scs = -1; + if (spCellConfigDedicated->initialDownlinkBWP) { + bwp_Dedicated = spCellConfigDedicated->initialDownlinkBWP; + scs = scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing; + } else if (spCellConfigDedicated->downlinkBWP_ToAddModList) { + struct NR_ServingCellConfig__downlinkBWP_ToAddModList *DL_BWP_list = spCellConfigDedicated->downlinkBWP_ToAddModList; + AssertFatal(DL_BWP_list->list.count == 1, "We should only have 1 BWP configured at a given time\n"); + NR_BWP_Downlink_t *bwp = DL_BWP_list->list.array[0]; + bwp_Dedicated = bwp->bwp_Dedicated; + scs = bwp->bwp_Common->genericParameters.subcarrierSpacing; } - - // Set DL MCS table - NR_BWP_DownlinkDedicated_t *bwp_Dedicated = SpCellConfig->spCellConfigDedicated->initialDownlinkBWP; - set_dl_mcs_table(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing, - configuration->force_256qam_off ? NULL : uecap, - bwp_Dedicated, - scc); - - NR_BWP_UplinkDedicated_t *ul_bwp_Dedicated = SpCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP; - set_ul_mcs_table(configuration->force_UL256qam_off ? NULL : uecap, scc, ul_bwp_Dedicated->pusch_Config->choice.setup); - - struct NR_ServingCellConfig__downlinkBWP_ToAddModList *DL_BWP_list = - SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList; - struct NR_UplinkConfig__uplinkBWP_ToAddModList *UL_BWP_list = uplinkConfig ? uplinkConfig->uplinkBWP_ToAddModList : NULL; - if (DL_BWP_list) { - for (int i = 0; i < DL_BWP_list->list.count; i++) { - NR_BWP_Downlink_t *bwp = DL_BWP_list->list.array[i]; - int scs = bwp->bwp_Common->genericParameters.subcarrierSpacing; - set_dl_mcs_table(scs, configuration->force_256qam_off ? NULL : uecap, bwp->bwp_Dedicated, scc); - } + if (bwp_Dedicated) { + set_dl_mcs_table(scs, configuration->force_256qam_off ? NULL : uecap, bwp_Dedicated, scc); + update_cqitables(bwp_Dedicated->pdsch_Config, csi_MeasConfig); } - if (UL_BWP_list) { - for (int i = 0; i < UL_BWP_list->list.count; i++) { - NR_BWP_Uplink_t *ul_bwp = UL_BWP_list->list.array[i]; - int bwp_size = NRRIV2BW(ul_bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - if (ul_bwp->bwp_Dedicated->pusch_Config) { - NR_PUSCH_Config_t *pusch_Config = ul_bwp->bwp_Dedicated->pusch_Config->choice.setup; - set_ul_mcs_table(configuration->force_UL256qam_off ? NULL : uecap, scc, pusch_Config); - if (pusch_Config->maxRank == NULL) { - pusch_Config->maxRank = calloc(1, sizeof(*pusch_Config->maxRank)); - } - *pusch_Config->maxRank = ul_max_layers; - } - - ASN_STRUCT_FREE(asn_DEF_NR_SetupRelease_SRS_Config, ul_bwp->bwp_Dedicated->srs_Config); - ul_bwp->bwp_Dedicated->srs_Config = get_config_srs(scc, - uecap, - bwp_size, - uid, - i + 1, - maxMIMO_Layers, - configuration->minRXTXTIME, - configuration->do_SRS); - } - } - update_cqitables(bwp_Dedicated->pdsch_Config, csi_MeasConfig); } void free_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig) @@ -3688,7 +3974,6 @@ static NR_ServingCellConfigCommon_t *clone_ServingCellConfigCommon(const NR_Serv } NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigCommon_t *servingcellconfigcommon, - const NR_ServingCellConfig_t *servingcellconfigdedicated, const NR_UE_NR_Capability_t *uecap, int scg_id, int servCellIndex, @@ -3697,10 +3982,7 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC { const nr_pdsch_AntennaPorts_t *pdschap = &configuration->pdsch_AntennaPorts; const int dl_antenna_ports = pdschap->N1 * pdschap->N2 * pdschap->XP; - const int do_csirs = configuration->do_CSIRS; - AssertFatal(servingcellconfigcommon, "servingcellconfigcommon is null\n"); - AssertFatal(servingcellconfigdedicated, "servingcellconfigdedicated is null\n"); if (uecap == NULL) LOG_E(RRC, "No UE Capabilities available when programming default CellGroup in NSA\n"); @@ -3732,46 +4014,35 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC NR_RLF_TimersAndConstants__ext1__t311_ms30000; secondaryCellGroup->spCellConfig->rlmInSyncOutOfSyncThreshold = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated)); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->tdd_UL_DL_ConfigurationDedicated = NULL; + NR_ServingCellConfig_t *configDedicated = calloc(1, sizeof(*configDedicated)); + configDedicated->tdd_UL_DL_ConfigurationDedicated = NULL; /// initialDownlinkBWP - secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP)); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdcch_Config = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->pdsch_Config = - config_pdsch(bitmap, 0, dl_antenna_ports); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->sps_Config = - NULL; // calloc(1,sizeof(struct NR_SetupRelease_SPS_Config)); + configDedicated->initialDownlinkBWP = calloc(1, sizeof(*configDedicated->initialDownlinkBWP)); + configDedicated->initialDownlinkBWP->pdcch_Config = NULL; + configDedicated->initialDownlinkBWP->pdsch_Config = + config_pdsch(bitmap, 0, dl_antenna_ports, configuration->ptrs); + configDedicated->initialDownlinkBWP->sps_Config = NULL; // calloc(1,sizeof(struct NR_SetupRelease_SPS_Config)); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->initialDownlinkBWP->radioLinkMonitoringConfig = NULL; + configDedicated->initialDownlinkBWP->radioLinkMonitoringConfig = NULL; /// initialUplinkBWP - if (!secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig) { - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig)); + if (!configDedicated->uplinkConfig) { + configDedicated->uplinkConfig = calloc(1, sizeof(*configDedicated->uplinkConfig)); } + NR_UplinkConfig_t *ulConfig = configDedicated->uplinkConfig; NR_BWP_UplinkDedicated_t *initialUplinkBWP = calloc(1, sizeof(*initialUplinkBWP)); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->initialUplinkBWP = initialUplinkBWP; + ulConfig->initialUplinkBWP = initialUplinkBWP; initialUplinkBWP->pucch_Config = NULL; - NR_PUSCH_Config_t *pusch_Config = NULL; - if (servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList) { - pusch_Config = clone_pusch_config( - servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated->pusch_Config->choice.setup); - } - initialUplinkBWP->pusch_Config = config_pusch(pusch_Config, configuration->use_deltaMCS,servingcellconfigcommon, uecap); - - long maxMIMO_Layers = - servingcellconfigdedicated->uplinkConfig && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig - && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1 - && servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers - ? *servingcellconfigdedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup->ext1->maxMIMO_Layers - : 1; + initialUplinkBWP->pusch_Config = config_pusch(configuration->use_deltaMCS, + servingcellconfigcommon, + uecap, + configuration->ptrs); + long maxMIMO_Layers = set_ul_max_layers(configuration, uecap); int curr_bwp = NRRIV2BW(servingcellconfigcommon->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); initialUplinkBWP->srs_Config = get_config_srs(servingcellconfigcommon, @@ -3785,89 +4056,70 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC // Downlink BWPs int n_dl_bwp = 1; - if (servingcellconfigdedicated->downlinkBWP_ToAddModList) { - n_dl_bwp = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count; + int firstActiveDownlinkBWP_Id = 1; + if (configuration->num_additional_bwps > 0) { + n_dl_bwp = configuration->num_additional_bwps; + firstActiveDownlinkBWP_Id = configuration->first_active_bwp; } - if (n_dl_bwp > 0) { - secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList)); - for (int bwp_loop = 0; bwp_loop < n_dl_bwp; bwp_loop++) { - NR_BWP_Downlink_t *bwp = calloc(1, sizeof(*bwp)); - config_downlinkBWP(bwp, - servingcellconfigcommon, - servingcellconfigdedicated, - uecap, - dl_antenna_ports, - configuration->force_256qam_off, - bwp_loop, - false, - configuration->num_agg_level_candidates); - asn1cSeqAdd(&secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list, bwp); - } - secondaryCellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id)); - *secondaryCellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = - servingcellconfigdedicated->firstActiveDownlinkBWP_Id ? *servingcellconfigdedicated->firstActiveDownlinkBWP_Id : 1; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id)); - *secondaryCellGroup->spCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = - servingcellconfigdedicated->defaultDownlinkBWP_Id ? *servingcellconfigdedicated->defaultDownlinkBWP_Id : 1; + configDedicated->downlinkBWP_ToAddModList = calloc(1, sizeof(*configDedicated->downlinkBWP_ToAddModList)); + for (int bwp_loop = 0; bwp_loop < n_dl_bwp; bwp_loop++) { + NR_BWP_Downlink_t *bwp = config_downlinkBWP(servingcellconfigcommon, + uecap, + dl_antenna_ports, + configuration->force_256qam_off, + bwp_loop, + false, + configuration); + asn1cSeqAdd(&configDedicated->downlinkBWP_ToAddModList->list, bwp); + configDedicated->firstActiveDownlinkBWP_Id = calloc(1, sizeof(*configDedicated->firstActiveDownlinkBWP_Id)); + *configDedicated->firstActiveDownlinkBWP_Id = firstActiveDownlinkBWP_Id; + configDedicated->defaultDownlinkBWP_Id = calloc(1, sizeof(*configDedicated->defaultDownlinkBWP_Id)); + *configDedicated->defaultDownlinkBWP_Id = 1; } // Uplink BWPs int n_ul_bwp = 1; - if (servingcellconfigdedicated->uplinkConfig && servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList) { - n_ul_bwp = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; + int firstActiveUplinkBWP_Id = 1; + if (configuration->num_additional_bwps > 0) { + n_ul_bwp = configuration->num_additional_bwps; + firstActiveUplinkBWP_Id = configuration->first_active_bwp; } if (n_ul_bwp > 0) { - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList)); + ulConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*ulConfig->uplinkBWP_ToAddModList)); for (int bwp_loop = 0; bwp_loop < n_ul_bwp; bwp_loop++) { - NR_BWP_Uplink_t *ubwp = calloc(1, sizeof(*ubwp)); - config_uplinkBWP(ubwp, bwp_loop, false, uid, configuration, servingcellconfigdedicated, servingcellconfigcommon, uecap); - asn1cSeqAdd(&secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list, ubwp); + NR_BWP_Uplink_t *ubwp = config_uplinkBWP(bwp_loop, false, uid, maxMIMO_Layers, configuration, servingcellconfigcommon, uecap); + asn1cSeqAdd(&ulConfig->uplinkBWP_ToAddModList->list, ubwp); } - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id)); - *secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = - servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id - ? *servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id - : 1; + ulConfig->firstActiveUplinkBWP_Id = calloc(1, sizeof(*ulConfig->firstActiveUplinkBWP_Id)); + *ulConfig->firstActiveUplinkBWP_Id = firstActiveUplinkBWP_Id; } - secondaryCellGroup->spCellConfig->spCellConfigDedicated->bwp_InactivityTimer = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToReleaseList = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList = NULL; + configDedicated->bwp_InactivityTimer = NULL; + configDedicated->downlinkBWP_ToReleaseList = NULL; + ulConfig->uplinkBWP_ToReleaseList = NULL; - if (!secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig) - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig)); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->present = - NR_SetupRelease_PUSCH_ServingCellConfig_PR_setup; - if (!secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup) - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup = calloc( - 1, - sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup)); - NR_PUSCH_ServingCellConfig_t *pusch_scc = - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->pusch_ServingCellConfig->choice.setup; + if (!ulConfig->pusch_ServingCellConfig) + ulConfig->pusch_ServingCellConfig = calloc(1, sizeof(*ulConfig->pusch_ServingCellConfig)); + ulConfig->pusch_ServingCellConfig->present = NR_SetupRelease_PUSCH_ServingCellConfig_PR_setup; + if (!ulConfig->pusch_ServingCellConfig->choice.setup) + ulConfig->pusch_ServingCellConfig->choice.setup = calloc(1, sizeof(*ulConfig->pusch_ServingCellConfig->choice.setup)); + NR_PUSCH_ServingCellConfig_t *pusch_scc = ulConfig->pusch_ServingCellConfig->choice.setup; pusch_scc->codeBlockGroupTransmission = NULL; pusch_scc->rateMatching = NULL; pusch_scc->xOverhead = NULL; if (!pusch_scc->ext1) pusch_scc->ext1 = calloc(1, sizeof(*pusch_scc->ext1)); - asn1cCallocOne(pusch_scc->ext1->maxMIMO_Layers, 1); + asn1cCallocOne(pusch_scc->ext1->maxMIMO_Layers, maxMIMO_Layers); pusch_scc->ext1->processingType2Enabled = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->carrierSwitching = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->supplementaryUplink = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->pdcch_ServingCellConfig = NULL; + ulConfig->carrierSwitching = NULL; + configDedicated->supplementaryUplink = NULL; + configDedicated->pdcch_ServingCellConfig = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig)); + configDedicated->pdsch_ServingCellConfig = calloc(1, sizeof(*configDedicated->pdsch_ServingCellConfig)); NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig = calloc(1, sizeof(*pdsch_servingcellconfig)); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->present = - NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; + configDedicated->pdsch_ServingCellConfig->present = NR_SetupRelease_PDSCH_ServingCellConfig_PR_setup; + configDedicated->pdsch_ServingCellConfig->choice.setup = pdsch_servingcellconfig; pdsch_servingcellconfig->codeBlockGroupTransmission = NULL; pdsch_servingcellconfig->xOverhead = NULL; asn1cCallocOne(pdsch_servingcellconfig->nrofHARQ_ProcessesForPDSCH, NR_PDSCH_ServingCellConfig__nrofHARQ_ProcessesForPDSCH_n16); @@ -3888,115 +4140,26 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC pdsch_servingcellconfig->ext3->downlinkHARQ_FeedbackDisabled_r17->choice.setup.buf[3] = 0xFF; } - secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig = - calloc(1, sizeof(*secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig)); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; + configDedicated->csi_MeasConfig = NULL; + configDedicated->csi_MeasConfig = calloc(1, sizeof(*configDedicated->csi_MeasConfig)); + configDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; + configDedicated->csi_MeasConfig->choice.setup = get_csiMeasConfig(configDedicated, + uecap, + servingcellconfigcommon, + configuration, + uid, + firstActiveUplinkBWP_Id, + bitmap); - NR_CSI_MeasConfig_t *csi_MeasConfig = calloc(1, sizeof(*csi_MeasConfig)); - secondaryCellGroup->spCellConfig->spCellConfigDedicated->csi_MeasConfig->choice.setup = csi_MeasConfig; + configDedicated->sCellDeactivationTimer = NULL; + configDedicated->crossCarrierSchedulingConfig = NULL; + configDedicated->tag_Id = 0; + configDedicated->dummy1 = NULL; + configDedicated->pathlossReferenceLinking = NULL; + configDedicated->servingCellMO = NULL; - csi_MeasConfig->csi_ResourceConfigToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_ResourceConfigToAddModList)); - csi_MeasConfig->csi_ResourceConfigToReleaseList = NULL; - - csi_MeasConfig->csi_SSB_ResourceSetToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_SSB_ResourceSetToAddModList)); - csi_MeasConfig->csi_SSB_ResourceSetToReleaseList = NULL; - - csi_MeasConfig->csi_ReportConfigToAddModList = calloc(1, sizeof(*csi_MeasConfig->csi_ReportConfigToAddModList)); - csi_MeasConfig->csi_ReportConfigToReleaseList = NULL; - - NR_CSI_SSB_ResourceSet_t *ssbresset0 = calloc(1, sizeof(*ssbresset0)); - ssbresset0->csi_SSB_ResourceSetId = 0; - - for (int i = 0; i < 64; i++) { - if ((bitmap >> (63 - i)) & 0x01) { - NR_SSB_Index_t *ssbres = NULL; - asn1cCallocOne(ssbres, i); - asn1cSeqAdd(&ssbresset0->csi_SSB_ResourceList.list, ssbres); - } - } - asn1cSeqAdd(&csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list, ssbresset0); - - for (int bwp_loop = 0; bwp_loop < n_dl_bwp; bwp_loop++) { - NR_BWP_Downlink_t *bwp = - secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_loop]; - int curr_bwp = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - - config_csirs(servingcellconfigcommon, csi_MeasConfig, dl_antenna_ports, curr_bwp, do_csirs, bwp_loop); - config_csiim(do_csirs, dl_antenna_ports, curr_bwp, csi_MeasConfig, bwp_loop); - - if (do_csirs) { - NR_CSI_ResourceConfig_t *csires = calloc(1, sizeof(*csires)); - csires->csi_ResourceConfigId = bwp->bwp_Id; - csires->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB; - csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = - calloc(1, sizeof(*csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); - csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList = - calloc(1, sizeof(*csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList)); - NR_NZP_CSI_RS_ResourceSetId_t *nzp0 = calloc(1, sizeof(*nzp0)); - *nzp0 = bwp_loop; - asn1cSeqAdd(&csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list, nzp0); - csires->bwp_Id = bwp->bwp_Id; - csires->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, csires); - } - if (do_csirs && dl_antenna_ports > 1) { - NR_CSI_ResourceConfig_t *csiresim = calloc(1, sizeof(*csiresim)); - csiresim->csi_ResourceConfigId = bwp->bwp_Id + 10; - csiresim->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_csi_IM_ResourceSetList; - csiresim->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList = - calloc(1, sizeof(*csiresim->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList)); - NR_CSI_IM_ResourceSetId_t *csiim00 = calloc(1, sizeof(*csiim00)); - *csiim00 = bwp_loop; - asn1cSeqAdd(&csiresim->csi_RS_ResourceSetList.choice.csi_IM_ResourceSetList->list, csiim00); - csiresim->bwp_Id = bwp->bwp_Id; - csiresim->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, csiresim); - } - NR_CSI_ResourceConfig_t *ssbres = calloc(1, sizeof(*ssbres)); - ssbres->csi_ResourceConfigId = bwp->bwp_Id + 20; - ssbres->csi_RS_ResourceSetList.present = NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB; - ssbres->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB = calloc(1, sizeof(*ssbres->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB)); - ssbres->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList = - calloc(1, sizeof(*ssbres->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList)); - NR_CSI_SSB_ResourceSetId_t *ssbres00 = calloc(1, sizeof(*ssbres00)); - *ssbres00 = 0; - asn1cSeqAdd(&ssbres->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list, ssbres00); - ssbres->bwp_Id = bwp->bwp_Id; - ssbres->resourceType = NR_CSI_ResourceConfig__resourceType_periodic; - asn1cSeqAdd(&csi_MeasConfig->csi_ResourceConfigToAddModList->list, ssbres); - - NR_PUCCH_CSI_Resource_t *pucchcsires1 = calloc(1, sizeof(*pucchcsires1)); - pucchcsires1->uplinkBandwidthPartId = bwp->bwp_Id; - pucchcsires1->pucch_Resource = 2; - - config_csi_meas_report(csi_MeasConfig, - servingcellconfigcommon, - pucchcsires1, - bwp->bwp_Dedicated->pdsch_Config, - pdschap, - *pdsch_servingcellconfig->ext1->maxMIMO_Layers, - bwp->bwp_Id, - uid, - curr_bwp); - config_rsrp_meas_report(csi_MeasConfig, - servingcellconfigcommon, - pucchcsires1, - do_csirs, - bwp->bwp_Id + 10, - uid, - curr_bwp, - dl_antenna_ports, - configuration->do_SINR); - } - secondaryCellGroup->spCellConfig->spCellConfigDedicated->sCellDeactivationTimer = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->tag_Id = 0; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->dummy1 = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->pathlossReferenceLinking = NULL; - secondaryCellGroup->spCellConfig->spCellConfigDedicated->servingCellMO = NULL; - - fill_harq_IEs(secondaryCellGroup->spCellConfig->spCellConfigDedicated, configuration->num_dlharq, configuration->num_ulharq); + fill_harq_IEs(configDedicated, configuration->num_dlharq, configuration->num_ulharq, firstActiveDownlinkBWP_Id); + secondaryCellGroup->spCellConfig->spCellConfigDedicated = configDedicated; if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_SpCellConfig, (void *)secondaryCellGroup->spCellConfig); @@ -4004,7 +4167,7 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC return secondaryCellGroup; } -NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc) +NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc, int frame) { NR_ReconfigurationWithSync_t *reconfigurationWithSync = calloc(1, sizeof(*reconfigurationWithSync)); reconfigurationWithSync->newUE_Identity = rnti; @@ -4014,6 +4177,19 @@ NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t u reconfigurationWithSync->spCellConfigCommon = clone_ServingCellConfigCommon(scc); + // in case of ReconfigurationWithSync, the epochTime_r17 must be present if there is a ntn_Config_r17 + if (reconfigurationWithSync->spCellConfigCommon->ext2 && reconfigurationWithSync->spCellConfigCommon->ext2->ntn_Config_r17) { + NR_NTN_Config_r17_t *ntncfg = reconfigurationWithSync->spCellConfigCommon->ext2->ntn_Config_r17; + if (!ntncfg->epochTime_r17) { + ntncfg->epochTime_r17 = calloc(1, sizeof(*ntncfg->epochTime_r17)); + // the epochTime_r17 is esp. relevant for the timer T430, which runs for multiples of 5 seconds. + // here we don't have access to the current subFrame number, so we only set the SFN. + // the error of up to 10 ms should be acceptable for this long running timer. + ntncfg->epochTime_r17->sfn_r17 = frame; + ntncfg->epochTime_r17->subFrameNR_r17 = 0; + } + } + reconfigurationWithSync->rach_ConfigDedicated = calloc(1, sizeof(*reconfigurationWithSync->rach_ConfigDedicated)); reconfigurationWithSync->rach_ConfigDedicated->present = NR_ReconfigurationWithSync__rach_ConfigDedicated_PR_uplink; NR_RACH_ConfigDedicated_t *uplink = calloc(1, sizeof(*uplink)); @@ -4039,3 +4215,171 @@ NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t u return reconfigurationWithSync; } + + +NR_MeasurementTimingConfiguration_t *get_nr_mtc(uint8_t *buf, uint32_t len) +{ + if (buf == NULL || len == 0) + return NULL; + + NR_MeasurementTimingConfiguration_t *mtc = NULL; + asn_dec_rval_t dec_rval = uper_decode(NULL, &asn_DEF_NR_MeasurementTimingConfiguration, (void **)&mtc, buf, len, 0, 0); + if (dec_rval.code != RC_OK) { + LOG_E(NR_MAC, "cannot decode NR MeasurementTimingConfiguration, ignoring\n"); + ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); + return NULL; + } + return mtc; +} + +/** @brief return Measurement Gap Repetition Period from ASN.1 config */ +static int get_mgrp(long mgrp) +{ + switch (mgrp) { + case NR_GapConfig__mgrp_ms20: + return 20; + case NR_GapConfig__mgrp_ms40: + return 40; + case NR_GapConfig__mgrp_ms80: + return 80; + case NR_GapConfig__mgrp_ms160: + return 160; + default: + LOG_E(NR_MAC, "Invalid MGRP %ld\n", mgrp); + return -1; + } +} + +/** @brief Return Measurement Gap Length from ASN.1 config */ +static float get_mgl(long mgl) +{ + switch (mgl) { + case NR_GapConfig__mgl_ms1dot5: + return 1.5; + case NR_GapConfig__mgl_ms3: + return 3.0; + case NR_GapConfig__mgl_ms3dot5: + return 3.5; + case NR_GapConfig__mgl_ms4: + return 4; + case NR_GapConfig__mgl_ms5dot5: + return 5.5; + case NR_GapConfig__mgl_ms6: + return 6; + default: + LOG_E(NR_MAC, "Invalid MGL %ld\n", mgl); + return -1; + } +} + +/** @brief Return Measurement Gap Timing Advance, from ASN.1 config */ +static float get_mgta(long mgta) +{ + switch (mgta) { + case NR_GapConfig__mgta_ms0: + return 0.0; + case NR_GapConfig__mgta_ms0dot25: + return 0.25; + case NR_GapConfig__mgta_ms0dot5: + return 0.5; + default: + LOG_E(NR_MAC, "Invalid MGTA %ld\n", mgta); + return -1; + } +} + +/** @brief Extract gapOffset from SSB MTC periodicity */ +static bool extract_gap_offset_from_smtc(const NR_SSB_MTC_t *ssb_mtc, long *gapOffset) +{ + if (!ssb_mtc) + return false; + + // Extract gapOffset based on periodicity + switch (ssb_mtc->periodicityAndOffset.present) { + case NR_SSB_MTC__periodicityAndOffset_PR_sf20: + *gapOffset = ssb_mtc->periodicityAndOffset.choice.sf20; + break; + case NR_SSB_MTC__periodicityAndOffset_PR_sf40: + *gapOffset = ssb_mtc->periodicityAndOffset.choice.sf40; + break; + case NR_SSB_MTC__periodicityAndOffset_PR_sf80: + *gapOffset = ssb_mtc->periodicityAndOffset.choice.sf80; + break; + case NR_SSB_MTC__periodicityAndOffset_PR_sf160: + *gapOffset = ssb_mtc->periodicityAndOffset.choice.sf160; + break; + default: + LOG_W(NR_RRC, "SMTC periodicity higher than MGRP\n"); + if (ssb_mtc->periodicityAndOffset.present == NR_SSB_MTC__periodicityAndOffset_PR_sf5) { + *gapOffset = ssb_mtc->periodicityAndOffset.choice.sf5; + } else if (ssb_mtc->periodicityAndOffset.present == NR_SSB_MTC__periodicityAndOffset_PR_sf10) { + *gapOffset = ssb_mtc->periodicityAndOffset.choice.sf10; + } + break; + } + + return true; +} + +measgap_config_t create_measgap_config(const NR_MeasurementTimingConfiguration_t *mtc, int scs, int min_rxtxtime) +{ + measgap_config_t mgc = {0}; + const NR_MeasTimingList_t *mtlist = mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; + const NR_MeasTiming_t *mt = mtlist->list.array[0]; + DevAssert(mt != NULL && mt->frequencyAndTiming != NULL); + const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming; + const NR_SSB_MTC_t *ssb_mtc = &ft->ssb_MeasurementTimingConfiguration; + + // Initialize with defaults + long mgrp = DEFAULT_MGRP; + long gapOffset = 0; + long mgta = DEFAULT_MGTA; + long mgl = DEFAULT_MGL; + + // Extract gapOffset from SSB MTC periodicity + if (!extract_gap_offset_from_smtc(ssb_mtc, &gapOffset)) { + return mgc; + } + + mgc.mgrp_ms = get_mgrp(mgrp); + DevAssert(mgc.mgrp_ms != -1); + mgc.mgrp = mgrp; + + mgc.gapOffset = gapOffset; + mgc.mgta = mgta; + mgc.n_slots_mgta = ((int)(10 * get_mgta(mgta)) << scs) / 10; + + // We start the timer K2 slots earlier to avoid scheduling feedback PUCCHs inside measGap + // or depending on the current min_rxtxtime earlier + // TS 38.214 - Table 6.1.2.1.1.2 + const int max_k2 = max(3, min_rxtxtime); + + mgc.n_slots_advance = mgc.n_slots_mgta + max_k2; + + mgc.mgl_ms = get_mgl(mgl); + DevAssert(mgc.mgl_ms != -1); + mgc.mgl = mgl; + mgc.mgl_slots = ((int)(10 * (mgc.mgl_ms + max_k2)) << scs) / 10; + + mgc.enable = true; + + return mgc; +} + +int encode_measgap_config(const measgap_config_t *c, uint8_t *buf) +{ + NR_MeasGapConfig_t *measGapConfig = calloc_or_fail(1, sizeof(*measGapConfig)); + measGapConfig->ext1 = calloc_or_fail(1, sizeof(*measGapConfig->ext1)); + measGapConfig->ext1->gapUE = calloc_or_fail(1, sizeof(*measGapConfig->ext1->gapUE)); + measGapConfig->ext1->gapUE->present = NR_SetupRelease_GapConfig_PR_setup; + NR_GapConfig_t *gap_config = calloc_or_fail(1, sizeof(*gap_config)); + measGapConfig->ext1->gapUE->choice.setup = gap_config; + gap_config->mgta = c->mgta; + gap_config->mgrp = c->mgrp; + gap_config->gapOffset = c->gapOffset; + gap_config->mgl = c->mgl; + asn_enc_rval_t enc_rval_mgc = uper_encode_to_buffer(&asn_DEF_NR_MeasGapConfig, NULL, measGapConfig, buf, 1024); + AssertFatal(enc_rval_mgc.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval_mgc.failed_type->name); + ASN_STRUCT_FREE(asn_DEF_NR_MeasGapConfig, measGapConfig); + return (int)((enc_rval_mgc.encoded + 7) >> 3); +} diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h index cdb4f5b792..89ce03e7f5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h @@ -28,6 +28,8 @@ #include "NR_BCCH-DL-SCH-Message.h" #include "NR_CellGroupConfig.h" #include "NR_UE-NR-Capability.h" +#include "NR_MeasConfig.h" +#include "NR_MeasurementTimingConfiguration.h" #include "NR_UL-CCCH-Message.h" #include "f1ap_messages_types.h" #include "common/platform_types.h" @@ -42,11 +44,14 @@ typedef struct nr_mac_config_t nr_mac_config_t; struct nr_mac_timers; typedef struct nr_mac_timers nr_mac_timers_t; +struct measgap_config; +typedef struct measgap_config measgap_config_t; + void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsch_TimeDomainAllocationList, frame_type_t frame_type, NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_ConfigurationCommon, int curr_bwp); -void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay); +void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay, int do_SRS); NR_SearchSpace_t *rrc_searchspace_config(bool is_common, int searchspaceid, int coresetid, @@ -84,12 +89,11 @@ NR_SIB19_r17_t *get_SIB19_NR(const NR_ServingCellConfigCommon_t *scc); NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, const NR_ServingCellConfigCommon_t *scc, - const NR_ServingCellConfig_t *servingcellconfigdedicated, const nr_mac_config_t *configuration, const nr_rlc_configuration_t *default_rlc_config); void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, const int uid, - NR_UE_NR_Capability_t *uecap, + const NR_UE_NR_Capability_t *uecap, const nr_mac_config_t *configuration, const NR_ServingCellConfigCommon_t *scc); void free_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig); @@ -100,14 +104,13 @@ NR_CellGroupConfig_t *decode_cellGroupConfig(const uint8_t *buffer, int max_buff * configuration, but it will also overwrite the ServingCellConfig passed in * parameter servingcellconfigdedicated! */ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigCommon_t *servingcellconfigcommon, - const NR_ServingCellConfig_t *servingcellconfigdedicated, const NR_UE_NR_Capability_t *uecap, int scg_id, int servCellIndex, const nr_mac_config_t *configuration, int uid); -NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc); +NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc, int frame); NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, @@ -118,5 +121,15 @@ NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, NR_RLC_Config_PR rlc_conf, long priority, const nr_rlc_configuration_t *default_rlc_config); +NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_t *cellGroupConfig, + const nr_mac_config_t *configuration, + const NR_UE_NR_Capability_t *uecap, + const NR_ServingCellConfigCommon_t *scc, + int uid, + int old_bwp, + int new_bwp); +NR_MeasurementTimingConfiguration_t *get_nr_mtc(uint8_t *buf, uint32_t len); +measgap_config_t create_measgap_config(const NR_MeasurementTimingConfiguration_t *mtc, int scs, int min_rxtxtime); +int encode_measgap_config(const measgap_config_t *c, uint8_t *buf); #endif diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index f93044f9cd..884c5f5621 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -231,8 +231,7 @@ bool pdcp_data_req(protocol_ctxt_t *ctxt_pP, hashtable_rc_t h_rc; uint8_t rb_offset= (srb_flagP == 0) ? DTCH -1 : 0; uint16_t pdcp_uid=0; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ,VCD_FUNCTION_IN); - CHECK_CTXT_ARGS(ctxt_pP); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_DATA_REQ, VCD_FUNCTION_IN); #if T_TRACER if (ctxt_pP->enb_flag != ENB_FLAG_NO) @@ -1262,7 +1261,7 @@ pdcp_run ( // IP/NAS -> PDCP traffic : TX, read the pkt from the upper layer buffer // if (LINK_ENB_PDCP_TO_GTPV1U && ctxt_pP->enb_flag == ENB_FLAG_NO) { - if (!get_softmodem_params()->emulate_l1 && (IS_SOFTMODEM_NOS1 || ctxt_pP->enb_flag == ENB_FLAG_NO)) { + if (IS_SOFTMODEM_NOS1 || ctxt_pP->enb_flag == ENB_FLAG_NO) { pdcp_fifo_read_input_sdus(ctxt_pP); } @@ -1272,9 +1271,7 @@ pdcp_run ( } else { start_meas(&UE_pdcp_stats[ctxt_pP->module_id].pdcp_ip); } - if (!get_softmodem_params()->emulate_l1) { - pdcp_fifo_flush_sdus(ctxt_pP); - } + pdcp_fifo_flush_sdus(ctxt_pP); if (ctxt_pP->enb_flag) { stop_meas(&eNB_pdcp_stats[ctxt_pP->module_id].pdcp_ip); diff --git a/openair2/LAYER2/RLC/rlc.h b/openair2/LAYER2/RLC/rlc.h index 9afad74714..4559eb3273 100644 --- a/openair2/LAYER2/RLC/rlc.h +++ b/openair2/LAYER2/RLC/rlc.h @@ -262,22 +262,6 @@ void rlc_data_ind(const protocol_ctxt_t *const, const sdu_size_t, uint8_t *const); -/*! \fn void rlc_data_conf (const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, const mui_t muiP, const rlc_tx_status_t statusP) -* \brief Interface with higher layers, confirm to upper layer the transmission status for a SDU stamped with a MUI, scheduled for transmission. -* \param[in] ctxtP Running context. -* \param[in] srb_flagP Flag to indicate SRB (1) or DRB (0) -* \param[in] rb_idP Radio bearer identifier. -* \param[in] muiP Message Unit identifier. -* \param[in] statusP Status of the transmission (RLC_SDU_CONFIRM_YES, RLC_SDU_CONFIRM_NO). -*/ -void rlc_data_conf( - const protocol_ctxt_t *const, - const srb_flag_t, - const rb_id_t, - const mui_t, - const rlc_tx_status_t ); - - /*! \fn rlc_op_status_t rlc_stat_req ( const protocol_ctxt_t* const ctxtP, const srb_flag_t srb_flagP, diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 99c427cc17..b19ccceb22 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -291,6 +291,32 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) &security_parameters); } + // PDCP Status Information requested + if (to_modif->pdcp_sn_status_requested) { + modified->pdcp_status = malloc_or_fail(sizeof(*modified->pdcp_status)); + nr_pdcp_count_t dl_count = {0}; + nr_pdcp_count_t ul_count = {0}; + nr_pdcp_get_drb_count_values(req->gNB_cu_cp_ue_id, to_modif->id, &ul_count, &dl_count); + modified->pdcp_status->dl_count.hfn = dl_count.hfn; + modified->pdcp_status->dl_count.sn = dl_count.sn; + modified->pdcp_status->ul_count.hfn = ul_count.hfn; + modified->pdcp_status->ul_count.sn = ul_count.sn; + } + + // PDCP Status received (from source CU-UP) + if (to_modif->pdcp_status) { + DevAssert(to_modif->pdcp_config); + DevAssert(to_modif->pdcp_config->pDCP_SN_Size_DL == to_modif->pdcp_config->pDCP_SN_Size_UL); + bool is_sn_len_18 = to_modif->pdcp_config->pDCP_SN_Size_DL == NR_PDCP_Config__drb__pdcp_SN_SizeDL_len18bits; + nr_pdcp_count_t dl_count = { .hfn = to_modif->pdcp_status->dl_count.hfn, .sn = to_modif->pdcp_status->dl_count.sn}; + nr_pdcp_count_t ul_count = { .hfn = to_modif->pdcp_status->ul_count.hfn, .sn = to_modif->pdcp_status->ul_count.sn}; + nr_pdcp_count_update(req->gNB_cu_cp_ue_id, + to_modif->id, + dl_count, + ul_count, + is_sn_len_18 ? LONG_SN_SIZE : SHORT_SN_SIZE); + } + if (f1inst < 0) // no F1-U? continue; // nothing to do @@ -300,6 +326,7 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) in_addr_t addr = to_modif->DlUpParamList[k].tl_info.tlAddress; GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].tl_info.teId); } + } } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index f3402bcf81..25081891d3 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -136,10 +136,10 @@ static void nr_pdcp_entity_recv_pdu(nr_pdcp_entity_t *entity, } if (entity->has_ciphering) - entity->cipher(entity->security_context, - buffer + header_size + sdap_header_size, - size - (header_size + sdap_header_size), - entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); + entity->decipher(entity->security_context, + buffer + header_size + sdap_header_size, + size - (header_size + sdap_header_size), + entity->rb_id, rcvd_count, entity->is_gnb ? 0 : 1); if (entity->has_integrity) { unsigned char integrity[PDCP_INTEGRITY_SIZE] = {0}; @@ -380,10 +380,12 @@ static void nr_pdcp_entity_set_security(struct nr_pdcp_entity_t *entity, if (parameters->ciphering_algorithm == 2) { entity->security_context = nr_pdcp_security_nea2_init(entity->security_keys_and_algos.ciphering_key); entity->cipher = nr_pdcp_security_nea2_cipher; + entity->decipher = nr_pdcp_security_nea2_cipher; entity->free_security = nr_pdcp_security_nea2_free_security; } else if (parameters->ciphering_algorithm == 1) { entity->security_context = nr_pdcp_security_nea1_init(entity->security_keys_and_algos.ciphering_key); entity->cipher = nr_pdcp_security_nea1_cipher; + entity->decipher = nr_pdcp_security_nea1_cipher; entity->free_security = nr_pdcp_security_nea1_free_security; } else { LOG_E(PDCP, "FATAL: only nea1 and nea2 supported for the moment\n"); @@ -599,6 +601,94 @@ static void nr_pdcp_entity_get_stats(nr_pdcp_entity_t *entity, *out = entity->stats; } +/** @note: this function applies to the gNB only */ +static nr_pdcp_count_t nr_pdcp_entity_get_count_dl(nr_pdcp_entity_t *entity) +{ + nr_pdcp_count_t count = {0}; + const int sn_bits = entity->sn_size; + const uint32_t sn_mask = entity->sn_max; + count.hfn = entity->rx_deliv >> sn_bits; + count.sn = entity->rx_deliv & sn_mask; + return count; +} + +/** @note: this function applies to the gNB only */ +static nr_pdcp_count_t nr_pdcp_entity_get_count_ul(nr_pdcp_entity_t *entity) +{ + nr_pdcp_count_t count = {0}; + const int sn_bits = entity->sn_size; + const uint32_t sn_mask = entity->sn_max; + count.hfn = entity->tx_next >> sn_bits; + count.sn = entity->tx_next & sn_mask; + return count; +} + +/** @note: this function applies to the gNB only */ +static void nr_pdcp_entity_set_count_dl(nr_pdcp_entity_t *entity, nr_pdcp_count_t pdcp_count, int sn_size) +{ + // SN length in bits + const uint32_t sn_mask = (1 << sn_size) - 1; + + // Compose COUNT values for tx_next (DL) and rx_next (UL) + uint32_t count = (pdcp_count.hfn << sn_size) | (pdcp_count.sn & sn_mask); + + // Apply the COUNT values + entity->rx_next = count + 1; + entity->rx_deliv = count; + + LOG_I(PDCP, + "DRB %d: Applied PDCP Count\n" + " DL COUNT - SN: %d HFN: %d (COUNT=%u)\n" + " SN length: %s\n" + " PDCP entity state after update:\n" + " rx_next = %u\n" + " rx_deliv = %u\n" + " sn_size = %d\n" + " sn_max = %d\n" + " window = %d\n", + entity->rb_id, + pdcp_count.sn, + pdcp_count.hfn, + count, + sn_size == LONG_SN_SIZE ? "18-bit" : "12-bit", + entity->rx_next, + entity->rx_deliv, + entity->sn_size, + entity->sn_max, + entity->window_size); +} + +/** @note: this function applies to the gNB only */ +static void nr_pdcp_entity_set_count_ul(nr_pdcp_entity_t *entity, nr_pdcp_count_t pdcp_count, int sn_size) +{ + // SN length in bits + const uint32_t sn_mask = (1 << sn_size) - 1; + + // Compose COUNT values for tx_next (DL) and rx_next (UL) + uint32_t count = (pdcp_count.hfn << sn_size) | (pdcp_count.sn & sn_mask); + + // Apply the COUNT values + entity->tx_next = count; + + LOG_I(PDCP, + "DRB %d: Applied PDCP Count\n" + " UL COUNT - SN: %d HFN: %d (COUNT=%u)\n" + " SN length: %s\n" + " PDCP entity state after update:\n" + " tx_next = %u\n" + " sn_size = %d\n" + " sn_max = %d\n" + " window = %d\n", + entity->rb_id, + pdcp_count.sn, + pdcp_count.hfn, + count, + sn_size == LONG_SN_SIZE ? "18-bit" : "12-bit", + entity->tx_next, + entity->sn_size, + entity->sn_max, + entity->window_size); +} nr_pdcp_entity_t *new_nr_pdcp_entity( nr_pdcp_entity_type_t type, @@ -673,5 +763,11 @@ nr_pdcp_entity_t *new_nr_pdcp_entity( nr_pdcp_entity_set_security(ret, security_parameters); + /* PDCP Count API */ + ret->get_pdcp_count_dl = nr_pdcp_entity_get_count_dl; + ret->get_pdcp_count_ul = nr_pdcp_entity_get_count_ul; + ret->set_pdcp_count_dl = nr_pdcp_entity_set_count_dl; + ret->set_pdcp_count_ul = nr_pdcp_entity_set_count_ul; + return ret; } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h index f05ba07b02..84ecce8997 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h @@ -55,6 +55,11 @@ typedef struct { uint8_t ciphering_key[NR_K_KEY_SIZE]; } nr_pdcp_entity_security_keys_and_algos_t; +typedef struct { + uint32_t sn; + uint32_t hfn; +} nr_pdcp_count_t; + typedef struct { //nr_pdcp_entity_type_t mode; /* PDU stats */ @@ -87,7 +92,6 @@ typedef struct { uint8_t mode; /* 0: PDCP AM, 1: PDCP UM, 2: PDCP TM */ } nr_pdcp_statistics_t; - typedef struct nr_pdcp_entity_t { nr_pdcp_entity_type_t type; @@ -156,6 +160,9 @@ typedef struct nr_pdcp_entity_t { void (*cipher)(stream_security_context_t *security_context, unsigned char *buffer, int length, int bearer, uint32_t count, int direction); + void (*decipher)(stream_security_context_t *security_context, + unsigned char *buffer, int length, + int bearer, uint32_t count, int direction); void (*free_security)(stream_security_context_t *security_context); stream_security_context_t *integrity_context; void (*integrity)(stream_security_context_t *integrity_context, @@ -177,6 +184,13 @@ typedef struct nr_pdcp_entity_t { /* Keep tracks of whether the PDCP entity was suspended or not */ bool entity_suspended; + + /* PDCP Count API */ + nr_pdcp_count_t (*get_pdcp_count_dl)(struct nr_pdcp_entity_t *entity); + nr_pdcp_count_t (*get_pdcp_count_ul)(struct nr_pdcp_entity_t *entity); + void (*set_pdcp_count_dl)(struct nr_pdcp_entity_t *entity, nr_pdcp_count_t count, int sn_size); + void (*set_pdcp_count_ul)(struct nr_pdcp_entity_t *entity, nr_pdcp_count_t count, int sn_size); + } nr_pdcp_entity_t; nr_pdcp_entity_t *new_nr_pdcp_entity( diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 4375692e9b..ce885b6b33 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -218,22 +218,6 @@ static void enqueue_rlc_data_req(const protocol_ctxt_t *const ctxt_pP, if (pthread_mutex_unlock(&q.m) != 0) abort(); } -void du_rlc_data_req(const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - confirm_t confirmP, - sdu_size_t sdu_sizeP, - uint8_t *sdu_pP) -{ - enqueue_rlc_data_req(ctxt_pP, - srb_flagP, - rb_idP, muiP, - confirmP, - sdu_sizeP, - sdu_pP); -} - /****************************************************************************/ /* rlc_data_req queue - end */ /****************************************************************************/ @@ -485,7 +469,7 @@ static void deliver_pdu_drb_gnb(void *deliver_pdu_data, ue_id_t ue_id, int rb_id if (NODE_IS_CU(node_type)) { LOG_D(PDCP, "%s() (drb %d) sending message to gtp size %d\n", __func__, rb_id, size); extern instance_t CUuniqInstance; - gtpv1uSendDirect(CUuniqInstance, ue_id, rb_id, (uint8_t *)buf, size, false, false); + gtpv1uSendDirectWithNRUSeqNum(CUuniqInstance, ue_id, rb_id, (uint8_t *)buf, size); } else { uint8_t *memblock = malloc16(size); memcpy(memblock, buf, size); @@ -1088,3 +1072,57 @@ int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len) return num_ues; } + +void nr_pdcp_count_update(ue_id_t ue_id, + rb_id_t drb_id, + nr_pdcp_count_t dl_count, + nr_pdcp_count_t ul_count, + int sn_size) +{ + nr_pdcp_manager_lock(nr_pdcp_ue_manager); + + nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id); + if (ue == NULL) { + LOG_E(PDCP, "UE %ld not found in PDCP manager\n", ue_id); + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return; + } + + nr_pdcp_entity_t *entity = nr_pdcp_get_rb(ue, drb_id, false); + if (entity == NULL) { + LOG_E(PDCP, "No PDCP entity found for UE %ld DRB %ld\n", ue_id, drb_id); + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return; + } + + entity->set_pdcp_count_dl(entity, dl_count, sn_size); + entity->set_pdcp_count_ul(entity, ul_count, sn_size); + + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); +} + +/** * @brief Get PDCP COUNT values (PDCP-SN and HFN) for UL and DL from the PDCP entity + * @param[in] ue_id Unique UE ID + * @param[in] rb_id Radio Bearer ID + * @param[out] ul_count UL PDCP count (SN, HFN) + * @param[out] dl_count DL PDCP count (SN, HFN) + */ +void nr_pdcp_get_drb_count_values(ue_id_t ue_id, rb_id_t rb_id, nr_pdcp_count_t *ul_count, nr_pdcp_count_t *dl_count) +{ + nr_pdcp_manager_lock(nr_pdcp_ue_manager); + + nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id); + + nr_pdcp_entity_t *entity = nr_pdcp_get_rb(ue, rb_id, false); + + if (!entity) { + LOG_E(PDCP, "No entity found (DRB %ld)\n", rb_id); + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); + return; + } + + *dl_count = entity->get_pdcp_count_dl(entity); + *ul_count = entity->get_pdcp_count_ul(entity); + + nr_pdcp_manager_unlock(nr_pdcp_ue_manager); +} diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index a77cc895e6..375bd27458 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -36,14 +36,6 @@ struct NR_SRB_ToAddMod; void nr_pdcp_layer_init(void); -void du_rlc_data_req(const protocol_ctxt_t *const ctxt_pP, - const srb_flag_t srb_flagP, - const rb_id_t rb_idP, - const mui_t muiP, - confirm_t confirmP, - sdu_size_t sdu_sizeP, - uint8_t *sdu_pP); - bool nr_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP, const srb_flag_t srb_flagP, const rb_id_t rb_id, @@ -133,4 +125,12 @@ int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len); bool nr_pdcp_get_statistics(ue_id_t ue_id, int srb_flag, int rb_id, nr_pdcp_statistics_t *out); +void nr_pdcp_count_update(ue_id_t ue_id, + rb_id_t drb_id, + nr_pdcp_count_t dl_count, + nr_pdcp_count_t ul_count, + int sn_size); + +void nr_pdcp_get_drb_count_values(ue_id_t ue_id, rb_id_t rb_id, nr_pdcp_count_t *ul_count, nr_pdcp_count_t *dl_count); + #endif /* NR_PDCP_OAI_API_H */ diff --git a/openair2/LAYER2/nr_rlc/CMakeLists.txt b/openair2/LAYER2/nr_rlc/CMakeLists.txt index d72ac37d09..7473b1d493 100644 --- a/openair2/LAYER2/nr_rlc/CMakeLists.txt +++ b/openair2/LAYER2/nr_rlc/CMakeLists.txt @@ -4,16 +4,17 @@ add_library(nr_rlc_core OBJECT nr_rlc_entity_tm.c nr_rlc_entity_um.c nr_rlc_pdu.c - nr_rlc_sdu.c) + nr_rlc_sdu.c + nr_rlc_rx_manager.c) target_include_directories(nr_rlc_core PRIVATE ../../..) -target_link_libraries(nr_rlc_core PRIVATE ${T_LIB}) +target_link_libraries(nr_rlc_core PRIVATE log_headers) add_library(nr_rlc STATIC asn1_utils.c nr_rlc_oai_api.c nr_rlc_ue_manager.c ) # L2_NR: for PDCP -target_link_libraries(nr_rlc PUBLIC pthread f1ap nr_rlc_core UTIL ${T_LIB}) +target_link_libraries(nr_rlc PUBLIC pthread f1ap nr_rlc_core log_headers) target_include_directories(nr_rlc PRIVATE ../../..) target_link_libraries(nr_rlc PRIVATE asn1_lte_rrc asn1_nr_rrc) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity.c index 6d35460331..e452981357 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.c @@ -125,6 +125,7 @@ nr_rlc_entity_t *new_nr_rlc_entity_am( ret->common.reestablishment = nr_rlc_entity_am_reestablishment; ret->common.delete_entity = nr_rlc_entity_am_delete; ret->common.available_tx_space = nr_rlc_entity_am_available_tx_space; + ret->common.tx_list_occupancy = nr_rlc_entity_am_tx_list_occupancy; ret->common.get_stats = nr_rlc_entity_get_stats; ret->common.deliver_sdu = deliver_sdu; @@ -144,6 +145,8 @@ nr_rlc_entity_t *new_nr_rlc_entity_am( */ ret->common.txsdu_avg_time_to_tx = time_average_new(100 * 1000, 1024); + ret->rx = nr_rlc_new_rx_manager(1 << (sn_field_length - 1)); + return (nr_rlc_entity_t *)ret; } @@ -184,6 +187,7 @@ nr_rlc_entity_t *new_nr_rlc_entity_um( ret->common.reestablishment = nr_rlc_entity_um_reestablishment; ret->common.delete_entity = nr_rlc_entity_um_delete; ret->common.available_tx_space = nr_rlc_entity_um_available_tx_space; + ret->common.tx_list_occupancy = nr_rlc_entity_um_tx_list_occupancy; ret->common.get_stats = nr_rlc_entity_get_stats; ret->common.deliver_sdu = deliver_sdu; @@ -224,6 +228,7 @@ nr_rlc_entity_t *new_nr_rlc_entity_tm( ret->common.reestablishment = nr_rlc_entity_tm_reestablishment; ret->common.delete_entity = nr_rlc_entity_tm_delete; ret->common.available_tx_space = nr_rlc_entity_tm_available_tx_space; + ret->common.tx_list_occupancy = nr_rlc_entity_tm_tx_list_occupancy; ret->common.get_stats = nr_rlc_entity_get_stats; ret->common.deliver_sdu = deliver_sdu; diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h index dc0bf4907c..459e9f59a5 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity.h @@ -116,6 +116,7 @@ typedef struct nr_rlc_entity_t { void (*delete_entity)(struct nr_rlc_entity_t *entity); int (*available_tx_space)(struct nr_rlc_entity_t *entity); + int (*tx_list_occupancy)(struct nr_rlc_entity_t *entity); void (*get_stats)(struct nr_rlc_entity_t *entity, nr_rlc_statistics_t *out); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c index 4d288b48cb..b1f87a7a05 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.c @@ -111,19 +111,17 @@ nr_rlc_sdu_segment_t *nr_rlc_tx_sdu_segment_list_add(nr_rlc_entity_am_t *entity, static int segment_already_received(nr_rlc_entity_am_t *entity, int sn, int so, int size) { - nr_rlc_pdu_t *l = entity->rx_list; + nr_rlc_pdu_t *l = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); int covered; while (l != NULL && size > 0) { - if (l->sn == sn) { - if (l->so <= so && so < l->so + l->size) { - covered = l->size - (so - l->so); - size -= covered; - so += covered; - } else if (l->so <= so+size-1 && so+size-1 < l->so + l->size) { - covered = size - (l->so - so); - size -= covered; - } + if (l->so <= so && so < l->so + l->size) { + covered = l->size - (so - l->so); + size -= covered; + so += covered; + } else if (l->so <= so+size-1 && so+size-1 < l->so + l->size) { + covered = size - (l->so - so); + size -= covered; } l = l->next; } @@ -136,27 +134,20 @@ static int segment_already_received(nr_rlc_entity_am_t *entity, */ static int sdu_full(nr_rlc_entity_am_t *entity, int sn) { - nr_rlc_pdu_t *l = entity->rx_list; - int last_byte; - int new_last_byte; + nr_rlc_pdu_t *l = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); - last_byte = -1; - while (l != NULL) { - if (l->sn == sn) - break; - l = l->next; - } + int last_byte = -1; /* check if the data has already been processed */ if (l != NULL && l->data == NULL) return 0; - while (l != NULL && l->sn == sn) { + while (l != NULL) { if (l->so > last_byte + 1) return 0; if (l->is_last) return 1; - new_last_byte = l->so + l->size - 1; + int new_last_byte = l->so + l->size - 1; if (new_last_byte > last_byte) last_byte = new_last_byte; l = l->next; @@ -168,14 +159,7 @@ static int sdu_full(nr_rlc_entity_am_t *entity, int sn) /* checks that an SDU has already been delivered */ static int sdu_delivered(nr_rlc_entity_am_t *entity, int sn) { - nr_rlc_pdu_t *l = entity->rx_list; - - while (l != NULL) { - if (l->sn == sn) - break; - l = l->next; - } - + nr_rlc_pdu_t *l = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); return l != NULL && l->data == NULL; } @@ -185,22 +169,17 @@ static int sdu_delivered(nr_rlc_entity_am_t *entity, int sn) */ static int sdu_has_missing_bytes(nr_rlc_entity_am_t *entity, int sn) { - nr_rlc_pdu_t *l = entity->rx_list; + nr_rlc_pdu_t *l = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); int last_byte; int new_last_byte; last_byte = -1; - while (l != NULL) { - if (l->sn == sn) - break; - l = l->next; - } /* check if the data has already been processed */ if (l != NULL && l->data == NULL) return 0; /* data already processed: no missing byte */ - while (l != NULL && l->sn == sn) { + while (l != NULL) { if (l->so > last_byte + 1) return 1; new_last_byte = l->so + l->size - 1; @@ -219,13 +198,10 @@ static void reassemble_and_deliver(nr_rlc_entity_am_t *entity, int sn) int so = 0; int bad_sdu = 0; - /* go to first segment of sn */ - pdu = entity->rx_list; - while (pdu->sn != sn) - pdu = pdu->next; + pdu = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); /* reassemble - free 'data' of each segment after processing */ - while (pdu != NULL && pdu->sn == sn) { + while (pdu != NULL) { int len = pdu->size - (so - pdu->so); if (so + len > NR_SDU_MAX && !bad_sdu) { LOG_E(RLC, "%s:%d:%s: bad SDU, too big, discarding\n", @@ -262,7 +238,6 @@ static void reception_actions(nr_rlc_entity_am_t *entity, nr_rlc_pdu_t *pdu) if (sn_compare_rx(entity, x, entity->rx_next_highest) >= 0) entity->rx_next_highest = (x + 1) % entity->sn_modulus; - /* todo: room for optimization: we can run through rx_list only once */ if (sdu_full(entity, x)) { reassemble_and_deliver(entity, x); @@ -275,21 +250,26 @@ static void reception_actions(nr_rlc_entity_am_t *entity, nr_rlc_pdu_t *pdu) if (x == entity->rx_next) { /* update rx_next and free all delivered SDUs at the head of the - * rx_list + * RX list */ int rx_next = entity->rx_next; - while (entity->rx_list != NULL && entity->rx_list->data == NULL && - entity->rx_list->sn == rx_next) { + int count = 0; + nr_rlc_pdu_t *l = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, rx_next); + while (l != NULL && l->data == NULL) { /* free all segments of this SDU */ do { - nr_rlc_pdu_t *p = entity->rx_list; - entity->rx_list = p->next; + nr_rlc_pdu_t *p = l; + l = l->next; free(p); - } while (entity->rx_list != NULL && - entity->rx_list->sn == rx_next); + } while (l != NULL); + nr_rlc_rx_manager_clear_pdu(entity->rx, rx_next); + count++; rx_next = (rx_next + 1) % entity->sn_modulus; + l = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, rx_next); } entity->rx_next = rx_next; + nr_rlc_rx_manager_advance(entity->rx, count); + nr_rlc_rx_manager_set_start(entity->rx, rx_next); } } @@ -833,7 +813,7 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, /* dicard PDU if rx buffer is full */ if (entity->rx_size + data_size > entity->rx_maxsize) { - LOG_D(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n", + LOG_W(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n", __FILE__, __LINE__, __FUNCTION__); goto discard; } @@ -864,8 +844,7 @@ void nr_rlc_entity_am_recv_pdu(nr_rlc_entity_t *_entity, entity->rx_size += data_size; pdu = nr_rlc_new_pdu(sn, so, is_first, is_last, buffer + size - data_size, data_size); - entity->rx_list = nr_rlc_pdu_list_add(sn_compare_rx, entity, - entity->rx_list, pdu); + nr_rlc_rx_manager_add_pdu(entity->rx, pdu); /* do reception actions (38.322 5.2.3.2.3) */ LOG_D(RLC, "RLC received PDU sn %d so %d is_first %d is_last %d data_size = %d \n", sn, so, is_first, is_last, data_size); @@ -1037,6 +1016,55 @@ typedef struct { nr_rlc_pdu_t *next; } missing_data_t; +/* returns the first RX PDU with rx_next <= sn <= rx_highest_status + * returns NULL if none is found + */ +static nr_rlc_pdu_t *get_first_rx_pdu(nr_rlc_entity_am_t *entity) +{ + int first_sn = entity->rx_next; + int last_sn = entity->rx_highest_status; + int sn = first_sn; + + while (sn != last_sn) { + nr_rlc_pdu_t *ret = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); + if (ret) + return ret; + sn = (sn + 1) % entity->sn_modulus; + } + + return nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); +} + +/* find the next RX PDU coming after 'cur' + * two cases: + * - there is a PDU with same SN, return it + * - find PDU with SN <= rx_highest_status if any + * limit search to rx_highest_status + */ +static nr_rlc_pdu_t *get_next_rx_pdu(nr_rlc_entity_am_t *entity, + nr_rlc_pdu_t *cur) +{ + if (cur->next) + return cur->next; + + /* don't process past rx_highest_status */ + if (cur->sn == entity->rx_highest_status) + return NULL; + + int first_sn = (cur->sn + 1) % entity->sn_modulus; + int last_sn = entity->rx_highest_status; + int sn = first_sn; + + while (sn != last_sn) { + nr_rlc_pdu_t *ret = nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); + if (ret) + return ret; + sn = (sn + 1) % entity->sn_modulus; + } + + return nr_rlc_rx_manager_get_pdu_from_sn(entity->rx, sn); +} + /* todo: rewrite this function, too messy */ static missing_data_t next_missing(nr_rlc_entity_am_t *entity, nr_rlc_pdu_t *cur, int check_head) @@ -1076,8 +1104,10 @@ next_pdu: max_so = cur_max_so; last_reached = last_reached | cur->is_last; + nr_rlc_pdu_t *cur_next = get_next_rx_pdu(entity, cur); + /* no next? */ - if (cur->next == NULL) { + if (cur_next == NULL) { /* inform the caller that work is over */ ret.next = NULL; @@ -1118,7 +1148,7 @@ next_pdu: return ret; } - cur = cur->next; + cur = cur_next; /* no discontinuity in data => process to next PDU */ if (cur->sn == sn && max_so >= cur->so - 1) @@ -1374,7 +1404,7 @@ static int generate_status(nr_rlc_entity_am_t *entity, char *buffer, int size) /* first 3 bytes, ack_sn and e1 will be set later */ nr_rlc_pdu_encoder_put_bits(&encoder, 0, 8*3); - cur = entity->rx_list; + cur = get_first_rx_pdu(entity); /* store the position of the e1 bit to be set if * there is a nack following @@ -1538,7 +1568,7 @@ static int status_size(nr_rlc_entity_am_t *entity, int maxsize) /* minimum 3 bytes */ size = 3; - cur = entity->rx_list; + cur = get_first_rx_pdu(entity); while (cur != NULL) { m = next_missing(entity, cur, nack_count == 0); @@ -1811,6 +1841,8 @@ void nr_rlc_entity_am_recv_sdu(nr_rlc_entity_t *_entity, if (entity->tx_size + size > entity->tx_maxsize) { entity->sdu_rejected++; + entity->common.stats.txpdu_dd_pkts++; + entity->common.stats.txpdu_dd_bytes += size; return; } @@ -2020,8 +2052,6 @@ void nr_rlc_entity_am_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id) static void clear_entity(nr_rlc_entity_am_t *entity) { - nr_rlc_pdu_t *cur_rx; - entity->rx_next = 0; entity->rx_next_status_trigger = 0; entity->rx_highest_status = 0; @@ -2045,13 +2075,7 @@ static void clear_entity(nr_rlc_entity_am_t *entity) entity->t_reassembly_start = 0; entity->t_status_prohibit_start = 0; - cur_rx = entity->rx_list; - while (cur_rx != NULL) { - nr_rlc_pdu_t *p = cur_rx; - cur_rx = cur_rx->next; - nr_rlc_free_pdu(p); - } - entity->rx_list = NULL; + nr_rlc_clear_rx_manager(entity->rx); entity->rx_size = 0; nr_rlc_free_sdu_segment_list(entity->tx_list); @@ -2081,6 +2105,7 @@ void nr_rlc_entity_am_delete(nr_rlc_entity_t *_entity) { nr_rlc_entity_am_t *entity = (nr_rlc_entity_am_t *)_entity; clear_entity(entity); + nr_rlc_free_rx_manager(entity->rx); time_average_free(entity->common.txsdu_avg_time_to_tx); free(entity); } @@ -2091,3 +2116,8 @@ int nr_rlc_entity_am_available_tx_space(nr_rlc_entity_t *_entity) return entity->tx_maxsize - entity->tx_size; } +int nr_rlc_entity_am_tx_list_occupancy(nr_rlc_entity_t *_entity) +{ + nr_rlc_entity_am_t *entity = (nr_rlc_entity_am_t *)_entity; + return entity->tx_size; +} diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h index 4c626c4826..3ffcab6176 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h @@ -25,6 +25,7 @@ #include "nr_rlc_entity.h" #include "nr_rlc_sdu.h" #include "nr_rlc_pdu.h" +#include "nr_rlc_rx_manager.h" typedef struct { nr_rlc_entity_t common; @@ -70,9 +71,9 @@ typedef struct { uint64_t t_status_prohibit_start; /* rx management */ - nr_rlc_pdu_t *rx_list; - int rx_size; - int rx_maxsize; + nr_rlc_rx_manager_t *rx; + int rx_size; + int rx_maxsize; /* tx management */ nr_rlc_sdu_segment_t *tx_list; @@ -100,5 +101,6 @@ void nr_rlc_entity_am_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id); void nr_rlc_entity_am_reestablishment(nr_rlc_entity_t *_entity); void nr_rlc_entity_am_delete(nr_rlc_entity_t *entity); int nr_rlc_entity_am_available_tx_space(nr_rlc_entity_t *entity); +int nr_rlc_entity_am_tx_list_occupancy(nr_rlc_entity_t *_entity); #endif /* _NR_RLC_ENTITY_AM_H_ */ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c index 7b541c02ff..be20d574c1 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.c @@ -221,3 +221,9 @@ int nr_rlc_entity_tm_available_tx_space(nr_rlc_entity_t *_entity) nr_rlc_entity_tm_t *entity = (nr_rlc_entity_tm_t *)_entity; return entity->tx_maxsize - entity->tx_size; } + +int nr_rlc_entity_tm_tx_list_occupancy(nr_rlc_entity_t *_entity) +{ + nr_rlc_entity_tm_t *entity = (nr_rlc_entity_tm_t *)_entity; + return entity->tx_size; +} diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h index 716b35d14d..2792017c34 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_tm.h @@ -56,5 +56,6 @@ void nr_rlc_entity_tm_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id); void nr_rlc_entity_tm_reestablishment(nr_rlc_entity_t *_entity); void nr_rlc_entity_tm_delete(nr_rlc_entity_t *entity); int nr_rlc_entity_tm_available_tx_space(nr_rlc_entity_t *entity); +int nr_rlc_entity_tm_tx_list_occupancy(nr_rlc_entity_t *_entity); #endif /* _NR_RLC_ENTITY_TM_H_ */ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c index 75e407328b..4edee0ddab 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.c @@ -765,3 +765,9 @@ int nr_rlc_entity_um_available_tx_space(nr_rlc_entity_t *_entity) nr_rlc_entity_um_t *entity = (nr_rlc_entity_um_t *)_entity; return entity->tx_maxsize - entity->tx_size; } + +int nr_rlc_entity_um_tx_list_occupancy(nr_rlc_entity_t *_entity) +{ + nr_rlc_entity_um_t *entity = (nr_rlc_entity_um_t *)_entity; + return entity->tx_size; +} diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h index 6395bfd47e..c32c5aaedf 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_entity_um.h @@ -80,5 +80,6 @@ void nr_rlc_entity_um_discard_sdu(nr_rlc_entity_t *_entity, int sdu_id); void nr_rlc_entity_um_reestablishment(nr_rlc_entity_t *_entity); void nr_rlc_entity_um_delete(nr_rlc_entity_t *entity); int nr_rlc_entity_um_available_tx_space(nr_rlc_entity_t *entity); +int nr_rlc_entity_um_tx_list_occupancy(nr_rlc_entity_t *_entity); #endif /* _NR_RLC_ENTITY_UM_H_ */ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 8dfa57f92b..e187541fd5 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -77,10 +77,10 @@ static uint64_t get_nr_rlc_current_time(void) static void release_rlc_entity_from_lcid(nr_rlc_ue_t *ue, logical_chan_id_t channel_id) { AssertFatal(channel_id != 0, "LCID = 0 shouldn't be handled here\n"); - nr_rlc_rb_t *rb = &ue->lcid2rb[channel_id - 1]; - if (rb->type == NR_RLC_NONE) + nr_lcid_rb_t *rb = &ue->lcid2rb[channel_id - 1]; + if (rb->type == NR_LCID_NONE) return; - if (rb->type == NR_RLC_SRB) { + if (rb->type == NR_LCID_SRB) { int id = rb->choice.srb_id - 1; AssertFatal(id >= 0, "logic bug: impossible to have srb0 here\n"); if (ue->srb[id]) { @@ -91,7 +91,7 @@ static void release_rlc_entity_from_lcid(nr_rlc_ue_t *ue, logical_chan_id_t chan LOG_E(RLC, "Trying to release a non-established enity with LCID %d\n", channel_id); } else { - AssertFatal(rb->type == NR_RLC_DRB, + AssertFatal(rb->type == NR_LCID_DRB, "Invalid RB type\n"); int id = rb->choice.drb_id - 1; if (ue->drb[id]) { @@ -108,14 +108,14 @@ logical_chan_id_t nr_rlc_get_lcid_from_rb(int ue_id, bool is_srb, int rb_id) nr_rlc_manager_lock(nr_rlc_ue_manager); nr_rlc_ue_t *ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ue_id); for (logical_chan_id_t id = 1; id <= 32; id++) { - nr_rlc_rb_t *rb = &ue->lcid2rb[id - 1]; + nr_lcid_rb_t *rb = &ue->lcid2rb[id - 1]; if (is_srb) { - if (rb->type == NR_RLC_SRB && rb->choice.srb_id == rb_id) { + if (rb->type == NR_LCID_SRB && rb->choice.srb_id == rb_id) { nr_rlc_manager_unlock(nr_rlc_ue_manager); return id; } } else { - if (rb->type == NR_RLC_DRB && rb->choice.drb_id == rb_id) { + if (rb->type == NR_LCID_DRB && rb->choice.drb_id == rb_id) { nr_rlc_manager_unlock(nr_rlc_ue_manager); return id; } @@ -130,14 +130,14 @@ static nr_rlc_entity_t *get_rlc_entity_from_lcid(nr_rlc_ue_t *ue, logical_chan_i { if (channel_id == 0) return ue->srb0; - nr_rlc_rb_t *rb = &ue->lcid2rb[channel_id - 1]; - if (rb->type == NR_RLC_NONE) + nr_lcid_rb_t *rb = &ue->lcid2rb[channel_id - 1]; + if (rb->type == NR_LCID_NONE) return NULL; - if (rb->type == NR_RLC_SRB) { + if (rb->type == NR_LCID_SRB) { AssertFatal(rb->choice.srb_id > 0, "logic bug: impossible to have srb0 here\n"); return ue->srb[rb->choice.srb_id - 1]; } else { - AssertFatal(rb->type == NR_RLC_DRB, + AssertFatal(rb->type == NR_LCID_DRB, "Invalid RB type\n"); return ue->drb[rb->choice.drb_id - 1]; } @@ -320,6 +320,25 @@ int nr_rlc_get_available_tx_space(const int ue_id, const logical_chan_id_t chann return ret; } +int nr_rlc_tx_list_occupancy(int ue_id, logical_chan_id_t lcid) +{ + int ret; + + nr_rlc_manager_lock(nr_rlc_ue_manager); + nr_rlc_ue_t *ue = nr_rlc_manager_get_ue(nr_rlc_ue_manager, ue_id); + nr_rlc_entity_t *rb = get_rlc_entity_from_lcid(ue, lcid); + + if (rb != NULL) { + ret = rb->tx_list_occupancy(rb); + } else { + ret = 0; + } + + nr_rlc_manager_unlock(nr_rlc_ue_manager); + + return ret; +} + int nr_rlc_module_init(nr_rlc_op_mode_t mode) { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; @@ -698,7 +717,7 @@ void nr_rlc_add_srb(int ue_id, int srb_id, const NR_RLC_BearerConfig_t *rlc_Bear NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity), "servedRadioBearer for SRB mandatory present when setting up an SRB RLC entity\n"); int local_id = rlc_BearerConfig->logicalChannelIdentity - 1; // LCID 0 for SRB 0 not mapped - ue->lcid2rb[local_id].type = NR_RLC_SRB; + ue->lcid2rb[local_id].type = NR_LCID_SRB; ue->lcid2rb[local_id].choice.srb_id = rlc_BearerConfig->servedRadioBearer->choice.srb_Identity; if (ue->srb[srb_id-1] != NULL) { LOG_E(RLC, "SRB %d already exists for UE %d, do nothing\n", srb_id, ue_id); @@ -763,7 +782,7 @@ static void add_drb_am(int ue_id, int drb_id, const NR_RLC_BearerConfig_t *rlc_B NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity), "servedRadioBearer for DRB mandatory present when setting up an SRB RLC entity\n"); int local_id = rlc_BearerConfig->logicalChannelIdentity - 1; // LCID 0 for SRB 0 not mapped - ue->lcid2rb[local_id].type = NR_RLC_DRB; + ue->lcid2rb[local_id].type = NR_LCID_DRB; ue->lcid2rb[local_id].choice.drb_id = rlc_BearerConfig->servedRadioBearer->choice.drb_Identity; if (ue->drb[drb_id-1] != NULL) { LOG_E(RLC, "DRB %d already exists for UE %d, do nothing\n", drb_id, ue_id); @@ -818,7 +837,7 @@ static void add_drb_um(int ue_id, int drb_id, const NR_RLC_BearerConfig_t *rlc_B NR_RLC_BearerConfig__servedRadioBearer_PR_drb_Identity), "servedRadioBearer for DRB mandatory present when setting up an SRB RLC entity\n"); int local_id = rlc_BearerConfig->logicalChannelIdentity - 1; // LCID 0 for SRB 0 not mapped - ue->lcid2rb[local_id].type = NR_RLC_DRB; + ue->lcid2rb[local_id].type = NR_LCID_DRB; ue->lcid2rb[local_id].choice.drb_id = rlc_BearerConfig->servedRadioBearer->choice.drb_Identity; if (ue->drb[drb_id-1] != NULL) { LOG_E(RLC, "DEBUG add_drb_um: warning DRB %d already exist for ue %d, do nothing\n", drb_id, ue_id); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h index fec65796d9..454a59b928 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h @@ -80,6 +80,8 @@ void nr_rlc_reconfigure_entity(int ue_id, int lc_id, NR_RLC_Config_t *rlc_Config int nr_rlc_get_available_tx_space(const int ue_id, const logical_chan_id_t channel_idP); +int nr_rlc_tx_list_occupancy(int ue_id, logical_chan_id_t lcid); + void nr_rlc_activate_avg_time_to_tx(const int ue_id, const logical_chan_id_t channel_id, const bool is_on); void nr_rlc_srb_recv_sdu(const int ue_id, const logical_chan_id_t channel_id, unsigned char *buf, int size); diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_rx_manager.c b/openair2/LAYER2/nr_rlc/nr_rlc_rx_manager.c new file mode 100644 index 0000000000..eccf74a208 --- /dev/null +++ b/openair2/LAYER2/nr_rlc/nr_rlc_rx_manager.c @@ -0,0 +1,114 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "nr_rlc_rx_manager.h" + +#include "common/utils/utils.h" + +nr_rlc_rx_manager_t *nr_rlc_new_rx_manager(int size) +{ + nr_rlc_rx_manager_t *ret = calloc_or_fail(1, sizeof(*ret)); + + ret->rx_list = calloc_or_fail(size, sizeof(*ret->rx_list)); + ret->size = size; + + return ret; +} + +void nr_rlc_clear_rx_manager(nr_rlc_rx_manager_t *m) +{ + for (int i = 0; i < m->size; i++) { + nr_rlc_pdu_t *cur = m->rx_list[i]; + while (cur) { + nr_rlc_pdu_t *f = cur; + cur = cur->next; + nr_rlc_free_pdu(f); + } + m->rx_list[i] = 0; + } + m->start = 0; + m->sn_start = 0; +} + +void nr_rlc_free_rx_manager(nr_rlc_rx_manager_t *m) +{ + nr_rlc_clear_rx_manager(m); + free(m->rx_list); + free(m); +} + +static inline int get_pos(nr_rlc_rx_manager_t *m, int sn) +{ + return (m->start + (sn - m->sn_start + m->size * 2)) % m->size; +} + +nr_rlc_pdu_t *nr_rlc_rx_manager_get_pdu_from_sn(nr_rlc_rx_manager_t *m, int sn) +{ + int pos = get_pos(m, sn); + return m->rx_list[pos]; +} + +void nr_rlc_rx_manager_clear_pdu(nr_rlc_rx_manager_t *m, int sn) +{ + int pos = get_pos(m, sn); + m->rx_list[pos] = 0; +} + +/* beware: after calling this function 'sn_start' is invalid, caller has + * to call nr_rlc_rx_manager_set_start() just after + */ +void nr_rlc_rx_manager_advance(nr_rlc_rx_manager_t *m, int count) +{ + m->start += count; + m->start %= m->size; +} + +void nr_rlc_rx_manager_set_start(nr_rlc_rx_manager_t *m, int sn_start) +{ + m->sn_start = sn_start; +} + +void nr_rlc_rx_manager_add_pdu(nr_rlc_rx_manager_t *m, nr_rlc_pdu_t *pdu) +{ + int pos = get_pos(m, pdu->sn); + + nr_rlc_pdu_t head; + nr_rlc_pdu_t *cur; + nr_rlc_pdu_t *prev; + + head.next = m->rx_list[pos]; + cur = m->rx_list[pos]; + prev = &head; + + /* order by 'so' */ + while (cur != NULL) { + /* check if 'pdu' is before 'cur' in the list */ + if (cur->so > pdu->so) { + break; + } + prev = cur; + cur = cur->next; + } + prev->next = pdu; + pdu->next = cur; + + m->rx_list[pos] = head.next; +} diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_rx_manager.h b/openair2/LAYER2/nr_rlc/nr_rlc_rx_manager.h new file mode 100644 index 0000000000..7de6984ce7 --- /dev/null +++ b/openair2/LAYER2/nr_rlc/nr_rlc_rx_manager.h @@ -0,0 +1,49 @@ +/* + * 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_RLC_RX_MANAGER_H_ +#define _NR_RLC_RX_MANAGER_H_ + +#include "nr_rlc_pdu.h" + +typedef struct { + /* 'rx_list' is managed as a circular buffer + * starts at rx_list[start] where is stored 'sn_start' + * for an RLC entity with an SN of n bits, its size is 2^(n-1) + * corresponding the the window size + */ + nr_rlc_pdu_t **rx_list; + int size; + int start; + int sn_start; +} nr_rlc_rx_manager_t; + +nr_rlc_rx_manager_t *nr_rlc_new_rx_manager(int size); +void nr_rlc_free_rx_manager(nr_rlc_rx_manager_t *m); +void nr_rlc_clear_rx_manager(nr_rlc_rx_manager_t *m); + +nr_rlc_pdu_t *nr_rlc_rx_manager_get_pdu_from_sn(nr_rlc_rx_manager_t *m, int sn); +void nr_rlc_rx_manager_clear_pdu(nr_rlc_rx_manager_t *m, int sn); +void nr_rlc_rx_manager_advance(nr_rlc_rx_manager_t *m, int count); +void nr_rlc_rx_manager_set_start(nr_rlc_rx_manager_t *m, int sn_start); +void nr_rlc_rx_manager_add_pdu(nr_rlc_rx_manager_t *m, nr_rlc_pdu_t *pdu); + +#endif /* _NR_RLC_RX_MANAGER_H_ */ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_sdu.c b/openair2/LAYER2/nr_rlc/nr_rlc_sdu.c index 60f50d0afd..d9e15b98c9 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_sdu.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_sdu.c @@ -25,6 +25,7 @@ #include #include "LOG/log.h" +#include "common/utils/assertions.h" nr_rlc_sdu_segment_t *nr_rlc_new_sdu( char *buffer, int size, diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.h b/openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.h index 3dec237958..67484e7108 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.h @@ -28,22 +28,12 @@ typedef void nr_rlc_ue_manager_t; -typedef enum nr_rlc_rb_type { NR_RLC_NONE = 0, NR_RLC_SRB = 1, NR_RLC_DRB = 2 } nr_rlc_rb_type; - typedef enum { NR_RLC_OP_MODE_SPLIT_GNB, NR_RLC_OP_MODE_MONO_GNB, NR_RLC_OP_MODE_UE, } nr_rlc_op_mode_t; -typedef struct nr_rlc_rb_t { - nr_rlc_rb_type type; - union { - int srb_id; - int drb_id; - } choice; -} nr_rlc_rb_t; - typedef void (*rlf_handler_t)(int rnti); typedef struct nr_rlc_ue_t { @@ -51,7 +41,7 @@ typedef struct nr_rlc_ue_t { nr_rlc_entity_t *srb0; nr_rlc_entity_t *srb[3]; nr_rlc_entity_t *drb[MAX_DRBS_PER_UE]; - nr_rlc_rb_t lcid2rb[32]; + nr_lcid_rb_t lcid2rb[32]; rlf_handler_t rlf_handler; } nr_rlc_ue_t; diff --git a/openair2/LAYER2/nr_rlc/tests/CMakeLists.txt b/openair2/LAYER2/nr_rlc/tests/CMakeLists.txt index c8d365ddf9..68d001ab94 100644 --- a/openair2/LAYER2/nr_rlc/tests/CMakeLists.txt +++ b/openair2/LAYER2/nr_rlc/tests/CMakeLists.txt @@ -1,7 +1,7 @@ foreach(TESTNUM RANGE 1 17) add_executable(nr_rlc_test_${TESTNUM} test.c) - target_link_libraries(nr_rlc_test_${TESTNUM} PRIVATE nr_rlc_core pthread UTIL ${T_LIB} minimal_lib) + target_link_libraries(nr_rlc_test_${TESTNUM} PRIVATE nr_rlc_core pthread utils minimal_lib) target_compile_definitions(nr_rlc_test_${TESTNUM} PRIVATE TEST="test${TESTNUM}.h") #target_include_directories(nr_rlc_test_${TESTNUM} PRIVATE LOG) #target_compile_options(nr_rlc_test_${TESTNUM} PRIVATE -g --coverage -Wall) diff --git a/openair2/LAYER2/nr_rlc/tests/Makefile b/openair2/LAYER2/nr_rlc/tests/Makefile index 1e9cd432bf..2673d0955d 100644 --- a/openair2/LAYER2/nr_rlc/tests/Makefile +++ b/openair2/LAYER2/nr_rlc/tests/Makefile @@ -2,7 +2,7 @@ CC=gcc CFLAGS=-Wall -g --coverage -I. -I../../../.. -D_STANDALONE_TESTING_ LIB=nr_rlc_entity.o nr_rlc_entity_am.o nr_rlc_entity_um.o nr_rlc_entity_tm.o \ - nr_rlc_pdu.o nr_rlc_sdu.o time_stat.o + nr_rlc_pdu.o nr_rlc_sdu.o nr_rlc_rx_manager.o time_stat.o tests: @./run_tests.sh diff --git a/openair2/M2AP/m2ap_common.c b/openair2/M2AP/m2ap_common.c index aa090d124d..d9183df6fb 100644 --- a/openair2/M2AP/m2ap_common.c +++ b/openair2/M2AP/m2ap_common.c @@ -47,7 +47,7 @@ ssize_t m2ap_generate_initiating_message( pdu.choice.initiatingMessage.criticality = criticality; ANY_fromType_aper((ANY_t *)&pdu.choice.initiatingMessage.value, td, sptr); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)&pdu); } @@ -80,7 +80,7 @@ ssize_t m2ap_generate_unsuccessfull_outcome( pdu.choice.successfulOutcome.criticality = criticality; ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)&pdu); } diff --git a/openair2/M2AP/m2ap_common.h b/openair2/M2AP/m2ap_common.h index 266b303518..a875d8d078 100644 --- a/openair2/M2AP/m2ap_common.h +++ b/openair2/M2AP/m2ap_common.h @@ -50,8 +50,6 @@ # define M2AP_PORT 36423 #endif -extern int asn1_xer_print; - #include "common/utils/LOG/log.h" #include "m2ap_default_values.h" #define M2AP_INFO(x, args...) LOG_I(M2AP, x, ##args) diff --git a/openair2/M2AP/m2ap_decoder.c b/openair2/M2AP/m2ap_decoder.c index 1237c4ec8e..4abd43f564 100644 --- a/openair2/M2AP/m2ap_decoder.c +++ b/openair2/M2AP/m2ap_decoder.c @@ -165,7 +165,7 @@ int m2ap_decode_pdu(M2AP_M2AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length, 0, 0); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, pdu); } diff --git a/openair2/M2AP/m2ap_encoder.c b/openair2/M2AP/m2ap_encoder.c index 8f798ff55c..81a3bfce92 100644 --- a/openair2/M2AP/m2ap_encoder.c +++ b/openair2/M2AP/m2ap_encoder.c @@ -44,7 +44,7 @@ int m2ap_encode_pdu(M2AP_M2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) DevAssert(buffer != NULL); DevAssert(len != NULL); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_M2AP_M2AP_PDU, (void *)pdu); } diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h index ce6acffc2c..52a0f28871 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.h @@ -138,8 +138,6 @@ void NR_IF_Module_kill(int Mod_id); void NR_UL_indication(NR_UL_IND_t *UL_INFO); -void RCconfig_nr_ue_macrlc(void); - /*Interface for Downlink, transmitting the DLSCH SDU, DCI SDU*/ void NR_Schedule_Response(NR_Sched_Rsp_t *Sched_INFO); diff --git a/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c b/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c deleted file mode 100644 index 5d2cf18974..0000000000 --- a/openair2/NR_PHY_INTERFACE/nfapi_5g_test.c +++ /dev/null @@ -1,21 +0,0 @@ - - -//openair2/NR_PHY_INTERFACE/nfapi_5g_test.c -#include "nfapi_nr_interface_scf.h" - -#include // for printf - -int main ( int argc, char** argv) -{ - nfapi_nr_cell_param_t nfapi_nr_cell_param_test; - nfapi_nr_param_tlv_t tlvs_to_report_list; - - nfapi_nr_cell_param_test.config_tlvs_to_report_list = &tlvs_to_report_list; - nfapi_nr_cell_param_test.phy_state = 0; - nfapi_nr_cell_param_test.release_capability = 0; - nfapi_nr_cell_param_test.skip_blank_dl_config = 0; - nfapi_nr_cell_param_test.skip_blank_ul_config = 0; - - printf(" test nfapi \n"); - return 0; -} diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index 0d0829181e..23cd60b25f 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -30,41 +30,16 @@ * \warning */ -#include -#include -#include - #include "PHY/defs_nr_UE.h" #include "NR_IF_Module.h" #include "NR_MAC_UE/mac_proto.h" #include "assertions.h" #include "SCHED_NR_UE/fapi_nr_ue_l1.h" -#include "executables/softmodem-common.h" #include "openair2/RRC/NR_UE/L2_interface_ue.h" -#include "openair2/GNB_APP/L1_nr_paramdef.h" -#include "openair2/GNB_APP/gnb_paramdef.h" -#include "radio/ETHERNET/if_defs.h" -#include -#include "openair2/GNB_APP/MACRLC_nr_paramdef.h" #define MAX_IF_MODULES 100 -UL_IND_t *UL_INFO = NULL; - -static eth_params_t stub_eth_params; static nr_ue_if_module_t *nr_ue_if_module_inst[MAX_IF_MODULES]; -static int ue_tx_sock_descriptor = -1; -static int ue_rx_sock_descriptor = -1; -static int g_harq_pid; -sem_t sfn_slot_semaphore; - -queue_t nr_sfn_slot_queue; -queue_t nr_chan_param_queue; -queue_t nr_dl_tti_req_queue; -queue_t nr_tx_req_queue; -queue_t nr_ul_dci_req_queue; -queue_t nr_ul_tti_req_queue; -static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request); void print_ue_mac_stats(const module_id_t mod, const int frame_rx, const int slot_rx) { @@ -90,7 +65,14 @@ void print_ue_mac_stats(const module_id_t mod, const int frame_rx, const int slo if (nbdl < 1) nbdl = 1; - cur += snprintf(cur, end - cur, "UE %d stats sfn: %d.%d, cumulated bad DCI %d\n", mod, frame_rx, slot_rx, mac->stats.bad_dci); + cur += snprintf(cur, + end - cur, + "UE %d RNTI %04x stats sfn: %d.%d, cumulated bad DCI %d\n", + mod, + mac->crnti, + frame_rx, + slot_rx, + mac->stats.bad_dci); cur += snprintf(cur, end - cur, " DL harq: %lu", mac->stats.dl.rounds[0]); int nb; @@ -119,961 +101,6 @@ void print_ue_mac_stats(const module_id_t mod, const int frame_rx, const int slo AssertFatal(!ret, "mutex failed %d\n", ret); } -void nrue_init_standalone_socket(int tx_port, int rx_port) -{ - { - struct sockaddr_in server_address; - int addr_len = sizeof(server_address); - memset(&server_address, 0, addr_len); - server_address.sin_family = AF_INET; - server_address.sin_port = htons(tx_port); - - int sd = socket(server_address.sin_family, SOCK_DGRAM, 0); - if (sd < 0) - { - LOG_E(NR_MAC, "Socket creation error standalone PNF\n"); - return; - } - - if (inet_pton(server_address.sin_family, stub_eth_params.remote_addr, &server_address.sin_addr) <= 0) - { - LOG_E(NR_MAC, "Invalid standalone PNF Address\n"); - close(sd); - return; - } - - // Using connect to use send() instead of sendto() - if (connect(sd, (struct sockaddr *)&server_address, addr_len) < 0) - { - LOG_E(NR_MAC, "Connection to standalone PNF failed: %s\n", strerror(errno)); - close(sd); - return; - } - assert(ue_tx_sock_descriptor == -1); - ue_tx_sock_descriptor = sd; - LOG_T(NR_RRC, "Successfully set up tx_socket in %s.\n", __FUNCTION__); - } - - { - struct sockaddr_in server_address; - int addr_len = sizeof(server_address); - memset(&server_address, 0, addr_len); - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = INADDR_ANY; - server_address.sin_port = htons(rx_port); - - int sd = socket(server_address.sin_family, SOCK_DGRAM, 0); - if (sd < 0) - { - LOG_E(MAC, "Socket creation error standalone PNF\n"); - return; - } - - if (bind(sd, (struct sockaddr *)&server_address, addr_len) < 0) - { - LOG_E(NR_MAC, "Connection to standalone PNF failed: %s\n", strerror(errno)); - close(sd); - return; - } - assert(ue_rx_sock_descriptor == -1); - ue_rx_sock_descriptor = sd; - LOG_T(NR_RRC, "Successfully set up rx_socket in %s.\n", __FUNCTION__); - } - LOG_D(NR_RRC, "NRUE standalone socket info: tx_port %d rx_port %d on %s.\n", - tx_port, rx_port, stub_eth_params.remote_addr); -} - -void send_nsa_standalone_msg(NR_UL_IND_t *UL_INFO, uint16_t msg_id) -{ - switch(msg_id) - { - case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: - { - char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; - LOG_T(NR_MAC, "RACH header id :%d\n", UL_INFO->rach_ind.header.message_id); - int encoded_size = nfapi_nr_p7_message_pack(&UL_INFO->rach_ind, buffer, sizeof(buffer), NULL); - if (encoded_size <= 0) - { - LOG_E(NR_MAC, "nfapi_nr_p7_message_pack has failed. Encoded size = %d\n", encoded_size); - return; - } - - LOG_D(NR_MAC, "NR_RACH_IND sent to Proxy, Size: %d Frame %d Slot %d Num PDUS %d\n", encoded_size, - UL_INFO->rach_ind.sfn, UL_INFO->rach_ind.slot, UL_INFO->rach_ind.number_of_pdus); - if (send(ue_tx_sock_descriptor, buffer, encoded_size, 0) < 0) - { - LOG_E(NR_MAC, "Send Proxy NR_UE failed\n"); - return; - } - break; - } - case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION: - { - char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; - LOG_T(NR_MAC, "RX header id :%d\n", UL_INFO->rx_ind.header.message_id); - int encoded_size = nfapi_nr_p7_message_pack(&UL_INFO->rx_ind, buffer, sizeof(buffer), NULL); - if (encoded_size <= 0) - { - LOG_E(NR_MAC, "nfapi_nr_p7_message_pack has failed. Encoded size = %d\n", encoded_size); - return; - } - - LOG_D(NR_MAC, "NR_RX_IND sent to Proxy, Size: %d Frame %d Slot %d Num PDUS %d\n", encoded_size, - UL_INFO->rx_ind.sfn, UL_INFO->rx_ind.slot, UL_INFO->rx_ind.number_of_pdus); - if (send(ue_tx_sock_descriptor, buffer, encoded_size, 0) < 0) - { - LOG_E(NR_MAC, "Send Proxy NR_UE failed\n"); - return; - } - break; - } - case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION: - { - char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; - LOG_T(NR_MAC, "CRC header id :%d\n", UL_INFO->crc_ind.header.message_id); - int encoded_size = nfapi_nr_p7_message_pack(&UL_INFO->crc_ind, buffer, sizeof(buffer), NULL); - if (encoded_size <= 0) - { - LOG_E(NR_MAC, "nfapi_nr_p7_message_pack has failed. Encoded size = %d\n", encoded_size); - return; - } - - LOG_D(NR_MAC, "NR_CRC_IND sent to Proxy, Size: %d Frame %d Slot %d Num PDUS %d\n", encoded_size, - UL_INFO->crc_ind.sfn, UL_INFO->crc_ind.slot, UL_INFO->crc_ind.number_crcs); - if (send(ue_tx_sock_descriptor, buffer, encoded_size, 0) < 0) - { - LOG_E(NR_MAC, "Send Proxy NR_UE failed\n"); - return; - } - break; - } - case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION: - { - char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; - LOG_D(NR_MAC, "UCI header id :%d\n", UL_INFO->uci_ind.header.message_id); - int encoded_size = nfapi_nr_p7_message_pack(&UL_INFO->uci_ind, buffer, sizeof(buffer), NULL); - if (encoded_size <= 0) - { - LOG_E(NR_MAC, "nfapi_nr_p7_message_pack has failed. Encoded size = %d\n", encoded_size); - return; - } - - LOG_D(NR_MAC, "NR_UCI_IND sent to Proxy, Size: %d Frame %d Slot %d Num PDUS %d\n", encoded_size, - UL_INFO->uci_ind.sfn, UL_INFO->uci_ind.slot, UL_INFO->uci_ind.num_ucis); - if (send(ue_tx_sock_descriptor, buffer, encoded_size, 0) < 0) - { - LOG_E(NR_MAC, "Send Proxy NR_UE failed\n"); - return; - } - break; - } - case NFAPI_NR_PHY_MSG_TYPE_SRS_INDICATION: - break; - default: - break; - } -} - -bool sfn_slot_matcher(void *sfn_slot_s, void *candidate) -{ - nfapi_p7_message_header_t *msg = candidate; - const struct sfn_slot_s *sfn_sf = (const struct sfn_slot_s *)sfn_slot_s; - - switch (msg->message_id) - { - case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: - { - nfapi_nr_rach_indication_t *ind = candidate; - return sfn_sf->sfn == ind->sfn && sfn_sf->slot == ind->slot; - } - - case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION: - { - nfapi_nr_rx_data_indication_t *ind = candidate; - return sfn_sf->sfn == ind->sfn && sfn_sf->slot == ind->slot; - } - - case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION: - { - nfapi_nr_crc_indication_t *ind = candidate; - return sfn_sf->sfn == ind->sfn && sfn_sf->slot == ind->slot; - } - - case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION: - { - nfapi_nr_uci_indication_t *ind = candidate; - return sfn_sf->sfn == ind->sfn && sfn_sf->slot == ind->slot; - } - - case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST: - { - nfapi_nr_dl_tti_request_t *ind = candidate; - return sfn_sf->sfn == ind->SFN && sfn_sf->slot == ind->Slot; - } - - case NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST: - { - nfapi_nr_tx_data_request_t *ind = candidate; - return sfn_sf->sfn == ind->SFN && sfn_sf->slot == ind->Slot; - } - - case NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST: - { - nfapi_nr_ul_dci_request_t *ind = candidate; - return sfn_sf->sfn == ind->SFN && sfn_sf->slot == ind->Slot; - } - - case NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST: - { - nfapi_nr_ul_tti_request_t *ind = candidate; - return sfn_sf->sfn == ind->SFN && sfn_sf->slot == ind->Slot; - } - - default: - LOG_E(NR_MAC, "sfn_slot_match bad ID: %d\n", msg->message_id); - - } - - return false; -} - -static void fill_dl_info_with_pdcch(fapi_nr_dci_indication_t *dci, nfapi_nr_dl_dci_pdu_t *rx_dci, int idx) -{ - int num_bytes = (rx_dci->PayloadSizeBits + 7) / 8; - LOG_D(NR_PHY, "[%d, %d] PDCCH DCI (Payload) for rnti %x with PayloadSizeBits %d, num_bytes %d\n", - dci->SFN, dci->slot, rx_dci->RNTI, rx_dci->PayloadSizeBits, num_bytes); - for (int k = 0; k < num_bytes; k++) - { - LOG_D(NR_MAC, "PDCCH DCI PDU payload[%d] = %d\n", k, rx_dci->Payload[k]); - dci->dci_list[idx].payloadBits[k] = rx_dci->Payload[k]; - } - dci->dci_list[idx].payloadSize = rx_dci->PayloadSizeBits; - dci->dci_list[idx].rnti = rx_dci->RNTI; - dci->dci_list[idx].n_CCE = rx_dci->CceIndex; - dci->dci_list[idx].N_CCE = rx_dci->AggregationLevel; - dci->number_of_dcis = idx + 1; -} - -static void fill_mib_in_rx_ind(nfapi_nr_dl_tti_request_pdu_t *pdu_list, fapi_nr_rx_indication_t *rx_ind, int pdu_idx, int pdu_type) -{ - AssertFatal(pdu_idx < sizeof(rx_ind->rx_indication_body) / sizeof(rx_ind->rx_indication_body[0]), - "pdu_index (%d) is greater than rx_indication_body size!\n", pdu_idx); - AssertFatal(pdu_idx == rx_ind->number_pdus, "Invalid pdu_idx %d!\n", pdu_idx); - - LOG_T(NR_MAC, "Recevied an SSB and are filling rx_ind with the MIB!\n"); - - nfapi_nr_dl_tti_ssb_pdu_rel15_t *ssb_pdu = &pdu_list->ssb_pdu.ssb_pdu_rel15; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.cell_id = ssb_pdu->PhysCellId; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[0] = (ssb_pdu->bchPayload) & 0xff; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[1] = (ssb_pdu->bchPayload >> 8) & 0xff; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.pdu[2] = (ssb_pdu->bchPayload >> 16) & 0xff; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.rsrp_dBm = ssb_pdu->ssbRsrp; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_index = ssb_pdu->SsbBlockIndex; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_length = pdu_list->PDUSize; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.ssb_start_subcarrier = ssb_pdu->SsbSubcarrierOffset; - rx_ind->rx_indication_body[pdu_idx].ssb_pdu.decoded_pdu = true; - rx_ind->rx_indication_body[pdu_idx].pdu_type = pdu_type; - rx_ind->number_pdus = pdu_idx + 1; -} - -static bool is_my_dci(NR_UE_MAC_INST_t *mac, nfapi_nr_dl_dci_pdu_t *received_pdu) -{ - /* For multiple UEs, we need to be able to filter the rx'd messages by - the RNTI. The filtering is different between NSA mode and SA mode. - NSA mode has a two step CFRA procedure and SA has a 4 step procedure. - We only need to check if the rx'd RNTI doesnt match the CRNTI if the RAR - has been processed already, in NSA mode. - In SA, depending on the RA state, we can have a SIB (0xffff), RAR (0x10b), - Msg3 (TC_RNTI) or an actual DCI message (CRNTI). When we get Msg3, the - MAC instance of the UE still has a CRNTI = 0. We should only check if the - CRNTI doesnt match the received RNTI in SA mode if Msg3 has been processed - already. Only once the RA procedure succeeds is the CRNTI value updated - to the TC_RNTI. */ - if (get_softmodem_params()->nsa) { - if (received_pdu->RNTI != mac->crnti && (received_pdu->RNTI != mac->ra.ra_rnti)) - return false; - } - if (IS_SA_MODE(get_softmodem_params())) { - if (mac->state == UE_NOT_SYNC) - return false; - if (received_pdu->RNTI == 0xFFFF) - return false; - if (received_pdu->RNTI != mac->crnti && mac->ra.ra_state == nrRA_SUCCEEDED) - return false; - if (received_pdu->RNTI != mac->ra.t_crnti && mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION) - return false; - if (received_pdu->RNTI != 0x10b && mac->ra.ra_state == nrRA_WAIT_RAR) - return false; - if (received_pdu->RNTI != 0xFFFF && mac->ra.ra_state <= nrRA_GENERATE_PREAMBLE) - return false; - } - return true; -} - -static void copy_dl_tti_req_to_dl_info(nr_downlink_indication_t *dl_info, nfapi_nr_dl_tti_request_t *dl_tti_request) -{ - NR_UE_MAC_INST_t *mac = get_mac_inst(dl_info->module_id); - mac->nr_ue_emul_l1.expected_sib = false; - memset(mac->nr_ue_emul_l1.index_has_sib, 0, sizeof(mac->nr_ue_emul_l1.index_has_sib)); - mac->nr_ue_emul_l1.expected_rar = false; - memset(mac->nr_ue_emul_l1.index_has_rar, 0, sizeof(mac->nr_ue_emul_l1.index_has_rar)); - mac->nr_ue_emul_l1.expected_dci = false; - memset(mac->nr_ue_emul_l1.index_has_dci, 0, sizeof(mac->nr_ue_emul_l1.index_has_dci)); - int pdu_idx = 0; - - int num_pdus = dl_tti_request->dl_tti_request_body.nPDUs; - AssertFatal(num_pdus >= 0, "Invalid dl_tti_request number of PDUS\n"); - - for (int i = 0; i < num_pdus; i++) - { - nfapi_nr_dl_tti_request_pdu_t *pdu_list = &dl_tti_request->dl_tti_request_body.dl_tti_pdu_list[i]; - if (pdu_list->PDUType == NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE) - { - LOG_D(NR_PHY, "[%d, %d] PDSCH PDU for rnti %x\n", - dl_tti_request->SFN, dl_tti_request->Slot, pdu_list->pdsch_pdu.pdsch_pdu_rel15.rnti); - } - - if (pdu_list->PDUType == NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE) - { - LOG_D(NR_PHY, "[%d, %d] PDCCH DCI PDU (Format for incoming PDSCH PDU)\n", - dl_tti_request->SFN, dl_tti_request->Slot); - uint16_t num_dcis = pdu_list->pdcch_pdu.pdcch_pdu_rel15.numDlDci; - if (num_dcis > 0) - { - if (!dl_info->dci_ind) - { - dl_info->dci_ind = CALLOC(1, sizeof(fapi_nr_dci_indication_t)); - } - dl_info->dci_ind->SFN = dl_tti_request->SFN; - dl_info->dci_ind->slot = dl_tti_request->Slot; - AssertFatal(num_dcis <= sizeof(dl_info->dci_ind->dci_list) / sizeof(dl_info->dci_ind->dci_list[0]), - "The number of DCIs is greater than dci_list"); - for (int j = 0; j < num_dcis; j++) - { - nfapi_nr_dl_dci_pdu_t *dci_pdu_list = &pdu_list->pdcch_pdu.pdcch_pdu_rel15.dci_pdu[j]; - if (!is_my_dci(mac, dci_pdu_list)) - { - continue; - } - fill_dl_info_with_pdcch(dl_info->dci_ind, dci_pdu_list, pdu_idx); - if (dci_pdu_list->RNTI == 0xffff) - { - mac->nr_ue_emul_l1.expected_sib = true; - mac->nr_ue_emul_l1.index_has_sib[j] = true; - LOG_T(NR_MAC, "Setting index_has_sib[%d] = true\n", j); - } - else if (dci_pdu_list->RNTI == mac->ra.ra_rnti) - { - mac->nr_ue_emul_l1.expected_rar = true; - mac->nr_ue_emul_l1.index_has_rar[j] = true; - LOG_T(NR_MAC, "Setting index_has_rar[%d] = true\n", j); - } - else - { - mac->nr_ue_emul_l1.expected_dci = true; - mac->nr_ue_emul_l1.index_has_dci[j] = true; - LOG_T(NR_MAC, "Setting index_has_dci[%d] = true\n", j); - } - pdu_idx++; - } - } - } - if (pdu_list->PDUType == NFAPI_NR_DL_TTI_SSB_PDU_TYPE) - { - /* If we get a MIB, we want to handle it right away and then come back. - The MIB and SIB come in the same dl_tti_req but the MIB should be - processed first and then the DCI and payload of the SIB1 can be - processed. The MIB should be handled first and then the rx_ind - will be freed after handling. This is why the PDU index will - always be zero for the RX_IND becasue we should not have more than - one MIB. */ - if (!dl_info->rx_ind) - { - dl_info->rx_ind = CALLOC(1, sizeof(*dl_info->rx_ind)); - } - fapi_nr_rx_indication_t *rx_ind = dl_info->rx_ind; - rx_ind->sfn = dl_tti_request->SFN; - rx_ind->slot = dl_tti_request->Slot; - fill_mib_in_rx_ind(pdu_list, rx_ind, 0, FAPI_NR_RX_PDU_TYPE_SSB); - nr_ue_dl_indication(&mac->dl_info); - } - } - dl_info->slot = dl_tti_request->Slot; - dl_info->frame = dl_tti_request->SFN; -} - -static void fill_rx_ind(nfapi_nr_pdu_t *pdu_list, fapi_nr_rx_indication_t *rx_ind, int pdu_idx, int pdu_type) -{ - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - AssertFatal(pdu_list->num_TLV < sizeof(pdu_list->TLVs) / sizeof(pdu_list->TLVs[0]), "Num TLVs exceeds TLV array size"); - int length = 0; - for (int j = 0; j < pdu_list->num_TLV; j++) - { - length += pdu_list->TLVs[j].length; - } - LOG_D(NR_PHY, "%s: num_tlv %d and length %d, pdu index %d\n", - __FUNCTION__, pdu_list->num_TLV, length, pdu_idx); - uint8_t *pdu = malloc(length); - AssertFatal(pdu != NULL, "%s: Out of memory in malloc", __FUNCTION__); - rx_ind->rx_indication_body[pdu_idx].pdsch_pdu.pdu = pdu; - for (int j = 0; j < pdu_list->num_TLV; j++) - { - const uint32_t *ptr; - if (pdu_list->TLVs[j].tag) - ptr = pdu_list->TLVs[j].value.ptr; - else - ptr = pdu_list->TLVs[j].value.direct; - memcpy(pdu, ptr, pdu_list->TLVs[j].length); - pdu += pdu_list->TLVs[j].length; - } - bool ack_nack = true; - if (mac->ra.ra_state >= nrRA_SUCCEEDED && should_drop_transport_block(rx_ind->slot, mac->crnti)) { - ack_nack = false; - } - rx_ind->rx_indication_body[pdu_idx].pdsch_pdu.ack_nack = ack_nack; - rx_ind->rx_indication_body[pdu_idx].pdsch_pdu.pdu_length = length; - rx_ind->rx_indication_body[pdu_idx].pdu_type = pdu_type; - -} - - -static void copy_tx_data_req_to_dl_info(nr_downlink_indication_t *dl_info, nfapi_nr_tx_data_request_t *tx_data_request) -{ - NR_UE_MAC_INST_t *mac = get_mac_inst(dl_info->module_id); - int num_pdus = tx_data_request->Number_of_PDUs; - AssertFatal(num_pdus >= 0, "Invalid tx_data_request number of PDUS\n"); - - if (!dl_info->rx_ind) - { - dl_info->rx_ind = CALLOC(num_pdus, sizeof(fapi_nr_rx_indication_t)); - } - AssertFatal(dl_info->rx_ind != NULL, "%s: Out of memory in calloc", __FUNCTION__); - fapi_nr_rx_indication_t *rx_ind = dl_info->rx_ind; - rx_ind->sfn = tx_data_request->SFN; - rx_ind->slot = tx_data_request->Slot; - - int pdu_idx = 0; - - for (int i = 0; i < num_pdus; i++) - { - nfapi_nr_pdu_t *pdu_list = &tx_data_request->pdu_list[i]; - if (mac->nr_ue_emul_l1.index_has_sib[i]) - { - AssertFatal(!get_softmodem_params()->nsa, - "Should not be processing SIB in NSA mode, something bad happened\n"); - fill_rx_ind(pdu_list, rx_ind, pdu_idx, FAPI_NR_RX_PDU_TYPE_SIB); - pdu_idx++; - } - else if (mac->nr_ue_emul_l1.index_has_rar[i]) - { - fill_rx_ind(pdu_list, rx_ind, pdu_idx, FAPI_NR_RX_PDU_TYPE_RAR); - pdu_idx++; - } - else if (mac->nr_ue_emul_l1.index_has_dci[i]) - { - fill_rx_ind(pdu_list, rx_ind, pdu_idx, FAPI_NR_RX_PDU_TYPE_DLSCH); - pdu_idx++; - } - else - { - LOG_T(NR_MAC, "mac->nr_ue_emul_l1.index_has_dci[%d] = 0, so this index contained a DCI for a different UE\n", i); - } - - } - dl_info->slot = tx_data_request->Slot; - dl_info->frame = tx_data_request->SFN; - dl_info->rx_ind->number_pdus = pdu_idx; -} - -static void copy_ul_dci_data_req_to_dl_info(nr_downlink_indication_t *dl_info, nfapi_nr_ul_dci_request_t *ul_dci_req) -{ - NR_UE_MAC_INST_t *mac = get_mac_inst(dl_info->module_id); - int pdu_idx = 0; - - int num_pdus = ul_dci_req->numPdus; - AssertFatal(num_pdus >= 0, "Invalid ul_dci_request number of PDUS\n"); - - for (int i = 0; i < num_pdus; i++) - { - nfapi_nr_ul_dci_request_pdus_t *pdu_list = &ul_dci_req->ul_dci_pdu_list[i]; - AssertFatal(pdu_list->PDUType == 0, "ul_dci_req pdu type != PUCCH"); - LOG_D(NR_PHY, "[%d %d] PUCCH PDU in ul_dci for rnti %x and numDLDCI = %d\n", - ul_dci_req->SFN, ul_dci_req->Slot, pdu_list->pdcch_pdu.pdcch_pdu_rel15.dci_pdu->RNTI, - pdu_list->pdcch_pdu.pdcch_pdu_rel15.numDlDci); - uint16_t num_dci = pdu_list->pdcch_pdu.pdcch_pdu_rel15.numDlDci; - if (num_dci > 0) - { - if (!dl_info->dci_ind) - { - dl_info->dci_ind = CALLOC(1, sizeof(fapi_nr_dci_indication_t)); - } - AssertFatal(dl_info->dci_ind != NULL, "%s: Out of memory in calloc", __FUNCTION__); - dl_info->dci_ind->SFN = ul_dci_req->SFN; - dl_info->dci_ind->slot = ul_dci_req->Slot; - AssertFatal(num_dci < sizeof(dl_info->dci_ind->dci_list) / sizeof(dl_info->dci_ind->dci_list[0]), "The number of DCIs is greater than dci_list"); - for (int j = 0; j < num_dci; j++) - { - nfapi_nr_dl_dci_pdu_t *dci_pdu_list = &pdu_list->pdcch_pdu.pdcch_pdu_rel15.dci_pdu[j]; - if (dci_pdu_list->RNTI != mac->crnti) - { - LOG_T(NR_MAC, "dci_pdu_list->RNTI (%x) != mac->crnti (%x)\n", dci_pdu_list->RNTI, mac->crnti); - continue; - } - fill_dl_info_with_pdcch(dl_info->dci_ind, dci_pdu_list, pdu_idx); - pdu_idx++; - } - } - } - dl_info->frame = ul_dci_req->SFN; - dl_info->slot = ul_dci_req->Slot; -} - -static bool send_crc_ind_and_rx_ind(int sfn, int slot) -{ - bool sent_crc_rx = true; - - struct sfn_slot_s sfn_slot = {.sfn = sfn, .slot = slot}; - nfapi_nr_rx_data_indication_t *rx_ind = unqueue_matching(&nr_rx_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot); - nfapi_nr_crc_indication_t *crc_ind = unqueue_matching(&nr_crc_ind_queue, MAX_QUEUE_SIZE, sfn_slot_matcher, &sfn_slot); - - if (crc_ind && crc_ind->number_crcs > 0) - { - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - for (int i = 0; i < crc_ind->number_crcs; i++) { - int harq_pid = crc_ind->crc_list[i].harq_id; - LOG_T(NR_MAC, "Resetting harq_pid %d active_ul_harq_sfn/slot\n", harq_pid); - mac->nr_ue_emul_l1.harq[harq_pid].active_ul_harq_sfn = -1; - mac->nr_ue_emul_l1.harq[harq_pid].active_ul_harq_slot = -1; - } - NR_UL_IND_t UL_INFO = { - .crc_ind = *crc_ind, - }; - send_nsa_standalone_msg(&UL_INFO, crc_ind->header.message_id); - free(crc_ind->crc_list); - free(crc_ind); - } - if (rx_ind && rx_ind->number_of_pdus > 0) - { - NR_UL_IND_t UL_INFO = { - .rx_ind = *rx_ind, - }; - send_nsa_standalone_msg(&UL_INFO, rx_ind->header.message_id); - free(rx_ind->pdu_list); - free(rx_ind); - } - else - { - sent_crc_rx = false; - } - return sent_crc_rx; -} - -static void copy_ul_tti_data_req_to_dl_info(nr_downlink_indication_t *dl_info, nfapi_nr_ul_tti_request_t *ul_tti_req) -{ - int num_pdus = ul_tti_req->n_pdus; - AssertFatal(num_pdus >= 0, "Invalid ul_tti_request number of PDUS\n"); - AssertFatal(num_pdus <= sizeof(ul_tti_req->pdus_list) / sizeof(ul_tti_req->pdus_list[0]), - "Too many pdus %d in ul_tti_req\n", num_pdus); - - if (!send_crc_ind_and_rx_ind(ul_tti_req->SFN, ul_tti_req->Slot)) - { - LOG_T(NR_MAC, "CRC_RX ind not sent\n"); - if (!put_queue(&nr_ul_tti_req_queue, ul_tti_req)) - { - LOG_E(NR_PHY, "put_queue failed for ul_tti_req.\n"); - } - return; - } -} - -static void fill_dci_from_dl_config(nr_downlink_indication_t*dl_ind, fapi_nr_dl_config_request_t *dl_config) -{ - - if (!dl_ind->dci_ind) - return; - - AssertFatal(dl_config->number_pdus < sizeof(dl_config->dl_config_list) / sizeof(dl_config->dl_config_list[0]), - "Too many dl_config pdus %d", dl_config->number_pdus); - for (int i = 0; i < dl_config->number_pdus; i++) { - LOG_D(PHY, "Filling DCI with a total of %d total DL PDUs (dl_config %p) \n", - dl_config->number_pdus, dl_config); - fapi_nr_dl_config_dci_dl_pdu_rel15_t *rel15_dci = &dl_config->dl_config_list[i].dci_config_pdu.dci_config_rel15; - int num_dci_options = rel15_dci->num_dci_options; - if (num_dci_options <= 0) - LOG_D(NR_MAC, "num_dci_opts = %d for pdu[%d] in dl_config_list\n", rel15_dci->num_dci_options, i); - AssertFatal(num_dci_options <= sizeof(rel15_dci->dci_length_options) / sizeof(rel15_dci->dci_length_options[0]), - "num_dci_options %d > dci_length_options array\n", num_dci_options); - AssertFatal(num_dci_options <= sizeof(rel15_dci->dci_format_options) / sizeof(rel15_dci->dci_format_options[0]), - "num_dci_options %d > dci_format_options array\n", num_dci_options); - - for (int j = 0; j < num_dci_options; j++) { - int num_dcis = dl_ind->dci_ind->number_of_dcis; - AssertFatal(num_dcis <= sizeof(dl_ind->dci_ind->dci_list) / sizeof(dl_ind->dci_ind->dci_list[0]), - "dl_config->number_pdus %d > dci_ind->dci_list array\n", num_dcis); - for (int k = 0; k < num_dcis; k++) { - LOG_T(NR_PHY, "Received len %d, length options[%d] %d, format assigned %d, format options[%d] %d\n", - dl_ind->dci_ind->dci_list[k].payloadSize, j, rel15_dci->dci_length_options[j], - dl_ind->dci_ind->dci_list[k].dci_format, j, rel15_dci->dci_format_options[j]); - if (rel15_dci->dci_length_options[j] == dl_ind->dci_ind->dci_list[k].payloadSize) { - dl_ind->dci_ind->dci_list[k].dci_format = rel15_dci->dci_format_options[j]; - dl_ind->dci_ind->dci_list[k].ss_type = rel15_dci->ss_type_options[j]; - dl_ind->dci_ind->dci_list[k].coreset_type = rel15_dci->coreset.CoreSetType; - LOG_D(NR_PHY, "format assigned dl_ind->dci_ind->dci_list[k].dci_format %d\n", - dl_ind->dci_ind->dci_list[k].dci_format); - } - } - } - } -} - -// This piece of code is not used in "normal" ue, but in "fapi mode" -void check_and_process_dci(nfapi_nr_dl_tti_request_t *dl_tti_request, - nfapi_nr_tx_data_request_t *tx_data_request, - nfapi_nr_ul_dci_request_t *ul_dci_request, - nfapi_nr_ul_tti_request_t *ul_tti_request) -{ - frame_t frame = 0; - int slot = 0; - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - - if (pthread_mutex_lock(&mac->mutex_dl_info)) abort(); - - if (dl_tti_request) { - frame = dl_tti_request->SFN; - slot = dl_tti_request->Slot; - LOG_D(NR_PHY, "[%d, %d] dl_tti_request\n", frame, slot); - copy_dl_tti_req_to_dl_info(&mac->dl_info, dl_tti_request); - } - /* This checks if the previously recevied DCI matches our current RNTI - value. The assumption is that if the DCI matches our RNTI, then the - incoming tx_data_request is also destined for the current UE. If the - RAR hasn't been processed yet, we do not want to be filtering the - tx_data_requests. */ - if (tx_data_request) { - if (mac->nr_ue_emul_l1.expected_sib || - mac->nr_ue_emul_l1.expected_rar || - mac->nr_ue_emul_l1.expected_dci) { - frame = tx_data_request->SFN; - slot = tx_data_request->Slot; - LOG_D(NR_PHY, "[%d, %d] PDSCH in tx_request\n", frame, slot); - copy_tx_data_req_to_dl_info(&mac->dl_info, tx_data_request); - } - else { - LOG_D(NR_MAC, "Unexpected tx_data_req\n"); - } - } - else if (ul_dci_request) { - frame = ul_dci_request->SFN; - slot = ul_dci_request->Slot; - LOG_D(NR_PHY, "[%d, %d] ul_dci_request\n", frame, slot); - copy_ul_dci_data_req_to_dl_info(&mac->dl_info, ul_dci_request); - } - else if (ul_tti_request) { - frame = ul_tti_request->SFN; - slot = ul_tti_request->Slot; - LOG_T(NR_PHY, "[%d, %d] ul_tti_request\n", frame, slot); - copy_ul_tti_data_req_to_dl_info(&mac->dl_info, ul_tti_request); - } - else { - if (pthread_mutex_unlock(&mac->mutex_dl_info)) abort(); - LOG_T(NR_MAC, "All indications were NULL in %s\n", __FUNCTION__); - return; - } - - if (dl_tti_request || tx_data_request || ul_dci_request) { - fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, slot); - fill_dci_from_dl_config(&mac->dl_info, dl_config); - } - nr_ue_dl_scheduler(mac, &mac->dl_info); - nr_ue_dl_indication(&mac->dl_info); - - if (pthread_mutex_unlock(&mac->mutex_dl_info)) - abort(); - int slots_per_frame = 20; //30 kHZ subcarrier spacing - int slot_ahead = 2; // TODO: Make this dynamic - - if (is_ul_slot((slot + slot_ahead) % slots_per_frame, &mac->frame_structure) - && mac->ra.ra_state != nrRA_SUCCEEDED) { - // If we filled dl_info AFTER we got the slot indication, we want to check if we should fill tx_req: - nr_uplink_indication_t ul_info = {.slot = (slot + slot_ahead) % slots_per_frame, - .frame = slot + slot_ahead >= slots_per_frame ? (frame + 1) % 1024 : frame}; - nr_ue_ul_scheduler(mac, &ul_info); - } -} - -void save_nr_measurement_info(nfapi_nr_dl_tti_request_t *dl_tti_request) -{ - int num_pdus = dl_tti_request->dl_tti_request_body.nPDUs; - char buffer[MAX_MESSAGE_SIZE]; - if (num_pdus <= 0) - { - LOG_E(NR_PHY, "%s: dl_tti_request number of PDUS <= 0\n", __FUNCTION__); - abort(); - } - LOG_T(NR_PHY, "%s: dl_tti_request number of PDUS: %d\n", __FUNCTION__, num_pdus); - for (int i = 0; i < num_pdus; i++) - { - nfapi_nr_dl_tti_request_pdu_t *pdu_list = &dl_tti_request->dl_tti_request_body.dl_tti_pdu_list[i]; - if (pdu_list->PDUType == NFAPI_NR_DL_TTI_SSB_PDU_TYPE) - { - LOG_T(NR_PHY, "Cell_id: %d, the ssb_block_idx %d, sc_offset: %d and payload %d\n", - pdu_list->ssb_pdu.ssb_pdu_rel15.PhysCellId, - pdu_list->ssb_pdu.ssb_pdu_rel15.SsbBlockIndex, - pdu_list->ssb_pdu.ssb_pdu_rel15.SsbSubcarrierOffset, - pdu_list->ssb_pdu.ssb_pdu_rel15.bchPayload); - pdu_list->ssb_pdu.ssb_pdu_rel15.ssbRsrp = 60; - LOG_T(NR_RRC, "Setting pdulist[%d].ssbRsrp to %d\n", i, pdu_list->ssb_pdu.ssb_pdu_rel15.ssbRsrp); - } - } - - size_t pack_len = nfapi_nr_p7_message_pack((void *)dl_tti_request, - buffer, - sizeof(buffer), - NULL); - if (pack_len < 0) - { - LOG_E(NR_PHY, "%s: Error packing nr p7 message.\n", __FUNCTION__); - } - nsa_sendmsg_to_lte_ue(buffer, pack_len, NR_UE_RRC_MEASUREMENT); - LOG_A(NR_RRC, "Populated NR_UE_RRC_MEASUREMENT information and sent to LTE UE\n"); -} - -static void enqueue_nr_nfapi_msg(void *buffer, ssize_t len, nfapi_p7_message_header_t header) -{ - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - switch (header.message_id) - { - case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST: - { - nfapi_nr_dl_tti_request_t *dl_tti_request = malloc16(sizeof(*dl_tti_request)); - if (nfapi_nr_p7_message_unpack(buffer, len, dl_tti_request, - sizeof(*dl_tti_request), NULL) < 0) - { - LOG_E(NR_PHY, "Message dl_tti_request failed to unpack\n"); - break; - } - LOG_D(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST message in sfn/slot %d %d. \n", - dl_tti_request->SFN, dl_tti_request->Slot); - - if (is_channel_modeling()) - save_pdsch_pdu_for_crnti(dl_tti_request); - - if (!put_queue(&nr_dl_tti_req_queue, dl_tti_request)) - { - LOG_E(NR_PHY, "put_queue failed for dl_tti_request.\n"); - free(dl_tti_request); - dl_tti_request = NULL; - } - break; - } - - case NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST: - { - nfapi_nr_tx_data_request_t *tx_data_request = malloc16(sizeof(*tx_data_request)); - if (nfapi_nr_p7_message_unpack(buffer, len, tx_data_request, - sizeof(*tx_data_request), NULL) < 0) - { - LOG_E(NR_PHY, "Message tx_data_request failed to unpack\n"); - break; - } - LOG_D(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST message in SFN/slot %d %d. \n", - tx_data_request->SFN, tx_data_request->Slot); - if (!put_queue(&nr_tx_req_queue, tx_data_request)) - { - LOG_E(NR_PHY, "put_queue failed for tx_request.\n"); - free(tx_data_request); - tx_data_request = NULL; - } - break; - } - - case NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST: - { - nfapi_nr_ul_dci_request_t *ul_dci_request = malloc16(sizeof(*ul_dci_request)); - if (nfapi_nr_p7_message_unpack(buffer, len, ul_dci_request, - sizeof(*ul_dci_request), NULL) < 0) - { - LOG_E(NR_PHY, "Message ul_dci_request failed to unpack\n"); - break; - } - LOG_D(NR_PHY, "Received an NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST message in SFN/slot %d %d. \n", - ul_dci_request->SFN, ul_dci_request->Slot); - if (!put_queue(&nr_ul_dci_req_queue, ul_dci_request)) - { - LOG_E(NR_PHY, "put_queue failed for ul_dci_request.\n"); - free(ul_dci_request); - ul_dci_request = NULL; - } - break; - } - - case NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST: - { - nfapi_nr_ul_tti_request_t *ul_tti_request = malloc16(sizeof(*ul_tti_request)); - if (nfapi_nr_p7_message_unpack(buffer, len, ul_tti_request, - sizeof(*ul_tti_request), NULL) < 0) - { - LOG_E(NR_PHY, "Message ul_tti_request failed to unpack\n"); - break; - } - /* We are filtering UL_TTI_REQs below. We only care about UL_TTI_REQs that - will trigger sending a ul_harq (CRC/RX pair). This UL_TTI_REQ will have - NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE. If we have not yet completed the CBRA/ - CFRA procedure, we need to queue all UL_TTI_REQs. */ - for (int i = 0; i < ul_tti_request->n_pdus; i++) { - if (ul_tti_request->pdus_list[i].pdu_type == NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE - && mac->ra.ra_state >= nrRA_SUCCEEDED) { - if (!put_queue(&nr_ul_tti_req_queue, ul_tti_request)) { - LOG_D(NR_PHY, "put_queue failed for ul_tti_request, calling put_queue_replace.\n"); - nfapi_nr_ul_tti_request_t *evicted_ul_tti_req = put_queue_replace(&nr_ul_tti_req_queue, ul_tti_request); - free(evicted_ul_tti_req); - } - break; - } else if (mac->ra.ra_state < nrRA_SUCCEEDED) { - if (!put_queue(&nr_ul_tti_req_queue, ul_tti_request)) { - LOG_D(NR_PHY, "put_queue failed for ul_tti_request, calling put_queue_replace.\n"); - nfapi_nr_ul_tti_request_t *evicted_ul_tti_req = put_queue_replace(&nr_ul_tti_req_queue, ul_tti_request); - free(evicted_ul_tti_req); - } - break; - } - } - break; - } - - default: - LOG_E(NR_PHY, "Invalid nFAPI message. Header ID %d\n", - header.message_id); - break; - } - return; -} - -static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request) -{ - int count_sent = 0; - NR_UE_MAC_INST_t *mac = get_mac_inst(0); - int number_of_pdu = dl_tti_request->dl_tti_request_body.nPDUs; - if (number_of_pdu <= 0) - { - LOG_E(NR_MAC, "%s: dl_tti_request pdu size <= 0\n", __FUNCTION__); - abort(); - } - - for (int i = 0; i < number_of_pdu; i++) - { - const nfapi_nr_dl_tti_request_pdu_t *pdu_list = &dl_tti_request->dl_tti_request_body.dl_tti_pdu_list[i]; - - if (pdu_list->PDUType == NFAPI_NR_DL_TTI_PDSCH_PDU_TYPE) - { - const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu = &pdu_list->pdsch_pdu.pdsch_pdu_rel15; - if (pdsch_pdu->rnti == mac->crnti && mac->ra.ra_state == nrRA_SUCCEEDED) { - read_channel_param(pdsch_pdu, dl_tti_request->Slot, count_sent); - count_sent++; - LOG_T(NR_MAC, "pdsch_pdu->rnti %x mac->crnti %x mac->ra.ra_state %d count_sent %d\n", - pdsch_pdu->rnti, mac->crnti, mac->ra.ra_state, count_sent); - } - } - } -} - -static uint16_t get_message_id(const uint8_t *buffer, ssize_t len) -{ - if (len < 4) - return 0; - - // Unpack 2 bytes message_id from buffer. - uint16_t v; - memcpy(&v, buffer + 2, sizeof(v)); - return ntohs(v); -} - -void *nrue_standalone_pnf_task(void *context) -{ - struct sockaddr_in server_address; - socklen_t addr_len = sizeof(server_address); - int sd = ue_rx_sock_descriptor; - assert(sd > 0); - - char buffer[NFAPI_MAX_PACKED_MESSAGE_SIZE]; - - LOG_I(NR_RRC, "Successfully started %s.\n", __FUNCTION__); - - while (true) - { - ssize_t len = recvfrom(sd, buffer, sizeof(buffer), MSG_TRUNC, (struct sockaddr *)&server_address, &addr_len); - if (len == -1) - { - LOG_E(NR_PHY, "reading from standalone pnf sctp socket failed \n"); - continue; - } - if (len > sizeof(buffer)) - { - LOG_E(NR_PHY, "%s(%d). Message truncated. %zd\n", __FUNCTION__, __LINE__, len); - continue; - } - if (len == sizeof(uint16_t)) - { - uint16_t *sfn_slot = CALLOC(1, sizeof(*sfn_slot)); - memcpy(sfn_slot, buffer, sizeof(*sfn_slot)); - - LOG_D(NR_PHY, "Received from proxy sfn_slot %x\n", *sfn_slot); - - if (!put_queue(&nr_sfn_slot_queue, sfn_slot)) - { - LOG_E(NR_PHY, "put_queue failed for sfn slot.\n"); - } - - if (sem_post(&sfn_slot_semaphore) != 0) - { - LOG_E(NR_PHY, "sem_post() error\n"); - abort(); - } - } - else if (get_message_id((const uint8_t *)buffer, len) == 0x0FFF) // 0x0FFF : channel info identifier. - { - nr_phy_channel_params_t *ch_info = CALLOC(1, sizeof(*ch_info)); - memcpy(ch_info, buffer, sizeof(*ch_info)); - - if (ch_info->nb_of_csi > 1) - LOG_W(NR_PHY, "Expecting only one CSI report.\n"); - - // TODO: Update sinr field of slot_rnti_mcs to be array. - for (int i = 0; i < ch_info->nb_of_csi; ++i) - { - int mu = 1; // NR-UE emul-L1 is hardcoded to 30kHZ, see check_and_process_dci() - int frame = NFAPI_SFNSLOTDEC2SFN(mu, ch_info->sfn_slot); - int slot = NFAPI_SFNSLOTDEC2SLOT(mu, ch_info->sfn_slot); - slot_rnti_mcs[slot].sinr = ch_info->csi[i].sinr; - slot_rnti_mcs[slot].area_code = ch_info->csi[i].area_code; - - LOG_D(NR_PHY, "Received_SINR[%d] = %f, sfn:slot %d:%d\n", i, ch_info->csi[i].sinr, frame, slot); - } - - if (!put_queue(&nr_chan_param_queue, ch_info)) - { - LOG_E(NR_PHY, "put_queue failed for sfn slot.\n"); - } - - if (sem_post(&sfn_slot_semaphore) != 0) - { - LOG_E(NR_MAC, "sem_post() error\n"); - abort(); - } - } - else - { - nfapi_p7_message_header_t header; - if (nfapi_p7_message_header_unpack(buffer, len, &header, sizeof(header), NULL) < 0) - { - LOG_E(NR_PHY, "Header unpack failed for nrue_standalone pnf\n"); - continue; - } - enqueue_nr_nfapi_msg(buffer, len, header); - } - } //while(true) -} - // L2 Abstraction Layer static int handle_bcch_bch(NR_UE_MAC_INST_t *mac, int cc_id, @@ -1106,9 +133,11 @@ static int handle_bcch_dlsch(NR_UE_MAC_INST_t *mac, unsigned int gNB_index, uint8_t ack_nack, uint8_t *pduP, - uint32_t pdu_len) + uint32_t pdu_len, + int frame, + int slot) { - nr_ue_decode_BCCH_DL_SCH(mac, cc_id, gNB_index, ack_nack, pduP, pdu_len); + nr_ue_decode_BCCH_DL_SCH(mac, cc_id, gNB_index, ack_nack, pduP, pdu_len, frame, slot); return 0; } @@ -1133,24 +162,10 @@ static nr_dci_format_t handle_dci(NR_UE_MAC_INST_t *mac, return nr_ue_process_dci_indication_pdu(mac, frame, slot, dci); } -static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm, float_t sinr_dB) -{ - mac->ssb_measurements.ssb_index = ssb_index; - mac->ssb_measurements.ssb_rsrp_dBm = rsrp_dbm; - mac->ssb_measurements.ssb_sinr_dB = sinr_dB; -} - // L2 Abstraction Layer // Note: sdu should always be processed because data and timing advance updates are transmitted by the UE static int8_t handle_dlsch(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id) { - /* L1 assigns harq_pid, but in emulated L1 mode we need to assign - the harq_pid based on the saved global g_harq_pid. Because we are - emulating L1, no antenna measurements are conducted to calculate - a harq_pid, therefore we must set it here. */ - if (get_softmodem_params()->emulate_l1) - dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.harq_pid = g_harq_pid; - if (mac->ra.ra_state != nrRA_WAIT_RAR) // no HARQ for MSG2 update_harq_status(mac, dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.harq_pid, @@ -1169,13 +184,11 @@ static void handle_rlm(rlm_t rlm_result, int frame, NR_UE_MAC_INST_t *mac) nr_mac_rrc_sync_ind(mac->ue_id, frame, is_sync); } -static int8_t handle_csirs_measurements(NR_UE_MAC_INST_t *mac, - frame_t frame, - int slot, - fapi_nr_csirs_measurements_t *csirs_measurements) +static int8_t handle_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements) { - handle_rlm(csirs_measurements->radiolink_monitoring, frame, mac); - return nr_ue_process_csirs_measurements(mac, frame, slot, csirs_measurements); + handle_rlm(l1_measurements->radiolink_monitoring, frame, mac); + nr_ue_process_l1_measurements(mac, frame, slot, l1_measurements); + return 0; } void update_harq_status(NR_UE_MAC_INST_t *mac, uint8_t harq_pid, uint8_t ack_nack) @@ -1185,7 +198,7 @@ void update_harq_status(NR_UE_MAC_INST_t *mac, uint8_t harq_pid, uint8_t ack_nac if (current_harq->active) { LOG_D(PHY,"Updating harq_status for harq_id %d, ack/nak %d\n", harq_pid, current_harq->ack); // we can prepare feedback for MSG4 in advance - if (mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION) + if (mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION || mac->ra.ra_state == nrRA_WAIT_MSGB) prepare_msg4_msgb_feedback(mac, harq_pid, ack_nack); else { current_harq->ack = ack_nack; @@ -1237,9 +250,6 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio continue; } dci_pdu_rel15_t *def_dci_pdu_rel15 = &mac->def_dci_pdu_rel15[dl_info->slot][dci_format]; - g_harq_pid = def_dci_pdu_rel15->harq_pid.val; - LOG_T(NR_MAC, "Setting harq_pid = %d and dci_index = %d (based on format)\n", g_harq_pid, dci_format); - ret_mask |= (1 << FAPI_NR_DCI_IND); AssertFatal(nr_ue_if_module_inst[dl_info->module_id] != NULL, "IF module is NULL!\n"); fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, dl_info->slot); @@ -1265,16 +275,12 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio rx_indication_body.pdu_type, dl_info->rx_ind->number_pdus); - switch(rx_indication_body.pdu_type){ + switch(rx_indication_body.pdu_type) { case FAPI_NR_RX_PDU_TYPE_SSB: handle_rlm(rx_indication_body.ssb_pdu.radiolink_monitoring, dl_info->frame, mac); if(rx_indication_body.ssb_pdu.decoded_pdu) { - handle_ssb_meas(mac, - rx_indication_body.ssb_pdu.ssb_index, - rx_indication_body.ssb_pdu.rsrp_dBm, - rx_indication_body.ssb_pdu.sinr_dB); ret_mask |= (handle_bcch_bch(mac, dl_info->cc_id, dl_info->gNB_index, @@ -1290,10 +296,13 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio break; case FAPI_NR_RX_PDU_TYPE_SIB: ret_mask |= (handle_bcch_dlsch(mac, - dl_info->cc_id, dl_info->gNB_index, + dl_info->cc_id, + dl_info->gNB_index, rx_indication_body.pdsch_pdu.ack_nack, rx_indication_body.pdsch_pdu.pdu, - rx_indication_body.pdsch_pdu.pdu_length)) << FAPI_NR_RX_PDU_TYPE_SIB; + rx_indication_body.pdsch_pdu.pdu_length, + dl_info->frame, + dl_info->slot)) << FAPI_NR_RX_PDU_TYPE_SIB; break; case FAPI_NR_RX_PDU_TYPE_DLSCH: ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_DLSCH; @@ -1304,15 +313,15 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio // resume RAR response window timer if MSG2 decoding failed nr_timer_suspension(&mac->ra.response_window_timer); } else { - LOG_I(PHY, "RAR-Msg2 decoded\n"); + LOG_I(PHY, "[UE %d] RAR-Msg2 decoded\n", mac->ue_id); } ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_RAR; break; - case FAPI_NR_CSIRS_IND: - ret_mask |= (handle_csirs_measurements(mac, - dl_info->frame, - dl_info->slot, - &rx_indication_body.csirs_measurements)) << FAPI_NR_CSIRS_IND; + case FAPI_NR_MEAS_IND: + ret_mask |= (handle_l1_measurements(mac, + dl_info->frame, + dl_info->slot, + &rx_indication_body.l1_measurements)) << FAPI_NR_MEAS_IND; break; default: break; @@ -1368,45 +377,14 @@ nr_ue_if_module_t *nr_ue_if_module_init(uint32_t module_id) nr_ue_if_module_inst[module_id]->sl_phy_config_request = nr_ue_sl_phy_config_request; nr_ue_if_module_inst[module_id]->sl_indication = nr_ue_sl_indication; } - if (get_softmodem_params()->emulate_l1) - nr_ue_if_module_inst[module_id]->scheduled_response = nr_ue_scheduled_response_stub; - else - nr_ue_if_module_inst[module_id]->scheduled_response = nr_ue_scheduled_response; + nr_ue_if_module_inst[module_id]->scheduled_response = nr_ue_scheduled_response; nr_ue_if_module_inst[module_id]->dl_indication = nr_ue_dl_indication; nr_ue_if_module_inst[module_id]->ul_indication = nr_ue_ul_indication; nr_ue_if_module_inst[module_id]->slot_indication = nr_ue_slot_indication; } - return nr_ue_if_module_inst[module_id]; } -void RCconfig_nr_ue_macrlc(void) { - int j; - paramdef_t MACRLC_Params[] = MACRLCPARAMS_DESC; - paramlist_def_t MACRLC_ParamList = {CONFIG_STRING_MACRLC_LIST, NULL, 0}; - - config_getlist(config_get_if(), &MACRLC_ParamList, MACRLC_Params, sizeofArray(MACRLC_Params), NULL); - if (MACRLC_ParamList.numelt > 0) { - for (j = 0; j < MACRLC_ParamList.numelt; j++) { - if (strcmp(*(MACRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "nfapi") == 0) { - stub_eth_params.my_addr = strdup( - *(MACRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_ADDRESS_IDX].strptr)); - stub_eth_params.remote_addr = strdup( - *(MACRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_ADDRESS_IDX].strptr)); - stub_eth_params.my_portc = - *(MACRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTC_IDX].iptr); - stub_eth_params.remote_portc = - *(MACRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTC_IDX].iptr); - stub_eth_params.my_portd = - *(MACRLC_ParamList.paramarray[j][MACRLC_LOCAL_N_PORTD_IDX].iptr); - stub_eth_params.remote_portd = - *(MACRLC_ParamList.paramarray[j][MACRLC_REMOTE_N_PORTD_IDX].iptr); - stub_eth_params.transp_preference = ETH_UDP_MODE; - } - } - } -} - static void handle_sl_bch(int ue_id, sl_nr_ue_mac_params_t *sl_mac, uint8_t *const sl_mib, diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h index 2bbd97db84..a1175282f0 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h @@ -34,11 +34,8 @@ #define __NR_IF_MODULE_H__ #include "common/platform_types.h" -#include #include "fapi_nr_ue_interface.h" -#include "openair2/PHY_INTERFACE/queue_t.h" #include "openair2/NR_PHY_INTERFACE/NR_IF_Module.h" -#include "NR_Packet_Drop.h" #include "nfapi/open-nFAPI/nfapi/public_inc/sidelink_nr_ue_interface.h" typedef enum sl_sidelink_slot_type { @@ -50,19 +47,6 @@ typedef enum sl_sidelink_slot_type { } sl_sidelink_slot_type_t; -extern queue_t nr_rach_ind_queue; -extern queue_t nr_rx_ind_queue; -extern queue_t nr_crc_ind_queue; -extern queue_t nr_uci_ind_queue; -extern queue_t nr_sfn_slot_queue; -extern queue_t nr_chan_param_queue; -extern queue_t nr_dl_tti_req_queue; -extern queue_t nr_tx_req_queue; -extern queue_t nr_ul_dci_req_queue; -extern queue_t nr_ul_tti_req_queue; - -extern slot_rnti_mcs_s slot_rnti_mcs[NUM_NFAPI_SLOT]; - typedef struct NR_UL_TIME_ALIGNMENT NR_UL_TIME_ALIGNMENT_t; typedef struct { @@ -292,32 +276,6 @@ typedef struct nr_ue_if_module_s { \param module_id module id*/ nr_ue_if_module_t *nr_ue_if_module_init(uint32_t module_id); -void nrue_init_standalone_socket(int tx_port, int rx_port); - -void *nrue_standalone_pnf_task(void *context); -extern sem_t sfn_slot_semaphore; - -typedef struct nfapi_dl_tti_config_req_tx_data_req_t -{ - nfapi_nr_dl_tti_request_pdu_t *dl_itti_config_req; - nfapi_nr_tx_data_request_t *tx_data_req_pdu_list; -} nfapi_dl_tti_config_req_tx_data_req_t; - -void send_nsa_standalone_msg(NR_UL_IND_t *UL_INFO, uint16_t msg_id); - -void save_nr_measurement_info(nfapi_nr_dl_tti_request_t *dl_tti_request); - -void check_and_process_dci(nfapi_nr_dl_tti_request_t *dl_tti_request, - nfapi_nr_tx_data_request_t *tx_data_request, - nfapi_nr_ul_dci_request_t *ul_dci_request, - nfapi_nr_ul_tti_request_t *ul_tti_request); - -struct sfn_slot_s { - int sfn; - int slot; -}; -bool sfn_slot_matcher(void *sfn_slot_s, void *candidate); - /**\brief interface between L1/L2, indicating the downlink related information, like dci_ind and rx_req \param dl_info including dci_ind and rx_request messages*/ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info); diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg.c b/openair2/RRC/LTE/MESSAGES/asn1_msg.c index 6ab23569af..61a0456511 100644 --- a/openair2/RRC/LTE/MESSAGES/asn1_msg.c +++ b/openair2/RRC/LTE/MESSAGES/asn1_msg.c @@ -4521,117 +4521,8 @@ is_en_dc_supported( #undef NCE } -void allocate_en_DC_r15(LTE_UE_EUTRA_Capability_t *cap) +OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) { - LOG_D(RRC, "Entered %s\n", __FUNCTION__); - if (!cap->nonCriticalExtension) - cap->nonCriticalExtension = CALLOC(1, sizeof(*cap->nonCriticalExtension)); - - typeof(cap->nonCriticalExtension) nce1 = cap->nonCriticalExtension; - if (!nce1->nonCriticalExtension) - nce1->nonCriticalExtension = CALLOC(1, sizeof(*nce1->nonCriticalExtension)); - - typeof(nce1->nonCriticalExtension) nce2 = nce1->nonCriticalExtension; - if (!nce2->nonCriticalExtension) - nce2->nonCriticalExtension = CALLOC(1, sizeof(*nce2->nonCriticalExtension)); - - typeof(nce2->nonCriticalExtension) nce3 = nce2->nonCriticalExtension; - if (!nce3->nonCriticalExtension) - nce3->nonCriticalExtension = CALLOC(1, sizeof(*nce3->nonCriticalExtension)); - - typeof(nce3->nonCriticalExtension) nce4 = nce3->nonCriticalExtension; - if (!nce4->nonCriticalExtension) - nce4->nonCriticalExtension = CALLOC(1, sizeof(*nce4->nonCriticalExtension)); - - typeof(nce4->nonCriticalExtension) nce5 = nce4->nonCriticalExtension; - if (!nce5->nonCriticalExtension) - nce5->nonCriticalExtension = CALLOC(1, sizeof(*nce5->nonCriticalExtension)); - - typeof(nce5->nonCriticalExtension) nce6 = nce5->nonCriticalExtension; - if (!nce6->nonCriticalExtension) - nce6->nonCriticalExtension = CALLOC(1, sizeof(*nce6->nonCriticalExtension)); - - typeof(nce6->nonCriticalExtension) nce7 = nce6->nonCriticalExtension; - if (!nce7->nonCriticalExtension) - nce7->nonCriticalExtension = CALLOC(1, sizeof(*nce7->nonCriticalExtension)); - - typeof(nce7->nonCriticalExtension) nce8 = nce7->nonCriticalExtension; - if (!nce8->nonCriticalExtension) - nce8->nonCriticalExtension = CALLOC(1, sizeof(*nce8->nonCriticalExtension)); - - typeof(nce8->nonCriticalExtension) nce9 = nce8->nonCriticalExtension; - if (!nce9->nonCriticalExtension) - nce9->nonCriticalExtension = CALLOC(1, sizeof(*nce9->nonCriticalExtension)); - - typeof(nce9->nonCriticalExtension) nce10 = nce9->nonCriticalExtension; - if (!nce10->nonCriticalExtension) - nce10->nonCriticalExtension = CALLOC(1, sizeof(*nce10->nonCriticalExtension)); - - typeof(nce10->nonCriticalExtension) nce11 = nce10->nonCriticalExtension; - if (!nce11->nonCriticalExtension) - nce11->nonCriticalExtension = CALLOC(1, sizeof(*nce11->nonCriticalExtension)); - - typeof(nce11->nonCriticalExtension) nce12 = nce11->nonCriticalExtension; - if (!nce12->nonCriticalExtension) - nce12->nonCriticalExtension = CALLOC(1, sizeof(*nce12->nonCriticalExtension)); - - typeof(nce12->nonCriticalExtension) nce13 = nce12->nonCriticalExtension; - if (!nce13->nonCriticalExtension) - nce13->nonCriticalExtension = CALLOC(1, sizeof(*nce13->nonCriticalExtension)); - - typeof(nce13->nonCriticalExtension) nce14 = nce13->nonCriticalExtension; - if (!nce14->nonCriticalExtension) - nce14->nonCriticalExtension = CALLOC(1, sizeof(*nce14->nonCriticalExtension)); - - typeof(nce14->nonCriticalExtension) nce15 = nce14->nonCriticalExtension; - if (!nce15->nonCriticalExtension) - nce15->nonCriticalExtension = CALLOC(1, sizeof(*nce15->nonCriticalExtension)); - - typeof(nce15->nonCriticalExtension) nce16 = nce15->nonCriticalExtension; - if (!nce16->nonCriticalExtension) - nce16->nonCriticalExtension = CALLOC(1, sizeof(*nce16->nonCriticalExtension)); - - typeof(nce16->nonCriticalExtension) nce17 = nce16->nonCriticalExtension; - if (!nce17->nonCriticalExtension) - nce17->nonCriticalExtension = CALLOC(1, sizeof(*nce17->nonCriticalExtension)); - - typeof(nce17->nonCriticalExtension) nce18 = nce17->nonCriticalExtension; - if (!nce18->nonCriticalExtension) - nce18->nonCriticalExtension = CALLOC(1, sizeof(*nce18->nonCriticalExtension)); - - typeof(nce18->nonCriticalExtension) nce19 = nce18->nonCriticalExtension; - if (!nce19->nonCriticalExtension) - nce19->nonCriticalExtension = CALLOC(1, sizeof(*nce19->nonCriticalExtension)); - - typeof(nce19->nonCriticalExtension) nce20 = nce19->nonCriticalExtension; - if (!nce20->nonCriticalExtension) - nce20->nonCriticalExtension = CALLOC(1, sizeof(*nce20->nonCriticalExtension)); - - typeof(nce20->nonCriticalExtension) nce21 = nce20->nonCriticalExtension; - if (!nce21->nonCriticalExtension) - nce21->nonCriticalExtension = CALLOC(1, sizeof(*nce21->nonCriticalExtension)); - - typeof(nce21->nonCriticalExtension) nce22 = nce21->nonCriticalExtension; - if (!nce22->nonCriticalExtension) - nce22->nonCriticalExtension = CALLOC(1, sizeof(*nce22->nonCriticalExtension)); - - typeof(nce22->nonCriticalExtension) nce23 = nce22->nonCriticalExtension; - if (!nce23->nonCriticalExtension) - nce23->nonCriticalExtension = CALLOC(1, sizeof(*nce23->nonCriticalExtension)); - - typeof(nce23->nonCriticalExtension) nce24 = nce23->nonCriticalExtension; - if (!nce24->irat_ParametersNR_r15) - nce24->irat_ParametersNR_r15 = CALLOC(1, sizeof(*nce24->irat_ParametersNR_r15)); - - typeof(nce24->irat_ParametersNR_r15) irat = nce24->irat_ParametersNR_r15; - if (!irat->en_DC_r15) - irat->en_DC_r15 = CALLOC(1, sizeof(*irat->en_DC_r15)); - - *irat->en_DC_r15 = LTE_IRAT_ParametersNR_r15__en_DC_r15_supported; - -} - -OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname, bool received_nr_msg) { static OAI_UECapability_t UECapability; /* TODO declared static to allow returning this has an address should be allocated in a cleaner way. */ static LTE_SupportedBandEUTRA_t Bandlist[4]; // the macro asn1cSeqAdd() does not copy the source, but only stores a reference to it static LTE_InterFreqBandInfo_t InterFreqBandInfo[4][4]; // the macro asn1cSeqAdd() does not copy the source, but only stores a reference to it @@ -4716,26 +4607,6 @@ OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname, bool // UE_EUTRA_Capability->measParameters.bandListEUTRA.list.count = 0; // no measurements on other bands // UE_EUTRA_Capability->featureGroupIndicators // null - - if (get_softmodem_params()->usim_test == 1) { - // featureGroup is mandatory for CMW tests - // featureGroup is filled only for usim-test mode - BIT_STRING_t *bit_string = CALLOC(1, sizeof(*bit_string)); - char featrG[4] = { 0x00, 0x08, 0x00, 0x04 }; - bit_string->buf = CALLOC(1, 4); - memcpy(bit_string->buf, featrG, 4); - bit_string->size = 4; - bit_string->bits_unused = 0; - UE_EUTRA_Capability->featureGroupIndicators = bit_string; - } - - if (get_softmodem_params()->nsa && received_nr_msg) - { - allocate_en_DC_r15(UE_EUTRA_Capability); - if (!is_en_dc_supported(UE_EUTRA_Capability)){ - LOG_E(RRC, "We did not properly allocate en_DC_r15 for UE_EUTRA_Capability\n"); - } - } } else { FILE *f = fopen(UE_EUTRA_Capability_xer_fname, "r"); assert(f); diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg.h b/openair2/RRC/LTE/MESSAGES/asn1_msg.h index 3d5a8bb68c..b7d9dc4856 100644 --- a/openair2/RRC/LTE/MESSAGES/asn1_msg.h +++ b/openair2/RRC/LTE/MESSAGES/asn1_msg.h @@ -368,12 +368,10 @@ int do_HandoverPreparation(char *ho_buf, int ho_size, LTE_UE_EUTRA_Capability_t int do_HandoverCommand(char *ho_buf, int ho_size, char *rrc_buf, int rrc_size); -OAI_UECapability_t *fill_ue_capability(char *LTE_UE_EUTRA_Capability_xer, bool received_nr_msg); +OAI_UECapability_t *fill_ue_capability(char *LTE_UE_EUTRA_Capability_xer); int is_en_dc_supported(LTE_UE_EUTRA_Capability_t *c); -void allocate_en_DC_r15(LTE_UE_EUTRA_Capability_t *cap); - uint8_t do_UECapabilityEnquiry( const protocol_ctxt_t *const ctxt_pP, diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index 2216fb5a75..70692bfaa9 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -64,9 +64,6 @@ #include "LTE_UECapabilityEnquiry.h" #include "LTE_UE-CapabilityRequest.h" -#include "NR_RAT-Type.h" -#include "NR_UE-CapabilityRAT-Container.h" - #include "common/utils/tun_if.h" #if ENABLE_RAL #include "rrc_UE_ral.h" @@ -97,9 +94,6 @@ //for D2D int ctrl_sock_fd; struct sockaddr_in prose_app_addr; -static const char nsa_ipaddr[] = "127.0.0.1"; -static int from_nr_ue_fd = -1; -static int to_nr_ue_fd = -1; int slrb_id; int send_ue_information = 0; // TimeToTrigger enum mapping table (36.331 TimeToTrigger IE) @@ -144,22 +138,10 @@ typedef struct rrc_dcch_data_copy_t LTE_DL_DCCH_Message_t *dl_dcch_msg; } rrc_dcch_data_copy_t; -typedef struct rrc_nrue_cap_info_t -{ - uint8_t mesg[RRC_BUF_SIZE]; - size_t mesg_len; - LTE_DL_DCCH_Message_t *dl_dcch_msg; -} rrc_nrue_cap_info_t; - static void rrc_ue_process_ueCapabilityEnquiry(const protocol_ctxt_t *const ctxt_pP, LTE_UECapabilityEnquiry_t *UECapabilityEnquiry, uint8_t eNB_index); -static void rrc_ue_process_nrueCapabilityEnquiry(const protocol_ctxt_t *const ctxt_pP, - LTE_UECapabilityEnquiry_t *UECapabilityEnquiry, - rrc_nrue_cap_info_t *nrue_cap_info, - uint8_t eNB_index); - /** \brief Generates/Encodes RRCConnnectionSetupComplete message at UE * \param ctxt_pP Running context * \param eNB_index Index of corresponding eNB/CH @@ -184,8 +166,6 @@ static void rrc_ue_generate_RRCConnectionReconfigurationComplete(const protocol_ static void rrc_ue_generate_MeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t eNB_index ); -static void rrc_ue_generate_nrMeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t eNB_index ); - static uint8_t check_trigger_meas_event( module_id_t module_idP, frame_t frameP, @@ -208,8 +188,6 @@ rrc_ue_process_MBMSCountingRequest( uint8_t eNB_index ); -static void process_nr_nsa_msg(nsa_msg_t *msg, int msg_len); -static void nsa_sendmsg_to_nrue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type); protocol_ctxt_t ctxt_pP_local; @@ -838,25 +816,6 @@ rrc_ue_process_measConfig( measObj->measObject.choice.measObjectEUTRA.allowedMeasBandwidth, measObj->measObject.choice.measObjectEUTRA.presenceAntennaPort1, measObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0]); - } else if (measObj->measObject.present == LTE_MeasObjectToAddMod__measObject_PR_measObjectNR_r15) { - ue->subframeCount = 0; - LOG_I(RRC, "NR_r15 Measurement: carrierFreq: %ld\n", - measObj->measObject.choice.measObjectNR_r15.carrierFreq_r15); - if (!get_softmodem_params()->nsa) { - LOG_E(RRC, "Not in NSA mode but attempting to send measurement request to NR-UE\n"); - return; - } - uint8_t buffer[RRC_BUF_SIZE]; - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_MeasObjectToAddMod, - NULL, - measObj, - buffer, - sizeof(buffer)); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %zu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - nsa_sendmsg_to_nrue(buffer, (enc_rval.encoded + 7)/8, RRC_MEASUREMENT_PROCEDURE); - LOG_A(RRC, "Encoded measurement object %zu bits (%zu bytes) and sent to NR UE\n", - enc_rval.encoded, (enc_rval.encoded + 7)/8); } LOG_D(RRC, "Adding measurement object [%d][%ld]\n", eNB_index, ind); ue->MeasObj[eNB_index][ind-1]=measObj; @@ -1697,102 +1656,6 @@ rrc_ue_process_MBMSCountingRequest( } - -//----------------------------------------------------------------------------- -void -rrc_ue_process_nrueCapabilityEnquiry( - const protocol_ctxt_t *const ctxt_pP, - LTE_UECapabilityEnquiry_t *UECapabilityEnquiry, - rrc_nrue_cap_info_t *nrue_cap_info, - uint8_t eNB_index -) -//----------------------------------------------------------------------------- -{ - asn_enc_rval_t enc_rval; - uint8_t buffer[RRC_BUF_SIZE]; - LOG_I(RRC,"[UE %d] Frame %d: Receiving from SRB1 (DL-DCCH), Processing NRUECapabilityEnquiry (eNB %d)\n", - ctxt_pP->module_id, - ctxt_pP->frame, - eNB_index); - LTE_UL_DCCH_Message_t ul_dcch_msg; - memset(&ul_dcch_msg, 0, sizeof(ul_dcch_msg)); - LTE_UECapabilityInformation_t *ue_cap = &ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation; - ul_dcch_msg.message.present = LTE_UL_DCCH_MessageType_PR_c1; - ul_dcch_msg.message.choice.c1.present = LTE_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation; - ue_cap->rrc_TransactionIdentifier = UECapabilityEnquiry->rrc_TransactionIdentifier; - - NR_UE_CapabilityRAT_Container_t ue_CapabilityRAT_Container; - memset(&ue_CapabilityRAT_Container, 0, sizeof(ue_CapabilityRAT_Container)); - ue_CapabilityRAT_Container.rat_Type = NR_RAT_Type_nr; - OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container.ue_CapabilityRAT_Container, - (const char *)nrue_cap_info->mesg, - nrue_cap_info->mesg_len); - # if(1) // TODO: The MRDC capabilites should be filled in the NR UE - NR_UE_CapabilityRAT_Container_t ue_CapabilityRAT_Container_mrdc; - memset(&ue_CapabilityRAT_Container_mrdc, 0, sizeof(ue_CapabilityRAT_Container_mrdc)); - uint8_t buffer_mrdc[RRC_BUF_SIZE]; - NR_UE_MRDC_Capability_t *UE_Capability_MRDC = CALLOC(1, sizeof(NR_UE_MRDC_Capability_t)); - asn_enc_rval_t enc_rval_mrdc = uper_encode_to_buffer(&asn_DEF_NR_UE_MRDC_Capability, - NULL, - (void *)UE_Capability_MRDC, - &buffer_mrdc, - sizeof(buffer_mrdc)); - AssertFatal (enc_rval_mrdc.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval_mrdc.failed_type->name, enc_rval_mrdc.encoded); - LOG_I(RRC, "[NR_RRC] NRUE MRDC Capability encoded, %ld bytes (%ld bits)\n", - (enc_rval_mrdc.encoded + 7) / 8, enc_rval_mrdc.encoded + 7); - - ue_CapabilityRAT_Container_mrdc.rat_Type = NR_RAT_Type_eutra_nr; - OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container_mrdc.ue_CapabilityRAT_Container, - (const char *)buffer_mrdc, - (enc_rval_mrdc.encoded + 7) / 8); - #endif - - ue_cap->criticalExtensions.present = LTE_UECapabilityInformation__criticalExtensions_PR_c1; - ue_cap->criticalExtensions.choice.c1.present = LTE_UECapabilityInformation__criticalExtensions__c1_PR_ueCapabilityInformation_r8; - ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.count = 0; - int count = UECapabilityEnquiry->criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list.count; - xer_fprint(stdout, &asn_DEF_NR_UE_CapabilityRAT_Container, (void *)&ue_CapabilityRAT_Container); - LTE_UE_CapabilityRequest_t *cap_req = &UECapabilityEnquiry->criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest; - for (int i = 0; i < count; i++) { - enc_rval.encoded = 0; - if (*cap_req->list.array[i] == LTE_RAT_Type_nr) { - asn1cSeqAdd(&ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list, - &ue_CapabilityRAT_Container); - ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.array[i]->rat_Type = LTE_RAT_Type_nr; - asn_enc_rval_t enc_rval_nr = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message, NULL, (void *) &ul_dcch_msg, buffer, sizeof(buffer)); - AssertFatal (enc_rval_nr.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", - enc_rval_nr.failed_type->name, enc_rval_nr.encoded); - enc_rval.encoded = enc_rval.encoded + enc_rval_nr.encoded; - xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg); - LOG_A(RRC, "%s: NR_UECapInfo LTE_RAT_Type_nr Encoded %zd bits (%zd bytes)\n", - __FUNCTION__, enc_rval.encoded, (enc_rval.encoded+7)/8); - } - else if (*cap_req->list.array[i] == LTE_RAT_Type_eutra_nr) { - asn1cSeqAdd(&ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list, - &ue_CapabilityRAT_Container_mrdc); - ue_cap->criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list.array[i]->rat_Type = LTE_RAT_Type_eutra_nr; - asn_enc_rval_t enc_rval_eutra_nr = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message, NULL, (void *) &ul_dcch_msg, buffer, sizeof(buffer)); - AssertFatal (enc_rval_eutra_nr.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", - enc_rval_eutra_nr.failed_type->name, enc_rval_eutra_nr.encoded); - enc_rval.encoded = enc_rval.encoded + enc_rval_eutra_nr.encoded; - xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg); - LOG_A(RRC, "%s: NR_UECapInfo LTE_RAT_Type_eutra_nr Encoded %zd bits (%zd bytes)\n", - __FUNCTION__, enc_rval.encoded, (enc_rval.encoded+7)/8); - } - rrc_data_req_ue ( - ctxt_pP, - DCCH, - rrc_mui++, - SDU_CONFIRM_NO, - (enc_rval.encoded + 7) / 8, - buffer, - PDCP_TRANSMISSION_MODE_CONTROL); - } -} - - - //----------------------------------------------------------------------------- void rrc_ue_process_ueCapabilityEnquiry( @@ -1861,57 +1724,9 @@ rrc_ue_process_ueCapabilityEnquiry( buffer, PDCP_TRANSMISSION_MODE_CONTROL); } - else if (*UECapabilityEnquiry->criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest.list.array[i] - == LTE_RAT_Type_nr) { - asn1cSeqAdd( - &ul_dcch_msg.message.choice.c1.choice.ueCapabilityInformation.criticalExtensions.choice.c1.choice.ueCapabilityInformation_r8.ue_CapabilityRAT_ContainerList.list, - &ue_CapabilityRAT_Container); - enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_UL_DCCH_Message, NULL, (void *) &ul_dcch_msg, buffer, 100); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - - if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { - xer_fprint(stdout, &asn_DEF_LTE_UL_DCCH_Message, (void *)&ul_dcch_msg); - } - - LOG_A(RRC, "%s: NR_UECapabilityInformation Encoded %zd bits (%zd bytes)\n", - __FUNCTION__, enc_rval.encoded,(enc_rval.encoded+7)/8); - rrc_data_req_ue ( - ctxt_pP, - DCCH, - rrc_mui++, - SDU_CONFIRM_NO, - (enc_rval.encoded + 7) / 8, - buffer, - PDCP_TRANSMISSION_MODE_CONTROL); - } } } -static bool is_nr_r15_config_present(LTE_RRCConnectionReconfiguration_r8_IEs_t *c) -{ -#define NCE nonCriticalExtension -#define chk(x) do { \ - if ((x) == NULL) { \ - LOG_I(RRC, "NULL at %d\n", __LINE__); \ - return false; \ - } \ -} while(0) - chk(c); - chk(c->NCE); - chk(c->NCE->NCE); - chk(c->NCE->NCE->NCE); - chk(c->NCE->NCE->NCE->NCE); - chk(c->NCE->NCE->NCE->NCE->NCE); - chk(c->NCE->NCE->NCE->NCE->NCE->NCE); - chk(c->NCE->NCE->NCE->NCE->NCE->NCE->NCE); - chk(c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE); - return c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->nr_Config_r15->present == - LTE_RRCConnectionReconfiguration_v1510_IEs__nr_Config_r15_PR_setup; - -#undef NCE -#undef chk -} /** \brief process the received rrcConnectionReconfiguration message at UE \param ctxt_pP Running context \param *rrcConnectionReconfiguration pointer to the sturcture @@ -1932,42 +1747,6 @@ static void rrc_ue_process_rrcConnectionReconfiguration(const protocol_ctxt_t *c criticalExtensions.choice.c1. choice.rrcConnectionReconfiguration_r8; - if (is_nr_r15_config_present(r_r8)) { - OCTET_STRING_t *nr_RadioBearer = r_r8->nonCriticalExtension->nonCriticalExtension-> - nonCriticalExtension->nonCriticalExtension->nonCriticalExtension-> - nonCriticalExtension->nonCriticalExtension->nonCriticalExtension-> - nr_RadioBearerConfig1_r15; - OCTET_STRING_t *nr_SecondaryCellGroup = r_r8->nonCriticalExtension->nonCriticalExtension-> - nonCriticalExtension->nonCriticalExtension->nonCriticalExtension-> - nonCriticalExtension->nonCriticalExtension->nonCriticalExtension-> - nr_Config_r15->choice.setup.nr_SecondaryCellGroupConfig_r15; - uint32_t total_size = nr_RadioBearer->size + nr_SecondaryCellGroup->size; - struct msg { - uint32_t RadioBearer_size; - uint32_t SecondaryCellGroup_size; - uint8_t trans_id; - uint8_t padding[3]; - uint8_t *buffer; - } msg; - - msg.buffer = calloc(total_size, sizeof(*msg.buffer)); - AssertFatal(msg.buffer != NULL, "Error in memory allocation\n"); - msg.RadioBearer_size = nr_RadioBearer->size; - msg.SecondaryCellGroup_size = nr_SecondaryCellGroup->size; - msg.trans_id = rrcConnectionReconfiguration->rrc_TransactionIdentifier; - memcpy(msg.buffer, nr_RadioBearer->buf, nr_RadioBearer->size); - memcpy(msg.buffer + nr_RadioBearer->size, nr_SecondaryCellGroup->buf, nr_SecondaryCellGroup->size); - - LOG_D(RRC, "nr_RadioBearerConfig1_r15 size %ld nr_SecondaryCellGroupConfig_r15 size %ld, sizeof(msg) = %zu\n", - nr_RadioBearer->size, - nr_SecondaryCellGroup->size, - sizeof(msg)); - - nsa_sendmsg_to_nrue(&msg, sizeof(msg), RRC_CONFIG_COMPLETE_REQ); - free(msg.buffer); - LOG_A(RRC, "Sent RRC_CONFIG_COMPLETE_REQ to the NR UE\n"); - } - if (r_r8->mobilityControlInfo) { LOG_I(RRC,"Mobility Control Information is present\n"); rrc_ue_process_mobilityControlInfo( @@ -2483,52 +2262,7 @@ static void rrc_ue_decode_dcch(const protocol_ctxt_t *const ctxt_pP, ctxt_pP->module_id, eNB_indexP); - LTE_UE_CapabilityRequest_t *ue_cap = &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry.criticalExtensions. - choice.c1.choice.ueCapabilityEnquiry_r8.ue_CapabilityRequest; - bool have_received_nrue_cap = false; - for (int i = 0; i < ue_cap->list.count; i++) { - if (*ue_cap->list.array[i] == LTE_RAT_Type_nr || *ue_cap->list.array[i] == LTE_RAT_Type_eutra_nr) { - have_received_nrue_cap = true; - break; - } - } - if (have_received_nrue_cap) { - LTE_UECapabilityEnquiry_t *ueCapabilityEnquiry_nsa = &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry; - OCTET_STRING_t * requestedFreqBandsNR = ueCapabilityEnquiry_nsa-> - criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.nonCriticalExtension-> - nonCriticalExtension->nonCriticalExtension->nonCriticalExtension-> - nonCriticalExtension->requestedFreqBandsNR_MRDC_r15; - nsa_sendmsg_to_nrue(requestedFreqBandsNR->buf, requestedFreqBandsNR->size, NRUE_CAPABILITY_ENQUIRY); - LOG_A(RRC, "Second ueCapabilityEnquiry (request for NR capabilities) sent to NR UE with size %zu\n", - requestedFreqBandsNR->size); - // Save ueCapabilityEnquiry so we can use in nsa mode after nrUE response is received - UE_RRC_INFO *info = &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP]; - if (info->dl_dcch_msg != NULL) { - info->dl_dcch_msg = NULL; - } - info->dl_dcch_msg = dl_dcch_msg; - dl_dcch_msg = NULL; - } else if (get_softmodem_params()->nsa && !have_received_nrue_cap) { - LTE_UECapabilityEnquiry_t *ueCapabilityEnquiry_nsa = &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry; - OCTET_STRING_t * requestedFreqBandsNR = ueCapabilityEnquiry_nsa-> - criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.nonCriticalExtension-> - nonCriticalExtension->nonCriticalExtension->nonCriticalExtension-> - nonCriticalExtension->requestedFreqBandsNR_MRDC_r15; - nsa_sendmsg_to_nrue(requestedFreqBandsNR->buf, requestedFreqBandsNR->size, UE_CAPABILITY_ENQUIRY); - LOG_A(RRC, "Initial ueCapabilityEnquiry sent to NR UE with size %zu\n", requestedFreqBandsNR->size); - // Save ueCapabilityEnquiry so we can use in nsa mode after nrUE response is received - UE_RRC_INFO *info = &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP]; - if (info->dl_dcch_msg != NULL) { - info->dl_dcch_msg = NULL; - } - info->dl_dcch_msg = dl_dcch_msg; - dl_dcch_msg = NULL; - } else { - rrc_ue_process_ueCapabilityEnquiry( - ctxt_pP, - &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry, - eNB_indexP); - } + rrc_ue_process_ueCapabilityEnquiry(ctxt_pP, &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry, eNB_indexP); break; case LTE_DL_DCCH_MessageType__c1_PR_counterCheck: @@ -2892,9 +2626,13 @@ int decode_BCCH_DLSCH_Message( if ((ctxt_pP->frame % 2) == 0) { // even frame if ((UE_rrc_inst[ctxt_pP->module_id].Info[eNB_index].SIStatus&1) == 0) { + if (!UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]) { + LOG_E(PHY,"UE_rrc_inst[%d].sib1[%d] is null, allocating\n", ctxt_pP->module_id, eNB_index); + openair_rrc_ue_init(ctxt_pP->module_id, eNB_index); + } LTE_SystemInformationBlockType1_t *sib1 = UE_rrc_inst[ctxt_pP->module_id].sib1[eNB_index]; - memcpy( (void *)sib1, - (void *)&bcch_message->message.choice.c1.choice.systemInformationBlockType1, + memcpy( sib1, + &bcch_message->message.choice.c1.choice.systemInformationBlockType1, sizeof(LTE_SystemInformationBlockType1_t) ); LOG_D( RRC, "[UE %"PRIu8"] Decoding First SIB1\n", ctxt_pP->module_id ); decode_SIB1( ctxt_pP, eNB_index, rsrq, rsrp ); @@ -4281,43 +4019,6 @@ void ue_meas_filtering( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_ } } } -//Below routine implements Measurement Reporting procedure from 36.331 Section 5.5.5 -//----------------------------------------------------------------------------- -void rrc_ue_generate_nrMeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t eNB_index ) { - uint8_t buffer[RRC_BUF_SIZE]; - UE_RRC_INST *ue = &UE_rrc_inst[ctxt_pP->module_id]; - uint8_t target_eNB_offset = ue->Info[0].handoverTarget; - LTE_PhysCellId_t targetCellId = ue->HandoverInfoUe.targetCellId; - - for (int i = 0; i < MAX_MEAS_ID; i++) { - if (ue->measReportList[eNB_index][i] != NULL) { - LTE_MeasId_t measId = ue->measReportList[eNB_index][i]->measId; - long rsrp_s = binary_search_float(RSRP_meas_mapping, 98, ue->rsrp_db_filtered[eNB_index]); - long rsrq_s = binary_search_float(RSRQ_meas_mapping, 35, ue->rsrq_db_filtered[eNB_index]); - long rsrp_tar = binary_search_float(RSRP_meas_mapping, 98, ue->rsrp_db_filtered[target_eNB_offset]); - long rsrq_tar = binary_search_float(RSRQ_meas_mapping, 35, ue->rsrq_db_filtered[target_eNB_offset]); - - LOG_I(RRC,"[UE %d] Frame %d: source eNB: %d target eNB: %d servingCell(%d) targetCell(%ld)\n", - ctxt_pP->module_id, - ctxt_pP->frame, - eNB_index, - target_eNB_offset, - get_adjacent_cell_id(ctxt_pP->module_id, eNB_index), - targetCellId); - - if (ctxt_pP->frame != 0) { - LOG_I(RRC, "measId %ld, targetCellId %ld, rsrp_s %ld, rsrq_s %ld, rsrp_t %ld, rsrq_t %ld\n", - measId, targetCellId, rsrp_s, rsrq_s, rsrp_tar, rsrq_tar); - ssize_t size = do_nrMeasurementReport(buffer, sizeof(buffer), measId, targetCellId, rsrp_s, rsrq_s, rsrp_tar, rsrq_tar); - AssertFatal(size >= 0, "do_nrMeasurementReport failed \n"); - LOG_I(RRC, "[UE %d] Frame %d : Generating Measurement Report for eNB %d\n", - ctxt_pP->module_id, ctxt_pP->frame, eNB_index); - const bool result = pdcp_data_req(ctxt_pP, SRB_FLAG_YES, DCCH, rrc_mui++, 0, size, buffer, PDCP_TRANSMISSION_MODE_DATA,NULL, NULL); - AssertFatal (result == true, "PDCP data request failed!\n"); - } - } - } -} //Below routine implements Measurement Reporting procedure from 36.331 Section 5.5.5 //----------------------------------------------------------------------------- @@ -4391,39 +4092,6 @@ void rrc_ue_generate_MeasurementReport(protocol_ctxt_t *const ctxt_pP, uint8_t e } } -static bool does_rrcConnReconfig_have_nr(const UE_RRC_INST *ue) { - for (int i = 0; i < NB_CNX_UE; i++) { - for (int j = 0; j < MAX_MEAS_ID; j++) { - LTE_ReportConfigId_t reportConfigId = ue->MeasId[i][j]->reportConfigId; - AssertFatal(reportConfigId >= 1 && reportConfigId <= MAX_MEAS_CONFIG, "Bad index\n"); - const LTE_ReportConfigToAddMod_t *rc = ue->ReportConfig[i][reportConfigId-1]; - if (rc == NULL) { - LOG_D(RRC, "UE_rrc_inst[ctxt_pP->module_id]->ReportConfig[%d][%ld] = NULL\n", i, reportConfigId-1); - continue; - } - if (rc->reportConfig.present != LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigInterRAT) { - LOG_D(RRC, "reportConfig.present = %d, not LTE_ReportConfigToAddMod__reportConfig_PR_reportConfigInterRAT\n", - rc->reportConfig.present); - continue; - } - LTE_ReportConfigInterRAT_t irat = rc->reportConfig.choice.reportConfigInterRAT; - if (irat.triggerType.present != LTE_ReportConfigInterRAT__triggerType_PR_event) { - LOG_D(RRC, "irat.triggerType.present = %d, not LTE_ReportConfigInterRAT__triggerType_PR_event\n", - irat.triggerType.present); - continue; - } - if (irat.triggerType.choice.event.eventId.present != LTE_ReportConfigInterRAT__triggerType__event__eventId_PR_eventB1_NR_r15) { - LOG_D(RRC, "irat.triggerType.choice.event.eventId.present = %d\n", - irat.triggerType.choice.event.eventId.present); - continue; - } - return true; - } - } - return false; -} - - // Measurement report triggering, described in 36.331 Section 5.5.4.1: called periodically //----------------------------------------------------------------------------- void ue_measurement_report_triggering(protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index ) { @@ -4524,49 +4192,6 @@ void ue_measurement_report_triggering(protocol_ctxt_t *const ctxt_pP, const uint } } } - - if (ue->MeasObj[i][measObjId-1]->measObject.present == LTE_MeasObjectToAddMod__measObject_PR_measObjectNR_r15) { - if (!does_rrcConnReconfig_have_nr(ue)) - break; - LTE_ReportConfigInterRAT_t *rc = &ue->ReportConfig[i][reportConfigId-1]->reportConfig.choice.reportConfigInterRAT; - LTE_TimeToTrigger_t trig_per = rc->triggerType.choice.event.timeToTrigger; - ttt_ms = timeToTrigger_ms[trig_per]; - LOG_D(RRC, "[UE %d] Frame %d: B1_NR_r15 event. count %d, ttt %ld\n", - ctxt_pP->module_id, ctxt_pP->frame, ue->subframeCount, ttt_ms); - if (ue->subframeCount < ttt_ms) { - ++ue->subframeCount; - break; - } - ue->subframeCount = 0; - bool is_state_connected = false; - bool is_t304_inactive = false; - bool have_meas_flag = false; - if (ue->Info[0].State >= RRC_CONNECTED) - is_state_connected = true; - if (ue->Info[0].T304_active == 0) - is_t304_inactive = true; - if (ue->HandoverInfoUe.measFlag == 1) - have_meas_flag = true; - - if (is_state_connected && is_t304_inactive && have_meas_flag) { - LOG_I(RRC,"[UE %d] Frame %d: Triggering generation of Meas Report for NR_r15. count = %d\n", - ctxt_pP->module_id, ctxt_pP->frame, ue->subframeCount); - if (ue->measReportList[i][j] == NULL) { - ue->measReportList[i][j] = malloc(sizeof(MEAS_REPORT_LIST)); - } - ue->measReportList[i][j]->measId = ue->MeasId[i][j]->measId; - ue->measReportList[i][j]->numberOfReportsSent = 0; - rrc_ue_generate_nrMeasurementReport(ctxt_pP, eNB_index); - ue->HandoverInfoUe.measFlag = 1; - LOG_I(RRC,"[UE %d] Frame %d: RSRB detected, state: %d \n", - ctxt_pP->module_id, ctxt_pP->frame, ue->Info[0].State); - } else { - if(ue->measReportList[i][j] != NULL) { - free(ue->measReportList[i][j]); - } - ue->measReportList[i][j] = NULL; - } - } } } } @@ -4966,38 +4591,6 @@ void *rrc_ue_task( void *args_p ) { break; } - case RRC_NRUE_CAP_INFO_IND: - { - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, RRC_NRUE_CAP_INFO_IND (msg_p).module_id, - ENB_FLAG_NO, RRC_NRUE_CAP_INFO_IND (msg_p).rnti, - RRC_NRUE_CAP_INFO_IND (msg_p).frame, - 0, - RRC_NRUE_CAP_INFO_IND (msg_p).eNB_index); - LOG_I(RRC, "[UE %d] Received %s. Now calling rrc_ue_process_nrueCapabilityEnquiry\n", - ue_mod_id, ITTI_MSG_NAME (msg_p)); - rrc_nrue_cap_info_t *nrue_cap_info = (void *)RRC_NRUE_CAP_INFO_IND (msg_p).sdu_p; - AssertFatal(RRC_NRUE_CAP_INFO_IND (msg_p).sdu_size == sizeof(*nrue_cap_info), "Size of nrue_cap_info incorrect\n"); - rrc_ue_process_nrueCapabilityEnquiry( - &ctxt, - &nrue_cap_info->dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry, - nrue_cap_info, - RRC_NRUE_CAP_INFO_IND (msg_p).eNB_index); - SEQUENCE_free(&asn_DEF_LTE_DL_DCCH_Message, nrue_cap_info->dl_dcch_msg, ASFM_FREE_EVERYTHING); - result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), RRC_NRUE_CAP_INFO_IND (msg_p).sdu_p); - AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); - break; - } - case NAS_OAI_TUN_NSA: - { - LOG_D(NAS, "Received %s: length %lu. About to send this to the NR UE\n", ITTI_MSG_NAME (msg_p), - sizeof(NAS_OAI_TUN_NSA (msg_p).buffer)); - char buffer[RRC_BUF_SIZE]; - memcpy(buffer, NAS_OAI_TUN_NSA(msg_p).buffer, sizeof(buffer)); - nsa_sendmsg_to_nrue(buffer, sizeof(buffer), OAI_TUN_IFACE_NSA); - break; - } - - case NAS_KENB_REFRESH_REQ: memcpy((void *)UE_rrc_inst[ue_mod_id].kenb, (void *)NAS_KENB_REFRESH_REQ(msg_p).kenb, sizeof(UE_rrc_inst[ue_mod_id].kenb)); LOG_D(RRC, "[UE %d] Received %s: refreshed RRC::KeNB = " @@ -5327,8 +4920,7 @@ openair_rrc_top_init_ue( memset (UE_rrc_inst, 0, NB_UE_INST * sizeof(UE_RRC_INST)); LOG_D(RRC, "ALLOCATE %d Bytes for UE_RRC_INST @ %p\n", (unsigned int)(NB_UE_INST*sizeof(UE_RRC_INST)), UE_rrc_inst); // fill UE capability - bool received_nr_msg = false; - UECap = fill_ue_capability (uecap_xer, received_nr_msg); + UECap = fill_ue_capability (uecap_xer); for (module_id = 0; module_id < NB_UE_INST; module_id++) { UE_rrc_inst[module_id].UECap = UECap; @@ -6401,233 +5993,3 @@ rrc_rx_tx_ue( VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_RX_TX,VCD_FUNCTION_OUT); return (RRC_OK); } - -void *recv_msgs_from_nr_ue(void *args_p) -{ - itti_mark_task_ready (TASK_RRC_NSA_UE); - for (;;) - { - nsa_msg_t msg; - int recvLen = recvfrom(from_nr_ue_fd, &msg, sizeof(msg), - MSG_WAITALL | MSG_TRUNC, NULL, NULL); - if (recvLen == -1) - { - LOG_E(RRC, "%s: recvfrom: %s\n", __func__, strerror(errno)); - continue; - } - if (recvLen > sizeof(msg)) - { - LOG_E(NR_RRC, "%s: Received a truncated message %d\n", __func__, recvLen); - continue; - } - LOG_D(RRC, "We have received a %d msg (%d bytes). Calling process_nr_nsa_msg\n", msg.msg_type, recvLen); - process_nr_nsa_msg(&msg, recvLen); - } - -} - -void nsa_sendmsg_to_nrue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type) -{ - LOG_I(RRC, "Entered %s \n", __FUNCTION__); - nsa_msg_t n_msg; - if (msg_len > sizeof(n_msg.msg_buffer)) - { - LOG_E(RRC, "%s: message too big: %zu\n", __func__, msg_len); - abort(); - } - n_msg.msg_type = msg_type; - memcpy(n_msg.msg_buffer, message, msg_len); - size_t to_send = sizeof(n_msg.msg_type) + msg_len; - - struct sockaddr_in sa = - { - .sin_family = AF_INET, - .sin_port = htons(6008 + ue_id_g * 2), - }; - int sent = sendto(to_nr_ue_fd, &n_msg, to_send, 0, - (struct sockaddr *)&sa, sizeof(sa)); - if (sent == -1) - { - LOG_E(RRC, "%s: sendto: %s\n", __func__, strerror(errno)); - return; - } - if (sent != to_send) - { - LOG_E(RRC, "%s: Short send %d != %zu\n", __func__, sent, to_send); - return; - } - LOG_I(RRC, "Sent a %d message to the nrUE (%d bytes) \n", msg_type, sent); -} - -void init_connections_with_nr_ue() -{ - struct sockaddr_in sa = - { - .sin_family = AF_INET, - .sin_port = htons(6007 + ue_id_g * 2), - }; - AssertFatal(from_nr_ue_fd == -1, "from_nr_ue_fd was assigned already"); - from_nr_ue_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (from_nr_ue_fd == -1) - { - LOG_E(RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, from_nr_ue_fd, errno, strerror(errno)); - abort(); - } - - if (inet_aton(nsa_ipaddr, &sa.sin_addr) == 0) - { - LOG_E(RRC, "Bad nsa_ipaddr '%s'\n", nsa_ipaddr); - abort(); - } - - if (bind(from_nr_ue_fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) - { - LOG_E(RRC,"%s: Failed to bind the socket\n", __FUNCTION__); - abort(); - } - - AssertFatal(to_nr_ue_fd == -1, "to_nr_ue_fd was assigned already"); - to_nr_ue_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (to_nr_ue_fd == -1) - { - LOG_E(RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, to_nr_ue_fd, errno, strerror(errno)); - abort(); - } - -} - -void process_nr_nsa_msg(nsa_msg_t *msg, int msg_len) -{ - if (msg_len < sizeof(msg->msg_type)) - { - LOG_E(RRC, "Msg_len = %d\n", msg_len); - return; - } - LOG_D(RRC, "We are processing an NSA message %d \n", msg->msg_type); - Rrc_Msg_Type_t msg_type = msg->msg_type; - uint8_t *const msg_buffer = msg->msg_buffer; - msg_len -= sizeof(msg->msg_type); - bool received_nr_msg = true; - protocol_ctxt_t ctxt; - module_id_t module_id = 0; - eNB_index_t eNB_index = 0; - - switch (msg_type) - { - case NRUE_CAPABILITY_INFO: - { - LOG_I(RRC, "Create itti msg to send received NRUE_CAPABILITY_INFO to eNB\n"); - - MessageDef *message_p; - rrc_nrue_cap_info_t *nrue_cap_buf = itti_malloc (TASK_RRC_NSA_UE, - TASK_RRC_UE, - sizeof(rrc_nrue_cap_info_t)); - AssertFatal(msg_len <= sizeof(nrue_cap_buf->mesg), "msg_len = %d\n", msg_len); - memcpy(nrue_cap_buf->mesg, msg_buffer, msg_len); - nrue_cap_buf->mesg_len = msg_len; - UE_RRC_INFO *info = &UE_rrc_inst[module_id].Info[eNB_index]; - nrue_cap_buf->dl_dcch_msg = info->dl_dcch_msg; - info->dl_dcch_msg = NULL; - message_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_NRUE_CAP_INFO_IND); - RRC_NRUE_CAP_INFO_IND (message_p).sdu_p = (void *)nrue_cap_buf; - RRC_NRUE_CAP_INFO_IND (message_p).sdu_size = sizeof(*nrue_cap_buf); - RRC_NRUE_CAP_INFO_IND (message_p).module_id = module_id; - RRC_NRUE_CAP_INFO_IND (message_p).rnti = info->rnti; - RRC_NRUE_CAP_INFO_IND (message_p).eNB_index = eNB_index; - itti_send_msg_to_task (TASK_RRC_UE, 0, message_p); - LOG_I(RRC, "Sent itti RRC_NRUE_CAP_INFO_IND\n"); - break; - } - case UE_CAPABILITY_DUMMY: - { - fill_ue_capability(NULL, received_nr_msg); - UE_rrc_inst[module_id].UECap = UE_rrc_inst->UECap; - if (!is_en_dc_supported(UE_rrc_inst->UECap->UE_EUTRA_Capability)) - { - LOG_E(RRC, "en_dc is NOT supported! Not sending RRC_DCCH_DATA_COPY_IND to update UE_Capability_INFO\n"); - break; - } - - LOG_I(RRC, "Send itti msg to trigger processing of capabilites b/c we have a UE_CAPABILITY_DUMMY\n"); - MessageDef *message_p; - rrc_dcch_data_copy_t *dl_dcch_buffer = itti_malloc (TASK_RRC_NSA_UE, - TASK_RRC_UE, - sizeof(rrc_dcch_data_copy_t)); - UE_RRC_INFO *info = &UE_rrc_inst[module_id].Info[eNB_index]; - dl_dcch_buffer->dl_dcch_msg = info->dl_dcch_msg; - info->dl_dcch_msg = NULL; - message_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_DCCH_DATA_COPY_IND); - RRC_DCCH_DATA_COPY_IND (message_p).sdu_p = (void *)dl_dcch_buffer; - RRC_DCCH_DATA_COPY_IND (message_p).sdu_size = sizeof(rrc_dcch_data_copy_t); - RRC_DCCH_DATA_COPY_IND (message_p).module_id = module_id; - RRC_DCCH_DATA_COPY_IND (message_p).rnti = info->rnti; - RRC_DCCH_DATA_COPY_IND (message_p).eNB_index = eNB_index; - itti_send_msg_to_task (TASK_RRC_UE, 0, message_p); - LOG_I(RRC, "Sent itti RRC_DCCH_DATA_COPY_IND\n"); - break; - } - - case NR_UE_RRC_MEASUREMENT: - { - nfapi_p7_message_header_t header; - if (nfapi_p7_message_header_unpack((void *)msg_buffer, msg_len, &header, sizeof(header), NULL) < 0) - { - LOG_E(MAC, "Header unpack failed in %s \n", __FUNCTION__); - break; - } - if (header.message_id != NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST) - { - LOG_E(MAC, "%s: Unexpected nfapi message type: %d\n", __FUNCTION__, header.message_id); - break; - } - - nfapi_nr_dl_tti_request_t dl_tti_request; - int unpack_len = nfapi_nr_p7_message_unpack((void *)msg_buffer, - msg_len, - &dl_tti_request, - sizeof(nfapi_nr_dl_tti_request_t), - NULL); - if (unpack_len < 0) - { - LOG_E(RRC, "%s: SSB PDU unpack failed \n", __FUNCTION__); - break; - } - int num_pdus = dl_tti_request.dl_tti_request_body.nPDUs; - if (num_pdus <= 0) - { - LOG_E(RRC, "%s: dl_tti_request number of PDUS <= 0\n", __FUNCTION__); - abort(); - } - for (int i = 0; i < num_pdus; i++) - { - nfapi_nr_dl_tti_request_pdu_t *pdu_list = &dl_tti_request.dl_tti_request_body.dl_tti_pdu_list[i]; - if (pdu_list->PDUType == NFAPI_NR_DL_TTI_SSB_PDU_TYPE) - { - LOG_I(RRC, "Got an NR_UE_RRC_MEASUREMENT. pdulist[%d].ssbRsrp = %d\n", - i, pdu_list->ssb_pdu.ssb_pdu_rel15.ssbRsrp); - } - } - break; - } - - case NR_RRC_CONFIG_COMPLETE_REQ: - { - LOG_I(RRC, "Got an NR_RRC_CONFIG_COMPLETE_REQ. Now make octet string and call below!\n"); - OCTET_STRING_t rrcConfigurationComplete; - memset(&rrcConfigurationComplete, 0, sizeof(rrcConfigurationComplete)); - OCTET_STRING_fromBuf(&rrcConfigurationComplete, - (const char *)msg_buffer, - msg_len); - UE_RRC_INFO *info = &UE_rrc_inst[module_id].Info[eNB_index]; - uint8_t t_id = info->dl_dcch_msg->message.choice.c1.choice. - rrcConnectionReconfiguration.rrc_TransactionIdentifier; - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_id, - ENB_FLAG_NO, info->rnti, - 0, 0, eNB_index); - rrc_ue_generate_RRCConnectionReconfigurationComplete(&ctxt, ctxt.eNB_index, t_id, &rrcConfigurationComplete); - break; - } - default: - LOG_E(RRC, "No NSA Message Found\n"); - } -} diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index 8d0fd2f8ed..4ddd7fc625 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -6354,7 +6354,7 @@ rrc_eNB_decode_dcch( /*NN: revise the condition */ /*FK: left the condition as is for the case MME is used (S1 mode) but setting dedicated_DRB = 1 otherwise (noS1 mode) so that no second RRCReconfiguration message activationg more DRB is sent as this causes problems with the nasmesh driver.*/ - if (!IS_SOFTMODEM_NOS1 || get_softmodem_params()->emulate_l1) { + if (!IS_SOFTMODEM_NOS1) { if (ue_context_p->ue_context.StatusRrc == RRC_RECONFIGURED) { dedicated_DRB = 1; LOG_I(RRC, @@ -7721,9 +7721,6 @@ void *rrc_enb_process_itti_msg(void *notUsed) { case X2AP_HANDOVER_REQ_ACK: { struct rrc_eNB_ue_context_s *ue_context_p = NULL; - x2ap_handover_req_ack_t *x2ap_handover_req_ack = NULL; - hashtable_rc_t hash_rc = HASH_TABLE_KEY_NOT_EXISTS; - gtpv1u_ue_data_t *gtpv1u_ue_data_p = NULL; ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], X2AP_HANDOVER_REQ_ACK(msg_p).rnti); if (ue_context_p == NULL) { @@ -7738,40 +7735,6 @@ void *rrc_enb_process_itti_msg(void *notUsed) { if (ue_context_p->ue_context.handover_info->state != HO_REQUEST) abort(); - hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, ue_context_p->ue_context.rnti, (void **)>pv1u_ue_data_p); - - /* set target enb gtp teid */ - if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { - LOG_E(RRC, "X2AP_HANDOVER_REQ_ACK func(), hashtable_get failed: while getting ue rnti %x in hashtable ue_mapping\n", ue_context_p->ue_context.rnti); - } else { - uint8_t nb_e_rabs_tobesetup = 0; - ebi_t eps_bearer_id = 0; - int ip_offset = 0; - in_addr_t in_addr; - x2ap_handover_req_ack = &X2AP_HANDOVER_REQ_ACK(msg_p); - nb_e_rabs_tobesetup = x2ap_handover_req_ack->nb_e_rabs_tobesetup; - ue_context_p->ue_context.nb_x2u_e_rabs = nb_e_rabs_tobesetup; - - for (int i = 0; i < nb_e_rabs_tobesetup; i++) { - ip_offset = 0; - eps_bearer_id = x2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id; - ue_context_p->ue_context.enb_gtp_x2u_ebi[i] = eps_bearer_id; - ue_context_p->ue_context.enb_gtp_x2u_teid[i] = x2ap_handover_req_ack->e_rabs_tobesetup[i].gtp_teid; - gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_teNB = x2ap_handover_req_ack->e_rabs_tobesetup[i].gtp_teid; - - if ((x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 4) || (x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 20)) { - in_addr = *((in_addr_t *)x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.buffer); - ip_offset = 4; - gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr = in_addr; - ue_context_p->ue_context.enb_gtp_x2u_addrs[i] = x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr; - } - - if ((x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 16) || (x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 20)) { - memcpy(gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip6_addr.s6_addr, &x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.buffer[ip_offset], 16); - } - } - } - rrc_eNB_process_handoverCommand(instance, ue_context_p, &X2AP_HANDOVER_REQ_ACK(msg_p)); ue_context_p->ue_context.handover_info->state = HO_PREPARE; break; diff --git a/openair2/RRC/LTE/rrc_proto.h b/openair2/RRC/LTE/rrc_proto.h index 38ba42b251..261e6a9960 100644 --- a/openair2/RRC/LTE/rrc_proto.h +++ b/openair2/RRC/LTE/rrc_proto.h @@ -331,12 +331,6 @@ void *rrc_enb_task(void *args_p); \param args_p Pointer on arguments to start the task. */ void *rrc_ue_task(void *args_p); -/**\brief RRC NSA UE task. - \param args_p Pointer on arguments to start the task. */ -void *recv_msgs_from_nr_ue(void *args_p); - -void init_connections_with_nr_ue(void); - void rrc_eNB_process_x2_setup_request(int mod_id, x2ap_setup_req_t *m); void rrc_eNB_process_x2_setup_response(int mod_id, x2ap_setup_resp_t *m); diff --git a/openair2/RRC/NR/CMakeLists.txt b/openair2/RRC/NR/CMakeLists.txt index 7537bd661d..658bfeee5a 100644 --- a/openair2/RRC/NR/CMakeLists.txt +++ b/openair2/RRC/NR/CMakeLists.txt @@ -1 +1,5 @@ add_subdirectory(MESSAGES) + +if(ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index ad973bdc5f..35b21a9722 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -64,6 +64,10 @@ #include "NR_LogicalChannelConfig.h" #include "NR_PDCP-Config.h" #include "NR_MAC-CellGroupConfig.h" +#include "NR_HandoverPreparationInformation.h" +#include "NR_HandoverCommand.h" +#include "NR_HandoverCommand-IEs.h" +#include "NR_AS-Config.h" #include "NR_SecurityModeCommand.h" #include "NR_CipheringAlgorithm.h" #include "NR_RRCReconfiguration-IEs.h" @@ -82,6 +86,8 @@ #include "NR_UE-CapabilityRequestFilterNR.h" #include "NR_HandoverPreparationInformation.h" #include "NR_HandoverPreparationInformation-IEs.h" +#include "NR_HandoverCommand.h" +#include "NR_UE-CapabilityRAT-ContainerList.h" #include "common/utils/nr/nr_common.h" #if defined(NR_Rel16) #include "NR_SCS-SpecificCarrier.h" @@ -197,6 +203,48 @@ int xer_nr_sprint(char *string, size_t string_size, asn_TYPE_descriptor_t *td, v return er.encoded; } +struct NR_UE_NR_Capability *get_ue_nr_capability(int rnti, uint8_t *buf, uint32_t len) +{ + if (!buf || len == 0) return NULL; + + NR_UE_CapabilityRAT_ContainerList_t *clist = NULL; + asn_dec_rval_t rval = uper_decode(NULL, &asn_DEF_NR_UE_CapabilityRAT_ContainerList, + (void **)&clist, buf, len, 0, 0); + + if (rval.code != RC_OK) { + LOG_W(NR_MAC, "UE RNTI %04x: Failed to decode container list\n", rnti); + return NULL; + } + + NR_UE_NR_Capability_t *cap = decode_nr_ue_capability(rnti, clist); + ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, clist); + return cap; +} + +NR_UE_NR_Capability_t *decode_nr_ue_capability(int rnti, const NR_UE_CapabilityRAT_ContainerList_t *clist) +{ + if (!clist) return NULL; + + for (int i = 0; i < clist->list.count; i++) { + const NR_UE_CapabilityRAT_Container_t *c = clist->list.array[i]; + if (c->rat_Type != NR_RAT_Type_nr) + continue; + + NR_UE_NR_Capability_t *cap = NULL; + asn_dec_rval_t rval = uper_decode(NULL, &asn_DEF_NR_UE_NR_Capability, + (void **)&cap, + c->ue_CapabilityRAT_Container.buf, + c->ue_CapabilityRAT_Container.size, + 0, 0); + if (rval.code == RC_OK) + return cap; + + LOG_W(NR_MAC, "UE RNTI %04x: Failed to decode NR capability (%zu bytes)\n", rnti, rval.consumed); + ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, cap); + } + return NULL; +} + //------------------------------------------------------------------------------ int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc) @@ -248,7 +296,7 @@ int do_RRCReject(uint8_t *const buffer) rrcReject->criticalExtensions.choice.rrcReject = CALLOC(1, sizeof(struct NR_RRCReject_IEs)); rrcReject->criticalExtensions.choice.rrcReject->waitTime = CALLOC(1, sizeof(NR_RejectWaitTime_t)); - *rrcReject->criticalExtensions.choice.rrcReject->waitTime = 1; + *rrcReject->criticalExtensions.choice.rrcReject->waitTime = 10; rrcReject->criticalExtensions.present = NR_RRCReject__criticalExtensions_PR_rrcReject; @@ -271,51 +319,6 @@ int do_RRCReject(uint8_t *const buffer) return (enc_rval.encoded + 7) / 8; } -/* returns a default radio bearer config suitable for NSA etc */ -NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, - int rb_id, - e_NR_CipheringAlgorithm ciphering_algorithm, - e_NR_SecurityConfig__keyToUse key_to_use, - const nr_pdcp_configuration_t *pdcp_config) -{ - NR_RadioBearerConfig_t *rbconfig = calloc(1, sizeof(*rbconfig)); - rbconfig->srb_ToAddModList = NULL; - rbconfig->srb3_ToRelease = NULL; - rbconfig->drb_ToAddModList = calloc(1,sizeof(*rbconfig->drb_ToAddModList)); - NR_DRB_ToAddMod_t *drb_ToAddMod = calloc(1,sizeof(*drb_ToAddMod)); - drb_ToAddMod->cnAssociation = calloc(1,sizeof(*drb_ToAddMod->cnAssociation)); - drb_ToAddMod->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity; - drb_ToAddMod->cnAssociation->choice.eps_BearerIdentity= eps_bearer_id; - drb_ToAddMod->drb_Identity = rb_id; - drb_ToAddMod->reestablishPDCP = NULL; - drb_ToAddMod->recoverPDCP = NULL; - drb_ToAddMod->pdcp_Config = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config)); - asn1cCalloc(drb_ToAddMod->pdcp_Config->drb, drb); - asn1cCallocOne(drb->discardTimer, encode_discard_timer(pdcp_config->drb.discard_timer)); - asn1cCallocOne(drb->pdcp_SN_SizeUL, encode_sn_size_ul(pdcp_config->drb.sn_size)); - asn1cCallocOne(drb->pdcp_SN_SizeDL, encode_sn_size_dl(pdcp_config->drb.sn_size)); - drb->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; - drb->headerCompression.choice.notUsed = 0; - drb->integrityProtection = NULL; - drb->statusReportRequired = NULL; - drb->outOfOrderDelivery = NULL; - - drb_ToAddMod->pdcp_Config->moreThanOneRLC = NULL; - asn1cCallocOne(drb_ToAddMod->pdcp_Config->t_Reordering, encode_t_reordering(pdcp_config->drb.t_reordering)); - drb_ToAddMod->pdcp_Config->ext1 = NULL; - - asn1cSeqAdd(&rbconfig->drb_ToAddModList->list,drb_ToAddMod); - - rbconfig->drb_ToReleaseList = NULL; - - asn1cCalloc(rbconfig->securityConfig, secConf); - asn1cCalloc(secConf->securityAlgorithmConfig, secConfAlgo); - secConfAlgo->cipheringAlgorithm = ciphering_algorithm; - secConfAlgo->integrityProtAlgorithm = NULL; - asn1cCallocOne(secConf->keyToUse, key_to_use); - return rbconfig; -} - //------------------------------------------------------------------------------ int do_RRCSetup(uint8_t *const buffer, size_t buffer_size, @@ -542,15 +545,35 @@ static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_re /* masterCellGroup */ if (params->cell_group_config) { - // Encode in extension IE (Master cell group) - uint8_t *buf = NULL; - ssize_t len = uper_encode_to_new_buffer(&asn_DEF_NR_CellGroupConfig, NULL, params->cell_group_config, (void **)&buf); - AssertFatal(len > 0, "ASN1 message encoding failed (%lu)!\n", len); + uint8_t temp[4096]; + asn_enc_rval_t enc = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, params->cell_group_config, temp, sizeof(temp)); + + if (enc.encoded <= 0) { + LOG_E(NR_RRC, "ASN.1 encoding failed for NR_CellGroupConfig (encoded=%ld)\n", enc.encoded); + if (enc.failed_type) { + LOG_E(NR_RRC, "Failed at ASN.1 type: %s\n", enc.failed_type->name); + } + if (enc.structure_ptr) { + LOG_E(NR_RRC, "Failed at structure element: %p\n", enc.structure_ptr); + } + // Print diagnostic information to help debug the issue + LOG_E(NR_RRC, "CellGroupConfig structure that failed to encode:\n"); + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)params->cell_group_config); + ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration_IEs, ie); + return NULL; + } + DevAssert(enc.encoded <= sizeof(temp) * 8); // Encoded data must fit in temp buffer + // Allocate buffer for the encoded data and copy it + // enc.encoded is in bits, convert to bytes + size_t encoded_bytes = (enc.encoded + 7) / 8; + uint8_t *buf = calloc_or_fail(1, encoded_bytes); + memcpy(buf, temp, encoded_bytes); + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)params->cell_group_config); } ie->nonCriticalExtension->masterCellGroup = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterCellGroup)); - *ie->nonCriticalExtension->masterCellGroup = (OCTET_STRING_t){.buf = buf, .size = len}; + *ie->nonCriticalExtension->masterCellGroup = (OCTET_STRING_t){.buf = buf, .size = encoded_bytes}; } /* masterKeyUpdate */ @@ -564,10 +587,51 @@ static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_re return ie; } +static byte_array_t do_HO_RRCReconfiguration(nr_rrc_reconfig_param_t *params) +{ + NR_RRCReconfiguration_IEs_t *ie = build_RRCReconfiguration_IEs(params); + byte_array_t msg = {.buf = NULL, .len = 0}; + + // Create the standalone RRCReconfiguration message + NR_RRCReconfiguration_t rrcReconf = {0}; + rrcReconf.rrc_TransactionIdentifier = params->transaction_id; + rrcReconf.criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; + rrcReconf.criticalExtensions.choice.rrcReconfiguration = ie; + + // Encode the message + int val = uper_encode_to_new_buffer(&asn_DEF_NR_RRCReconfiguration, NULL, &rrcReconf, (void **)&msg.buf); + if (val <= 0) { + LOG_E(NR_RRC, "ASN1 RRCReconfiguration message encoding failed\n"); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_RRCReconfiguration, &rrcReconf); + return msg; + } + msg.len = val; + LOG_D(NR_RRC, "RRCReconfiguration: Encoded (%ld bytes)\n", msg.len); + + // don't free what we did not allocate, so set fields with pointers to NULL + // if memory comes from outside + ie->measConfig = NULL; + if (ie->radioBearerConfig) { + ie->radioBearerConfig->srb3_ToRelease = NULL; + ie->radioBearerConfig->drb_ToReleaseList = NULL; + ie->radioBearerConfig->drb_ToAddModList = NULL; + ie->radioBearerConfig->srb_ToAddModList = NULL; + ie->radioBearerConfig->securityConfig = NULL; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_RRCReconfiguration, &rrcReconf); + + return msg; +} + byte_array_t do_RRCReconfiguration(const nr_rrc_reconfig_param_t *params) { byte_array_t msg = {.buf = NULL, .len = 0}; NR_RRCReconfiguration_IEs_t *ie = build_RRCReconfiguration_IEs(params); + if (!ie) { + LOG_E(NR_RRC, "%s: failed to encode RRCReconfiguration\n", __func__); + return msg; + } NR_DL_DCCH_Message_t dl_dcch_msg = {0}; dl_dcch_msg.message.present = NR_DL_DCCH_MessageType_PR_c1; @@ -785,6 +849,58 @@ int do_RRCSetupComplete(uint8_t *buffer, return((enc_rval.encoded+7)/8); } +// TODO: This function is only implemented for event A2 +int do_nrMeasurementReport_SA(long trigger_to_measid, + long trigger_quantity, + long rs_type, + uint16_t Nid_cell, + int rsrp_index, + uint8_t *buffer, + size_t buffer_size) +{ + asn_enc_rval_t enc_rval; + NR_UL_DCCH_Message_t ul_dcch_msg = {0}; + + ul_dcch_msg.message.present = NR_UL_DCCH_MessageType_PR_c1; + asn1cCalloc(ul_dcch_msg.message.choice.c1, c1); + c1->present = NR_UL_DCCH_MessageType__c1_PR_measurementReport; + + asn1cCalloc(c1->choice.measurementReport, measurementReport); + measurementReport->criticalExtensions.present = NR_MeasurementReport__criticalExtensions_PR_measurementReport; + + asn1cCalloc(measurementReport->criticalExtensions.choice.measurementReport, mrIE); + mrIE->measResults.measId = trigger_to_measid; + + NR_MeasResultServMO_t *measResultServMo = calloc_or_fail(1, sizeof(*measResultServMo)); + + NR_MeasResultNR_t *measResultServingCell = &measResultServMo->measResultServingCell; + asn1cCalloc(measResultServingCell->physCellId, pci); + *pci = Nid_cell; + + struct NR_MeasQuantityResults *active_mq_res = calloc_or_fail(1, sizeof(*active_mq_res)); + if (trigger_quantity == NR_MeasTriggerQuantityOffset_PR_rsrp) { + asn1cCalloc(active_mq_res->rsrp, rsrp); + // Assign precomputed RSRP index + *rsrp = rsrp_index; + if (rs_type == NR_NR_RS_Type_ssb) + measResultServingCell->measResult.cellResults.resultsSSB_Cell = active_mq_res; + else + measResultServingCell->measResult.cellResults.resultsCSI_RS_Cell = active_mq_res; + } + + ASN_SEQUENCE_ADD(&mrIE->measResults.measResultServingMOList.list, measResultServMo); + enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, NULL, (void *)&ul_dcch_msg, buffer, buffer_size); + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg); + } + + LOG_I(NR_RRC, "MeasurementReport Encoded %zd bits (%zd bytes)\n", enc_rval.encoded, (enc_rval.encoded + 7) / 8); + + return ((enc_rval.encoded + 7) / 8); +} + int do_NR_DLInformationTransfer(uint8_t *buffer, size_t buffer_len, uint8_t transaction_id, @@ -956,85 +1072,148 @@ int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t r return((enc_rval.encoded+7)/8); } +static NR_MeasObjectToAddMod_t *get_MeasObject(const struct NR_MeasTiming__frequencyAndTiming *ft, + int band, + NR_ARFCN_ValueNR_t ssbFrequency, + NR_MeasObjectId_t measObjectId) +{ + const NR_SSB_MTC_t *ssb_mtc = &ft->ssb_MeasurementTimingConfiguration; + NR_MeasObjectToAddMod_t *mo = calloc_or_fail(1, sizeof(*mo)); + mo->measObjectId = measObjectId; + mo->measObject.present = NR_MeasObjectToAddMod__measObject_PR_measObjectNR; + NR_MeasObjectNR_t *monr = calloc_or_fail(1, sizeof(*monr)); + asn1cCallocOne(monr->ssbFrequency, ssbFrequency); + asn1cCallocOne(monr->ssbSubcarrierSpacing, ft->ssbSubcarrierSpacing); + monr->referenceSignalConfig.ssb_ConfigMobility = calloc_or_fail(1, sizeof(*monr->referenceSignalConfig.ssb_ConfigMobility)); + monr->referenceSignalConfig.ssb_ConfigMobility->deriveSSB_IndexFromCell = true; + monr->absThreshSS_BlocksConsolidation = calloc_or_fail(1, sizeof(*monr->absThreshSS_BlocksConsolidation)); + asn1cCallocOne(monr->absThreshSS_BlocksConsolidation->thresholdRSRP, 36); + asn1cCallocOne(monr->nrofSS_BlocksToAverage, 8); + monr->smtc1 = calloc_or_fail(1, sizeof(*monr->smtc1)); + monr->smtc1->periodicityAndOffset = ssb_mtc->periodicityAndOffset; + monr->smtc1->duration = ssb_mtc->duration; + monr->quantityConfigIndex = 1; + monr->ext1 = calloc_or_fail(1, sizeof(*monr->ext1)); + asn1cCallocOne(monr->ext1->freqBandIndicatorNR, band); + mo->measObject.choice.measObjectNR = monr; + return mo; +} + +static NR_MeasIdToAddMod_t *get_MeasId(NR_MeasId_t measId, NR_ReportConfigId_t reportConfigId, NR_MeasObjectId_t measObjectId) +{ + NR_MeasIdToAddMod_t *measid = calloc_or_fail(1, sizeof(NR_MeasIdToAddMod_t)); + measid->measId = measId; + measid->reportConfigId = reportConfigId; + measid->measObjectId = measObjectId; + return measid; +} + NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, int band, int scs, + int nr_pci, NR_ReportConfigToAddMod_t *rc_PER, NR_ReportConfigToAddMod_t *rc_A2, seq_arr_t *rc_A3_seq, - seq_arr_t *pci_seq) + seq_arr_t *neigh_seq) { - NR_MeasConfig_t *mc = calloc(1, sizeof(*mc)); - mc->measObjectToAddModList = calloc(1, sizeof(*mc->measObjectToAddModList)); - mc->reportConfigToAddModList = calloc(1, sizeof(*mc->reportConfigToAddModList)); - mc->measIdToAddModList = calloc(1, sizeof(*mc->measIdToAddModList)); + DevAssert(mt != NULL && mt->frequencyAndTiming != NULL); + const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming; + NR_MeasConfig_t *mc = calloc_or_fail(1, sizeof(*mc)); + mc->measObjectToAddModList = calloc_or_fail(1, sizeof(*mc->measObjectToAddModList)); + mc->reportConfigToAddModList = calloc_or_fail(1, sizeof(*mc->reportConfigToAddModList)); + mc->measIdToAddModList = calloc_or_fail(1, sizeof(*mc->measIdToAddModList)); + + // Report Configuration: A reporting configuration defines the reporting criteria. The reporting criteria are classified as event + // triggered reporting, periodic reporting, CGI reporting or SFTD reporting. + + // Periodic report if (rc_PER) asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_PER); - if (rc_A2) + // Event A2 + if (rc_A2) asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A2); + // Event A3 if (rc_A3_seq) { for (int i = 0; i < rc_A3_seq->size; i++) { NR_ReportConfigToAddMod_t *rc_A3 = (NR_ReportConfigToAddMod_t *)seq_arr_at(rc_A3_seq, i); - asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A3); + // Create a deep copy of the report config + NR_ReportConfigToAddMod_t *rc_A3_copy = NULL; + int result = asn_copy(&asn_DEF_NR_ReportConfigToAddMod, (void **)&rc_A3_copy, rc_A3); + AssertFatal(result >= 0, "error during asn_copy() of ReportConfigToAddMod\n"); + asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A3_copy); } } - DevAssert(mt != NULL && mt->frequencyAndTiming != NULL); - const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming; - const NR_SSB_MTC_t *ssb_mtc = &ft->ssb_MeasurementTimingConfiguration; - // Measurement Objects: Specifies what is to be measured. For NR and inter-RAT E-UTRA measurements, this may include // cell-specific offsets, blacklisted cells to be ignored and whitelisted cells to consider for measurements. - NR_MeasObjectToAddMod_t *mo1 = calloc(1, sizeof(*mo1)); - mo1->measObjectId = 1; - mo1->measObject.present = NR_MeasObjectToAddMod__measObject_PR_measObjectNR; - NR_MeasObjectNR_t *monr1 = calloc(1, sizeof(*monr1)); - asn1cCallocOne(monr1->ssbFrequency, ft->carrierFreq); - asn1cCallocOne(monr1->ssbSubcarrierSpacing, ft->ssbSubcarrierSpacing); - monr1->referenceSignalConfig.ssb_ConfigMobility = calloc(1, sizeof(*monr1->referenceSignalConfig.ssb_ConfigMobility)); - monr1->referenceSignalConfig.ssb_ConfigMobility->deriveSSB_IndexFromCell = true; - monr1->absThreshSS_BlocksConsolidation = calloc(1, sizeof(*monr1->absThreshSS_BlocksConsolidation)); - asn1cCallocOne(monr1->absThreshSS_BlocksConsolidation->thresholdRSRP, 36); - asn1cCallocOne(monr1->nrofSS_BlocksToAverage, 8); - monr1->smtc1 = calloc(1, sizeof(*monr1->smtc1)); - monr1->smtc1->periodicityAndOffset = ssb_mtc->periodicityAndOffset; - monr1->smtc1->duration = ssb_mtc->duration; - monr1->quantityConfigIndex = 1; - monr1->ext1 = calloc(1, sizeof(*monr1->ext1)); - asn1cCallocOne(monr1->ext1->freqBandIndicatorNR, band); - if (pci_seq) { - for (int i = 0; i < pci_seq->size; i++) { - if (monr1->cellsToAddModList == NULL) { - monr1->cellsToAddModList = calloc(1, sizeof(*monr1->cellsToAddModList)); - } + // Serving cell + NR_MeasObjectToAddMod_t *mo1 = get_MeasObject(ft, band, ft->carrierFreq, 1); + NR_MeasObjectNR_t *monr1 = mo1->measObject.choice.measObjectNR; + monr1->cellsToAddModList = calloc_or_fail(1, sizeof(*monr1->cellsToAddModList)); + NR_CellsToAddMod_t *cell = calloc_or_fail(1, sizeof(*cell)); + cell->physCellId = nr_pci; + ASN_SEQUENCE_ADD(&monr1->cellsToAddModList->list, cell); + asn1cSeqAdd(&mc->measObjectToAddModList->list, mo1); - NR_CellsToAddMod_t *cell = calloc(1, sizeof(*cell)); - int *pci = (int *)seq_arr_at(pci_seq, i); - cell->physCellId = *pci; - ASN_SEQUENCE_ADD(&monr1->cellsToAddModList->list, cell); + // Neighbour cells + if (neigh_seq) { + int mo_id = 2; + FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, neigh_cell, neigh_seq) { + NR_MeasObjectToAddMod_t *mo_neighbour = get_MeasObject(ft, neigh_cell->band, neigh_cell->absoluteFrequencySSB, mo_id); + NR_MeasObjectNR_t *monr = mo_neighbour->measObject.choice.measObjectNR; + monr->cellsToAddModList = calloc_or_fail(1, sizeof(*monr->cellsToAddModList)); + NR_CellsToAddMod_t *cell = calloc_or_fail(1, sizeof(*cell)); + cell->physCellId = neigh_cell->physicalCellId; + ASN_SEQUENCE_ADD(&monr->cellsToAddModList->list, cell); + asn1cSeqAdd(&mc->measObjectToAddModList->list, mo_neighbour); + mo_id++; } } - mo1->measObject.choice.measObjectNR = monr1; - asn1cSeqAdd(&mc->measObjectToAddModList->list, mo1); + // Measurement identities: A list of measurement identities where each measurement identity links one measurement object with one + // reporting configuration. By configuring multiple measurement identities, it is possible to link more than one measurement + // object to the same reporting configuration, as well as to link more than one reporting configuration to the same measurement + // object. - // Preparation of measId - for (uint8_t reportIdx = 0; reportIdx < mc->reportConfigToAddModList->list.count; reportIdx++) { - const NR_ReportConfigId_t reportId = mc->reportConfigToAddModList->list.array[reportIdx]->reportConfigId; - NR_MeasIdToAddMod_t *measid = calloc(1, sizeof(NR_MeasIdToAddMod_t)); - measid->measId = reportIdx + 1; - measid->reportConfigId = reportId; - measid->measObjectId = 1; - asn1cSeqAdd(&mc->measIdToAddModList->list, measid); + // MeasId for Periodic report + int meas_idx = 0; + if (rc_PER) { + for (; meas_idx < mc->measObjectToAddModList->list.count; meas_idx++) { + const NR_MeasObjectId_t measObjectId = mc->measObjectToAddModList->list.array[meas_idx]->measObjectId; + NR_MeasIdToAddMod_t *measid = get_MeasId(meas_idx + 1, rc_PER->reportConfigId, measObjectId); + asn1cSeqAdd(&mc->measIdToAddModList->list, measid); + } } - mc->quantityConfig = calloc(1, sizeof(*mc->quantityConfig)); - mc->quantityConfig->quantityConfigNR_List = calloc(1, sizeof(*mc->quantityConfig->quantityConfigNR_List)); - NR_QuantityConfigNR_t *qcnr = calloc(1, sizeof(*qcnr)); + // MeasId for Event A2 + if (rc_A2) { + NR_MeasIdToAddMod_t *measid_A2 = get_MeasId(meas_idx + 1, rc_A2->reportConfigId, 1); + meas_idx++; + asn1cSeqAdd(&mc->measIdToAddModList->list, measid_A2); + } + + // MeasId for Event A3 + if (neigh_seq) { + int i = 0; + FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, neigh_cell, neigh_seq) { + NR_ReportConfigId_t reportConfigId = neigh_cell->physicalCellId == -1 ? 3 : i + 4; + NR_MeasIdToAddMod_t *measid_A3 = get_MeasId(meas_idx + 1, reportConfigId, i + 2); + meas_idx++; + asn1cSeqAdd(&mc->measIdToAddModList->list, measid_A3); + i++; + } + } + + // Quantity configurations: The quantity configuration defines the measurement filtering configuration used for measurement event + // evaluation and related reporting, and for periodical reporting of that measurement. + mc->quantityConfig = calloc_or_fail(1, sizeof(*mc->quantityConfig)); + mc->quantityConfig->quantityConfigNR_List = calloc_or_fail(1, sizeof(*mc->quantityConfig->quantityConfigNR_List)); + NR_QuantityConfigNR_t *qcnr = calloc_or_fail(1, sizeof(*qcnr)); asn1cCallocOne(qcnr->quantityConfigCell.ssb_FilterConfig.filterCoefficientRSRP, NR_FilterCoefficient_fc6); asn1cCallocOne(qcnr->quantityConfigCell.csi_RS_FilterConfig.filterCoefficientRSRP, NR_FilterCoefficient_fc6); asn1cSeqAdd(&mc->quantityConfig->quantityConfigNR_List->list, qcnr); @@ -1042,6 +1221,201 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, return mc; } +/** @brief Prepares removal of measurement configurations related to the source gNB. + * This function decodes the HandoverPreparationInformation received from the source gNB, + * extracts the source MeasConfig, and marks those entries (measurement objects, report + * configurations, and measurement IDs) for removal by populating the corresponding + * ToRemoveList fields in the UE's current measConfig. + * This ensures that obsolete or source-specific measurement configurations are removed + * from the UE after handover and allows the target gNB to install its own valid configuration. + * @param measConfig Target gNB's current measurement configuration to be updated. + * @param prep_info Encoded HandoverPreparationInformation received from the source gNB.*/ +void fill_removal_lists_from_source_measConfig(NR_MeasConfig_t *currentMC, byte_array_t prep_info) +{ + if (currentMC == NULL) { + LOG_E(NR_RRC, "HO LOG: UE's Measurement Configuration is NULL!\n"); + return; + } + + // Decodes the HandoverPreparationInformation message + NR_HandoverPreparationInformation_t *hpi = NULL; + asn_dec_rval_t hoPrep_dec_rval = uper_decode_complete(NULL, + &asn_DEF_NR_HandoverPreparationInformation, + (void **)&hpi, + (uint8_t *)prep_info.buf, + prep_info.len); + + if (hoPrep_dec_rval.code != RC_OK || hoPrep_dec_rval.consumed < 0) { + LOG_E(NR_RRC, "Handover Prep Info decode error while removing source gnb measurement configuration!\n"); + return; + } + + /* Decodes the RRCReconfiguration message within the HandoverPreparationInformation + and extract the measConfig provided by the source gNB */ + if (!hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation->sourceConfig) { + LOG_W(NR_RRC, "Missing sourceConfig: in source gNB rrcReconfiguration\n"); + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi); + return; + } + NR_RRCReconfiguration_t *rrcReconf = NULL; + NR_AS_Config_t *sourceConfig = hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation->sourceConfig; + asn_dec_rval_t rrcReconf_dec_rval = uper_decode_complete(NULL, + &asn_DEF_NR_RRCReconfiguration, + (void **)&rrcReconf, + (uint8_t *)sourceConfig->rrcReconfiguration.buf, + sourceConfig->rrcReconfiguration.size); + if (rrcReconf_dec_rval.code != RC_OK || rrcReconf_dec_rval.consumed < 0) { + LOG_E(NR_RRC, "Failed to decode source gNB rrcReconfiguration!\n"); + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi); + return; + } + + if (rrcReconf->criticalExtensions.choice.rrcReconfiguration->measConfig == NULL) { + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi); + ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, rrcReconf); + return; + } + + NR_MeasConfig_t *sourceMC = rrcReconf->criticalExtensions.choice.rrcReconfiguration->measConfig; + + /* Add measurement objects, report configurations, and measurement IDs + to the UE's measConfig removal lists, and update UE->measConfig */ + if (sourceMC->measObjectToAddModList->list.count > 0) { + currentMC->measObjectToRemoveList = calloc_or_fail(1, sizeof(*currentMC->measObjectToRemoveList)); + for (int i = 0; i < sourceMC->measObjectToAddModList->list.count; i++) { + NR_MeasObjectId_t *measObjId = calloc_or_fail(1, sizeof(NR_MeasObjectId_t)); + *measObjId = sourceMC->measObjectToAddModList->list.array[i]->measObjectId; + asn1cSeqAdd(¤tMC->measObjectToRemoveList->list, measObjId); + } + } + + if (sourceMC->reportConfigToAddModList->list.count > 0) { + currentMC->reportConfigToRemoveList = calloc_or_fail(1, sizeof(*currentMC->reportConfigToRemoveList)); + for (int i = 0; i < sourceMC->reportConfigToAddModList->list.count; i++) { + NR_ReportConfigId_t *reportConfigId = calloc_or_fail(1, sizeof(NR_ReportConfigId_t)); + *reportConfigId = sourceMC->reportConfigToAddModList->list.array[i]->reportConfigId; + asn1cSeqAdd(¤tMC->reportConfigToRemoveList->list, reportConfigId); + } + } + + if (sourceMC->measIdToAddModList->list.count > 0) { + currentMC->measIdToRemoveList = calloc_or_fail(1, sizeof(*currentMC->measIdToRemoveList)); + for (int i = 0; i < sourceMC->measIdToAddModList->list.count; i++) { + NR_MeasId_t *measId = calloc_or_fail(1, sizeof(NR_MeasId_t)); + *measId = sourceMC->measIdToAddModList->list.array[i]->measId; + asn1cSeqAdd(¤tMC->measIdToRemoveList->list, measId); + } + } + + // Clean up allocated memory + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi); + ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, rrcReconf); +} + +int doRRCReconfiguration_from_HandoverCommand(byte_array_t *ba, const byte_array_t handoverCommand) +{ + // Decode Handover Command + NR_HandoverCommand_t *hoCommand = NULL; + asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_HandoverCommand, (void **)&hoCommand, handoverCommand.buf, handoverCommand.len); + + if (dec_rval.code != RC_OK && dec_rval.consumed == 0) { + LOG_E(NR_RRC, "Can not decode Handover Command!\n"); + return -1; + } + + // Prepare DL DCCH message for RRCReconfiguration + NR_DL_DCCH_Message_t dl_dcch_msg = {0}; + asn_enc_rval_t enc_rval; + dl_dcch_msg.message.present = NR_DL_DCCH_MessageType_PR_c1; + asn1cCalloc(dl_dcch_msg.message.choice.c1, c1); + c1->present = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; + asn1cCalloc(c1->choice.rrcReconfiguration, rrcReconf); + + // Decode RRCReconfiguration from handoverCommandMessage + OCTET_STRING_t *ho = &hoCommand->criticalExtensions.choice.c1->choice.handoverCommand->handoverCommandMessage; + uper_decode_complete(NULL, &asn_DEF_NR_RRCReconfiguration, (void **)&rrcReconf, ho->buf, ho->size); + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); + + // Encode DL DCCH message in buffer + enc_rval = uper_encode_to_buffer(&asn_DEF_NR_DL_DCCH_Message, NULL, &dl_dcch_msg, ba->buf, ba->len); + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); + ASN_STRUCT_FREE(asn_DEF_NR_HandoverCommand, hoCommand); + + return ((enc_rval.encoded + 7) / 8); +} + +byte_array_t get_HandoverCommandMessage(nr_rrc_reconfig_param_t *params) +{ + // Encode RRCReconfiguration to buffer + byte_array_t msg = do_HO_RRCReconfiguration(params); + + // Add RRCReconfiguration to handoverCommand + NR_HandoverCommand_t HoCommand = {0}; + HoCommand.criticalExtensions.present = NR_HandoverCommand__criticalExtensions_PR_c1; + asn1cCalloc(HoCommand.criticalExtensions.choice.c1, c1); + c1->present = NR_HandoverCommand__criticalExtensions__c1_PR_handoverCommand; + asn1cCalloc(HoCommand.criticalExtensions.choice.c1->choice.handoverCommand, hc); + OCTET_STRING_fromBuf(&hc->handoverCommandMessage, (const char *)msg.buf, msg.len); + free_byte_array(msg); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_HandoverCommand, (void *)&HoCommand); + + // Encode handoverCommand to buffer + byte_array_t buffer = {.len = -1, .buf = NULL}; + buffer.len = uper_encode_to_new_buffer(&asn_DEF_NR_HandoverCommand, NULL, (void *)&HoCommand, (void **)&buffer.buf); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_HandoverCommand, &HoCommand); + + return buffer; +} + +/** @brief HandoverPreparationInformation message (11.2.2 of TS 38.331) + * 1) generate RRCReconfiguration to be transferred + * 2) encodes UE Capabilities from UE Context + * 3) encodes AS context + * 4) generates HO Preparation Info */ +byte_array_t get_HandoverPreparationInformation(nr_rrc_reconfig_param_t *params, int scell_pci) +{ + // Buffer to return + byte_array_t buffer = {.buf = NULL, .len = 0}; + + /* Prepare handoverPreparationInformation IEs */ + NR_HandoverPreparationInformation_t hoPrepInfo = {0}; + hoPrepInfo.criticalExtensions.present = NR_HandoverPreparationInformation__criticalExtensions_PR_c1; + asn1cCalloc(hoPrepInfo.criticalExtensions.choice.c1, c1); + c1->present = NR_HandoverPreparationInformation__criticalExtensions__c1_PR_handoverPreparationInformation; + asn1cCalloc(c1->choice.handoverPreparationInformation, hpi); + + /* Decode stored NR_UE_CapabilityRAT_ContainerList and add to IEs */ + NR_UE_CapabilityRAT_ContainerList_t *clist = NULL; + asn_dec_rval_t dec_rval = + uper_decode(NULL, &asn_DEF_NR_UE_CapabilityRAT_ContainerList, (void **)&clist, params->ue_cap.buf, params->ue_cap.len, 0, 0); + if (dec_rval.code != RC_OK) { + LOG_W(NR_RRC, "Failed to decode UE capability container list for HandoverPreparationInformation, ignoring capabilities\n"); + return buffer; + } + hpi->ue_CapabilityRAT_List = *clist; + free(clist); + + /* sourceConfig: Encode RRCReconfiguration as used in the source cell */ + byte_array_t msg = do_HO_RRCReconfiguration(params); + asn1cCalloc(hpi->sourceConfig, sourceConfig); + OCTET_STRING_fromBuf(&sourceConfig->rrcReconfiguration, (const char *)msg.buf, msg.len); + free_byte_array(msg); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_HandoverPreparationInformation, (void **)&hoPrepInfo); + + /* encode */ + buffer.len = uper_encode_to_new_buffer(&asn_DEF_NR_HandoverPreparationInformation, NULL, (void *)&hoPrepInfo, (void *)&buffer.buf); + AssertFatal(buffer.len > 0, "ASN1 message encoding failed (%ld)!\n", buffer.len); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_HandoverPreparationInformation, &hoPrepInfo); + return buffer; +} + void free_MeasConfig(NR_MeasConfig_t *mc) { ASN_STRUCT_FREE(asn_DEF_NR_MeasConfig, mc); @@ -1122,3 +1496,17 @@ int do_NR_HandoverPreparationInformation(const uint8_t *uecap_buf, int uecap_buf ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi); return (enc_rval.encoded + 7) / 8; } + +int do_NR_MeasConfig(const NR_MeasConfig_t *measconfig, uint8_t *buf, int buf_size) +{ + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_MeasConfig, NULL, measconfig, buf, buf_size); + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + return (enc_rval.encoded + 7) / 8; +} + +int do_NR_MeasurementTimingConfiguration(const NR_MeasurementTimingConfiguration_t *mtc, uint8_t *buf, int buf_size) +{ + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_MeasurementTimingConfiguration, NULL, mtc, buf, buf_size); + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + return (enc_rval.encoded + 7) / 8; +} diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 3ac4695eba..48a0ea734b 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -50,10 +50,14 @@ #include "NR_ReestablishmentCause.h" #include "NR_SRB-ToAddModList.h" #include "NR_SecurityConfig.h" +#include "NR_MeasurementReport.h" +#include "NR_MeasurementTimingConfiguration.h" +#include "NR_UE-CapabilityRAT-ContainerList.h" #include "ds/seq_arr.h" #include "ds/byte_array.h" #include "rrc_messages_types.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" +#include "common/utils/nr/nr_common.h" struct asn_TYPE_descriptor_s; typedef struct { @@ -68,6 +72,7 @@ typedef struct { NR_CellGroupConfig_t *cell_group_config; bool masterKeyUpdate; int nextHopChainingCount; + byte_array_t ue_cap; } nr_rrc_reconfig_param_t; /* @@ -84,12 +89,6 @@ int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc); int do_RRCReject(uint8_t *const buffer); -NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, - int rb_id, - e_NR_CipheringAlgorithm ciphering_algorithm, - e_NR_SecurityConfig__keyToUse key_to_use, - const nr_pdcp_configuration_t *pdcp_config); - int do_RRCSetup(uint8_t *const buffer, size_t buffer_size, const uint8_t transaction_id, @@ -120,8 +119,20 @@ int do_RRCSetupComplete(uint8_t *buffer, int do_NR_HandoverPreparationInformation(const uint8_t *uecap_buf, int uecap_buf_size, uint8_t *buf, int buf_size); +int do_NR_MeasConfig(const NR_MeasConfig_t *measconfig, uint8_t *buf, int buf_size); + +int do_NR_MeasurementTimingConfiguration(const NR_MeasurementTimingConfiguration_t *mtc, uint8_t *buf, int buf_size); + int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv, uint64_t fiveG_S_TMSI_part1); +int do_nrMeasurementReport_SA(long trigger_to_measid, + long trigger_quantity, + long rs_type, + uint16_t Nid_cell, + int rsrp_index, + uint8_t *buffer, + size_t buffer_size); + int do_NR_RRCReconfigurationComplete_for_nsa(uint8_t *buffer, size_t buffer_size, NR_RRC_TransactionIdentifier_t Transaction_id); int do_NR_RRCReconfigurationComplete(uint8_t *buffer, size_t buffer_size, const uint8_t Transaction_id); @@ -148,11 +159,20 @@ int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t r NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, int band, int scs, + int nr_pci, NR_ReportConfigToAddMod_t *rc_PER, NR_ReportConfigToAddMod_t *rc_A2, seq_arr_t *rc_A3_seq, - seq_arr_t *pci_seq); + seq_arr_t *neigh_seq); void free_MeasConfig(NR_MeasConfig_t *mc); int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi); +byte_array_t get_HandoverPreparationInformation(nr_rrc_reconfig_param_t *params, int scell_pci); +byte_array_t get_HandoverCommandMessage(nr_rrc_reconfig_param_t *params); +void fill_removal_lists_from_source_measConfig(NR_MeasConfig_t *measConfig, byte_array_t prep_info); +int doRRCReconfiguration_from_HandoverCommand(byte_array_t *ba, byte_array_t handoverCommand); + +struct NR_UE_NR_Capability *get_ue_nr_capability(int rnti, uint8_t *buf, uint32_t len); +NR_UE_NR_Capability_t *decode_nr_ue_capability(int rnti, const NR_UE_CapabilityRAT_ContainerList_t *clist); + #endif /* __RRC_NR_MESSAGES_ASN1_MSG__H__ */ diff --git a/openair2/RRC/NR/mac_rrc_dl.h b/openair2/RRC/NR/mac_rrc_dl.h index d6937591b5..4bd106d679 100644 --- a/openair2/RRC/NR/mac_rrc_dl.h +++ b/openair2/RRC/NR/mac_rrc_dl.h @@ -33,11 +33,11 @@ typedef void (*f1_setup_failure_func_t)(sctp_assoc_t assoc_id, const f1ap_setup_ typedef void (*gnb_du_configuration_update_ack_func_t)(sctp_assoc_t assoc_id, const f1ap_gnb_du_configuration_update_acknowledge_t *ack); -typedef void (*ue_context_setup_request_func_t)(sctp_assoc_t assoc_id, const f1ap_ue_context_setup_t *req); -typedef void (*ue_context_modification_request_func_t)(sctp_assoc_t assoc_id, const f1ap_ue_context_modif_req_t *req); +typedef void (*ue_context_setup_request_func_t)(sctp_assoc_t assoc_id, const f1ap_ue_context_setup_req_t *req); +typedef void (*ue_context_modification_request_func_t)(sctp_assoc_t assoc_id, const f1ap_ue_context_mod_req_t *req); typedef void (*ue_context_modification_confirm_func_t)(sctp_assoc_t assoc_id, const f1ap_ue_context_modif_confirm_t *confirm); typedef void (*ue_context_modification_refuse_func_t)(sctp_assoc_t assoc_id, const f1ap_ue_context_modif_refuse_t *refuse); -typedef void (*ue_context_release_command_func_t)(sctp_assoc_t assoc_id, const f1ap_ue_context_release_cmd_t *cmd); +typedef void (*ue_context_release_command_func_t)(sctp_assoc_t assoc_id, const f1ap_ue_context_rel_cmd_t *cmd); typedef void (*dl_rrc_message_transfer_func_t)(sctp_assoc_t assoc_id, const f1ap_dl_rrc_message_t *dl_rrc); diff --git a/openair2/RRC/NR/mac_rrc_dl_direct.c b/openair2/RRC/NR/mac_rrc_dl_direct.c index 4f8d45ac8c..83c1130fcb 100644 --- a/openair2/RRC/NR/mac_rrc_dl_direct.c +++ b/openair2/RRC/NR/mac_rrc_dl_direct.c @@ -58,13 +58,13 @@ static void gnb_du_configuration_update_ack_direct(sctp_assoc_t assoc_id, const gnb_du_configuration_update_acknowledge(ack); } -static void ue_context_setup_request_direct(sctp_assoc_t assoc_id, const f1ap_ue_context_setup_t *req) +static void ue_context_setup_request_direct(sctp_assoc_t assoc_id, const f1ap_ue_context_setup_req_t *req) { AssertFatal(assoc_id == -1, "illegal assoc_id %d\n", assoc_id); ue_context_setup_request(req); } -static void ue_context_modification_request_direct(sctp_assoc_t assoc_id, const f1ap_ue_context_modif_req_t *req) +static void ue_context_modification_request_direct(sctp_assoc_t assoc_id, const f1ap_ue_context_mod_req_t *req) { AssertFatal(assoc_id == -1, "illegal assoc_id %d\n", assoc_id); ue_context_modification_request(req); @@ -82,7 +82,7 @@ static void ue_context_modification_refuse_direct(sctp_assoc_t assoc_id, const f ue_context_modification_refuse(refuse); } -static void ue_context_release_command_direct(sctp_assoc_t assoc_id, const f1ap_ue_context_release_cmd_t *cmd) +static void ue_context_release_command_direct(sctp_assoc_t assoc_id, const f1ap_ue_context_rel_cmd_t *cmd) { AssertFatal(assoc_id == -1, "illegal assoc_id %d\n", assoc_id); ue_context_release_command(cmd); diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index 9fef2dea58..37cb6d70f9 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -30,8 +30,9 @@ #include "intertask_interface.h" #include "mac_rrc_dl.h" #include "nr_rrc_defs.h" -#include "openair2/F1AP/lib/f1ap_rrc_message_transfer.h" -#include "openair2/F1AP/lib/f1ap_interface_management.h" +#include "lib/f1ap_rrc_message_transfer.h" +#include "lib/f1ap_interface_management.h" +#include "lib/f1ap_ue_context.h" static void f1_reset_cu_initiated_f1ap(sctp_assoc_t assoc_id, const f1ap_reset_t *reset) { @@ -75,116 +76,19 @@ static void gnb_du_configuration_update_ack_f1ap(sctp_assoc_t assoc_id, const f1 itti_send_msg_to_task(TASK_CU_F1, 0, msg); } -static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_context_setup_t *req) +static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_context_setup_req_t *req) { MessageDef *msg = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_SETUP_REQ); msg->ittiMsgHeader.originInstance = assoc_id; - f1ap_ue_context_setup_t *f1ap_msg = &F1AP_UE_CONTEXT_SETUP_REQ(msg); - *f1ap_msg = *req; - if (req->cu_to_du_rrc_information != NULL) { - f1ap_msg->cu_to_du_rrc_information = calloc(1, sizeof(*f1ap_msg->cu_to_du_rrc_information)); - AssertFatal(f1ap_msg->cu_to_du_rrc_information != NULL, "out of memory\n"); - const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information; - if (req->cu_to_du_rrc_information->cG_ConfigInfo != NULL) { - cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information; - du2cu_new->cG_ConfigInfo_length = du2cu_req->cG_ConfigInfo_length; - du2cu_new->cG_ConfigInfo = malloc_or_fail(du2cu_new->cG_ConfigInfo_length); - memcpy(du2cu_new->cG_ConfigInfo, du2cu_req->cG_ConfigInfo, du2cu_new->cG_ConfigInfo_length); - } - AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n"); - if (req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList != NULL) { - cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information; - DevAssert(du2cu_req->uE_CapabilityRAT_ContainerList_length > 0); - du2cu_new->uE_CapabilityRAT_ContainerList_length = du2cu_req->uE_CapabilityRAT_ContainerList_length; - du2cu_new->uE_CapabilityRAT_ContainerList = malloc(du2cu_new->uE_CapabilityRAT_ContainerList_length); - AssertFatal(du2cu_new->uE_CapabilityRAT_ContainerList != NULL, "out of memory\n"); - memcpy(du2cu_new->uE_CapabilityRAT_ContainerList, du2cu_req->uE_CapabilityRAT_ContainerList, du2cu_new->uE_CapabilityRAT_ContainerList_length); - } - if (req->cu_to_du_rrc_information->handoverPreparationInfo != NULL) { - cu_to_du_rrc_information_t *du2cu_new = f1ap_msg->cu_to_du_rrc_information; - DevAssert(du2cu_req->handoverPreparationInfo_length > 0); - du2cu_new->handoverPreparationInfo_length = du2cu_req->handoverPreparationInfo_length; - du2cu_new->handoverPreparationInfo = malloc_or_fail(du2cu_new->handoverPreparationInfo_length); - memcpy(du2cu_new->handoverPreparationInfo, du2cu_req->handoverPreparationInfo, du2cu_new->handoverPreparationInfo_length); - } - } - if (req->drbs_to_be_setup_length > 0) { - int n = req->drbs_to_be_setup_length; - f1ap_msg->drbs_to_be_setup_length = n; - f1ap_msg->drbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->drbs_to_be_setup)); - AssertFatal(f1ap_msg->drbs_to_be_setup != NULL, "out of memory\n"); - memcpy(f1ap_msg->drbs_to_be_setup, req->drbs_to_be_setup, n * sizeof(*f1ap_msg->drbs_to_be_setup)); - } - if (req->srbs_to_be_setup_length > 0) { - int n = req->srbs_to_be_setup_length; - f1ap_msg->srbs_to_be_setup_length = n; - f1ap_msg->srbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->srbs_to_be_setup)); - AssertFatal(f1ap_msg->srbs_to_be_setup != NULL, "out of memory\n"); - memcpy(f1ap_msg->srbs_to_be_setup, req->srbs_to_be_setup, n * sizeof(*f1ap_msg->srbs_to_be_setup)); - } - if (req->rrc_container_length > 0) { - f1ap_msg->rrc_container = calloc(req->rrc_container_length, sizeof(*f1ap_msg->rrc_container)); - AssertFatal(f1ap_msg->rrc_container != NULL, "out of memory\n"); - f1ap_msg->rrc_container_length = req->rrc_container_length; - memcpy(f1ap_msg->rrc_container, req->rrc_container, req->rrc_container_length); - } + F1AP_UE_CONTEXT_SETUP_REQ(msg) = cp_ue_context_setup_req(req); itti_send_msg_to_task(TASK_CU_F1, 0, msg); } -static void ue_context_modification_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_context_modif_req_t *req) +static void ue_context_modification_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_context_mod_req_t *req) { MessageDef *msg = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_MODIFICATION_REQ); msg->ittiMsgHeader.originInstance = assoc_id; - f1ap_ue_context_modif_req_t *f1ap_msg = &F1AP_UE_CONTEXT_MODIFICATION_REQ(msg); - *f1ap_msg = *req; - if (req->cu_to_du_rrc_information != NULL) { - f1ap_msg->cu_to_du_rrc_information = calloc(1, sizeof(*f1ap_msg->cu_to_du_rrc_information)); - AssertFatal(f1ap_msg->cu_to_du_rrc_information != NULL, "out of memory\n"); - AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL && req->cu_to_du_rrc_information->cG_ConfigInfo_length == 0, "cg_ConfigInfo not implemented\n"); - AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n"); - if (req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList != NULL) { - const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information; - cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information; - DevAssert(du2cu_req->uE_CapabilityRAT_ContainerList_length > 0); - du2cu_new->uE_CapabilityRAT_ContainerList_length = du2cu_req->uE_CapabilityRAT_ContainerList_length; - du2cu_new->uE_CapabilityRAT_ContainerList = malloc(du2cu_new->uE_CapabilityRAT_ContainerList_length); - AssertFatal(du2cu_new->uE_CapabilityRAT_ContainerList != NULL, "out of memory\n"); - memcpy(du2cu_new->uE_CapabilityRAT_ContainerList, du2cu_req->uE_CapabilityRAT_ContainerList, du2cu_new->uE_CapabilityRAT_ContainerList_length); - } - } - AssertFatal(req->drbs_to_be_modified_length == 0, "drbs_to_be_modified not supported yet\n"); - if (req->drbs_to_be_setup_length > 0) { - int n = req->drbs_to_be_setup_length; - f1ap_msg->drbs_to_be_setup_length = n; - f1ap_msg->drbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->drbs_to_be_setup)); - AssertFatal(f1ap_msg->drbs_to_be_setup != NULL, "out of memory\n"); - memcpy(f1ap_msg->drbs_to_be_setup, req->drbs_to_be_setup, n * sizeof(*f1ap_msg->drbs_to_be_setup)); - } - if (req->srbs_to_be_setup_length > 0) { - int n = req->srbs_to_be_setup_length; - f1ap_msg->srbs_to_be_setup_length = n; - f1ap_msg->srbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->srbs_to_be_setup)); - AssertFatal(f1ap_msg->srbs_to_be_setup != NULL, "out of memory\n"); - memcpy(f1ap_msg->srbs_to_be_setup, req->srbs_to_be_setup, n * sizeof(*f1ap_msg->srbs_to_be_setup)); - } - if (req->drbs_to_be_released_length > 0) { - int n = req->drbs_to_be_released_length; - f1ap_msg->drbs_to_be_released_length = n; - f1ap_msg->drbs_to_be_released = calloc(n, sizeof(*f1ap_msg->drbs_to_be_released)); - AssertFatal(f1ap_msg->drbs_to_be_released != NULL, "out of memory\n"); - memcpy(f1ap_msg->drbs_to_be_released, req->drbs_to_be_released, n * sizeof(*f1ap_msg->drbs_to_be_released)); - } - if (req->rrc_container_length > 0) { - f1ap_msg->rrc_container = calloc(req->rrc_container_length, sizeof(*f1ap_msg->rrc_container)); - AssertFatal(f1ap_msg->rrc_container != NULL, "out of memory\n"); - f1ap_msg->rrc_container_length = req->rrc_container_length; - memcpy(f1ap_msg->rrc_container, req->rrc_container, req->rrc_container_length); - } - if (req->transm_action_ind != NULL) { - f1ap_msg->transm_action_ind = malloc(sizeof *f1ap_msg->transm_action_ind); - AssertFatal(f1ap_msg->transm_action_ind != NULL, "out of memory\n"); - *f1ap_msg->transm_action_ind = *req->transm_action_ind; - } + F1AP_UE_CONTEXT_MODIFICATION_REQ(msg) = cp_ue_context_mod_req(req); itti_send_msg_to_task(TASK_CU_F1, 0, msg); } @@ -215,18 +119,11 @@ static void ue_context_modification_refuse_f1ap(sctp_assoc_t assoc_id, const f1a itti_send_msg_to_task(TASK_CU_F1, 0, msg); } -static void ue_context_release_command_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_context_release_cmd_t *cmd) +static void ue_context_release_command_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_context_rel_cmd_t *cmd) { MessageDef *message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_UE_CONTEXT_RELEASE_CMD); message_p->ittiMsgHeader.originInstance = assoc_id; - f1ap_ue_context_release_cmd_t *msg = &F1AP_UE_CONTEXT_RELEASE_CMD(message_p); - *msg = *cmd; - if (cmd->rrc_container_length > 0) { - msg->rrc_container = calloc(cmd->rrc_container_length, sizeof(*msg->rrc_container)); - AssertFatal(msg->rrc_container != NULL, "out of memory\n"); - msg->rrc_container_length = cmd->rrc_container_length; - memcpy(msg->rrc_container, cmd->rrc_container, cmd->rrc_container_length); - } + F1AP_UE_CONTEXT_RELEASE_CMD(message_p) = cp_ue_context_rel_cmd(cmd); itti_send_msg_to_task (TASK_CU_F1, 0, message_p); } diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index f2434eceaf..e76802338c 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -56,6 +56,7 @@ #include "intertask_interface.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_configuration.h" +#include "openair2/SDAP/nr_sdap/nr_sdap_configuration.h" typedef enum { NR_RRC_OK=0, @@ -99,6 +100,23 @@ typedef enum pdu_session_satus_e { PDU_SESSION_STATUS_RELEASED } pdu_session_status_t; +typedef struct pdusession_s { + /* Unique pdusession_id for the UE. */ + int pdusession_id; + byte_array_t nas_pdu; + /* Quality of service for this pdusession */ + seq_arr_t qos; + /* The transport layer address for the IP packets */ + pdu_session_type_t pdu_session_type; + // NG-RAN endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_outgoing; + // UPF endpoint of the NG-U (N3) transport bearer + gtpu_tunnel_t n3_incoming; + nssai_t nssai; + // PDU Session specific SDAP configuration + nr_sdap_configuration_t sdap_config; +} pdusession_t; + typedef struct pdu_session_param_s { pdusession_t param; pdu_session_status_t status; @@ -106,48 +124,16 @@ typedef struct pdu_session_param_s { ngap_cause_t cause; } rrc_pdu_session_param_t; -/** - * @brief F1-U tunnel configuration -*/ -typedef struct f1u_tunnel_s { - /* F1-U Tunnel Endpoint Identifier (on DU side) */ - uint32_t teid; - /* Downlink F1-U Transport Layer (on DU side) */ - transport_layer_addr_t addr; -} f1u_tunnel_t; - typedef struct drb_s { int status; int drb_id; - struct cnAssociation_s { - int present; - int eps_BearerIdentity; - struct sdap_config_s { - bool defaultDRB; - int pdusession_id; - int sdap_HeaderDL; - int sdap_HeaderUL; - int mappedQoS_FlowsToAdd[QOSFLOW_MAX_VALUE]; - } sdap_config; - } cnAssociation; - struct pdcp_config_s { - int discardTimer; - int pdcp_SN_SizeUL; - int pdcp_SN_SizeDL; - int t_Reordering; - int integrityProtection; - struct headerCompression_s { - int NotUsed; - int present; - } headerCompression; - struct ext1_s { - int cipheringDisabled; - } ext1; - } pdcp_config; + int pdusession_id; // F1-U Downlink Tunnel Config (on DU side) - f1u_tunnel_t du_tunnel_config; + gtpu_tunnel_t du_tunnel_config; // F1-U Uplink Tunnel Config (on CU-UP side) - f1u_tunnel_t cuup_tunnel_config; + gtpu_tunnel_t cuup_tunnel_config; + // DRB-specific PDCP configuration + nr_pdcp_configuration_t pdcp_config; } drb_t; typedef enum { @@ -163,13 +149,24 @@ typedef enum { RRC_UECAPABILITY_ENQUIRY, } rrc_action_t; +typedef struct nr_redcap_ue_cap { + bool support_of_redcap_r17; + bool support_of_16drb_redcap_r17; + bool pdcp_drb_long_sn_redcap_r17; + bool rlc_am_drb_long_sn_redcap_r17; +} nr_redcap_ue_cap_t; + +typedef struct { + int drb_id; + pdusession_level_qos_parameter_t qos; +} nr_rrc_qos_t; + /* forward declaration */ typedef struct nr_handover_context_s nr_handover_context_t; typedef struct gNB_RRC_UE_s { time_t last_seen; // last time this UE has been accessed - drb_t established_drbs[MAX_DRBS_PER_UE]; NR_DRB_ToReleaseList_t *DRB_ReleaseList; NR_SRB_INFO_TABLE_ENTRY Srb[NR_NUM_SRB]; @@ -225,8 +222,10 @@ typedef struct gNB_RRC_UE_s { rb_id_t nsa_gtp_psi[S1AP_MAX_E_RAB]; //SA block - int nb_of_pdusessions; - rrc_pdu_session_param_t pduSession[NGAP_MAX_PDU_SESSION]; + seq_arr_t pduSessions; + // Established DRBs + seq_arr_t drbs; + rrc_action_t xids[NR_RRC_TRANSACTION_IDENTIFIER_NUMBER]; uint8_t e_rab_release_command_flag; uint32_t ue_rrc_inactivity_timer; @@ -247,6 +246,7 @@ typedef struct gNB_RRC_UE_s { int max_delays_pdu_session; bool ongoing_pdusession_setup_request; + nr_redcap_ue_cap_t *redcap_cap; } gNB_RRC_UE_t; typedef struct rrc_gNB_ue_context_s { @@ -300,7 +300,8 @@ typedef struct { int physicalCellId; int absoluteFrequencySSB; int subcarrierSpacing; - plmn_identity_t plmn; + int band; + plmn_id_t plmn; uint32_t tac; bool isIntraFrequencyNeighbour; } nr_neighbour_cell_t; @@ -385,6 +386,7 @@ typedef struct gNB_RRC_INST_s { RB_HEAD(rrc_cuup_tree, nr_rrc_cuup_container_t) cuups; // CU-UPs, indexed by assoc_id size_t num_cuups; + // PDCP configuration parameters loaded during startup nr_pdcp_configuration_t pdcp_config; nr_rlc_configuration_t rlc_config; } gNB_RRC_INST; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 3a4fed6411..777ea9a8d1 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -44,7 +44,7 @@ #define SRB2 2 void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id); -void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp); +void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_resp_t *resp); void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context); void rrc_remove_nsa_user_context(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context); @@ -72,6 +72,8 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, uint32_t nas_length, uint8_t *nas_buffer); +NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cellid); + bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd); @@ -106,15 +108,13 @@ int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib, uint3 void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *const ue_context_pP, - int n_drbs, - const f1ap_drb_to_be_setup_t *drbs); + const e1ap_bearer_setup_resp_t *resp); void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *const ue_context_pP, - int n_drbs, - const f1ap_drb_to_be_setup_t *drbs, + const e1ap_bearer_setup_resp_t *resp, int n_rel_drbs, - const f1ap_drb_to_be_released_t *rel_drbs); + const f1ap_drb_to_release_t *rel_drbs); void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params); @@ -122,7 +122,11 @@ byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t * nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish); -pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession); -f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param); +f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param); void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); +NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish); +NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do_integrity, bool do_ciphering); +void activate_srb(gNB_RRC_UE_t *UE, int srb_id); +void e1_notify_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_drb_status_t *drb_status); + #endif diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f69e03b810..c2734c755a 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -38,6 +38,7 @@ #include #include #include +#include "5g_platform_types.h" #include "openair2/RRC/NR/nr_rrc_proto.h" #include "openair2/RRC/NR/rrc_gNB_UE_context.h" #include "openair3/SECU/key_nas_deriver.h" @@ -78,13 +79,15 @@ #include "oai_asn1.h" #include "openair2/F1AP/f1ap_common.h" #include "openair2/F1AP/f1ap_ids.h" -#include "openair2/F1AP/lib/f1ap_lib_extern.h" -#include "lib/f1ap_interface_management.h" +#include "openair2/F1AP/lib/f1ap_rrc_message_transfer.h" +#include "openair2/F1AP/lib/f1ap_interface_management.h" +#include "openair2/F1AP/lib/f1ap_ue_context.h" #include "rrc_gNB_NGAP.h" #include "rrc_gNB_du.h" #include "rrc_gNB_mobility.h" #include "rrc_gNB_radio_bearers.h" #include "rrc_messages_types.h" +#include "rrc_gNB_asn1.h" #include "seq_arr.h" #include "tree.h" #include "uper_decoder.h" @@ -97,6 +100,8 @@ #include "NR_DL-DCCH-Message.h" #include "ds/byte_array.h" #include "alg/find.h" +#include "NR_HandoverCommand.h" +#include "openair2/SDAP/nr_sdap/nr_sdap_configuration.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -112,16 +117,44 @@ mui_t rrc_gNB_mui = 0; typedef struct deliver_ue_ctxt_release_data_t { gNB_RRC_INST *rrc; - f1ap_ue_context_release_cmd_t *release_cmd; + f1ap_ue_context_rel_cmd_t *release_cmd; sctp_assoc_t assoc_id; } deliver_ue_ctxt_release_data_t; +const NR_RedCapParameters_r17_t *get_redcapparam_r17(NR_UE_NR_Capability_t *UE_Capability_nr) +{ + if (UE_Capability_nr && UE_Capability_nr->nonCriticalExtension && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension + && UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->redCapParameters_r17) { + return UE_Capability_nr->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->nonCriticalExtension + ->nonCriticalExtension->redCapParameters_r17; + } else + return NULL; +} + static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id) { DevAssert(deliver_pdu_data != NULL); deliver_ue_ctxt_release_data_t *data = deliver_pdu_data; - data->release_cmd->rrc_container = (uint8_t*) buf; - data->release_cmd->rrc_container_length = size; + byte_array_t rrc_cont = {.buf = (uint8_t *)buf, .len = size}; + data->release_cmd->rrc_container = &rrc_cont; data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd); } @@ -278,7 +311,7 @@ unsigned int rrc_gNB_get_next_transaction_identifier(module_id_t gnb_mod_idP) * for the radio bearer changes, with some expections for SRB1 (i.e. when resuming * an RRC connection, or at the first reconfiguration after RRC connection * reestablishment in NR, do not re-establish PDCP) */ -static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish) +NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish) { if (!ue->Srb[SRB1].Active) { LOG_E(NR_RRC, "Call SRB list while SRB1 doesn't exist\n"); @@ -299,19 +332,63 @@ static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablis return list; } -static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) +static NR_SDAP_Config_t *nr_rrc_build_sdap_config_ie(const int pdusession_id, + uint8_t n_flows, + pdusession_level_qos_parameter_t *qos, + const nr_sdap_configuration_t *sdap_config) +{ + DevAssert(n_flows < MAX_QOS_FLOWS); + // SDAP + NR_SDAP_Config_t *sc = calloc_or_fail(1, sizeof(*sc)); + sc->defaultDRB = true; + sc->pdu_Session = pdusession_id; + sc->sdap_HeaderDL = sdap_config->header_dl_absent ? NR_SDAP_Config__sdap_HeaderDL_absent : NR_SDAP_Config__sdap_HeaderDL_present; + sc->sdap_HeaderUL = sdap_config->header_ul_absent ? NR_SDAP_Config__sdap_HeaderUL_absent : NR_SDAP_Config__sdap_HeaderUL_present; + // QoS + asn1cCalloc(sc->mappedQoS_FlowsToAdd, mappedQoS_FlowsToAdd); + for (uint8_t i = 0; i < n_flows; ++i) { + DevAssert(i < MAX_QOS_FLOWS); + NR_QFI_t *qfi = calloc_or_fail(1, sizeof(*qfi)); + *qfi = qos[i].qfi; + LOG_D(NR_RRC, "Adding QFI %ld to PDU Session %d\n", *qfi, pdusession_id); + asn1cSeqAdd(&mappedQoS_FlowsToAdd->list, qfi); + } + return sc; +} + +NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do_integrity, bool do_ciphering) { - NR_DRB_ToAddMod_t *DRB_config = NULL; NR_DRB_ToAddModList_t *DRB_configList = CALLOC(sizeof(*DRB_configList), 1); - for (int i = 0; i < MAX_DRBS_PER_UE; i++) { - if (ue->established_drbs[i].status != DRB_INACTIVE) { - DRB_config = generateDRB_ASN1(&ue->established_drbs[i]); - if (reestablish) { - asn1cCallocOne(DRB_config->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true); - } - asn1cSeqAdd(&DRB_configList->list, DRB_config); + FOR_EACH_SEQ_ARR(drb_t *, drb, &ue->drbs) { + rrc_pdu_session_param_t *pduSession = find_pduSession(&ue->pduSessions, drb->pdusession_id); + if (!pduSession) { + LOG_D(NR_RRC, "PDU Session %d not found, skip\n", drb->pdusession_id); + continue; } + pdusession_t *session = &pduSession->param; + NR_DRB_ToAddMod_t *drb_ToAddMod = calloc_or_fail(1, sizeof(*drb_ToAddMod)); + drb_ToAddMod->drb_Identity = drb->drb_id; + // PDCP config + drb_ToAddMod->pdcp_Config = nr_rrc_build_pdcp_config_ie(do_integrity, do_ciphering, &drb->pdcp_config); + if (reestablish) { + asn1cCallocOne(drb_ToAddMod->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true); + } + // cn-association: SDAP config + // Get all QoS flows mapped to this DRB + pdusession_level_qos_parameter_t flows_to_add[MAX_QOS_FLOWS] = {0}; + uint8_t n_flows = 0; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, q, &session->qos) + { + if (q->drb_id == drb->drb_id) { + DevAssert(n_flows < MAX_QOS_FLOWS); + flows_to_add[n_flows++] = q->qos; + } + } + asn1cCalloc(drb_ToAddMod->cnAssociation, cn_association); + cn_association->present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config; + cn_association->choice.sdap_Config = nr_rrc_build_sdap_config_ie(drb->pdusession_id, n_flows, flows_to_add, &session->sdap_config); + asn1cSeqAdd(&DRB_configList->list, drb_ToAddMod); } if (DRB_configList->list.count == 0) { free(DRB_configList); @@ -320,12 +397,12 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) return DRB_configList; } -static void freeSRBlist(NR_SRB_ToAddModList_t *l) +void freeSRBlist(NR_SRB_ToAddModList_t *l) { ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, l); } -static void activate_srb(gNB_RRC_UE_t *UE, int srb_id) +void activate_srb(gNB_RRC_UE_t *UE, int srb_id) { AssertFatal(srb_id == 1 || srb_id == 2, "handling only SRB 1 or 2\n"); if (UE->Srb[srb_id].Active == 1) { @@ -393,10 +470,9 @@ static void rrc_gNB_generate_RRCSetup(instance_t instance, rrc->mac_rrc.dl_rrc_message_transfer(ue_data.du_assoc_id, &dl_rrc); } -static void rrc_gNB_generate_RRCReject(module_id_t module_id, rrc_gNB_ue_context_t *const ue_context_pP) +static void rrc_gNB_generate_RRCReject(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *const ue_context_pP) //----------------------------------------------------------------------------- { - gNB_RRC_INST *rrc = RC.nrrrc[module_id]; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; LOG_A(NR_RRC, "Send RRCReject to RNTI %04x\n", ue_p->rnti); @@ -420,10 +496,10 @@ static void rrc_gNB_generate_RRCReject(module_id_t module_id, rrc_gNB_ue_context .rrc_container = buf, .rrc_container_length = size, .srb_id = srbid, - .execute_duplication = 1, - .RAT_frequency_priority_information.en_dc = 0 }; rrc->mac_rrc.dl_rrc_message_transfer(ue_data.du_assoc_id, &dl_rrc); + /* release the created UE context, we rejected the UE */ + rrc_remove_ue(rrc, ue_context_pP); } //----------------------------------------------------------------------------- @@ -516,12 +592,12 @@ static NR_ReportConfigToAddMod_t *prepare_a2_event_report(const nr_a2_event_t *a return rc_A2; } -static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event) +static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event, NR_ReportConfigId_t reportConfigId) { NR_ReportConfigToAddMod_t *rc_A3 = calloc(1, sizeof(*rc_A3)); // 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID // starts from 4 - rc_A3->reportConfigId = a3_event->pci == -1 ? 3 : a3_event->pci + 4; + rc_A3->reportConfigId = reportConfigId; rc_A3->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR; NR_EventTriggerConfig_t *etrc_A3 = calloc(1, sizeof(*etrc_A3)); etrc_A3->eventId.present = NR_EventTriggerConfig__eventId_PR_eventA3; @@ -557,19 +633,19 @@ void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]); } -/** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ -nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish) +NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cellid) { - uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - nr_rrc_du_container_t *du = get_du_for_ue(rrc, UE->rrc_ue_id); + nr_rrc_du_container_t *du = get_du_by_cell_id((gNB_RRC_INST *)rrc, nr_cellid); DevAssert(du != NULL); f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; - NR_MeasConfig_t *measconfig = NULL; - NR_ReportConfigToAddMod_t *rc_PER = NULL; - NR_ReportConfigToAddMod_t *rc_A2 = NULL; - seq_arr_t *rc_A3_seq = NULL; - seq_arr_t *pci_seq = NULL; + if (du->mtc != NULL) { + NR_ReportConfigToAddMod_t *rc_PER = NULL; + NR_ReportConfigToAddMod_t *rc_A2 = NULL; + seq_arr_t rc_A3_seq = {0}; + seq_arr_t neigh_seq = {0}; + seq_arr_init(&rc_A3_seq, sizeof(NR_ReportConfigToAddMod_t)); + seq_arr_init(&neigh_seq, sizeof(nr_neighbour_cell_t)); int scs = get_ssb_scs(cell_info); int band = get_dl_band(cell_info); const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; @@ -579,30 +655,25 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC if (neighbour_config) neighbour_cells = neighbour_config->neighbour_cells; - if (neighbour_cells - && rrc->measurementConfiguration.a3_event_list - && rrc->measurementConfiguration.a3_event_list->size > 0) { + if (neighbour_cells && rrc->measurementConfiguration.a3_event_list && rrc->measurementConfiguration.a3_event_list->size > 0) { /* Loop through neighbours and find related A3 configuration If no related A3 but there is default add the default one. If default one added once as a report, no need to add it again && duplication. */ - rc_A3_seq = malloc(sizeof(seq_arr_t)); - pci_seq = malloc(sizeof(seq_arr_t)); - seq_arr_init(rc_A3_seq, sizeof(NR_ReportConfigToAddMod_t)); - seq_arr_init(pci_seq, sizeof(int)); - LOG_D(NR_RRC, "HO LOG: Preparing A3 Event Measurement Configuration!\n"); - bool is_default_a3_added = false; + LOG_D(NR_RRC, "Preparing A3 Event Measurement Configuration!\n"); + bool default_a3_added = false; // To ensure that the default configuration is only added once for (int i = 0; i < neighbour_cells->size; i++) { nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i); - if (!neighbourCell->isIntraFrequencyNeighbour) + if (default_a3_added && neighbourCell->physicalCellId == -1) continue; - seq_arr_push_back(pci_seq, &neighbourCell->physicalCellId, sizeof(int)); - const nr_a3_event_t *a3Event = get_a3_configuration(rrc, neighbourCell->physicalCellId); - if (!a3Event || is_default_a3_added) - continue; - if (a3Event->pci == -1) - is_default_a3_added = true; - seq_arr_push_back(rc_A3_seq, prepare_a3_event_report(a3Event), sizeof(NR_ReportConfigToAddMod_t)); + seq_arr_push_back(&neigh_seq, neighbourCell, sizeof(nr_neighbour_cell_t)); + const nr_a3_event_t *a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, neighbourCell->physicalCellId); + if (a3Event) { + NR_ReportConfigId_t reportConfigId = neighbourCell->physicalCellId == -1 ? 3 : i + 4; + seq_arr_push_back(&rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t)); + if (neighbourCell->physicalCellId == -1) + default_a3_added = true; + } } } if (rrc->measurementConfiguration.per_event) @@ -610,17 +681,27 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC if (rrc->measurementConfiguration.a2_event) rc_A2 = prepare_a2_event_report(rrc->measurementConfiguration.a2_event); - measconfig = get_MeasConfig(mt, band, scs, rc_PER, rc_A2, rc_A3_seq, pci_seq); + NR_MeasConfig_t *result = get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, &rc_A3_seq, &neigh_seq); + + // Clean up sequence arrays + seq_arr_free(&rc_A3_seq, NULL); + seq_arr_free(&neigh_seq, NULL); + + return result; } + return NULL; +} - if (UE->measConfig) - free_MeasConfig(UE->measConfig); - - UE->measConfig = measconfig; +/** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ +nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish) +{ + uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); // Re-establish PDCP for SRB2 only + bool do_integrity = rrc->security.do_drb_integrity; + bool do_ciphering = rrc->security.do_drb_ciphering; NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reest_bitmap); - NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish, do_integrity, do_ciphering); nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup, .transaction_id = xid, @@ -630,14 +711,16 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC .srb_config_list = SRBs}; UE->DRB_ReleaseList = NULL; // pointer transferred to params - for (int i = 0; i < UE->nb_of_pdusessions; i++) { - if (UE->pduSession[i].param.nas_pdu.len > 0) { - params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->pduSession[i].param.nas_pdu; - UE->pduSession[i].param.nas_pdu.buf = NULL; - UE->pduSession[i].param.nas_pdu.len = 0; - LOG_D(NR_RRC, "Transfer NAS info with size %ld (pdusession idx %d) to RRCReconfiguration params\n", UE->pduSession[i].param.nas_pdu.len, i); + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &UE->pduSessions) { + pdusession_t *session = &item->param; + if (session->nas_pdu.len > 0) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = session->nas_pdu; + session->nas_pdu.buf = NULL; + session->nas_pdu.len = 0; + LOG_D(NR_RRC, "Transfer NAS info with size %ld to RRCReconfiguration params\n", session->nas_pdu.len); } } + if (UE->nas_pdu.len > 0) { params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->nas_pdu; UE->nas_pdu.buf = NULL; @@ -670,12 +753,11 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ return; } - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { - ue_p->pduSession[i].xid = params.transaction_id; - } - if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { - ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) { + if (item->param.nas_pdu.buf) + item->xid = params.transaction_id; + if (item->status < PDU_SESSION_STATUS_ESTABLISHED) { + item->status = PDU_SESSION_STATUS_DONE; } } @@ -692,40 +774,24 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false); ue_p->xids[params.transaction_id] = RRC_PDUSESSION_MODIFY; - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { - rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) { + pdusession_t *session = &item->param; // bypass the new and already configured pdu sessions - if (session->status >= PDU_SESSION_STATUS_DONE) { - session->xid = params.transaction_id; + if (item->status >= PDU_SESSION_STATUS_DONE) { + item->xid = params.transaction_id; continue; } - if (session->cause.type != NGAP_CAUSE_NOTHING) { + if (item->cause.type != NGAP_CAUSE_NOTHING) { // set xid of failure pdu session - session->xid = params.transaction_id; - session->status = PDU_SESSION_STATUS_FAILED; - continue; - } - - // search exist DRB_config - int j; - for (j = 0; i < MAX_DRBS_PER_UE; j++) { - if (ue_p->established_drbs[j].status != DRB_INACTIVE - && ue_p->established_drbs[j].cnAssociation.sdap_config.pdusession_id == session->param.pdusession_id) - break; - } - - if (j == MAX_DRBS_PER_UE) { - ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_unspecified}; - session->xid = params.transaction_id; - session->status = PDU_SESSION_STATUS_FAILED; - session->cause = cause; + item->xid = params.transaction_id; + item->status = PDU_SESSION_STATUS_FAILED; continue; } // Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping - for (qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) { - switch (session->param.qos[qos_flow_index].fiveQI) { + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) { + switch (qos->qos.fiveQI) { case 1: //100ms case 2: //150ms case 3: //50ms @@ -739,18 +805,17 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t break; default: - LOG_E(NR_RRC, "not supported 5qi %lu\n", session->param.qos[qos_flow_index].fiveQI); + LOG_E(NR_RRC, "not supported 5qi %lu\n", qos->qos.fiveQI); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_not_supported_5QI_value}; - session->status = PDU_SESSION_STATUS_FAILED; - session->xid = params.transaction_id; - session->cause = cause; + item->status = PDU_SESSION_STATUS_FAILED; + item->xid = params.transaction_id; + item->cause = cause; continue; } - LOG_I(NR_RRC, "index %d, QOS flow %d, 5QI %ld \n", i, qos_flow_index, session->param.qos[qos_flow_index].fiveQI); + LOG_I(NR_RRC, "PDU Session ID %d, QOS flow %d, 5QI %ld \n", session->pdusession_id, qos_flow_index, qos->qos.fiveQI); } - - session->status = PDU_SESSION_STATUS_DONE; - session->xid = params.transaction_id; + item->status = PDU_SESSION_STATUS_DONE; + item->xid = params.transaction_id; } byte_array_t msg = do_RRCReconfiguration(¶ms); @@ -774,16 +839,21 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, uint8_t *nas_buffer) //----------------------------------------------------------------------------- { - NR_DRB_ToReleaseList_t *DRB_Release_configList2 = CALLOC(sizeof(*DRB_Release_configList2), 1); + nr_rrc_reconfig_param_t params = {.transaction_id = xid}; - for (int i = 0; i < NB_RB_MAX; i++) { - if ((ue_p->pduSession[i].status == PDU_SESSION_STATUS_TORELEASE) && ue_p->pduSession[i].xid == xid) { - asn1cSequenceAdd(DRB_Release_configList2->list, NR_DRB_Identity_t, DRB_release); - *DRB_release = i + 1; + NR_DRB_ToReleaseList_t *to_release = CALLOC(sizeof(*to_release), 1); + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) { + if ((item->status != PDU_SESSION_STATUS_TORELEASE) && item->xid != xid) + continue; + FOR_EACH_SEQ_ARR(drb_t *, drb, &ue_p->drbs) { + if (drb->pdusession_id == item->param.pdusession_id) { + asn1cSequenceAdd(to_release->list, NR_DRB_Identity_t, DRB_release); + *DRB_release = drb->drb_id; // DRB ID + } } } + params.drb_release_list = to_release; - nr_rrc_reconfig_param_t params = {.drb_release_list = DRB_Release_configList2, .transaction_id = xid}; if (nas_length > 0) { params.dedicated_NAS_msg_list[params.num_nas_msg].buf = nas_buffer; params.dedicated_NAS_msg_list[params.num_nas_msg++].len = nas_length; @@ -809,22 +879,65 @@ static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_inf nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); } -/* \brief find existing PDU session inside E1AP Bearer Modif message, or - * point to new one. - * \param bearer_modif E1AP Bearer Modification Message - * \param pdu_id PDU session ID - * \return pointer to existing PDU session, or to new/unused one. */ -static pdu_session_to_mod_t *find_or_next_pdu_session(e1ap_bearer_mod_req_t *bearer_modif, int pdu_id) +/** @brief Add DRB modification to E1AP bearer modification request + * Finds PDU session by DRB ID, creates/updates PDU session modification entry + * and appends DRB modification + * @param req E1AP bearer modification request + * @param ue UE context + * @param drb_id DRB ID to find PDU session for + * @param drb_to_mod DRB modification data to append + * @return true if successful, false if PDU session not found */ +static bool append_e1_drb_mod_req(e1ap_bearer_mod_req_t *req, + gNB_RRC_UE_t *ue, + const int drb_id, + const DRB_nGRAN_to_mod_t *drb_to_mod) { - for (int i = 0; i < bearer_modif->numPDUSessionsMod; ++i) { - if (bearer_modif->pduSessionMod[i].sessionId == pdu_id) - return &bearer_modif->pduSessionMod[i]; + // Find PDU session by DRB ID + rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb_id); + if (!pdu) { + LOG_E(NR_RRC, "UE %d: Failed to append E1 DRB mod, no PDU session found (DRB=%d)\n", ue->rrc_ue_id, drb_id); + return false; } - /* E1AP Bearer Modification has no PDU session to modify with that ID, create - * new entry */ - DevAssert(bearer_modif->numPDUSessionsMod < E1AP_MAX_NUM_PDU_SESSIONS - 1); - bearer_modif->numPDUSessionsMod += 1; - return &bearer_modif->pduSessionMod[bearer_modif->numPDUSessionsMod - 1]; + + int pdu_id = pdu->param.pdusession_id; + + // Find existing PDU session modification entry or create new one + pdu_session_to_mod_t *pdu_mod = NULL; + for (int i = 0; i < req->numPDUSessionsMod; ++i) { + if (req->pduSessionMod[i].sessionId == pdu_id) { + pdu_mod = &req->pduSessionMod[i]; + break; + } + } + + // Create new PDU session modification entry if not found + if (!pdu_mod) { + DevAssert(req->numPDUSessionsMod < E1AP_MAX_NUM_PDU_SESSIONS); + int new_index = req->numPDUSessionsMod++; + req->pduSessionMod[new_index].sessionId = pdu_id; + pdu_mod = &req->pduSessionMod[new_index]; + } + + // Append DRB modification + DevAssert(pdu_mod->numDRB2Modify < E1AP_MAX_NUM_DRBS); + pdu_mod->DRBnGRanModList[pdu_mod->numDRB2Modify++] = *drb_to_mod; + + return true; +} + +/** @brief Create DRB modification for reestablishment from existing DRB */ +static DRB_nGRAN_to_mod_t get_e1_drb_mod_reestablishment(const drb_t *drb, const bearer_context_pdcp_config_t *pdcp_config) +{ + DRB_nGRAN_to_mod_t drb_e1 = {0}; + drb_e1.id = drb->drb_id; + drb_e1.numDlUpParam = 1; + memcpy(&drb_e1.DlUpParamList[0].tl_info.tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb_e1.DlUpParamList[0].tl_info.teId = drb->du_tunnel_config.teid; + /* PDCP configuration */ + drb_e1.pdcp_config = malloc_or_fail(sizeof(*drb_e1.pdcp_config)); + *drb_e1.pdcp_config = *pdcp_config; + drb_e1.pdcp_config->pDCP_Reestablishment = true; + return drb_e1; } /** @@ -837,45 +950,18 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) .gNB_cu_up_ue_id = ue_p->rrc_ue_id, }; // Quit re-establishment notification if no CU-UP is associated - if (!is_cuup_associated(rrc)) { + if (!is_cuup_associated(rrc) || !ue_associated_to_cuup(rrc, ue_p)) { return; } - if (!ue_associated_to_cuup(rrc, ue_p)) - return; + + bool um_on_default_drb = rrc->configuration.um_on_default_drb; /* loop through active DRBs */ - for (int drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) { - drb_t *drb = get_drb(ue_p, drb_id); - if (drb->status == DRB_INACTIVE) - continue; - /* fetch an existing PDU session for this DRB */ - rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue_p, drb_id); - if (pdu == NULL) { - LOG_E(RRC, "UE %d: E1 Bearer Context Modification: no PDU session for DRB ID %d\n", ue_p->rrc_ue_id, drb_id); - continue; + FOR_EACH_SEQ_ARR(drb_t *, drb, &ue_p->drbs) { + bearer_context_pdcp_config_t pdcp = set_bearer_context_pdcp_config(drb->pdcp_config, um_on_default_drb, ue_p->redcap_cap); + DRB_nGRAN_to_mod_t drb_e1 = get_e1_drb_mod_reestablishment(drb, &pdcp); + if (!append_e1_drb_mod_req(&req, ue_p, drb->drb_id, &drb_e1)) { + LOG_W(NR_RRC, "UE %d: Failed to append E1 DRB mod for reestablishment (DRB=%d)\n", ue_p->rrc_ue_id, drb->drb_id); } - /* Get pointer to existing (or new one) PDU session to modify in E1 */ - pdu_session_to_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu->param.pdusession_id); - AssertError(pdu != NULL, - continue, - "UE %u: E1 Bearer Context Modification: PDU session %d to setup is null\n", - ue_p->rrc_ue_id, - pdu->param.pdusession_id); - /* Prepare PDU for E1 Bearear Context Modification Request */ - pdu_e1->sessionId = pdu->param.pdusession_id; - /* Fill DRB to setup with ID, DL TL and DL TEID */ - DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; - drb_e1->id = drb_id; - drb_e1->numDlUpParam = 1; - memcpy(&drb_e1->DlUpParamList[0].tl_info.tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb_e1->DlUpParamList[0].tl_info.teId = drb->du_tunnel_config.teid; - /* PDCP configuration */ - if (!drb_e1->pdcp_config) - drb_e1->pdcp_config = malloc_or_fail(sizeof(*drb_e1->pdcp_config)); - bearer_context_pdcp_config_t *pdcp_config = drb_e1->pdcp_config; - set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb); - pdcp_config->pDCP_Reestablishment = true; - /* increase DRB to modify counter */ - pdu_e1->numDRB2Modify += 1; } #if 0 @@ -891,6 +977,7 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) /* Send E1 Bearer Context Modification Request (3GPP TS 38.463) */ sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue_p); rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); + free_e1ap_context_mod_request(&req); } /** @@ -1036,11 +1123,14 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR * or at the first reconfiguration after RRC connection reestablishment in NR */ NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, 1 << SRB2); // Re-establish PDCP for SRB2 only /* Create drb-ToAddModList */ - NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true); + bool do_integrity = rrc->security.do_drb_integrity; + bool do_ciphering = rrc->security.do_drb_ciphering; + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true, do_integrity, do_ciphering); uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; nr_rrc_reconfig_param_t params = {.cell_group_config = cellGroupConfig, + .meas_config = ue_p->measConfig, .drb_config_list = DRBs, .srb_config_list = SRBs, .transaction_id = new_xid}; @@ -1135,10 +1225,17 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); LOG_E(NR_RRC, "RRCSetupRequest without random UE identity or S-TMSI not supported, let's reject the UE %04x\n", msg->crnti); - rrc_gNB_generate_RRCReject(0, ue_context_p); + rrc_gNB_generate_RRCReject(rrc, ue_context_p); return; } + // If the DU to CU RRC Container IE is not included in the INITIAL UL RRC MESSAGE TRANSFER, + // the gNB-CU should reject the UE under the assumption that the gNB-DU is not able to serve such UE + if (msg->du2cu_rrc_container == NULL) { + // this will remove the UE context + rrc_gNB_generate_RRCReject(rrc, ue_context_p); + return; + } NR_CellGroupConfig_t *cellGroupConfig = NULL; asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_CellGroupConfig, @@ -1153,6 +1250,7 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, UE->nr_cellid = msg->nr_cellid; UE->masterCellGroup = cellGroupConfig; UE->ongoing_reconfiguration = false; + UE->measConfig = nr_rrc_get_measconfig(rrc, UE->nr_cellid); activate_srb(UE, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); } @@ -1348,6 +1446,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, int servingCellRSRP = 0; int neighbourCellRSRP = 0; int scell_pci = -1; + int best_rsrp = -10000; switch (event_triggered->eventId.present) { case NR_EventTriggerConfig__eventId_PR_eventA2: @@ -1408,14 +1507,20 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, // No F1 connection but static neighbour configuration is available const nr_a3_event_t *a3_event_configuration = get_a3_configuration(rrc, neighbour->physicalCellId); // Additional check - This part can be modified according to additional cell specific Handover Margin + // a3-Offset: The actual value is field value * 0.5 dB. if (a3_event_configuration - && ((a3_event_configuration->a3_offset + a3_event_configuration->hysteresis) + && ((a3_event_configuration->a3_offset * 0.5 + a3_event_configuration->hysteresis) < (neighbourCellRSRP - servingCellRSRP))) { + if (neighbourCellRSRP > best_rsrp) { + // UE can send multiple neighbour cells A3 event report in 1 Meas Report. So, we need to find the best neighbour + best_rsrp = neighbourCellRSRP; + LOG_I(NR_RRC, "HO LOG: Serving Cell RSRP: %d - Best Neighbor RSRP: %d ! Trigger N2 HO\n", servingCellRSRP, best_rsrp); + nr_rrc_trigger_n2_ho(rrc, ue, scell_pci, neighbour); + } LOG_D(NR_RRC, "HO LOG: Trigger N2 HO for the neighbour gnb: %u cell: %lu\n", neighbour->gNB_ID, neighbour->nrcell_id); } } else if (neigh_cell && neighbour) { /* we know the cell and are connected to the DU! */ - gNB_RRC_INST *rrc = RC.nrrrc[0]; nr_rrc_du_container_t *source_du = get_du_by_cell_id(rrc, serving_cell->nr_cellid); DevAssert(source_du); nr_rrc_du_container_t *target_du = get_du_by_cell_id(rrc, neigh_cell->nr_cellid); @@ -1424,7 +1529,6 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, LOG_W(NR_RRC, "UE %d: received A3 event for stronger neighbor PCI %d, but no such neighbour in configuration\n", ue->rrc_ue_id, neighbour_pci); } } - } break; default: LOG_D(NR_RRC, "NR_EventTriggerConfig__eventId_PR_NOTHING or Other event report\n"); @@ -1546,7 +1650,7 @@ static void handle_ueCapabilityInformation(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, ue_cap_info->criticalExtensions.choice.ueCapabilityInformation->ue_CapabilityRAT_ContainerList; /* Encode UE-CapabilityRAT-ContainerList for sending to the DU */ - free(UE->ue_cap_buffer.buf); + FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer); UE->ue_cap_buffer.len = uper_encode_to_new_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, NULL, ue_CapabilityRAT_ContainerList, @@ -1565,21 +1669,26 @@ static void handle_ueCapabilityInformation(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, UE->UE_Capability_nr = 0; } - asn_dec_rval_t dec_rval = uper_decode(NULL, - &asn_DEF_NR_UE_NR_Capability, - (void **)&UE->UE_Capability_nr, - ue_cap_container->ue_CapabilityRAT_Container.buf, - ue_cap_container->ue_CapabilityRAT_Container.size, - 0, - 0); + UE->UE_Capability_nr = decode_nr_ue_capability(UE->rnti, ue_CapabilityRAT_ContainerList); + if (!UE->UE_Capability_nr) { + LOG_E(NR_RRC, "UE %d: NR capability decoding failed\n", UE->rrc_ue_id); + return; + } + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr); } - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - LOG_E(NR_RRC, "UE %d: Failed to decode nr UE capabilities (%zu bytes)\n", UE->rrc_ue_id, dec_rval.consumed); - ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr); - UE->UE_Capability_nr = 0; + const NR_RedCapParameters_r17_t *redcap_p = get_redcapparam_r17(UE->UE_Capability_nr); + if (redcap_p) { + UE->redcap_cap = calloc_or_fail(1, sizeof(*UE->redcap_cap)); + UE->redcap_cap->support_of_redcap_r17 = redcap_p->supportOfRedCap_r17 != NULL; + UE->redcap_cap->support_of_16drb_redcap_r17 = redcap_p->supportOf16DRB_RedCap_r17 != NULL; + if (UE->UE_Capability_nr->pdcp_Parameters.ext2) + UE->redcap_cap->pdcp_drb_long_sn_redcap_r17 = UE->UE_Capability_nr->pdcp_Parameters.ext2->longSN_RedCap_r17 != NULL; + if (UE->UE_Capability_nr->rlc_Parameters && UE->UE_Capability_nr->rlc_Parameters->ext2) + UE->redcap_cap->rlc_am_drb_long_sn_redcap_r17 = + UE->UE_Capability_nr->rlc_Parameters->ext2->am_WithLongSN_RedCap_r17 != NULL; } UE->UE_Capability_size = ue_cap_container->ue_CapabilityRAT_Container.size; @@ -1736,8 +1845,12 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U UE->n_initial_pdu = 0; free(UE->initial_pdus); UE->initial_pdus = NULL; - } else if (UE->nb_of_pdusessions > 0) + } else if (seq_arr_size(&UE->pduSessions) > 0) rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(rrc, UE, xid); + else + LOG_W(NR_RRC, + "UE %d: RRC Reconfiguration Complete for PDU session establishment, but no PDU sessions were setup\n", + UE->rrc_ue_id); break; case RRC_PDUSESSION_MODIFY: rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(rrc, UE, xid); @@ -1774,12 +1887,14 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); - f1ap_ue_context_modif_req_t ue_context_modif_req = { + ReconfigurationCompl_t rc = RRCreconf_success; + f1ap_ue_context_mod_req_t req = { .gNB_CU_ue_id = UE->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, - .ReconfigComplOutcome = RRCreconf_success, + .reconfig_compl = &rc, }; - rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); + rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &req); + /* nothing to be freed */ } static void rrc_gNB_generate_UECapabilityEnquiry(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue) @@ -1996,93 +2111,152 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC /* \brief fill E1 bearer modification's DRB from F1 DRB * \param drb_e1 pointer to a DRB inside an E1 bearer modification message * \param drb_f1 pointer to a DRB inside an F1 UE Ctxt modification Response */ -static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) +static DRB_nGRAN_to_mod_t fill_e1_bearer_modif_from_f1(const f1ap_drb_setup_t *drb_f1) { - drb_e1->id = drb_f1->drb_id; - drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length; - drb_e1->DlUpParamList[0].tl_info.tlAddress = drb_f1->up_dl_tnl[0].tl_address; - drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid; + DRB_nGRAN_to_mod_t drb_e1 = {0}; + drb_e1.id = drb_f1->id; + drb_e1.numDlUpParam = drb_f1->up_dl_tnl_len; + drb_e1.DlUpParamList[0].tl_info.tlAddress = drb_f1->up_dl_tnl[0].tl_address; + drb_e1.DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid; + return drb_e1; } -/** - * @brief Store F1-U DL TL and TEID in RRC -*/ -static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p) +static gtpu_tunnel_t f1u_gtp_update(uint32_t teid, const in_addr_t addr) { - f1u->teid = p->teid; - memcpy(&f1u->addr.buffer, &p->tl_address, sizeof(uint8_t) * 4); - f1u->addr.length = sizeof(in_addr_t); + gtpu_tunnel_t out = {0}; + out.teid = teid; + memcpy(&out.addr.buffer, &addr, 4); + out.addr.length = sizeof(addr); + return out; } /** * @brief Update DRB TEID information in RRC storage from received DRB list */ -static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_RRC_UE_t *ue) +static void store_du_f1u_tunnel(const f1ap_drb_setup_t *drbs, int n, gNB_RRC_UE_t *ue) { for (int i = 0; i < n; i++) { - const f1ap_drb_to_be_setup_t *drb_f1 = &drbs[i]; - AssertFatal(drb_f1->up_dl_tnl_length == 1, "can handle only one UP param\n"); - AssertFatal(drb_f1->drb_id < MAX_DRBS_PER_UE, "illegal DRB ID %ld\n", drb_f1->drb_id); - drb_t *drb = get_drb(ue, drb_f1->drb_id); - f1u_dl_gtp_update(&drb->du_tunnel_config, &drb_f1->up_dl_tnl[0]); + const f1ap_drb_setup_t *drb_f1 = &drbs[i]; + AssertFatal(drb_f1->up_dl_tnl_len == 1, "can handle only one UP param\n"); + AssertFatal(drb_f1->id < MAX_DRBS_PER_UE, "illegal DRB ID %d\n", drb_f1->id); + drb_t *drb = get_drb(&ue->drbs, drb_f1->id); + DevAssert(drb); + drb->du_tunnel_config = f1u_gtp_update(drb_f1->up_dl_tnl[0].teid, drb_f1->up_dl_tnl[0].tl_address); } } -/* - * @brief Store F1-U UL TEID and address in RRC - */ -static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p) +static DRB_nGRAN_to_mod_t get_e1_drb_mod_pdcp_status(const drb_t *drb, + bearer_context_pdcp_config_t *pdcp_config, + const ngap_drb_status_t *drb_status) { - f1u->teid = p->tl_info.teId; - memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4); - f1u->addr.length = sizeof(in_addr_t); + DevAssert(drb_status); + DevAssert(pdcp_config); + DevAssert(drb); + DRB_nGRAN_to_mod_t drb_to_mod = {0}; + drb_to_mod.id = drb->drb_id; + drb_to_mod.pdcp_sn_status_requested = false; + // PDCP SN Status Information + drb_to_mod.pdcp_config = calloc_or_fail(1, sizeof(*drb_to_mod.pdcp_config)); + *drb_to_mod.pdcp_config = *pdcp_config; + drb_to_mod.pdcp_status = calloc_or_fail(1, sizeof(*drb_to_mod.pdcp_status)); + drb_to_mod.pdcp_status->dl_count.hfn = drb_status->dl_count.hfn; + drb_to_mod.pdcp_status->dl_count.sn = drb_status->dl_count.pdcp_sn; + drb_to_mod.pdcp_status->ul_count.hfn = drb_status->ul_count.hfn; + drb_to_mod.pdcp_status->ul_count.sn = drb_status->ul_count.pdcp_sn; + return drb_to_mod; } -/* \brief use list of DRBs and send the corresponding bearer update message via - * E1 to the CU of this UE. Also updates TEID info internally */ -static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) +/** @brief Send E1 bearer context modification request to CU-UP */ +static void e1_send_bearer_modification_request(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, e1ap_bearer_mod_req_t *req) { - // Quit bearer updates if no CU-UP is associated - if (!is_cuup_associated(rrc)) { + if (req->numPDUSessionsMod == 0) { + LOG_W(NR_RRC, "UE %d: No PDU sessions to modify in E1 bearer update\n", UE->rrc_ue_id); return; } - // we assume the same UE ID in CU-UP and CU-CP + DevAssert(req->numPDUSessions == 0); + req->secInfo = malloc_or_fail(sizeof(*req->secInfo)); + fill_security_info(rrc, UE, req->secInfo); + + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); + rrc->cucp_cuup.bearer_context_mod(assoc_id, req); +} + +/** @brief Send E1 bearer updates for DRBs to setup from F1 UE Context Modification Response */ +static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_setup_t *drbs) +{ + if (!is_cuup_associated(rrc) || n <= 0) + return; + e1ap_bearer_mod_req_t req = { .gNB_cu_cp_ue_id = UE->rrc_ue_id, .gNB_cu_up_ue_id = UE->rrc_ue_id, }; for (int i = 0; i < n; i++) { - const f1ap_drb_to_be_setup_t *drb_f1 = &drbs[i]; - rrc_pdu_session_param_t *pdu_ue = find_pduSession_from_drbId(UE, drb_f1->drb_id); - if (pdu_ue == NULL) { - LOG_E(RRC, "UE %d: UE Context Modif Response: no PDU session for DRB ID %ld\n", UE->rrc_ue_id, drb_f1->drb_id); + const f1ap_drb_setup_t *drb_f1 = &drbs[i]; + int drb_id = drb_f1->id; + rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(UE, drb_id); + if (!pdu) continue; + DRB_nGRAN_to_mod_t drb_to_mod = fill_e1_bearer_modif_from_f1(drb_f1); + if (!append_e1_drb_mod_req(&req, UE, drb_id, &drb_to_mod)) { + LOG_W(NR_RRC, "UE %d: Failed to append E1 DRB mod from F1 (DRB=%d)\n", UE->rrc_ue_id, drb_id); } - pdu_session_to_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); - DevAssert(pdu_e1 != NULL); - pdu_e1->sessionId = pdu_ue->param.pdusession_id; - DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; - /* Fill E1 bearer context modification */ - fill_e1_bearer_modif(drb_e1, drb_f1); - pdu_e1->numDRB2Modify += 1; } - DevAssert(req.numPDUSessionsMod > 0); - DevAssert(req.numPDUSessions == 0); - // Always send security information - req.secInfo = malloc_or_fail(sizeof(*req.secInfo)); - fill_security_info(rrc, UE, req.secInfo); + e1_send_bearer_modification_request(rrc, UE, &req); + free_e1ap_context_mod_request(&req); +} - // send the E1 bearer modification request message to update F1-U tunnel info - sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); - rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); +/** @brief Request PDCP status from CU-UP during inter-CU handover */ +static void e1_request_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) +{ + if (!is_cuup_associated(rrc)) + return; + + e1ap_bearer_mod_req_t req = { + .gNB_cu_cp_ue_id = UE->rrc_ue_id, + .gNB_cu_up_ue_id = UE->rrc_ue_id, + }; + + FOR_EACH_SEQ_ARR(drb_t *, drb, &UE->drbs) { + DRB_nGRAN_to_mod_t drb_to_mod = {.id = drb->drb_id, .pdcp_sn_status_requested = true}; + LOG_D(NR_RRC, "PDCP Status requested (drb_id=%d)\n", drb->drb_id); + if (!append_e1_drb_mod_req(&req, UE, drb->drb_id, &drb_to_mod)) { + LOG_W(NR_RRC, "UE %d: Failed to append E1 DRB mod for PDCP status request (DRB=%d)\n", UE->rrc_ue_id, drb->drb_id); + } + } + + e1_send_bearer_modification_request(rrc, UE, &req); + free_e1ap_context_mod_request(&req); +} + +/** @brief Notify CU-UP with PDCP status during handover */ +void e1_notify_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_drb_status_t *drb_status) +{ + if (!is_cuup_associated(rrc) || !drb_status) + return; + + e1ap_bearer_mod_req_t req = { + .gNB_cu_cp_ue_id = UE->rrc_ue_id, + .gNB_cu_up_ue_id = UE->rrc_ue_id, + }; + + FOR_EACH_SEQ_ARR(drb_t *, drb, &UE->drbs) { + LOG_I(NR_RRC, "Forward PDCP Status to CU-UP (drb_id=%d)\n", drb->drb_id); + bearer_context_pdcp_config_t pdcp_config = set_bearer_context_pdcp_config(drb->pdcp_config, rrc->configuration.um_on_default_drb, UE->redcap_cap); + DRB_nGRAN_to_mod_t drb_to_mod = get_e1_drb_mod_pdcp_status(drb, &pdcp_config, drb_status); + append_e1_drb_mod_req(&req, UE, drb->drb_id, &drb_to_mod); + } + + e1_send_bearer_modification_request(rrc, UE, &req); + free_e1ap_context_mod_request(&req); } static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance_t instance) { - f1ap_ue_context_setup_t *resp = &F1AP_UE_CONTEXT_SETUP_RESP(msg_p); + f1ap_ue_context_setup_resp_t *resp = &F1AP_UE_CONTEXT_SETUP_RESP(msg_p); gNB_RRC_INST *rrc = RC.nrrrc[instance]; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, resp->gNB_CU_ue_id); if (!ue_context_p) { @@ -2093,13 +2267,22 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance UE->f1_ue_context_active = true; NR_CellGroupConfig_t *cellGroupConfig = NULL; - asn_dec_rval_t dec_rval = uper_decode_complete(NULL, - &asn_DEF_NR_CellGroupConfig, - (void **)&cellGroupConfig, - (uint8_t *)resp->du_to_cu_rrc_information->cellGroupConfig, - resp->du_to_cu_rrc_information->cellGroupConfig_length); + byte_array_t *cgc = &resp->du_to_cu_rrc_info.cell_group_config; + asn_dec_rval_t dec_rval = + uper_decode_complete(NULL, &asn_DEF_NR_CellGroupConfig, (void **)&cellGroupConfig, (uint8_t *)cgc->buf, cgc->len); AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "Cell group config decode error\n"); + if (resp->du_to_cu_rrc_info.meas_gap_config) { + NR_MeasGapConfig_t *measGapConfig = NULL; + asn_dec_rval_t dec_rval_mgc = uper_decode_complete(NULL, + &asn_DEF_NR_MeasGapConfig, + (void **)&measGapConfig, + (uint8_t *)resp->du_to_cu_rrc_info.meas_gap_config->buf, + resp->du_to_cu_rrc_info.meas_gap_config->len); + AssertFatal(dec_rval_mgc.code == RC_OK && dec_rval_mgc.consumed > 0, "measGapConfig decode error\n"); + UE->measConfig->measGapConfig = measGapConfig; + } + if (UE->masterCellGroup) { ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); LOG_I(RRC, "UE %04x replacing existing CellGroupConfig with new one received from DU\n", UE->rnti); @@ -2113,16 +2296,16 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance return; } - if (resp->drbs_to_be_setup_length > 0) { - int num_drb = get_number_active_drbs(UE); - DevAssert(num_drb == 0 || num_drb == resp->drbs_to_be_setup_length); + if (resp->drbs_len > 0) { + int num_drb = seq_arr_size(&UE->drbs); + DevAssert(num_drb == 0 || num_drb == resp->drbs_len); /* Note: we would ideally check that SRB2 is acked, but at least LiteOn DU * seems buggy and does not ack, so simply check that locally we activated */ AssertFatal(UE->Srb[1].Active && UE->Srb[2].Active, "SRBs 1 and 2 must be active during DRB Establishment"); - store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE); + store_du_f1u_tunnel(resp->drbs, resp->drbs_len, UE); if (num_drb == 0) - e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); + e1_send_bearer_updates(rrc, UE, resp->drbs_len, resp->drbs); else cuup_notify_reestablishment(rrc, UE); } @@ -2143,23 +2326,25 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_assoc_t assoc_id) { const int instance = 0; - f1ap_ue_context_release_req_t *req = &F1AP_UE_CONTEXT_RELEASE_REQ(msg_p); + f1ap_ue_context_rel_req_t *req = &F1AP_UE_CONTEXT_RELEASE_REQ(msg_p); gNB_RRC_INST *rrc = RC.nrrrc[instance]; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_CU_ue_id); - // TODO what happens if no AMF connected? should also handle, set an_release true int srbid = 1; - if (!ue_context_p) { - LOG_W(RRC, "could not find UE context for CU UE ID %u: auto-generate release command\n", req->gNB_CU_ue_id); + // valid AMF UE NGAP ID range is 0..2^40-1 + if (!ue_context_p || ue_context_p->ue_context.amf_ue_ngap_id >= (1LL << 40)) { + const char *reason = !ue_context_p ? "could not find UE context" : "no AMF"; + LOG_W(RRC, "%s for CU UE ID %u: auto-generate release command\n", reason, req->gNB_CU_ue_id); uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; int size = do_NR_RRCRelease(buffer, NR_RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(0)); - f1ap_ue_context_release_cmd_t ue_context_release_cmd = { + RETURN_IF_INVALID_ASSOC_ID(assoc_id); + f1ap_ue_context_rel_cmd_t ue_context_release_cmd = { .gNB_CU_ue_id = req->gNB_CU_ue_id, .gNB_DU_ue_id = req->gNB_DU_ue_id, .cause = F1AP_CAUSE_RADIO_NETWORK, .cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release - .srb_id = srbid, + .srb_id = &srbid, // C-ifRRCContainer => is added below }; - deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd}; + deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd, .assoc_id = assoc_id}; nr_pdcp_data_req_srb(req->gNB_CU_ue_id, srbid, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data); return; } @@ -2173,12 +2358,11 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as // ongoing; free the UE, and remove the HO context. LOG_W(NR_RRC, "UE %d: release request from source DU ID %ld during HO, marking HO as complete\n", UE->rrc_ue_id, source_ctx->du->setup_req->gNB_DU_id); RETURN_IF_INVALID_ASSOC_ID(source_ctx->du->assoc_id); - f1ap_ue_context_release_cmd_t cmd = { + f1ap_ue_context_rel_cmd_t cmd = { .gNB_CU_ue_id = UE->rrc_ue_id, .gNB_DU_ue_id = source_ctx->du_ue_id, .cause = F1AP_CAUSE_RADIO_NETWORK, .cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure - .srb_id = DL_SCH_LCID_DCCH, }; rrc->mac_rrc.ue_context_release_command(assoc_id, &cmd); nr_rrc_finalize_ho(UE); @@ -2197,10 +2381,18 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as static void rrc_delete_ue_data(gNB_RRC_UE_t *UE) { + /* Clean up handover context if it exists */ + if (UE->ho_context) + nr_rrc_finalize_ho(UE); ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr); ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, UE->measResults); + FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer); free_MeasConfig(UE->measConfig); + free(UE->redcap_cap); + UE->redcap_cap = NULL; + seq_arr_free(&UE->pduSessions, free_pdusession); + seq_arr_free(&UE->drbs, free_drb); } void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p) @@ -2218,7 +2410,7 @@ void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p) static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p) { const int instance = 0; - f1ap_ue_context_release_complete_t *complete = &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg_p); + f1ap_ue_context_rel_cplt_t *complete = &F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg_p); gNB_RRC_INST *rrc = RC.nrrrc[instance]; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, complete->gNB_CU_ue_id); if (!ue_context_p) { @@ -2231,16 +2423,14 @@ static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p) /* only trigger release if it has been requested by core * otherwise, it might be CU that requested release on a DU during normal * operation (i.e, handover) */ - uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]; - get_pduSession_array(UE, pdu_sessions); - rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, UE->nb_of_pdusessions, pdu_sessions); + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, &UE->pduSessions); rrc_remove_ue(RC.nrrrc[0], ue_context_p); } } static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, instance_t instance) { - f1ap_ue_context_modif_resp_t *resp = &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg_p); + f1ap_ue_context_mod_resp_t *resp = &F1AP_UE_CONTEXT_MODIFICATION_RESP(msg_p); gNB_RRC_INST *rrc = RC.nrrrc[instance]; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, resp->gNB_CU_ue_id); if (!ue_context_p) { @@ -2249,27 +2439,34 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - if (resp->drbs_to_be_setup_length > 0) { - store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE); - e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); + bool is_inter_cu_ho = UE->ho_context && UE->ho_context->source && !UE->ho_context->target; + if (resp->drbs_len > 0) { // DRB to setup + store_du_f1u_tunnel(resp->drbs, resp->drbs_len, UE); + e1_send_bearer_updates(rrc, UE, resp->drbs_len, resp->drbs); + } else if (is_inter_cu_ho) { // PDCP status request + e1_request_pdcp_status(rrc, UE); } - if (resp->du_to_cu_rrc_information != NULL && resp->du_to_cu_rrc_information->cellGroupConfig != NULL) { + if (resp->du_to_cu_rrc_info) { NR_CellGroupConfig_t *cellGroupConfig = NULL; - asn_dec_rval_t dec_rval = uper_decode_complete(NULL, - &asn_DEF_NR_CellGroupConfig, - (void **)&cellGroupConfig, - (uint8_t *)resp->du_to_cu_rrc_information->cellGroupConfig, - resp->du_to_cu_rrc_information->cellGroupConfig_length); + byte_array_t *cgc = &resp->du_to_cu_rrc_info->cell_group_config; + asn_dec_rval_t dec_rval = + uper_decode_complete(NULL, &asn_DEF_NR_CellGroupConfig, (void **)&cellGroupConfig, (uint8_t *)cgc->buf, cgc->len); AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "Cell group config decode error\n"); - if (UE->masterCellGroup) { - ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); - LOG_I(RRC, "UE %04x replacing existing CellGroupConfig with new one received from DU\n", UE->rnti); + /* hack for interoperability with srsRAN: ignore cell group config if empty */ + /* cell group config is empty if buffer length is 2 and content is all 0 */ + bool cgc_is_empty = cgc->len == 2 && cgc->buf[0] == 0 && cgc->buf[1] == 0; + if (!cgc_is_empty) { + if (UE->masterCellGroup) { + ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); + LOG_I(RRC, "UE %04x replacing existing CellGroupConfig with new one received from DU\n", UE->rnti); + } + UE->masterCellGroup = cellGroupConfig; + rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE); + } else { + LOG_W(NR_RRC, "hack: UE %d: ignore empty CellGroupConfig in UEContextModificationResponse\n", UE->rrc_ue_id); } - UE->masterCellGroup = cellGroupConfig; - - rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE); } // Reconfiguration should have been sent to the UE, so it will attempt the @@ -2363,30 +2560,25 @@ unsigned int mask_flip(unsigned int x) { return((((x>>8) + (x<<8))&0xffff)>>6); } -pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession) -{ - pdusession_t *pdu = &pduSession->param; - for (int i = 0; i < pdu->nb_qos; i++) { - if (qfi == pdu->qos[i].qfi) - return &pdu->qos[i]; - } - AssertFatal(1 == 0, "The pdu session %d does not contain a qos flow with qfi = %d\n", pdu->pdusession_id, qfi); - return NULL; -} - /* \bref return F1AP QoS characteristics based on Qos flow parameters */ -f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param) +f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param) { - f1ap_qos_characteristics_t qos_char = {0}; + f1ap_qos_flow_param_t qos_char = {0}; if (qos_param->fiveQI_type == DYNAMIC) { qos_char.qos_type = DYNAMIC; - qos_char.dynamic.fiveqi = qos_param->fiveQI; - qos_char.dynamic.qos_priority_level = qos_param->qos_priority; + qos_char.dyn.prio = qos_param->qos_priority; + qos_char.dyn.pdb = 100; // TODO + qos_char.dyn.per.scalar = 10; // TODO + qos_char.dyn.per.exponent = 100; // TODO } else { qos_char.qos_type = NON_DYNAMIC; - qos_char.non_dynamic.fiveqi = qos_param->fiveQI; - qos_char.non_dynamic.qos_priority_level = qos_param->qos_priority; + qos_char.nondyn.fiveQI = qos_param->fiveQI; } + const qos_arp_t *a = &qos_param->arp; + qos_char.arp.prio = a->priority_level; + qos_char.arp.preempt_cap = + a->pre_emp_capability == PEC_MAY_TRIGGER_PREEMPTION ? MAY_TRIGGER_PREEMPTION : SHALL_NOT_TRIGGER_PREEMPTION; + qos_char.arp.preempt_vuln = a->pre_emp_vulnerability == PEV_PREEMPTABLE ? PREEMPTABLE : NOT_PREEMPTABLE; return qos_char; } @@ -2396,38 +2588,55 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const pdu_session_setup_t *pduSession, int numPduSession, - f1ap_drb_to_be_setup_t drbs[32]) + f1ap_drb_to_setup_t drbs[32]) { int nb_drb = 0; for (int p = 0; p < numPduSession; ++p) { - rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, pduSession[p].id, false); - DevAssert(RRC_pduSession); + rrc_pdu_session_param_t *pdu = find_pduSession(&UE->pduSessions, pduSession[p].id); + DevAssert(pdu); for (int i = 0; i < pduSession[p].numDRBSetup; i++) { const DRB_nGRAN_setup_t *drb_config = &pduSession[p].DRBnGRanList[i]; - f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; - drb->drb_id = pduSession[p].DRBnGRanList[i].id; - drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; - drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tl_info.tlAddress; - drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].tl_info.teId; - drb->up_ul_tnl_length = 1; + drb_t *rrc_drb = get_drb(&UE->drbs, pduSession[p].DRBnGRanList[i].id); + nr_pdcp_configuration_t pdcp = rrc_drb->pdcp_config; + DevAssert(rrc_drb); + + DevAssert(nb_drb < MAX_DRBS_PER_UE); + f1ap_drb_to_setup_t *drb = &drbs[nb_drb]; + drb->id = rrc_drb->drb_id; + + drb->qos_choice = F1AP_QOS_CHOICE_NR; /* pass QoS info to MAC */ int nb_qos_flows = drb_config->numQosFlowSetup; AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n"); - drb->drb_info.flows_to_be_setup_length = nb_qos_flows; - drb->drb_info.flows_mapped_to_drb = calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t)); - AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); + drb->nr.flows_len = nb_qos_flows; + drb->nr.flows = calloc_or_fail(nb_qos_flows, sizeof(*drb->nr.flows)); for (int j = 0; j < nb_qos_flows; j++) { - drb->drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi; - pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession); - drb->drb_info.flows_mapped_to_drb[j].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char); + int qfi = drb_config->qosFlows[j].qfi; + /* find the QoS characteristics stored at RRC based on QFI returned + * from E1. We expect this to correspond to a QFI we passed to E1 + * previously, so we expect it to exist. */ + nr_rrc_qos_t *qos_param = find_qos(&pdu->param.qos, qfi); + DevAssert(qos_param); + f1ap_drb_flows_mapped_t *flow = &drb->nr.flows[j]; + flow->qfi = qfi; + flow->param = get_qos_char_from_qos_flow_param(&qos_param->qos); } /* the DRB QoS parameters: we just reuse the ones from the first flow */ - drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; + drb->nr.drb_qos = drb->nr.flows[0].param; /* pass NSSAI info to MAC */ - drb->nssai = RRC_pduSession->param.nssai; + drb->nr.nssai = pdu->param.nssai; + + drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tl_info.tlAddress; + drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].tl_info.teId; + drb->up_ul_tnl_len = 1; + drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; + DevAssert(pdcp.drb.sn_size == 18 || pdcp.drb.sn_size == 12); + drb->dl_pdcp_sn_len = malloc_or_fail(sizeof(*drb->dl_pdcp_sn_len)); + *drb->dl_pdcp_sn_len = pdcp.drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; + drb->ul_pdcp_sn_len = malloc_or_fail(sizeof(*drb->ul_pdcp_sn_len)); + *drb->ul_pdcp_sn_len = pdcp.drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; nb_drb++; } @@ -2455,33 +2664,39 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp // save the tunnel address for the PDU sessions for (int i = 0; i < resp->numPDUSessions; i++) { pdu_session_setup_t *e1_pdu = &resp->pduSession[i]; - rrc_pdu_session_param_t *rrc_pdu = find_pduSession(UE, e1_pdu->id, false); + rrc_pdu_session_param_t *rrc_pdu = find_pduSession(&UE->pduSessions, e1_pdu->id); if (rrc_pdu == NULL) { LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id); continue; } - rrc_pdu->param.gNB_teid_N3 = e1_pdu->tl_info.teId; - memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4); - rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t); + rrc_pdu->param.n3_outgoing = f1u_gtp_update(e1_pdu->tl_info.teId, e1_pdu->tl_info.tlAddress); // save the tunnel address for the DRBs - for (int i = 0; i < e1_pdu->numDRBSetup; i++) { - DRB_nGRAN_setup_t *drb_config = &e1_pdu->DRBnGRanList[i]; + for (int j = 0; j < e1_pdu->numDRBSetup; j++) { + DRB_nGRAN_setup_t *drb_config = &e1_pdu->DRBnGRanList[j]; // numUpParam only relevant in F1, but not monolithic AssertFatal(drb_config->numUpParam <= 1, "can only up to one UP param\n"); - drb_t *drb = get_drb(UE, drb_config->id); - f1u_ul_gtp_update(&drb->cuup_tunnel_config, &drb_config->UpParamList[0]); + drb_t *drb = get_drb(&UE->drbs, drb_config->id); + if (!drb) { + LOG_E(RRC, "E1: DRB %ld not found for PDU session %ld\n", drb_config->id, e1_pdu->id); + continue; + } + UP_TL_information_t *tl_info = &drb_config->UpParamList[0].tl_info; + drb->cuup_tunnel_config = f1u_gtp_update(tl_info->teId, tl_info->tlAddress); } } - /* Instruction towards the DU for DRB configuration and tunnel creation */ - f1ap_drb_to_be_setup_t drbs[32]; // maximum DRB can be 32 - int nb_drb = fill_drb_to_be_setup_from_e1_resp(rrc, UE, resp->pduSession, resp->numPDUSessions, drbs); + // If HO Preparation Info is stored, N2 handover is ongoing + if (UE->ho_context) { + LOG_I(NR_RRC, "Received Bearer Context Setup Response for UE %d with valid HO Context\n", UE->rrc_ue_id); + UE->ho_context->target->ho_trigger(rrc, UE); + return; + } if (!UE->f1_ue_context_active) - rrc_gNB_generate_UeContextSetupRequest(rrc, ue_context_p, nb_drb, drbs); + rrc_gNB_generate_UeContextSetupRequest(rrc, ue_context_p, resp); else - rrc_gNB_generate_UeContextModificationRequest(rrc, ue_context_p, nb_drb, drbs, 0, NULL); + rrc_gNB_generate_UeContextModificationRequest(rrc, ue_context_p, resp, 0, NULL); } /** @brief E1AP Bearer Context Setup Failure processing on CU-CP */ @@ -2506,10 +2721,26 @@ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t return; } - // there is not really anything to do here as of now + int n_drb_mod = 0; + int drb_ids[MAX_DRBS_PER_UE] = {0}; + e1_pdcp_status_info_t pdcp_status[MAX_DRBS_PER_UE] = {0}; for (int i = 0; i < resp->numPDUSessionsMod; ++i) { const pdu_session_modif_t *pdu = &resp->pduSessionMod[i]; LOG_I(RRC, "UE %d: PDU session ID %ld modified %d bearers\n", resp->gNB_cu_cp_ue_id, pdu->id, pdu->numDRBModified); + for (int j = 0; j < pdu->numDRBModified; j++) { + // Trigger UL RAN Status Transfer + if (pdu->DRBnGRanModList[j].pdcp_status) { + DevAssert(n_drb_mod < MAX_DRBS_PER_UE); + drb_ids[n_drb_mod] = pdu->DRBnGRanModList[j].id; + pdcp_status[n_drb_mod++] = *pdu->DRBnGRanModList[j].pdcp_status; + } + } + } + if (n_drb_mod) { + LOG_I(NR_RRC, "UE %d: received PDU Status Info - send UL RAN Status Transfer\n", resp->gNB_cu_cp_ue_id); + gNB_RRC_UE_t *ue = &ue_context_p->ue_context; + if (ue->ho_context && ue->ho_context->source) + ue->ho_context->source->ho_status_transfer(rrc, ue, n_drb_mod, drb_ids, pdcp_status); } } @@ -2542,6 +2773,34 @@ void rrc_gNB_process_e1_bearer_context_release_cplt(const e1ap_bearer_release_cp LOG_I(RRC, "UE %d: received bearer release complete\n", cplt->gNB_cu_cp_ue_id); } +static void print_meas_result_quantity(FILE *f, const NR_MeasQuantityResults_t *mqr) +{ + fprintf(f, " resultSSB:"); + if (!mqr) { + fprintf(f, " NOT PROVIDED\n"); + return; + } + if (mqr->rsrp) { + const long rrsrp = *mqr->rsrp - 156; + fprintf(f, " RSRP %ld dBm", rrsrp); + } else { + fprintf(f, " RSRP not provided"); + } + if (mqr->rsrq) { + const float rrsrq = (float) (*mqr->rsrq - 87) / 2.0f; + fprintf(f, " RSRQ %.1f dB", rrsrq); + } else { + fprintf(f, " RSRQ not provided"); + } + if (mqr->sinr) { + const float rsinr = (float) (*mqr->sinr - 46) / 2.0f; + fprintf(f, " SINR %.1f dB", rsinr); + } else { + fprintf(f, " SINR not provided"); + } + fprintf(f, "\n"); +} + static void print_rrc_meas(FILE *f, const NR_MeasResults_t *measresults) { DevAssert(measresults->measResultServingMOList.list.count >= 1); @@ -2550,37 +2809,21 @@ static void print_rrc_meas(FILE *f, const NR_MeasResults_t *measresults) NR_MeasResultServMO_t *measresultservmo = measresults->measResultServingMOList.list.array[0]; NR_MeasResultNR_t *measresultnr = &measresultservmo->measResultServingCell; - NR_MeasQuantityResults_t *mqr = measresultnr->measResult.cellResults.resultsSSB_Cell; if (measresultnr->physCellId) fprintf(f, - " servingCellId %ld MeasResultNR for phyCellId %ld:\n resultSSB:", + " servingCellId %ld MeasResultNR for phyCellId %ld:\n", measresultservmo->servCellId, *measresultnr->physCellId); - if (mqr != NULL) { - const long rrsrp = *mqr->rsrp - 156; - const float rrsrq = (float) (*mqr->rsrq - 87) / 2.0f; - const float rsinr = (float) (*mqr->sinr - 46) / 2.0f; - fprintf(f, "RSRP %ld dBm RSRQ %.1f dB SINR %.1f dB\n", rrsrp, rrsrq, rsinr); - } else { - fprintf(f, "NOT PROVIDED\n"); - } + print_meas_result_quantity(f, measresultnr->measResult.cellResults.resultsSSB_Cell); if (measresults->measResultNeighCells && measresults->measResultNeighCells->present == NR_MeasResults__measResultNeighCells_PR_measResultListNR) { NR_MeasResultListNR_t *meas_neigh = measresults->measResultNeighCells->choice.measResultListNR; for (int i = 0; i < meas_neigh->list.count; ++i) { NR_MeasResultNR_t *measresultneigh = meas_neigh->list.array[i]; - NR_MeasQuantityResults_t *neigh_mqr = measresultneigh->measResult.cellResults.resultsSSB_Cell; if (measresultneigh->physCellId) - fprintf(f, " neighboring cell for phyCellId %ld:\n resultSSB:", *measresultneigh->physCellId); - if (mqr != NULL) { - const long rrsrp = *neigh_mqr->rsrp - 156; - const float rrsrq = (float)(*neigh_mqr->rsrq - 87) / 2.0f; - const float rsinr = (float)(*neigh_mqr->sinr - 46) / 2.0f; - fprintf(f, "RSRP %ld dBm RSRQ %.1f dB SINR %.1f dB\n", rrsrp, rrsrq, rsinr); - } else { - fprintf(f, "NOT PROVIDED\n"); - } + fprintf(f, " neighboring cell for phyCellId %ld:\n", *measresultneigh->physCellId); + print_meas_result_quantity(f, measresultneigh->measResult.cellResults.resultsSSB_Cell); } } } @@ -2633,11 +2876,8 @@ static bool write_rrc_stats(const gNB_RRC_INST *rrc) time_t last_seen = now - ue_ctxt->last_seen; fprintf(f, " last RRC activity: %ld seconds ago\n", last_seen); - if (ue_ctxt->nb_of_pdusessions == 0) - fprintf(f, " (no PDU sessions)\n"); - for (int nb_pdu = 0; nb_pdu < ue_ctxt->nb_of_pdusessions; ++nb_pdu) { - const rrc_pdu_session_param_t *pdu = &ue_ctxt->pduSession[nb_pdu]; - fprintf(f, " PDU session %d ID %d status %s\n", nb_pdu, pdu->param.pdusession_id, get_pdusession_status_text(pdu->status)); + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, pdu, &ue_ctxt->pduSessions) { + fprintf(f, " PDU session ID %d status %s\n", pdu->param.pdusession_id, get_pdusession_status_text(pdu->status)); } fprintf(f, " associated DU: "); @@ -2735,6 +2975,10 @@ void *rrc_gnb_task(void *args_p) { rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(msg_p, instance); break; + case NGAP_DL_RAN_STATUS_TRANSFER: + rrc_gNB_process_NGAP_DL_RAN_STATUS_TRANSFER(msg_p, instance); + break; + /* Messages from F1AP task */ case F1AP_SETUP_REQ: AssertFatal(!NODE_IS_DU(RC.nrrrc[instance]->node_type), "should not receive F1AP_SETUP_REQUEST in DU!\n"); @@ -2744,10 +2988,12 @@ void *rrc_gnb_task(void *args_p) { case F1AP_UE_CONTEXT_SETUP_RESP: rrc_CU_process_ue_context_setup_response(msg_p, instance); + free_ue_context_setup_resp(&F1AP_UE_CONTEXT_SETUP_RESP(msg_p)); break; case F1AP_UE_CONTEXT_MODIFICATION_RESP: rrc_CU_process_ue_context_modification_response(msg_p, instance); + free_ue_context_mod_resp(&F1AP_UE_CONTEXT_MODIFICATION_RESP(msg_p)); break; case F1AP_UE_CONTEXT_MODIFICATION_REQUIRED: @@ -2756,10 +3002,12 @@ void *rrc_gnb_task(void *args_p) { case F1AP_UE_CONTEXT_RELEASE_REQ: rrc_CU_process_ue_context_release_request(msg_p, msg_p->ittiMsgHeader.originInstance); + free_ue_context_rel_req(&F1AP_UE_CONTEXT_RELEASE_REQ(msg_p)); break; case F1AP_UE_CONTEXT_RELEASE_COMPLETE: rrc_CU_process_ue_context_release_complete(msg_p); + free_ue_context_rel_cplt(&F1AP_UE_CONTEXT_RELEASE_COMPLETE(msg_p)); break; case F1AP_LOST_CONNECTION: @@ -2850,6 +3098,16 @@ void *rrc_gnb_task(void *args_p) { rrc_gNB_process_PAGING_IND(msg_p, instance); break; + case NGAP_HANDOVER_REQUEST: + rrc_gNB_process_Handover_Request(RC.nrrrc[instance], instance, &NGAP_HANDOVER_REQUEST(msg_p)); + rrc_gNB_free_Handover_Request(&NGAP_HANDOVER_REQUEST(msg_p)); // Free transfered NG message + break; + + case NGAP_HANDOVER_COMMAND: + rrc_gNB_process_HandoverCommand(RC.nrrrc[instance], &NGAP_HANDOVER_COMMAND(msg_p)); + rrc_gNB_free_Handover_Command(&NGAP_HANDOVER_COMMAND(msg_p)); // Free transfered NG message + break; + default: LOG_E(NR_RRC, "[gNB %ld] Received unexpected message %s\n", instance, msg_name_p); break; @@ -2894,12 +3152,13 @@ void rrc_gNB_generate_RRCRelease(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) LOG_UE_DL_EVENT(UE, "Send RRC Release\n"); f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); - f1ap_ue_context_release_cmd_t ue_context_release_cmd = { + int srbid = 1; + f1ap_ue_context_rel_cmd_t ue_context_release_cmd = { .gNB_CU_ue_id = UE->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, .cause = F1AP_CAUSE_RADIO_NETWORK, .cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release - .srb_id = DL_SCH_LCID_DCCH, + .srb_id = &srbid, // C-ifRRCContainer => is added below }; deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd, .assoc_id = ue_data.du_assoc_id}; nr_pdcp_data_req_srb(UE->rrc_ue_id, DL_SCH_LCID_DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data); @@ -3000,8 +3259,7 @@ int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint //----------------------------------------------------------------------------- void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *const ue_context_pP, - int n_drbs, - const f1ap_drb_to_be_setup_t *drbs) + const e1ap_bearer_setup_resp_t *resp) //----------------------------------------------------------------------------- { gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; @@ -3009,47 +3267,78 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc, AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); - cu_to_du_rrc_information_t cu2du = {0}; - cu_to_du_rrc_information_t *cu2du_p = NULL; - if (ue_p->ue_cap_buffer.len > 0 && ue_p->ue_cap_buffer.buf != NULL) { - cu2du_p = &cu2du; - cu2du.uE_CapabilityRAT_ContainerList = ue_p->ue_cap_buffer.buf; - cu2du.uE_CapabilityRAT_ContainerList_length = ue_p->ue_cap_buffer.len; + f1ap_cu_to_du_rrc_info_t cu2du = {0}; + if (ue_p->ue_cap_buffer.len > 0) { + cu2du.ue_cap = malloc_or_fail(sizeof(byte_array_t)); + *cu2du.ue_cap = copy_byte_array(ue_p->ue_cap_buffer); + } + + nr_rrc_du_container_t *du = get_du_for_ue((gNB_RRC_INST *)rrc, ue_p->rrc_ue_id); + byte_array_t *meas_timing_config = NULL; + if (du->mtc && ue_p->measConfig && ue_p->measConfig->measObjectToAddModList) { + NR_MeasObjectToAddModList_t *mo_list = ue_p->measConfig->measObjectToAddModList; + NR_ARFCN_ValueNR_t ssbFrequency0; + for (int i = 0; i < mo_list->list.count; i++) { + NR_MeasObjectToAddMod_t *mo = mo_list->list.array[i]; + if (mo->measObject.present == NR_MeasObjectToAddMod__measObject_PR_measObjectNR) { + NR_MeasObjectNR_t *monr = mo->measObject.choice.measObjectNR; + if (i == 0) { + ssbFrequency0 = *monr->ssbFrequency; + } else if (ssbFrequency0 != *monr->ssbFrequency) { + meas_timing_config = calloc_or_fail(1, sizeof(*meas_timing_config)); + meas_timing_config->buf = calloc_or_fail(1, NR_RRC_BUF_SIZE); + meas_timing_config->len = do_NR_MeasurementTimingConfiguration(du->mtc, meas_timing_config->buf, NR_RRC_BUF_SIZE); + cu2du.meas_timing_config = meas_timing_config; + break; + } + } + } } int nb_srb = 1; - f1ap_srb_to_be_setup_t srbs[1] = {{.srb_id = 2, .lcid = 2}}; - activate_srb(ue_p, 2); + f1ap_srb_to_setup_t *srbs = calloc_or_fail(nb_srb, sizeof(*srbs)); + srbs[0].id = 2; + activate_srb(ue_p, srbs[0].id); + + /* Instruction towards the DU for DRB configuration and tunnel creation */ + f1ap_drb_to_setup_t *drbs = calloc_or_fail(32, sizeof(*drbs)); // maximum DRB can be 32 + int n_drbs = fill_drb_to_be_setup_from_e1_resp(rrc, ue_p, resp->pduSession, resp->numPDUSessions, drbs); + + /* gNB-DU UE Aggregate Maximum Bit Rate Uplink is C- ifDRBSetup */ + uint64_t *agg_mbr = malloc_or_fail(sizeof(*agg_mbr)); + *agg_mbr = 1000000000 /* bps */; - /* the callback will fill the UE context setup request and forward it */ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); - f1ap_ue_context_setup_t ue_context_setup_req = { + uint32_t *du_ue_id = malloc_or_fail(sizeof(*du_ue_id)); + *du_ue_id = ue_data.secondary_ue; + f1ap_ue_context_setup_req_t ue_context_setup_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, - .gNB_DU_ue_id = ue_data.secondary_ue, + .gNB_DU_ue_id = du_ue_id, .plmn.mcc = rrc->configuration.plmn[0].mcc, .plmn.mnc = rrc->configuration.plmn[0].mnc, .plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length, .nr_cellid = rrc->nr_cellid, - .servCellId = 0, /* TODO: correct value? */ - .srbs_to_be_setup_length = nb_srb, - .srbs_to_be_setup = srbs, - .drbs_to_be_setup_length = n_drbs, - .drbs_to_be_setup = (f1ap_drb_to_be_setup_t *)drbs, - .cu_to_du_rrc_information = cu2du_p, + .servCellIndex = 0, /* TODO: correct value? */ + .srbs_len = nb_srb, + .srbs = srbs, + .drbs_len = n_drbs, + .drbs = drbs, + .cu_to_du_rrc_info = cu2du, + .gnb_du_ue_agg_mbr_ul = agg_mbr, }; rrc->mac_rrc.ue_context_setup_request(ue_data.du_assoc_id, &ue_context_setup_req); + free_ue_context_setup_req(&ue_context_setup_req); LOG_I(RRC, "UE %d trigger UE context setup request with %d DRBs\n", ue_p->rrc_ue_id, n_drbs); } //----------------------------------------------------------------------------- void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *const ue_context_pP, - int n_drbs, - const f1ap_drb_to_be_setup_t *drbs, + const e1ap_bearer_setup_resp_t *resp, int n_rel_drbs, - const f1ap_drb_to_be_released_t *rel_drbs) + const f1ap_drb_to_release_t *rel_drbs) //----------------------------------------------------------------------------- { gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; @@ -3058,30 +3347,32 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n"); - cu_to_du_rrc_information_t cu2du = {0}; - cu_to_du_rrc_information_t *cu2du_p = NULL; - if (ue_p->ue_cap_buffer.len > 0 && ue_p->ue_cap_buffer.buf != NULL) { - cu2du_p = &cu2du; - cu2du.uE_CapabilityRAT_ContainerList = ue_p->ue_cap_buffer.buf; - cu2du.uE_CapabilityRAT_ContainerList_length = ue_p->ue_cap_buffer.len; + f1ap_cu_to_du_rrc_info_t *cu2du = NULL; + if (ue_p->ue_cap_buffer.len > 0) { + cu2du = calloc_or_fail(1, sizeof(*cu2du)); + cu2du->ue_cap = calloc_or_fail(1, sizeof(*cu2du->ue_cap)); + *cu2du->ue_cap = copy_byte_array(ue_p->ue_cap_buffer); } + /* Instruction towards the DU for DRB configuration and tunnel creation */ + f1ap_drb_to_setup_t *drbs = calloc_or_fail(32, sizeof(*drbs)); // maximum DRB can be 32 + int n_drbs = fill_drb_to_be_setup_from_e1_resp(rrc, ue_p, resp->pduSession, resp->numPDUSessions, drbs); + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); - f1ap_ue_context_modif_req_t ue_context_modif_req = { + f1ap_ue_context_mod_req_t ue_context_modif_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, - .plmn.mcc = rrc->configuration.plmn[0].mcc, - .plmn.mnc = rrc->configuration.plmn[0].mnc, - .plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length, - .nr_cellid = rrc->nr_cellid, - .servCellId = 0, /* TODO: correct value? */ - .drbs_to_be_setup_length = n_drbs, - .drbs_to_be_setup = (f1ap_drb_to_be_setup_t *)drbs, - .drbs_to_be_released_length = n_rel_drbs, - .drbs_to_be_released = (f1ap_drb_to_be_released_t *)rel_drbs, - .cu_to_du_rrc_information = cu2du_p, + .drbs_len = n_drbs, + .drbs = drbs, + .drbs_rel_len = n_rel_drbs, + .drbs_rel = (f1ap_drb_to_release_t *)rel_drbs, + .cu_to_du_rrc_info = cu2du, }; rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); + // avoid attempt to release rel_drbs + ue_context_modif_req.drbs_rel_len = 0; + ue_context_modif_req.drbs_rel = NULL; + free_ue_context_mod_req(&ue_context_modif_req); LOG_I(RRC, "UE %d trigger UE context modification request with %d DRBs\n", ue_p->rrc_ue_id, n_drbs); } diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 9fd4306962..7d75384a9b 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -36,8 +36,14 @@ #include #include #include +#include #include "E1AP_ConfidentialityProtectionIndication.h" #include "E1AP_IntegrityProtectionIndication.h" +#include "NR_UE-CapabilityRAT-ContainerList.h" +#include "NR_HandoverCommand.h" +#include "NR_HandoverCommand-IEs.h" +#include "E1AP_RLC-Mode.h" +#include "NR_PDCP-Config.h" #include "NGAP_CauseRadioNetwork.h" #include "NGAP_Dynamic5QIDescriptor.h" #include "NGAP_GTPTunnel.h" @@ -48,6 +54,7 @@ #include "NGAP_QosFlowSetupRequestItem.h" #include "NGAP_asn_constant.h" #include "NGAP_ProtocolIE-Field.h" +#include "NGAP_CellSize.h" #include "NR_UE-NR-Capability.h" #include "NR_UERadioAccessCapabilityInformation.h" #include "MAC/mac.h" @@ -81,6 +88,9 @@ #include "rrc_messages_types.h" #include "s1ap_messages_types.h" #include "uper_encoder.h" +#include "rrc_gNB_mobility.h" +#include "rrc_gNB_du.h" +#include "common/utils/alg/find.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -161,6 +171,36 @@ static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn) return guami; } +/** @brief Copy NGAP PDU Session Transfer item to RRC pdusession_t struct */ +static void cp_pdusession_transfer_to_pdusession(pdusession_t *dst, const pdusession_transfer_t *src) +{ + dst->pdu_session_type = src->pdu_session_type; + dst->n3_incoming = src->n3_incoming; + /* QoS handling */ + DevAssert(!dst->qos.data); + DevAssert(src->nb_qos < MAX_QOS_FLOWS); + // Initialise mapped QoS list per PDU Session + seq_arr_init(&dst->qos, sizeof(nr_rrc_qos_t)); + // Add QoS flow to list + for (uint8_t i = 0; i < src->nb_qos; ++i) { + if (!add_qos(&dst->qos, &src->qos[i])) { + LOG_E(NR_RRC, "Failed to add QoS flow %d for PDU session %d\n", src->qos[i].qfi, dst->pdusession_id); + continue; + } + } +} + +/** @brief Copy NGAP PDU Session Resource item to RRC pdusession_t struct to setup */ +static void cp_pdusession_resource_item_to_pdusession(pdusession_t *dst, const pdusession_resource_item_t *src) +{ + dst->pdusession_id = src->pdusession_id; + dst->nas_pdu = src->nas_pdu; + dst->nssai = src->nssai; + + // Use the PDU session transfer function to handle QoS and other PDU session transfer-specific fields + cp_pdusession_transfer_to_pdusession(dst, &src->pdusessionTransfer); +} + /** * @brief Prepare the Initial UE Message (Uplink NAS) to be forwarded to the AMF over N2 * extracts NAS PDU, Selected PLMN and Registered AMF from the RRCSetupComplete @@ -194,7 +234,8 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC } int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; // Convert 1-based PLMN Identity IE to 0-based index req->plmn = rrc->configuration.plmn[selected_plmn_identity]; // Select from the stored list - LOG_I(NGAP, "Selected PLMN in the NG Initial UE Message: MCC %u, MNC %u\n", req->plmn.mcc, req->plmn.mnc); + plmn_id_t *p = &req->plmn; + LOG_I(NGAP, "Selected PLMN in the NG Initial UE Message: MCC=%03d MNC=%0*d\n", p->mcc, p->mnc_digit_length, p->mnc); /* 5G-S-TMSI */ if (UE->Initialue_identity_5g_s_TMSI.presence) { @@ -225,112 +266,55 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC itti_send_msg_to_task(TASK_NGAP, rrc->module_id, message_p); } -static void fill_qos(NGAP_QosFlowSetupRequestList_t *qos, pdusession_t *session) +/** @brief Returns an instance of E1AP DRB To Setup List */ +static DRB_nGRAN_to_setup_t fill_e1_drb_to_setup(const drb_t *rrc_drb, + const pdusession_t *session, + bool const um_on_default_drb, + const nr_redcap_ue_cap_t *redcap_cap) { - DevAssert(qos->list.count > 0); - DevAssert(qos->list.count <= NGAP_maxnoofQosFlows); - for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) { - NGAP_QosFlowSetupRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx]; - // Set the QOS informations - session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; - NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics; - AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx); - if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { - AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = NON_DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI; + DRB_nGRAN_to_setup_t drb_ngran = {0}; + drb_ngran.id = rrc_drb->drb_id; + + drb_ngran.sdap_config.defaultDRB = true; + drb_ngran.sdap_config.sDAP_Header_UL = session->sdap_config.header_ul_absent ? 1 : 0; + drb_ngran.sdap_config.sDAP_Header_DL = session->sdap_config.header_dl_absent ? 1 : 0; + + drb_ngran.pdcp_config = set_bearer_context_pdcp_config(rrc_drb->pdcp_config, um_on_default_drb, redcap_cap); + + drb_ngran.numCellGroups = 1; + for (int k = 0; k < drb_ngran.numCellGroups; k++) { + drb_ngran.cellGroupList[k] = MCG; // 1 cellGroup only + } + + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) { + pdusession_level_qos_parameter_t *qos_session = &qos->qos; + DevAssert(drb_ngran.numQosFlow2Setup < MAX_QOS_FLOWS); + qos_flow_to_setup_t *qos_flow = &drb_ngran.qosFlows[drb_ngran.numQosFlow2Setup++]; + qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; + qos_flow->qfi = qos_session->qfi; + qos_char->qos_type = qos_session->fiveQI_type; + if (qos_char->qos_type == DYNAMIC) { + qos_char->dynamic.fiveqi = qos_session->fiveQI; + qos_char->dynamic.qos_priority_level = qos_session->qos_priority; } else { - AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI); + qos_char->non_dynamic.fiveqi = qos_session->fiveQI; + qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority; } - ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority; - NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters.allocationAndRetentionPriority; - tmp->priority_level = tmp2->priorityLevelARP; - tmp->pre_emp_capability = tmp2->pre_emptionCapability; - tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability; + ngran_allocation_retention_priority_t *arp_out = &qos_flow->qos_params.alloc_reten_priority; + qos_arp_t *arp_in = &qos_session->arp; + arp_out->priority_level = arp_in->priority_level; + arp_out->preemption_capability = arp_in->pre_emp_capability; + arp_out->preemption_vulnerability = arp_in->pre_emp_vulnerability; } - session->nb_qos = qos->list.count; + + return drb_ngran; } -static int decodePDUSessionResourceSetup(pdusession_t *session) +static nr_sdap_configuration_t get_sdap_config(const bool enable_sdap) { - NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = NULL; - asn_codec_ctx_t st = {.max_stack_size = 100 * 1000}; - asn_dec_rval_t dec_rval = aper_decode(&st, - &asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, - (void **)&pdusessionTransfer, - session->pdusessionTransfer.buf, - session->pdusessionTransfer.len, - 0, - 0); - - if (dec_rval.code != RC_OK) { - LOG_E(NR_RRC, "can not decode PDUSessionResourceSetupRequestTransfer\n"); - return -1; - } - - for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) { - NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i]; - switch (pdusessionTransfer_ies->id) { - /* optional PDUSessionAggregateMaximumBitRate */ - case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate: - break; - - /* mandatory UL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: { - NGAP_GTPTunnel_t *gTPTunnel_p = pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel; - - /* Set the transport layer address */ - memcpy(session->upf_addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); - - session->upf_addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused; - - /* GTP tunnel endpoint ID */ - OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, session->gtp_teid); - } - - break; - - /* optional AdditionalUL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation: - break; - - /* optional DataForwardingNotPossible */ - case NGAP_ProtocolIE_ID_id_DataForwardingNotPossible: - break; - - /* mandatory PDUSessionType */ - case NGAP_ProtocolIE_ID_id_PDUSessionType: - session->pdu_session_type = (uint8_t)pdusessionTransfer_ies->value.choice.PDUSessionType; - break; - - /* optional SecurityIndication */ - case NGAP_ProtocolIE_ID_id_SecurityIndication: - break; - - /* optional NetworkInstance */ - case NGAP_ProtocolIE_ID_id_NetworkInstance: - break; - - /* mandatory QosFlowSetupRequestList */ - case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: - fill_qos(&pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList, session); - break; - - /* optional CommonNetworkInstance */ - case NGAP_ProtocolIE_ID_id_CommonNetworkInstance: - break; - - default: - LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id); - return -1; - } - } - ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer); - - return 0; + nr_sdap_configuration_t sdap = {.header_dl_absent = !enable_sdap, .header_ul_absent = !enable_sdap}; + return sdap; } /** @@ -358,15 +342,15 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession e1ap_nssai_t cuup_nssai = {0}; for (int i = 0; i < n; i++) { - rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true); + // Retrieve SDAP configuration and PDU Session to the list + sessions[i].sdap_config = get_sdap_config(rrc->configuration.enable_sdap); + rrc_pdu_session_param_t *pduSession = add_pduSession(&UE->pduSessions, &sessions[i]); + if (!pduSession) { + LOG_E(NR_RRC, "Could not add PDU Session %d for UE %d\n", sessions[i].pdusession_id, UE->rrc_ue_id); + continue; + } pdusession_t *session = &pduSession->param; - session->pdusession_id = sessions[i].pdusession_id; - LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); - session->pdu_session_type = sessions[i].pdu_session_type; - session->nas_pdu = sessions[i].nas_pdu; - session->pdusessionTransfer = sessions[i].pdusessionTransfer; - session->nssai = sessions[i].nssai; - decodePDUSessionResourceSetup(session); + // Fill E1 Bearer Context Modification Request bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; security_information_t *secInfo = &bearer_req.secInfo; secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; @@ -386,63 +370,25 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession : SECURITY_NOT_NEEDED; sec->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? SECURITY_REQUIRED : SECURITY_NOT_NEEDED; - pdu->UP_TL_information.teId = session->gtp_teid; - memcpy(&pdu->UP_TL_information.tlAddress, session->upf_addr.buffer, sizeof(in_addr_t)); - - /* we assume for the moment one DRB per PDU session. Activate the bearer, - * and configure in RRC. */ - int drb_id = get_next_available_drb_id(UE); - drb_t *rrc_drb = generateDRB(UE, - drb_id, - pduSession, - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering, - &rrc->pdcp_config); + gtpu_tunnel_t *n3_incoming = &session->n3_incoming; + pdu->UP_TL_information.teId = n3_incoming->teid; + memcpy(&pdu->UP_TL_information.tlAddress, n3_incoming->addr.buffer, sizeof(in_addr_t)); + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, n3_incoming->addr.buffer, ip_str, sizeof(ip_str)); + LOG_I(NR_RRC, "Bearer Context Setup: PDU Session ID=%d, incoming TEID=0x%08x, Addr=%s\n", session->pdusession_id, n3_incoming->teid, ip_str); pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding - for (int j=0; j < pdu->numDRB2Setup; j++) { - DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; - - drb->id = rrc_drb->drb_id; - /* SDAP */ - struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; - drb->sdap_config.defaultDRB = sdap_config->defaultDRB; - drb->sdap_config.sDAP_Header_UL = sdap_config->sdap_HeaderUL; - drb->sdap_config.sDAP_Header_DL = sdap_config->sdap_HeaderDL; - /* PDCP */ - set_bearer_context_pdcp_config(&drb->pdcp_config, rrc_drb, rrc->configuration.um_on_default_drb); - - drb->numCellGroups = 1; // assume one cell group associated with a DRB - - // Set all Cell Group IDs to MCG - for (int k=0; k < drb->numCellGroups; k++) { - cell_group_id_t *cellGroup = drb->cellGroupList + k; - *cellGroup = MCG; - } - - drb->numQosFlow2Setup = session->nb_qos; - for (int k=0; k < drb->numQosFlow2Setup; k++) { - qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; - pdusession_level_qos_parameter_t *qos_session = session->qos + k; - - qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; - qos_flow->qfi = qos_session->qfi; - qos_char->qos_type = qos_session->fiveQI_type; - if (qos_char->qos_type == DYNAMIC) { - qos_char->dynamic.fiveqi = qos_session->fiveQI; - qos_char->dynamic.qos_priority_level = qos_session->qos_priority; - } else { - qos_char->non_dynamic.fiveqi = qos_session->fiveQI; - qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority; - } - - ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; - ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority; - rent_priority->priority_level = rent_priority_in->priority_level; - rent_priority->preemption_capability = rent_priority_in->pre_emp_capability; - rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability; + for (int j = 0; j < pdu->numDRB2Setup; j++) { + drb_t *rrc_drb = nr_rrc_add_drb(&UE->drbs, session->pdusession_id, &rrc->pdcp_config); + if (!rrc_drb) { + LOG_E(NR_RRC, "UE %d: failed to add DRB for PDU session ID %d\n", UE->rrc_ue_id, session->pdusession_id); + return false; } + DevAssert(seq_arr_size(&pduSession->param.qos) == 1); + nr_rrc_qos_t *qos = (nr_rrc_qos_t *)seq_arr_at(&pduSession->param.qos, 0); + qos->drb_id = rrc_drb->drb_id; // map DRB to QFI + LOG_I(NR_RRC, "UE %d: added DRB %d for PDU session ID %d\n", UE->rrc_ue_id, rrc_drb->drb_id, rrc_drb->pdusession_id); + pdu->DRBnGRanList[0] = fill_e1_drb_to_setup(rrc_drb, session, rrc->configuration.um_on_default_drb, UE->redcap_cap); } } /* Limitation: we assume one fixed CU-UP per UE. We base the selection on @@ -480,7 +426,7 @@ static void send_ngap_initial_context_setup_resp_fail(instance_t instance, resp->gNB_ue_ngap_id = msg->gNB_ue_ngap_id; for (int i = 0; i < msg->nb_of_pdusessions; i++) { - fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession_param[i].pdusession_id, cause); + fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession[i].pdusession_id, cause); } resp->nb_of_pdusessions = 0; resp->nb_of_pdusessions_failed = msg->nb_of_pdusessions; @@ -519,10 +465,9 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t /* if there are PDU sessions to setup, store them to be created once * security (and UE capabilities) are received */ UE->n_initial_pdu = req->nb_of_pdusessions; - UE->initial_pdus = calloc(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); - AssertFatal(UE->initial_pdus != NULL, "out of memory\n"); + UE->initial_pdus = calloc_or_fail(UE->n_initial_pdu, sizeof(*UE->initial_pdus)); for (int i = 0; i < UE->n_initial_pdu; ++i) - UE->initial_pdus[i] = req->pdusession_param[i]; + cp_pdusession_resource_item_to_pdusession(&UE->initial_pdus[i], &req->pdusession[i]); } /* security */ @@ -567,6 +512,35 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t return 0; } +static gtpu_tunnel_t cp_gtp_tunnel(const gtpu_tunnel_t in) +{ + gtpu_tunnel_t out = {0}; + out.teid = in.teid; + out.addr.length = in.addr.length; + memcpy(out.addr.buffer, in.addr.buffer, out.addr.length); + return out; +} + +/** @brief Fill NG PDU Session Setup item from stored setup PDU Session in RRC list */ +static pdusession_setup_t fill_ngap_pdusession_setup(pdusession_t *session) +{ + DevAssert(session != NULL); + pdusession_setup_t out = {0}; + out.pdusession_id = session->pdusession_id; + out.pdu_session_type = session->pdu_session_type; + out.n3_outgoing = cp_gtp_tunnel(session->n3_outgoing); + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos_session, &session->qos) { + DevAssert(out.nb_of_qos_flow < MAX_QOS_FLOWS); + pdusession_associate_qosflow_t *q = &out.associated_qos_flows[out.nb_of_qos_flow++]; + q->qfi = qos_session->qos.qfi; + q->qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; + } + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, out.n3_outgoing.addr.buffer, ip_str, sizeof(ip_str)); + LOG_I(NR_RRC, "PDU Session Setup: ID=%d, outgoing TEID=0x%08x, Addr=%s\n", out.pdusession_id, out.n3_outgoing.teid, ip_str); + return out; +} + void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) { MessageDef *msg_p = NULL; @@ -577,21 +551,10 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_ resp->gNB_ue_ngap_id = UE->rrc_ue_id; - for (int pdusession = 0; pdusession < UE->nb_of_pdusessions; pdusession++) { - rrc_pdu_session_param_t *session = &UE->pduSession[pdusession]; + // Optional: PDU Sessions to Setup + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) { if (session->status == PDU_SESSION_STATUS_DONE) { - pdu_sessions_done++; - resp->pdusessions[pdusession].pdusession_id = session->param.pdusession_id; - resp->pdusessions[pdusession].gtp_teid = session->param.gNB_teid_N3; - memcpy(resp->pdusessions[pdusession].gNB_addr.buffer, - session->param.gNB_addr_N3.buffer, - sizeof(resp->pdusessions[pdusession].gNB_addr.buffer)); - resp->pdusessions[pdusession].gNB_addr.length = 4; // Fixme: IPv4 hard coded here - resp->pdusessions[pdusession].nb_of_qos_flow = session->param.nb_qos; - for (int qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) { - resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; - resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; - } + resp->pdusessions[pdu_sessions_done++] = fill_ngap_pdusession_setup(&session->param); } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { session->status = PDU_SESSION_STATUS_FAILED; ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID}; @@ -771,32 +734,10 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE ngap_pdusession_setup_resp_t *resp = &NGAP_PDUSESSION_SETUP_RESP(msg_p); resp->gNB_ue_ngap_id = UE->rrc_ue_id; - for (int pdusession = 0; pdusession < UE->nb_of_pdusessions; pdusession++) { - rrc_pdu_session_param_t *session = &UE->pduSession[pdusession]; + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) { if (session->status == PDU_SESSION_STATUS_DONE) { - pdusession_setup_t *tmp = &resp->pdusessions[pdu_sessions_done]; - tmp->pdusession_id = session->param.pdusession_id; - tmp->nb_of_qos_flow = session->param.nb_qos; - tmp->gtp_teid = session->param.gNB_teid_N3; - tmp->pdu_session_type = session->param.pdu_session_type; - tmp->gNB_addr.length = session->param.gNB_addr_N3.length; - memcpy(tmp->gNB_addr.buffer, session->param.gNB_addr_N3.buffer, tmp->gNB_addr.length); - for (int qos_flow_index = 0; qos_flow_index < tmp->nb_of_qos_flow; qos_flow_index++) { - tmp->associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; - tmp->associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; - } - + resp->pdusessions[pdu_sessions_done++] = fill_ngap_pdusession_setup(&session->param); session->status = PDU_SESSION_STATUS_ESTABLISHED; - LOG_I(NR_RRC, - "msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d, pdusession_id %d, teid: %u \n ", - pdu_sessions_done, - pdusession, - session->status, - xid, - UE->nb_of_pdusessions, - tmp->pdusession_id, - tmp->gtp_teid); - pdu_sessions_done++; } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) { session->status = PDU_SESSION_STATUS_FAILED; pdusession_failed_t *fail = &resp->pdusessions_failed[pdu_sessions_failed]; @@ -807,10 +748,6 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE } resp->nb_of_pdusessions = pdu_sessions_done; resp->nb_of_pdusessions_failed = pdu_sessions_failed; - // } else { - // LOG_D(NR_RRC,"xid does not corresponds (context pdu_sessions index %d, status %d, xid %d/%d) \n ", - // pdusession, UE->pdusession[pdusession].status, xid, UE->pdusession[pdusession].xid); - // } } if ((pdu_sessions_done > 0 || pdu_sessions_failed)) { @@ -818,8 +755,8 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); } - for(int i = 0; i < NB_RB_MAX; i++) { - UE->pduSession[i].xid = -1; + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) { + session->xid = -1; } return; @@ -860,9 +797,7 @@ static void send_ngap_pdu_session_setup_resp_fail(instance_t instance, ngap_pdus resp->nb_of_pdusessions_failed = msg->nb_pdusessions_tosetup; resp->nb_of_pdusessions = 0; for (int i = 0; i < resp->nb_of_pdusessions_failed; ++i) { - fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], - msg->pdusession_setup_params[i].pdusession_id, - cause); + fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession[i].pdusession_id, cause); } itti_send_msg_to_task(TASK_NGAP, instance, msg_resp); } @@ -908,8 +843,8 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins // At least one because marking one as existing, and setting up another, that // might be more work than is worth it. See 8.2.1.4 in 38.413 for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) { - const pdusession_t *p = &msg->pdusession_setup_params[i]; - rrc_pdu_session_param_t *exist = find_pduSession(UE, p->pdusession_id, false /* don't create */); + const pdusession_resource_item_t *p = &msg->pdusession[i]; + rrc_pdu_session_param_t *exist = find_pduSession(&UE->pduSessions, p->pdusession_id); if (exist) { LOG_E(NR_RRC, "UE %d: already has existing PDU session %d rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id, p->pdusession_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_PDU_SESSION_ID_INSTANCES}; @@ -941,7 +876,13 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return; } - if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRate.br_dl)) { + pdusession_t to_setup[NGAP_MAX_PDU_SESSION] = {0}; + for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) + cp_pdusession_resource_item_to_pdusession(&to_setup[i], &msg->pdusession[i]); + + uint64_t dl_ambr = msg->has_ue_ambr ? msg->ueAggMaxBitRate.br_dl : 0; + + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, to_setup, dl_ambr)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE}; @@ -952,102 +893,34 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins } } -static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *session) +/** @brief Update existing QoS Flow mapped in the UE context */ +static void nr_rrc_update_qos(seq_arr_t *list, const int nb_qos, const pdusession_level_qos_parameter_t *in_qos) { - // we need to duplicate the function fill_qos because all data types are slightly different - DevAssert(qos->list.count > 0); - DevAssert(qos->list.count <= NGAP_maxnoofQosFlows); - for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) { - NGAP_QosFlowAddOrModifyRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx]; - // Set the QOS informations - session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier; - NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters->qosCharacteristics; - AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx); - if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { - AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = NON_DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI; + DevAssert(nb_qos == 1); + DevAssert(nb_qos < MAX_QOS_FLOWS); + for (uint8_t i = 0; i < nb_qos; ++i) { + nr_rrc_qos_t *qos = find_qos(list, in_qos[i].qfi); + if (qos) { + AssertFatal(qos->qos.qfi == in_qos[i].qfi, "QoS Flow to modify must match existing one"); + LOG_I(NR_RRC, "Updating QoS for QFI=%d\n", in_qos[i].qfi); + qos->qos = in_qos[i]; } else { - AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = DYNAMIC; - session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI); + LOG_E(NR_RRC, "Failed to update QoS for QFI=%d: QoS flow not found\n", in_qos[i].qfi); } - - ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority; - NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters->allocationAndRetentionPriority; - tmp->priority_level = tmp2->priorityLevelARP; - tmp->pre_emp_capability = tmp2->pre_emptionCapability; - tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability; } - session->nb_qos = qos->list.count; } -static void decodePDUSessionResourceModify(pdusession_t *param, const byte_array_t pdu) +/** @brief Update stored pdusession_t in list from NGAP PDU Session Resource item */ +static void nr_rrc_update_pdusession(pdusession_t *dst, const pdusession_resource_item_t *src) { - NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = NULL; - asn_dec_rval_t dec_rval = aper_decode(NULL, - &asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, - (void **)&pdusessionTransfer, - pdu.buf, - pdu.len, - 0, - 0); - - if (dec_rval.code != RC_OK) { - LOG_E(NR_RRC, "could not decode PDUSessionResourceModifyRequestTransfer\n"); - return; - } - - for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) { - NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j]; - switch (pdusessionTransfer_ies->id) { - /* optional PDUSessionAggregateMaximumBitRate */ - case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate\n"); - break; - - /* optional UL-NGU-UP-TNLModifyList */ - case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList\n"); - break; - - /* optional NetworkInstance */ - case NGAP_ProtocolIE_ID_id_NetworkInstance: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_NetworkInstance\n"); - break; - - /* optional QosFlowAddOrModifyRequestList */ - case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList: - fill_qos2(&pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList, param); - break; - - /* optional QosFlowToReleaseList */ - case NGAP_ProtocolIE_ID_id_QosFlowToReleaseList: - // TODO - LOG_E(NR_RRC, "Can't handle NGAP_ProtocolIE_ID_id_QosFlowToReleaseList\n"); - break; - - /* optional AdditionalUL-NGU-UP-TNLInformation */ - case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation\n"); - break; - - /* optional CommonNetworkInstance */ - case NGAP_ProtocolIE_ID_id_CommonNetworkInstance: - // TODO - LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_CommonNetworkInstance\n"); - break; - - default: - LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id); - return; - } - } - ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer,pdusessionTransfer ); + dst->pdusession_id = src->pdusession_id; + dst->nas_pdu = src->nas_pdu; + dst->pdu_session_type = src->pdusessionTransfer.pdu_session_type; + dst->n3_incoming = src->pdusessionTransfer.n3_incoming; + dst->nssai = src->nssai; + DevAssert(dst->qos.data); // QoS list has to be initialized at this stage + // Update QoS flow + nr_rrc_update_qos(&dst->qos, src->pdusessionTransfer.nb_qos, src->pdusessionTransfer.qos); } //------------------------------------------------------------------------------ @@ -1068,35 +941,21 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins gNB_RRC_UE_t *UE = &ue_context_p->ue_context; bool all_failed = true; for (int i = 0; i < req->nb_pdusessions_tomodify; i++) { - rrc_pdu_session_param_t *sess; - const pdusession_t *sessMod = req->pdusession_modify_params + i; - for (sess = UE->pduSession; sess < UE->pduSession + UE->nb_of_pdusessions; sess++) - if (sess->param.pdusession_id == sessMod->pdusession_id) - break; - if (sess == UE->pduSession + UE->nb_of_pdusessions) { + const pdusession_resource_item_t *sessMod = &req->pdusession[i]; + rrc_pdu_session_param_t *session = find_pduSession(&UE->pduSessions, sessMod->pdusession_id); + if (!session) { LOG_W(NR_RRC, "Requested modification of non-existing PDU session, refusing modification\n"); - UE->nb_of_pdusessions++; - sess->status = PDU_SESSION_STATUS_FAILED; - sess->param.pdusession_id = sessMod->pdusession_id; - sess->cause.type = NGAP_CAUSE_RADIO_NETWORK; - UE->pduSession[i].cause.type = NGAP_CAUSE_RADIO_NETWORK; - UE->pduSession[i].cause.value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID; + rrc_pdu_session_param_t to_add = {0}; + to_add.status = PDU_SESSION_STATUS_FAILED; + to_add.param.pdusession_id = sessMod->pdusession_id; + to_add.cause.type = NGAP_CAUSE_RADIO_NETWORK; + to_add.cause.value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID; + seq_arr_push_back(&UE->pduSessions, &to_add, sizeof(to_add)); } else { all_failed = false; - sess->status = PDU_SESSION_STATUS_NEW; - sess->param.pdusession_id = sessMod->pdusession_id; - sess->cause.type = NGAP_CAUSE_RADIO_NETWORK; - sess->cause.value = NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_PDU_SESSION_ID_INSTANCES; - sess->status = PDU_SESSION_STATUS_NEW; - sess->param.pdusession_id = sessMod->pdusession_id; - sess->cause.type = NGAP_CAUSE_NOTHING; - if (sessMod->nas_pdu.buf != NULL) { - UE->pduSession[i].param.nas_pdu = sessMod->nas_pdu; - } - // Save new pdu session parameters, qos, upf addr, teid - decodePDUSessionResourceModify(&sess->param, UE->pduSession[i].param.pdusessionTransfer); - sess->param.UPF_addr_N3 = sessMod->upf_addr; - sess->param.UPF_teid_N3 = sessMod->gtp_teid; + session->status = PDU_SESSION_STATUS_NEW; + session->cause.type = NGAP_CAUSE_NOTHING; + nr_rrc_update_pdusession(&session->param, sessMod); } } @@ -1114,11 +973,12 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins msg->gNB_ue_ngap_id = req->gNB_ue_ngap_id; msg->nb_of_pdusessions = 0; - for (int i = 0; i < UE->nb_of_pdusessions; i++) { - if (UE->pduSession[i].status == PDU_SESSION_STATUS_FAILED) { - msg->pdusessions_failed[i].pdusession_id = UE->pduSession[i].param.pdusession_id; - msg->pdusessions_failed[i].cause.type = UE->pduSession[i].cause.type; - msg->pdusessions_failed[i].cause.value = UE->pduSession[i].cause.value; + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) { + if (session->status == PDU_SESSION_STATUS_FAILED) { + msg->pdusessions_failed[msg->nb_of_pdusessions_failed].pdusession_id = session->param.pdusession_id; + msg->pdusessions_failed[msg->nb_of_pdusessions_failed].cause.type = session->cause.type; + msg->pdusessions_failed[msg->nb_of_pdusessions_failed].cause.value = session->cause.value; + msg->nb_of_pdusessions_failed++; } } itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p); @@ -1129,8 +989,13 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins int rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid) { MessageDef *msg_p = NULL; - uint8_t pdu_sessions_failed = 0; - uint8_t pdu_sessions_done = 0; + uint16_t pdu_sessions_failed = 0; + uint16_t pdu_sessions_done = 0; + + if (!seq_arr_size(&UE->pduSessions)) { + LOG_W(NR_RRC, "UE %d: No PDU sessions in the list, don't send NG PDU Session Modify Response\n", UE->rrc_ue_id); + return -1; + } msg_p = itti_alloc_new_message (TASK_RRC_GNB, rrc->module_id, NGAP_PDUSESSION_MODIFY_RESP); if (msg_p == NULL) { @@ -1142,63 +1007,54 @@ int rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE resp->gNB_ue_ngap_id = UE->rrc_ue_id; - for (int i = 0; i < UE->nb_of_pdusessions; i++) { - if (xid != UE->pduSession[i].xid) { - LOG_W(NR_RRC, "xid does not correspond (context pdu session index %d, status %d, xid %d/%d) \n ", i, UE->pduSession[i].status, xid, UE->pduSession[i].xid); + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) { + if (xid != session->xid) { + LOG_W(NR_RRC, + "xid does not correspond (PDU Session %d, status %d, xid %d/%d) \n ", + session->param.pdusession_id, + session->status, + xid, + session->xid); continue; } - if (UE->pduSession[i].status == PDU_SESSION_STATUS_DONE) { - rrc_pdu_session_param_t *pduSession = find_pduSession(UE, UE->pduSession[i].param.pdusession_id, false); - if (pduSession) { - LOG_I(NR_RRC, "update pdu session %d \n", pduSession->param.pdusession_id); - // Update UE->pduSession - pduSession->status = PDU_SESSION_STATUS_ESTABLISHED; - pduSession->cause.type = NGAP_CAUSE_NOTHING; - for (int qos_flow_index = 0; qos_flow_index < UE->pduSession[i].param.nb_qos; qos_flow_index++) { - pduSession->param.qos[qos_flow_index] = UE->pduSession[i].param.qos[qos_flow_index]; - } - resp->pdusessions[pdu_sessions_done].pdusession_id = UE->pduSession[i].param.pdusession_id; - for (int qos_flow_index = 0; qos_flow_index < UE->pduSession[i].param.nb_qos; qos_flow_index++) { - resp->pdusessions[pdu_sessions_done].qos[qos_flow_index].qfi = UE->pduSession[i].param.qos[qos_flow_index].qfi; - } - resp->pdusessions[pdu_sessions_done].pdusession_id = UE->pduSession[i].param.pdusession_id; - resp->pdusessions[pdu_sessions_done].nb_of_qos_flow = UE->pduSession[i].param.nb_qos; - LOG_I(NR_RRC, - "Modify Resp (msg index %d, pdu session index %d, status %d, xid %d): nb_of_pduSessions %d, pdusession_id %d \n ", - pdu_sessions_done, - i, - UE->pduSession[i].status, - xid, - UE->nb_of_pdusessions, - resp->pdusessions[pdu_sessions_done].pdusession_id); - pdu_sessions_done++; - } else { - LOG_W(NR_RRC, "PDU SESSION modify of a not existing pdu session %d \n", UE->pduSession[i].param.pdusession_id); - resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = UE->pduSession[i].param.pdusession_id; - ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID}; - resp->pdusessions_failed[pdu_sessions_failed].cause = cause; - pdu_sessions_failed++; + if (session->status == PDU_SESSION_STATUS_DONE) { + LOG_I(NR_RRC, "Successfully modified PDU Session %d \n", session->param.pdusession_id); + // Update status + session->status = PDU_SESSION_STATUS_ESTABLISHED; + session->cause.type = NGAP_CAUSE_NOTHING; + // Fill response + DevAssert(pdu_sessions_done < NGAP_MAX_PDU_SESSION); + pdusession_modify_t *p = &resp->pdusessions[pdu_sessions_done++]; + p->pdusession_id = session->param.pdusession_id; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos_session, &session->param.qos) { + DevAssert(p->nb_of_qos_flow < MAX_QOS_FLOWS); + qos_flow_tobe_modified_t *q = &p->qos[p->nb_of_qos_flow++]; + q->qfi = qos_session->qos.qfi; } - } else if ((UE->pduSession[i].status == PDU_SESSION_STATUS_NEW) || (UE->pduSession[i].status == PDU_SESSION_STATUS_ESTABLISHED)) { + LOG_I(NR_RRC, + "Modify Resp (msg index %d, status %d, xid %d): nb_of_pduSessions %ld, pdusession_id %d \n ", + pdu_sessions_done, + session->status, + xid, + seq_arr_size(&UE->pduSessions), + p->pdusession_id); + } else if ((session->status == PDU_SESSION_STATUS_NEW) || (session->status == PDU_SESSION_STATUS_ESTABLISHED)) { LOG_D(NR_RRC, "PDU SESSION is NEW or already ESTABLISHED\n"); - } else if (UE->pduSession[i].status == PDU_SESSION_STATUS_FAILED) { - resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = UE->pduSession[i].param.pdusession_id; - resp->pdusessions_failed[pdu_sessions_failed].cause.type = UE->pduSession[i].cause.type; - resp->pdusessions_failed[pdu_sessions_failed].cause.value = UE->pduSession[i].cause.value; + } else if (session->status == PDU_SESSION_STATUS_FAILED) { + DevAssert(pdu_sessions_failed < NGAP_MAX_PDU_SESSION); + resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = session->param.pdusession_id; + resp->pdusessions_failed[pdu_sessions_failed].cause.type = session->cause.type; + resp->pdusessions_failed[pdu_sessions_failed].cause.value = session->cause.value; pdu_sessions_failed++; - } - else - LOG_W(NR_RRC, - "Modify pdu session %d, unknown state %d \n ", - UE->pduSession[i].param.pdusession_id, - UE->pduSession[i].status); + } else + LOG_W(NR_RRC, "Modify pdu session %d, unknown state %d \n ", session->param.pdusession_id, session->status); } resp->nb_of_pdusessions = pdu_sessions_done; resp->nb_of_pdusessions_failed = pdu_sessions_failed; if (pdu_sessions_done > 0 || pdu_sessions_failed > 0) { - LOG_D(NR_RRC, "NGAP_PDUSESSION_MODIFY_RESP: sending the message (total pdu session %d)\n", UE->nb_of_pdusessions); + LOG_D(NR_RRC, "NGAP_PDUSESSION_MODIFY_RESP: sending the message (total pdu session %ld)\n", seq_arr_size(&UE->pduSessions)); itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p); } else { itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); @@ -1223,8 +1079,10 @@ void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(const module_id_t gnb_mod_idP, req->gNB_ue_ngap_id = UE->rrc_ue_id; req->cause.type = causeP.type; req->cause.value = causeP.value; - for (int i = 0; i < UE->nb_of_pdusessions; i++) { - req->pdusessions[i].pdusession_id = UE->pduSession[i].param.pdusession_id; + // PDU Session Resource List (optional) + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) { + DevAssert(req->nb_of_pdusessions < NGAP_MAX_PDU_SESSION); + req->pdusessions[req->nb_of_pdusessions].pdusession_id = session->param.pdusession_id; req->nb_of_pdusessions++; } itti_send_msg_to_task(TASK_NGAP, GNB_MODULE_ID_TO_INSTANCE(gnb_mod_idP), msg); @@ -1259,16 +1117,206 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_REQ(MessageDef *msg_p, instance_t in } } -//----------------------------------------------------------------------------- +/** @brief Sends the NG Handover Failure from the Target NG-RAN to the AMF */ +void rrc_gNB_send_NGAP_HANDOVER_FAILURE(gNB_RRC_INST *rrc, ngap_handover_failure_t *msg) +{ + LOG_I(NR_RRC, "Send NG Handover Failure message (amf_ue_ngap_id %ld) with cause %d \n ", msg->amf_ue_ngap_id, msg->cause.value); + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_HANDOVER_FAILURE); + NGAP_HANDOVER_FAILURE(msg_p) = *msg; + itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); +} + +/** @brief Process NG Handover Request message (8.4.2.2 3GPP TS 38.413) */ +int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, ngap_handover_request_t *msg) +{ + // Check if UE context already exists for this AMF UE NGAP ID + rrc_gNB_ue_context_t *existing_ue_context = rrc_gNB_get_ue_context_by_amf_ue_ngap_id(rrc, msg->amf_ue_ngap_id); + if (existing_ue_context != NULL) { + LOG_E(RRC, "UE context already exists for AMF UE NGAP ID %ld, cannot process handover request\n", msg->amf_ue_ngap_id); + ngap_handover_failure_t fail = { + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_HO_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM, + }; + rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail); + return -1; + } + + struct nr_rrc_du_container_t *du = get_du_by_cell_id(rrc, msg->nr_cell_id); + if (du == NULL) { + /* Cell Not Found! Return HO Request Failure*/ + LOG_E(RRC, "Failed to process Handover Request: no DU found with NR Cell ID=%lu \n", msg->nr_cell_id); + ngap_handover_failure_t fail = { + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_RADIO_RESOURCES_NOT_AVAILABLE, + }; + rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail); + return -1; + } + uint16_t pci = du->setup_req->cell[0].info.nr_pci; + LOG_I(NR_RRC, "Received Handover Request (on NR Cell ID=%lu, PCI=%u) \n", msg->nr_cell_id, pci); + + // Create UE context + sctp_assoc_t curr_assoc_id = du->assoc_id; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_create_ue_context(curr_assoc_id, UINT16_MAX, rrc, UINT64_MAX, UINT32_MAX); + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + + // allocate context for target + UE->ho_context = alloc_ho_ctx(HO_CTX_TARGET); + UE->ho_context->target->ho_trigger = nr_rrc_trigger_n2_ho_target; + + // Store IDs in UE context + UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; + UE->ue_guami = msg->guami; + UE->ho_context->target->ue_ho_prep_info = copy_byte_array(msg->ue_ho_prep_info); + // store the received UE Security Capabilities in the UE context + FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer); + UE->ue_cap_buffer = copy_byte_array(msg->ue_cap); + + /* store the received Security Context in the UE context + and take it into use as defined in TS 33.501 */ + set_UE_security_algos(rrc, UE, &msg->security_capabilities); + UE->nh_ncc = msg->security_context.next_hop_chain_count; + memcpy(UE->nh, msg->security_context.next_hop, SECURITY_KEY_LENGTH); + // Reset KgNB + memset(UE->kgnb, 0, SECURITY_KEY_LENGTH); + // Derive KgNB* + const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; + uint32_t ssb_arfcn = get_ssb_arfcn(du); + nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, UE->nh, UE->kgnb); + UE->as_security_active = true; + // Activate SRBs + activate_srb(UE, SRB1); + activate_srb(UE, SRB2); + nr_rrc_pdcp_config_security(UE, false); + + // Process all PDU Session Resource Setup items from handover request + DevAssert(msg->nb_of_pdusessions <= NGAP_MAX_PDU_SESSION); + pdusession_t to_setup[NGAP_MAX_PDU_SESSION]; + for (int i = 0; i < msg->nb_of_pdusessions; i++) { + ho_request_pdusession_t *ho_pdu = &msg->pduSessionResourceSetupList[i]; + pdusession_t *pdu = &to_setup[i]; + pdu->nssai = ho_pdu->nssai; + pdu->pdu_session_type = ho_pdu->pdu_session_type; + pdu->pdusession_id = ho_pdu->pdusession_id; + cp_pdusession_transfer_to_pdusession(pdu, &ho_pdu->pdusessionTransfer); + } + + if (!trigger_bearer_setup(rrc, UE, msg->nb_of_pdusessions, to_setup, msg->ue_ambr.br_dl)) { + LOG_E(NR_RRC, "Failed to establish PDU session: handover failed\n"); + + ngap_handover_failure_t fail = { + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_HO_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM, + }; + rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail); + rrc_remove_ue(rrc, ue_context_p); + return -1; + } + + return 0; +} + +void rrc_gNB_free_Handover_Request(ngap_handover_request_t *msg) +{ + free_byte_array(msg->ue_cap); + free_byte_array(msg->ue_ho_prep_info); + free(msg->mobility_restriction); +} + +/** @brief Send NG Uplink RAN Status Transfer message (8.4.6 3GPP TS 38.413) + * Direction: source NG-RAN node -> AMF */ +int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + const int n_to_mod, + const int *drb_ids, + const e1_pdcp_status_info_t *pdcp_status) +{ + AssertFatal(UE != NULL, "UE context is NULL\n"); + DevAssert(n_to_mod <= MAX_DRBS_PER_UE); + DevAssert(drb_ids); + + LOG_I(NR_RRC, + "Sending NGAP Uplink RAN Status Transfer (AMF_UE_NGAP_ID=%" PRIu64 ", GNB_UE_NGAP_ID=%u)\n", + UE->amf_ue_ngap_id, + UE->rrc_ue_id); + + ngap_ran_status_transfer_t msg = { + .amf_ue_ngap_id = UE->amf_ue_ngap_id, + .gnb_ue_ngap_id = UE->rrc_ue_id, + }; + + // Loop through DRBs and extract COUNT values + for (int i = 0; i < n_to_mod; ++i) { + int drb_id = drb_ids[i]; + + // Find the DRB in the UE's DRB list + drb_t *drb = get_drb(&UE->drbs, drb_id); + if (!drb) { + LOG_E(NR_RRC, "Failed to send UL RAN Status Transfer: DRB %d not found\n", drb_id); + continue; + } + + bool sn_length_18 = drb->pdcp_config.drb.sn_size == 18; + + DevAssert(msg.ran_status.nb_drb < MAX_DRBS_PER_UE); + ngap_drb_status_t *item = &msg.ran_status.drb_status_list[msg.ran_status.nb_drb++]; + item->drb_id = drb_id; + + const e1_pdcp_count_t *ul_pdcp = &pdcp_status[i].ul_count; + const e1_pdcp_count_t *dl_pdcp = &pdcp_status[i].dl_count; + + item->ul_count.pdcp_sn = ul_pdcp->sn; + item->ul_count.hfn = ul_pdcp->hfn; + item->ul_count.sn_len = sn_length_18 ? NGAP_SN_LENGTH_18 : NGAP_SN_LENGTH_12; + + item->dl_count.pdcp_sn = dl_pdcp->sn; + item->dl_count.hfn = dl_pdcp->hfn; + item->dl_count.sn_len = sn_length_18 ? NGAP_SN_LENGTH_18 : NGAP_SN_LENGTH_12; + } + + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UL_RAN_STATUS_TRANSFER); + NGAP_UL_RAN_STATUS_TRANSFER(msg_p) = msg; + itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); + + return 0; +} + +/** @brief Process NG Handover Command on Source gNB */ +void rrc_gNB_process_HandoverCommand(gNB_RRC_INST *rrc, const ngap_handover_command_t *msg) +{ + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, msg->gNB_ue_ngap_id); + + if (ue_context_p == NULL) { + LOG_W(NR_RRC, "Unknown UE context associated to gNB_ue_ngap_id (%u)\n", msg->gNB_ue_ngap_id); + return; + } + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + + uint8_t buffer[NR_RRC_BUF_SIZE]; + byte_array_t ba = {.buf = buffer, .len = sizeof(buffer)}; + int enc = doRRCReconfiguration_from_HandoverCommand(&ba, msg->handoverCommand); + DevAssert(enc > 0); + + rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, buffer, enc); + LOG_A(NR_RRC, "Send reconfiguration (HO Command) to UE %u/RNTI %04x\n", UE->rrc_ue_id, UE->rnti); +} + +void rrc_gNB_free_Handover_Command(ngap_handover_command_t *msg) +{ + free_byte_array(msg->handoverCommand); +} + /* * Process the NG command NGAP_UE_CONTEXT_RELEASE_COMMAND, sent by AMF. * The gNB should remove all pdu session, NG context, and other context of the UE. */ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance) { - gNB_RRC_INST *rrc = RC.nrrrc[0]; - uint32_t gNB_ue_ngap_id = 0; - gNB_ue_ngap_id = NGAP_UE_CONTEXT_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id; + gNB_RRC_INST *rrc = RC.nrrrc[instance]; + uint32_t gNB_ue_ngap_id = NGAP_UE_CONTEXT_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id; rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], gNB_ue_ngap_id); if (ue_context_p == NULL) { @@ -1276,7 +1324,7 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_ LOG_W(NR_RRC, "[gNB %ld] In NGAP_UE_CONTEXT_RELEASE_COMMAND: unknown UE from gNB_ue_ngap_id (%u)\n", instance, gNB_ue_ngap_id); - rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance, gNB_ue_ngap_id, 0, NULL); + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance, gNB_ue_ngap_id, NULL); return -1; } @@ -1307,25 +1355,24 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_ /* UE will be freed after UE context release complete */ } else { // the DU is offline already - uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]; - get_pduSession_array(UE, pdu_sessions); - rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, UE->nb_of_pdusessions, pdu_sessions); + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, &UE->pduSessions); rrc_remove_ue(rrc, ue_context_p); } return 0; } -void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, - uint32_t gNB_ue_ngap_id, - int num_pdu, - uint32_t pdu_session_id[256]) +void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t gNB_ue_ngap_id, seq_arr_t *pdusessions) { MessageDef *msg = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_COMPLETE); - NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg).gNB_ue_ngap_id = gNB_ue_ngap_id; - NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg).num_pdu_sessions = num_pdu; - for (int i = 0; i < num_pdu; ++i) - NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg).pdu_session_id[i] = pdu_session_id[i]; + ngap_ue_release_complete_t *complete = &NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg); + complete->gNB_ue_ngap_id = gNB_ue_ngap_id; + // PDU Session Resource List (Optional) + if (pdusessions && seq_arr_size(pdusessions)) { + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, pdusessions) { + complete->pdu_session_id[complete->num_pdu_sessions++] = session->param.pdusession_id; + } + } itti_send_msg_to_task(TASK_NGAP, instance, msg); } @@ -1369,29 +1416,113 @@ void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, LOG_I(NR_RRC,"Send message to ngap: NGAP_UE_CAPABILITIES_IND\n"); } +void rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, byte_array_t ho_command) +{ + LOG_D(NR_RRC, "Sending Handover Request Acknowledge\n"); + + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_HANDOVER_REQUEST_ACKNOWLEDGE); + ngap_handover_request_ack_t *msg = &NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(msg_p); + memset(msg, 0, sizeof(*msg)); + + // RAN UE NGAP ID + msg->gNB_ue_ngap_id = UE->rrc_ue_id; + // AMF UE NGAP ID + msg->amf_ue_ngap_id = UE->amf_ue_ngap_id; + // PDU Session Resource Admitted List + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t*, session, &UE->pduSessions) { + session->status = PDU_SESSION_STATUS_ESTABLISHED; + // PDU Session ID + DevAssert(msg->nb_of_pdusessions < NGAP_MAX_PDU_SESSION); + pdu_session_resource_admitted_t *pdu = &msg->pdusessions[msg->nb_of_pdusessions++]; + pdu->pdu_session_id = session->param.pdusession_id; + // Handover Request Acknowledge Transfer + ho_request_ack_transfer_t *transfer = &pdu->ack_transfer; + transfer->gtp_teid = session->param.n3_outgoing.teid; + memcpy(transfer->gNB_addr.buffer, session->param.n3_outgoing.addr.buffer, session->param.n3_outgoing.addr.length); + transfer->gNB_addr.length = session->param.n3_outgoing.addr.length; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->param.qos) { + DevAssert(transfer->nb_of_qos_flow < MAX_QOS_FLOWS); + pdusession_associate_qosflow_t *qos_setup = &transfer->qos_setup_list[transfer->nb_of_qos_flow++]; + qos_setup->qfi = qos->qos.qfi; + qos_setup->qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; + } + } + // Target to Source Transparent Container + msg->target2source = copy_byte_array(ho_command); + + itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); +} + +/** @brief Prepare NG Handover Notify message and inform NGAP */ +void rrc_gNB_send_NGAP_HANDOVER_NOTIFY(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) +{ + LOG_I(NR_RRC, "Triggering NGAP Handover Notify\n"); + nr_rrc_du_container_t *du = get_du_by_cell_id(rrc, rrc->nr_cellid); + if (du == NULL) { + LOG_E(NR_RRC, "Failed to send Handover Notify: no DU found with NR Cell ID=%lu\n", rrc->nr_cellid); + return; + } + + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_HANDOVER_NOTIFY); + ngap_handover_notify_t *ho_notify = &NGAP_HANDOVER_NOTIFY(msg_p); + memset(ho_notify, 0, sizeof(*ho_notify)); + + ho_notify->gNB_ue_ngap_id = UE->rrc_ue_id; + ho_notify->amf_ue_ngap_id = UE->amf_ue_ngap_id; + ho_notify->user_info.nrCellIdentity = rrc->nr_cellid; + + target_ran_node_id_t *target_ng_ran = &ho_notify->user_info.target_ng_ran; + target_ng_ran->tac = *du->setup_req->cell->info.tac; + target_ng_ran->targetgNBId = rrc->node_id; + target_ng_ran->plmn_identity = du->setup_req->cell->info.plmn; + + itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); +} + +/** @brief Prepare NG Handover Cancel (source NG-RAN) and inform NGAP (N2-based HO only) + * 3GPP TS 38.413 §8.4.5 (Handover Cancellation) - source NG-RAN -> AMF + * 3GPP TS 38.413 §9.2.3.11 (HANDOVER CANCEL) + * @param rrc CU/RRC instance + * @param UE UE context + * @param cause cancellation cause */ +void rrc_gNB_send_NGAP_HANDOVER_CANCEL(int module_id, gNB_RRC_UE_t *UE, ngap_cause_t cause) +{ + DevAssert(UE != NULL); + + LOG_I(NR_RRC, "Triggering NGAP Handover Cancel (gNB_ue_ngap_id=%d, amf_ue_ngap_id=%ld)\n", UE->rrc_ue_id, UE->amf_ue_ngap_id); + + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_HANDOVER_CANCEL); + ngap_handover_cancel_t *ho_cancel = &NGAP_HANDOVER_CANCEL(msg_p); + memset(ho_cancel, 0, sizeof(*ho_cancel)); + + /* Mandatory IEs (38.413 §9.2.3.11) */ + ho_cancel->gNB_ue_ngap_id = UE->rrc_ue_id; + ho_cancel->amf_ue_ngap_id = UE->amf_ue_ngap_id; + ho_cancel->cause = cause; + + itti_send_msg_to_task(TASK_NGAP, module_id, msg_p); +} + void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid) { - int pdu_sessions_released = 0; MessageDef *msg_p; msg_p = itti_alloc_new_message (TASK_RRC_GNB, rrc->module_id, NGAP_PDUSESSION_RELEASE_RESPONSE); ngap_pdusession_release_resp_t *resp = &NGAP_PDUSESSION_RELEASE_RESPONSE(msg_p); memset(resp, 0, sizeof(*resp)); resp->gNB_ue_ngap_id = UE->rrc_ue_id; - for (int i = 0; i < UE->nb_of_pdusessions; i++) { - if (xid == UE->pduSession[i].xid) { - resp->pdusession_release[pdu_sessions_released].pdusession_id = UE->pduSession[i].param.pdusession_id; - pdu_sessions_released++; - //clear - memset(&UE->pduSession[i], 0, sizeof(*UE->pduSession)); - UE->pduSession[i].status = PDU_SESSION_STATUS_RELEASED; - LOG_W(NR_RRC, "Released pdu session, but code to finish to free memory\n"); + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) { + if (xid == session->xid) { + const pdusession_t *pdusession = &session->param; + if (session->status == PDU_SESSION_STATUS_TORELEASE) { + DevAssert(resp->nb_of_pdusessions_released < NGAP_MAX_PDU_SESSION); + resp->pdusession_release[resp->nb_of_pdusessions_released++].pdusession_id = pdusession->pdusession_id; + } + session->status = PDU_SESSION_STATUS_RELEASED; } } - resp->nb_of_pdusessions_released = pdu_sessions_released; - resp->nb_of_pdusessions_failed = 0; - LOG_I(NR_RRC, "NGAP PDUSESSION RELEASE RESPONSE: rrc_ue_id %u release_pdu_sessions %d\n", resp->gNB_ue_ngap_id, pdu_sessions_released); + LOG_I(NR_RRC, "NGAP PDUSESSION RELEASE RESPONSE: rrc_ue_id %u release_pdu_sessions %d\n", resp->gNB_ue_ngap_id, resp->nb_of_pdusessions_released); itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p); } @@ -1418,14 +1549,9 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); UE->xids[xid] = RRC_PDUSESSION_RELEASE; for (int pdusession = 0; pdusession < cmd->nb_pdusessions_torelease; pdusession++) { - rrc_pdu_session_param_t *pduSession = find_pduSession(UE, cmd->pdusession_release_params[pdusession].pdusession_id, false); + rrc_pdu_session_param_t *pduSession = find_pduSession(&UE->pduSessions, cmd->pdusession_release_params[pdusession].pdusession_id); if (!pduSession) { - LOG_I(NR_RRC, "no pdusession_id, AMF requested to close it id=%d\n", cmd->pdusession_release_params[pdusession].pdusession_id); - int j=UE->nb_of_pdusessions++; - UE->pduSession[j].status = PDU_SESSION_STATUS_FAILED; - UE->pduSession[j].param.pdusession_id = cmd->pdusession_release_params[pdusession].pdusession_id; - ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID}; - UE->pduSession[j].cause = cause; + LOG_E(NR_RRC, "Failed to release non-existing PDU Session %d\n", cmd->pdusession_release_params[pdusession].pdusession_id); continue; } if (pduSession->status == PDU_SESSION_STATUS_FAILED) { @@ -1457,37 +1583,31 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_ return 0; } -void nr_rrc_rx_tx(void) { - // check timers - - // check if UEs are lost, to remove them from upper layers - - // - -} - -/*------------------------------------------------------------------------------*/ int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance) { - for (uint16_t tai_size = 0; tai_size < NGAP_PAGING_IND(msg_p).tai_size; tai_size++) { - LOG_I(NR_RRC,"[gNB %ld] In NGAP_PAGING_IND: MCC %d, MNC %d, TAC %d\n", instance, NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc, - NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc, NGAP_PAGING_IND(msg_p).tac[tai_size]); + ngap_paging_ind_t *msg = &NGAP_PAGING_IND(msg_p); + for (uint16_t tai_size = 0; tai_size < msg->tai_size; tai_size++) { + plmn_id_t *p = &msg->plmn_identity[tai_size]; + LOG_I(NR_RRC, + "[gNB %ld] TAI List for Paging: MCC=%03d, MNC=%0*d, TAC=%d\n", + instance, + p->mcc, + p->mnc_digit_length, + p->mnc, + msg->tac[tai_size]); gNB_RrcConfigurationReq *req = &RC.nrrrc[instance]->configuration; for (uint8_t j = 0; j < req->num_plmn; j++) { - plmn_id_t *plmn = &req->plmn[j]; - if (plmn->mcc == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc - && plmn->mnc == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc && req->tac == NGAP_PAGING_IND(msg_p).tac[tai_size]) { + plmn_id_t *req_plmn = &req->plmn[j]; + if (req_plmn->mcc == p->mcc && req_plmn->mnc == p->mnc && req->tac == msg->tac[tai_size]) { for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { AssertFatal(false, "to be implemented properly\n"); if (NODE_IS_CU(RC.nrrrc[instance]->node_type)) { MessageDef *m = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_PAGING_IND); - F1AP_PAGING_IND(m).plmn.mcc = RC.nrrrc[j]->configuration.plmn[0].mcc; - F1AP_PAGING_IND(m).plmn.mnc = RC.nrrrc[j]->configuration.plmn[0].mnc; - F1AP_PAGING_IND(m).plmn.mnc_digit_length = RC.nrrrc[j]->configuration.plmn[0].mnc_digit_length; + F1AP_PAGING_IND(m).plmn = *req_plmn; F1AP_PAGING_IND (m).nr_cellid = RC.nrrrc[j]->nr_cellid; - F1AP_PAGING_IND (m).ueidentityindexvalue = (uint16_t)(NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi%1024); - F1AP_PAGING_IND (m).fiveg_s_tmsi = NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi; - F1AP_PAGING_IND (m).paging_drx = NGAP_PAGING_IND(msg_p).paging_drx; + F1AP_PAGING_IND(m).ueidentityindexvalue = (uint16_t)(msg->ue_paging_identity.s_tmsi.m_tmsi % 1024); + F1AP_PAGING_IND(m).fiveg_s_tmsi = msg->ue_paging_identity.s_tmsi.m_tmsi; + F1AP_PAGING_IND(m).paging_drx = msg->paging_drx; LOG_E(F1AP, "ueidentityindexvalue %u fiveg_s_tmsi %ld paging_drx %u\n", F1AP_PAGING_IND (m).ueidentityindexvalue, F1AP_PAGING_IND (m).fiveg_s_tmsi, F1AP_PAGING_IND (m).paging_drx); itti_send_msg_to_task(TASK_CU_F1, instance, m); } else { @@ -1500,3 +1620,113 @@ int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance) return 0; } + +/** @brief Callback for NGAP Handover Required message (3GPP TS 38.413 9.2.3.1) + * Direction: source gNB -> AMF */ +void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + const nr_neighbour_cell_t *neighbour, + const byte_array_t hoPrepInfo) +{ + LOG_I(NR_RRC, "Handover Preparation: send Handover Required (target gNB ID=%d, PCI=%d)\n", neighbour->gNB_ID, neighbour->physicalCellId); + + const plmn_id_t plmn = neighbour->plmn; + const target_ran_node_id_t target = { + .plmn_identity = plmn, + .tac = neighbour->tac, + .targetgNBId = neighbour->gNB_ID, + }; + + ngap_handover_required_t msg = { + .amf_ue_ngap_id = UE->amf_ue_ngap_id, + .gNB_ue_ngap_id = UE->rrc_ue_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_HANDOVER_DESIRABLE_FOR_RADIO_REASON, + .handoverType = HANDOVER_TYPE_INTRA5GS, + .target_gnb_id = target, + }; + + cell_id_t target_cell = { + .nrCellIdentity = neighbour->nrcell_id, + .plmn_identity = plmn, + }; + + // Source to Target Transparent Container (M) + msg.source2target = calloc_or_fail(1, sizeof(*msg.source2target)); + // Target Cell ID (M) + msg.source2target->targetCellId = target_cell; + // RRC Container (M) + msg.source2target->handoverInfo = copy_byte_array(hoPrepInfo); + // UE History Info (M) + msg.source2target->ue_history_info.cause = malloc_or_fail(sizeof(*msg.source2target->ue_history_info.cause)); + msg.source2target->ue_history_info.cause->type = NGAP_CAUSE_RADIO_NETWORK; + msg.source2target->ue_history_info.cause->value = NGAP_CAUSE_RADIO_NETWORK_HANDOVER_DESIRABLE_FOR_RADIO_REASON; + msg.source2target->ue_history_info.type = NGAP_CellSize_small; + msg.source2target->ue_history_info.time_in_cell = 500; // dummy number for now + msg.source2target->ue_history_info.id = target_cell; + + /* Fill both PDU Session Resource List IE (M) in Handover Required + and PDU Session Resource Information List IE (O) in the Source NG-RAN + Node to Target NG-RAN Node Transparent Container */ + FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t*, pduSession, &UE->pduSessions) { + if (pduSession->status != PDU_SESSION_STATUS_DONE && pduSession->status != PDU_SESSION_STATUS_ESTABLISHED) + continue; + pdusession_t *session = &pduSession->param; + DevAssert(msg.nb_of_pdusessions < NGAP_MAX_PDU_SESSION); + pdusession_resource_t *pdu = &msg.pdusessions[msg.nb_of_pdusessions++]; + // PDU Session ID + pdu->pdusession_id = session->pdusession_id; + // PDU Session Resource Information List (O) + DevAssert(msg.source2target->nb_pdu_session_resource < NGAP_MAX_PDU_SESSION); + pdusession_resource_info_t *pdu_info = &msg.source2target->pdu_session_resource[msg.source2target->nb_pdu_session_resource++]; + pdu_info->pdusession_id = session->pdusession_id; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) { + DevAssert(pdu_info->nb_of_qos_flow < MAX_QOS_FLOWS); + qosflow_info_t *qos_flow = &pdu_info->qos_flow_info[pdu_info->nb_of_qos_flow++]; + qos_flow->qfi = qos->qos.qfi; + } + } + + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_HANDOVER_REQUIRED); + NGAP_HANDOVER_REQUIRED(msg_p) = msg; + itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); +} + +int rrc_gNB_process_NGAP_DL_RAN_STATUS_TRANSFER(MessageDef *msg_p, instance_t instance) +{ + const ngap_ran_status_transfer_t *cmd = &NGAP_DL_RAN_STATUS_TRANSFER(msg_p); + gNB_RRC_INST *rrc = RC.nrrrc[instance]; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, cmd->gnb_ue_ngap_id); + + if (!ue_context_p) { + LOG_E(NR_RRC, "[gNB %ld] No UE context for gNB_ue_ngap_id %u\n", instance, cmd->gnb_ue_ngap_id); + return -1; + } + + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + LOG_I(NR_RRC, + "[gNB %ld] DL RAN Status Transfer for gNB_ue_ngap_id %u AMF_UE_NGAP_ID %lu\n", + instance, + cmd->gnb_ue_ngap_id, + cmd->amf_ue_ngap_id); + + for (int i = 0; i < cmd->ran_status.nb_drb; ++i) { + const ngap_drb_status_t *s = &cmd->ran_status.drb_status_list[i]; + LOG_I(NR_RRC, + "DL RAN Status Transfer - DRB ID %d:\n" + " UL COUNT: PDCP SN = %u, HFN = %u (%s)\n" + " DL COUNT: PDCP SN = %u, HFN = %u (%s)\n", + s->drb_id, + s->ul_count.pdcp_sn, + s->ul_count.hfn, + s->ul_count.sn_len == NGAP_SN_LENGTH_18 ? "18-bit" : "12-bit", + s->dl_count.pdcp_sn, + s->dl_count.hfn, + s->dl_count.sn_len == NGAP_SN_LENGTH_18 ? "18-bit" : "12-bit"); + + // Send to PDCP layer + e1_notify_pdcp_status(rrc, UE, s); + } + + return 0; +} diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.h b/openair2/RRC/NR/rrc_gNB_NGAP.h index 22fff8705f..91c7722c52 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.h +++ b/openair2/RRC/NR/rrc_gNB_NGAP.h @@ -74,10 +74,7 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_REQ(MessageDef *msg_p, instance_t in int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance); -void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, - uint32_t gNB_ue_ngap_id, - int num_pdu, - uint32_t pdu_session_id[256]); +void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t gNB_ue_ngap_id, seq_arr_t *pduSessions); void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_UECapabilityInformation_t *const ue_cap_info); @@ -89,4 +86,30 @@ void nr_rrc_pdcp_config_security(gNB_RRC_UE_t *UE, bool enable_ciphering); int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance); +void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + const nr_neighbour_cell_t *neighbourCellConfiguration, + const byte_array_t hoPrepInfo); + +void rrc_gNB_send_NGAP_HANDOVER_FAILURE(gNB_RRC_INST *rrc, ngap_handover_failure_t *msg); + +int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, ngap_handover_request_t *msg); +void rrc_gNB_free_Handover_Request(ngap_handover_request_t *msg); + +void rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, byte_array_t ho_command); + +void rrc_gNB_process_HandoverCommand(gNB_RRC_INST *rrc, const ngap_handover_command_t *msg); +void rrc_gNB_free_Handover_Command(ngap_handover_command_t *msg); + +void rrc_gNB_send_NGAP_HANDOVER_NOTIFY(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE); +void rrc_gNB_send_NGAP_HANDOVER_CANCEL(int module_id, gNB_RRC_UE_t *UE, ngap_cause_t cause); + +int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + const int n_to_mod, + const int *drb_ids, + const e1_pdcp_status_info_t *pdcp_status); + +int rrc_gNB_process_NGAP_DL_RAN_STATUS_TRANSFER(MessageDef *msg_p, instance_t instance); + #endif diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.c b/openair2/RRC/NR/rrc_gNB_UE_context.c index b39abd9a30..9a2c3fb6f6 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.c +++ b/openair2/RRC/NR/rrc_gNB_UE_context.c @@ -40,6 +40,7 @@ #include "linear_alloc.h" #include "openair2/F1AP/f1ap_ids.h" #include "tree.h" +#include "rrc_gNB_radio_bearers.h" static void rrc_gNB_ue_context_update_time(rrc_gNB_ue_context_t *ctxt) { @@ -78,9 +79,6 @@ rrc_gNB_ue_context_t *rrc_gNB_allocate_new_ue_context(gNB_RRC_INST *rrc_instance new_p->ue_context.rrc_ue_id = uid_linear_allocator_new(&rrc_instance_pP->uid_allocator) + 1; rrc_gNB_ue_context_update_time(new_p); - for(int i = 0; i < NB_RB_MAX; i++) - new_p->ue_context.pduSession[i].xid = -1; - LOG_D(NR_RRC, "Returning new RRC UE context RRC ue id: %d\n", new_p->ue_context.rrc_ue_id); return(new_p); } @@ -124,6 +122,18 @@ rrc_gNB_ue_context_t *rrc_gNB_get_ue_context_by_rnti_any_du(gNB_RRC_INST *rrc_in return NULL; } +/** @brief Fetch UE Context by the unique AMF UE NGAP ID */ +rrc_gNB_ue_context_t *rrc_gNB_get_ue_context_by_amf_ue_ngap_id(gNB_RRC_INST *rrc_instance_pP, uint64_t amf_ue_ngap_id) +{ + rrc_gNB_ue_context_t *ue_context_p; + RB_FOREACH (ue_context_p, rrc_nr_ue_tree_s, &(rrc_instance_pP->rrc_ue_head)) { + if (ue_context_p->ue_context.amf_ue_ngap_id == amf_ue_ngap_id) { + return ue_context_p; + } + } + return NULL; +} + void rrc_gNB_free_mem_ue_context(rrc_gNB_ue_context_t *const ue_context_pP) //----------------------------------------------------------------------------- { @@ -200,6 +210,8 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id, gNB_RRC_UE_t *ue = &ue_context_p->ue_context; ue->rnti = rnti; ue->random_ue_identity = ue_identityP; + // signal "no AMF UE NGAP ID" because valid range is 0..2^40-1 + ue->amf_ue_ngap_id = INT64_MAX; f1_ue_data_t ue_data = {.secondary_ue = du_ue_id, .du_assoc_id = assoc_id}; AssertFatal(!cu_exists_f1_ue_data(ue->rrc_ue_id), "UE F1 Context for ID %d already exists, logic bug\n", @@ -209,6 +221,11 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id, ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */ ue->ongoing_pdusession_setup_request = false; + // Initialise setup PDU Sessions list + seq_arr_init(&ue->pduSessions, sizeof(rrc_pdu_session_param_t)); + // Initialise setup DRBs list + seq_arr_init(&ue->drbs, sizeof(drb_t)); + RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p); LOG_UE_EVENT(ue, "Create UE context: CU UE ID %u DU UE ID %u (rnti: %04x, random ue id %lx)\n", diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.h b/openair2/RRC/NR/rrc_gNB_UE_context.h index 9485672463..b8edd159c4 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.h +++ b/openair2/RRC/NR/rrc_gNB_UE_context.h @@ -46,6 +46,7 @@ rrc_gNB_ue_context_t* rrc_gNB_allocate_new_ue_context(gNB_RRC_INST* rrc_instance rrc_gNB_ue_context_t* rrc_gNB_get_ue_context(gNB_RRC_INST* rrc_instance_pP, ue_id_t ue); rrc_gNB_ue_context_t* rrc_gNB_get_ue_context_by_rnti(gNB_RRC_INST* rrc_instance_pP, sctp_assoc_t assoc_id, rnti_t rntiP); rrc_gNB_ue_context_t* rrc_gNB_get_ue_context_by_rnti_any_du(gNB_RRC_INST* rrc_instance_pP, rnti_t rntiP); +rrc_gNB_ue_context_t* rrc_gNB_get_ue_context_by_amf_ue_ngap_id(gNB_RRC_INST* rrc_instance_pP, uint64_t amf_ue_ngap_id); void rrc_gNB_free_mem_ue_context(rrc_gNB_ue_context_t* const ue_context_pP); diff --git a/openair2/RRC/NR/rrc_gNB_asn1.c b/openair2/RRC/NR/rrc_gNB_asn1.c new file mode 100644 index 0000000000..17f4bb8af5 --- /dev/null +++ b/openair2/RRC/NR/rrc_gNB_asn1.c @@ -0,0 +1,48 @@ +/* + * 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 +#include "NR_DRB-ToAddMod.h" +#include "NR_RadioBearerConfig.h" +#include "common/utils/oai_asn1.h" +#include "common/utils/LOG/log.h" +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h" + +NR_PDCP_Config_t *nr_rrc_build_pdcp_config_ie(const bool integrity, const bool ciphering, const nr_pdcp_configuration_t *pdcp) +{ + NR_PDCP_Config_t *out = calloc_or_fail(1, sizeof(*out)); + asn1cCallocOne(out->t_Reordering, encode_t_reordering(pdcp->drb.t_reordering)); + if (!ciphering) { + asn1cCalloc(out->ext1, ext1); + asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true); + } + asn1cCalloc(out->drb, drb); + asn1cCallocOne(drb->discardTimer, encode_discard_timer(pdcp->drb.discard_timer)); + asn1cCallocOne(drb->pdcp_SN_SizeUL, encode_sn_size_ul(pdcp->drb.sn_size)); + asn1cCallocOne(drb->pdcp_SN_SizeDL, encode_sn_size_dl(pdcp->drb.sn_size)); + drb->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; + drb->headerCompression.choice.notUsed = 0; + if (integrity) { + asn1cCallocOne(drb->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled); + } + return out; +} diff --git a/openair2/ENB_APP/NB_IoT_config.h b/openair2/RRC/NR/rrc_gNB_asn1.h similarity index 71% rename from openair2/ENB_APP/NB_IoT_config.h rename to openair2/RRC/NR/rrc_gNB_asn1.h index 314fca8180..b706a68a15 100644 --- a/openair2/ENB_APP/NB_IoT_config.h +++ b/openair2/RRC/NR/rrc_gNB_asn1.h @@ -19,19 +19,15 @@ * contact@openairinterface.org */ -/* - nbiot_config.h - ------------------- - AUTHOR : Francois Taburet - COMPANY : NOKIA - EMAIL : francois.taburet@nokia-bell-labs.com -*/ -#ifndef INCLUDE_NBIOT_CONFIG_H -#define INCLUDE_NBIOT_CONFIG_H +#ifndef _RRC_GNB_ASN1_H_ +#define _RRC_GNB_ASN1_H_ +#include +#include "seq_arr.h" +#include "NR_DRB-ToAddMod.h" +#include "NR_RadioBearerConfig.h" +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" + +NR_PDCP_Config_t *nr_rrc_build_pdcp_config_ie(const bool integrity, const bool ciphering, const nr_pdcp_configuration_t *pdcp); -extern void RCconfig_NbIoTL1(void) ; -extern void RCconfig_NbIoTmacrlc(void); -extern int RCconfig_NbIoTRRC(MessageDef *msg_p, int nbiotrrc_id,eNB_RRC_INST_NB_IoT *nbiotrrc); -extern void RCConfig_NbIoT(RAN_CONTEXT_t *RC); #endif diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index a650a03604..246df60626 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -257,6 +257,11 @@ static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_config nc->absoluteFrequencySSB); return false; } + // Check neighbour band + if (get_dl_band(cell) != nc->band) { + LOG_W(NR_RRC, "Cell %ld in neighbour config: Band mismatch (%d vs %d)\n", cell->nr_cellid, get_dl_band(cell), nc->band); + return false; + } if (get_ssb_scs(cell) != nc->subcarrierSpacing) { LOG_W(NR_RRC, "Cell %ld in neighbour config: SCS mismatch (%d vs %d)\n", @@ -437,6 +442,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) if (rrc->node_name != NULL) resp.gNB_CU_name = strdup(rrc->node_name); rrc->mac_rrc.f1_setup_response(assoc_id, &resp); + free_f1ap_setup_response(&resp); /* we need to setup one default UE for phy-test and do-ra modes in the MAC */ if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) @@ -452,12 +458,12 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id) RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) { gNB_RRC_UE_t *UE = &ue_context_p->ue_context; uint32_t ue_id = UE->rrc_ue_id; - if (UE->ho_context != NULL) { + if (UE->ho_context != NULL) LOG_W(NR_RRC, "DU disconnected while handover for UE %d active\n", ue_id); - nr_rrc_finalize_ho(UE); - } f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id); - if (ue_data.du_assoc_id == assoc_id && IS_SA_MODE(get_softmodem_params())) { + if (ue_data.du_assoc_id != assoc_id) + continue; /* this UE is on another DU */ + if (IS_SA_MODE(get_softmodem_params())) { /* this UE belongs to the DU that disconnected, set du_assoc_id to 0, * meaning DU is offline, then trigger release request */ ue_data.du_assoc_id = 0; @@ -600,9 +606,12 @@ void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t ASN_STRUCT_FREE(asn_DEF_NR_MIB, du->mib); ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1); ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, du->mtc); - /* TODO: free setup request */ + if (du->setup_req) + free_f1ap_setup_request(du->setup_req); + free(du->setup_req); nr_rrc_du_container_t *removed = RB_REMOVE(rrc_du_tree, &rrc->dus, du); DevAssert(removed != NULL); + free(du); rrc->num_dus--; int num = invalidate_du_connections(rrc, assoc_id); @@ -613,6 +622,8 @@ void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t nr_rrc_du_container_t *get_du_for_ue(gNB_RRC_INST *rrc, uint32_t ue_id) { + if (!cu_exists_f1_ue_data(ue_id)) + return NULL; f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id); return get_du_by_assoc_id(rrc, ue_data.du_assoc_id); } diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 647f253989..552cc881d6 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -31,6 +31,7 @@ #include "rrc_gNB_UE_context.h" #include "openair2/LAYER2/NR_MAC_COMMON/nr_mac.h" #include "openair2/F1AP/f1ap_ids.h" +#include "openair2/F1AP/lib/f1ap_ue_context.h" #include "MESSAGES/asn1_msg.h" #include "nr_pdcp/nr_pdcp_oai_api.h" #include "openair3/SECU/key_nas_deriver.h" @@ -41,8 +42,7 @@ #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" #endif -typedef enum { HO_CTX_BOTH, HO_CTX_SOURCE, HO_CTX_TARGET } ho_ctx_type_t; -static nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type) +nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type) { nr_handover_context_t *ho_ctx = calloc_or_fail(1, sizeof(*ho_ctx)); if (type == HO_CTX_SOURCE || type == HO_CTX_BOTH) { @@ -57,46 +57,54 @@ static nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type) static void free_ho_ctx(nr_handover_context_t *ho_ctx) { free(ho_ctx->source); + if (ho_ctx->target) + FREE_AND_ZERO_BYTE_ARRAY(ho_ctx->target->ue_ho_prep_info); free(ho_ctx->target); free(ho_ctx); } -static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE]) +/** @brief Fill DRB to Be Setup List in F1 UE Context Setup Request (optional list) + * @return 0 if list is empty, list size otherwise */ +static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_drb_to_setup_t drbs[MAX_DRBS_PER_UE]) { int nb_drb = 0; - for (int i = 0; i < MAX_DRBS_PER_UE; ++i) { - drb_t *rrc_drb = &ue->established_drbs[i]; - if (rrc_drb->status == DRB_INACTIVE) - continue; - f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; + FOR_EACH_SEQ_ARR(drb_t *, rrc_drb, &ue->drbs) { + DevAssert(nb_drb < MAX_DRBS_PER_UE); + f1ap_drb_to_setup_t *drb = &drbs[nb_drb]; + nr_pdcp_configuration_t *pdcp = &rrc_drb->pdcp_config; nb_drb++; - drb->drb_id = rrc_drb->drb_id; - drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; - memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid; - drb->up_ul_tnl_length = 1; - /* fetch an existing PDU session for this DRB */ - rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb->drb_id); - AssertFatal(pdu != NULL, "no PDU session for DRB ID %ld\n", drb->drb_id); - drb->nssai = pdu->param.nssai; + rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, rrc_drb->drb_id); + AssertFatal(pdu != NULL, "no PDU session for DRB ID %d\n", rrc_drb->drb_id); - // for the moment, we only support one QoS flow. Put a reminder in case - // this changes - AssertFatal(pdu->param.nb_qos == 1, "only 1 Qos flow supported\n"); - drb->drb_info.flows_to_be_setup_length = 1; - drb->drb_info.flows_mapped_to_drb = calloc_or_fail(1, sizeof(drb->drb_info.flows_mapped_to_drb[0])); - AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); - int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0]; - DevAssert(qfi > 0); - drb->drb_info.flows_mapped_to_drb[0].qfi = qfi; - pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(qfi, pdu); - drb->drb_info.flows_mapped_to_drb[0].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char); + drb->id = rrc_drb->drb_id; + drb->qos_choice = F1AP_QOS_CHOICE_NR; + drb->nr.nssai = pdu->param.nssai; + drb->nr.flows_len = 1; + drb->nr.flows = calloc_or_fail(1, sizeof(*drb->nr.flows)); + + // Find the QoS flow associated with this DRB + // Since we don't have QFI mapping in the new structure, we'll use the first QoS flow + AssertFatal(seq_arr_size(&pdu->param.qos) == 1, "only 1 Qos flow supported\n"); + nr_rrc_qos_t *qos_param = (nr_rrc_qos_t *)seq_arr_at(&pdu->param.qos, 0); + DevAssert(qos_param->qos.qfi > 0); + drb->nr.flows[0].qfi = qos_param->qos.qfi; + drb->nr.flows[0].param = get_qos_char_from_qos_flow_param(&qos_param->qos); /* the DRB QoS parameters: we just reuse the ones from the first flow */ - drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; + drb->nr.drb_qos = drb->nr.flows[0].param; + + memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid; + drb->up_ul_tnl_len = 1; + + drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; + DevAssert(pdcp->drb.sn_size == 18 || pdcp->drb.sn_size == 12); + drb->dl_pdcp_sn_len = malloc_or_fail(sizeof(*drb->dl_pdcp_sn_len)); + *drb->dl_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; + drb->ul_pdcp_sn_len = malloc_or_fail(sizeof(*drb->ul_pdcp_sn_len)); + *drb->ul_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B; } return nb_drb; } @@ -116,18 +124,16 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, byte_array_t *ho_prep_info, ho_req_ack_t ack, ho_success_t success, - ho_cancel_t cancel) + ho_cancel_t cancel, + ho_failure_t failure) { DevAssert(rrc != NULL); DevAssert(ue != NULL); DevAssert(target_du != NULL); // source_du might be NULL -> inter-CU handover DevAssert(ho_prep_info->buf != NULL && ho_prep_info->len > 0); + DevAssert(ue->ho_context); - if (ue->ho_context != NULL) { - LOG_E(NR_RRC, "handover for UE %u ongoing, cannot trigger new\n", ue->rrc_ue_id); - return; - } // if any reconfiguration is ongoing, abort handover request for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) { if (ue->xids[i] != RRC_ACTION_NONE) { @@ -136,15 +142,13 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, } } - // if we know the source DU (F1 handover), allocate the context for it, - // otherwise only for the target DU (N2, Xn) - ho_ctx_type_t ctx_type = source_du != NULL ? HO_CTX_BOTH : HO_CTX_TARGET; - nr_handover_context_t *ho_ctx = alloc_ho_ctx(ctx_type); + nr_handover_context_t *ho_ctx = ue->ho_context; ho_ctx->target->du = target_du; // we will know target->{du_ue_id,new_rnti} once we have UE ctxt setup // response ho_ctx->target->ho_req_ack = ack; ho_ctx->target->ho_success = success; + ho_ctx->target->ho_failure = failure; const f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); if (source_du != NULL) { @@ -159,7 +163,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, int result = asn_copy(&asn_DEF_NR_CellGroupConfig, (void **)&ho_ctx->source->old_cellGroupConfig, ue->masterCellGroup); AssertFatal(result == 0, "error during asn_copy() of CellGroupConfig\n"); } - ue->ho_context = ho_ctx; + LOG_A(NR_RRC, "Handover triggered for UE %u/RNTI %04x towards DU %ld/assoc_id %d/PCI %d\n", ue->rrc_ue_id, @@ -168,75 +172,79 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, target_du->assoc_id, target_du->setup_req->cell[0].info.nr_pci); - cu_to_du_rrc_information_t cu2du = { - .handoverPreparationInfo = ho_prep_info->buf, - .handoverPreparationInfo_length = ho_prep_info->len, - }; - - f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE] = {0}; + f1ap_drb_to_setup_t *drbs = calloc_or_fail(MAX_DRBS_PER_UE, sizeof(*drbs)); int nb_drb = fill_drb_to_be_setup(rrc, ue, drbs); - f1ap_srb_to_be_setup_t srbs[2] = {{.srb_id = 1, .lcid = 1}, {.srb_id = 2, .lcid = 2}}; + int nb_srb = 2; + f1ap_srb_to_setup_t *srbs = calloc_or_fail(nb_srb, sizeof(*srbs)); + srbs[0].id = 1; + srbs[1].id = 2; + + free_MeasConfig(ue->measConfig); + ue->measConfig = nr_rrc_get_measconfig(rrc, target_du->setup_req->cell[0].info.nr_cellid); + byte_array_t *meas_config = calloc_or_fail(1, sizeof(*meas_config)); + meas_config->buf = calloc_or_fail(1, NR_RRC_BUF_SIZE); + meas_config->len = do_NR_MeasConfig(ue->measConfig, meas_config->buf, NR_RRC_BUF_SIZE); + + byte_array_t *meas_timing_config = NULL; + if (target_du->mtc) { + meas_timing_config = calloc_or_fail(1, sizeof(*meas_timing_config)); + meas_timing_config->buf = calloc_or_fail(1, NR_RRC_BUF_SIZE); + meas_timing_config->len = do_NR_MeasurementTimingConfiguration(target_du->mtc, meas_timing_config->buf, NR_RRC_BUF_SIZE); + } + + byte_array_t *hpi = malloc_or_fail(sizeof(*hpi)); + *hpi = copy_byte_array(*ho_prep_info); + + uint64_t *ue_agg_mbr = malloc_or_fail(sizeof(*ue_agg_mbr)); + *ue_agg_mbr = 1000000000 /*bps*/; + f1ap_served_cell_info_t *cell_info = &target_du->setup_req->cell[0].info; RETURN_IF_INVALID_ASSOC_ID(target_du->assoc_id); - f1ap_ue_context_setup_t ue_context_setup_req = { + f1ap_ue_context_setup_req_t ue_context_setup_req = { .gNB_CU_ue_id = ue->rrc_ue_id, - .gNB_DU_ue_id = 0, /* TODO: this should be optional! */ .plmn.mcc = cell_info->plmn.mcc, .plmn.mnc = cell_info->plmn.mnc, .plmn.mnc_digit_length = cell_info->plmn.mnc_digit_length, .nr_cellid = cell_info->nr_cellid, - .servCellId = 0, // TODO: correct value? - .srbs_to_be_setup_length = 2, - .srbs_to_be_setup = srbs, - .drbs_to_be_setup_length = nb_drb, - .drbs_to_be_setup = drbs, - .cu_to_du_rrc_information = &cu2du, + .servCellIndex = 0, // TODO: correct value? + .srbs_len = nb_srb, + .srbs = srbs, + .drbs_len = nb_drb, + .drbs = drbs, + .cu_to_du_rrc_info.ho_prep_info = hpi, + .cu_to_du_rrc_info.meas_config = meas_config, + .cu_to_du_rrc_info.meas_timing_config = meas_timing_config, + .gnb_du_ue_agg_mbr_ul = ue_agg_mbr, }; rrc->mac_rrc.ue_context_setup_request(target_du->assoc_id, &ue_context_setup_req); + free_ue_context_setup_req(&ue_context_setup_req); } -/* -void nr_rrc_trigger_n2_ho(gNB_RRC_INST *rrc, int nr_cgi, uint8_t *ho_prep_info, uint32_t *ho_prep_len, void *pdu_session) -{ - // call from outside (via NGAP message), with the request for handover for a - // (any) UE. This handler should, in order: - // - // 1. look up the target DU =du= via get_du_by_cell_id(nr_cgi) - // (and reject the request if it can't find the DU) - // 2. create a context for a new UE =UE=, based on pdu_session information - // 3. call nr_initiate_handover(rrc, UE, NULL, du, ho_prep_info, ho_prep_len); - // - // after success of the DU, send the result via =success_ptr= to the source - // CU. -} -*/ - typedef struct deliver_ue_ctxt_modification_data_t { gNB_RRC_INST *rrc; - f1ap_ue_context_modif_req_t *modification_req; + f1ap_ue_context_mod_req_t *modification_req; sctp_assoc_t assoc_id; } deliver_ue_ctxt_modification_data_t; + static void rrc_deliver_ue_ctxt_modif_req(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id) { DevAssert(deliver_pdu_data != NULL); deliver_ue_ctxt_modification_data_t *data = deliver_pdu_data; - data->modification_req->rrc_container = (uint8_t*)buf; - data->modification_req->rrc_container_length = size; + byte_array_t ba = {.buf = (uint8_t *) buf, .len = size}; + data->modification_req->rrc_container = &ba; data->rrc->mac_rrc.ue_context_modification_request(data->assoc_id, data->modification_req); } -static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *rrc_reconf, int rrc_reconf_len) + +void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *rrc_reconf, int rrc_reconf_len) { f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id); TransmActionInd_t transmission_action_indicator = TransmActionInd_STOP; RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); - f1ap_ue_context_modif_req_t ue_context_modif_req = { + f1ap_ue_context_mod_req_t ue_context_modif_req = { .gNB_CU_ue_id = ue->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, - .plmn = rrc->configuration.plmn[0], - .nr_cellid = rrc->nr_cellid, // TODO target cell ID - .servCellId = 0, // TODO: correct value? .transm_action_ind = &transmission_action_indicator, }; deliver_ue_ctxt_modification_data_t data = {.rrc = rrc, @@ -277,6 +285,7 @@ static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) DevAssert(UE->ho_context->source != NULL); rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, buffer.buf, buffer.len); LOG_A(NR_RRC, "HO acknowledged: Send reconfiguration for UE %u/RNTI %04x...\n", UE->rrc_ue_id, UE->rnti); + free_byte_array(buffer); /* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331 * (SRB1 is re-established with RRCReestablishment message) @@ -299,12 +308,11 @@ static void nr_rrc_f1_ho_complete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) nr_ho_source_cu_t *source_ctx = UE->ho_context->source; DevAssert(source_ctx != NULL); RETURN_IF_INVALID_ASSOC_ID(source_ctx->du->assoc_id); - f1ap_ue_context_release_cmd_t cmd = { + f1ap_ue_context_rel_cmd_t cmd = { .gNB_CU_ue_id = UE->rrc_ue_id, .gNB_DU_ue_id = source_ctx->du_ue_id, .cause = F1AP_CAUSE_RADIO_NETWORK, .cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure - .srb_id = DL_SCH_LCID_DCCH, }; rrc->mac_rrc.ue_context_release_command(source_ctx->du->assoc_id, &cmd); LOG_I(NR_RRC, "UE %d Handover: trigger release on DU assoc_id %d\n", UE->rrc_ue_id, source_ctx->du->assoc_id); @@ -315,12 +323,11 @@ static void nr_rrc_cancel_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) DevAssert(UE->ho_context != NULL); nr_ho_target_cu_t *target_ctx = UE->ho_context->target; DevAssert(target_ctx != NULL); - f1ap_ue_context_release_cmd_t cmd = { + f1ap_ue_context_rel_cmd_t cmd = { .gNB_CU_ue_id = UE->rrc_ue_id, .gNB_DU_ue_id = target_ctx->du_ue_id, .cause = F1AP_CAUSE_RADIO_NETWORK, // better .cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure - .srb_id = DL_SCH_LCID_DCCH, }; rrc->mac_rrc.ue_context_release_command(target_ctx->du->assoc_id, &cmd); } @@ -333,6 +340,13 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain uint8_t buf[NR_RRC_BUF_SIZE]; int size = do_NR_HandoverPreparationInformation(ue->ue_cap_buffer.buf, ue->ue_cap_buffer.len, buf, sizeof buf); + // Allocate handover context (both CU and DU) + if (ue->ho_context != NULL) { + LOG_E(NR_RRC, "Ongoing handover for UE %d, cannot trigger new\n", ue->rrc_ue_id); + return; + } + ue->ho_context = alloc_ho_ctx(HO_CTX_BOTH); + // corresponds to a "handover request", 38.300 Sec 9.3.2.3 // see also 38.413 Sec 9.3.1.29 for information on source-CU to target-CU // information (Source NG-RAN Node to Target NG-RAN Node Transparent Container) @@ -343,7 +357,7 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain ho_success_t success = nr_rrc_f1_ho_complete; ho_cancel_t cancel = nr_rrc_cancel_f1_ho; byte_array_t hpi = {.buf = buf, .len = size}; - nr_initiate_handover(rrc, ue, source_du, target_du, &hpi, ack, success, cancel); + nr_initiate_handover(rrc, ue, source_du, target_du, &hpi, ack, success, cancel, NULL); } void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue) @@ -377,3 +391,224 @@ void nr_HO_F1_trigger_telnet(gNB_RRC_INST *rrc, uint32_t rrc_ue_id) nr_rrc_trigger_f1_ho(rrc, ue, source_du, target_du); } + +/** @brief Generate the HandoverPreparationInformation to be carried + * in the RRC Container (9.3.1.29 of 3GPP TS 38.413) of the Source + * NG-RAN Node to Target NG-RAN Node Transparent Container IE */ +static byte_array_t rrc_gNB_generate_HandoverPreparationInformation(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, int serving_pci) +{ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue, 0, false); + params.ue_cap = ue->ue_cap_buffer; + + byte_array_t hoPrepInfo = get_HandoverPreparationInformation(¶ms, serving_pci); + free_RRCReconfiguration_params(params); + + if (hoPrepInfo.len < 0) { + LOG_E(NR_RRC, "HandoverPreparationInformation generation failed for UE %d\n", ue->rrc_ue_id); + return hoPrepInfo; + } + + LOG_D(NR_RRC, "HO LOG: Handover Preparation for UE %lu Encoded (%zd bytes)\n", ue->amf_ue_ngap_id, hoPrepInfo.len); + + return hoPrepInfo; +} + +static byte_array_t rrc_gNB_encode_HandoverCommand(gNB_RRC_UE_t *UE, gNB_RRC_INST *rrc) +{ + DevAssert(UE->ho_context); + DevAssert(UE->ho_context->target); + + NR_SecurityConfig_t *sec = calloc_or_fail(1, sizeof(*sec)); + sec->keyToUse = calloc_or_fail(1, sizeof(*sec->keyToUse)); + *sec->keyToUse = NR_SecurityConfig__keyToUse_master; + sec->securityAlgorithmConfig = calloc_or_fail(1, sizeof(*sec->securityAlgorithmConfig)); + struct NR_SecurityAlgorithmConfig *alg = sec->securityAlgorithmConfig; + alg->cipheringAlgorithm = UE->ciphering_algorithm; + alg->integrityProtAlgorithm = calloc_or_fail(1, sizeof(*alg->integrityProtAlgorithm)); + *alg->integrityProtAlgorithm = UE->integrity_algorithm; + + // Mark source gNB's measurement configuration for removal in UE->measConfig + if (UE->ho_context->target->ue_ho_prep_info.len) { + fill_removal_lists_from_source_measConfig(UE->measConfig, UE->ho_context->target->ue_ho_prep_info); + } + + /* 3GPP TS 38.331 RadioBearerConfig: re-establish PDCP whenever + the security key used for this radio bearer changes, e.g. for SRB2 + when receiving reconfiguration with sync [...]. Similarly, for DRBs + PDCP re-establishment is necessary with derivation of new UP keys */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, (1 << 1) | (1 << 2), true); + UE->xids[params.transaction_id] = RRC_DEDICATED_RECONF; + + params.security_config = sec; + params.masterKeyUpdate = true; + params.nextHopChainingCount = UE->nh_ncc; + byte_array_t out = get_HandoverCommandMessage(¶ms); + + // Free remove lists in UE->measConfig + ASN_STRUCT_FREE(asn_DEF_NR_MeasIdToRemoveList, UE->measConfig->measIdToRemoveList); + ASN_STRUCT_FREE(asn_DEF_NR_ReportConfigToRemoveList, UE->measConfig->reportConfigToRemoveList); + ASN_STRUCT_FREE(asn_DEF_NR_MeasObjectToRemoveList, UE->measConfig->measObjectToRemoveList); + + free_RRCReconfiguration_params(params); + return out; +} + +/** @brief This callback is used by the target gNB + * to trigger the Handover Request Acknowledge towards the AMF */ +static void nr_rrc_n2_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) +{ + AssertFatal(cu_exists_f1_ue_data(UE->rrc_ue_id), "No CU found for rrc_ue_id %d\n", UE->rrc_ue_id); + + f1_ue_data_t previous_data = cu_get_f1_ue_data(UE->rrc_ue_id); + /* this is the callback for N2 handover after F1 UE context setup response in + * the handover case. Check that there was no associated DU, then set it */ + AssertFatal(previous_data.secondary_ue == -1, "there was already a DU present\n"); + previous_data.secondary_ue = UE->ho_context->target->du_ue_id; + bool success = cu_update_f1_ue_data(UE->rrc_ue_id, &previous_data); + DevAssert(success); + LOG_I(NR_RRC, "Updated CU F1AP Context for UE %d, DU Id : %u\n", UE->rrc_ue_id, UE->ho_context->target->du_ue_id); + + byte_array_t hoCommand = rrc_gNB_encode_HandoverCommand(UE, rrc); + if (hoCommand.len < 0) { + LOG_E(NR_RRC, "ASN1 message encoding failed: failed to generate Handover Command Message\n"); + ngap_handover_failure_t fail = {.amf_ue_ngap_id = UE->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_HO_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM}; + UE->ho_context->target->ho_failure(rrc, UE->rrc_ue_id, &fail); + return; + } else { + LOG_D(NR_RRC, "HO LOG: Handover Command for UE %u Encoded (%ld bytes)\n", UE->rrc_ue_id, hoCommand.len); + } + + rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(rrc, UE, hoCommand); + free_byte_array(hoCommand); +} + +/** @brief This callback is used by the target gNB + * to trigger the Handover Notify towards the AMF */ +static void nr_rrc_n2_ho_complete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) +{ + rrc_gNB_send_NGAP_HANDOVER_NOTIFY(rrc, UE); +} + +/** @brief This callback is used by the source gNB to inform the AMF + * about the cancellation of an ongoing handover */ +static void nr_rrc_n2_ho_cancel(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) +{ + DevAssert(UE->ho_context); + DevAssert(UE->ho_context->source); + ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_HANDOVER_CANCELLED}; + rrc_gNB_send_NGAP_HANDOVER_CANCEL(rrc->module_id, UE, cause); +} + +/** @brief Callback function to trigger NG Handover Failure on the target gNB, to inform the AMF + * that the preparation of resources has failed (e.g. unsatisfied criteria, gNB is already loaded). + * This message represents an Unsuccessful Outcome of the Handover Resource Allocation */ +void nr_rrc_n2_ho_failure(gNB_RRC_INST *rrc, uint32_t gnb_ue_id, ngap_handover_failure_t *msg) +{ + LOG_I(NR_RRC, "Triggering N2 Handover Failure\n"); + rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, msg); + LOG_I(NR_RRC, "Send UE Context Release for gnb_ue_id %d\n", gnb_ue_id); + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, gnb_ue_id); + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(rrc->module_id, ue_context_p, msg->cause); + return; +} + +/** @brief Trigger N2 Handover on the target gNB: + * 1) set up callbacks + * 2) initiate N2 handover on target NG-RAN, which triggers the set up + * of HO context and UE Context Setup procedures */ +void nr_rrc_trigger_n2_ho_target(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue) +{ + ho_req_ack_t ack = nr_rrc_n2_ho_acknowledge; + ho_success_t success = nr_rrc_n2_ho_complete; + ho_failure_t failure = nr_rrc_n2_ho_failure; + + const nr_rrc_du_container_t *target_du = get_du_for_ue(rrc, ue->rrc_ue_id); + nr_initiate_handover(rrc, ue, NULL, target_du, &ue->ho_context->target->ue_ho_prep_info, ack, success, NULL, failure); + FREE_AND_ZERO_BYTE_ARRAY(ue->ho_context->target->ue_ho_prep_info); + + NR_UE_NR_Capability_t *ue_cap = get_ue_nr_capability(ue->rnti, ue->ue_cap_buffer.buf, ue->ue_cap_buffer.len); + ue->UE_Capability_nr = ue_cap; + ue->UE_Capability_size = ue->ue_cap_buffer.len; + +} + +/** @brief Trigger N2 handover on source gNB: + * 1) Prepare RRC Container with HandoverPreparationInformation message + * 2) send NGAP Handover Required message */ +void nr_rrc_trigger_n2_ho(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *ue, + int serving_pci, + const nr_neighbour_cell_t *neighbour_config) +{ + byte_array_t hoPrepInfo = rrc_gNB_generate_HandoverPreparationInformation(rrc, ue, serving_pci); + if (hoPrepInfo.len < 0) { + free_byte_array(hoPrepInfo); + LOG_E(NR_RRC, "Failed to trigger N2 handover on source gNB for UE %x\n", ue->rrc_ue_id); + return; + } + + // allocate context for source + if (ue->ho_context != NULL) { + LOG_E(NR_RRC, "Ongoing handover for UE %d, cannot trigger new\n", ue->rrc_ue_id); + return; + } + + ue->ho_context = alloc_ho_ctx(HO_CTX_SOURCE); + ue->ho_context->source->du = get_du_for_ue(rrc, ue->rrc_ue_id); + ue->ho_context->source->ho_status_transfer = rrc_gNB_send_NGAP_ul_ran_status_transfer; + ue->ho_context->source->ho_cancel = nr_rrc_n2_ho_cancel; + + rrc_gNB_send_NGAP_HANDOVER_REQUIRED(rrc, ue, neighbour_config, hoPrepInfo); + free_byte_array(hoPrepInfo); +} + +extern const nr_neighbour_cell_t *get_neighbour_cell_by_pci(const neighbour_cell_configuration_t *cell, int pci); +extern const neighbour_cell_configuration_t *get_neighbour_cell_config(const gNB_RRC_INST *rrc, int cell_id); + +void nr_HO_N2_trigger_telnet(gNB_RRC_INST *rrc, uint32_t neighbour_pci, uint32_t rrc_ue_id) +{ + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, rrc_ue_id); + if (ue_context_p == NULL) { + LOG_E(NR_RRC, "N2 HO trigger failed for UE %d: cannot find UE context\n", rrc_ue_id); + return; + } + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + + struct nr_rrc_du_container_t *du = get_du_for_ue(rrc, rrc_ue_id); + if (du == NULL) { + LOG_E(NR_RRC, "N2 HO trigger failed for UE %d: Unknown DU\n", rrc_ue_id); + return; + } + uint16_t scell_pci = du->setup_req->cell[0].info.nr_pci; + + // Simulate handover on the same cell (testing purposes) + if (neighbour_pci == scell_pci) { + LOG_I(NR_RRC, "UE %d: trigger handover on the same cell PCI=%d\n", rrc_ue_id, neighbour_pci); + nr_neighbour_cell_t neighbourConfig = { + .isIntraFrequencyNeighbour = true, + .gNB_ID = du->setup_req->gNB_DU_id, + .nrcell_id = du->setup_req->cell[0].info.nr_cellid, + .physicalCellId = du->setup_req->cell[0].info.nr_pci, + .plmn = du->setup_req->cell[0].info.plmn, + .subcarrierSpacing = du->setup_req->cell[0].info.tdd.tbw.scs, + }; + nr_rrc_trigger_n2_ho(rrc, UE, neighbour_pci, &neighbourConfig); + return; + } + + const f1ap_served_cell_info_t *scell_du = get_cell_information_by_phycellId(scell_pci); + DevAssert(scell_du); + LOG_I(NR_RRC, "UE %d: triggered N2 HO, source PCI=%d to target PCI=%d\n", rrc_ue_id, scell_pci, neighbour_pci); + + const neighbour_cell_configuration_t *cell = get_neighbour_cell_config(rrc, scell_du->nr_cellid); + const nr_neighbour_cell_t *neighbour = get_neighbour_cell_by_pci(cell, neighbour_pci); + + if (neighbour == NULL) { + LOG_E(NR_RRC, "N2 HO trigger failed for UE %d: could not find neighbour cell with PCI=%d\n", rrc_ue_id, neighbour_pci); + return; + } + + nr_rrc_trigger_n2_ho(rrc, UE, scell_du->nr_pci, neighbour); +} diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index 6e9bcbcfe6..7010cc83ba 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -23,6 +23,7 @@ #include #include "common/utils/ds/byte_array.h" +#include "nr_rrc_defs.h" /* forward declarations */ typedef struct gNB_RRC_INST_s gNB_RRC_INST; @@ -32,6 +33,12 @@ typedef struct nr_rrc_du_container_t nr_rrc_du_container_t; typedef struct NR_CellGroupConfig NR_CellGroupConfig_t; typedef void (*ho_cancel_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); +typedef int (*ho_status_transfer_t)(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + const int n_to_mod, + const int *drb_ids, + const e1_pdcp_status_info_t *pdcp_status); + typedef struct nr_ho_source_cu { /// pointer to the (source) DU structure const nr_rrc_du_container_t *du; @@ -47,11 +54,16 @@ typedef struct nr_ho_source_cu { /// function pointer to announce the handover cancellation, e.g., /// reestablishment ho_cancel_t ho_cancel; + /// status transfer + ho_status_transfer_t ho_status_transfer; } nr_ho_source_cu_t; /* acknowledgement of handover request. buf+len is the RRC Reconfiguration */ typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); typedef void (*ho_success_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); +typedef void (*ho_failure_t)(gNB_RRC_INST *rrc, uint32_t gnb_ue_id, ngap_handover_failure_t *msg); +typedef void (*ho_trigger_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); + typedef struct nr_ho_target_cu { /// pointer to the (target) DU structure const nr_rrc_du_container_t *du; @@ -61,10 +73,16 @@ typedef struct nr_ho_target_cu { uint32_t du_ue_id; /// new (target) RNTI (as for du_ue_id) rnti_t new_rnti; + /// Handover Preparation Buffer + byte_array_t ue_ho_prep_info; + /// function pointer to trigger handover on target gNB + ho_trigger_t ho_trigger; /// function pointer to announce handover request acknowledgment ho_req_ack_t ho_req_ack; /// function pointer to announce handover success ho_success_t ho_success; + /// function pointer to announce the handover failure + ho_failure_t ho_failure; } nr_ho_target_cu_t; typedef struct nr_handover_context_s { @@ -72,7 +90,20 @@ typedef struct nr_handover_context_s { nr_ho_target_cu_t *target; } nr_handover_context_t; +typedef enum { HO_CTX_BOTH, HO_CTX_SOURCE, HO_CTX_TARGET } ho_ctx_type_t; +nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type); + void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_container_t *source_du, nr_rrc_du_container_t *target_du); void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue); +void nr_rrc_n2_ho_failure(gNB_RRC_INST *rrc, uint32_t gnb_ue_id, ngap_handover_failure_t *msg); + +void nr_rrc_trigger_n2_ho(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *ue, + int serving_pci, + const nr_neighbour_cell_t *neighbour_config); + +void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *rrc_reconf, int rrc_reconf_len); + +void nr_rrc_trigger_n2_ho_target(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); #endif /* RRC_GNB_MOBILITY_H_ */ diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index 8ac172a21e..f0f7201517 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -71,18 +71,14 @@ #include "xer_decoder.h" #include "xer_encoder.h" #include "f1ap_common.h" +#include "lib/f1ap_ue_context.h" +#include "rrc_gNB_asn1.h" // In case of phy-test and do-ra mode, read UE capabilities directly from file // and put it into a CG-ConfigInfo field static int cg_config_info_from_ue_cap_file(uint32_t maxlen, uint8_t buf[maxlen]) { - NR_CG_ConfigInfo_t *cgci = calloc_or_fail(1, sizeof(*cgci)); - cgci->criticalExtensions.present = NR_CG_ConfigInfo__criticalExtensions_PR_c1; - cgci->criticalExtensions.choice.c1 = calloc_or_fail(1, sizeof(*cgci->criticalExtensions.choice.c1)); - cgci->criticalExtensions.choice.c1->present = NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo; - NR_CG_ConfigInfo_IEs_t *cgci_ies = calloc_or_fail(1, sizeof(*cgci_ies)); - cgci->criticalExtensions.choice.c1->choice.cg_ConfigInfo = cgci_ies; - + OCTET_STRING_t *list_buf = NULL; if (uecap_file != NULL) { LOG_I(NR_RRC, "creating CG-ConfigInfo from UE capability file %s\n", uecap_file); @@ -103,14 +99,31 @@ static int cg_config_info_from_ue_cap_file(uint32_t maxlen, uint8_t buf[maxlen]) DevAssert(dec_rval.code == RC_OK); //xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, cap); - OCTET_STRING_t *os_cap = calloc_or_fail(1, sizeof(*os_cap)); - os_cap->size = uper_encode_to_new_buffer(&asn_DEF_NR_UE_NR_Capability, NULL, cap, (void **)&os_cap->buf); - cgci_ies->ue_CapabilityInfo = os_cap; + uint8_t *buf = NULL; + int sizebuf = uper_encode_to_new_buffer(&asn_DEF_NR_UE_NR_Capability, NULL, cap, (void **)&buf); + NR_UE_CapabilityRAT_Container_t *cont = calloc_or_fail(1, sizeof(*cont)); + cont->rat_Type = NR_RAT_Type_nr; + cont->ue_CapabilityRAT_Container.buf = buf; + cont->ue_CapabilityRAT_Container.size = sizebuf; + NR_UE_CapabilityRAT_ContainerList_t *clist = calloc_or_fail(1, sizeof(*clist)); + asn1cSeqAdd(&clist->list, cont); + list_buf = calloc_or_fail(1, sizeof(*list_buf)); + list_buf->size = uper_encode_to_new_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, NULL, clist, (void **)&list_buf->buf); + ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, clist); } + NR_CG_ConfigInfo_t *cgci = calloc_or_fail(1, sizeof(*cgci)); + cgci->criticalExtensions.present = NR_CG_ConfigInfo__criticalExtensions_PR_c1; + cgci->criticalExtensions.choice.c1 = calloc_or_fail(1, sizeof(*cgci->criticalExtensions.choice.c1)); + cgci->criticalExtensions.choice.c1->present = NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo; + NR_CG_ConfigInfo_IEs_t *cgci_ies = calloc_or_fail(1, sizeof(*cgci_ies)); + cgci->criticalExtensions.choice.c1->choice.cg_ConfigInfo = cgci_ies; + cgci_ies->ue_CapabilityInfo = list_buf; + //xer_fprint(stdout, &asn_DEF_NR_CG_ConfigInfo, cgci); asn_enc_rval_t rval = uper_encode_to_buffer(&asn_DEF_NR_CG_ConfigInfo, NULL, cgci, buf, maxlen); DevAssert(rval.encoded > 0); + ASN_STRUCT_FREE(asn_DEF_NR_CG_ConfigInfo, cgci); return (rval.encoded + 7) >> 3; } @@ -122,6 +135,32 @@ static instance_t get_f1_gtp_instance(void) return inst->gtpInst; } +/* returns a default radio bearer config suitable for NSA etc */ +static NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, + int rb_id, + e_NR_CipheringAlgorithm ciphering_algorithm, + e_NR_SecurityConfig__keyToUse key_to_use, + const nr_pdcp_configuration_t *pdcp_config) +{ + NR_RadioBearerConfig_t *rbconfig = calloc_or_fail(1, sizeof(*rbconfig)); + rbconfig->drb_ToAddModList = calloc_or_fail(1, sizeof(*rbconfig->drb_ToAddModList)); + NR_DRB_ToAddMod_t *drb_ToAddMod = calloc_or_fail(1, sizeof(*drb_ToAddMod)); + drb_ToAddMod->drb_Identity = rb_id; + drb_ToAddMod->pdcp_Config = nr_rrc_build_pdcp_config_ie(false, false, pdcp_config); + asn1cCalloc(drb_ToAddMod->cnAssociation, cn_association); + cn_association->present = NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity; + cn_association->choice.eps_BearerIdentity = eps_bearer_id; + asn1cSeqAdd(&rbconfig->drb_ToAddModList->list, drb_ToAddMod); + asn1cCalloc(rbconfig->securityConfig, secConf); + asn1cCalloc(secConf->securityAlgorithmConfig, secConfAlgo); + secConfAlgo->cipheringAlgorithm = ciphering_algorithm; + secConfAlgo->integrityProtAlgorithm = NULL; + asn1cCallocOne(secConf->keyToUse, key_to_use); + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_DRB_ToAddMod, drb_ToAddMod); + return rbconfig; +} + /* generate prototypes for the tree management functions (RB_INSERT used in rrc_add_nsa_user) */ RB_PROTOTYPE(rrc_nr_ue_tree_s, rrc_gNB_ue_context_s, entries, rrc_gNB_compare_ue_rnti_id); @@ -137,18 +176,16 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_ nr_pdcp_entity_security_keys_and_algos_t security_parameters = {0}; uint8_t tmp[1024]; - uint8_t *cgci_buf = NULL; - uint32_t cgci_len = 0; + byte_array_t cgci = {0}; if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) { DevAssert(m == NULL); UE->rb_config = get_default_rbconfig(10 /* EPS bearer ID */, 1 /* drb ID */, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master, &rrc->pdcp_config); - cgci_len = cg_config_info_from_ue_cap_file(sizeof tmp, tmp); - DevAssert(cgci_len > 0); - cgci_buf = tmp; + int len = cg_config_info_from_ue_cap_file(sizeof tmp, tmp); + DevAssert(len > 0); + cgci = create_byte_array(len, tmp); } else { DevAssert(m != NULL); - cgci_buf = m->rrc_buffer; - cgci_len = m->rrc_buffer_size; + cgci = create_byte_array(m->rrc_buffer_size, m->rrc_buffer); /* TODO: handle more than one bearer */ if (m->nb_e_rabs_tobeadded != 1) { @@ -272,25 +309,24 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_ UE->rb_config->drb_ToAddModList, &security_parameters); - cu_to_du_rrc_information_t cu2du = { - .cG_ConfigInfo = cgci_buf, - .cG_ConfigInfo_length = cgci_len, - }; /* assumption: only a single bearer, see above */ NR_DRB_ToAddModList_t *rb_list = UE->rb_config->drb_ToAddModList; AssertFatal(rb_list->list.count == 1, "can only handle one bearer for NSA/phy-test/do-ra, but has %d\n", rb_list->list.count); int drb_id = rb_list->list.array[0]->drb_Identity; - f1ap_flows_mapped_to_drb_t *flow = calloc(1, sizeof(f1ap_flows_mapped_to_drb_t)); - flow->qos_params.qos_characteristics.qos_type = NON_DYNAMIC; - flow->qfi = flow->qos_params.qos_characteristics.non_dynamic.fiveqi = 9; - f1ap_drb_to_be_setup_t drbs = { - .drb_id = drb_id, - .rlc_mode = F1AP_RLC_MODE_UM_BIDIR, // hardcoded keep it backwards compatible for now - // rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM, - .up_ul_tnl_length = 1, - .drb_info.flows_to_be_setup_length = 1, - .drb_info.flows_mapped_to_drb = flow, - }; + f1ap_drb_to_setup_t *drb = calloc_or_fail(1, sizeof(*drb)); + drb->id = drb_id; + // hardcoded keep it backwards compatible for now + // rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM, + drb->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; + drb->up_ul_tnl_len = 1; + drb->qos_choice = F1AP_QOS_CHOICE_NR; // we don't have EUTRAN yet, "approximate" it + drb->nr.flows_len = 1; + f1ap_drb_flows_mapped_t *flow = drb->nr.flows = calloc_or_fail(drb->nr.flows_len, sizeof(*flow)); + flow->qfi = 9; + flow->param.qos_type = NON_DYNAMIC; + flow->param.nondyn.fiveQI = 9; + flow->param.arp.prio = 5; + // Note: E1 support for NSA/phy-test/do-ra not implemented yet instance_t f1inst = get_f1_gtp_instance(); if (f1inst >= 0) { @@ -305,25 +341,30 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_ gtpv1u_gnb_create_tunnel_resp_t resp = {0}; int ret = gtpv1u_create_ngu_tunnel(f1inst, &req, &resp, NULL, NULL); AssertFatal(ret == 0, "gtpv1u_create_ngu_tunnel failed: ret %d\n", ret); - drbs.up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - memcpy(&drbs.up_ul_tnl[0].tl_address, &resp.gnb_addr.buffer, 4); - drbs.up_ul_tnl[0].teid = resp.gnb_NGu_teid[0]; + memcpy(&drb->up_ul_tnl[0].tl_address, &resp.gnb_addr.buffer, 4); + drb->up_ul_tnl[0].teid = resp.gnb_NGu_teid[0]; + drb->up_ul_tnl_len = 1; } - f1ap_ue_context_setup_t req = { + uint64_t *ue_agg_mbr_ul = malloc_or_fail(sizeof(*ue_agg_mbr_ul)); + *ue_agg_mbr_ul = 1000000000; + byte_array_t *cg_configinfo = malloc_or_fail(sizeof(*cg_configinfo)); + *cg_configinfo = cgci; + f1ap_ue_context_setup_req_t req = { .gNB_CU_ue_id = UE->rrc_ue_id, - .gNB_DU_ue_id = 0xffffffff, /* not known yet */ .plmn.mcc = rrc->configuration.plmn[0].mcc, .plmn.mnc = rrc->configuration.plmn[0].mnc, .plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length, .nr_cellid = rrc->nr_cellid, - .servCellId = 0, - .drbs_to_be_setup_length = 1, - .drbs_to_be_setup = &drbs, - .cu_to_du_rrc_information = &cu2du, + .servCellIndex = 0, + .drbs_len = 1, + .drbs = drb, + .cu_to_du_rrc_info.cg_configinfo = cg_configinfo, + .gnb_du_ue_agg_mbr_ul = ue_agg_mbr_ul, }; f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); rrc->mac_rrc.ue_context_setup_request(ue_data.du_assoc_id, &req); + free_ue_context_setup_req(&req); } static NR_RRCReconfiguration_IEs_t *get_default_reconfig(const NR_CellGroupConfig_t *secondaryCellGroup) @@ -382,7 +423,7 @@ static NR_CG_Config_t *generate_CG_Config(const NR_RRCReconfiguration_t *reconfi return cg_Config; } -void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp) +void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_resp_t *resp) { DevAssert(resp->crnti != NULL); /* we did not fill any DU-related ID info in rrc_add_nsa_user() */ @@ -397,12 +438,12 @@ void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_co if (f1inst >= 0) { // Note: E1 support for NSA/phy-test/do-ra not implemented yet // so set up GTP from here - for (int i = 0; i < resp->drbs_to_be_setup_length; ++i) { - f1ap_drb_to_be_setup_t *drb = &resp->drbs_to_be_setup[i]; - DevAssert(drb->up_dl_tnl_length == 1); + for (int i = 0; i < resp->drbs_len; ++i) { + f1ap_drb_setup_t *drb = &resp->drbs[i]; + DevAssert(drb->up_dl_tnl_len == 1); in_addr_t addr = drb->up_dl_tnl[0].tl_address; uint32_t teid = drb->up_dl_tnl[0].teid; - GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, UE->rrc_ue_id, drb->drb_id, addr, teid); + GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, UE->rrc_ue_id, drb->id, addr, teid); } } @@ -412,6 +453,7 @@ void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_co reconfig->criticalExtensions.choice.rrcReconfiguration = get_default_reconfig(UE->masterCellGroup); NR_CG_Config_t *CG_Config = generate_CG_Config(reconfig, UE->rb_config); + ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, reconfig); if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) { /* we are done, no X2 answer necessary */ @@ -461,7 +503,7 @@ void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context) gNB_RRC_UE_t *UE = &ue_context->ue_context; f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); - f1ap_ue_context_release_cmd_t cmd = { + f1ap_ue_context_rel_cmd_t cmd = { .gNB_CU_ue_id = UE->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, .cause = F1AP_CAUSE_RADIO_NETWORK, diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index e22ee7ffd6..5af84f0399 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -31,188 +31,198 @@ #include "ngap_messages_types.h" #include "oai_asn1.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h" +#include "common/utils/alg/find.h" -rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create) +static bool eq_qfi(const void *vval, const void *vit) { - int j; - for (j = 0; j < ue->nb_of_pdusessions; j++) - if (id == ue->pduSession[j].param.pdusession_id) - break; - if (j == ue->nb_of_pdusessions) { - if (create) - ue->nb_of_pdusessions++; - else - return NULL; + const int id = *(const int *)vval; + const nr_rrc_qos_t *elem = (const nr_rrc_qos_t *)vit; + return elem->qos.qfi == id; +} + +/** @brief Retrieves mapped QoS in UE context for the input @param qfi + * @return pointer to the found QoS, NULL if not found */ +nr_rrc_qos_t *find_qos(seq_arr_t *seq, int qfi) +{ + DevAssert(seq); + elm_arr_t elm = find_if(seq, &qfi, eq_qfi); + if (elm.found) + return (nr_rrc_qos_t *)elm.it; + return NULL; +} + +/** @brief Adds a new QoS @param in to UE context the list + * @note A UE can have up to 64 QoS flows which can be multiplexed + * into one or more DRBs. The QFI is the unique ID of the mapping. + * @return pointer to the newly added QoS */ +nr_rrc_qos_t *add_qos(seq_arr_t *qos, const pdusession_level_qos_parameter_t *in) +{ + DevAssert(qos); + DevAssert(in); + + if (seq_arr_size(qos) == MAX_QOS_FLOWS) { + LOG_W(NR_RRC, "Reached maximum number of QoS flows = %ld\n", seq_arr_size(qos)); + return NULL; } - return ue->pduSession + j; + + nr_rrc_qos_t item = {.qos = *in}; + seq_arr_push_back(qos, &item, sizeof(nr_rrc_qos_t)); + + // Double check successful add + nr_rrc_qos_t *added = find_qos(qos, in->qfi); + DevAssert(added); + LOG_I(NR_RRC, "Added QoS flow with qfi=%d, total number of QoS flows = %ld\n", in->qfi, seq_arr_size(qos)); + + // Only one QoS flow is supported + AssertFatal(seq_arr_size(qos) == 1, "only 1 Qos flow supported\n"); + + return added; +} + +/** @brief Free QoS flows list items */ +static void free_qos(void *ptr) { /*nothing to do*/ } + +/** @brief Free QoS flows list */ +static void free_rrc_qos_list(seq_arr_t *seq) +{ + seq_arr_free(seq, free_qos); +} + +static bool eq_pdu_session_id(const void *vval, const void *vit) +{ + const int id = *(const int *)vval; + const rrc_pdu_session_param_t *elem = vit; + return elem->param.pdusession_id == id; +} + +/** @brief Free pdusession_t */ +void free_pdusession(void *ptr) +{ + rrc_pdu_session_param_t *elem = ptr; + free_rrc_qos_list(&elem->param.qos); + free_byte_array(elem->param.nas_pdu); +} + +/** @brief Retrieves PDU Session for the input ID + * @return pointer to the found PDU Session, NULL if not found */ +rrc_pdu_session_param_t *find_pduSession(seq_arr_t *seq, int id) +{ + DevAssert(seq); + elm_arr_t elm = find_if(seq, &id, eq_pdu_session_id); + if (elm.found) + return (rrc_pdu_session_param_t *)elm.it; + return NULL; +} + +/** @brief Adds a new PDU Session to the list + * @return pointer to the new PDU Session */ +rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusession_t *in) +{ + DevAssert(sessions_ptr); + DevAssert(in); + + if (seq_arr_size(sessions_ptr) == NGAP_MAX_PDU_SESSION) { + LOG_W(NR_RRC, "Reached maximum number of PDU Session = %ld\n", seq_arr_size(sessions_ptr)); + return NULL; + } + + rrc_pdu_session_param_t *exists = find_pduSession(sessions_ptr, in->pdusession_id); + if (exists) { + LOG_E(NR_RRC, "Trying to add an already existing PDU Session with ID=%d\n", in->pdusession_id); + return NULL; + } + + rrc_pdu_session_param_t new = {.param = *in, .status = PDU_SESSION_STATUS_NEW, .xid = -1}; + seq_arr_push_back(sessions_ptr, &new, sizeof(rrc_pdu_session_param_t)); + rrc_pdu_session_param_t *added = find_pduSession(sessions_ptr, in->pdusession_id); + DevAssert(added); + LOG_I(NR_RRC, "Added PDU Session %d, (total nb of sessions = %ld)\n", in->pdusession_id, seq_arr_size(sessions_ptr)); + + return added; +} + +/** @brief Add drb_t item in the UE context list for @param pdusession_id */ +drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp) +{ + DevAssert(drb_ptr); + DevAssert(pdcp != NULL); + DevAssert(pdusession_id > 0 && pdusession_id <= NGAP_MAX_PDU_SESSION); + + // Get next available DRB ID + int drb_id = 0; + + // First, try to find the lowest available ID (prefer smaller IDs) + for (drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) { + if (get_drb(drb_ptr, drb_id) == NULL) { + break; // Found available ID + } + } + + if (drb_id > MAX_DRBS_PER_UE) { + LOG_E(NR_RRC, "Cannot set up new DRB for pdusession_id=%d - reached maximum capacity\n", pdusession_id); + return NULL; + } + + // Add item to the list + drb_t in = {.drb_id = drb_id, .pdusession_id = pdusession_id, .pdcp_config = *pdcp}; + seq_arr_push_back(drb_ptr, &in, sizeof(drb_t)); + drb_t *out = get_drb(drb_ptr, drb_id); + DevAssert(out); + LOG_I(NR_RRC, "Added DRB %d to established list (PDU Session ID=%d, total DRBs = %ld)\n", out->drb_id, pdusession_id, seq_arr_size(drb_ptr)); + return out; +} + +static bool eq_drb_id(const void *vval, const void *vit) +{ + const int id = *(const int *)vval; + const drb_t *elem = (const drb_t *)vit; + return elem->drb_id == id; +} + +/** @brief Retrieves DRB for the input ID + * @return pointer to the found DRB, NULL if not found */ +drb_t *get_drb(seq_arr_t *seq, int id) +{ + DevAssert(id > 0 && id <= MAX_DRBS_PER_UE); + elm_arr_t elm = find_if(seq, &id, eq_drb_id); + if (elm.found) + return (drb_t *)elm.it; + return NULL; +} + +/** @brief Free pdusession_t */ +void free_drb(void *ptr) +{ + // do nothing } rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id) { - const drb_t *drb = &ue->established_drbs[drb_id - 1]; - if (drb->status == DRB_INACTIVE) { - LOG_E(NR_RRC, "UE %d: DRB %d inactive\n", ue->rrc_ue_id, drb_id); + const drb_t *drb = get_drb(&ue->drbs, drb_id); + if (!drb) { + LOG_E(NR_RRC, "UE %d: DRB %d not found\n", ue->rrc_ue_id, drb_id); return NULL; } - int id = drb->cnAssociation.sdap_config.pdusession_id; - return find_pduSession(ue, id, false); + int id = drb->pdusession_id; + return find_pduSession(&ue->pduSessions, id); } -void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]) +bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp, + bool um_on_default_drb, + const nr_redcap_ue_cap_t *redcap_cap) { - for (int i = 0; i < ue->nb_of_pdusessions && i < NGAP_MAX_PDU_SESSION; ++i) - pdu_sessions[i] = ue->pduSession[i].param.pdusession_id; -} - -drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) -{ - DevAssert(drb_id > 0 && drb_id <= 32); - DevAssert(ue != NULL); - - return &ue->established_drbs[drb_id - 1]; -} - -void set_default_drb_pdcp_config(struct pdcp_config_s *pdcp_config, - int do_drb_integrity, - int do_drb_ciphering, - const nr_pdcp_configuration_t *default_pdcp_config) -{ - AssertError(pdcp_config != NULL, return, "Failed to set default PDCP configuration for DRB!\n"); - pdcp_config->discardTimer = encode_discard_timer(default_pdcp_config->drb.discard_timer); - pdcp_config->pdcp_SN_SizeDL = encode_sn_size_dl(default_pdcp_config->drb.sn_size); - pdcp_config->pdcp_SN_SizeUL = encode_sn_size_ul(default_pdcp_config->drb.sn_size); - pdcp_config->t_Reordering = encode_t_reordering(default_pdcp_config->drb.t_reordering); - pdcp_config->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; - pdcp_config->headerCompression.NotUsed = 0; - pdcp_config->integrityProtection = do_drb_integrity ? NR_PDCP_Config__drb__integrityProtection_enabled : 1; - pdcp_config->ext1.cipheringDisabled = do_drb_ciphering ? 1 : NR_PDCP_Config__ext1__cipheringDisabled_true; -} - -void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb) -{ - AssertError(rrc_drb != NULL && pdcp_config != NULL, return, "Failed to set default bearer context PDCP configuration!\n"); - pdcp_config->pDCP_SN_Size_UL = rrc_drb->pdcp_config.pdcp_SN_SizeUL; - pdcp_config->pDCP_SN_Size_DL = rrc_drb->pdcp_config.pdcp_SN_SizeDL; - pdcp_config->discardTimer = rrc_drb->pdcp_config.discardTimer; - pdcp_config->reorderingTimer = rrc_drb->pdcp_config.t_Reordering; - pdcp_config->rLC_Mode = um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; -} - -drb_t *generateDRB(gNB_RRC_UE_t *ue, - uint8_t drb_id, - const rrc_pdu_session_param_t *pduSession, - bool enable_sdap, - int do_drb_integrity, - int do_drb_ciphering, - const nr_pdcp_configuration_t *pdcp_config) -{ - DevAssert(ue != NULL); - - LOG_I(NR_RRC, "UE %d: configure DRB ID %d for PDU session ID %d\n", ue->rrc_ue_id, drb_id, pduSession->param.pdusession_id); - - drb_t *est_drb = &ue->established_drbs[drb_id - 1]; - DevAssert(est_drb->status == DRB_INACTIVE); - - est_drb->status = DRB_ACTIVE; - est_drb->drb_id = drb_id; - est_drb->cnAssociation.sdap_config.defaultDRB = true; - - /* SDAP Configuration */ - est_drb->cnAssociation.present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config; - est_drb->cnAssociation.sdap_config.pdusession_id = pduSession->param.pdusession_id; - if (enable_sdap) { - est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present; - est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present; + bearer_context_pdcp_config_t out = {0}; + if (redcap_cap && redcap_cap->support_of_redcap_r17 && !redcap_cap->pdcp_drb_long_sn_redcap_r17) { + LOG_I(NR_RRC, "UE is RedCap without long PDCP SN support: overriding PDCP SN size to 12\n"); + out.pDCP_SN_Size_DL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len12bits; + out.pDCP_SN_Size_UL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len12bits; } else { - est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; - est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; + out.pDCP_SN_Size_DL = encode_sn_size_dl(pdcp.drb.sn_size); + out.pDCP_SN_Size_UL = encode_sn_size_ul(pdcp.drb.sn_size); } - for (int qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) { - est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi; - if (pduSession->param.qos[qos_flow_index].fiveQI > 5) - est_drb->status = DRB_ACTIVE_NONGBR; - else - est_drb->status = DRB_ACTIVE; - } - /* PDCP Configuration */ - set_default_drb_pdcp_config(&est_drb->pdcp_config, do_drb_integrity, do_drb_ciphering, pdcp_config); - - drb_t *rrc_drb = get_drb(ue, drb_id); - DevAssert(rrc_drb == est_drb); /* to double check that we create the same which we would retrieve */ - return rrc_drb; -} - -NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1) -{ - NR_DRB_ToAddMod_t *DRB_config = CALLOC(1, sizeof(*DRB_config)); - NR_SDAP_Config_t *SDAP_config = CALLOC(1, sizeof(NR_SDAP_Config_t)); - - asn1cCalloc(DRB_config->cnAssociation, association); - asn1cCalloc(SDAP_config->mappedQoS_FlowsToAdd, sdapFlows); - asn1cCalloc(DRB_config->pdcp_Config, pdcpConfig); - asn1cCalloc(pdcpConfig->drb, drb); - - DRB_config->drb_Identity = drb_asn1->drb_id; - association->present = drb_asn1->cnAssociation.present; - - /* SDAP Configuration */ - SDAP_config->pdu_Session = drb_asn1->cnAssociation.sdap_config.pdusession_id; - SDAP_config->sdap_HeaderDL = drb_asn1->cnAssociation.sdap_config.sdap_HeaderDL; - SDAP_config->sdap_HeaderUL = drb_asn1->cnAssociation.sdap_config.sdap_HeaderUL; - SDAP_config->defaultDRB = drb_asn1->cnAssociation.sdap_config.defaultDRB; - - for (int qos_flow_index = 0; qos_flow_index < QOSFLOW_MAX_VALUE; qos_flow_index++) { - if (drb_asn1->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] != 0) { - asn1cSequenceAdd(sdapFlows->list, NR_QFI_t, qfi); - *qfi = drb_asn1->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index]; - } - } - - association->choice.sdap_Config = SDAP_config; - - /* PDCP Configuration */ - asn1cCallocOne(drb->discardTimer, drb_asn1->pdcp_config.discardTimer); - asn1cCallocOne(drb->pdcp_SN_SizeUL, drb_asn1->pdcp_config.pdcp_SN_SizeUL); - asn1cCallocOne(drb->pdcp_SN_SizeDL, drb_asn1->pdcp_config.pdcp_SN_SizeDL); - asn1cCallocOne(pdcpConfig->t_Reordering, drb_asn1->pdcp_config.t_Reordering); - - drb->headerCompression.present = drb_asn1->pdcp_config.headerCompression.present; - drb->headerCompression.choice.notUsed = drb_asn1->pdcp_config.headerCompression.NotUsed; - - if (!drb_asn1->pdcp_config.integrityProtection) { - asn1cCallocOne(drb->integrityProtection, drb_asn1->pdcp_config.integrityProtection); - } - if (!drb_asn1->pdcp_config.ext1.cipheringDisabled) { - asn1cCalloc(pdcpConfig->ext1, ext1); - asn1cCallocOne(ext1->cipheringDisabled, drb_asn1->pdcp_config.ext1.cipheringDisabled); - } - - return DRB_config; -} - -uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue) -{ - for (uint8_t drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++) - if (ue->established_drbs[drb_id].status == DRB_INACTIVE) - return drb_id + 1; - /* From this point, we need to handle the case that all DRBs are already used by the UE. */ - LOG_E(RRC, "Error - All the DRBs are used - Handle this\n"); - return DRB_INACTIVE; -} - -int get_number_active_drbs(gNB_RRC_UE_t *ue) -{ - int n = 0; - for (int i = 0; i < MAX_DRBS_PER_UE; ++i) - if (ue->established_drbs[i].status != DRB_INACTIVE) - n++; - return n; -} - -bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id) -{ - drb_t *drb = get_drb(ue, drb_id); - if (drb == NULL) - return DRB_INACTIVE; - return drb->status != DRB_INACTIVE; + out.discardTimer = encode_discard_timer(pdcp.drb.discard_timer); + out.reorderingTimer = encode_t_reordering(pdcp.drb.t_reordering); + out.rLC_Mode = um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; + out.pDCP_Reestablishment = false; + return out; } diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index 4a249496ff..f6821e314b 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -24,61 +24,38 @@ #include #include -#include "NR_DRB-ToAddMod.h" #include "e1ap_messages_types.h" #include "nr_rrc_defs.h" -#define DRB_ACTIVE_NONGBR (2) /* DRB is used for Non-GBR Flows */ -#define DRB_ACTIVE (1) -#define DRB_INACTIVE (0) -#define GBR_FLOW (1) -#define NONGBR_FLOW (0) - -/// @brief Generates an ASN1 DRB-ToAddMod, from the established_drbs in gNB_RRC_UE_t. -/// @param drb_t drb_asn1 -/// @return Returns the ASN1 DRB-ToAddMod structs. -NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1); - /// @brief retrieve the data structure representing DRB with ID drb_id of UE ue -drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id); +drb_t *get_drb(seq_arr_t *seq, int id); -/// @brief Creates and stores a DRB in the gNB_RRC_UE_t struct -/// @param ue The gNB_RRC_UE_t struct that holds information for the UEs -/// @param drb_id The Data Radio Bearer Identity to be created for the established DRB. -/// @param pduSession The PDU Session that the DRB is created for. -/// @param enable_sdap If true the SDAP header will be added to the packet, else it will not add or search for SDAP header. -/// @param do_drb_integrity -/// @param do_drb_ciphering -/// @param pdcp_config -/// @return returns a pointer to the generated DRB structure -drb_t *generateDRB(gNB_RRC_UE_t *ue, - uint8_t drb_id, - const rrc_pdu_session_param_t *pduSession, - bool enable_sdap, - int do_drb_integrity, - int do_drb_ciphering, - const nr_pdcp_configuration_t *pdcp_config); +/// @brief retrieve PDU session of UE ue with ID id +rrc_pdu_session_param_t *find_pduSession(seq_arr_t *seq, int id); -/// @brief return the next available (inactive) DRB ID of UE ue -uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue); - -/// @brief returns the number of active DRBs for this UE -int get_number_active_drbs(gNB_RRC_UE_t *ue); - -/// @brief check if DRB with ID drb_id of UE ue is active -bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id); - -/// @brief retrieve PDU session of UE ue with ID id, optionally creating it if -/// create is true -rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create); +/// @brief Add a new PDU session for UE @param ue and configuration @param in +rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusession_t *in); /// @brief get PDU session of UE ue through the DRB drb_id rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id); -/// @brief get the PDU sessions of this UE in a single array -void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]); +/// @brief set PDCP configuration in E1 Bearer Context Management message +bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp, + bool um_on_default_drb, + const nr_redcap_ue_cap_t *redcap_cap); -/// @brief set PDCP configuration in a bearer context management message -void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb); +void free_pdusession(void *ptr); + +/// @brief Add DRB to RRC list +drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp); + +/// @brief Function to free DRB in RRC +void free_drb(void *ptr); + +/// @brief retrieve QoS flow associated to @param qfi +nr_rrc_qos_t *find_qos(seq_arr_t *seq, int qfi); + +/// @brief Add a new QoS to the list +nr_rrc_qos_t *add_qos(seq_arr_t *qos, const pdusession_level_qos_parameter_t *in); #endif diff --git a/openair2/RRC/NR/tests/CMakeLists.txt b/openair2/RRC/NR/tests/CMakeLists.txt new file mode 100644 index 0000000000..f7a4a95b1b --- /dev/null +++ b/openair2/RRC/NR/tests/CMakeLists.txt @@ -0,0 +1,7 @@ + +add_executable(rrc_bearers_test rrc_bearers_test.c ../rrc_gNB_radio_bearers.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c) +add_dependencies(tests rrc_bearers_test) +add_test(NAME rrc_bearers_test COMMAND rrc_bearers_test) +target_include_directories(rrc_bearers_test PRIVATE ./common/utils/ds common/utils/LOG) +target_link_libraries(rrc_bearers_test PRIVATE ds alg asn1_e1ap asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs LOG T) +target_compile_definitions(rrc_bearers_test PRIVATE ENABLE_TESTS) diff --git a/openair2/RRC/NR/tests/rrc_bearers_test.c b/openair2/RRC/NR/tests/rrc_bearers_test.c new file mode 100644 index 0000000000..982a1b0cd9 --- /dev/null +++ b/openair2/RRC/NR/tests/rrc_bearers_test.c @@ -0,0 +1,173 @@ +/* + * 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 +#include +#include +#include +#include "common/utils/utils.h" +#include "common/utils/assertions.h" +#include "openair2/RRC/NR/rrc_gNB_radio_bearers.h" +#include "ds/seq_arr.h" +#include "common/utils/LOG/log.h" + +int nr_rlc_get_available_tx_space(int module_id, int rnti, int drb_id) { return 0; } +softmodem_params_t *get_softmodem_params(void) { return NULL; } +configmodule_interface_t *uniqCfg = NULL; + +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + printf("detected error at %s:%d:%s: %s\n", file, line, function, s); + abort(); +} + +static void test_rrc_pdu_session(void) +{ + const int pdu_session_id = 3; + gNB_RRC_UE_t ue = {0}; + seq_arr_init(&ue.pduSessions, sizeof(rrc_pdu_session_param_t)); + + /* test add */ + pdusession_t p1 = {0}; + seq_arr_init(&p1.qos, sizeof(nr_rrc_qos_t)); + p1.pdusession_id = pdu_session_id; + p1.n3_incoming.teid = 2002; + LOG_I(NR_RRC, "Adding first PDU Session with ID %d\n", p1.pdusession_id); + rrc_pdu_session_param_t *s1 = add_pduSession(&ue.pduSessions, &p1); // add 1st PDU Session + AssertFatal(s1 != NULL, "Could not add PDU Session\n"); + AssertFatal(s1->param.pdusession_id == p1.pdusession_id, "PDU Session ID mismatch in added PDU Session\n"); + AssertFatal(s1->param.n3_incoming.teid == p1.n3_incoming.teid, "teid mismatch in added PDU Session\n"); + LOG_A(NR_RRC, "First PDU Session added successfully\n"); + + /* test find */ + rrc_pdu_session_param_t *a1 = find_pduSession(&ue.pduSessions, p1.pdusession_id); + AssertFatal(a1 != NULL, "Could not find PDU Session\n"); + AssertFatal(a1 == s1, "Found PDU Session mismatch\n"); + LOG_A(NR_RRC, "PDU Session find test passed\n"); + + /* test add duplicate */ + pdusession_t input2 = {0}; + seq_arr_init(&input2.qos, sizeof(nr_rrc_qos_t)); + input2.pdusession_id = pdu_session_id; + input2.n3_incoming.teid = 9999; + rrc_pdu_session_param_t *s2 = add_pduSession(&ue.pduSessions, &input2); // add 2nd PDU Session + AssertFatal(s2 == NULL, "Duplicated PDU session was added!\n"); + LOG_A(NR_RRC, "Duplicated PDU session test passed\n"); + seq_arr_free(&input2.qos, NULL); + + /* add DRB and fetch PDU Session */ + seq_arr_init(&ue.drbs, sizeof(drb_t)); + nr_pdcp_configuration_t pdcp = {.drb.discard_timer = 100, .drb.sn_size = 18, .drb.t_reordering = 50}; + drb_t *added = nr_rrc_add_drb(&ue.drbs, pdu_session_id, &pdcp); + AssertFatal(added != NULL, "Failed to add DRB"); + rrc_pdu_session_param_t *a2 = find_pduSession_from_drbId(&ue, added->drb_id); + AssertFatal(a2 && a2->param.pdusession_id == pdu_session_id, "find_pduSession_from_drbId failed"); + + seq_arr_free(&ue.pduSessions, free_pdusession); + seq_arr_free(&ue.drbs, free_drb); +} + +// ---------------- DRB TESTS ---------------- + +static void test_rrc_drb(void) +{ + LOG_I(NR_RRC, "Starting DRB test\n"); + seq_arr_t pduSessions = {0}; + seq_arr_t drbs = {0}; + seq_arr_init(&pduSessions, sizeof(rrc_pdu_session_param_t)); + seq_arr_init(&drbs, sizeof(drb_t)); + + /* test add 1 DRB to 1st PDU session */ + const int id1 = 1; + pdusession_t s1 = {0}; + seq_arr_init(&s1.qos, sizeof(nr_rrc_qos_t)); + s1.pdusession_id = id1; + add_pduSession(&pduSessions, &s1); // add PDU session + + nr_pdcp_configuration_t pdcp = {.drb.discard_timer = 100, .drb.sn_size = 18, .drb.t_reordering = 50}; + drb_t *in1 = nr_rrc_add_drb(&drbs, id1, &pdcp); // add DRB + AssertFatal(in1, "add_rrc_drb failed"); + LOG_A(NR_RRC, "First DRB created with ID %d\n", in1->drb_id); + + drb_t *out1 = get_drb(&drbs, 1); // fetch DRB + AssertFatal(out1 && out1 == in1, "get_drb failed"); + LOG_A(NR_RRC, "DRB retrieval test passed\n"); + + /* test add DRB to 2nd PDU session */ + const int id2 = 2; + pdusession_t s2 = {0}; + seq_arr_init(&s2.qos, sizeof(nr_rrc_qos_t)); + s2.pdusession_id = id2; + add_pduSession(&pduSessions, &s2); // add 2nd PDU session + drb_t *in2 = nr_rrc_add_drb(&drbs, id2, &pdcp); // add DRB to 2nd PDU session + AssertFatal(in2, "add_rrc_drb failed"); + LOG_A(NR_RRC, "Second DRB created with ID %d\n", in2->drb_id); + drb_t *out2 = get_drb(&drbs, 2); + AssertFatal(out2 && out2->drb_id == 2, "get_drb failed"); + LOG_A(NR_RRC, "Second DRB retrieval test passed\n"); + + seq_arr_free(&pduSessions, free_pdusession); + seq_arr_free(&drbs, free_drb); +} + +// ---------------- DRB TESTS ---------------- + +static void test_rrc_qos(void) +{ + seq_arr_t pduSessions = {0}; + seq_arr_init(&pduSessions, sizeof(rrc_pdu_session_param_t)); + + const int session_id = 70; + pdusession_t in = {0}; + in.pdusession_id = session_id; + seq_arr_init(&in.qos, sizeof(nr_rrc_qos_t)); + add_pduSession(&pduSessions, &in); + LOG_A(NR_RRC, "Created PDU Session %d for QoS test\n", session_id); + + const int qfi = 4; + const pdusession_level_qos_parameter_t param = { .fiveQI = 9, .fiveQI_type = NON_DYNAMIC, .qfi = qfi }; + LOG_A(NR_RRC, "Adding QoS flow with QFI %d\n", qfi); + nr_rrc_qos_t *added = add_qos(&in.qos, ¶m); + AssertFatal(added, "add_qos failed"); + LOG_A(NR_RRC, "QoS flow added successfully\n"); + + nr_rrc_qos_t *found = find_qos(&in.qos, qfi); + AssertFatal(found && found == added, "find_qos failed"); + LOG_A(NR_RRC, "QoS flow find test passed\n"); + + seq_arr_free(&pduSessions, free_pdusession); +} + +int main() +{ + // Initialize logging system + logInit(); + // Set logging level for NR_RRC to show INFO messages + set_log(NR_RRC, OAILOG_INFO); + // PDU Session + test_rrc_pdu_session(); + // DRB + test_rrc_drb(); + // QoS + test_rrc_qos(); + LOG_A(NR_RRC, "All RRC Bearers tests passed successfully!\n"); + return 0; +} diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c index 09bce459f2..bae8915916 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.c +++ b/openair2/RRC/NR_UE/L2_interface_ue.c @@ -37,6 +37,17 @@ typedef uint32_t channel_t; +void nr_mac_rrc_meas_ind_ue(module_id_t module_id, uint32_t gNB_index, uint16_t Nid_cell, bool csi_meas, bool is_neighboring_cell, int rsrp_dBm) +{ + MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_MEAS_DATA_IND); + NR_RRC_MAC_MEAS_DATA_IND(message_p).gnb_index = gNB_index; + NR_RRC_MAC_MEAS_DATA_IND(message_p).Nid_cell = Nid_cell; + NR_RRC_MAC_MEAS_DATA_IND(message_p).is_csi_meas = csi_meas; + NR_RRC_MAC_MEAS_DATA_IND(message_p).is_neighboring_cell = is_neighboring_cell; + NR_RRC_MAC_MEAS_DATA_IND(message_p).rsrp_dBm = rsrp_dBm; + itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(module_id), message_p); +} + void nr_mac_rrc_sync_ind(const module_id_t module_id, const frame_t frame, const bool in_sync) { MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_SYNC_IND); @@ -121,35 +132,40 @@ void nr_mac_rrc_data_ind_ue(const module_id_t module_id, } } -void process_msg_rcc_to_mac(MessageDef *msg) +void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id) { - instance_t ue_id = ITTI_MSG_DESTINATION_INSTANCE(msg); - switch (ITTI_MSG_ID(msg)) { + switch (msg->payload_type) { case NR_MAC_RRC_CONFIG_RESET: - nr_rrc_mac_config_req_reset(ue_id, NR_MAC_RRC_CONFIG_RESET(msg).cause); + nr_rrc_mac_config_req_reset(instance_id, msg->payload.config_reset.cause); break; case NR_MAC_RRC_CONFIG_CG: - nr_rrc_mac_config_req_cg(ue_id, 0, NR_MAC_RRC_CONFIG_CG(msg).cellGroupConfig, NR_MAC_RRC_CONFIG_CG(msg).UE_NR_Capability); - asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, NR_MAC_RRC_CONFIG_CG(msg).cellGroupConfig); + nr_rrc_mac_config_req_cg(instance_id, 0, msg->payload.config_cg.cellGroupConfig, msg->payload.config_cg.UE_NR_Capability); + ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, msg->payload.config_cg.cellGroupConfig); break; case NR_MAC_RRC_CONFIG_MIB: - nr_rrc_mac_config_req_mib(ue_id, 0, NR_MAC_RRC_CONFIG_MIB(msg).bcch->message.choice.mib, NR_MAC_RRC_CONFIG_MIB(msg).get_sib); - ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, NR_MAC_RRC_CONFIG_MIB(msg).bcch); + nr_rrc_mac_config_req_mib(instance_id, + 0, + msg->payload.config_mib.bcch->message.choice.mib, + msg->payload.config_mib.get_sib, + msg->payload.config_mib.access_barred); + ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, msg->payload.config_mib.bcch); break; case NR_MAC_RRC_CONFIG_SIB1: { - NR_SIB1_t *sib1 = NR_MAC_RRC_CONFIG_SIB1(msg).sib1; - bool can_start_ra = NR_MAC_RRC_CONFIG_SIB1(msg).can_start_ra; - nr_rrc_mac_config_req_sib1(ue_id, 0, sib1, can_start_ra); - SEQUENCE_free(&asn_DEF_NR_SIB1, NR_MAC_RRC_CONFIG_SIB1(msg).sib1, ASFM_FREE_EVERYTHING); + NR_SIB1_t *sib1 = msg->payload.config_sib1.sib1; + bool can_start_ra = msg->payload.config_sib1.can_start_ra; + nr_rrc_mac_config_req_sib1(instance_id, 0, sib1, can_start_ra); + SEQUENCE_free(&asn_DEF_NR_SIB1, msg->payload.config_sib1.sib1, ASFM_FREE_EVERYTHING); } break; case NR_MAC_RRC_CONFIG_OTHER_SIB: { - bool can_start_ra = NR_MAC_RRC_CONFIG_OTHER_SIB(msg).can_start_ra; - nr_rrc_mac_config_other_sib(ue_id, NR_MAC_RRC_CONFIG_OTHER_SIB(msg).sib19, can_start_ra); + bool can_start_ra = msg->payload.config_other_sib.can_start_ra; + nr_rrc_mac_config_other_sib(instance_id, msg->payload.config_other_sib.sib19, can_start_ra); } break; + case NR_MAC_RRC_RESUME_RB: + nr_rrc_mac_resume_rb(instance_id, msg->payload.resume_rb.is_srb, msg->payload.resume_rb.rb_id); + break; default: - LOG_E(NR_MAC, "Unexpected msg from RRC: %d\n", ITTI_MSG_ID(msg)); + LOG_E(NR_MAC, "Unexpected msg from RRC: %d\n", msg->payload_type); } - itti_free(ITTI_MSG_ORIGIN_ID(msg), msg); } void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id) diff --git a/openair2/RRC/NR_UE/L2_interface_ue.h b/openair2/RRC/NR_UE/L2_interface_ue.h index e36f6d83fb..5c7a4c16af 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.h +++ b/openair2/RRC/NR_UE/L2_interface_ue.h @@ -37,11 +37,16 @@ void nr_mac_rrc_data_ind_ue(const module_id_t module_id, const channel_t channel, const uint8_t* pduP, const sdu_size_t pdu_len); +void nr_mac_rrc_meas_ind_ue(module_id_t module_id, + uint32_t gNB_index, + uint16_t Nid_cell, + bool csi_meas, + bool is_neighboring_cell, + int rsrp_dBm); void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id); void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload); void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id); void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success); -void nsa_sendmsg_to_lte_ue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type); -void process_msg_rcc_to_mac(MessageDef *msg); +void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id); #endif diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index bb58191e24..d23dd14c58 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -72,7 +72,7 @@ #include "nr_nas_msg.h" #include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" -static NR_UE_RRC_INST_t *NR_UE_rrc_inst; +static NR_UE_RRC_INST_t *NR_UE_rrc_inst[MAX_NUM_NR_UE_INST] = {0}; /* NAS Attach request with IMSI */ static const char nr_nas_attach_req_imsi_dummy_NSA_case[] = { 0x07, @@ -134,23 +134,29 @@ static const char nr_nas_attach_req_imsi_dummy_NSA_case[] = { 0x11, }; -static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, - const NR_CellGroupConfig_t *cellGroupConfig); - -static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc, - NR_RadioBearerConfig_t *const radioBearerConfig); -static void nr_rrc_ue_generate_rrcReestablishmentComplete(const NR_UE_RRC_INST_t *rrc, const NR_RRCReestablishment_t *rrcReestablishment); -static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_len); -static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECapabilityEnquiry_t *UECapabilityEnquiry); -static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc, - OCTET_STRING_t *masterCellGroup, - long *fullConfig); - -static void nr_rrc_ue_process_measConfig(rrcPerNB_t *rrc, NR_MeasConfig_t *const measConfig, NR_UE_Timers_Constants_t *timers); - -NR_UE_RRC_INST_t* get_NR_UE_rrc_inst(int instance) +/** + * @brief Sends an RRC message to the connected UE MAC instance. + * + * @param rrc UE RRC instance structure + * @param msg RRC message to be sent to MAC + */ +static void nr_rrc_send_msg_to_mac(NR_UE_RRC_INST_t *rrc, nr_mac_rrc_message_t *msg) { - return &NR_UE_rrc_inst[instance]; + AssertFatal(rrc->mac_input_nf != NULL, "MAC input NF is NULL for UE %ld\n", rrc->ue_id); + notifiedFIFO_elt_t *nf_msg = newNotifiedFIFO_elt(sizeof(nr_mac_rrc_message_t), 0, NULL, NULL); + nr_mac_rrc_message_t *rrc_msg = NotifiedFifoData(nf_msg); + memcpy(rrc_msg, msg, sizeof(nr_mac_rrc_message_t)); + pushNotifiedFIFO(rrc->mac_input_nf, nf_msg); +} + +NR_UE_RRC_INST_t *get_NR_UE_rrc_inst(int instance) +{ + AssertFatal(instance >= 0 && instance < MAX_NUM_NR_UE_INST, "RRC instance %d out of bounds\n", instance); + NR_UE_RRC_INST_t *rrc = NR_UE_rrc_inst[instance]; + if (rrc == NULL) + return NULL; + AssertFatal(rrc->ue_id == instance, "RRC ID %d doesn't match with input %d\n", (int)rrc->ue_id, instance); + return rrc; } static NR_RB_status_t get_DRB_status(const NR_UE_RRC_INST_t *rrc, NR_DRB_Identity_t drb_id) @@ -165,9 +171,121 @@ static void set_DRB_status(NR_UE_RRC_INST_t *rrc, NR_DRB_Identity_t drb_id, NR_R rrc->status_DRBs[drb_id - 1] = status; } -static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, NR_UE_RRC_INST_t *rrc) +static int get_ulsyncvalidityduration_timer_value(NR_NTN_Config_r17_t *ntncfg) +{ + int retval = 0; + AssertFatal(ntncfg, "NTN-Config IE not present\n"); + + if (ntncfg->ntn_UlSyncValidityDuration_r17) { + const int values[] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 120, 180, 240, 900}; + retval = values[*ntncfg->ntn_UlSyncValidityDuration_r17]; + } + + return retval; +} + +static void get_epochtime_from_sib19scheduling(NR_UE_RRC_SI_INFO *SI_info, int *frame, int *subframe) +{ + // TS 38.331 section 5.2.2.3.2 + // SI-window starts at the slot #a, where a = x mod N + // x = (si-WindowPosition -1) × w, where w is the si-WindowLength; + // N is the number of slots in a radio frame + int wl_slots = 5 << SI_info->si_windowlength; + int x = (SI_info->sib19_windowposition - 1) * wl_slots; + int slots_per_subframe = 1 << SI_info->scs; + int N = slots_per_subframe * 10; + int slot_end_sib19_window = (x % N) + wl_slots; + + *frame += (slot_end_sib19_window / N); + int slot = slot_end_sib19_window % N; + *subframe = ceil(slot / slots_per_subframe); + + LOG_I(NR_RRC, + "Get EPOCHTIME: x:%d, N:%d, slot_endw:%d, frame:%d, subframe:%d , slot:%d\n", + x, + N, + slot_end_sib19_window, + *frame, + *subframe, + slot); +} + +static int eval_epoch_time(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int frame) +{ + int epoch_frame = 0, epoch_subframe = 0; + int diff_frames = 0; + AssertFatal(frame >= 0, "Frame Incorrect, results in incorrect EPOCH time evaluation\n"); + if (ntncfg->epochTime_r17) { + epoch_frame = ntncfg->epochTime_r17->sfn_r17; + epoch_subframe = ntncfg->epochTime_r17->subFrameNR_r17; + } else { + // EPOCH time is optional in case of SIB19. This case happens only in case of SIB19 NTN config + // If no EPOCH time is sent, epochtime points to SIB19 window end slot in the current scheduling window + epoch_frame = frame; + epoch_subframe = 0; + get_epochtime_from_sib19scheduling(SI_info, &epoch_frame, &epoch_subframe); + // Adding epochTime IE in SIB19, later MAC will use it. + ntncfg->epochTime_r17 = CALLOC(1, sizeof(NR_EpochTime_r17_t)); + ntncfg->epochTime_r17->sfn_r17 = epoch_frame; + ntncfg->epochTime_r17->subFrameNR_r17 = epoch_subframe; + } + // For serving cell, the field sfn indicates the current SFN or the next upcoming SFN + // after the frame where the message indicating the epochTime is received + // i.e. Epochframe can be present or future SFN + diff_frames = (epoch_frame - frame + 1024) % 1024; // According to 38.331 Epochtime is defined for serving cell like this + LOG_I(NR_RRC, "Epoch frame %d, ahead by %d frames\n", epoch_frame, diff_frames); + return diff_frames; +} + +static int get_ntn_timervalues(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int diff_frames, int *val430_ms) +{ + int val430 = get_ulsyncvalidityduration_timer_value(ntncfg); + int sib19_periodicity_ms = (SI_info->sib19_periodicity + 1) * 10; + *val430_ms = val430 * 1000 + diff_frames * 10; // in ms + if (*val430_ms <= sib19_periodicity_ms) + LOG_E(NR_RRC, "Too small T430 value. Might result in frequent ULSYNC failure\n"); + + // Depending on ulsyncvalidity duration, SIB19 timer expires 15secs/2secs before T430 + // LArger values might be used for GEO and epoch time interval can be around 10 secs + // Lower values will be used for NGSO (LEO/MEO), epoch time interval can be between 2-3 secs. + // TODO remove the hardoded values and define a better strategy to determine the time of expiry + // with real GEO/LEO/MEO SATs. + int expire_before_ms = ((val430 >= 120) ? 10000 : 2000); + int diff = *val430_ms - expire_before_ms; + int sib19_timer_ms = (diff > 0) ? diff : ((*val430_ms - sib19_periodicity_ms) > 0) ? (*val430_ms - sib19_periodicity_ms) : 0; + LOG_I(NR_RRC, "val430:%d s, T430:%d ms, sib19_timer:%d ms\n", val430, *val430_ms, sib19_timer_ms); + return sib19_timer_ms; +} + +static void nr_rrc_process_ntnconfig(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int frame) +{ + SI_info->SInfo_r17.sib19_validity = true; + // Check if Epochtime is sent or not + int diff_frames = eval_epoch_time(SI_info, ntncfg, frame); + + if (ntncfg->ntn_UlSyncValidityDuration_r17) { // ulsyncvalidity duration configured + int val430_ms = 0, sib19_timer_ms = 0; + sib19_timer_ms = get_ntn_timervalues(SI_info, ntncfg, diff_frames, &val430_ms); + // T430 should be started only in connected mode. + // Inorder to avoid starting T430 when entering connected mode, T430 is started as soon as + // SIB19 is received, and if UE enters connected mode T430 will be in running. + // T430 expiry in RRC idle or inactive states does nothing. + nr_timer_setup(&rrc->timers_and_constants.T430, val430_ms, 10); + nr_timer_start(&rrc->timers_and_constants.T430); + // SIB19 should be received before T430 expires + // SIB19 validity timer should expire before T430 expiry such that new SIB19 is read + if (sib19_timer_ms > 0) { + nr_timer_setup(&SI_info->SInfo_r17.sib19_timer, sib19_timer_ms, 10); + nr_timer_start(&SI_info->SInfo_r17.sib19_timer); + } else + // This makes sure that SIB19 is read again in the next window + SI_info->SInfo_r17.sib19_validity = false; + } else + nr_timer_start(&SI_info->SInfo_r17.sib19_timer); +} + +static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, NR_UE_RRC_INST_t *rrc, int frame) { - instance_t ue_id = rrc->ue_id; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_IN); // Dump contents @@ -240,11 +358,10 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, nr_timer_start(&SI_info->sib14_timer); break; case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib19_v1700: - SI_info->SInfo_r17.sib19_validity = true; - if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG) - xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)typeandinfo->choice.sib19_v1700); sib19 = typeandinfo->choice.sib19_v1700; - nr_timer_start(&SI_info->SInfo_r17.sib19_timer); + if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG) + xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)sib19); + nr_rrc_process_ntnconfig(rrc, SI_info, sib19->ntn_Config_r17, frame); break; default: break; @@ -252,10 +369,12 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si, } if (sib19) { - MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_OTHER_SIB); - asn_copy(&asn_DEF_NR_SIB19_r17, (void **)&NR_MAC_RRC_CONFIG_OTHER_SIB(msg).sib19, sib19); - NR_MAC_RRC_CONFIG_OTHER_SIB(msg).can_start_ra = rrc->is_NTN_UE; - itti_send_msg_to_task(TASK_MAC_UE, ue_id, msg); + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_OTHER_SIB; + nr_mac_rrc_config_other_sib_t *sib19_msg = &rrc_msg.payload.config_other_sib; + asn_copy(&asn_DEF_NR_SIB19_r17, (void **)&sib19_msg->sib19, sib19); + sib19_msg->can_start_ra = rrc->is_NTN_UE; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RRC_UE_DECODE_SI, VCD_FUNCTION_OUT); } @@ -335,6 +454,27 @@ static bool verify_NTN_access(const NR_UE_RRC_SI_INFO *SI_info, const NR_SIB1_v1 return ntn_access && sib19_present; } +static void get_sib19_schedinfo(NR_UE_RRC_SI_INFO *SI_info, NR_SI_SchedulingInfo_v1700_t *si_SchedInfo_v1700) +{ + // Find the SIB19 periodicity configured in the scheduling info + if (si_SchedInfo_v1700) { + int count_v17 = si_SchedInfo_v1700->schedulingInfoList2_r17.list.count; + for (int i = 0; i < count_v17; i++) { + struct NR_SchedulingInfo2_r17 *schedulingInfo2 = si_SchedInfo_v1700->schedulingInfoList2_r17.list.array[i]; + for (int j = 0; j < schedulingInfo2->sib_MappingInfo_r17.list.count; j++) { + struct NR_SIB_TypeInfo_v1700 *sib_TypeInfo_v1700 = schedulingInfo2->sib_MappingInfo_r17.list.array[j]; + if (sib_TypeInfo_v1700->sibType_r17.present == NR_SIB_TypeInfo_v1700__sibType_r17_PR_type1_r17) { + if (sib_TypeInfo_v1700->sibType_r17.choice.type1_r17 == NR_SIB_TypeInfo_v1700__sibType_r17__type1_r17_sibType19) { + SI_info->sib19_periodicity = 8 << schedulingInfo2->si_Periodicity_r17; + SI_info->sib19_windowposition = schedulingInfo2->si_WindowPosition_r17; + return; + } + } + } + } + } +} + static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_info, NR_SIB1_t *sib1) { if(g_log->log_component[NR_RRC].level >= OAILOG_DEBUG) @@ -355,18 +495,255 @@ static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_inf si_SchedInfo_v1700 = sib1_v1700->si_SchedulingInfo_v1700; } + AssertFatal(sib1->servingCellConfigCommon, "configuration issue in SIB1\n"); + SI_info->scs = sib1->servingCellConfigCommon->downlinkConfigCommon.initialDownlinkBWP.genericParameters.subcarrierSpacing; + SI_info->si_windowlength = (sib1->si_SchedulingInfo) ? sib1->si_SchedulingInfo->si_WindowLength : 0; // configure default SI nr_rrc_configure_default_SI(SI_info, sib1->si_SchedulingInfo, si_SchedInfo_v1700); rrc->is_NTN_UE = verify_NTN_access(SI_info, sib1_v1700); + if (rrc->is_NTN_UE) + get_sib19_schedinfo(SI_info, si_SchedInfo_v1700); // configure timers and constant nr_rrc_set_sib1_timers_and_constants(&rrc->timers_and_constants, sib1); // RRC storage of SIB1 timers and constants (eg needed in re-establishment) UPDATE_IE(rrc->timers_and_constants.sib1_TimersAndConstants, sib1->ue_TimersAndConstants, NR_UE_TimersAndConstants_t); - MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_SIB1); - NR_MAC_RRC_CONFIG_SIB1(msg).sib1 = sib1; - NR_MAC_RRC_CONFIG_SIB1(msg).can_start_ra = !rrc->is_NTN_UE; - itti_send_msg_to_task(TASK_MAC_UE, rrc->ue_id, msg); + + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_SIB1; + nr_mac_rrc_config_sib1_t *config_sib1 = &rrc_msg.payload.config_sib1; + config_sib1->sib1 = sib1; + config_sib1->can_start_ra = !rrc->is_NTN_UE; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); +} + +static void nr_rrc_nh_update(NR_UE_RRC_INST_t *rrc, uint8_t *kamf, uint8_t *sync_input) +{ + uint8_t nh[SECURITY_KEY_LEN] = {0}; + nr_derive_nh(kamf, sync_input, nh); + log_hex_buffer("Sync input = stored NH", rrc->nh, SECURITY_KEY_LEN); + memcpy(rrc->nh, nh, SECURITY_KEY_LEN); + rrc->nhcc++; // Increase stored nextHopChainingCount +} + +/** @brief AS security key update procedure (5.3.5.7 3GPP TS 38.331) */ +void as_security_key_update(NR_UE_RRC_INST_t *rrc, NR_MasterKeyUpdate_t *mku) +{ + if (mku->nas_Container) { + LOG_E(NR_RRC, "forward the nas-Container to the upper layers: not implemented yet\n"); + } + if (mku->keySetChangeIndicator) { + LOG_E(NR_RRC, "derive or update the K gNB key based on the K AMF key, as specified in TS 33.501: not implemented yet\n"); + } else { + /* derive or update the K gNB key based on the current K gNB key or the NH, using the nextHopChainingCount + value indicated in the received masterKeyUpdate, as specified in 6.9.2.3.3 3GPP TS 33.501 */ + if (mku->nextHopChainingCount != rrc->nhcc) { + // - If the UE received an NCC value that was different from the NCC associated with the currently active + // K gNB/K eNB, the UE shall first synchronize the locally kept NH parameter by computing the function defined in + // Annex A.10 iteratively (and increasing the NCC value until it matches the NCC value received from the source + // ng-eNB/gNB via the HO command message. + LOG_A(NR_RRC, "Received masterKeyUpdate (nextHopChainingCount %ld): update security keys\n", mku->nextHopChainingCount); + /** @todo: The KAMF should be obtained from NAS. This exchange over ITTI must be synchronized + * with the rest of the RRCReconfiguration procedure, in particular, the RadioBearerConfig + * processing that triggers bearer modifications. Security configueration of bearers must + * complete using the newly derived keys. As a workaround NAS is directly accessed here. */ + nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id); + uint8_t *kamf = nas->security.kamf; + log_hex_buffer("Stored kamf", kamf, SECURITY_KEY_LEN); + if (rrc->nhcc == 0) { // First derivation + derive_kgnb(kamf, 0, rrc->kgnb); + log_hex_buffer("Sync input = derived kgnb", rrc->kgnb, SECURITY_KEY_LEN); + nr_rrc_nh_update(rrc, kamf, rrc->kgnb); + } + for (int i = rrc->nhcc; i < mku->nextHopChainingCount; i++) { // Following derivations + LOG_D(NR_RRC, "Derive keys for ChainingCount = %d\n", i); + nr_rrc_nh_update(rrc, kamf, rrc->nh); + } + nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->nh, rrc->kgnb); + // When the NCC values match, the UE shall compute the K NG-RAN * + // from the synchronized NH parameter and the target PCI and its frequency ARFCN-DL/EARFCN-DL using the + // function defined in Annex A.11 and A.12. + // The UE shall use the KNG-RAN * as the K gNB when communicating with the target gNB and as the KeNB when + // communicating with the target ng-eNB. + } else { + nr_derive_key_ng_ran_star(rrc->phyCellID, rrc->arfcn_ssb, rrc->kgnb, rrc->kgnb); + } + log_hex_buffer("Derived kgnb", rrc->kgnb, SECURITY_KEY_LEN); + } +} + +static nr_pdcp_entity_security_keys_and_algos_t get_security_rrc_parameters(NR_UE_RRC_INST_t *ue, bool cp) +{ + nr_pdcp_entity_security_keys_and_algos_t out = {0}; + out.ciphering_algorithm = ue->cipheringAlgorithm; + out.integrity_algorithm = ue->integrityProtAlgorithm; + nr_derive_key(cp ? RRC_ENC_ALG : UP_ENC_ALG, ue->cipheringAlgorithm, ue->kgnb, out.ciphering_key); + nr_derive_key(cp ? RRC_INT_ALG : UP_INT_ALG, ue->integrityProtAlgorithm, ue->kgnb, out.integrity_key); + return out; +} + +/** @brief Check if there is dedicated NAS information to forward to NAS */ +static void nr_rrc_process_dedicatedNAS_MessageList(NR_UE_RRC_INST_t *rrc, NR_RRCReconfiguration_v1530_IEs_t *rec_1530) +{ + if (rec_1530->dedicatedNAS_MessageList) { + struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *tmp = rec_1530->dedicatedNAS_MessageList; + for (int i = 0; i < tmp->list.count; i++) { + MessageDef *ittiMsg = itti_alloc_new_message(TASK_RRC_NRUE, rrc->ue_id, NAS_CONN_ESTABLI_CNF); + nas_establish_cnf_t *msg = &NAS_CONN_ESTABLI_CNF(ittiMsg); + msg->errCode = AS_SUCCESS; + msg->nasMsg.length = tmp->list.array[i]->size; + msg->nasMsg.nas_data = malloc_or_fail(msg->nasMsg.length); + memcpy(msg->nasMsg.nas_data, tmp->list.array[i]->buf, msg->nasMsg.length); + itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, ittiMsg); + } + } +} + +/** + * @brief add, modify and release SRBs and/or DRBs + * @ref 3GPP TS 38.331 + */ +static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc, NR_RadioBearerConfig_t *const radioBearerConfig) +{ + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void *)radioBearerConfig); + + if (radioBearerConfig->srb3_ToRelease) { + nr_pdcp_release_srb(ue_rrc->ue_id, 3); + ue_rrc->Srb[3] = RB_NOT_PRESENT; + } + + nr_pdcp_entity_security_keys_and_algos_t security_rrc_parameters = {0}; + nr_pdcp_entity_security_keys_and_algos_t security_up_parameters = {0}; + + if (ue_rrc->as_security_activated) { + if (radioBearerConfig->securityConfig != NULL) { + // When the field is not included, continue to use the currently configured keyToUse + if (radioBearerConfig->securityConfig->keyToUse) { + AssertFatal(*radioBearerConfig->securityConfig->keyToUse == NR_SecurityConfig__keyToUse_master, + "Secondary key usage seems not to be implemented\n"); + ue_rrc->keyToUse = *radioBearerConfig->securityConfig->keyToUse; + } + // When the field is not included, continue to use the currently configured security algorithm + if (radioBearerConfig->securityConfig->securityAlgorithmConfig) { + ue_rrc->cipheringAlgorithm = radioBearerConfig->securityConfig->securityAlgorithmConfig->cipheringAlgorithm; + ue_rrc->integrityProtAlgorithm = *radioBearerConfig->securityConfig->securityAlgorithmConfig->integrityProtAlgorithm; + } + } + security_rrc_parameters = get_security_rrc_parameters(ue_rrc, true); + security_up_parameters = get_security_rrc_parameters(ue_rrc, false); + } + + if (radioBearerConfig->srb_ToAddModList != NULL) { + for (int cnt = 0; cnt < radioBearerConfig->srb_ToAddModList->list.count; cnt++) { + struct NR_SRB_ToAddMod *srb = radioBearerConfig->srb_ToAddModList->list.array[cnt]; + if (ue_rrc->Srb[srb->srb_Identity] == RB_NOT_PRESENT) { + ue_rrc->Srb[srb->srb_Identity] = RB_ESTABLISHED; + add_srb(false, + ue_rrc->ue_id, + radioBearerConfig->srb_ToAddModList->list.array[cnt], + &security_rrc_parameters); + } + else { + AssertFatal(srb->discardOnPDCP == NULL, "discardOnPDCP not yet implemented\n"); + if (srb->reestablishPDCP) { + ue_rrc->Srb[srb->srb_Identity] = RB_ESTABLISHED; + nr_pdcp_reestablishment(ue_rrc->ue_id, + srb->srb_Identity, + true, + &security_rrc_parameters); + } + if (srb->pdcp_Config && srb->pdcp_Config->t_Reordering) + nr_pdcp_reconfigure_srb(ue_rrc->ue_id, srb->srb_Identity, *srb->pdcp_Config->t_Reordering); + } + } + } + + if (radioBearerConfig->drb_ToReleaseList) { + for (int cnt = 0; cnt < radioBearerConfig->drb_ToReleaseList->list.count; cnt++) { + NR_DRB_Identity_t *DRB_id = radioBearerConfig->drb_ToReleaseList->list.array[cnt]; + if (DRB_id) { + nr_pdcp_release_drb(ue_rrc->ue_id, *DRB_id); + set_DRB_status(ue_rrc, *DRB_id, RB_NOT_PRESENT); + } + } + } + + /** + * Establish/reconfig DRBs if DRB-ToAddMod is present + * according to 3GPP TS 38.331 clause 5.3.5.6.5 DRB addition/modification + */ + if (radioBearerConfig->drb_ToAddModList != NULL) { + for (int cnt = 0; cnt < radioBearerConfig->drb_ToAddModList->list.count; cnt++) { + struct NR_DRB_ToAddMod *drb = radioBearerConfig->drb_ToAddModList->list.array[cnt]; + int DRB_id = drb->drb_Identity; + if (get_DRB_status(ue_rrc, DRB_id) != RB_NOT_PRESENT) { + if (drb->reestablishPDCP) { + set_DRB_status(ue_rrc, DRB_id, RB_ESTABLISHED); + /* get integrity and cipehring settings from radioBearerConfig */ + bool has_integrity = drb->pdcp_Config != NULL + && drb->pdcp_Config->drb != NULL + && drb->pdcp_Config->drb->integrityProtection != NULL; + bool has_ciphering = !(drb->pdcp_Config != NULL + && drb->pdcp_Config->ext1 != NULL + && drb->pdcp_Config->ext1->cipheringDisabled != NULL); + security_up_parameters.ciphering_algorithm = has_ciphering ? ue_rrc->cipheringAlgorithm : 0; + security_up_parameters.integrity_algorithm = has_integrity ? ue_rrc->integrityProtAlgorithm : 0; + /* re-establish */ + nr_pdcp_reestablishment(ue_rrc->ue_id, + DRB_id, + false, + &security_up_parameters); + } + AssertFatal(drb->recoverPDCP == NULL, "recoverPDCP not yet implemented\n"); + /* sdap-Config is included (SA mode) */ + NR_SDAP_Config_t *sdap_Config = drb->cnAssociation ? drb->cnAssociation->choice.sdap_Config : NULL; + /* PDCP reconfiguration */ + if (drb->pdcp_Config) + nr_pdcp_reconfigure_drb(ue_rrc->ue_id, DRB_id, drb->pdcp_Config); + /* SDAP entity reconfiguration */ + if (sdap_Config) + nr_reconfigure_sdap_entity(sdap_Config, ue_rrc->ue_id, sdap_Config->pdu_Session, DRB_id); + } else { + set_DRB_status(ue_rrc ,DRB_id, RB_ESTABLISHED); + add_drb(false, + ue_rrc->ue_id, + radioBearerConfig->drb_ToAddModList->list.array[cnt], + &security_up_parameters); + } + } + } // drb_ToAddModList // + + ue_rrc->nrRrcState = RRC_STATE_CONNECTED_NR; + LOG_I(NR_RRC, "State = NR_RRC_CONNECTED\n"); +} + +static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc, + OCTET_STRING_t *masterCellGroup, + long *fullConfig, + int gNB_index) +{ + AssertFatal(!fullConfig, "fullConfig not supported yet\n"); + NR_CellGroupConfig_t *cellGroupConfig = NULL; + uper_decode(NULL, + &asn_DEF_NR_CellGroupConfig, //might be added prefix later + (void **)&cellGroupConfig, + (uint8_t *)masterCellGroup->buf, + masterCellGroup->size, 0, 0); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); + } + + nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index); + + LOG_D(RRC, "Sending CellGroupConfig to MAC the pointer will be managed by mac\n"); + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_CG; + nr_mac_rrc_config_cg_t *mac_msg = &rrc_msg.payload.config_cg; + mac_msg->cellGroupConfig = cellGroupConfig; + mac_msg->UE_NR_Capability = rrc->UECap.UE_NR_Capability; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); } static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCReconfiguration_v1530_IEs_t *rec_1530, int gNB_index) @@ -376,23 +753,11 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe LOG_E(NR_RRC, "RRCReconfiguration includes fullConfig but this is not implemented yet\n"); } if (rec_1530->masterCellGroup) - nr_rrc_ue_process_masterCellGroup(rrc, rec_1530->masterCellGroup, rec_1530->fullConfig); + nr_rrc_ue_process_masterCellGroup(rrc, rec_1530->masterCellGroup, rec_1530->fullConfig, gNB_index); if (rec_1530->masterKeyUpdate) { - // TODO perform AS security key update procedure as specified in 5.3.5.7 - LOG_E(NR_RRC, "RRCReconfiguration includes masterKeyUpdate but this is not implemented yet\n"); - } - /* Check if there is dedicated NAS information to forward to NAS */ - if (rec_1530->dedicatedNAS_MessageList) { - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *tmp = rec_1530->dedicatedNAS_MessageList; - for (int i = 0; i < tmp->list.count; i++) { - MessageDef *ittiMsg = itti_alloc_new_message(TASK_RRC_NRUE, rrc->ue_id, NAS_CONN_ESTABLI_CNF); - nas_establish_cnf_t *msg = &NAS_CONN_ESTABLI_CNF(ittiMsg); - msg->errCode = AS_SUCCESS; - msg->nasMsg.length = tmp->list.array[i]->size; - msg->nasMsg.nas_data = tmp->list.array[i]->buf; - itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, ittiMsg); - } - tmp->list.count = 0; // to prevent the automatic free by ASN1_FREE + as_security_key_update(rrc, rec_1530->masterKeyUpdate); + nr_pdcp_entity_security_keys_and_algos_t sp = get_security_rrc_parameters(rrc, true); + nr_pdcp_config_set_security(rrc->ue_id, 1, true, &sp); } NR_UE_RRC_SI_INFO *SI_info = &rrc->perNB[gNB_index].SInfo; if (rec_1530->dedicatedSIB1_Delivery) { @@ -426,7 +791,7 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe SEQUENCE_free(&asn_DEF_NR_SystemInformation, si, 1); } else { LOG_I(NR_RRC, "[UE %ld] Decoding dedicatedSystemInformationDelivery\n", rrc->ue_id); - nr_decode_SI(SI_info, si, rrc); + nr_decode_SI(SI_info, si, rrc, rrc->current_frame); } } if (rec_1530->otherConfig) { @@ -462,6 +827,274 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe } } +static void handle_meas_reporting_remove(rrcPerNB_t *rrc, int id, NR_UE_Timers_Constants_t *timers) +{ + // remove the measurement reporting entry for this measId if included + asn1cFreeStruc(asn_DEF_NR_VarMeasReport, rrc->MeasReport[id]); + // TODO stop the periodical reporting timer or timer T321, whichever is running, + // and reset the associated information (e.g. timeToTrigger) for this measId + nr_timer_stop(&timers->T321); + + l3_measurements_t *l3_measurements = &rrc->l3_measurements; + nr_timer_stop(&l3_measurements->TA2); + nr_timer_stop(&l3_measurements->periodic_report_timer); + + l3_measurements->reports_sent = 0; + l3_measurements->max_reports = 0; + l3_measurements->report_interval_ms = 0; +} + +static void handle_measobj_remove(rrcPerNB_t *rrc, struct NR_MeasObjectToRemoveList *remove_list, NR_UE_Timers_Constants_t *timers) +{ + // section 5.5.2.4 in 38.331 + for (int i = 0; i < remove_list->list.count; i++) { + // for each measObjectId included in the received measObjectToRemoveList + // that is part of measObjectList in the configuration + NR_MeasObjectId_t id = *remove_list->list.array[i]; + if (rrc->MeasObj[id - 1]) { + // remove the entry with the matching measObjectId from the measObjectList + asn1cFreeStruc(asn_DEF_NR_MeasObjectToAddMod, rrc->MeasObj[id - 1]); + // remove all measId associated with this measObjectId from the measIdList + for (int j = 0; j < MAX_MEAS_ID; j++) { + if (rrc->MeasId[j] && rrc->MeasId[j]->measObjectId == id) { + asn1cFreeStruc(asn_DEF_NR_MeasIdToAddMod, rrc->MeasId[j]); + handle_meas_reporting_remove(rrc, j, timers); + } + } + } + } +} + +static void update_ssb_configmob(NR_SSB_ConfigMobility_t *source, NR_SSB_ConfigMobility_t *target) +{ + if (source->ssb_ToMeasure) + HANDLE_SETUPRELEASE_IE(target->ssb_ToMeasure, source->ssb_ToMeasure, NR_SSB_ToMeasure_t, asn_DEF_NR_SSB_ToMeasure); + target->deriveSSB_IndexFromCell = source->deriveSSB_IndexFromCell; + if (source->ss_RSSI_Measurement) + UPDATE_IE(target->ss_RSSI_Measurement, source->ss_RSSI_Measurement, NR_SS_RSSI_Measurement_t); +} + +static void update_nr_measobj(NR_MeasObjectNR_t *source, NR_MeasObjectNR_t *target) +{ + UPDATE_IE(target->ssbFrequency, source->ssbFrequency, NR_ARFCN_ValueNR_t); + UPDATE_IE(target->ssbSubcarrierSpacing, source->ssbSubcarrierSpacing, NR_SubcarrierSpacing_t); + UPDATE_IE(target->smtc1, source->smtc1, NR_SSB_MTC_t); + if (source->smtc2) { + target->smtc2->periodicity = source->smtc2->periodicity; + if (source->smtc2->pci_List) + UPDATE_IE(target->smtc2->pci_List, source->smtc2->pci_List, struct NR_SSB_MTC2__pci_List); + } + else + asn1cFreeStruc(asn_DEF_NR_SSB_MTC2, target->smtc2); + UPDATE_IE(target->refFreqCSI_RS, source->refFreqCSI_RS, NR_ARFCN_ValueNR_t); + if (source->referenceSignalConfig.ssb_ConfigMobility) + update_ssb_configmob(source->referenceSignalConfig.ssb_ConfigMobility, target->referenceSignalConfig.ssb_ConfigMobility); + UPDATE_IE(target->absThreshSS_BlocksConsolidation, source->absThreshSS_BlocksConsolidation, NR_ThresholdNR_t); + UPDATE_IE(target->absThreshCSI_RS_Consolidation, source->absThreshCSI_RS_Consolidation, NR_ThresholdNR_t); + UPDATE_IE(target->nrofSS_BlocksToAverage, source->nrofSS_BlocksToAverage, long); + UPDATE_IE(target->nrofCSI_RS_ResourcesToAverage, source->nrofCSI_RS_ResourcesToAverage, long); + target->quantityConfigIndex = source->quantityConfigIndex; + target->offsetMO = source->offsetMO; + if (source->cellsToRemoveList) { + RELEASE_IE_FROMLIST(source->cellsToRemoveList, target->cellsToAddModList, physCellId); + } + if (source->cellsToAddModList) { + if (!target->cellsToAddModList) + target->cellsToAddModList = calloc(1, sizeof(*target->cellsToAddModList)); + ADDMOD_IE_FROMLIST(source->cellsToAddModList, target->cellsToAddModList, physCellId, NR_CellsToAddMod_t); + } + if (source->excludedCellsToRemoveList) { + RELEASE_IE_FROMLIST(source->excludedCellsToRemoveList, target->excludedCellsToAddModList, pci_RangeIndex); + } + if (source->excludedCellsToAddModList) { + if (!target->excludedCellsToAddModList) + target->excludedCellsToAddModList = calloc(1, sizeof(*target->excludedCellsToAddModList)); + ADDMOD_IE_FROMLIST(source->excludedCellsToAddModList, target->excludedCellsToAddModList, pci_RangeIndex, NR_PCI_RangeElement_t); + } + if (source->allowedCellsToRemoveList) { + RELEASE_IE_FROMLIST(source->allowedCellsToRemoveList, target->allowedCellsToAddModList, pci_RangeIndex); + } + if (source->allowedCellsToAddModList) { + if (!target->allowedCellsToAddModList) + target->allowedCellsToAddModList = calloc(1, sizeof(*target->allowedCellsToAddModList)); + ADDMOD_IE_FROMLIST(source->allowedCellsToAddModList, target->allowedCellsToAddModList, pci_RangeIndex, NR_PCI_RangeElement_t); + } + if (source->ext1) { + UPDATE_IE(target->ext1->freqBandIndicatorNR, source->ext1->freqBandIndicatorNR, NR_FreqBandIndicatorNR_t); + UPDATE_IE(target->ext1->measCycleSCell, source->ext1->measCycleSCell, long); + } +} + +static void handle_measobj_addmod(rrcPerNB_t *rrc, struct NR_MeasObjectToAddModList *addmod_list) +{ + // section 5.5.2.5 in 38.331 + for (int i = 0; i < addmod_list->list.count; i++) { + NR_MeasObjectToAddMod_t *measObj = addmod_list->list.array[i]; + if (measObj->measObject.present != NR_MeasObjectToAddMod__measObject_PR_measObjectNR) { + LOG_E(NR_RRC, "Cannot handle MeasObjt other than NR\n"); + continue; + } + NR_MeasObjectId_t id = measObj->measObjectId; + if (rrc->MeasObj[id]) { + update_nr_measobj(measObj->measObject.choice.measObjectNR, rrc->MeasObj[id]->measObject.choice.measObjectNR); + } + else { + // add a new entry for the received measObject to the measObjectList + UPDATE_IE(rrc->MeasObj[id], addmod_list->list.array[i], NR_MeasObjectToAddMod_t); + } + } +} + +static void handle_reportconfig_remove(rrcPerNB_t *rrc, + struct NR_ReportConfigToRemoveList *remove_list, + NR_UE_Timers_Constants_t *timers) +{ + for (int i = 0; i < remove_list->list.count; i++) { + NR_ReportConfigId_t id = *remove_list->list.array[i]; + // remove the entry with the matching reportConfigId from the reportConfigList + asn1cFreeStruc(asn_DEF_NR_ReportConfigToAddMod, rrc->ReportConfig[id]); + for (int j = 0; j < MAX_MEAS_ID; j++) { + if (rrc->MeasId[j] && rrc->MeasId[j]->reportConfigId == id) { + // remove all measId associated with the reportConfigId from the measIdList + asn1cFreeStruc(asn_DEF_NR_MeasIdToAddMod, rrc->MeasId[j]); + handle_meas_reporting_remove(rrc, j, timers); + } + } + } +} + +static void handle_reportconfig_addmod(rrcPerNB_t *rrc, + struct NR_ReportConfigToAddModList *addmod_list, + NR_UE_Timers_Constants_t *timers) +{ + for (int i = 0; i < addmod_list->list.count; i++) { + NR_ReportConfigToAddMod_t *rep = addmod_list->list.array[i]; + if (rep->reportConfig.present != NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR) { + LOG_E(NR_RRC, "Cannot handle reportConfig type other than NR\n"); + continue; + } + NR_ReportConfigId_t id = rep->reportConfigId; + if (rrc->ReportConfig[id]) { + for (int j = 0; j < MAX_MEAS_ID; j++) { + // for each measId associated with this reportConfigId included in the measIdList + if (rrc->MeasId[j] && rrc->MeasId[j]->reportConfigId == id) + handle_meas_reporting_remove(rrc, j, timers); + } + } + UPDATE_IE(rrc->ReportConfig[id], addmod_list->list.array[i], NR_ReportConfigToAddMod_t); + } +} + +static void handle_quantityconfig(rrcPerNB_t *rrc, NR_QuantityConfig_t *quantityConfig, NR_UE_Timers_Constants_t *timers) +{ + if (quantityConfig->quantityConfigNR_List) { + for (int i = 0; i < quantityConfig->quantityConfigNR_List->list.count; i++) { + NR_QuantityConfigNR_t *quantityNR = quantityConfig->quantityConfigNR_List->list.array[i]; + if (!rrc->QuantityConfig[i]) + rrc->QuantityConfig[i] = calloc(1, sizeof(*rrc->QuantityConfig[i])); + rrc->QuantityConfig[i]->quantityConfigCell = quantityNR->quantityConfigCell; + // TODO: It remains to compute ssb_filter_coeff_rsrp and csi_RS_filter_coeff_rsrp for multiple quantityConfig + // TS 38.331 - 5.5.3.2 Layer 3 filtering + NR_QuantityConfigRS_t *qcc = &quantityNR->quantityConfigCell; + l3_measurements_t *l3_measurements = &rrc->l3_measurements; + if (qcc->ssb_FilterConfig.filterCoefficientRSRP) + l3_measurements->ssb_filter_coeff_rsrp = 1. / pow(2, (*qcc->ssb_FilterConfig.filterCoefficientRSRP) / 4); + if (qcc->csi_RS_FilterConfig.filterCoefficientRSRP) + l3_measurements->csi_RS_filter_coeff_rsrp = 1. / pow(2, (*qcc->csi_RS_FilterConfig.filterCoefficientRSRP) / 4); + if (quantityNR->quantityConfigRS_Index) + UPDATE_IE(rrc->QuantityConfig[i]->quantityConfigRS_Index, quantityNR->quantityConfigRS_Index, struct NR_QuantityConfigRS); + } + } + for (int j = 0; j < MAX_MEAS_ID; j++) { + // for each measId included in the measIdList + if (rrc->MeasId[j]) + handle_meas_reporting_remove(rrc, j, timers); + } +} + +static void handle_measid_remove(rrcPerNB_t *rrc, struct NR_MeasIdToRemoveList *remove_list, NR_UE_Timers_Constants_t *timers) +{ + for (int i = 0; i < remove_list->list.count; i++) { + NR_MeasId_t id = *remove_list->list.array[i]; + if (rrc->MeasId[id]) { + asn1cFreeStruc(asn_DEF_NR_MeasIdToAddMod, rrc->MeasId[id]); + handle_meas_reporting_remove(rrc, id, timers); + } + } +} + +static void handle_measid_addmod(rrcPerNB_t *rrc, struct NR_MeasIdToAddModList *addmod_list, NR_UE_Timers_Constants_t *timers) +{ + for (int i = 0; i < addmod_list->list.count; i++) { + NR_MeasId_t id = addmod_list->list.array[i]->measId; + NR_ReportConfigId_t reportId = addmod_list->list.array[i]->reportConfigId; + NR_MeasObjectId_t measObjectId = addmod_list->list.array[i]->measObjectId; + UPDATE_IE(rrc->MeasId[id], addmod_list->list.array[i], NR_MeasIdToAddMod_t); + handle_meas_reporting_remove(rrc, id, timers); + if (rrc->ReportConfig[reportId]) { + NR_ReportConfigToAddMod_t *report = rrc->ReportConfig[reportId]; + AssertFatal(report->reportConfig.present == NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR, + "Only NR config report is supported\n"); + NR_ReportConfigNR_t *reportNR = report->reportConfig.choice.reportConfigNR; + // if the reportType is set to reportCGI in the reportConfig associated with this measId + if (reportNR->reportType.present == NR_ReportConfigNR__reportType_PR_reportCGI) { + if (rrc->MeasObj[measObjectId]) { + if (rrc->MeasObj[measObjectId]->measObject.present == NR_MeasObjectToAddMod__measObject_PR_measObjectNR) { + NR_MeasObjectNR_t *obj_nr = rrc->MeasObj[measObjectId]->measObject.choice.measObjectNR; + NR_ARFCN_ValueNR_t freq = 0; + if (obj_nr->ssbFrequency) + freq = *obj_nr->ssbFrequency; + else if (obj_nr->refFreqCSI_RS) + freq = *obj_nr->refFreqCSI_RS; + AssertFatal(freq > 0, "Invalid ARFCN frequency for this measurement object\n"); + if (get_freq_range_from_arfcn(freq) == FR2) + nr_timer_setup(&timers->T321, 16000, 10); // 16 seconds for FR2 + else + nr_timer_setup(&timers->T321, 2000, 10); // 2 seconds for FR1 + } + else // EUTRA + nr_timer_setup(&timers->T321, 1000, 10); // 1 second for EUTRA + nr_timer_start(&timers->T321); + } + } + } + } +} + +static void nr_rrc_ue_process_measConfig(rrcPerNB_t *rrc, NR_MeasConfig_t *const measConfig, NR_UE_Timers_Constants_t *timers) +{ + if (measConfig->measObjectToRemoveList) + handle_measobj_remove(rrc, measConfig->measObjectToRemoveList, timers); + + if (measConfig->measObjectToAddModList) + handle_measobj_addmod(rrc, measConfig->measObjectToAddModList); + + if (measConfig->reportConfigToRemoveList) + handle_reportconfig_remove(rrc, measConfig->reportConfigToRemoveList, timers); + + if (measConfig->reportConfigToAddModList) + handle_reportconfig_addmod(rrc, measConfig->reportConfigToAddModList, timers); + + if (measConfig->quantityConfig) + handle_quantityconfig(rrc, measConfig->quantityConfig, timers); + + if (measConfig->measIdToRemoveList) + handle_measid_remove(rrc, measConfig->measIdToRemoveList, timers); + + if (measConfig->measIdToAddModList) + handle_measid_addmod(rrc, measConfig->measIdToAddModList, timers); + + LOG_W(NR_RRC, "Measurement gaps not yet supported!\n"); + + if (measConfig->s_MeasureConfig) { + if (measConfig->s_MeasureConfig->present == NR_MeasConfig__s_MeasureConfig_PR_ssb_RSRP) { + rrc->s_measure = measConfig->s_MeasureConfig->choice.ssb_RSRP; + } else if (measConfig->s_MeasureConfig->present == NR_MeasConfig__s_MeasureConfig_PR_csi_RSRP) { + rrc->s_measure = measConfig->s_MeasureConfig->choice.csi_RSRP; + } + } +} + static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_index, NR_RRCReconfiguration_t *reconfiguration) { rrcPerNB_t *rrcNB = rrc->perNB + gNB_index; @@ -470,6 +1103,9 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_ case NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration: { NR_RRCReconfiguration_IEs_t *ie = reconfiguration->criticalExtensions.choice.rrcReconfiguration; + if (ie->nonCriticalExtension) + nr_rrc_process_reconfiguration_v1530(rrc, ie->nonCriticalExtension, gNB_index); + if (ie->radioBearerConfig) { LOG_I(NR_RRC, "RRCReconfiguration includes radio Bearer Configuration\n"); nr_rrc_ue_process_RadioBearerConfig(rrc, ie->radioBearerConfig); @@ -477,8 +1113,11 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_ xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void *)ie->radioBearerConfig); } + /** @note This triggers PDU Session Establishment Accept which sets up the TUN interface. + * SDAP entity is a pre-requisite, therefore the radioBearerConfig has to be processed + * (in nr_rrc_ue_process_RadioBearerConfig, add_drb) early enough, or it may cause a race condition in SDAP. */ if (ie->nonCriticalExtension) - nr_rrc_process_reconfiguration_v1530(rrc, ie->nonCriticalExtension, gNB_index); + nr_rrc_process_dedicatedNAS_MessageList(rrc, ie->nonCriticalExtension); if (ie->secondaryCellGroup) { NR_CellGroupConfig_t *cellGroupConfig = NULL; @@ -502,15 +1141,15 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_ if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); - nr_rrc_cellgroup_configuration(rrc, cellGroupConfig); + nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index); AssertFatal(!IS_SA_MODE(get_softmodem_params()), "secondaryCellGroup only used in NSA for now\n"); - MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_CG); - // cellGroupConfig will be managed by MAC - NR_MAC_RRC_CONFIG_CG(msg).cellGroupConfig = cellGroupConfig; - // UE_NR_Capability remain a race condition between this rrc thread and mac thread - NR_MAC_RRC_CONFIG_CG(msg).UE_NR_Capability = rrc->UECap.UE_NR_Capability; - itti_send_msg_to_task(TASK_MAC_UE, rrc->ue_id, msg); + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_CG; + nr_mac_rrc_config_cg_t *config_cg = &rrc_msg.payload.config_cg; + config_cg->cellGroupConfig = cellGroupConfig; + config_cg->UE_NR_Capability = rrc->UECap.UE_NR_Capability; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); } if (ie->measConfig) { LOG_I(NR_RRC, "RRCReconfiguration includes Measurement Configuration\n"); @@ -592,66 +1231,66 @@ static bool verify_ue_cap(NR_UE_NR_Capability_t *UE_NR_Capability, int nb_antenn return true; } -NR_UE_RRC_INST_t* nr_rrc_init_ue(char* uecap_file, int nb_inst, int num_ant_tx) +NR_UE_RRC_INST_t* nr_rrc_init_ue(char* uecap_file, int instance_id, int num_ant_tx) { - NR_UE_rrc_inst = (NR_UE_RRC_INST_t *)calloc(nb_inst, sizeof(NR_UE_RRC_INST_t)); - AssertFatal(NR_UE_rrc_inst, "Couldn't allocate %d instances of RRC module\n", nb_inst); + AssertFatal(instance_id < MAX_NUM_NR_UE_INST, "RRC instance %d out of bounds\n", instance_id); + AssertFatal(NR_UE_rrc_inst[instance_id] == NULL, "RRC instance %d already initialized\n", instance_id); + NR_UE_rrc_inst[instance_id] = calloc_or_fail(1, sizeof(NR_UE_RRC_INST_t)); + NR_UE_RRC_INST_t *rrc = NR_UE_rrc_inst[instance_id]; + rrc->ue_id = instance_id; + // fill UE-NR-Capability @ UE-CapabilityRAT-Container here. + rrc->selected_plmn_identity = 1; + rrc->ra_trigger = RA_NOT_RUNNING; + rrc->dl_bwp_id = 0; + rrc->ul_bwp_id = 0; + rrc->as_security_activated = false; + rrc->detach_after_release = false; + rrc->reconfig_after_reestab = false; + /* 5G-S-TMSI */ + rrc->fiveG_S_TMSI = UINT64_MAX; + rrc->access_barred = false; - for(int nr_ue = 0; nr_ue < nb_inst; nr_ue++) { - NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[nr_ue]; - rrc->ue_id = nr_ue; - // fill UE-NR-Capability @ UE-CapabilityRAT-Container here. - rrc->selected_plmn_identity = 1; - rrc->ra_trigger = RA_NOT_RUNNING; - rrc->dl_bwp_id = 0; - rrc->ul_bwp_id = 0; - rrc->as_security_activated = false; - rrc->detach_after_release = false; - rrc->reconfig_after_reestab = false; - /* 5G-S-TMSI */ - rrc->fiveG_S_TMSI = UINT64_MAX; - - FILE *f = NULL; - if (uecap_file) - f = fopen(uecap_file, "r"); - if (f) { - char UE_NR_Capability_xer[65536]; - size_t size = fread(UE_NR_Capability_xer, 1, sizeof UE_NR_Capability_xer, f); - if (size == 0 || size == sizeof UE_NR_Capability_xer) { - LOG_E(NR_RRC, "UE Capabilities XER file %s is too large (%ld)\n", uecap_file, size); - } - else { - asn_dec_rval_t dec_rval = - xer_decode(0, &asn_DEF_NR_UE_NR_Capability, (void *)&rrc->UECap.UE_NR_Capability, UE_NR_Capability_xer, size); - assert(dec_rval.code == RC_OK); - } - fclose(f); - /* Verify consistency of num PHY antennas vs UE Capabilities */ - verify_ue_cap(rrc->UECap.UE_NR_Capability, num_ant_tx); + FILE *f = NULL; + if (uecap_file) + f = fopen(uecap_file, "r"); + if (f) { + char UE_NR_Capability_xer[65536]; + size_t size = fread(UE_NR_Capability_xer, 1, sizeof UE_NR_Capability_xer, f); + if (size == 0 || size == sizeof UE_NR_Capability_xer) { + LOG_E(NR_RRC, "UE Capabilities XER file %s is too large (%ld)\n", uecap_file, size); + } else { + asn_dec_rval_t dec_rval = + xer_decode(0, &asn_DEF_NR_UE_NR_Capability, (void *)&rrc->UECap.UE_NR_Capability, UE_NR_Capability_xer, size); + assert(dec_rval.code == RC_OK); } - - memset(&rrc->timers_and_constants, 0, sizeof(rrc->timers_and_constants)); - set_default_timers_and_constants(&rrc->timers_and_constants); - - for (int j = 0; j < NR_NUM_SRB; j++) - rrc->Srb[j] = RB_NOT_PRESENT; - for (int j = 1; j <= MAX_DRBS_PER_UE; j++) - set_DRB_status(rrc, j, RB_NOT_PRESENT); - // SRB0 activated by default - rrc->Srb[0] = RB_ESTABLISHED; - for (int j = 0; j < NR_MAX_NUM_LCID; j++) - rrc->active_RLC_entity[j] = false; - - for (int i = 0; i < NB_CNX_UE; i++) { - rrcPerNB_t *ptr = &rrc->perNB[i]; - ptr->SInfo = (NR_UE_RRC_SI_INFO){0}; - init_SI_timers(&ptr->SInfo); - } - - init_sidelink(rrc); + fclose(f); + /* Verify consistency of num PHY antennas vs UE Capabilities */ + verify_ue_cap(rrc->UECap.UE_NR_Capability, num_ant_tx); } - return NR_UE_rrc_inst; + memset(&rrc->timers_and_constants, 0, sizeof(rrc->timers_and_constants)); + set_default_timers_and_constants(&rrc->timers_and_constants); + + for (int j = 0; j < NR_NUM_SRB; j++) + rrc->Srb[j] = RB_NOT_PRESENT; + for (int j = 1; j <= MAX_DRBS_PER_UE; j++) + set_DRB_status(rrc, j, RB_NOT_PRESENT); + // SRB0 activated by default + rrc->Srb[0] = RB_ESTABLISHED; + for (int j = 0; j < NR_MAX_NUM_LCID; j++) + rrc->active_RLC_entity[j] = false; + + for (int i = 0; i < NB_CNX_UE; i++) { + rrcPerNB_t *ptr = &rrc->perNB[i]; + ptr->SInfo = (NR_UE_RRC_SI_INFO){0}; + ptr->l3_measurements = (l3_measurements_t){0}; + ptr->l3_measurements.ssb_filter_coeff_rsrp = 1.0f; + ptr->l3_measurements.csi_RS_filter_coeff_rsrp = 1.0f; + init_SI_timers(&ptr->SInfo); + } + + init_sidelink(rrc); + return rrc; } bool check_si_validity(NR_UE_RRC_SI_INFO *SI_info, int si_type) @@ -820,11 +1459,12 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc, } NR_UE_RRC_SI_INFO *SI_info = &rrc->perNB[gNB_index].SInfo; + bool barred = rrc->access_barred || bcch_message->message.choice.mib->cellBarred == NR_MIB__cellBarred_barred; int get_sib = 0; if (IS_SA_MODE(get_softmodem_params()) && !SI_info->sib_pending && bcch_message->message.present == NR_BCCH_BCH_MessageType_PR_mib - && bcch_message->message.choice.mib->cellBarred == NR_MIB__cellBarred_notBarred + && !barred && rrc->nrRrcState != RRC_STATE_DETACH_NR) { // to schedule MAC to get SI if required get_sib = check_si_status(SI_info); @@ -832,11 +1472,13 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc, SI_info->sib_pending = true; } if (bcch_message->message.present == NR_BCCH_BCH_MessageType_PR_mib) { - MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_MIB); - // mac will manage the pointer - NR_MAC_RRC_CONFIG_MIB(msg).bcch = bcch_message; - NR_MAC_RRC_CONFIG_MIB(msg).get_sib = get_sib; - itti_send_msg_to_task(TASK_MAC_UE, rrc->ue_id, msg); + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_MIB; + nr_mac_rrc_config_mib_t *config_mib = &rrc_msg.payload.config_mib; + config_mib->bcch = bcch_message; + config_mib->get_sib = get_sib; + config_mib->access_barred = barred; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); } else { LOG_E(NR_RRC, "RRC-received BCCH message is not a MIB\n"); ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, bcch_message); @@ -894,6 +1536,11 @@ static void nr_rrc_handle_msg3_indication(NR_UE_RRC_INST_t *rrc, rnti_t rnti) nr_rlc_reconfigure_entity(rrc->ue_id, lc_id, NULL); // resume SRB1 rrc->Srb[srb_id] = RB_ESTABLISHED; + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_RESUME_RB; + rrc_msg.payload.resume_rb.is_srb = true; + rrc_msg.payload.resume_rb.rb_id = 1; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); break; case DURING_HANDOVER: AssertFatal(1==0, "ra_trigger not implemented yet!\n"); @@ -924,7 +1571,9 @@ static void nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc, uint8_t *const Sdu, const uint8_t Sdu_len, const uint8_t rsrq, - const uint8_t rsrp) + const uint8_t rsrp, + int frame, + int slot) { NR_UE_RRC_SI_INFO *SI_info = &rrc->perNB[gNB_index].SInfo; SI_info->sib_pending = false; @@ -960,9 +1609,9 @@ static void nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc, bcch_message->message.choice.c1->choice.systemInformationBlockType1 = NULL; break; case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformation: - LOG_I(NR_RRC, "[UE %ld] Decoding SI\n", rrc->ue_id); + LOG_I(NR_RRC, "[UE %ld] %d:%d Decoding SI\n", rrc->ue_id, frame, slot); NR_SystemInformation_t *si = bcch_message->message.choice.c1->choice.systemInformation; - nr_decode_SI(SI_info, si, rrc); + nr_decode_SI(SI_info, si, rrc, frame); break; case NR_BCCH_DL_SCH_MessageType__c1_PR_NOTHING: default: @@ -980,8 +1629,7 @@ static void nr_rrc_signal_maxrtxindication(int ue_id) itti_send_msg_to_task(TASK_RRC_NRUE, ue_id, msg); } -static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, - const NR_CellGroupConfig_t *cellGroupConfig) +static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupConfig_t *cellGroupConfig) { if (cellGroupConfig->rlc_BearerToReleaseList != NULL) { for (int i = 0; i < cellGroupConfig->rlc_BearerToReleaseList->list.count; i++) { @@ -1019,7 +1667,9 @@ static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, } } -static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, NR_ReconfigurationWithSync_t *reconfigurationWithSync) +static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, + NR_ReconfigurationWithSync_t *reconfigurationWithSync, + int gNB_index) { // perform Reconfiguration with sync according to 5.3.5.5.2 if (!rrc->as_security_activated && !(get_softmodem_params()->phy_test || get_softmodem_params()->do_ra)) { @@ -1051,15 +1701,26 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, NR_Rec } rrc->rnti = reconfigurationWithSync->newUE_Identity; // reset the MAC entity of this cell group (done at MAC in handle_reconfiguration_with_sync) + + // 3GPP TS38.331 section 5.3.5.5.2 + nr_timer_stop(&tac->T430); + if (reconfigurationWithSync->spCellConfigCommon && + reconfigurationWithSync->spCellConfigCommon->ext2 && + reconfigurationWithSync->spCellConfigCommon->ext2->ntn_Config_r17) { + NR_NTN_Config_r17_t *ntncfg = reconfigurationWithSync->spCellConfigCommon->ext2->ntn_Config_r17; + // EPOCH time is always sent if NTN config is sent through DCCH + AssertFatal(ntncfg->epochTime_r17, "NTN-CONFIG sent in dedicated mode should have EPOCHTIME\n"); + nr_rrc_process_ntnconfig(rrc, &rrc->perNB[gNB_index].SInfo, ntncfg, rrc->current_frame); + } } -void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig) +void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig, int gNB_index) { NR_SpCellConfig_t *spCellConfig = cellGroupConfig->spCellConfig; if(spCellConfig) { if (spCellConfig->reconfigurationWithSync) { LOG_I(NR_RRC, "Processing reconfigurationWithSync\n"); - nr_rrc_process_reconfigurationWithSync(rrc, spCellConfig->reconfigurationWithSync); + nr_rrc_process_reconfigurationWithSync(rrc, spCellConfig->reconfigurationWithSync, gNB_index); } nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(rrc, spCellConfig->rlf_TimersAndConstants); if (spCellConfig->spCellConfigDedicated) { @@ -1079,32 +1740,6 @@ void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t AssertFatal(cellGroupConfig->sCellToAddModList == NULL, "Secondary serving cell addition not implemented\n"); } - -static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc, - OCTET_STRING_t *masterCellGroup, - long *fullConfig) -{ - AssertFatal(!fullConfig, "fullConfig not supported yet\n"); - NR_CellGroupConfig_t *cellGroupConfig = NULL; - uper_decode(NULL, - &asn_DEF_NR_CellGroupConfig, //might be added prefix later - (void **)&cellGroupConfig, - (uint8_t *)masterCellGroup->buf, - masterCellGroup->size, 0, 0); - - if (LOG_DEBUGFLAG(DEBUG_ASN1)) { - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); - } - - nr_rrc_cellgroup_configuration(rrc, cellGroupConfig); - - LOG_D(RRC, "Sending CellGroupConfig to MAC the pointer will be managed by mac\n"); - MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_CG); - NR_MAC_RRC_CONFIG_CG(msg).cellGroupConfig = cellGroupConfig; - NR_MAC_RRC_CONFIG_CG(msg).UE_NR_Capability = rrc->UECap.UE_NR_Capability; - itti_send_msg_to_task(TASK_MAC_UE, rrc->ue_id, msg); -} - static void rrc_ue_generate_RRCSetupComplete(const NR_UE_RRC_INST_t *rrc, const uint8_t Transaction_id) { uint8_t buffer[100]; @@ -1143,24 +1778,70 @@ static void rrc_ue_generate_RRCSetupComplete(const NR_UE_RRC_INST_t *rrc, const nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL); } +static void nr_rrc_rrcsetup_fallback(NR_UE_RRC_INST_t *rrc) +{ + LOG_W(NR_RRC, + "[UE %ld] Recived RRCSetup in response to %s request\n", + rrc->ue_id, rrc->ra_trigger == RRC_CONNECTION_REESTABLISHMENT ? "RRCReestablishment" : "RRCResume"); + + // discard any stored UE Inactive AS context and suspendConfig + // TODO + + // discard any current AS security context including + // K_RRCenc key, the K_RRCint key, the K_UPint key and the K_UPenc key + // TODO only kgnb is stored + memset(rrc->kgnb, 0, sizeof(rrc->kgnb)); + rrc->as_security_activated = false; + + // release radio resources for all established RBs except SRB0, + // including release of the RLC entities, of the associated PDCP entities and of SDAP + for (int i = 1; i <= MAX_DRBS_PER_UE; i++) { + if (get_DRB_status(rrc, i) != RB_NOT_PRESENT) { + set_DRB_status(rrc, i, RB_NOT_PRESENT); + nr_pdcp_release_drb(rrc->ue_id, i); + } + } + for (int i = 1; i < NR_NUM_SRB; i++) { + if (rrc->Srb[i] != RB_NOT_PRESENT) { + rrc->Srb[i] = RB_NOT_PRESENT; + nr_pdcp_release_srb(rrc->ue_id, i); + } + } + for (int i = 1; i < NR_MAX_NUM_LCID; i++) { + if (rrc->active_RLC_entity[i]) { + rrc->active_RLC_entity[i] = false; + nr_rlc_release_entity(rrc->ue_id, i); + } + } + nr_sdap_delete_ue_entities(rrc->ue_id); + + // release the RRC configuration except for the default L1 parameter values, + // default MAC Cell Group configuration and CCCH configuration + // TODO to be completed + NR_UE_MAC_reset_cause_t cause = RRC_SETUP_REESTAB_RESUME; + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_RESET; + rrc_msg.payload.config_reset.cause = cause; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); + + // indicate to upper layers fallback of the RRC connection + // TODO + + // stop timer T380, if running + // TODO not implemented yet +} + static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc, const NR_RRCSetup_t *rrcSetup) { // if the RRCSetup is received in response to an RRCReestablishmentRequest // or RRCResumeRequest or RRCResumeRequest1 - // TODO none of the procedures implemented yet - if (rrc->ra_trigger == RRC_CONNECTION_REESTABLISHMENT) { - LOG_E(NR_RRC, "Handling of RRCSetup in response of RRCReestablishment not implemented yet. Going back to IDLE.\n"); - nr_rrc_going_to_IDLE(rrc, OTHER, NULL); - return; - } + if (rrc->ra_trigger == RRC_CONNECTION_REESTABLISHMENT || rrc->ra_trigger == RRC_RESUME_REQUEST) + nr_rrc_rrcsetup_fallback(rrc); // perform the cell group configuration procedure in accordance with the received masterCellGroup - nr_rrc_ue_process_masterCellGroup(rrc, - &rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup, - NULL); + nr_rrc_ue_process_masterCellGroup(rrc, &rrcSetup->criticalExtensions.choice.rrcSetup->masterCellGroup, NULL, 0); // perform the radio bearer configuration procedure in accordance with the received radioBearerConfig - nr_rrc_ue_process_RadioBearerConfig(rrc, - &rrcSetup->criticalExtensions.choice.rrcSetup->radioBearerConfig); + nr_rrc_ue_process_RadioBearerConfig(rrc, &rrcSetup->criticalExtensions.choice.rrcSetup->radioBearerConfig); // TODO (not handled) if stored, discard the cell reselection priority information provided by // the cellReselectionPriorities or inherited from another RAT @@ -1172,7 +1853,11 @@ static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc, const NR_RRCSetup_t * nr_timer_stop(&timers->T319); nr_timer_stop(&timers->T320); - // TODO if T390 and T302 are running (not implemented) + // if T390 (not implemented) and T302 are running + // stop timer + // perform the actions as specified in 5.3.14.4 + nr_timer_stop(&timers->T302); + handle_302_expired_stopped(rrc); // if the RRCSetup is received in response to an RRCResumeRequest, RRCResumeRequest1 or RRCSetupRequest // enter RRC_CONNECTED @@ -1182,13 +1867,54 @@ static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc, const NR_RRCSetup_t * MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_NAS_CONN_ESTABLISH_IND); itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, msg_p); + // resetting the RA trigger state after receiving MSG4 with RRCSetup + rrc->ra_trigger = RA_NOT_RUNNING; + // set the content of RRCSetupComplete message // TODO procedues described in 5.3.3.4 seems more complex than what we actualy do rrc_ue_generate_RRCSetupComplete(rrc, rrcSetup->rrc_TransactionIdentifier); } -static int8_t nr_rrc_ue_decode_ccch(NR_UE_RRC_INST_t *rrc, - const NRRrcMacCcchDataInd *ind) +static void nr_rrc_process_rrcreject(NR_UE_RRC_INST_t *rrc, const NR_RRCReject_t *rrcReject) +{ + // stop timer T300, T302, T319 if running; + NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; + nr_timer_stop(&timers->T300); + nr_timer_stop(&timers->T302); + nr_timer_stop(&timers->T319); + + // reset MAC and release the default MAC Cell Group configuration + NR_UE_MAC_reset_cause_t cause = REJECT; + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_RESET; + rrc_msg.payload.config_reset.cause = cause; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); + + // if waitTime is configured in the RRCReject: start timer T302, with the timer value set to the waitTime + NR_RejectWaitTime_t *waitTime = NULL; + if (rrcReject->criticalExtensions.present == NR_RRCReject__criticalExtensions_PR_rrcReject) { + NR_RRCReject_IEs_t *ies = rrcReject->criticalExtensions.choice.rrcReject; + waitTime = ies->waitTime; // Wait time value in seconds + } + if (waitTime) { + nr_timer_setup(&timers->T302, *waitTime * 1000, 10); + nr_timer_start(&timers->T302); + rrc->access_barred = true; + } else { + LOG_W(RRC, "Error: waitTime should be always included in RRCReject message\n"); + } + + // TODO if RRCReject is received in response to a request from upper layers + // inform the upper layer that access barring is applicable for all access categories except categories '0' and '2' + + // TODO if RRCReject is received in response to an RRCSetupRequest + // inform upper layers about the failure to setup the RRC connection, upon which the procedure ends + + // TODO else if RRCReject is received in response to an RRCResumeRequest or an RRCResumeRequest1 + // Resume not implemented yet +} + +static int8_t nr_rrc_ue_decode_ccch(NR_UE_RRC_INST_t *rrc, const NRRrcMacCcchDataInd *ind) { NR_DL_CCCH_Message_t *dl_ccch_msg = NULL; asn_dec_rval_t dec_rval; @@ -1215,7 +1941,8 @@ static int8_t nr_rrc_ue_decode_ccch(NR_UE_RRC_INST_t *rrc, break; case NR_DL_CCCH_MessageType__c1_PR_rrcReject: - LOG_I(NR_RRC, "[UE%ld] Logical Channel DL-CCCH (SRB0), Received RRCReject \n", rrc->ue_id); + LOG_W(NR_RRC, "[UE%ld] Logical Channel DL-CCCH (SRB0), Received RRCReject \n", rrc->ue_id); + nr_rrc_process_rrcreject(rrc, dl_ccch_msg->message.choice.c1->choice.rrcReject); rval = 0; break; @@ -1378,385 +2105,6 @@ static void nr_rrc_ue_process_securityModeCommand(NR_UE_RRC_INST_t *ue_rrc, } } -static void handle_meas_reporting_remove(rrcPerNB_t *rrc, int id, NR_UE_Timers_Constants_t *timers) -{ - // remove the measurement reporting entry for this measId if included - asn1cFreeStruc(asn_DEF_NR_VarMeasReport, rrc->MeasReport[id]); - // TODO stop the periodical reporting timer or timer T321, whichever is running, - // and reset the associated information (e.g. timeToTrigger) for this measId - nr_timer_stop(&timers->T321); -} - -static void handle_measobj_remove(rrcPerNB_t *rrc, struct NR_MeasObjectToRemoveList *remove_list, NR_UE_Timers_Constants_t *timers) -{ - // section 5.5.2.4 in 38.331 - for (int i = 0; i < remove_list->list.count; i++) { - // for each measObjectId included in the received measObjectToRemoveList - // that is part of measObjectList in the configuration - NR_MeasObjectId_t id = *remove_list->list.array[i]; - if (rrc->MeasObj[id - 1]) { - // remove the entry with the matching measObjectId from the measObjectList - asn1cFreeStruc(asn_DEF_NR_MeasObjectToAddMod, rrc->MeasObj[id - 1]); - // remove all measId associated with this measObjectId from the measIdList - for (int j = 0; j < MAX_MEAS_ID; j++) { - if (rrc->MeasId[j] && rrc->MeasId[j]->measObjectId == id) { - asn1cFreeStruc(asn_DEF_NR_MeasIdToAddMod, rrc->MeasId[j]); - handle_meas_reporting_remove(rrc, j, timers); - } - } - } - } -} - -static void update_ssb_configmob(NR_SSB_ConfigMobility_t *source, NR_SSB_ConfigMobility_t *target) -{ - if (source->ssb_ToMeasure) - HANDLE_SETUPRELEASE_IE(target->ssb_ToMeasure, source->ssb_ToMeasure, NR_SSB_ToMeasure_t, asn_DEF_NR_SSB_ToMeasure); - target->deriveSSB_IndexFromCell = source->deriveSSB_IndexFromCell; - if (source->ss_RSSI_Measurement) - UPDATE_IE(target->ss_RSSI_Measurement, source->ss_RSSI_Measurement, NR_SS_RSSI_Measurement_t); -} - -static void update_nr_measobj(NR_MeasObjectNR_t *source, NR_MeasObjectNR_t *target) -{ - UPDATE_IE(target->ssbFrequency, source->ssbFrequency, NR_ARFCN_ValueNR_t); - UPDATE_IE(target->ssbSubcarrierSpacing, source->ssbSubcarrierSpacing, NR_SubcarrierSpacing_t); - UPDATE_IE(target->smtc1, source->smtc1, NR_SSB_MTC_t); - if (source->smtc2) { - target->smtc2->periodicity = source->smtc2->periodicity; - if (source->smtc2->pci_List) - UPDATE_IE(target->smtc2->pci_List, source->smtc2->pci_List, struct NR_SSB_MTC2__pci_List); - } - else - asn1cFreeStruc(asn_DEF_NR_SSB_MTC2, target->smtc2); - UPDATE_IE(target->refFreqCSI_RS, source->refFreqCSI_RS, NR_ARFCN_ValueNR_t); - if (source->referenceSignalConfig.ssb_ConfigMobility) - update_ssb_configmob(source->referenceSignalConfig.ssb_ConfigMobility, target->referenceSignalConfig.ssb_ConfigMobility); - UPDATE_IE(target->absThreshSS_BlocksConsolidation, source->absThreshSS_BlocksConsolidation, NR_ThresholdNR_t); - UPDATE_IE(target->absThreshCSI_RS_Consolidation, source->absThreshCSI_RS_Consolidation, NR_ThresholdNR_t); - UPDATE_IE(target->nrofSS_BlocksToAverage, source->nrofSS_BlocksToAverage, long); - UPDATE_IE(target->nrofCSI_RS_ResourcesToAverage, source->nrofCSI_RS_ResourcesToAverage, long); - target->quantityConfigIndex = source->quantityConfigIndex; - target->offsetMO = source->offsetMO; - if (source->cellsToRemoveList) { - RELEASE_IE_FROMLIST(source->cellsToRemoveList, target->cellsToAddModList, physCellId); - } - if (source->cellsToAddModList) { - if (!target->cellsToAddModList) - target->cellsToAddModList = calloc(1, sizeof(*target->cellsToAddModList)); - ADDMOD_IE_FROMLIST(source->cellsToAddModList, target->cellsToAddModList, physCellId, NR_CellsToAddMod_t); - } - if (source->excludedCellsToRemoveList) { - RELEASE_IE_FROMLIST(source->excludedCellsToRemoveList, target->excludedCellsToAddModList, pci_RangeIndex); - } - if (source->excludedCellsToAddModList) { - if (!target->excludedCellsToAddModList) - target->excludedCellsToAddModList = calloc(1, sizeof(*target->excludedCellsToAddModList)); - ADDMOD_IE_FROMLIST(source->excludedCellsToAddModList, target->excludedCellsToAddModList, pci_RangeIndex, NR_PCI_RangeElement_t); - } - if (source->allowedCellsToRemoveList) { - RELEASE_IE_FROMLIST(source->allowedCellsToRemoveList, target->allowedCellsToAddModList, pci_RangeIndex); - } - if (source->allowedCellsToAddModList) { - if (!target->allowedCellsToAddModList) - target->allowedCellsToAddModList = calloc(1, sizeof(*target->allowedCellsToAddModList)); - ADDMOD_IE_FROMLIST(source->allowedCellsToAddModList, target->allowedCellsToAddModList, pci_RangeIndex, NR_PCI_RangeElement_t); - } - if (source->ext1) { - UPDATE_IE(target->ext1->freqBandIndicatorNR, source->ext1->freqBandIndicatorNR, NR_FreqBandIndicatorNR_t); - UPDATE_IE(target->ext1->measCycleSCell, source->ext1->measCycleSCell, long); - } -} - -static void handle_measobj_addmod(rrcPerNB_t *rrc, struct NR_MeasObjectToAddModList *addmod_list) -{ - // section 5.5.2.5 in 38.331 - for (int i = 0; i < addmod_list->list.count; i++) { - NR_MeasObjectToAddMod_t *measObj = addmod_list->list.array[i]; - if (measObj->measObject.present != NR_MeasObjectToAddMod__measObject_PR_measObjectNR) { - LOG_E(NR_RRC, "Cannot handle MeasObjt other than NR\n"); - continue; - } - NR_MeasObjectId_t id = measObj->measObjectId; - if (rrc->MeasObj[id]) { - update_nr_measobj(measObj->measObject.choice.measObjectNR, rrc->MeasObj[id]->measObject.choice.measObjectNR); - } - else { - // add a new entry for the received measObject to the measObjectList - UPDATE_IE(rrc->MeasObj[id], addmod_list->list.array[i], NR_MeasObjectToAddMod_t); - } - } -} - -static void handle_reportconfig_remove(rrcPerNB_t *rrc, - struct NR_ReportConfigToRemoveList *remove_list, - NR_UE_Timers_Constants_t *timers) -{ - for (int i = 0; i < remove_list->list.count; i++) { - NR_ReportConfigId_t id = *remove_list->list.array[i]; - // remove the entry with the matching reportConfigId from the reportConfigList - asn1cFreeStruc(asn_DEF_NR_ReportConfigToAddMod, rrc->ReportConfig[id]); - for (int j = 0; j < MAX_MEAS_ID; j++) { - if (rrc->MeasId[j] && rrc->MeasId[j]->reportConfigId == id) { - // remove all measId associated with the reportConfigId from the measIdList - asn1cFreeStruc(asn_DEF_NR_MeasIdToAddMod, rrc->MeasId[j]); - handle_meas_reporting_remove(rrc, j, timers); - } - } - } -} - -static void handle_reportconfig_addmod(rrcPerNB_t *rrc, - struct NR_ReportConfigToAddModList *addmod_list, - NR_UE_Timers_Constants_t *timers) -{ - for (int i = 0; i < addmod_list->list.count; i++) { - NR_ReportConfigToAddMod_t *rep = addmod_list->list.array[i]; - if (rep->reportConfig.present != NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR) { - LOG_E(NR_RRC, "Cannot handle reportConfig type other than NR\n"); - continue; - } - NR_ReportConfigId_t id = rep->reportConfigId; - if (rrc->ReportConfig[id]) { - for (int j = 0; j < MAX_MEAS_ID; j++) { - // for each measId associated with this reportConfigId included in the measIdList - if (rrc->MeasId[j] && rrc->MeasId[j]->reportConfigId == id) - handle_meas_reporting_remove(rrc, j, timers); - } - } - UPDATE_IE(rrc->ReportConfig[id], addmod_list->list.array[i], NR_ReportConfigToAddMod_t); - } -} - -static void handle_quantityconfig(rrcPerNB_t *rrc, NR_QuantityConfig_t *quantityConfig, NR_UE_Timers_Constants_t *timers) -{ - if (quantityConfig->quantityConfigNR_List) { - for (int i = 0; i < quantityConfig->quantityConfigNR_List->list.count; i++) { - NR_QuantityConfigNR_t *quantityNR = quantityConfig->quantityConfigNR_List->list.array[i]; - if (!rrc->QuantityConfig[i]) - rrc->QuantityConfig[i] = calloc(1, sizeof(*rrc->QuantityConfig[i])); - rrc->QuantityConfig[i]->quantityConfigCell = quantityNR->quantityConfigCell; - if (quantityNR->quantityConfigRS_Index) - UPDATE_IE(rrc->QuantityConfig[i]->quantityConfigRS_Index, quantityNR->quantityConfigRS_Index, struct NR_QuantityConfigRS); - } - } - for (int j = 0; j < MAX_MEAS_ID; j++) { - // for each measId included in the measIdList - if (rrc->MeasId[j]) - handle_meas_reporting_remove(rrc, j, timers); - } -} - -static void handle_measid_remove(rrcPerNB_t *rrc, struct NR_MeasIdToRemoveList *remove_list, NR_UE_Timers_Constants_t *timers) -{ - for (int i = 0; i < remove_list->list.count; i++) { - NR_MeasId_t id = *remove_list->list.array[i]; - if (rrc->MeasId[id]) { - asn1cFreeStruc(asn_DEF_NR_MeasIdToAddMod, rrc->MeasId[id]); - handle_meas_reporting_remove(rrc, id, timers); - } - } -} - -static void handle_measid_addmod(rrcPerNB_t *rrc, struct NR_MeasIdToAddModList *addmod_list, NR_UE_Timers_Constants_t *timers) -{ - for (int i = 0; i < addmod_list->list.count; i++) { - NR_MeasId_t id = addmod_list->list.array[i]->measId; - NR_ReportConfigId_t reportId = addmod_list->list.array[i]->reportConfigId; - NR_MeasObjectId_t measObjectId = addmod_list->list.array[i]->measObjectId; - UPDATE_IE(rrc->MeasId[id], addmod_list->list.array[i], NR_MeasIdToAddMod_t); - handle_meas_reporting_remove(rrc, id, timers); - if (rrc->ReportConfig[reportId]) { - NR_ReportConfigToAddMod_t *report = rrc->ReportConfig[reportId]; - AssertFatal(report->reportConfig.present == NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR, - "Only NR config report is supported\n"); - NR_ReportConfigNR_t *reportNR = report->reportConfig.choice.reportConfigNR; - // if the reportType is set to reportCGI in the reportConfig associated with this measId - if (reportNR->reportType.present == NR_ReportConfigNR__reportType_PR_reportCGI) { - if (rrc->MeasObj[measObjectId]) { - if (rrc->MeasObj[measObjectId]->measObject.present == NR_MeasObjectToAddMod__measObject_PR_measObjectNR) { - NR_MeasObjectNR_t *obj_nr = rrc->MeasObj[measObjectId]->measObject.choice.measObjectNR; - NR_ARFCN_ValueNR_t freq = 0; - if (obj_nr->ssbFrequency) - freq = *obj_nr->ssbFrequency; - else if (obj_nr->refFreqCSI_RS) - freq = *obj_nr->refFreqCSI_RS; - AssertFatal(freq > 0, "Invalid ARFCN frequency for this measurement object\n"); - if (get_freq_range_from_arfcn(freq) == FR2) - nr_timer_setup(&timers->T321, 16000, 10); // 16 seconds for FR2 - else - nr_timer_setup(&timers->T321, 2000, 10); // 2 seconds for FR1 - } - else // EUTRA - nr_timer_setup(&timers->T321, 1000, 10); // 1 second for EUTRA - nr_timer_start(&timers->T321); - } - } - } - } -} - -static void nr_rrc_ue_process_measConfig(rrcPerNB_t *rrc, NR_MeasConfig_t *const measConfig, NR_UE_Timers_Constants_t *timers) -{ - if (measConfig->measObjectToRemoveList) - handle_measobj_remove(rrc, measConfig->measObjectToRemoveList, timers); - - if (measConfig->measObjectToAddModList) - handle_measobj_addmod(rrc, measConfig->measObjectToAddModList); - - if (measConfig->reportConfigToRemoveList) - handle_reportconfig_remove(rrc, measConfig->reportConfigToRemoveList, timers); - - if (measConfig->reportConfigToAddModList) - handle_reportconfig_addmod(rrc, measConfig->reportConfigToAddModList, timers); - - if (measConfig->quantityConfig) - handle_quantityconfig(rrc, measConfig->quantityConfig, timers); - - if (measConfig->measIdToRemoveList) - handle_measid_remove(rrc, measConfig->measIdToRemoveList, timers); - - if (measConfig->measIdToAddModList) - handle_measid_addmod(rrc, measConfig->measIdToAddModList, timers); - - AssertFatal(!measConfig->measGapConfig, "Measurement gaps not yet supported\n"); - AssertFatal(!measConfig->measGapSharingConfig, "Measurement gaps not yet supported\n"); - - if (measConfig->s_MeasureConfig) { - if (measConfig->s_MeasureConfig->present == NR_MeasConfig__s_MeasureConfig_PR_ssb_RSRP) { - rrc->s_measure = measConfig->s_MeasureConfig->choice.ssb_RSRP; - } else if (measConfig->s_MeasureConfig->present == NR_MeasConfig__s_MeasureConfig_PR_csi_RSRP) { - rrc->s_measure = measConfig->s_MeasureConfig->choice.csi_RSRP; - } - } -} - -/** - * @brief add, modify and release SRBs and/or DRBs - * @ref 3GPP TS 38.331 - */ -static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc, - NR_RadioBearerConfig_t *const radioBearerConfig) -{ - if (LOG_DEBUGFLAG(DEBUG_ASN1)) - xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void *)radioBearerConfig); - - if (radioBearerConfig->srb3_ToRelease) { - nr_pdcp_release_srb(ue_rrc->ue_id, 3); - ue_rrc->Srb[3] = RB_NOT_PRESENT; - } - - nr_pdcp_entity_security_keys_and_algos_t security_rrc_parameters = {0}; - nr_pdcp_entity_security_keys_and_algos_t security_up_parameters = {0}; - - if (ue_rrc->as_security_activated) { - if (radioBearerConfig->securityConfig != NULL) { - // When the field is not included, continue to use the currently configured keyToUse - if (radioBearerConfig->securityConfig->keyToUse) { - AssertFatal(*radioBearerConfig->securityConfig->keyToUse == NR_SecurityConfig__keyToUse_master, - "Secondary key usage seems not to be implemented\n"); - ue_rrc->keyToUse = *radioBearerConfig->securityConfig->keyToUse; - } - // When the field is not included, continue to use the currently configured security algorithm - if (radioBearerConfig->securityConfig->securityAlgorithmConfig) { - ue_rrc->cipheringAlgorithm = radioBearerConfig->securityConfig->securityAlgorithmConfig->cipheringAlgorithm; - ue_rrc->integrityProtAlgorithm = *radioBearerConfig->securityConfig->securityAlgorithmConfig->integrityProtAlgorithm; - } - } - security_rrc_parameters.ciphering_algorithm = ue_rrc->cipheringAlgorithm; - security_rrc_parameters.integrity_algorithm = ue_rrc->integrityProtAlgorithm; - nr_derive_key(RRC_ENC_ALG, ue_rrc->cipheringAlgorithm, ue_rrc->kgnb, security_rrc_parameters.ciphering_key); - nr_derive_key(RRC_INT_ALG, ue_rrc->integrityProtAlgorithm, ue_rrc->kgnb, security_rrc_parameters.integrity_key); - security_up_parameters.ciphering_algorithm = ue_rrc->cipheringAlgorithm; - security_up_parameters.integrity_algorithm = ue_rrc->integrityProtAlgorithm; - nr_derive_key(UP_ENC_ALG, ue_rrc->cipheringAlgorithm, ue_rrc->kgnb, security_up_parameters.ciphering_key); - nr_derive_key(UP_INT_ALG, ue_rrc->integrityProtAlgorithm, ue_rrc->kgnb, security_up_parameters.integrity_key); - } - - if (radioBearerConfig->srb_ToAddModList != NULL) { - for (int cnt = 0; cnt < radioBearerConfig->srb_ToAddModList->list.count; cnt++) { - struct NR_SRB_ToAddMod *srb = radioBearerConfig->srb_ToAddModList->list.array[cnt]; - if (ue_rrc->Srb[srb->srb_Identity] == RB_NOT_PRESENT) { - ue_rrc->Srb[srb->srb_Identity] = RB_ESTABLISHED; - add_srb(false, - ue_rrc->ue_id, - radioBearerConfig->srb_ToAddModList->list.array[cnt], - &security_rrc_parameters); - } - else { - AssertFatal(srb->discardOnPDCP == NULL, "discardOnPDCP not yet implemented\n"); - if (srb->reestablishPDCP) { - ue_rrc->Srb[srb->srb_Identity] = RB_ESTABLISHED; - nr_pdcp_reestablishment(ue_rrc->ue_id, - srb->srb_Identity, - true, - &security_rrc_parameters); - } - if (srb->pdcp_Config && srb->pdcp_Config->t_Reordering) - nr_pdcp_reconfigure_srb(ue_rrc->ue_id, srb->srb_Identity, *srb->pdcp_Config->t_Reordering); - } - } - } - - if (radioBearerConfig->drb_ToReleaseList) { - for (int cnt = 0; cnt < radioBearerConfig->drb_ToReleaseList->list.count; cnt++) { - NR_DRB_Identity_t *DRB_id = radioBearerConfig->drb_ToReleaseList->list.array[cnt]; - if (DRB_id) { - nr_pdcp_release_drb(ue_rrc->ue_id, *DRB_id); - set_DRB_status(ue_rrc, *DRB_id, RB_NOT_PRESENT); - } - } - } - - /** - * Establish/reconfig DRBs if DRB-ToAddMod is present - * according to 3GPP TS 38.331 clause 5.3.5.6.5 DRB addition/modification - */ - if (radioBearerConfig->drb_ToAddModList != NULL) { - for (int cnt = 0; cnt < radioBearerConfig->drb_ToAddModList->list.count; cnt++) { - struct NR_DRB_ToAddMod *drb = radioBearerConfig->drb_ToAddModList->list.array[cnt]; - int DRB_id = drb->drb_Identity; - if (get_DRB_status(ue_rrc, DRB_id) != RB_NOT_PRESENT) { - if (drb->reestablishPDCP) { - set_DRB_status(ue_rrc, DRB_id, RB_ESTABLISHED); - /* get integrity and cipehring settings from radioBearerConfig */ - bool has_integrity = drb->pdcp_Config != NULL - && drb->pdcp_Config->drb != NULL - && drb->pdcp_Config->drb->integrityProtection != NULL; - bool has_ciphering = !(drb->pdcp_Config != NULL - && drb->pdcp_Config->ext1 != NULL - && drb->pdcp_Config->ext1->cipheringDisabled != NULL); - security_up_parameters.ciphering_algorithm = has_ciphering ? ue_rrc->cipheringAlgorithm : 0; - security_up_parameters.integrity_algorithm = has_integrity ? ue_rrc->integrityProtAlgorithm : 0; - /* re-establish */ - nr_pdcp_reestablishment(ue_rrc->ue_id, - DRB_id, - false, - &security_up_parameters); - } - AssertFatal(drb->recoverPDCP == NULL, "recoverPDCP not yet implemented\n"); - /* sdap-Config is included (SA mode) */ - NR_SDAP_Config_t *sdap_Config = drb->cnAssociation ? drb->cnAssociation->choice.sdap_Config : NULL; - /* PDCP reconfiguration */ - if (drb->pdcp_Config) - nr_pdcp_reconfigure_drb(ue_rrc->ue_id, DRB_id, drb->pdcp_Config); - /* SDAP entity reconfiguration */ - if (sdap_Config) - nr_reconfigure_sdap_entity(sdap_Config, ue_rrc->ue_id, sdap_Config->pdu_Session, DRB_id); - } else { - set_DRB_status(ue_rrc ,DRB_id, RB_ESTABLISHED); - add_drb(false, - ue_rrc->ue_id, - radioBearerConfig->drb_ToAddModList->list.array[cnt], - &security_up_parameters); - } - } - } // drb_ToAddModList // - - ue_rrc->nrRrcState = RRC_STATE_CONNECTED_NR; - LOG_I(NR_RRC, "State = NR_RRC_CONNECTED\n"); -} - static void nr_rrc_ue_generate_RRCReconfigurationComplete(NR_UE_RRC_INST_t *rrc, const int srb_id, const uint8_t Transaction_id) { uint8_t buffer[32]; @@ -1771,6 +2119,16 @@ static void nr_rrc_ue_generate_RRCReconfigurationComplete(NR_UE_RRC_INST_t *rrc, nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL); } +static void nr_rrc_ue_generate_rrcReestablishmentComplete(const NR_UE_RRC_INST_t *rrc, + const NR_RRCReestablishment_t *rrcReestablishment) +{ + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; + int size = do_RRCReestablishmentComplete(buffer, NR_RRC_BUF_SIZE, rrcReestablishment->rrc_TransactionIdentifier); + LOG_I(NR_RRC, "[RAPROC] Logical Channel UL-DCCH (SRB1), Generating RRCReestablishmentComplete (bytes %d)\n", size); + int srb_id = 1; // RRC re-establishment complete on SRB1 + nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL); +} + static void nr_rrc_ue_process_rrcReestablishment(NR_UE_RRC_INST_t *rrc, const int gNB_index, const NR_RRCReestablishment_t *rrcReestablishment, @@ -1830,6 +2188,69 @@ static void nr_rrc_ue_process_rrcReestablishment(NR_UE_RRC_INST_t *rrc, nr_rrc_ue_generate_rrcReestablishmentComplete(rrc, rrcReestablishment); } +static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECapabilityEnquiry_t *UECapabilityEnquiry) +{ + NR_UL_DCCH_Message_t ul_dcch_msg = {0}; + LOG_I(NR_RRC, "Receiving from SRB1 (DL-DCCH), Processing UECapabilityEnquiry\n"); + + ul_dcch_msg.message.present = NR_UL_DCCH_MessageType_PR_c1; + asn1cCalloc(ul_dcch_msg.message.choice.c1, c1); + c1->present = NR_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation; + asn1cCalloc(c1->choice.ueCapabilityInformation, info); + info->rrc_TransactionIdentifier = UECapabilityEnquiry->rrc_TransactionIdentifier; + if (!rrc->UECap.UE_NR_Capability) { + rrc->UECap.UE_NR_Capability = CALLOC(1, sizeof(NR_UE_NR_Capability_t)); + asn1cSequenceAdd(rrc->UECap.UE_NR_Capability->rf_Parameters.supportedBandListNR.list, NR_BandNR_t, nr_bandnr); + nr_bandnr->bandNR = 1; + } + xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, (void *)rrc->UECap.UE_NR_Capability); + + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UE_NR_Capability, + NULL, + (void *)rrc->UECap.UE_NR_Capability, + &rrc->UECap.sdu[0], + MAX_UE_NR_CAPABILITY_SIZE); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + rrc->UECap.sdu_size = (enc_rval.encoded + 7) / 8; + LOG_I(PHY, "[RRC]UE NR Capability encoded, %d bytes (%zd bits)\n", rrc->UECap.sdu_size, enc_rval.encoded + 7); + /* RAT Container */ + NR_UE_CapabilityRAT_Container_t *ue_CapabilityRAT_Container = CALLOC(1, sizeof(NR_UE_CapabilityRAT_Container_t)); + ue_CapabilityRAT_Container->rat_Type = NR_RAT_Type_nr; + OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container->ue_CapabilityRAT_Container, (const char *)rrc->UECap.sdu, rrc->UECap.sdu_size); + NR_UECapabilityEnquiry_IEs_t *ueCapabilityEnquiry_ie = UECapabilityEnquiry->criticalExtensions.choice.ueCapabilityEnquiry; + // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.buf = UE_rrc_inst[ue_mod_idP].UECapability; + // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.size = UE_rrc_inst[ue_mod_idP].UECapability_size; + AssertFatal(UECapabilityEnquiry->criticalExtensions.present == NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry, + "UECapabilityEnquiry->criticalExtensions.present (%d) != UECapabilityEnquiry__criticalExtensions_PR_c1 (%d)\n", + UECapabilityEnquiry->criticalExtensions.present,NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry); + + NR_UECapabilityInformation_t *ueCapabilityInformation = ul_dcch_msg.message.choice.c1->choice.ueCapabilityInformation; + ueCapabilityInformation->criticalExtensions.present = NR_UECapabilityInformation__criticalExtensions_PR_ueCapabilityInformation; + asn1cCalloc(ueCapabilityInformation->criticalExtensions.choice.ueCapabilityInformation, infoIE); + asn1cCalloc(infoIE->ue_CapabilityRAT_ContainerList, UEcapList); + UEcapList->list.count = 0; + + for (int i = 0; i < ueCapabilityEnquiry_ie->ue_CapabilityRAT_RequestList.list.count; i++) { + if (ueCapabilityEnquiry_ie->ue_CapabilityRAT_RequestList.list.array[i]->rat_Type == NR_RAT_Type_nr) { + asn1cSeqAdd(&UEcapList->list, ue_CapabilityRAT_Container); + uint8_t buffer[500]; + asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, NULL, (void *)&ul_dcch_msg, buffer, 500); + AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg); + } + LOG_I(NR_RRC, "UECapabilityInformation Encoded %zd bits (%zd bytes)\n", enc_rval.encoded, (enc_rval.encoded + 7) / 8); + int srb_id = 1; // UECapabilityInformation on SRB1 + nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, (enc_rval.encoded + 7) / 8, buffer, deliver_pdu_srb_rlc, NULL); + } + } + /* Free struct members after it's done + including locally allocated ue_CapabilityRAT_Container */ + ASN_STRUCT_RESET(asn_DEF_NR_UL_DCCH_Message, &ul_dcch_msg); +} + + static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc, const srb_id_t Srb_id, const uint8_t *const Buffer, @@ -1868,11 +2289,23 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc, if (rrc->reconfig_after_reestab) { // if this is the first RRCReconfiguration message after successful completion of the RRC re-establishment procedure // resume SRB2 and DRBs that are suspended - if (rrc->Srb[2] == RB_SUSPENDED) + if (rrc->Srb[2] == RB_SUSPENDED) { rrc->Srb[2] = RB_ESTABLISHED; + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_RESUME_RB; + rrc_msg.payload.resume_rb.is_srb = true; + rrc_msg.payload.resume_rb.rb_id = 2; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); + } for (int i = 1; i <= MAX_DRBS_PER_UE; i++) { - if (get_DRB_status(rrc, i) == RB_SUSPENDED) + if (get_DRB_status(rrc, i) == RB_SUSPENDED) { set_DRB_status(rrc, i, RB_ESTABLISHED); + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_RESUME_RB; + rrc_msg.payload.resume_rb.is_srb = true; + rrc_msg.payload.resume_rb.rb_id = i; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); + } } rrc->reconfig_after_reestab = false; } @@ -1907,22 +2340,21 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc, break; case NR_DL_DCCH_MessageType__c1_PR_dlInformationTransfer: { - NR_DLInformationTransfer_t *dlInformationTransfer = c1->choice.dlInformationTransfer; + NR_DLInformationTransfer_t *dlInfo = c1->choice.dlInformationTransfer; - if (dlInformationTransfer->criticalExtensions.present - == NR_DLInformationTransfer__criticalExtensions_PR_dlInformationTransfer) { + if (dlInfo->criticalExtensions.present == NR_DLInformationTransfer__criticalExtensions_PR_dlInformationTransfer) { + NR_DLInformationTransfer_IEs_t *dlInfo_IE = dlInfo->criticalExtensions.choice.dlInformationTransfer; /* This message hold a dedicated info NAS payload, forward it to NAS */ - NR_DedicatedNAS_Message_t *dedicatedNAS_Message = - dlInformationTransfer->criticalExtensions.choice.dlInformationTransfer->dedicatedNAS_Message; - - MessageDef *ittiMsg = itti_alloc_new_message(TASK_RRC_NRUE, rrc->ue_id, NAS_DOWNLINK_DATA_IND); - dl_info_transfer_ind_t *msg = &NAS_DOWNLINK_DATA_IND(ittiMsg); - msg->UEid = rrc->ue_id; - msg->nasMsg.length = dedicatedNAS_Message->size; - msg->nasMsg.nas_data = malloc(msg->nasMsg.length); - memcpy(msg->nasMsg.nas_data, dedicatedNAS_Message->buf, msg->nasMsg.length); - itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, ittiMsg); - dedicatedNAS_Message->buf = NULL; // to keep the buffer, up to NAS to free it + NR_DedicatedNAS_Message_t *dedicatedNAS_Message = dlInfo_IE->dedicatedNAS_Message; + if (dedicatedNAS_Message) { + MessageDef *ittiMsg = itti_alloc_new_message(TASK_RRC_NRUE, rrc->ue_id, NAS_DOWNLINK_DATA_IND); + dl_info_transfer_ind_t *msg = &NAS_DOWNLINK_DATA_IND(ittiMsg); + msg->UEid = rrc->ue_id; + msg->nasMsg.length = dedicatedNAS_Message->size; + msg->nasMsg.nas_data = malloc(msg->nasMsg.length); + memcpy(msg->nasMsg.nas_data, dedicatedNAS_Message->buf, msg->nasMsg.length); + itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, ittiMsg); + } } } break; case NR_DL_DCCH_MessageType__c1_PR_mobilityFromNRCommand: @@ -1949,6 +2381,146 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc, return 0; } +static void apply_ema(val_init_t *vi_rsrp_dBm, float filter_coeff_rsrp, int rsrp_dBm) +{ + int *quant = &vi_rsrp_dBm->val; + bool *meas_init = &vi_rsrp_dBm->init; + float coef = *meas_init ? filter_coeff_rsrp : 1.0f; // if not init, first measurement gets full weight + *quant = (1.0f - coef) * (*quant) + coef * rsrp_dBm; + *meas_init = true; +} + +void nr_ue_meas_filtering(rrcPerNB_t *rrc, bool is_neighboring_cell, uint16_t Nid_cell, bool csi_meas, int rsrp_dBm) +{ + if (is_neighboring_cell) + return; + + l3_measurements_t *l3_measurements = &rrc->l3_measurements; + meas_t *meas_cell = &l3_measurements->serving_cell; + if (meas_cell->Nid_cell != Nid_cell) { + meas_cell->ss_rsrp_dBm.init = false; + meas_cell->csi_rsrp_dBm.init = false; + } + meas_cell->Nid_cell = Nid_cell; + + if (csi_meas) + apply_ema(&meas_cell->csi_rsrp_dBm, l3_measurements->csi_RS_filter_coeff_rsrp, rsrp_dBm); + else + apply_ema(&meas_cell->ss_rsrp_dBm, l3_measurements->ssb_filter_coeff_rsrp, rsrp_dBm); +} + +static long get_measurement_report_interval_ms(NR_ReportInterval_t interval) +{ + switch (interval) { + case NR_ReportInterval_ms120: + return 120; + case NR_ReportInterval_ms240: + return 240; + case NR_ReportInterval_ms480: + return 480; + case NR_ReportInterval_ms640: + return 640; + case NR_ReportInterval_ms1024: + return 1024; + case NR_ReportInterval_ms2048: + return 2048; + case NR_ReportInterval_ms5120: + return 5120; + case NR_ReportInterval_ms10240: + return 10240; + case NR_ReportInterval_min1: + return 60000; + case NR_ReportInterval_min6: + return 360000; + case NR_ReportInterval_min12: + return 720000; + case NR_ReportInterval_min30: + return 1800000; + default: + return 1024; + } +} + +static void nr_ue_check_meas_report(NR_UE_RRC_INST_t *rrc, const uint8_t gnb_index) +{ + rrcPerNB_t *rrcNB = rrc->perNB + gnb_index; + l3_measurements_t *l3_measurements = &rrcNB->l3_measurements; + + for (int i = 0; i < MAX_MEAS_CONFIG; i++) { + NR_ReportConfigToAddMod_t *report_config = rrcNB->ReportConfig[i]; + if (report_config == NULL) + continue; + + if (report_config->reportConfig.present != NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR) + continue; + + NR_ReportConfigNR_t *report_config_nr = report_config->reportConfig.choice.reportConfigNR; + if (report_config_nr->reportType.present != NR_ReportConfigNR__reportType_PR_eventTriggered) + continue; + + NR_EventTriggerConfig_t *event_trigger_config = report_config_nr->reportType.choice.eventTriggered; + if (event_trigger_config->eventId.present != NR_EventTriggerConfig__eventId_PR_eventA2) + continue; + + struct NR_EventTriggerConfig__eventId__eventA2 *event_A2 = event_trigger_config->eventId.choice.eventA2; + if (event_A2->a2_Threshold.present != NR_MeasTriggerQuantity_PR_rsrp) + continue; + + meas_t *serving_cell = &l3_measurements->serving_cell; + int serving_cell_rsrp = INT_MAX; + if (serving_cell->ss_rsrp_dBm.init == true) { + serving_cell_rsrp = serving_cell->ss_rsrp_dBm.val; + } else if (serving_cell->csi_rsrp_dBm.init == true) { + serving_cell_rsrp = serving_cell->csi_rsrp_dBm.val; + } else { + LOG_E(NR_RRC, "There are no RSRP measurements taken for the active cell\n"); + } + + // TS 38.133 - Table 10.1.6.1-1: SS-RSRP and CSI-RSRP measurement report mapping + int rsrp_threshold = event_A2->a2_Threshold.choice.rsrp - 157; + int rsrp_hysteresis = event_A2->hysteresis >> 1; + + // TS 38.331 - 5.5.4.3 Event A2 (Serving becomes worse than threshold) + if (serving_cell_rsrp + rsrp_hysteresis < rsrp_threshold) { + if (!nr_timer_is_active(&l3_measurements->TA2) && (l3_measurements->reports_sent == 0)) { + nr_timer_setup(&l3_measurements->TA2, get_A2_event_time_to_trigger(event_A2->timeToTrigger), 10); + nr_timer_start(&l3_measurements->TA2); + int report_config_id = report_config->reportConfigId; + int meas_id = -1; + for (int j = 0; j < MAX_MEAS_ID; j++) { + NR_MeasIdToAddMod_t *meas_id_toAddMod = rrcNB->MeasId[j]; + if (meas_id_toAddMod == NULL) { + continue; + } + if (meas_id_toAddMod->reportConfigId == report_config_id) { + meas_id = meas_id_toAddMod->measId; + } + } + AssertFatal(meas_id > 0, "meas_id did not found for report_config_id %i\n", report_config_id); + + l3_measurements->trigger_to_measid = meas_id; + l3_measurements->trigger_quantity = event_A2->a2_Threshold.present; + l3_measurements->rs_type = event_trigger_config->rsType; + l3_measurements->reports_sent = 0; + l3_measurements->max_reports = (event_trigger_config->reportAmount == NR_EventTriggerConfig__reportAmount_infinity) + ? INT_MAX + : (1 << event_trigger_config->reportAmount); + l3_measurements->report_interval_ms = get_measurement_report_interval_ms(event_trigger_config->reportInterval); + + LOG_W(NR_RRC, + "(active_cell_rsrp) %i + (rsrp_hysteresis) %i < (rsrp_threshold) %i\n", + serving_cell_rsrp, + rsrp_hysteresis, + rsrp_threshold); + } + } else if (nr_timer_is_active(&l3_measurements->TA2) && (serving_cell_rsrp - rsrp_hysteresis > rsrp_threshold)) { + nr_timer_stop(&l3_measurements->TA2); + nr_timer_stop(&l3_measurements->periodic_report_timer); + l3_measurements->reports_sent = 0; + } + } +} + void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded) { NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; @@ -1985,7 +2557,7 @@ void *rrc_nrue(void *notUsed) instance_t instance = ITTI_MSG_DESTINATION_INSTANCE(msg_p); LOG_D(NR_RRC, "[UE %ld] Received %s\n", instance, ITTI_MSG_NAME(msg_p)); - NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[instance]; + NR_UE_RRC_INST_t *rrc = get_NR_UE_rrc_inst(instance); AssertFatal(instance == rrc->ue_id, "Instance %ld received from ITTI doesn't matach with UE-ID %ld\n", instance, rrc->ue_id); switch (ITTI_MSG_ID(msg_p)) { @@ -2004,7 +2576,8 @@ void *rrc_nrue(void *notUsed) } break; case NRRRC_FRAME_PROCESS: - LOG_D(NR_RRC, "Received %s: frame %d\n", ITTI_MSG_NAME(msg_p), NRRRC_FRAME_PROCESS(msg_p).frame); + rrc->current_frame = NRRRC_FRAME_PROCESS(msg_p).frame; + LOG_D(NR_RRC, "Received %s: frame %d\n", ITTI_MSG_NAME(msg_p), rrc->current_frame); // increase the timers every 10ms (every new frame) nr_rrc_handle_timers(rrc); NR_UE_RRC_SI_INFO *SInfo = &rrc->perNB[NRRRC_FRAME_PROCESS(msg_p).gnb_id].SInfo; @@ -2048,7 +2621,14 @@ void *rrc_nrue(void *notUsed) if (bcch->is_bch) nr_rrc_ue_decode_NR_BCCH_BCH_Message(rrc, bcch->gnb_index, bcch->phycellid, bcch->ssb_arfcn, bcch->sdu, bcch->sdu_size); else - nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(rrc, bcch->gnb_index, bcch->sdu, bcch->sdu_size, bcch->rsrq, bcch->rsrp); + nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(rrc, + bcch->gnb_index, + bcch->sdu, + bcch->sdu_size, + bcch->rsrq, + bcch->rsrp, + bcch->frame, + bcch->slot); break; case NR_RRC_MAC_SBCCH_DATA_IND: @@ -2057,6 +2637,21 @@ void *rrc_nrue(void *notUsed) nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(rrc, sbcch->gnb_index,sbcch->frame, sbcch->slot, sbcch->sdu, sbcch->sdu_size, sbcch->rx_slss_id); + case NR_RRC_MAC_MEAS_DATA_IND: + + LOG_D(NR_RRC, "[%s][Nid_cell %i] Received %s measurements: RSRP = %i (dBm)\n", + NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_neighboring_cell? "Neighboring cell" : "Active cell", + NR_RRC_MAC_MEAS_DATA_IND(msg_p).Nid_cell, + NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_csi_meas ? "CSI meas" : "SSB meas", + NR_RRC_MAC_MEAS_DATA_IND(msg_p).rsrp_dBm); + + rrcPerNB_t *rrcNB = rrc->perNB + NR_RRC_MAC_MEAS_DATA_IND(msg_p).gnb_index; + nr_ue_meas_filtering(rrcNB, + NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_neighboring_cell, + NR_RRC_MAC_MEAS_DATA_IND(msg_p).Nid_cell, + NR_RRC_MAC_MEAS_DATA_IND(msg_p).is_csi_meas, + NR_RRC_MAC_MEAS_DATA_IND(msg_p).rsrp_dBm); + nr_ue_check_meas_report(rrc, NR_RRC_MAC_MEAS_DATA_IND(msg_p).gnb_index); break; case NR_RRC_MAC_CCCH_DATA_IND: { @@ -2066,11 +2661,11 @@ void *rrc_nrue(void *notUsed) case NR_RRC_DCCH_DATA_IND: nr_rrc_ue_decode_dcch(rrc, - NR_RRC_DCCH_DATA_IND(msg_p).dcch_index, - NR_RRC_DCCH_DATA_IND(msg_p).sdu_p, - NR_RRC_DCCH_DATA_IND(msg_p).sdu_size, - NR_RRC_DCCH_DATA_IND(msg_p).gNB_index, - &NR_RRC_DCCH_DATA_IND(msg_p).msg_integrity); + NR_RRC_DCCH_DATA_IND(msg_p).dcch_index, + NR_RRC_DCCH_DATA_IND(msg_p).sdu_p, + NR_RRC_DCCH_DATA_IND(msg_p).sdu_size, + NR_RRC_DCCH_DATA_IND(msg_p).gNB_index, + &NR_RRC_DCCH_DATA_IND(msg_p).msg_integrity); /* this is allocated by itti_malloc in PDCP task (deliver_sdu_srb) then passed to the RRC task and freed after use */ free(NR_RRC_DCCH_DATA_IND(msg_p).sdu_p); @@ -2140,75 +2735,6 @@ void nr_rrc_ue_process_sidelink_radioResourceConfig(NR_SetupRelease_SL_ConfigDed } } -static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECapabilityEnquiry_t *UECapabilityEnquiry) -{ - NR_UL_DCCH_Message_t ul_dcch_msg = {0}; - // - LOG_I(NR_RRC, "Receiving from SRB1 (DL-DCCH), Processing UECapabilityEnquiry\n"); - - ul_dcch_msg.message.present = NR_UL_DCCH_MessageType_PR_c1; - asn1cCalloc(ul_dcch_msg.message.choice.c1, c1); - c1->present = NR_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation; - asn1cCalloc(c1->choice.ueCapabilityInformation, info); - info->rrc_TransactionIdentifier = UECapabilityEnquiry->rrc_TransactionIdentifier; - if (!rrc->UECap.UE_NR_Capability) { - rrc->UECap.UE_NR_Capability = CALLOC(1, sizeof(NR_UE_NR_Capability_t)); - asn1cSequenceAdd(rrc->UECap.UE_NR_Capability->rf_Parameters.supportedBandListNR.list, NR_BandNR_t, nr_bandnr); - nr_bandnr->bandNR = 1; - } - xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, (void *)rrc->UECap.UE_NR_Capability); - - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UE_NR_Capability, - NULL, - (void *)rrc->UECap.UE_NR_Capability, - &rrc->UECap.sdu[0], - MAX_UE_NR_CAPABILITY_SIZE); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - rrc->UECap.sdu_size = (enc_rval.encoded + 7) / 8; - LOG_I(PHY, "[RRC]UE NR Capability encoded, %d bytes (%zd bits)\n", rrc->UECap.sdu_size, enc_rval.encoded + 7); - /* RAT Container */ - NR_UE_CapabilityRAT_Container_t *ue_CapabilityRAT_Container = CALLOC(1, sizeof(NR_UE_CapabilityRAT_Container_t)); - ue_CapabilityRAT_Container->rat_Type = NR_RAT_Type_nr; - OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container->ue_CapabilityRAT_Container, (const char *)rrc->UECap.sdu, rrc->UECap.sdu_size); - NR_UECapabilityEnquiry_IEs_t *ueCapabilityEnquiry_ie = UECapabilityEnquiry->criticalExtensions.choice.ueCapabilityEnquiry; - if (get_softmodem_params()->nsa == 1) { - OCTET_STRING_t *requestedFreqBandsNR = ueCapabilityEnquiry_ie->ue_CapabilityEnquiryExt; - nsa_sendmsg_to_lte_ue(requestedFreqBandsNR->buf, requestedFreqBandsNR->size, UE_CAPABILITY_INFO); - } - // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.buf = UE_rrc_inst[ue_mod_idP].UECapability; - // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.size = UE_rrc_inst[ue_mod_idP].UECapability_size; - AssertFatal(UECapabilityEnquiry->criticalExtensions.present == NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry, - "UECapabilityEnquiry->criticalExtensions.present (%d) != UECapabilityEnquiry__criticalExtensions_PR_c1 (%d)\n", - UECapabilityEnquiry->criticalExtensions.present,NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry); - - NR_UECapabilityInformation_t *ueCapabilityInformation = ul_dcch_msg.message.choice.c1->choice.ueCapabilityInformation; - ueCapabilityInformation->criticalExtensions.present = NR_UECapabilityInformation__criticalExtensions_PR_ueCapabilityInformation; - asn1cCalloc(ueCapabilityInformation->criticalExtensions.choice.ueCapabilityInformation, infoIE); - asn1cCalloc(infoIE->ue_CapabilityRAT_ContainerList, UEcapList); - UEcapList->list.count = 0; - - for (int i = 0; i < ueCapabilityEnquiry_ie->ue_CapabilityRAT_RequestList.list.count; i++) { - if (ueCapabilityEnquiry_ie->ue_CapabilityRAT_RequestList.list.array[i]->rat_Type == NR_RAT_Type_nr) { - asn1cSeqAdd(&UEcapList->list, ue_CapabilityRAT_Container); - uint8_t buffer[500]; - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, NULL, (void *)&ul_dcch_msg, buffer, 500); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - - if (LOG_DEBUGFLAG(DEBUG_ASN1)) { - xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg); - } - LOG_I(NR_RRC, "UECapabilityInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8); - int srb_id = 1; // UECapabilityInformation on SRB1 - nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, (enc_rval.encoded + 7) / 8, buffer, deliver_pdu_srb_rlc, NULL); - } - } - /* Free struct members after it's done - including locally allocated ue_CapabilityRAT_Container */ - ASN_STRUCT_RESET(asn_DEF_NR_UL_DCCH_Message, &ul_dcch_msg); -} - static void nr_rrc_initiate_rrcReestablishment(NR_UE_RRC_INST_t *rrc, NR_ReestablishmentCause_t cause) { rrc->reestablishment_cause = cause; @@ -2242,196 +2768,10 @@ static void nr_rrc_initiate_rrcReestablishment(NR_UE_RRC_INST_t *rrc, NR_Reestab // reset MAC // release spCellConfig, if configured // perform cell selection in accordance with the cell selection process - MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_RESET); - NR_MAC_RRC_CONFIG_RESET(msg).cause = RE_ESTABLISHMENT; - itti_send_msg_to_task(TASK_MAC_UE, rrc->ue_id, msg); -} - -static void nr_rrc_ue_generate_rrcReestablishmentComplete(const NR_UE_RRC_INST_t *rrc, - const NR_RRCReestablishment_t *rrcReestablishment) -{ - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = do_RRCReestablishmentComplete(buffer, NR_RRC_BUF_SIZE, rrcReestablishment->rrc_TransactionIdentifier); - LOG_I(NR_RRC, "[RAPROC] Logical Channel UL-DCCH (SRB1), Generating RRCReestablishmentComplete (bytes %d)\n", size); - int srb_id = 1; // RRC re-establishment complete on SRB1 - nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL); -} - -void *recv_msgs_from_lte_ue(void *args_p) -{ - itti_mark_task_ready (TASK_RRC_NSA_NRUE); - int from_lte_ue_fd = get_from_lte_ue_fd(); - for (;;) { - nsa_msg_t msg; - int recvLen = recvfrom(from_lte_ue_fd, &msg, sizeof(msg), MSG_WAITALL | MSG_TRUNC, NULL, NULL); - if (recvLen == -1) { - LOG_E(NR_RRC, "%s: recvfrom: %s\n", __func__, strerror(errno)); - continue; - } - if (recvLen > sizeof(msg)) { - LOG_E(NR_RRC, "%s: Received truncated message %d\n", __func__, recvLen); - continue; - } - process_lte_nsa_msg(NR_UE_rrc_inst, &msg, recvLen); - } - return NULL; -} - -static void nsa_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc) -{ - NR_UE_NR_Capability_t *UE_Capability_nr = rrc->UECap.UE_NR_Capability = CALLOC(1, sizeof(NR_UE_NR_Capability_t)); - NR_BandNR_t *nr_bandnr = CALLOC(1, sizeof(NR_BandNR_t)); - nr_bandnr->bandNR = 78; - asn1cSeqAdd(&UE_Capability_nr->rf_Parameters.supportedBandListNR.list, nr_bandnr); - OAI_NR_UECapability_t *UECap = CALLOC(1, sizeof(OAI_NR_UECapability_t)); - UECap->UE_NR_Capability = UE_Capability_nr; - - asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UE_NR_Capability, - NULL, - (void *)UE_Capability_nr, - &UECap->sdu[0], - MAX_UE_NR_CAPABILITY_SIZE); - AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - UECap->sdu_size = (enc_rval.encoded + 7) / 8; - LOG_A(NR_RRC, "[NR_RRC] NRUE Capability encoded, %d bytes (%zd bits)\n", - UECap->sdu_size, enc_rval.encoded + 7); - - NR_UE_CapabilityRAT_Container_t ue_CapabilityRAT_Container; - memset(&ue_CapabilityRAT_Container, 0, sizeof(NR_UE_CapabilityRAT_Container_t)); - ue_CapabilityRAT_Container.rat_Type = NR_RAT_Type_nr; - OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container.ue_CapabilityRAT_Container, - (const char *)rrc->UECap.sdu, - rrc->UECap.sdu_size); - - nsa_sendmsg_to_lte_ue(ue_CapabilityRAT_Container.ue_CapabilityRAT_Container.buf, - ue_CapabilityRAT_Container.ue_CapabilityRAT_Container.size, - NRUE_CAPABILITY_INFO); -} - -static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_len) -{ - if (msg_len < sizeof(msg->msg_type)) { - LOG_E(RRC, "Msg_len = %d\n", msg_len); - return; - } - LOG_D(NR_RRC, "Processing an NSA message\n"); - Rrc_Msg_Type_t msg_type = msg->msg_type; - uint8_t *const msg_buffer = msg->msg_buffer; - msg_len -= sizeof(msg->msg_type); - switch (msg_type) { - case UE_CAPABILITY_ENQUIRY: { - LOG_D(NR_RRC, "We are processing a %d message \n", msg_type); - NR_FreqBandList_t *nr_freq_band_list = NULL; - asn_dec_rval_t dec_rval = uper_decode_complete(NULL, - &asn_DEF_NR_FreqBandList, - (void **)&nr_freq_band_list, - msg_buffer, - msg_len); - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - SEQUENCE_free(&asn_DEF_NR_FreqBandList, nr_freq_band_list, ASFM_FREE_EVERYTHING); - LOG_E(RRC, "Failed to decode UECapabilityInfo (%zu bits)\n", dec_rval.consumed); - break; - } - for (int i = 0; i < nr_freq_band_list->list.count; i++) { - LOG_D(NR_RRC, "Received NR band information: %ld.\n", - nr_freq_band_list->list.array[i]->choice.bandInformationNR->bandNR); - } - int dummy_msg = 0;// whatever piece of data, it will never be used by sendee - LOG_D(NR_RRC, "We are calling nsa_sendmsg_to_lte_ue to send a UE_CAPABILITY_DUMMY\n"); - nsa_sendmsg_to_lte_ue(&dummy_msg, sizeof(dummy_msg), UE_CAPABILITY_DUMMY); - LOG_A(NR_RRC, "Sent initial NRUE Capability response to LTE UE\n"); - break; - } - - case NRUE_CAPABILITY_ENQUIRY: { - LOG_I(NR_RRC, "We are processing a %d message \n", msg_type); - NR_FreqBandList_t *nr_freq_band_list = NULL; - asn_dec_rval_t dec_rval = uper_decode_complete(NULL, - &asn_DEF_NR_FreqBandList, - (void **)&nr_freq_band_list, - msg_buffer, - msg_len); - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - SEQUENCE_free(&asn_DEF_NR_FreqBandList, nr_freq_band_list, ASFM_FREE_EVERYTHING); - LOG_E(NR_RRC, "Failed to decode UECapabilityInfo (%zu bits)\n", dec_rval.consumed); - break; - } - LOG_I(NR_RRC, "Calling nsa_rrc_ue_process_ueCapabilityEnquiry\n"); - nsa_rrc_ue_process_ueCapabilityEnquiry(rrc); - break; - } - - case RRC_MEASUREMENT_PROCEDURE: { - LOG_I(NR_RRC, "We are processing a %d message \n", msg_type); - - LTE_MeasObjectToAddMod_t *nr_meas_obj = NULL; - asn_dec_rval_t dec_rval = uper_decode_complete(NULL, - &asn_DEF_NR_MeasObjectToAddMod, - (void **)&nr_meas_obj, - msg_buffer, - msg_len); - if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { - SEQUENCE_free(&asn_DEF_NR_MeasObjectToAddMod, nr_meas_obj, ASFM_FREE_EVERYTHING); - LOG_E(RRC, "Failed to decode measurement object (%zu bits) %d\n", dec_rval.consumed, dec_rval.code); - break; - } - LOG_D(NR_RRC, "NR carrierFreq_r15 (ssb): %ld and sub carrier spacing:%ld\n", - nr_meas_obj->measObject.choice.measObjectNR_r15.carrierFreq_r15, - nr_meas_obj->measObject.choice.measObjectNR_r15.rs_ConfigSSB_r15.subcarrierSpacingSSB_r15); - start_oai_nrue_threads(); - break; - } - - case RRC_CONFIG_COMPLETE_REQ: { - struct msg { - uint32_t RadioBearer_size; - uint32_t SecondaryCellGroup_size; - uint8_t trans_id; - uint8_t padding[3]; - uint8_t buffer[]; - } hdr; - AssertFatal(msg_len >= sizeof(hdr), "Bad received msg\n"); - memcpy(&hdr, msg_buffer, sizeof(hdr)); - LOG_I(NR_RRC, "We got an RRC_CONFIG_COMPLETE_REQ\n"); - uint32_t nr_RadioBearer_size = hdr.RadioBearer_size; - uint32_t nr_SecondaryCellGroup_size = hdr.SecondaryCellGroup_size; - AssertFatal(sizeof(hdr) + nr_RadioBearer_size + nr_SecondaryCellGroup_size <= msg_len, - "nr_RadioBearerConfig1_r15 size %u nr_SecondaryCellGroupConfig_r15 size %u sizeof(hdr) %zu, msg_len = %d\n", - nr_RadioBearer_size, - nr_SecondaryCellGroup_size, - sizeof(hdr), - msg_len); - NR_RRC_TransactionIdentifier_t t_id = hdr.trans_id; - LOG_I(NR_RRC, "nr_RadioBearerConfig1_r15 size %d nr_SecondaryCellGroupConfig_r15 size %d t_id %ld\n", - nr_RadioBearer_size, - nr_SecondaryCellGroup_size, - t_id); - - uint8_t *nr_RadioBearer_buffer = msg_buffer + offsetof(struct msg, buffer); - uint8_t *nr_SecondaryCellGroup_buffer = nr_RadioBearer_buffer + nr_RadioBearer_size; - process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, nr_SecondaryCellGroup_buffer, nr_SecondaryCellGroup_size); - process_nsa_message(NR_UE_rrc_inst, nr_RadioBearerConfigX_r15, nr_RadioBearer_buffer, nr_RadioBearer_size); - LOG_I(NR_RRC, "Calling do_NR_RRCReconfigurationComplete. t_id %ld \n", t_id); - uint8_t buffer[NR_RRC_BUF_SIZE]; - size_t size = do_NR_RRCReconfigurationComplete_for_nsa(buffer, sizeof(buffer), t_id); - nsa_sendmsg_to_lte_ue(buffer, size, NR_RRC_CONFIG_COMPLETE_REQ); - break; - } - - case OAI_TUN_IFACE_NSA: { - LOG_I(NR_RRC, "We got an OAI_TUN_IFACE_NSA!!\n"); - char cmd_line[NR_RRC_BUF_SIZE]; - memcpy(cmd_line, msg_buffer, sizeof(cmd_line)); - LOG_D(NR_RRC, "Command line: %s\n", cmd_line); - if (background_system(cmd_line) != 0) - LOG_E(NR_RRC, "ESM-PROC - failed command '%s'", cmd_line); - break; - } - - default: - LOG_E(NR_RRC, "No NSA Message Found\n"); - } + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_RESET; + rrc_msg.payload.config_reset.cause = RE_ESTABLISHMENT; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); } void handle_RRCRelease(NR_UE_RRC_INST_t *rrc) @@ -2515,17 +2855,16 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, nr_timer_setup(&tac->T302, target, 10); nr_timer_start(&tac->T302); // TODO inform upper layers that access barring is applicable - // for all access categories except categories '0' and '2'. - LOG_E(NR_RRC,"Go to IDLE. Handling RRCRelease message including a waitTime not implemented\n"); + // for all access categories except categories '0' and '2'. + // for now we just set the access barred in RRC + rrc->access_barred = true; } } } if (!waitTime) { if (nr_timer_is_active(&tac->T302)) { nr_timer_stop(&tac->T302); - // TODO barring alleviation as in 5.3.14.4 - // not implemented - LOG_E(NR_RRC,"Go to IDLE. Barring alleviation not implemented\n"); + handle_302_expired_stopped(rrc); } } if (nr_timer_is_active(&tac->T390)) { @@ -2618,9 +2957,10 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, // reset MAC NR_UE_MAC_reset_cause_t cause = (rrc->nrRrcState == RRC_STATE_DETACH_NR) ? DETACH : GO_TO_IDLE; - MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_RESET); - NR_MAC_RRC_CONFIG_RESET(msg).cause = cause; - itti_send_msg_to_task(TASK_MAC_UE, rrc->ue_id, msg); + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_RESET; + rrc_msg.payload.config_reset.cause = cause; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); // enter RRC_IDLE LOG_I(NR_RRC, "RRC moved into IDLE state\n"); @@ -2635,6 +2975,13 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, msg_p); } +void handle_302_expired_stopped(NR_UE_RRC_INST_t *rrc) +{ + // for each Access Category for which T390 (TODO not implemented) is not running + // consider the barring for this Access Category to be alleviated + rrc->access_barred = false; +} + void handle_t300_expiry(NR_UE_RRC_INST_t *rrc) { rrc->ra_trigger = RRC_CONNECTION_SETUP; @@ -2642,18 +2989,37 @@ void handle_t300_expiry(NR_UE_RRC_INST_t *rrc) // reset MAC, release the MAC configuration NR_UE_MAC_reset_cause_t cause = T300_EXPIRY; - MessageDef *msg = itti_alloc_new_message(TASK_RRC_NRUE, 0, NR_MAC_RRC_CONFIG_RESET); - NR_MAC_RRC_CONFIG_RESET(msg).cause = cause; - itti_send_msg_to_task(TASK_MAC_UE, rrc->ue_id, msg); + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_RESET; + rrc_msg.payload.config_reset.cause = cause; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); + // TODO handle connEstFailureControl // TODO inform upper layers about the failure to establish the RRC connection } +void handle_t430_expiry(NR_UE_RRC_INST_t *rrc) +{ + // SPEC 38.331 section 5.2.2.6 + // Reacquire SIB19 after T430 expiry + for (int i = 0; i < NB_CNX_UE; i++) { + rrcPerNB_t *nb = &rrc->perNB[i]; + NR_UE_RRC_SI_INFO *SI_info = &nb->SInfo; + SI_info->SInfo_r17.sib19_validity = false; + } + // Indicate MAC that UL SYNC is LOST + NR_UE_MAC_reset_cause_t cause = UL_SYNC_LOST_T430_EXPIRED; + nr_mac_rrc_message_t rrc_msg = {0}; + rrc_msg.payload_type = NR_MAC_RRC_CONFIG_RESET; + rrc_msg.payload.config_reset.cause = cause; + nr_rrc_send_msg_to_mac(rrc, &rrc_msg); +} + //This calls the sidelink preconf message after RRC, MAC instances are created. void start_sidelink(int instance) { - NR_UE_RRC_INST_t *rrc = &NR_UE_rrc_inst[instance]; + NR_UE_RRC_INST_t *rrc = get_NR_UE_rrc_inst(instance); if (get_softmodem_params()->sl_mode == 2) { @@ -2662,3 +3028,27 @@ void start_sidelink(int instance) } } + +void nr_rrc_set_mac_queue(instance_t instance, notifiedFIFO_t *mac_input_nf) +{ + NR_UE_RRC_INST_t *rrc = get_NR_UE_rrc_inst(instance); + rrc->mac_input_nf = mac_input_nf; +} + +void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id) +{ + uint8_t buffer[NR_RRC_BUF_SIZE]; + l3_measurements_t *l3m = &rrc->l3_measurements; + int rsrp_dBm = l3m->rs_type == NR_NR_RS_Type_ssb ? l3m->serving_cell.ss_rsrp_dBm.val : l3m->serving_cell.csi_rsrp_dBm.val; + int rsrp_index = get_rsrp_index(rsrp_dBm); + uint8_t size = do_nrMeasurementReport_SA(l3m->trigger_to_measid, + l3m->trigger_quantity, + l3m->rs_type, + l3m->serving_cell.Nid_cell, + rsrp_index, + buffer, + sizeof(buffer)); + + int srb_id = 1; // possibly TODO in SRB3 in some cases + nr_pdcp_data_req_srb(ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL); +} diff --git a/openair2/RRC/NR_UE/rrc_defs.h b/openair2/RRC/NR_UE/rrc_defs.h index e428c4c160..ae8837bff2 100644 --- a/openair2/RRC/NR_UE/rrc_defs.h +++ b/openair2/RRC/NR_UE/rrc_defs.h @@ -63,6 +63,7 @@ #include "RRC/NR/nr_rrc_common.h" #include "as_message.h" #include "common/utils/nr/nr_common.h" +#include "notified_fifo.h" #define NB_CNX_UE 2//MAX_MANAGED_RG_PER_MOBILE #define MAX_MEAS_OBJ 64 @@ -94,6 +95,7 @@ typedef enum RA_trigger_e { RA_NOT_RUNNING, RRC_CONNECTION_SETUP, RRC_CONNECTION_REESTABLISHMENT, + RRC_RESUME_REQUEST, DURING_HANDOVER, NON_SYNCHRONISED, TRANSITION_FROM_RRC_INACTIVE, @@ -151,6 +153,11 @@ typedef struct UE_RRC_SI_INFO_NR_s { bool sib14_validity; NR_timer_t sib14_timer; NR_UE_RRC_SI_INFO_r17 SInfo_r17; + // Extracted from SIB1 + int scs; + int sib19_periodicity; + int sib19_windowposition; + int si_windowlength; } NR_UE_RRC_SI_INFO; typedef struct NR_UE_Timers_Constants_s { @@ -167,6 +174,8 @@ typedef struct NR_UE_Timers_Constants_s { NR_timer_t T325; NR_timer_t T380; NR_timer_t T390; + // NTN timer T430 which guards UL SYNC + NR_timer_t T430; // counters uint32_t N310_cnt; uint32_t N311_cnt; @@ -183,6 +192,20 @@ typedef enum { typedef enum { RB_NOT_PRESENT, RB_ESTABLISHED, RB_SUSPENDED } NR_RB_status_t; +typedef struct l3_measurements_s { + float ssb_filter_coeff_rsrp; + float csi_RS_filter_coeff_rsrp; + meas_t serving_cell; + long trigger_to_measid; + long trigger_quantity; + long rs_type; + int reports_sent; + int max_reports; + long report_interval_ms; + NR_timer_t TA2; + NR_timer_t periodic_report_timer; +} l3_measurements_t; + typedef struct rrcPerNB { NR_MeasObjectToAddMod_t *MeasObj[MAX_MEAS_OBJ]; NR_ReportConfigToAddMod_t *ReportConfig[MAX_MEAS_CONFIG]; @@ -192,12 +215,13 @@ typedef struct rrcPerNB { NR_MeasGapConfig_t *measGapConfig; NR_UE_RRC_SI_INFO SInfo; NR_RSRP_Range_t s_measure; + l3_measurements_t l3_measurements; } rrcPerNB_t; typedef struct NR_UE_RRC_INST_s { instance_t ue_id; rrcPerNB_t perNB[NB_CNX_UE]; - + bool access_barred; rnti_t rnti; uint32_t phyCellID; long arfcn_ssb; @@ -224,6 +248,10 @@ typedef struct NR_UE_RRC_INST_s { e_NR_IntegrityProtAlgorithm integrityProtAlgorithm; long keyToUse; bool as_security_activated; + /// Next Hop Chaining Count + uint8_t nh[32]; + uint64_t nhcc; + bool detach_after_release; NR_timer_t release_timer; NR_RRCRelease_t *RRCRelease; @@ -233,11 +261,14 @@ typedef struct NR_UE_RRC_INST_s { bool reconfig_after_reestab; // 5G-S-TMSI uint64_t fiveG_S_TMSI; + // Frame timing received from MAC + int current_frame; //Sidelink params NR_SL_PreconfigurationNR_r16_t *sl_preconfig; // NTN params bool is_NTN_UE; + notifiedFIFO_t *mac_input_nf; } NR_UE_RRC_INST_t; #endif diff --git a/openair2/RRC/NR_UE/rrc_nsa.c b/openair2/RRC/NR_UE/rrc_nsa.c deleted file mode 100644 index 279e920779..0000000000 --- a/openair2/RRC/NR_UE/rrc_nsa.c +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include -#include "common/utils/LOG/log.h" -#include "openair2/RRC/NR_UE/rrc_proto.h" - -static const char nsa_ipaddr[] = "127.0.0.1"; -static int from_lte_ue_fd = -1; -static int to_lte_ue_fd = -1; -uint16_t ue_id_g; - -int get_from_lte_ue_fd() -{ - return from_lte_ue_fd; -} - -void nsa_sendmsg_to_lte_ue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type) -{ - LOG_I(NR_RRC, "Entered %s \n", __FUNCTION__); - nsa_msg_t n_msg; - if (msg_len > sizeof(n_msg.msg_buffer)) - { - LOG_E(NR_RRC, "%s: message too big: %zu\n", __func__, msg_len); - abort(); - } - n_msg.msg_type = msg_type; - memcpy(n_msg.msg_buffer, message, msg_len); - size_t to_send = sizeof(n_msg.msg_type) + msg_len; - - struct sockaddr_in sa = - { - .sin_family = AF_INET, - .sin_port = htons(6007 + ue_id_g * 2), - }; - int sent = sendto(from_lte_ue_fd, &n_msg, to_send, 0, - (struct sockaddr *)&sa, sizeof(sa)); - if (sent == -1) - { - LOG_E(NR_RRC, "%s: sendto: %s\n", __func__, strerror(errno)); - return; - } - if (sent != to_send) - { - LOG_E(NR_RRC, "%s: Short send %d != %zu\n", __func__, sent, to_send); - return; - } - LOG_D(NR_RRC, "Sent a %d message to the LTE UE (%d bytes) \n", msg_type, sent); -} - -void init_connections_with_lte_ue(void) -{ - struct sockaddr_in sa = - { - .sin_family = AF_INET, - .sin_port = htons(6008 + ue_id_g * 2), - }; - AssertFatal(from_lte_ue_fd == -1, "from_lte_ue_fd %d was assigned already", from_lte_ue_fd); - from_lte_ue_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (from_lte_ue_fd == -1) - { - LOG_E(NR_RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, from_lte_ue_fd, errno, strerror(errno)); - abort(); - } - - if (inet_aton(nsa_ipaddr, &sa.sin_addr) == 0) - { - LOG_E(NR_RRC, "Bad nsa_ipaddr '%s'\n", nsa_ipaddr); - abort(); - } - - if (bind(from_lte_ue_fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) - { - LOG_E(NR_RRC,"%s: Failed to bind the socket\n", __FUNCTION__); - abort(); - } - - AssertFatal(to_lte_ue_fd == -1, "to_lte_ue_fd was assigned already"); - to_lte_ue_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (to_lte_ue_fd == -1) - { - LOG_E(NR_RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, to_lte_ue_fd, errno, strerror(errno)); - abort(); - } - LOG_I(NR_RRC, "Started LTE-NR link in the nr-UE\n"); -} diff --git a/openair2/RRC/NR_UE/rrc_proto.h b/openair2/RRC/NR_UE/rrc_proto.h index f4728f0f58..1ebb728884 100644 --- a/openair2/RRC/NR_UE/rrc_proto.h +++ b/openair2/RRC/NR_UE/rrc_proto.h @@ -47,7 +47,7 @@ void init_nsa_message (NR_UE_RRC_INST_t *rrc, char* reconfig_file, char* rbconfi void process_nsa_message(NR_UE_RRC_INST_t *rrc, nsa_message_t nsa_message_type, void *message, int msg_len); -void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig); +void nr_rrc_cellgroup_configuration(NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig, int gNB_index); void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, NR_Release_Cause_t release_cause, @@ -55,6 +55,8 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, void handle_RRCRelease(NR_UE_RRC_INST_t *rrc); +void rrc_ue_generate_measurementReport(rrcPerNB_t *rrc, instance_t ue_id); + void set_rlf_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_UE_TimersAndConstants_t *ue_TimersAndConstants); /**\brief RRC UE task. @@ -64,14 +66,7 @@ void *rrc_nrue(void *args_p); void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc); void handle_rlf_detection(NR_UE_RRC_INST_t *rrc); - -/**\brief RRC NSA UE task. - \param void *args_p Pointer on arguments to start the task. */ -void *recv_msgs_from_lte_ue(void *args_p); - -void init_connections_with_lte_ue(void); - -extern void start_oai_nrue_threads(void); +void handle_302_expired_stopped(NR_UE_RRC_INST_t *rrc); int get_from_lte_ue_fd(); @@ -80,7 +75,9 @@ void init_SI_timers(NR_UE_RRC_SI_INFO *SInfo); void nr_ue_rrc_timer_trigger(int module_id, int frame, int gnb_id); void handle_t300_expiry(NR_UE_RRC_INST_t *rrc); +void handle_t430_expiry(NR_UE_RRC_INST_t *rrc); +int get_A2_event_time_to_trigger(long time_to_trigger); void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac); void set_default_timers_and_constants(NR_UE_Timers_Constants_t *tac); void nr_rrc_set_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_SIB1_t *sib1); @@ -104,6 +101,8 @@ void nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(NR_UE_RRC_INST_t *rrc, const sdu_size_t pdu_len, const uint16_t rx_slss_id); +void nr_rrc_set_mac_queue(instance_t instance, notifiedFIFO_t *mac_input_nf); + /** @}*/ #endif diff --git a/openair2/RRC/NR_UE/rrc_timers_and_constants.c b/openair2/RRC/NR_UE/rrc_timers_and_constants.c index 6629055b3a..133ffb8d8e 100644 --- a/openair2/RRC/NR_UE/rrc_timers_and_constants.c +++ b/openair2/RRC/NR_UE/rrc_timers_and_constants.c @@ -122,6 +122,36 @@ void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo) } } +void handle_meas_timers(NR_UE_RRC_INST_t *rrc) +{ + for (int i = 0; i < NB_CNX_UE; i++) { + rrcPerNB_t *nb = &rrc->perNB[i]; + l3_measurements_t *l3_measurements = &nb->l3_measurements; + + bool ta2_expired = nr_timer_tick(&l3_measurements->TA2); + if (ta2_expired && l3_measurements->trigger_quantity > 0) { + rrc_ue_generate_measurementReport(nb, rrc->ue_id); + l3_measurements->reports_sent = 1; + + if (l3_measurements->reports_sent < l3_measurements->max_reports) { + nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10); + nr_timer_start(&l3_measurements->periodic_report_timer); + } + } + + bool periodic_expired = nr_timer_tick(&l3_measurements->periodic_report_timer); + if (periodic_expired && l3_measurements->reports_sent < l3_measurements->max_reports) { + rrc_ue_generate_measurementReport(nb, rrc->ue_id); + l3_measurements->reports_sent++; + + if (l3_measurements->reports_sent < l3_measurements->max_reports) { + nr_timer_setup(&l3_measurements->periodic_report_timer, l3_measurements->report_interval_ms, 10); + nr_timer_start(&l3_measurements->periodic_report_timer); + } + } + } +} + void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc) { NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; @@ -132,7 +162,7 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc) bool t300_expired = nr_timer_tick(&timers->T300); if(t300_expired) { - LOG_W(NR_RRC, "Timer T300 expired! No timely response to RRCSetupRequest\n"); + LOG_W(NR_RRC, "[UE %ld] Timer T300 expired! No timely response to RRCSetupRequest\n", rrc->ue_id); handle_t300_expiry(rrc); } @@ -140,13 +170,21 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc) // Upon T301 expiry, the UE shall perform the actions upon going to RRC_IDLE // with release cause 'RRC connection failure' if(t301_expired) { - LOG_W(NR_RRC, "Timer T301 expired! No timely response to RRCReestabilshmentRequest\n"); + LOG_W(NR_RRC, "[UE %ld] Timer T301 expired! No timely response to RRCReestabilshmentRequest\n", rrc->ue_id); nr_rrc_going_to_IDLE(rrc, RRC_CONNECTION_FAILURE, NULL); } + bool t302_expired = nr_timer_tick(&timers->T302); + // 5.3.14.4 in 38.331 + // consider the barring for this Access Category to be alleviated + if (t302_expired) { + LOG_W(NR_RRC, "[UE %ld] Timer T302 expired! Access barring alleviated!\n", rrc->ue_id); + handle_302_expired_stopped(rrc); + } + bool t304_expired = nr_timer_tick(&timers->T304); if(t304_expired) { - LOG_W(NR_RRC, "Timer T304 expired\n"); + LOG_W(NR_RRC, "[UE %ld] Timer T304 expired\n", rrc->ue_id); // TODO // For T304 of MCG, in case of the handover from NR or intra-NR // handover, initiate the RRC re-establishment procedure; @@ -156,19 +194,29 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc) bool t310_expired = nr_timer_tick(&timers->T310); if(t310_expired) { - LOG_W(NR_RRC, "Timer T310 expired\n"); + LOG_W(NR_RRC, "[UE %ld] Timer T310 expired\n", rrc->ue_id); // handle detection of radio link failure // as described in 5.3.10.3 of 38.331 handle_rlf_detection(rrc); } bool t311_expired = nr_timer_tick(&timers->T311); - if(t311_expired) { - LOG_W(NR_RRC, "Timer T311 expired! No suitable cell found in time after initiation of re-establishment\n"); + if (t311_expired) { + LOG_W(NR_RRC, "[UE %ld] Timer T311 expired! No suitable cell found in time after initiation of re-establishment\n", rrc->ue_id); // Upon T311 expiry, the UE shall perform the actions upon going to RRC_IDLE // with release cause 'RRC connection failure' nr_rrc_going_to_IDLE(rrc, RRC_CONNECTION_FAILURE, NULL); } + + bool t430_expired = nr_timer_tick(&rrc->timers_and_constants.T430); + if (t430_expired && rrc->nrRrcState == RRC_STATE_CONNECTED_NR && rrc->is_NTN_UE) { + LOG_W(NR_RRC, "[UE %ld] Timer T430 expired! Indicate UL SYNC LOSS to MAC\n", rrc->ue_id); + // Upon T430 expiry, the UE shall reacquire SIB19 and re-obtain UL-SYNC + // Spec 38.331 Section 5.2.2.6 + handle_t430_expiry(rrc); + } + + handle_meas_timers(rrc); } int nr_rrc_get_T304(long t304) @@ -614,3 +662,43 @@ void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac) tac->N310_cnt = 0; tac->N311_cnt = 0; } + +int get_A2_event_time_to_trigger(long time_to_trigger) +{ + switch (time_to_trigger) { + case NR_TimeToTrigger_ms0: + return 0; + case NR_TimeToTrigger_ms40: + return 40; + case NR_TimeToTrigger_ms64: + return 64; + case NR_TimeToTrigger_ms80: + return 80; + case NR_TimeToTrigger_ms100: + return 100; + case NR_TimeToTrigger_ms128: + return 128; + case NR_TimeToTrigger_ms160: + return 160; + case NR_TimeToTrigger_ms256: + return 256; + case NR_TimeToTrigger_ms320: + return 320; + case NR_TimeToTrigger_ms480: + return 480; + case NR_TimeToTrigger_ms512: + return 512; + case NR_TimeToTrigger_ms640: + return 640; + case NR_TimeToTrigger_ms1024: + return 1024; + case NR_TimeToTrigger_ms1280: + return 1280; + case NR_TimeToTrigger_ms2560: + return 2560; + case NR_TimeToTrigger_ms5120: + return 5120; + default: + AssertFatal(false, "Invalid TimeToTrigger %ld\n", time_to_trigger); + } +} diff --git a/openair2/F1AP/lib/f1ap_lib_extern.h b/openair2/SDAP/nr_sdap/nr_sdap_configuration.h similarity index 81% rename from openair2/F1AP/lib/f1ap_lib_extern.h rename to openair2/SDAP/nr_sdap/nr_sdap_configuration.h index f95b685540..f590278bf8 100644 --- a/openair2/F1AP/lib/f1ap_lib_extern.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_configuration.h @@ -19,9 +19,15 @@ * contact@openairinterface.org */ -#ifndef F1AP_LIB_EXTERN_H_ -#define F1AP_LIB_EXTERN_H_ +#ifndef _NR_SDAP_CONFIGURATION_H_ +#define _NR_SDAP_CONFIGURATION_H_ -#include "f1ap_rrc_message_transfer.h" +#include "stdbool.h" -#endif /* F1AP_LIB_EXTERN_H_ */ +typedef struct { + // SDAP Headers + bool header_dl_absent; + bool header_ul_absent; +} nr_sdap_configuration_t; + +#endif /* _NR_SDAP_CONFIGURATION_H_ */ diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index 7f2f3dd07c..6860fba6e6 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -577,12 +577,11 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) { nr_sdap_entity_t *entityPtr = sdap_info.sdap_entity_llist; nr_sdap_entity_t *entityPrev = NULL; - bool ret = false; int upperBound = 0; if (entityPtr == NULL && (pdusession_id) * (pdusession_id - NGAP_MAX_PDU_SESSION) > 0) { LOG_E(SDAP, "SDAP entities not established or Invalid range of pdusession_id [0, 256].\n"); - return ret; + return false; } LOG_D(SDAP, "Deleting SDAP entity for UE %lx and PDU Session id %d\n", ue_id, entityPtr->pdusession_id); @@ -592,7 +591,7 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) remove_ip_if(entityPtr); free(entityPtr); LOG_D(SDAP, "Successfully deleted Entity.\n"); - ret = true; + return true; } else { while ((entityPtr->ue_id != ue_id || entityPtr->pdusession_id != pdusession_id) && entityPtr->next_entity != NULL && upperBound < SDAP_MAX_NUM_OF_ENTITIES) { @@ -608,11 +607,11 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) } free(entityPtr); LOG_D(SDAP, "Successfully deleted Entity.\n"); - ret = true; + return true; } } LOG_E(SDAP, "Entity does not exist or it was not found.\n"); - return ret; + return false; } bool nr_sdap_delete_ue_entities(ue_id_t ue_id) diff --git a/openair2/X2AP/x2ap_common.c b/openair2/X2AP/x2ap_common.c index a687b90666..0fc63b7de5 100644 --- a/openair2/X2AP/x2ap_common.c +++ b/openair2/X2AP/x2ap_common.c @@ -47,7 +47,7 @@ ssize_t x2ap_generate_initiating_message( pdu.choice.initiatingMessage.criticality = criticality; ANY_fromType_aper((ANY_t *)&pdu.choice.initiatingMessage.value, td, sptr); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)&pdu); } @@ -79,7 +79,7 @@ ssize_t x2ap_generate_successfull_outcome( pdu.choice.successfulOutcome.criticality = criticality; ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)&pdu); } @@ -111,7 +111,7 @@ ssize_t x2ap_generate_unsuccessfull_outcome( pdu.choice.successfulOutcome.criticality = criticality; ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)&pdu); } diff --git a/openair2/X2AP/x2ap_common.h b/openair2/X2AP/x2ap_common.h index 81880cb71c..36dfe24287 100644 --- a/openair2/X2AP/x2ap_common.h +++ b/openair2/X2AP/x2ap_common.h @@ -49,8 +49,6 @@ # define X2AP_PORT 36422 #endif -extern int asn1_xer_print; - #include "common/utils/LOG/log.h" #define X2AP_INFO(x, args...) LOG_I(X2AP, x, ##args) #define X2AP_ERROR(x, args...) LOG_E(X2AP, x, ##args) diff --git a/openair2/X2AP/x2ap_eNB_decoder.c b/openair2/X2AP/x2ap_eNB_decoder.c index 6d7897bf14..81cb77dfef 100644 --- a/openair2/X2AP/x2ap_eNB_decoder.c +++ b/openair2/X2AP/x2ap_eNB_decoder.c @@ -156,7 +156,7 @@ int x2ap_eNB_decode_pdu(X2AP_X2AP_PDU_t *pdu, const uint8_t *const buffer, uint3 length, 0, 0); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, pdu); } diff --git a/openair2/X2AP/x2ap_eNB_encoder.c b/openair2/X2AP/x2ap_eNB_encoder.c index 8b1c030d35..a82eb03f9a 100644 --- a/openair2/X2AP/x2ap_eNB_encoder.c +++ b/openair2/X2AP/x2ap_eNB_encoder.c @@ -44,7 +44,7 @@ int x2ap_eNB_encode_pdu(X2AP_X2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) DevAssert(buffer != NULL); DevAssert(len != NULL); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)pdu); } diff --git a/openair2/XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake b/openair2/XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake index 3cc71e8415..cb0c762983 100644 --- a/openair2/XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake +++ b/openair2/XNAP/MESSAGES/ASN1/xnap_R16.2.0.cmake @@ -833,7 +833,6 @@ set(xnap_headers asn_SEQUENCE_OF.h asn_SET_OF.h asn_system.h - ber_decoder.h ber_tlv_length.h ber_tlv_tag.h BIT_STRING.h diff --git a/openair3/M3AP/m3ap_common.c b/openair3/M3AP/m3ap_common.c index e43275d96c..669d7eaa5e 100644 --- a/openair3/M3AP/m3ap_common.c +++ b/openair3/M3AP/m3ap_common.c @@ -47,7 +47,7 @@ ssize_t m3ap_generate_initiating_message( pdu.choice.initiatingMessage.criticality = criticality; ANY_fromType_aper((ANY_t *)&pdu.choice.initiatingMessage.value, td, sptr); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)&pdu); } @@ -80,7 +80,7 @@ ssize_t m3ap_generate_unsuccessfull_outcome( pdu.choice.successfulOutcome.criticality = criticality; ANY_fromType_aper((ANY_t *)&pdu.choice.successfulOutcome.value, td, sptr); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)&pdu); } diff --git a/openair3/M3AP/m3ap_common.h b/openair3/M3AP/m3ap_common.h index 7c8ea18a5d..f5acb6bdf5 100644 --- a/openair3/M3AP/m3ap_common.h +++ b/openair3/M3AP/m3ap_common.h @@ -48,8 +48,6 @@ # define M3AP_PORT 36444 #endif -extern int asn1_xer_print; - #include "common/utils/LOG/log.h" #include "m3ap_default_values.h" #define M3AP_INFO(x, args...) LOG_I(M3AP, x, ##args) diff --git a/openair3/M3AP/m3ap_decoder.c b/openair3/M3AP/m3ap_decoder.c index cee0a5ff41..36c8f64fae 100644 --- a/openair3/M3AP/m3ap_decoder.c +++ b/openair3/M3AP/m3ap_decoder.c @@ -188,7 +188,7 @@ int m3ap_decode_pdu(M3AP_M3AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length, 0, 0); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, pdu); } diff --git a/openair3/M3AP/m3ap_encoder.c b/openair3/M3AP/m3ap_encoder.c index 2e1cbf80af..86a710ca90 100644 --- a/openair3/M3AP/m3ap_encoder.c +++ b/openair3/M3AP/m3ap_encoder.c @@ -44,7 +44,7 @@ int m3ap_encode_pdu(M3AP_M3AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) DevAssert(buffer != NULL); DevAssert(len != NULL); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_M3AP_M3AP_PDU, (void *)pdu); } diff --git a/openair3/NAS/CMakeLists.txt b/openair3/NAS/CMakeLists.txt index 50bfe97bc3..54ccefb0f5 100644 --- a/openair3/NAS/CMakeLists.txt +++ b/openair3/NAS/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(COMMON) add_subdirectory(NR_UE) add_subdirectory(UE) +add_subdirectory(TOOLS) diff --git a/openair3/NAS/COMMON/UTIL/nas_log.h b/openair3/NAS/COMMON/UTIL/nas_log.h index 710c165440..de7b6357fe 100644 --- a/openair3/NAS/COMMON/UTIL/nas_log.h +++ b/openair3/NAS/COMMON/UTIL/nas_log.h @@ -97,6 +97,7 @@ typedef enum { #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) #ifdef LOG_E + # define LOG_TRACE(s, x, args...) \ do { \ switch (s) { \ @@ -111,9 +112,6 @@ do { \ # define LOG_FUNC_IN LOG_ENTER(NAS) # define LOG_FUNC_OUT LOG_END(NAS) # define LOG_FUNC_RETURN(rETURNcODE) LOG_RETURN(NAS,rETURNcODE) - -extern int nas_log_func_indent; - #else # define LOG_TRACE(s, x, args...) # define LOG_DUMP(dATA, lEN) LOG_DUMPMSG(NAS, LOG_DUMP_CHAR,dATA, lEN, " Dump %d:\n", lEN) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt index 0f4445c353..7aafc588e2 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt @@ -14,6 +14,7 @@ add_library(fgs_5gmm_lib OBJECT FGSUplinkNasTransport.c FGSDeregistrationRequestUEOriginating.c fgmm_authentication_failure.c + fgmm_authentication_reject.c ) target_link_libraries(fgs_5gmm_lib PUBLIC fgs_5gmm_ies_lib) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.c new file mode 100644 index 0000000000..193df8f7dd --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.c @@ -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 "fgmm_authentication_reject.h" +#include +#include // For htons and ntohs +#include // For malloc and free +#include "fgmm_lib.h" + +#define MIN_AUTH_REJECT_LEN 3 + +/** @brief Encode Authentication Reject (8.2.5 of 3GPP TS 24.501) */ +int encode_fgmm_auth_reject(byte_array_t *buffer, const fgmm_auth_reject_msg_t *msg) +{ + uint32_t encoded = 0; + + const byte_array_t *eap_msg = &msg->eap_msg; + if (eap_msg->len > 0) { + return encode_eap_msg_ie(buffer, eap_msg); + } + return encoded; +} + +/** @brief Decode Authentication Reject (8.2.5 of 3GPP TS 24.501) + * the message contains only optional IEIs (EAP MSG) */ +int decode_fgmm_auth_reject(fgmm_auth_reject_msg_t *msg, const byte_array_t *buffer) +{ + if (buffer->len < MIN_AUTH_REJECT_LEN) { + // No optional IEIs present + return 0; + } + byte_array_t ba = *buffer; // Local copy of buffer + uint32_t decoded = 0; + // Decode the IEI + uint8_t iei = buffer->buf[decoded++]; + UPDATE_BYTE_ARRAY(ba, decoded); + if (iei == IEI_EAPMSG) { + return (decoded + decode_eap_msg_ie(&msg->eap_msg, &ba)); + } + PRINT_NAS_ERROR("Expected EAP MSG but it is not present"); + return -1; +} + +bool eq_auth_reject(fgmm_auth_reject_msg_t *a, fgmm_auth_reject_msg_t *b) +{ + _NAS_EQ_CHECK_LONG(a->eap_msg.len, b->eap_msg.len); + if (a->eap_msg.len > 0) { + return !memcmp(a->eap_msg.buf, b->eap_msg.buf, a->eap_msg.len); + } + return true; +} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.h new file mode 100644 index 0000000000..33ae7a5181 --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_authentication_reject.h @@ -0,0 +1,38 @@ +/* + * 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 FGMM_AUTH_REJECT_H +#define FGMM_AUTH_REJECT_H + +#include +#include "fgmm_lib.h" +#include "common/utils/ds/byte_array.h" + +typedef struct { + // EAP Message (Optional) + byte_array_t eap_msg; +} fgmm_auth_reject_msg_t; + +int decode_fgmm_auth_reject(fgmm_auth_reject_msg_t *msg, const byte_array_t *buffer); +int encode_fgmm_auth_reject(byte_array_t *buffer, const fgmm_auth_reject_msg_t *msg); +bool eq_auth_reject(fgmm_auth_reject_msg_t *a, fgmm_auth_reject_msg_t *b); + +#endif /* FGMM_AUTH_REJECT_H */ diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c index 1b607589d9..63c6ec0d32 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.c @@ -25,8 +25,11 @@ #include // For malloc and free #include "common/utils/ds/byte_array.h" +#define IEI_LEN 1 #define GPRS_TIMER_LENGTH 3 // octets #define FGS_NAS_CAUSE_LENGTH 1 +#define MIN_EAP_MSG_LEN 7 +#define MIN_EAP_CONTENTS_LEN 4 /** * Encode PDU Session Status and PDU session reactivation result (optional IEs) @@ -152,12 +155,72 @@ bool eq_gprs_timer(const gprs_timer_t *a, const gprs_timer_t *b) return true; } -/* Decode EAP Message (todo) */ -int decode_eap_msg_ie(const byte_array_t *buffer) +/** @brief Encode EAP message IE (3GPP TS 24.501 9.11.2.2) */ +int encode_eap_msg_ie(byte_array_t *buffer, const byte_array_t *msg) { - int eap_msg_len = (buffer->buf[0] << 8) | buffer->buf[1]; - PRINT_NAS_ERROR("EAP message IE in NAS Service Reject is not handled\n"); - return eap_msg_len + 2; // content length + 2 octets for the length IE + int encoded = 0; + + // Sanity check on buffer length + if (buffer->len < MIN_EAP_MSG_LEN) { + PRINT_NAS_ERROR("Invalid buffer length %ld", buffer->len); + return -1; + } + + // Sanity check on input length + if (msg->len < MIN_EAP_CONTENTS_LEN || msg->len > MAX_EAP_CONTENTS_LEN) { + PRINT_NAS_ERROR("Invalid EAP message length %ld", msg->len); + return -1; + } + + // Encode IEI + buffer->buf[encoded++] = IEI_EAPMSG; + + // Encode length of EAP message content + uint16_t len = htons(msg->len); + memcpy(&buffer->buf[encoded], &len, sizeof(len)); + encoded += sizeof(len); + + // Encode EAP message content + memcpy(&buffer->buf[encoded], msg->buf, msg->len); + encoded += msg->len; + + return encoded; +} + +/** @brief Decode EAP message IE (3GPP TS 24.501 9.11.2.2): + length of contents and message payload */ +int decode_eap_msg_ie(byte_array_t *eap_msg, const byte_array_t *buffer) +{ + int decoded = 0; + int min_len_to_decode = MIN_EAP_MSG_LEN - IEI_LEN; + + // Check buffer length validity + if (buffer->len < min_len_to_decode) { + PRINT_NAS_ERROR("Invalid buffer for decoding EAP message IE"); + return -1; + } + + // Decode length IE + eap_msg->len = (buffer->buf[decoded] << 8) | buffer->buf[decoded + 1]; + decoded += 2; + + // Check payload length validity + if (eap_msg->len < MIN_EAP_CONTENTS_LEN || eap_msg->len > MAX_EAP_CONTENTS_LEN) { + PRINT_NAS_ERROR("Invalid EAP message length %ld", eap_msg->len); + return -1; + } + + // Check for buffer overflow + if (buffer->len < decoded + eap_msg->len) { + PRINT_NAS_ERROR("Buffer too short for EAP message: %ld < %ld", buffer->len, decoded + eap_msg->len); + return -1; + } + + // Copy EAP payload + memcpy(eap_msg->buf, &buffer->buf[decoded], eap_msg->len); + decoded += eap_msg->len; + + return decoded; } int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h index 25118f2742..8d833e74aa 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_lib.h @@ -39,6 +39,7 @@ both PDU Session Status and PDU session Reactivation Result IEs */ #define MAX_PDU_SESSION_CONTENTS_LEN 32 #define MAX_NUM_PSI 16 #define MAX_NUM_PDU_ERRORS 256 +#define MAX_EAP_CONTENTS_LEN 1500 /* This macro updates the local copy of a byte_array_t pointer used for enc/dec */ @@ -164,7 +165,8 @@ int decode_pdu_session_ie(uint8_t *psi, const byte_array_t *buffer); int encode_gprs_timer_ie(byte_array_t *buffer, nas_service_IEI_t iei, const gprs_timer_t *timer); int decode_gprs_timer_ie(gprs_timer_t *timer, const byte_array_t *buffer); bool eq_gprs_timer(const gprs_timer_t *a, const gprs_timer_t *b); -int decode_eap_msg_ie(const byte_array_t *buffer); +int decode_eap_msg_ie(byte_array_t *eap_msg, const byte_array_t *buffer); +int encode_eap_msg_ie(byte_array_t *buffer, const byte_array_t *msg); int encode_fgs_nas_cause(byte_array_t *buffer, const cause_id_t *cause); int decode_fgs_nas_cause(cause_id_t *cause, const byte_array_t *buffer); diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c index 797deede84..63e2901f61 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.c @@ -133,7 +133,7 @@ int decode_fgs_service_accept(fgs_service_accept_msg_t *msg, const byte_array_t break; case IEI_EAPMSG: - DECODE_NAS_IE(ba, decode_eap_msg_ie(&ba), decoded); + DECODE_NAS_IE(ba, decode_eap_msg_ie(&msg->eap_msg, &ba), decoded); break; default: diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h index 9f82f47eb1..c5d042b674 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_accept.h @@ -47,6 +47,9 @@ typedef struct { // T3448 Value (Optional) gprs_timer_t *t3448; + + // EAP Message (Optional) + byte_array_t eap_msg; } fgs_service_accept_msg_t; int decode_fgs_service_accept(fgs_service_accept_msg_t *msg, const byte_array_t *buffer); diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.c index 74175fda36..14078637a3 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.c @@ -59,6 +59,11 @@ int encode_fgs_service_reject(byte_array_t *buffer, const fgs_service_reject_msg ENCODE_NAS_IE(ba, encode_gprs_timer_ie(&ba, IEI_T3448_VALUE, msg->t3448), encoded); } + // EAP message (Optional) + if (msg->eap_msg) { + ENCODE_NAS_IE(ba, encode_eap_msg_ie(&ba, msg->eap_msg), encoded); + } + return encoded; } @@ -99,7 +104,7 @@ int decode_fgs_service_reject(fgs_service_reject_msg_t *msg, const byte_array_t break; case IEI_EAPMSG: - DECODE_NAS_IE(ba, decode_eap_msg_ie((const byte_array_t *)&ba), decoded); + DECODE_NAS_IE(ba, decode_eap_msg_ie(msg->eap_msg, &ba), decoded); break; case IEI_CAG_INFO_LIST: { diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.h index 61337d8525..29c8ab9b72 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/fgmm_service_reject.h @@ -35,6 +35,8 @@ typedef struct { bool has_psi_status; // T3448 Value (Optional) gprs_timer_t *t3448; + // EAP message (optional) + byte_array_t *eap_msg; } fgs_service_reject_msg_t; int decode_fgs_service_reject(fgs_service_reject_msg_t *msg, const byte_array_t *buffer); diff --git a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c index f733bdd3a5..d9f837d6b0 100644 --- a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c +++ b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c @@ -9,6 +9,7 @@ #include "fgmm_service_reject.h" #include "fgmm_authentication_failure.h" #include "FGSNASSecurityModeReject.h" +#include "fgmm_authentication_reject.h" #include "nr_nas_msg.h" void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) @@ -298,6 +299,44 @@ static void test_security_mode_reject(void) AssertFatal(eq_sec_mode_reject(&orig, &dec), "test_sec_mode_reject() failed: original and decoded messages do not match\n"); } +/** + * @brief Test NAS Authentication Reject enc/dec + */ +static void test_auth_reject(void) +{ + // Dummy NAS Authentication Reject message + uint8_t dummy_eap_msg[] = {0x12, 0x34, 0x56, 0x78, 0x91, 0x01, 0x23}; // Example EAP message + fgmm_auth_reject_msg_t orig = { + .eap_msg.len = sizeof(dummy_eap_msg), + }; + orig.eap_msg.buf = dummy_eap_msg; + + // Expected encoded data + uint8_t expected_enc[] = {0x78, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78, 0x91, 0x01, 0x23}; + + // Buffer + uint8_t buf[10] = {0}; + byte_array_t buffer = {.buf = buf, .len = sizeof(buf)}; + + // Encode + int encoded_length = encode_fgmm_auth_reject(&buffer, &orig); + AssertFatal(encoded_length >= 0, "encode_fgmm_auth_reject() failed\n"); + + // Compare the raw encoded buffer with expected encoded data + AssertFatal(encoded_length == sizeof(expected_enc), "Encoded length mismatch %d != %ld \n", encoded_length, sizeof(expected_enc)); + AssertFatal(memcmp(buffer.buf, expected_enc, encoded_length) == 0, "Encoding mismatch!\n"); + + // Decode + fgmm_auth_reject_msg_t dec = {0}; + uint8_t eap_msg[1500] = {0}; + dec.eap_msg.buf = eap_msg; + int decoded_length = decode_fgmm_auth_reject(&dec, &buffer); + AssertFatal(decoded_length >= 0, "decode_fgmm_auth_reject() failed\n"); + + // Compare original and decoded messages + AssertFatal(eq_auth_reject(&orig, &dec), "test_auth_reject() failed: original and decoded messages do not match\n"); +} + int main() { test_regression_registration_accept(); @@ -305,6 +344,7 @@ int main() test_service_accept(); test_service_reject(); test_auth_failure(); + test_auth_reject(); test_security_mode_reject(); return 0; } diff --git a/openair3/NAS/NR_UE/CMakeLists.txt b/openair3/NAS/NR_UE/CMakeLists.txt index ec391092e5..edc596fa5f 100644 --- a/openair3/NAS/NR_UE/CMakeLists.txt +++ b/openair3/NAS/NR_UE/CMakeLists.txt @@ -11,6 +11,7 @@ target_link_libraries(nr_nas PUBLIC nas_common_ies_lib nas_utils ds + UTIL ) target_include_directories(nr_nas PUBLIC . 5GS/) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 5709d482c6..d0230e0a03 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -32,6 +32,7 @@ #include "nr_nas_msg.h" #include #include "NR_NAS_defs.h" +#include #include #include #include @@ -70,12 +71,12 @@ #include "fgs_nas_utils.h" #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" +#include "fgmm_authentication_reject.h" #include "ds/byte_array.h" #include "key_nas_deriver.h" +#include "nr-uesoftmodem.h" -#define MAX_NAS_UE 4 - -static nr_ue_nas_t nr_ue_nas[MAX_NAS_UE] = {0}; +static nr_ue_nas_t nr_ue_nas[MAX_NUM_NR_UE_INST] = {0}; #define FOREACH_STATE(TYPE_DEF) \ TYPE_DEF(NAS_SECURITY_NO_SECURITY_CONTEXT, 0) \ @@ -299,7 +300,44 @@ static void nas_security_decrypt_payload(nr_ue_nas_t *nas, byte_array_t buffer, free(decrypted); } -static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t buffer, fgs_nas_msg_t msg_type) +static fgs_nas_msg_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) +{ + if (pdu_buffer == NULL) + goto error; + + /* get security header type */ + if (length < 2) + goto error; + + 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 security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t buffer) { if (nas->security_container == NULL) return NAS_SECURITY_NO_SECURITY_CONTEXT; @@ -312,9 +350,11 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t b LOG_D(NAS, "Security type is: %s\n", print_info(security_type, security_header_type_s, sizeofArray(security_header_type_s))); switch (security_type) { - case PLAIN_5GS_MSG: + case PLAIN_5GS_MSG: { + fgs_nas_msg_t msg_type = get_msg_type(buffer.buf, buffer.len); return unprotected_allowed(buffer, msg_type) ? NAS_SECURITY_UNPROTECTED : NAS_SECURITY_BAD_INPUT; break; + } case INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX: stream_security_container_delete(nas->security_container); nas->security_container = NULL; @@ -634,7 +674,7 @@ static void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) nr_ue_nas_t *get_ue_nas_info(module_id_t module_id) { - DevAssert(module_id < MAX_NAS_UE); + AssertFatal(module_id < MAX_NUM_NR_UE_INST, "Invalid module_id %d\n", module_id); if (!nr_ue_nas[module_id].uicc) { nr_ue_nas[module_id].uicc = checkUicc(module_id); nr_ue_nas[module_id].UE_id = module_id; @@ -1062,6 +1102,33 @@ static void handle_fgmm_authentication_request(nr_ue_nas_t *nas, as_nas_info_t * generateAuthenticationResp(nas, initialNasMsg, buffer->buf); } +/** @brief Handle authentication not accepted by the network + * This function assumes the message is not integrity protected, processes the received + * NAS message and logs whether a EAP-failure is enclosed. The UE enters state: 5GMM-DEREGISTERED. + * @todo The UE shall performs actions as per 5.4.1.3.5 of 3GPP TS 24.501, including + * (1) Abort any ongoing 5GMM procedure (2) Stop all active timers: T3510, T3516, T3517, + * T3519, T3520, T3521 (3) Delete stored SUCI. (4) handle EAP-failure message. */ +static void handle_authentication_reject(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *pdu, int pdu_length) +{ + LOG_E(NAS, "Received Authentication Reject message from the network\n"); + uint8_t eap_msg[MAX_EAP_CONTENTS_LEN] = {0}; + fgmm_auth_reject_msg_t msg = {.eap_msg.buf = eap_msg}; + + byte_array_t ba = {.buf = pdu + 3 /* skip header */, .len = pdu_length}; + if (decode_fgmm_auth_reject(&msg, &ba) < 0) { + LOG_E(NAS, "Could not decode Authentication Reject\n"); + return; + } + + if (msg.eap_msg.len > 0) { + /** @todo UE handling EAP-failure message (5.4.1.2.2.11 of 3GPP TS 24.501) */ + LOG_W(NAS, "NAS Authentication Reject contains an EAP message: handling is not implemented\n"); + log_hex_buffer("EAP-Failure", msg.eap_msg.buf, msg.eap_msg.len); + } + + nas->fiveGMM_state = FGS_DEREGISTERED; +} + int nas_itti_kgnb_refresh_req(instance_t instance, const uint8_t kgnb[32]) { MessageDef *message_p; @@ -1495,6 +1562,10 @@ static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length, */ void handleDownlinkNASTransport(uint8_t * pdu_buffer, int pdu_length, int instance) { + if (pdu_length < 17) { + LOG_E(NAS, "Received DL NAS Transport message too short (%d)\n", pdu_length); + return; + } uint8_t msg_type = *(pdu_buffer + 16); if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { LOG_A(NAS, "Received PDU Session Establishment Accept in DL NAS Transport\n"); @@ -1674,43 +1745,6 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * } } -static fgs_nas_msg_t get_msg_type(uint8_t *pdu_buffer, uint32_t length) -{ - if (pdu_buffer == NULL) - goto error; - - /* get security header type */ - if (length < 2) - goto error; - - 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(nr_ue_nas_t *nas, const as_nas_info_t *initial_nas_msg) { MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_UPLINK_DATA_REQ); @@ -1738,10 +1772,10 @@ static void send_nas_5gmm_ind(instance_t instance, const Guti5GSMobileIdentity_t itti_send_msg_to_task(TASK_RRC_NRUE, instance, msg); } -static void request_default_pdusession(nr_ue_nas_t *nas) +static void request_pdusession(nr_ue_nas_t *nas, int pdusession_id) { MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_PDU_SESSION_REQ); - NAS_PDU_SESSION_REQ(message_p).pdusession_id = get_softmodem_params()->default_pdu_session_id; + NAS_PDU_SESSION_REQ(message_p).pdusession_id = pdusession_id; NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6 NAS_PDU_SESSION_REQ(message_p).sst = nas->uicc->nssai_sst; NAS_PDU_SESSION_REQ(message_p).sd = nas->uicc->nssai_sd; @@ -1833,7 +1867,10 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff if (get_user_nssai_idx(msg.nas_allowed_nssai, nas) < 0) { LOG_E(NAS, "NSSAI parameters not match with allowed NSSAI. Couldn't request PDU session.\n"); } else { - request_default_pdusession(nas); + request_pdusession(nas, get_softmodem_params()->default_pdu_session_id); + if (get_nrUE_params()->extra_pdu_id != -1) { + request_pdusession(nas, get_nrUE_params()->extra_pdu_id); + } } // Free local message after processing free_fgmm_registration_accept(&msg); @@ -1970,13 +2007,13 @@ void *nas_nrue(void *args_p) NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length); byte_array_t ba = {.buf = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.nas_data, .len = NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length}; - fgs_nas_msg_t msg_type = get_msg_type(ba.buf, ba.len); - security_state_t security_state = nas_security_rx_process(nas, ba, msg_type); + security_state_t security_state = nas_security_rx_process(nas, ba); if (security_state > NAS_SECURITY_INTEGRITY_PASSED) { LOG_E(NAS, "NAS integrity failed, discard incoming message: security state is %s\n", security_state_info[security_state].text); break; } + fgs_nas_msg_t msg_type = get_msg_type(ba.buf, ba.len); if (msg_type == FGS_REGISTRATION_ACCEPT) { handle_registration_accept(nas, ba.buf, ba.len); } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { @@ -2038,13 +2075,13 @@ void *nas_nrue(void *args_p) uint8_t *pdu_buffer = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.nas_data; int pdu_length = NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length; byte_array_t buffer = {.buf = pdu_buffer, .len = pdu_length}; - fgs_nas_msg_t msg_type = get_msg_type(pdu_buffer, pdu_length); - security_state_t security_state = nas_security_rx_process(nas, buffer, msg_type); + security_state_t security_state = nas_security_rx_process(nas, buffer); if (security_state > NAS_SECURITY_INTEGRITY_PASSED) { LOG_E(NAS, "NAS integrity failed, discard incoming message\n"); break; } + fgs_nas_msg_t msg_type = get_msg_type(pdu_buffer, pdu_length); LOG_I(NAS, "[UE %ld] Received %s type %s with length %u\n", nas->UE_id, @@ -2059,6 +2096,9 @@ void *nas_nrue(void *args_p) case FGS_AUTHENTICATION_REQUEST: handle_fgmm_authentication_request(nas, &initialNasMsg, &buffer); break; + case FGS_AUTHENTICATION_REJECT: + handle_authentication_reject(nas, &initialNasMsg, pdu_buffer, pdu_length); + break; case FGS_SECURITY_MODE_COMMAND: handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length); break; @@ -2079,10 +2119,23 @@ void *nas_nrue(void *args_p) case FGS_PDU_SESSION_ESTABLISHMENT_REJ: LOG_E(NAS, "Received PDU Session Establishment reject\n"); break; - case FGS_REGISTRATION_REJECT: - LOG_E(NAS, "Received Registration reject cause: %s\n", cause_text_info[pdu_buffer[17]].text); + case FGS_REGISTRATION_REJECT: { + + if (pdu_length < 18) { + LOG_E(NAS, "Received Registration reject message too short\n"); + break; + } + + uint8_t cause = pdu_buffer[17]; + if (cause >= sizeof(cause_text_info) / sizeof(cause_text_info[0])) { + LOG_E(NAS, "Received Registration reject cause %d unknown\n", cause); + break; + } + + LOG_E(NAS, "Received Registration reject cause: %s\n", cause_text_info[cause].text); exit(1); break; + } case FGS_SERVICE_ACCEPT: { handle_service_accept(nas, &buffer); break; @@ -2107,7 +2160,7 @@ void *nas_nrue(void *args_p) case NAS_INIT_NOS1_IF: { const int pdu_session_id = get_softmodem_params()->default_pdu_session_id; - const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3"; + const char *ip = "10.0.1.2"; const int qfi = 7; create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id); set_qfi(qfi, pdu_session_id, nas->UE_id); diff --git a/openair3/NAS/TOOLS/CMakeLists.txt b/openair3/NAS/TOOLS/CMakeLists.txt new file mode 100755 index 0000000000..50058ad5bc --- /dev/null +++ b/openair3/NAS/TOOLS/CMakeLists.txt @@ -0,0 +1,31 @@ +add_library(conf2uedata_lib OBJECT + conf_emm.c + conf_user_data.c + conf_usim.c + conf_network.c + conf_user_plmn.c + conf_parser.c + fs.c + display.c + ../UE/API/USIM/usim_api.c + ../UE/API/USIM/aka_functions.c + ../COMMON/UTIL/OctetString.c + ${OPENAIR_DIR}/common/utils/mem/memory.c + ${OPENAIR_DIR}/common/utils/utils.c +) +target_link_libraries(conf2uedata_lib PUBLIC log_headers) + +add_executable(conf2uedata conf2uedata.c) +target_link_libraries(conf2uedata PRIVATE conf2uedata_lib) +set_target_properties(conf2uedata PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(conf2uedata PRIVATE LOG minimal_lib ${libconfig_LIBRARIES}) + +add_executable(usim usim.c) +target_link_libraries(usim PRIVATE conf2uedata_lib) +set_target_properties(usim PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(usim PRIVATE LOG minimal_lib ${libconfig_LIBRARIES}) + +add_executable(nvram nvram.c) +target_link_libraries(nvram PRIVATE conf2uedata_lib) +set_target_properties(nvram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(nvram PRIVATE LOG minimal_lib ${libconfig_LIBRARIES}) diff --git a/openair3/NAS/TOOLS/conf2uedata.c b/openair3/NAS/TOOLS/conf2uedata.c index 80a6933c05..d746d5ed3d 100644 --- a/openair3/NAS/TOOLS/conf2uedata.c +++ b/openair3/NAS/TOOLS/conf2uedata.c @@ -3,6 +3,7 @@ #include // memset, strncpy #include +#include "log.h" #include "conf2uedata.h" #include "display.h" #include "conf_parser.h" @@ -42,6 +43,7 @@ int main(int argc, char**argv) { exit(1); } + logInit(); if ( parse_config_file(output_dir, conf_file, OUTPUT_ALL) == false ) { exit(1); } diff --git a/openair3/NAS/TOOLS/conf_usim.c b/openair3/NAS/TOOLS/conf_usim.c index 3a5c6dbf6d..f66df1457c 100644 --- a/openair3/NAS/TOOLS/conf_usim.c +++ b/openair3/NAS/TOOLS/conf_usim.c @@ -8,301 +8,284 @@ #include "conf_usim.h" bool parse_ue_sim_param(config_setting_t *ue_setting, int user_id, usim_data_conf_t *u) { - int rc = true; - config_setting_t *ue_param_setting = NULL; - ue_param_setting = config_setting_get_member(ue_setting, SIM); - if (ue_param_setting == NULL) { - printf("Check SIM section for UE%d. EXITING...\n", user_id); - return false; - } - rc = config_setting_lookup_string(ue_param_setting, MSIN, &u->msin); - if (rc != 1 || strlen(u->msin) > 10 || strlen(u->msin) < 9) { - printf("Check SIM MSIN section for UE%d. Exiting\n", user_id); - return false; - } - rc = config_setting_lookup_string(ue_param_setting, USIM_API_K, - &u->usim_api_k); - if (rc != 1) { - printf("Check SIM USIM_API_K section for UE%d. Exiting\n", user_id); - return false; - } - rc = config_setting_lookup_string(ue_param_setting, OPC, &u->opc); - if (rc != 1) { - printf("Check SIM OPC section for UE%d. Exiting\n", user_id); - return false; - } - rc = config_setting_lookup_string(ue_param_setting, MSISDN, &u->msisdn); - if (rc != 1) { - printf("Check SIM MSISDN section for UE%d. Exiting\n", user_id); - return false; - } - return true; + int rc = true; + config_setting_t *ue_param_setting = NULL; + ue_param_setting = config_setting_get_member(ue_setting, SIM); + if (ue_param_setting == NULL) { + printf("Check SIM section for UE%d. EXITING...\n", user_id); + return false; + } + rc = config_setting_lookup_string(ue_param_setting, MSIN, &u->msin); + if (rc != 1 || strlen(u->msin) > 10 || strlen(u->msin) < 9) { + printf("Check SIM MSIN section for UE%d. Exiting\n", user_id); + return false; + } + rc = config_setting_lookup_string(ue_param_setting, USIM_API_K, &u->usim_api_k); + if (rc != 1) { + printf("Check SIM USIM_API_K section for UE%d. Exiting\n", user_id); + return false; + } + rc = config_setting_lookup_string(ue_param_setting, OPC, &u->opc); + if (rc != 1) { + printf("Check SIM OPC section for UE%d. Exiting\n", user_id); + return false; + } + rc = config_setting_lookup_string(ue_param_setting, MSISDN, &u->msisdn); + if (rc != 1) { + printf("Check SIM MSISDN section for UE%d. Exiting\n", user_id); + return false; + } + return true; } void gen_usim_data(usim_data_conf_t *u, usim_data_t *usim_data, const user_plmns_t *user_plmns, const networks_t networks) { - int hplmn_index = get_plmn_index(u->hplmn, networks); - const plmn_conf_param_t *conf = &networks.items[hplmn_index].conf; - memset(usim_data, 0, sizeof(usim_data_t)); - usim_data->imsi.length = 8; - usim_data->imsi.u.num.parity = get_msin_parity(u->msin, - conf->mcc, - conf->mnc); + int hplmn_index = get_plmn_index(u->hplmn, networks); + const plmn_conf_param_t *conf = &networks.items[hplmn_index].conf; + memset(usim_data, 0, sizeof(usim_data_t)); + usim_data->imsi.length = 8; + usim_data->imsi.u.num.parity = get_msin_parity(u->msin, conf->mcc, conf->mnc); - usim_data->imsi.u.num.digit1 = conf->mcc[0]; - usim_data->imsi.u.num.digit2 = conf->mcc[1]; - usim_data->imsi.u.num.digit3 = conf->mcc[2]; + usim_data->imsi.u.num.digit1 = conf->mcc[0]; + usim_data->imsi.u.num.digit2 = conf->mcc[1]; + usim_data->imsi.u.num.digit3 = conf->mcc[2]; - usim_data->imsi.u.num.digit4 = conf->mnc[0]; - usim_data->imsi.u.num.digit5 = conf->mnc[1]; + usim_data->imsi.u.num.digit4 = conf->mnc[0]; + usim_data->imsi.u.num.digit5 = conf->mnc[1]; - if (strlen(conf->mnc) == 2) { - usim_data->imsi.u.num.digit6 = u->msin[0]; - usim_data->imsi.u.num.digit7 = u->msin[1]; - usim_data->imsi.u.num.digit8 = u->msin[2]; - usim_data->imsi.u.num.digit9 = u->msin[3]; - usim_data->imsi.u.num.digit10 = u->msin[4]; - usim_data->imsi.u.num.digit11 = u->msin[5]; - usim_data->imsi.u.num.digit12 = u->msin[6]; - usim_data->imsi.u.num.digit13 = u->msin[7]; - usim_data->imsi.u.num.digit14 = u->msin[8]; - usim_data->imsi.u.num.digit15 = u->msin[9]; - } else { - usim_data->imsi.u.num.digit6 = conf->mnc[2]; - usim_data->imsi.u.num.digit7 = u->msin[0]; - usim_data->imsi.u.num.digit8 = u->msin[1]; - usim_data->imsi.u.num.digit9 = u->msin[2]; - usim_data->imsi.u.num.digit10 = u->msin[3]; - usim_data->imsi.u.num.digit11 = u->msin[4]; - usim_data->imsi.u.num.digit12 = u->msin[5]; - usim_data->imsi.u.num.digit13 = u->msin[6]; - usim_data->imsi.u.num.digit14 = u->msin[7]; - usim_data->imsi.u.num.digit15 = u->msin[8]; - } + if (strlen(conf->mnc) == 2) { + usim_data->imsi.u.num.digit6 = u->msin[0]; + usim_data->imsi.u.num.digit7 = u->msin[1]; + usim_data->imsi.u.num.digit8 = u->msin[2]; + usim_data->imsi.u.num.digit9 = u->msin[3]; + usim_data->imsi.u.num.digit10 = u->msin[4]; + usim_data->imsi.u.num.digit11 = u->msin[5]; + usim_data->imsi.u.num.digit12 = u->msin[6]; + usim_data->imsi.u.num.digit13 = u->msin[7]; + usim_data->imsi.u.num.digit14 = u->msin[8]; + usim_data->imsi.u.num.digit15 = u->msin[9]; + } else { + usim_data->imsi.u.num.digit6 = conf->mnc[2]; + usim_data->imsi.u.num.digit7 = u->msin[0]; + usim_data->imsi.u.num.digit8 = u->msin[1]; + usim_data->imsi.u.num.digit9 = u->msin[2]; + usim_data->imsi.u.num.digit10 = u->msin[3]; + usim_data->imsi.u.num.digit11 = u->msin[4]; + usim_data->imsi.u.num.digit12 = u->msin[5]; + usim_data->imsi.u.num.digit13 = u->msin[6]; + usim_data->imsi.u.num.digit14 = u->msin[7]; + usim_data->imsi.u.num.digit15 = u->msin[8]; + } - /* - * Ciphering and Integrity Keys - */ - usim_data->keys.ksi = KSI; - memset(&usim_data->keys.ck, 0, USIM_CK_SIZE); - memset(&usim_data->keys.ik, 0, USIM_IK_SIZE); - /* - * Higher Priority PLMN search period - */ - usim_data->hpplmn = 0x00; /* Disable timer */ + /* + * Ciphering and Integrity Keys + */ + usim_data->keys.ksi = KSI; + memset(&usim_data->keys.ck, 0, USIM_CK_SIZE); + memset(&usim_data->keys.ik, 0, USIM_IK_SIZE); + /* + * Higher Priority PLMN search period + */ + usim_data->hpplmn = 0x00; /* Disable timer */ - /* - * List of Forbidden PLMNs - */ - for (int i = 0; i < USIM_FPLMN_MAX; i++) { - memset(&usim_data->fplmn[i], 0xff, sizeof(plmn_t)); - } - if (user_plmns->forbiddens.size > 0) { - for (int i = 0; i < user_plmns->forbiddens.size; i++) { - usim_data->fplmn[i] = networks.items[user_plmns->forbiddens.items[i]].plmn; - } - } + /* + * List of Forbidden PLMNs + */ + for (int i = 0; i < USIM_FPLMN_MAX; i++) { + memset(&usim_data->fplmn[i], 0xff, sizeof(plmn_t)); + } + if (user_plmns->forbiddens.size > 0) { + for (int i = 0; i < user_plmns->forbiddens.size; i++) { + usim_data->fplmn[i] = networks.items[user_plmns->forbiddens.items[i]].plmn; + } + } - /* - * Location Information - */ - usim_data->loci.tmsi = DEFAULT_TMSI; - usim_data->loci.lai.plmn = networks.items[hplmn_index].plmn; - usim_data->loci.lai.lac = DEFAULT_LAC; - usim_data->loci.status = USIM_LOCI_NOT_UPDATED; - /* - * Packet Switched Location Information - */ - usim_data->psloci.p_tmsi = DEFAULT_P_TMSI; - usim_data->psloci.signature[0] = 0x01; - usim_data->psloci.signature[1] = 0x02; - usim_data->psloci.signature[2] = 0x03; - usim_data->psloci.rai.plmn = networks.items[hplmn_index].plmn; - usim_data->psloci.rai.lac = DEFAULT_LAC; - usim_data->psloci.rai.rac = DEFAULT_RAC; - usim_data->psloci.status = USIM_PSLOCI_NOT_UPDATED; - /* - * Administrative Data - */ - usim_data->ad.UE_Operation_Mode = USIM_NORMAL_MODE; - usim_data->ad.Additional_Info = 0xffff; - usim_data->ad.MNC_Length = strlen(conf->mnc); - /* - * EPS NAS security context - */ - usim_data->securityctx.length = 52; - usim_data->securityctx.KSIasme.type = USIM_KSI_ASME_TAG; - usim_data->securityctx.KSIasme.length = 1; - usim_data->securityctx.KSIasme.value[0] = KSI_ASME; - usim_data->securityctx.Kasme.type = USIM_K_ASME_TAG; - usim_data->securityctx.Kasme.length = USIM_K_ASME_SIZE; - memset(usim_data->securityctx.Kasme.value, 0, - usim_data->securityctx.Kasme.length); - usim_data->securityctx.ulNAScount.type = USIM_UL_NAS_COUNT_TAG; - usim_data->securityctx.ulNAScount.length = USIM_UL_NAS_COUNT_SIZE; - memset(usim_data->securityctx.ulNAScount.value, 0, - usim_data->securityctx.ulNAScount.length); - usim_data->securityctx.dlNAScount.type = USIM_DL_NAS_COUNT_TAG; - usim_data->securityctx.dlNAScount.length = USIM_DL_NAS_COUNT_SIZE; - memset(usim_data->securityctx.dlNAScount.value, 0, - usim_data->securityctx.dlNAScount.length); - usim_data->securityctx.algorithmID.type = USIM_INT_ENC_ALGORITHMS_TAG; - usim_data->securityctx.algorithmID.length = 1; - usim_data->securityctx.algorithmID.value[0] = SECURITY_ALGORITHMS; - /* - * Subcriber's Number - */ - usim_data->msisdn.length = 7; - usim_data->msisdn.number.ext = 1; - usim_data->msisdn.number.ton = MSISDN_TON_UNKNOWKN; - usim_data->msisdn.number.npi = MSISDN_NPI_ISDN_TELEPHONY; - usim_data->msisdn.conf1_record_id = 0xff; /* Not used */ - usim_data->msisdn.ext1_record_id = 0xff; /* Not used */ - int j = 0; - for (int i = 0; i < strlen(u->msisdn); i += 2) { - usim_data->msisdn.number.digit[j].msb = u->msisdn[i]; - j++; - } - j = 0; - for (int i = 1; i < strlen(u->msisdn); i += 2) { - usim_data->msisdn.number.digit[j].lsb = u->msisdn[i]; - j++; + /* + * Location Information + */ + usim_data->loci.tmsi = DEFAULT_TMSI; + usim_data->loci.lai.plmn = networks.items[hplmn_index].plmn; + usim_data->loci.lai.lac = DEFAULT_LAC; + usim_data->loci.status = USIM_LOCI_NOT_UPDATED; + /* + * Packet Switched Location Information + */ + usim_data->psloci.p_tmsi = DEFAULT_P_TMSI; + usim_data->psloci.signature[0] = 0x01; + usim_data->psloci.signature[1] = 0x02; + usim_data->psloci.signature[2] = 0x03; + usim_data->psloci.rai.plmn = networks.items[hplmn_index].plmn; + usim_data->psloci.rai.lac = DEFAULT_LAC; + usim_data->psloci.rai.rac = DEFAULT_RAC; + usim_data->psloci.status = USIM_PSLOCI_NOT_UPDATED; + /* + * Administrative Data + */ + usim_data->ad.UE_Operation_Mode = USIM_NORMAL_MODE; + usim_data->ad.Additional_Info = 0xffff; + usim_data->ad.MNC_Length = strlen(conf->mnc); + /* + * EPS NAS security context + */ + usim_data->securityctx.length = 52; + usim_data->securityctx.KSIasme.type = USIM_KSI_ASME_TAG; + usim_data->securityctx.KSIasme.length = 1; + usim_data->securityctx.KSIasme.value[0] = KSI_ASME; + usim_data->securityctx.Kasme.type = USIM_K_ASME_TAG; + usim_data->securityctx.Kasme.length = USIM_K_ASME_SIZE; + memset(usim_data->securityctx.Kasme.value, 0, usim_data->securityctx.Kasme.length); + usim_data->securityctx.ulNAScount.type = USIM_UL_NAS_COUNT_TAG; + usim_data->securityctx.ulNAScount.length = USIM_UL_NAS_COUNT_SIZE; + memset(usim_data->securityctx.ulNAScount.value, 0, usim_data->securityctx.ulNAScount.length); + usim_data->securityctx.dlNAScount.type = USIM_DL_NAS_COUNT_TAG; + usim_data->securityctx.dlNAScount.length = USIM_DL_NAS_COUNT_SIZE; + memset(usim_data->securityctx.dlNAScount.value, 0, usim_data->securityctx.dlNAScount.length); + usim_data->securityctx.algorithmID.type = USIM_INT_ENC_ALGORITHMS_TAG; + usim_data->securityctx.algorithmID.length = 1; + usim_data->securityctx.algorithmID.value[0] = SECURITY_ALGORITHMS; + /* + * Subcriber's Number + */ + usim_data->msisdn.length = 7; + usim_data->msisdn.number.ext = 1; + usim_data->msisdn.number.ton = MSISDN_TON_UNKNOWKN; + usim_data->msisdn.number.npi = MSISDN_NPI_ISDN_TELEPHONY; + usim_data->msisdn.conf1_record_id = 0xff; /* Not used */ + usim_data->msisdn.ext1_record_id = 0xff; /* Not used */ + int j = 0; + for (int i = 0; i < strlen(u->msisdn); i += 2) { + usim_data->msisdn.number.digit[j].msb = u->msisdn[i]; + j++; + } + j = 0; + for (int i = 1; i < strlen(u->msisdn); i += 2) { + usim_data->msisdn.number.digit[j].lsb = u->msisdn[i]; + j++; + } + if (strlen(u->msisdn) % 2 == 0) { + for (int i = strlen(u->msisdn) / 2; i < 10; i++) { + usim_data->msisdn.number.digit[i].msb = 0xf; + usim_data->msisdn.number.digit[i].lsb = 0xf; + } + } else { + usim_data->msisdn.number.digit[strlen(u->msisdn) / 2].lsb = 0xf; + for (int i = (strlen(u->msisdn) / 2) + 1; i < 10; i++) { + usim_data->msisdn.number.digit[i].msb = 0xf; + usim_data->msisdn.number.digit[i].lsb = 0xf; + } + } + /* + * PLMN Network Name and Operator PLMN List + */ + for (int i = 0; i < user_plmns->operators.size; i++) { + network_record_t record = networks.items[user_plmns->operators.items[i]].record; + usim_pnn_t *pnn = usim_data->pnn + i; + pnn->fullname.type = USIM_PNN_FULLNAME_TAG; + pnn->fullname.length = min(sizeof(pnn->fullname.value) - 1, strlen(record.fullname)); + memcpy(pnn->fullname.value, record.fullname + 1, pnn->fullname.length); + pnn->fullname.value[pnn->fullname.length] = 0; + pnn->shortname.type = USIM_PNN_SHORTNAME_TAG; + pnn->shortname.length = min(sizeof(pnn->shortname.value) - 1, strlen(record.shortname)); + memcpy(pnn->shortname.value, record.shortname + 1, pnn->shortname.length); + pnn->shortname.value[pnn->shortname.length] = 0; + usim_data->opl[i] = (usim_opl_t){record.plmn, record.tac_start, record.tac_end, i}; + } + if (user_plmns->operators.size < USIM_OPL_MAX) { + for (int i = user_plmns->operators.size; i < USIM_OPL_MAX; i++) { + memset(&usim_data->opl[i].plmn, 0xff, sizeof(plmn_t)); + } + } - } - if (strlen(u->msisdn) % 2 == 0) { - for (int i = strlen(u->msisdn) / 2; i < 10; i++) { - usim_data->msisdn.number.digit[i].msb = 0xf; - usim_data->msisdn.number.digit[i].lsb = 0xf; - } - } else { - usim_data->msisdn.number.digit[strlen(u->msisdn) / 2].lsb = 0xf; - for (int i = (strlen(u->msisdn) / 2) + 1; i < 10; i++) { - usim_data->msisdn.number.digit[i].msb = 0xf; - usim_data->msisdn.number.digit[i].lsb = 0xf; - } - } - /* - * PLMN Network Name and Operator PLMN List - */ - for (int i = 0; i < user_plmns->operators.size; i++) { - network_record_t record = networks.items[user_plmns->operators.items[i]].record; - usim_data->pnn[i].fullname.type = USIM_PNN_FULLNAME_TAG; - usim_data->pnn[i].fullname.length = strlen(record.fullname); - strncpy((char*) usim_data->pnn[i].fullname.value, record.fullname, - usim_data->pnn[i].fullname.length); - usim_data->pnn[i].shortname.type = USIM_PNN_SHORTNAME_TAG; - usim_data->pnn[i].shortname.length = strlen(record.shortname); - strncpy((char*) usim_data->pnn[i].shortname.value, record.shortname, - usim_data->pnn[i].shortname.length); - usim_data->opl[i].plmn = record.plmn; - usim_data->opl[i].start = record.tac_start; - usim_data->opl[i].end = record.tac_end; - usim_data->opl[i].record_id = i; - } - if (user_plmns->operators.size < USIM_OPL_MAX) { - for (int i = user_plmns->operators.size; i < USIM_OPL_MAX; i++) { - memset(&usim_data->opl[i].plmn, 0xff, sizeof(plmn_t)); - } - } + /* + * List of Equivalent HPLMNs + */ + for (int i = 0; i < user_plmns->equivalents_home.size; i++) { + usim_data->ehplmn[i] = networks.items[user_plmns->equivalents_home.items[i]].plmn; + } + if (user_plmns->equivalents_home.size < USIM_EHPLMN_MAX) { + for (int i = user_plmns->equivalents_home.size; i < USIM_EHPLMN_MAX; i++) { + memset(&usim_data->ehplmn[i], 0xff, sizeof(plmn_t)); + } + } + /* + * Home PLMN Selector with Access Technology + */ + usim_data->hplmn.plmn = networks.items[hplmn_index].plmn; + usim_data->hplmn.AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); - /* - * List of Equivalent HPLMNs - */ - for (int i = 0; i < user_plmns->equivalents_home.size; i++) { - usim_data->ehplmn[i] = networks.items[user_plmns->equivalents_home.items[i]].plmn; - } - if (user_plmns->equivalents_home.size < USIM_EHPLMN_MAX) { - for (int i = user_plmns->equivalents_home.size; i < USIM_EHPLMN_MAX; i++) { - memset(&usim_data->ehplmn[i], 0xff, sizeof(plmn_t)); - } - } - /* - * Home PLMN Selector with Access Technology - */ - usim_data->hplmn.plmn = networks.items[hplmn_index].plmn; - usim_data->hplmn.AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); + /* + * List of user controlled PLMN selector with Access Technology + */ + for (int i = 0; i < USIM_PLMN_MAX; i++) { + memset(&usim_data->plmn[i], 0xff, sizeof(plmn_t)); + } + if (user_plmns->users_controlled.size > 0) { + for (int i = 0; i < user_plmns->users_controlled.size; i++) { + usim_data->plmn[i].plmn = networks.items[user_plmns->users_controlled.items[i]].plmn; + } + } - /* - * List of user controlled PLMN selector with Access Technology - */ - for (int i = 0; i < USIM_PLMN_MAX; i++) { - memset(&usim_data->plmn[i], 0xff, sizeof(plmn_t)); - } - if (user_plmns->users_controlled.size > 0) { - for (int i = 0; i < user_plmns->users_controlled.size; i++) { - usim_data->plmn[i].plmn = networks.items[user_plmns->users_controlled.items[i]].plmn; - } - } + // List of operator controlled PLMN selector with Access Technology - // List of operator controlled PLMN selector with Access Technology - - for (int i = 0; i < USIM_OPLMN_MAX; i++) { - memset(&usim_data->oplmn[i], 0xff, sizeof(plmn_t)); - } - if (user_plmns->operators_controlled.size > 0) { - for (int i = 0; i < user_plmns->operators_controlled.size; i++) { - usim_data->oplmn[i].plmn = networks.items[user_plmns->operators_controlled.items[i]].plmn; - usim_data->oplmn[i].AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN - | USIM_ACT_EUTRAN); - } - } - /* - * EPS Location Information - */ - usim_data->epsloci.guti.gummei.plmn = - networks.items[hplmn_index].plmn; - usim_data->epsloci.guti.gummei.MMEgid = DEFAULT_MME_ID; - usim_data->epsloci.guti.gummei.MMEcode = DEFAULT_MME_CODE; - usim_data->epsloci.guti.m_tmsi = DEFAULT_M_TMSI; - usim_data->epsloci.tai.plmn = usim_data->epsloci.guti.gummei.plmn; - usim_data->epsloci.tai.tac = DEFAULT_TAC; - usim_data->epsloci.status = USIM_EPSLOCI_UPDATED; - /* - * Non-Access Stratum configuration - */ - usim_data->nasconfig.NAS_SignallingPriority.type = - USIM_NAS_SIGNALLING_PRIORITY_TAG; - usim_data->nasconfig.NAS_SignallingPriority.length = 1; - usim_data->nasconfig.NAS_SignallingPriority.value[0] = 0x00; - usim_data->nasconfig.NMO_I_Behaviour.type = USIM_NMO_I_BEHAVIOUR_TAG; - usim_data->nasconfig.NMO_I_Behaviour.length = 1; - usim_data->nasconfig.NMO_I_Behaviour.value[0] = 0x00; - usim_data->nasconfig.AttachWithImsi.type = USIM_ATTACH_WITH_IMSI_TAG; - usim_data->nasconfig.AttachWithImsi.length = 1; + for (int i = 0; i < USIM_OPLMN_MAX; i++) { + memset(&usim_data->oplmn[i], 0xff, sizeof(plmn_t)); + } + if (user_plmns->operators_controlled.size > 0) { + for (int i = 0; i < user_plmns->operators_controlled.size; i++) { + usim_data->oplmn[i].plmn = networks.items[user_plmns->operators_controlled.items[i]].plmn; + usim_data->oplmn[i].AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); + } + } + /* + * EPS Location Information + */ + usim_data->epsloci.guti.gummei.plmn = networks.items[hplmn_index].plmn; + usim_data->epsloci.guti.gummei.MMEgid = DEFAULT_MME_ID; + usim_data->epsloci.guti.gummei.MMEcode = DEFAULT_MME_CODE; + usim_data->epsloci.guti.m_tmsi = DEFAULT_M_TMSI; + usim_data->epsloci.tai.plmn = usim_data->epsloci.guti.gummei.plmn; + usim_data->epsloci.tai.tac = DEFAULT_TAC; + usim_data->epsloci.status = USIM_EPSLOCI_UPDATED; + /* + * Non-Access Stratum configuration + */ + usim_data->nasconfig.NAS_SignallingPriority.type = USIM_NAS_SIGNALLING_PRIORITY_TAG; + usim_data->nasconfig.NAS_SignallingPriority.length = 1; + usim_data->nasconfig.NAS_SignallingPriority.value[0] = 0x00; + usim_data->nasconfig.NMO_I_Behaviour.type = USIM_NMO_I_BEHAVIOUR_TAG; + usim_data->nasconfig.NMO_I_Behaviour.length = 1; + usim_data->nasconfig.NMO_I_Behaviour.value[0] = 0x00; + usim_data->nasconfig.AttachWithImsi.type = USIM_ATTACH_WITH_IMSI_TAG; + usim_data->nasconfig.AttachWithImsi.length = 1; #if defined(START_WITH_GUTI) - usim_data->nasconfig.AttachWithImsi.value[0] = 0x00; + usim_data->nasconfig.AttachWithImsi.value[0] = 0x00; #else - usim_data->nasconfig.AttachWithImsi.value[0] = 0x01; + usim_data->nasconfig.AttachWithImsi.value[0] = 0x01; #endif - usim_data->nasconfig.MinimumPeriodicSearchTimer.type = - USIM_MINIMUM_PERIODIC_SEARCH_TIMER_TAG; - usim_data->nasconfig.MinimumPeriodicSearchTimer.length = 1; - usim_data->nasconfig.MinimumPeriodicSearchTimer.value[0] = 0x00; - usim_data->nasconfig.ExtendedAccessBarring.type = - USIM_EXTENDED_ACCESS_BARRING_TAG; - usim_data->nasconfig.ExtendedAccessBarring.length = 1; - usim_data->nasconfig.ExtendedAccessBarring.value[0] = 0x00; - usim_data->nasconfig.Timer_T3245_Behaviour.type = - USIM_TIMER_T3245_BEHAVIOUR_TAG; - usim_data->nasconfig.Timer_T3245_Behaviour.length = 1; - usim_data->nasconfig.Timer_T3245_Behaviour.value[0] = 0x00; + usim_data->nasconfig.MinimumPeriodicSearchTimer.type = USIM_MINIMUM_PERIODIC_SEARCH_TIMER_TAG; + usim_data->nasconfig.MinimumPeriodicSearchTimer.length = 1; + usim_data->nasconfig.MinimumPeriodicSearchTimer.value[0] = 0x00; + usim_data->nasconfig.ExtendedAccessBarring.type = USIM_EXTENDED_ACCESS_BARRING_TAG; + usim_data->nasconfig.ExtendedAccessBarring.length = 1; + usim_data->nasconfig.ExtendedAccessBarring.value[0] = 0x00; + usim_data->nasconfig.Timer_T3245_Behaviour.type = USIM_TIMER_T3245_BEHAVIOUR_TAG; + usim_data->nasconfig.Timer_T3245_Behaviour.length = 1; + usim_data->nasconfig.Timer_T3245_Behaviour.value[0] = 0x00; - /* initialize the subscriber authentication security key */ - if (hex_string_to_hex_value(usim_data->keys.usim_api_k, - u->usim_api_k, USIM_API_K_SIZE) == -1 || - hex_string_to_hex_value(usim_data->keys.opc, - u->opc, OPC_SIZE) == -1) { - fprintf(stderr, "fix your configuration file\n"); - exit(1); - } + /* initialize the subscriber authentication security key */ + if (hex_string_to_hex_value(usim_data->keys.usim_api_k, u->usim_api_k, USIM_API_K_SIZE) == -1 + || hex_string_to_hex_value(usim_data->keys.opc, u->opc, OPC_SIZE) == -1) { + fprintf(stderr, "fix your configuration file\n"); + exit(1); + } } bool write_usim_data(const char *directory, int user_id, usim_data_t *usim_data){ - int rc; - char *filename = make_filename(directory, USIM_API_NVRAM_FILENAME, user_id); - rc = usim_api_write(filename, usim_data); - free(filename); - return rc; + int rc; + char *filename = make_filename(directory, USIM_API_NVRAM_FILENAME, user_id); + rc = usim_api_write(filename, usim_data); + free(filename); + return rc; } diff --git a/openair3/NAS/TOOLS/nvram.c b/openair3/NAS/TOOLS/nvram.c index ad39462dc9..4162e5fc58 100644 --- a/openair3/NAS/TOOLS/nvram.c +++ b/openair3/NAS/TOOLS/nvram.c @@ -42,6 +42,7 @@ Description Implements the utility used to generate data stored in the #include #include +#include "log.h" #include "conf_parser.h" #include "display.h" @@ -104,6 +105,7 @@ int main (int argc, char * const argv[]) _display_usage(argv[0]); exit(EXIT_SUCCESS); } + logInit(); /* compute default data directory if no output_dir is given */ if ( output_dir == NULL ) { diff --git a/openair3/NAS/TOOLS/usim.c b/openair3/NAS/TOOLS/usim.c index 9d74499144..40de38e4b2 100644 --- a/openair3/NAS/TOOLS/usim.c +++ b/openair3/NAS/TOOLS/usim.c @@ -42,6 +42,7 @@ Description Implements the utility used to generate data stored in the #include #include +#include "log.h" #include "conf_parser.h" #include "display.h" @@ -105,6 +106,7 @@ int main (int argc, char * const argv[]) exit(EXIT_SUCCESS); } + logInit(); /* compute default data directory if no output_dir is given */ if ( output_dir == NULL ) { output_dir = getenv(OUTPUT_DIR_ENV); diff --git a/openair3/NAS/UE/API/USIM/aka_functions.c b/openair3/NAS/UE/API/USIM/aka_functions.c index d2e3fc36c5..1f461c3bbf 100644 --- a/openair3/NAS/UE/API/USIM/aka_functions.c +++ b/openair3/NAS/UE/API/USIM/aka_functions.c @@ -303,7 +303,7 @@ void ComputeOPc(const u8 op[16], u8 op_c_pP[16]) return; } /* end of function ComputeOPc */ /*-------------------- Rijndael round subkeys ---------------------*/ -u8 roundKeys[11][4][4]; +static u8 roundKeys[11][4][4]; /*--------------------- Rijndael S box table ----------------------*/ const u8 S[256] = { 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, diff --git a/openair3/NAS/UE/EMM/Authentication.c b/openair3/NAS/UE/EMM/Authentication.c index 55b269f413..33e42e9d99 100644 --- a/openair3/NAS/UE/EMM/Authentication.c +++ b/openair3/NAS/UE/EMM/Authentication.c @@ -210,14 +210,7 @@ int emm_proc_authentication_request(nas_user_t *user, int native_ksi, int ksi, * of the core network by means of the received AUTN parameter and * request the USIM to compute RES, CK and IK for given RAND */ - if(get_softmodem_params()->usim_test == 0) - { - rc = usim_api_authenticate(&user->usim_data, rand, autn, &auts, &res, &ck, &ik); - } - else - { - rc = usim_api_authenticate_test(&user->usim_data, rand, autn, &auts, &res, &ck, &ik); - } + rc = usim_api_authenticate(&user->usim_data, rand, autn, &auts, &res, &ck, &ik); } if (rc != RETURNok) { diff --git a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c index a49f71cd4b..e497353a01 100644 --- a/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c +++ b/openair3/NAS/UE/EMM/SAP/EmmDeregisteredNormalService.c @@ -110,14 +110,7 @@ int EmmDeregisteredNormalService(nas_user_t *user, const emm_reg_t *evt) /* * Initiate the attach procedure for EPS services */ - if(get_softmodem_params()->usim_test == 0) - { - rc = emm_proc_attach(user, EMM_ATTACH_TYPE_EPS); - } - else - { - rc = emm_proc_attach(user, EMM_ATTACH_TYPE_IMSI); // CMW500 IMSI initial attach expected - } + rc = emm_proc_attach(user, EMM_ATTACH_TYPE_EPS); break; case _EMMREG_ATTACH_REQ: diff --git a/openair3/NAS/UE/EMM/emm_main.c b/openair3/NAS/UE/EMM/emm_main.c index 3deabbe9be..e934012e4c 100644 --- a/openair3/NAS/UE/EMM/emm_main.c +++ b/openair3/NAS/UE/EMM/emm_main.c @@ -51,11 +51,6 @@ Description Defines the EPS Mobility Management procedure call manager, #include "IdleMode.h" #include "common/utils/mem/oai_memory.h" -/****************************************************************************/ -/**************** E X T E R N A L D E F I N I T I O N S ****************/ -/****************************************************************************/ -extern uint8_t usim_test; - /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ /****************************************************************************/ diff --git a/openair3/NAS/UE/UEprocess.c b/openair3/NAS/UE/UEprocess.c index 1de5db45ab..2a38c6a461 100644 --- a/openair3/NAS/UE/UEprocess.c +++ b/openair3/NAS/UE/UEprocess.c @@ -72,7 +72,6 @@ static void _nas_signal_handler(int signal); static void _nas_clean(user_api_id_t *user_api_id, int net_fd); -uint8_t usim_test = 0; // FIXME user must be set up with right itti message instance // FIXME allocate user and initialize its fields nas_user_t *user = NULL; diff --git a/openair3/NGAP/ngap_common.c b/openair3/NGAP/ngap_common.c index 7b960fed0b..c3865cff10 100644 --- a/openair3/NGAP/ngap_common.c +++ b/openair3/NGAP/ngap_common.c @@ -31,8 +31,6 @@ #include "conversions.h" #include "ngap_common.h" -int asn1_xer_print = 0; - void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in) { switch (in->type) { @@ -68,6 +66,43 @@ void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in) } } +ngap_cause_t decode_ngap_cause(const NGAP_Cause_t *in) +{ + ngap_cause_t out = {0}; + switch (in->present) { + case NGAP_Cause_PR_radioNetwork: + out.type = NGAP_CAUSE_RADIO_NETWORK; + out.value = in->choice.radioNetwork; + break; + + case NGAP_Cause_PR_transport: + out.type = NGAP_CAUSE_TRANSPORT; + out.value = in->choice.transport; + break; + + case NGAP_Cause_PR_nas: + out.type = NGAP_CAUSE_NAS; + out.value = in->choice.nas; + break; + + case NGAP_Cause_PR_protocol: + out.type = NGAP_CAUSE_PROTOCOL; + out.value = in->choice.protocol; + break; + + case NGAP_Cause_PR_misc: + out.type = NGAP_CAUSE_MISC; + out.value = in->choice.misc; + break; + + default: + out.type = NGAP_CAUSE_NOTHING; + NGAP_ERROR("Unknown failure cause %d\n", in->present); + break; + } + return out; +} + nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in) { nr_guami_t out = {0}; @@ -114,3 +149,125 @@ ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_Mobility TBCD_TO_MCC_MNC(&in->servingPLMN, out.serving_plmn.mcc, out.serving_plmn.mnc, out.serving_plmn.mnc_digit_length); return out; } + +void encode_ngap_target_id(NGAP_HandoverRequiredIEs_t *out, const target_ran_node_id_t *in) +{ + out->id = NGAP_ProtocolIE_ID_id_TargetID; + out->criticality = NGAP_Criticality_reject; + out->value.present = NGAP_HandoverRequiredIEs__value_PR_TargetID; + // CHOICE Target ID: NG-RAN (M) + out->value.choice.TargetID.present = NGAP_TargetID_PR_targetRANNodeID; + asn1cCalloc(out->value.choice.TargetID.choice.targetRANNodeID, targetRan); + // Global RAN Node ID (M) + targetRan->globalRANNodeID.present = NGAP_GlobalRANNodeID_PR_globalGNB_ID; + asn1cCalloc(targetRan->globalRANNodeID.choice.globalGNB_ID, globalGnbId); + globalGnbId->gNB_ID.present = NGAP_GNB_ID_PR_gNB_ID; + MACRO_GNB_ID_TO_BIT_STRING(in->targetgNBId, &globalGnbId->gNB_ID.choice.gNB_ID); + MCC_MNC_TO_PLMNID(in->plmn_identity.mcc, in->plmn_identity.mnc, in->plmn_identity.mnc_digit_length, &globalGnbId->pLMNIdentity); + // Selected TAI (M) + INT24_TO_OCTET_STRING(in->tac, &targetRan->selectedTAI.tAC); + MCC_MNC_TO_PLMNID(in->plmn_identity.mcc, + in->plmn_identity.mnc, + in->plmn_identity.mnc_digit_length, + &targetRan->selectedTAI.pLMNIdentity); +} + +void encode_ngap_nr_cgi(NGAP_NR_CGI_t *out, const plmn_id_t *plmn, const uint32_t cell_id) +{ + out->iE_Extensions = NULL; + MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &out->pLMNIdentity); + NR_CELL_ID_TO_BIT_STRING(cell_id, &out->nRCellIdentity); +} + +pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params) +{ + pdusession_level_qos_parameter_t out = {0}; + // QFI + out.qfi = qfi; + AssertFatal(params != NULL, "QoS parameters are NULL\n"); + // QosCharacteristics + const NGAP_QosCharacteristics_t *qosChar = ¶ms->qosCharacteristics; + AssertFatal(qosChar != NULL, "QoS characteristics are NULL\n"); + if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { + AssertFatal(qosChar->choice.nonDynamic5QI != NULL, "nonDynamic5QI is NULL\n"); + out.fiveQI_type = NON_DYNAMIC; + out.fiveQI = qosChar->choice.nonDynamic5QI->fiveQI; + } else if (qosChar->present == NGAP_QosCharacteristics_PR_dynamic5QI) { + AssertFatal(qosChar->choice.dynamic5QI != NULL, "dynamic5QI is NULL\n"); + out.fiveQI_type = DYNAMIC; + out.fiveQI = *qosChar->choice.dynamic5QI->fiveQI; + } else { + AssertFatal(0, "Unsupported QoS Characteristics present value: %d\n", qosChar->present); + } + // Allocation and Retention Priority + const NGAP_AllocationAndRetentionPriority_t *arp = ¶ms->allocationAndRetentionPriority; + out.arp.priority_level = arp->priorityLevelARP; + out.arp.pre_emp_capability = arp->pre_emptionCapability; + out.arp.pre_emp_vulnerability = arp->pre_emptionVulnerability; + + return out; +} + +static gtpu_tunnel_t decode_TNLInformation(const NGAP_GTPTunnel_t *gTPTunnel_p) +{ + gtpu_tunnel_t out = {0}; + // Transport layer address + memcpy(out.addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size); + out.addr.length = gTPTunnel_p->transportLayerAddress.size - gTPTunnel_p->transportLayerAddress.bits_unused; + // GTP tunnel endpoint ID + OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, out.teid); + return out; +} + +void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf) +{ + void *decoded = NULL; + asn_codec_ctx_t ctx = {.max_stack_size = 100 * 1000}; + asn_dec_rval_t rval = aper_decode(&ctx, td, &decoded, buf.buf, buf.size, 0, 0); + if (rval.code != RC_OK) { + NGAP_ERROR("Decoding failed for %s\n", td->name); + return NULL; + } + return decoded; +} + +/** @brief Decode PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */ +bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in) +{ + void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, in); + if (!decoded) { + LOG_E(NR_RRC, "Failed to decode PDUSessionResourceSetupRequestTransfer\n"); + return false; + } + + NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceSetupRequestTransfer_t *)decoded; + for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) { + NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i]; + switch (pdusessionTransfer_ies->id) { + // UL NG-U UP TNL Information (Mandatory) + case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: + out->n3_incoming = decode_TNLInformation(pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel); + break; + + // PDU Session Type (Mandatory) + case NGAP_ProtocolIE_ID_id_PDUSessionType: + out->pdu_session_type = pdusessionTransfer_ies->value.choice.PDUSessionType; + break; + + // QoS Flow Setup Request List (Mandatory) + case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList: + out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.count; + for (int i = 0; i < out->nb_qos; i++) { + NGAP_QosFlowSetupRequestItem_t *item = pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList.list.array[i]; + out->qos[i] = fill_qos(item->qosFlowIdentifier, &item->qosFlowLevelQosParameters); + } + break; + + default: + LOG_D(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id); + } + } + ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, pdusessionTransfer); + + return true; +} diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h index 82a8fe9234..9afaf47c4b 100644 --- a/openair3/NGAP/ngap_common.h +++ b/openair3/NGAP/ngap_common.h @@ -48,9 +48,6 @@ #define NGAP_UE_ID_FMT "0x%06"PRIX32 -extern int asn_debug; -extern int asn1_xer_print; - # include "common/utils/LOG/log.h" # include "ngap_gNB_default_values.h" # define NGAP_ERROR(x, args...) LOG_E(NGAP, x, ##args) @@ -86,10 +83,16 @@ typedef int (*ngap_message_decoded_callback)(sctp_assoc_t assoc_id, uint32_t str void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in); nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in); +ngap_cause_t decode_ngap_cause(const NGAP_Cause_t *in); ngap_ambr_t decode_ngap_UEAggregateMaximumBitRate(const NGAP_UEAggregateMaximumBitRate_t *in); nssai_t decode_ngap_nssai(const NGAP_S_NSSAI_t *in); ngap_security_capabilities_t decode_ngap_security_capabilities(const NGAP_UESecurityCapabilities_t *in); ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_MobilityRestrictionList_t *in); +void encode_ngap_target_id(NGAP_HandoverRequiredIEs_t *out, const target_ran_node_id_t *in); +void encode_ngap_nr_cgi(NGAP_NR_CGI_t *out, const plmn_id_t *plmn, const uint32_t cell_id); +pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQosParameters_t *params); +void *decode_pdusession_transfer(const asn_TYPE_descriptor_t *td, const OCTET_STRING_t buf); +bool decodePDUSessionResourceSetup(pdusession_transfer_t *out, const OCTET_STRING_t in); /** @}*/ diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index ae8d806e18..b03e153486 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -55,6 +55,8 @@ #include "ngap_gNB_management_procedures.h" #include "ngap_gNB_nas_procedures.h" #include "ngap_messages_types.h" +#include "ngap_gNB_mobility_management.h" +#include "ngap_gNB_ue_context.h" #include "oai_asn1.h" #include "openair3/SECU/kdf.h" #include "queue.h" @@ -275,12 +277,252 @@ void ngap_gNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind) { AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } + /** @brief UE Mobility Management: callback for Handover Required */ +int ngap_handover_required(instance_t instance, ngap_handover_required_t *msg) +{ + DevAssert(msg != NULL); + NGAP_DEBUG("Triggered Handover Required\n"); + /* Retrieve the NGAP gNB instance associated with Mod_id */ + ngap_gNB_instance_t *ngap_gNB_instance_p = ngap_gNB_get_instance(instance); + DevAssert(ngap_gNB_instance_p != NULL); + + ngap_gNB_ue_context_t *ue_context_p = NULL; + if ((ue_context_p = ngap_get_ue_context(msg->gNB_ue_ngap_id)) == NULL) { + /* The context for this gNB ue ngap id doesn't exist in the map of gNB UEs */ + NGAP_WARN("Failed to find ue context associated with gNB ue ngap id: 0x%08x\n", msg->gNB_ue_ngap_id); + return -1; + } + + DevAssert(ue_context_p->gNB_ue_ngap_id == msg->gNB_ue_ngap_id); + + NGAP_NGAP_PDU_t *pdu = encode_ng_handover_required(msg); + DevAssert(pdu != NULL); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, pdu); + + byte_array_t out = { .buf = NULL, .len = 0 }; + if (ngap_gNB_encode_pdu(pdu, &out.buf, (uint32_t *)&out.len) < 0) { + NGAP_ERROR("Failed to encode Handover Required message\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + + /* UE associated signalling -> use the allocated stream */ + ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, + ue_context_p->amf_ref->assoc_id, + out.buf, + out.len, + ue_context_p->tx_stream); + + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return 0; +} + void ngap_gNB_init(void) { NGAP_DEBUG("Starting NGAP layer\n"); ngap_gNB_prepare_internal_data(); itti_mark_task_ready(TASK_NGAP); } +static int ngap_gNB_handover_failure(instance_t instance, const ngap_handover_failure_t *msg) +{ + ngap_gNB_ue_context_t *ue_context_p = NULL; + uint8_t *buffer = NULL; + uint32_t length; + + ngap_gNB_instance_t *ngap_gNB_instance_p = ngap_gNB_get_instance(instance); + DevAssert(msg != NULL); + DevAssert(ngap_gNB_instance_p != NULL); + + NGAP_NGAP_PDU_t *pdu = encode_ng_handover_failure(msg); + DevAssert(pdu != NULL); + + if (ngap_gNB_encode_pdu(pdu, &buffer, &length) < 0) { + NGAP_ERROR("Failed to encode HANDOVER FAILURE MESSAGE\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + + ngap_gNB_amf_data_t *amf = ngap_gNB_get_AMF_from_instance(ngap_gNB_instance_p); + if ((ue_context_p = ngap_get_ue_context_from_amf_ue_ngap_id(msg->amf_ue_ngap_id)) == NULL) { + //The context for this gNB ue ngap id doesn't exist in the map of gNB UEs + NGAP_WARN("Failed to find UE context associated with amf_ue_ngap_id=%ld\n", msg->amf_ue_ngap_id); + /*In this case there is no ue context since HO REQ might be failed at preprocessing stage itself. + * so sctp message send to AMF based on its assoc_id */ + ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, amf->assoc_id, buffer, length, 0); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + + ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, amf->assoc_id, buffer, length, amf->nextstream); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + + return 0; +} + +static int ngap_gNB_handover_request_acknowledge(instance_t instance, ngap_handover_request_ack_t *msg) +{ + byte_array_t ba = { .buf = NULL, .len = 0 }; + + /* Retrieve the NGAP gNB instance associated with Mod_id */ + ngap_gNB_instance_t *ngap = ngap_gNB_get_instance(instance); + DevAssert(msg != NULL); + DevAssert(ngap != NULL); + + NGAP_NGAP_PDU_t *pdu = encode_ng_handover_request_ack(msg); + DevAssert(pdu != NULL); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, pdu); + + if (ngap_gNB_encode_pdu(pdu, &ba.buf, (uint32_t *)&ba.len) < 0) { + NGAP_ERROR("Failed to encode Handover Request Acknowledge message\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + + // Create and store NGAP UE context + ngap_gNB_ue_context_t ue_context_p = { + .amf_ref = ngap_gNB_get_AMF_from_instance(ngap), + .gNB_ue_ngap_id = msg->gNB_ue_ngap_id, + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .gNB_instance = ngap, + .ue_state = NGAP_UE_CONNECTED, + }; + if (!ue_context_p.amf_ref) { + NGAP_ERROR("Failed to fetch AMF for current NGAP instance\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + ngap_store_ue_context(&ue_context_p); + + /* UE associated signalling -> use the allocated stream */ + ngap_gNB_itti_send_sctp_data_req(ngap->instance, ue_context_p.amf_ref->assoc_id, ba.buf, ba.len, ue_context_p.tx_stream); + NGAP_INFO("Sent Handover Request Acknowledge to AMF\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return 0; +} + +static int ngap_gNB_handover_notify(instance_t instance, const ngap_handover_notify_t *msg) +{ + LOG_D(NGAP, "Encode NGAP Handover Notify\n"); + ngap_gNB_ue_context_t *ue_context_p = NULL; + byte_array_t ba = { .buf = NULL, .len = 0}; + + /* Retrieve the NGAP gNB instance associated with Mod_id */ + ngap_gNB_instance_t *ngap_gNB_instance_p = ngap_gNB_get_instance(instance); + DevAssert(msg != NULL); + DevAssert(ngap_gNB_instance_p != NULL); + + if ((ue_context_p = ngap_get_ue_context(msg->gNB_ue_ngap_id)) == NULL) { + NGAP_ERROR("Failed to find UE context for Handover Notify: gNB_ue_ngap_id=%d\n", msg->gNB_ue_ngap_id); + return -1; + } + DevAssert(ue_context_p->gNB_ue_ngap_id == msg->gNB_ue_ngap_id); + + if (ue_context_p->amf_ue_ngap_id != msg->amf_ue_ngap_id) { + NGAP_ERROR("Failed to encode Handover Notify: unknown amf_ue_ngap_id=%ld\n", msg->amf_ue_ngap_id); + return -1; + } + + NGAP_NGAP_PDU_t *pdu = encode_ng_handover_notify(msg); + if (!pdu) { + NGAP_ERROR("Failed to encode NG Handover Notify\n"); + return -1; + } + + if (ngap_gNB_encode_pdu(pdu, &ba.buf, (uint32_t *)&ba.len) < 0) { + NGAP_ERROR("Failed to encode NG Handover Notify message\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + + /* UE associated signalling -> use the allocated stream */ + ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, + ue_context_p->amf_ref->assoc_id, + ba.buf, + ba.len, + ue_context_p->tx_stream); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + + return 0; +} + +/** @brief NGAP: Handover Cancel callback */ +static int ngap_gNB_handover_cancel(instance_t instance, const ngap_handover_cancel_t *msg) +{ + DevAssert(msg != NULL); + byte_array_t ba = {.buf = NULL, .len = 0}; + + // Retrieve NGAP gNB instance + ngap_gNB_instance_t *ngap_gNB_instance_p = ngap_gNB_get_instance(instance); + DevAssert(ngap_gNB_instance_p != NULL); + + // we must have the UE context by RAN UE NGAP ID + ngap_gNB_ue_context_t *ue_context_p = ngap_get_ue_context(msg->gNB_ue_ngap_id); + if (ue_context_p == NULL) { + NGAP_ERROR("Failed to encode Handover Cancel: no UE context for gNB_ue_ngap_id=%d\n", msg->gNB_ue_ngap_id); + return -1; + } + DevAssert(ue_context_p->gNB_ue_ngap_id == msg->gNB_ue_ngap_id); + + if (ue_context_p->amf_ue_ngap_id != msg->amf_ue_ngap_id) { + NGAP_ERROR("Failed to encode Handover Cancel: mismatched amf_ue_ngap_id=%ld\n", msg->amf_ue_ngap_id); + return -1; + } + + /* Encode NGAP PDU */ + NGAP_NGAP_PDU_t *pdu = encode_ng_handover_cancel(msg); + DevAssert(pdu != NULL); + + if (ngap_gNB_encode_pdu(pdu, &ba.buf, (uint32_t *)&ba.len) < 0) { + NGAP_ERROR("Failed to encode NG Handover Cancel message PDU\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + + /* UE-associated signalling -> use the UE's allocated SCTP stream */ + ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, + ue_context_p->amf_ref->assoc_id, + ba.buf, + ba.len, + ue_context_p->tx_stream); + + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return 0; +} + +int ngap_gNB_handle_ul_ran_status_transfer(instance_t instance, const ngap_ran_status_transfer_t *msg) +{ + NGAP_DEBUG("Triggered UL RAN Status Transfer\n"); + + ngap_gNB_instance_t *ngap_gNB_instance_p = ngap_gNB_get_instance(instance); + DevAssert(ngap_gNB_instance_p != NULL); + + ngap_gNB_ue_context_t *ue_context_p = ngap_get_ue_context(msg->gnb_ue_ngap_id); + if (!ue_context_p) { + NGAP_ERROR("Failed to find UE context for gNB_ue_ngap_id %d\n", msg->gnb_ue_ngap_id); + return -1; + } + + DevAssert(ue_context_p->gNB_ue_ngap_id == msg->gnb_ue_ngap_id); + + NGAP_NGAP_PDU_t *pdu = encode_ng_ul_ran_status_transfer(msg); + DevAssert(pdu != NULL); + + byte_array_t out = {.buf = NULL, .len = 0}; + if (ngap_gNB_encode_pdu(pdu, &out.buf, (uint32_t *)&out.len) < 0) { + NGAP_ERROR("UL RAN Status Transfer encoding failure\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + + ngap_gNB_itti_send_sctp_data_req(instance, ue_context_p->amf_ref->assoc_id, out.buf, out.len, ue_context_p->tx_stream); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return 0; +} + void *ngap_gNB_process_itti_msg(void *notUsed) { MessageDef *received_msg = NULL; int result; @@ -344,14 +586,6 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { ngap_gNB_nas_non_delivery_ind(instance, &NGAP_NAS_NON_DELIVERY_IND(received_msg)); break; - case NGAP_PATH_SWITCH_REQ: - ngap_gNB_path_switch_req(instance, &NGAP_PATH_SWITCH_REQ(received_msg)); - break; - - case NGAP_PDUSESSION_MODIFICATION_IND: - ngap_gNB_generate_PDUSESSION_Modification_Indication(instance, &NGAP_PDUSESSION_MODIFICATION_IND(received_msg)); - break; - case NGAP_UE_CONTEXT_RELEASE_COMPLETE: ngap_ue_context_release_complete(instance, &NGAP_UE_CONTEXT_RELEASE_COMPLETE(received_msg)); break; @@ -364,6 +598,33 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { ngap_gNB_pdusession_release_resp(instance, &NGAP_PDUSESSION_RELEASE_RESPONSE(received_msg)); break; + case NGAP_HANDOVER_REQUIRED: + if (ngap_handover_required(instance, &NGAP_HANDOVER_REQUIRED(received_msg)) < 0) { + NGAP_ERROR("Handover Required failure: indication to RRC is not sent!\n"); + } + break; + + case NGAP_HANDOVER_FAILURE: + ngap_gNB_handover_failure(instance, &NGAP_HANDOVER_FAILURE(received_msg)); + break; + + case NGAP_HANDOVER_REQUEST_ACKNOWLEDGE: + ngap_gNB_handover_request_acknowledge(instance, &NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(received_msg)); + free_ng_handover_req_ack(&NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(received_msg)); + break; + + case NGAP_HANDOVER_NOTIFY: + ngap_gNB_handover_notify(instance, &NGAP_HANDOVER_NOTIFY(received_msg)); + break; + + case NGAP_HANDOVER_CANCEL: + ngap_gNB_handover_cancel(instance, &NGAP_HANDOVER_CANCEL(received_msg)); + break; + + case NGAP_UL_RAN_STATUS_TRANSFER: + ngap_gNB_handle_ul_ran_status_transfer(instance, &NGAP_UL_RAN_STATUS_TRANSFER(received_msg)); + break; + default: NGAP_ERROR("Received unhandled message: %d:%s\n", ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); break; @@ -416,7 +677,7 @@ static int ngap_gNB_generate_ng_setup_request( pdu.choice.initiatingMessage->value.present = NGAP_InitiatingMessage__value_PR_NGSetupRequest; out = &pdu.choice.initiatingMessage->value.choice.NGSetupRequest; /* mandatory */ - ie = (NGAP_NGSetupRequestIEs_t *)calloc(1, sizeof(NGAP_NGSetupRequestIEs_t)); + ie = calloc_or_fail(1, sizeof(NGAP_NGSetupRequestIEs_t)); ie->id = NGAP_ProtocolIE_ID_id_GlobalRANNodeID; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_NGSetupRequestIEs__value_PR_GlobalRANNodeID; @@ -439,7 +700,7 @@ static int ngap_gNB_generate_ng_setup_request( /* optional */ if (instance_p->gNB_name) { - ie = (NGAP_NGSetupRequestIEs_t *)calloc(1, sizeof(NGAP_NGSetupRequestIEs_t)); + ie = calloc_or_fail(1, sizeof(NGAP_NGSetupRequestIEs_t)); ie->id = NGAP_ProtocolIE_ID_id_RANNodeName; ie->criticality = NGAP_Criticality_ignore; ie->value.present = NGAP_NGSetupRequestIEs__value_PR_RANNodeName; @@ -449,28 +710,28 @@ static int ngap_gNB_generate_ng_setup_request( } /* mandatory */ - ie = (NGAP_NGSetupRequestIEs_t *)calloc(1, sizeof(NGAP_NGSetupRequestIEs_t)); + ie = calloc_or_fail(1, sizeof(NGAP_NGSetupRequestIEs_t)); ie->id = NGAP_ProtocolIE_ID_id_SupportedTAList; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_NGSetupRequestIEs__value_PR_SupportedTAList; { - ta = (NGAP_SupportedTAItem_t *)calloc(1, sizeof(NGAP_SupportedTAItem_t)); + ta = (NGAP_SupportedTAItem_t *)calloc_or_fail(1, sizeof(NGAP_SupportedTAItem_t)); INT24_TO_OCTET_STRING(instance_p->tac, &ta->tAC); { for (int i = 0; i < ngap_amf_data_p->broadcast_plmn_num; ++i) { - plmn = (NGAP_BroadcastPLMNItem_t *)calloc(1, sizeof(NGAP_BroadcastPLMNItem_t)); + plmn = (NGAP_BroadcastPLMNItem_t *)calloc_or_fail(1, sizeof(NGAP_BroadcastPLMNItem_t)); ngap_plmn_t *plmn_req = &instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[i]]; plmn_id_t *plmn_id = &instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[i]].plmn; MCC_MNC_TO_TBCD(plmn_id->mcc, plmn_id->mnc, plmn_id->mnc_digit_length, &plmn->pLMNIdentity); for (int si = 0; si < plmn_req->num_nssai; si++) { - ssi = (NGAP_SliceSupportItem_t *)calloc(1, sizeof(NGAP_SliceSupportItem_t)); + ssi = (NGAP_SliceSupportItem_t *)calloc_or_fail(1, sizeof(NGAP_SliceSupportItem_t)); INT8_TO_OCTET_STRING(plmn_req->s_nssai[si].sst, &ssi->s_NSSAI.sST); const uint32_t sd = plmn_req->s_nssai[si].sd; if (sd != 0xffffff) { - ssi->s_NSSAI.sD = calloc(1, sizeof(NGAP_SD_t)); - ssi->s_NSSAI.sD->buf = calloc(3, sizeof(uint8_t)); + ssi->s_NSSAI.sD = calloc_or_fail(1, sizeof(NGAP_SD_t)); + ssi->s_NSSAI.sD->buf = calloc_or_fail(3, sizeof(uint8_t)); ssi->s_NSSAI.sD->size = 3; ssi->s_NSSAI.sD->buf[0] = (sd & 0xff0000) >> 16; ssi->s_NSSAI.sD->buf[1] = (sd & 0x00ff00) >> 8; @@ -488,7 +749,7 @@ static int ngap_gNB_generate_ng_setup_request( asn1cSeqAdd(&out->protocolIEs.list, ie); /* mandatory */ - ie = (NGAP_NGSetupRequestIEs_t *)calloc(1, sizeof(NGAP_NGSetupRequestIEs_t)); + ie = calloc_or_fail(1, sizeof(NGAP_NGSetupRequestIEs_t)); ie->id = NGAP_ProtocolIE_ID_id_DefaultPagingDRX; ie->criticality = NGAP_Criticality_ignore; ie->value.present = NGAP_NGSetupRequestIEs__value_PR_PagingDRX; @@ -498,11 +759,13 @@ static int ngap_gNB_generate_ng_setup_request( if (ngap_gNB_encode_pdu(&pdu, &buffer, &len) < 0) { NGAP_ERROR("Failed to encode NG setup request\n"); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } /* Non UE-Associated signalling -> stream = 0 */ ngap_gNB_itti_send_sctp_data_req(instance_p->instance, ngap_amf_data_p->assoc_id, buffer, len, 0); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return ret; } diff --git a/openair3/NGAP/ngap_gNB_context_management_procedures.c b/openair3/NGAP/ngap_gNB_context_management_procedures.c index 7abbec2592..7f114d5bf6 100644 --- a/openair3/NGAP/ngap_gNB_context_management_procedures.c +++ b/openair3/NGAP/ngap_gNB_context_management_procedures.c @@ -111,6 +111,7 @@ int ngap_ue_context_release_complete(instance_t instance, if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { /* Encode procedure has failed... */ NGAP_ERROR("Failed to encode UE context release complete\n"); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } @@ -125,6 +126,7 @@ int ngap_ue_context_release_complete(instance_t instance, ngap_gNB_ue_context_t *tmp = ngap_detach_ue_context(ue_release_complete_p->gNB_ue_ngap_id); if (tmp) free(tmp); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } @@ -207,6 +209,7 @@ int ngap_ue_context_release_req(instance_t instance, if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { /* Encode procedure has failed... */ NGAP_ERROR("Failed to encode UE context release complete\n"); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } @@ -215,6 +218,7 @@ int ngap_ue_context_release_req(instance_t instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } diff --git a/openair3/NGAP/ngap_gNB_decoder.c b/openair3/NGAP/ngap_gNB_decoder.c index 4b76abecbb..481cccf876 100644 --- a/openair3/NGAP/ngap_gNB_decoder.c +++ b/openair3/NGAP/ngap_gNB_decoder.c @@ -70,6 +70,12 @@ static int ngap_gNB_decode_initiating_message(NGAP_NGAP_PDU_t *pdu) { NGAP_INFO("PDUSESSIONSetup initiating message\n"); break; + case NGAP_ProcedureCode_id_HandoverPreparation: + res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); + free(res.buffer); + NGAP_INFO("Handover Preparation initiating message\n"); + break; + case NGAP_ProcedureCode_id_PDUSessionResourceModify: res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); free(res.buffer); @@ -88,6 +94,18 @@ static int ngap_gNB_decode_initiating_message(NGAP_NGAP_PDU_t *pdu) { NGAP_INFO("TODO ErrorIndication initiating message\n"); break; + case NGAP_ProcedureCode_id_HandoverResourceAllocation: + res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); + free(res.buffer); + NGAP_INFO("Handover Resource Allocation initiating message\n"); + break; + + case NGAP_ProcedureCode_id_DownlinkRANStatusTransfer: + res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); + free(res.buffer); + NGAP_INFO("DL RAN Status Transfer initiating message\n"); + break; + default: NGAP_ERROR("Unknown procedure ID (%d) for initiating message\n", (int)pdu->choice.initiatingMessage->procedureCode); @@ -119,6 +137,10 @@ static int ngap_gNB_decode_successful_outcome(NGAP_NGAP_PDU_t *pdu) { free(res.buffer); break; + case NGAP_ProcedureCode_id_HandoverPreparation: + res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); + free(res.buffer); + break; default: NGAP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n", diff --git a/openair3/NGAP/ngap_gNB_encoder.c b/openair3/NGAP/ngap_gNB_encoder.c index ee3b37e07d..be3945c2f0 100644 --- a/openair3/NGAP/ngap_gNB_encoder.c +++ b/openair3/NGAP/ngap_gNB_encoder.c @@ -52,7 +52,10 @@ static inline int ngap_gNB_encode_initiating(NGAP_NGAP_PDU_t *pdu, uint8_t **buf NGAP_ProcedureCode_id_NASNonDeliveryIndication, NGAP_ProcedureCode_id_UEContextReleaseRequest, NGAP_ProcedureCode_id_PathSwitchRequest, - NGAP_ProcedureCode_id_PDUSessionResourceModifyIndication}; + NGAP_ProcedureCode_id_PDUSessionResourceModifyIndication, + NGAP_ProcedureCode_id_UplinkRANStatusTransfer, + NGAP_ProcedureCode_id_HandoverPreparation, + NGAP_ProcedureCode_id_HandoverNotification}; int i; for (i = 0; i < sizeofArray(tmp); i++) if (pdu->choice.initiatingMessage->procedureCode == tmp[i]) @@ -76,7 +79,8 @@ static inline int ngap_gNB_encode_successfull_outcome(NGAP_NGAP_PDU_t *pdu, uint NGAP_ProcedureCode_id_UEContextRelease, NGAP_ProcedureCode_id_PDUSessionResourceSetup, NGAP_ProcedureCode_id_PDUSessionResourceModify, - NGAP_ProcedureCode_id_PDUSessionResourceRelease}; + NGAP_ProcedureCode_id_PDUSessionResourceRelease, + NGAP_ProcedureCode_id_HandoverResourceAllocation}; int i; for (i = 0; i < sizeofArray(tmp); i++) if (pdu->choice.successfulOutcome->procedureCode == tmp[i]) @@ -97,8 +101,17 @@ static inline int ngap_gNB_encode_unsuccessfull_outcome(NGAP_NGAP_PDU_t *pdu, ui { DevAssert(pdu != NULL); - if (pdu->choice.unsuccessfulOutcome->procedureCode != NGAP_ProcedureCode_id_InitialContextSetup) { - NGAP_DEBUG("Unknown procedure ID (%d) for unsuccessfull outcome message\n", (int)pdu->choice.unsuccessfulOutcome->procedureCode); + const NGAP_ProcedureCode_t id[] = {NGAP_ProcedureCode_id_InitialContextSetup, NGAP_ProcedureCode_id_HandoverResourceAllocation}; + + int i; + for (i = 0; i < sizeofArray(id); i++) { + if (pdu->choice.unsuccessfulOutcome->procedureCode == id[i]) { + break; + } + } + + if (i == sizeofArray(id)) { + NGAP_WARN("Unknown procedure ID (%ld) for successful outcome message\n", pdu->choice.successfulOutcome->procedureCode); return -1; } @@ -115,7 +128,7 @@ int ngap_gNB_encode_pdu(NGAP_NGAP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) DevAssert(pdu != NULL); DevAssert(buffer != NULL); DevAssert(len != NULL); - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, (void *)pdu); } switch (pdu->present) { @@ -135,6 +148,5 @@ int ngap_gNB_encode_pdu(NGAP_NGAP_PDU_t *pdu, uint8_t **buffer, uint32_t *len) NGAP_DEBUG("Unknown message outcome (%d) or not implemented", (int)pdu->present); return -1; } - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, pdu); return ret; } diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 3f6b718861..95c2dd45a7 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -44,7 +44,9 @@ #include "ngap_common.h" #include "ngap_gNB_decoder.h" #include "ngap_gNB_defs.h" +#include "ngap_gNB_nnsf.h" #include "ngap_gNB_management_procedures.h" +#include "ngap_gNB_mobility_management.h" #include "ngap_gNB_nas_procedures.h" #include "ngap_gNB_trace.h" #include "ngap_gNB_ue_context.h" @@ -237,7 +239,6 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str STAILQ_INSERT_TAIL(&amf_desc_p->served_guami, new_guami_p, next); } - ngap_dump_served_guami(amf_desc_p); /* Set the capacity of this AMF */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_NGSetupResponseIEs_t, ie, container, @@ -254,7 +255,7 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str memcpy(amf_desc_p->amf_name, ie->value.choice.AMFName.buf, ie->value.choice.AMFName.size); amf_desc_p->amf_name[ie->value.choice.AMFName.size] = '\0'; } - + ngap_dump_served_guami(amf_desc_p); /* mandatory set the plmn supports */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_NGSetupResponseIEs_t, ie, container, @@ -694,6 +695,42 @@ static int ngap_gNB_handle_error_indication(sctp_assoc_t assoc_id, uint32_t stre return 0; } +/** @brief Handler for NGAP Handover Request message (AMF -> target NG-RAN) + * Decode the NGAP message and transfer to RRC */ +static int ngap_gNB_handle_handover_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + ngap_gNB_amf_data_t *amf_desc_p = ngap_gNB_get_AMF(NULL, assoc_id, 0); + if (amf_desc_p == NULL) { + NGAP_ERROR("Received Handover Request for non existing AMF context\n"); + return -1; + } + + MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_HANDOVER_REQUEST); + ngap_handover_request_t *msg = &NGAP_HANDOVER_REQUEST(message_p); + memset(msg, 0, sizeof(*msg)); + + if (decode_ng_handover_request(msg, pdu) < 0) { + NGAP_ERROR("Failed to decode NG Handover Request\n"); + ngap_handover_failure_t fail = { + .amf_ue_ngap_id = msg->amf_ue_ngap_id, + .cause.type = NGAP_CAUSE_RADIO_NETWORK, + .cause.value = NGAP_CAUSE_RADIO_NETWORK_HO_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM, + }; + NGAP_INFO("Send NG Handover Failure message (amf_ue_ngap_id %ld) with cause %d \n ", fail.amf_ue_ngap_id, fail.cause.value); + MessageDef *msg_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_HANDOVER_FAILURE); + NGAP_HANDOVER_FAILURE(msg_p) = fail; + itti_send_msg_to_task(TASK_NGAP, amf_desc_p->ngap_gNB_instance->instance, msg_p); + return -1; + } + + NGAP_INFO("Received NG Handover Request from AMF %s (ID=%lu)\n", amf_desc_p->amf_name, msg->amf_ue_ngap_id); + itti_send_msg_to_task(TASK_RRC_GNB, amf_desc_p->ngap_gNB_instance->instance, message_p); + + return 0; +} + static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { int i; @@ -750,6 +787,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, false); if (ie != NULL) { msg->ue_ambr = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); + msg->has_ue_ambr = true; } /* id-GUAMI */ @@ -762,13 +800,16 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 for (i = 0; i < ie->value.choice.PDUSessionResourceSetupListCxtReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemCxtReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.array[i]; - msg->pdusession_param[i].pdusession_id = item_p->pDUSessionID; - msg->pdusession_param[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); if (item_p->nAS_PDU) { - msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + } + bool ret = decodePDUSessionResourceSetup(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + if (!ret) { + NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Initial Context Setup Request\n"); + return -1; } - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; - msg->pdusession_param[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); } } @@ -926,8 +967,11 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 /* UE Aggregated Maximum Bitrate */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, true); - msg->ueAggMaxBitRate = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); + NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, false); + if (ie != NULL) { + msg->ueAggMaxBitRate = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); + msg->has_ue_ambr = true; + } NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListSUReq, true); @@ -936,16 +980,113 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 for (int i = 0; i < ie->value.choice.PDUSessionResourceSetupListSUReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemSUReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListSUReq.list.array[i]; - msg->pdusession_setup_params[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; // S-NSSAI - msg->pdusession_setup_params[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + msg->pdusession[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; - msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); - msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); + bool ret = decodePDUSessionResourceSetup(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceSetupRequestTransfer); + if (!ret) { + NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Setup Request\n"); + return -1; + } } - itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); + itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); + + return 0; +} + +/** @brief Handler for the NG Handover Command + * AMF -> source NG-RAN */ +static int ngap_gNB_handle_handover_command(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) +{ + NGAP_INFO("Received NG Handover Command\n"); + ngap_gNB_amf_data_t *amf_desc_p = NULL; + DevAssert(pdu != NULL); + + if ((amf_desc_p = ngap_gNB_get_AMF(NULL, assoc_id, 0)) == NULL) { + NGAP_ERROR( + "[SCTP %u] Received Handover Command for non " + "existing AMF context\n", + assoc_id); + return -1; + } + + MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_HANDOVER_COMMAND); + ngap_handover_command_t *msg = &NGAP_HANDOVER_COMMAND(message_p); + memset(msg, 0, sizeof(*msg)); + if (decode_ng_handover_command(msg, pdu) < 0) { + NGAP_ERROR("Failed to decode NG Handover Command"); + free_ng_handover_command(msg); + itti_free(TASK_NGAP, message_p); + return -1; + } + + ngap_gNB_ue_context_t *ue_desc_p = ngap_get_ue_context(msg->gNB_ue_ngap_id); + if (!ue_desc_p) { + NGAP_ERROR( + "[SCTP %u] Received HO Command Msg for non existing UE context (gNB_ue_ngap_id %d) \n", + assoc_id, + msg->gNB_ue_ngap_id); + free_ng_handover_command(msg); + itti_free(TASK_NGAP, message_p); + return -1; + } + + ue_desc_p->rx_stream = stream; + + if (ue_desc_p->amf_ue_ngap_id != msg->amf_ue_ngap_id) { + NGAP_ERROR("UE context amf_ue_ngap_id is different form that of the message (%ld != %ld)", + ue_desc_p->amf_ue_ngap_id, + msg->amf_ue_ngap_id); + free_ng_handover_command(msg); + itti_free(TASK_NGAP, message_p); + return -1; + } + + NGAP_DEBUG("Handover Command is parsed with a size of: %ld. Sending to RRC GNB!\n", msg->handoverCommand.len); + itti_send_msg_to_task(TASK_RRC_GNB, amf_desc_p->ngap_gNB_instance->instance, message_p); + + return 0; +} + +/** @brief Handler for NG Handover Cancel Acknowledge */ +static int ngap_gNB_handle_handover_cancel_ack(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) +{ + NGAP_INFO("Received NG Handover Cancel Acknowledge\n"); + ngap_gNB_amf_data_t *amf_desc_p = NULL; + DevAssert(pdu != NULL); + + amf_desc_p = ngap_gNB_get_AMF(NULL, assoc_id, 0); + if (amf_desc_p == NULL) { + NGAP_ERROR("[SCTP %u] Received Handover Cancel Ack for non-existing AMF context\n", assoc_id); + return -1; + } + + MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_HANDOVER_CANCEL_ACK); + ngap_handover_cancel_ack_t *msg = &NGAP_HANDOVER_CANCEL_ACK(message_p); + + if (decode_ng_handover_cancel_ack(msg, pdu) < 0) { + NGAP_ERROR("Failed to decode NG Handover Cancel Acknowledge\n"); + itti_free(TASK_NGAP, message_p); + return -1; + } + + ngap_gNB_ue_context_t *ue_desc_p = ngap_get_ue_context(msg->gNB_ue_ngap_id); + if (!ue_desc_p) { + NGAP_ERROR("[SCTP %u] Handover Cancel Ack for unknown UE context (gNB_ue_ngap_id %d)\n", assoc_id, msg->gNB_ue_ngap_id); + itti_free(TASK_NGAP, message_p); + return -1; + } + + if (ue_desc_p->amf_ue_ngap_id != msg->amf_ue_ngap_id) { + NGAP_WARN("AMF UE NGAP ID mismatch in HO Cancel Ack (ctx %ld != msg %ld)", ue_desc_p->amf_ue_ngap_id, msg->amf_ue_ngap_id); + } + + ue_desc_p->rx_stream = stream; + + // cancel was already handled at RRC level, do not forward return 0; } @@ -1024,7 +1165,14 @@ static int ngap_gNB_handle_paging(sctp_assoc_t assoc_id, uint32_t stream, NGAP_N TBCD_TO_MCC_MNC(&(item_p->tAI.pLMNIdentity), msg->plmn_identity[i].mcc, msg->plmn_identity[i].mnc, msg->plmn_identity[i].mnc_digit_length); OCTET_STRING_TO_INT16(&(item_p->tAI.tAC), msg->tac[i]); msg->tai_size++; - NGAP_DEBUG("[SCTP %u] Received Paging: MCC %d, MNC %d, TAC %d\n", assoc_id, msg->plmn_identity[i].mcc, msg->plmn_identity[i].mnc, msg->tac[i]); + plmn_id_t *p = &msg->plmn_identity[i]; + LOG_D(NGAP, + "[SCTP %u] PLMN in TAI list for Paging: MCC=%03d, MNC=%0*d, TAC=%d\n", + assoc_id, + p->mcc, + p->mnc_digit_length, + p->mnc, + msg->tac[i]); } //paging parameter values @@ -1039,6 +1187,37 @@ static int ngap_gNB_handle_paging(sctp_assoc_t assoc_id, uint32_t stream, NGAP_N return 0; } +static bool decodePDUSessionResourceModify(pdusession_transfer_t *out, const OCTET_STRING_t in) +{ + void *decoded = decode_pdusession_transfer(&asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, in); + if (!decoded) { + LOG_E(NR_RRC, "Failed to decode PDUSessionResourceModifyRequestTransfer\n"); + return false; + } + + NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = (NGAP_PDUSessionResourceModifyRequestTransfer_t *)decoded; + for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) { + NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j]; + switch (pdusessionTransfer_ies->id) { + /* optional QosFlowAddOrModifyRequestList */ + case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList: + out->nb_qos = pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.count; + for (int i = 0; i < out->nb_qos; i++) { + NGAP_QosFlowAddOrModifyRequestItem_t *item = + pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList.list.array[i]; + out->qos[i] = fill_qos(item->qosFlowIdentifier, item->qosFlowLevelQosParameters); + } + break; + + default: + LOG_E(NR_RRC, "Unhandled optional IE %ld\n", pdusessionTransfer_ies->id); + return false; + } + } + ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, pdusessionTransfer); + return true; +} + static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) { ngap_gNB_amf_data_t *amf_desc_p = NULL; @@ -1116,13 +1295,15 @@ static int ngap_gNB_handle_pdusession_modify_request(sctp_assoc_t assoc_id, uint for (int i = 0; i < ie->value.choice.PDUSessionResourceModifyListModReq.list.count; i++) { NGAP_PDUSessionResourceModifyItemModReq_t *item_p = ie->value.choice.PDUSessionResourceModifyListModReq.list.array[i]; - msg->pdusession_modify_params[i].pdusession_id = item_p->pDUSessionID; + msg->pdusession[i].pdusession_id = item_p->pDUSessionID; // check for the NAS PDU if (item_p->nAS_PDU != NULL && item_p->nAS_PDU->size > 0) { - msg->pdusession_modify_params[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); - OCTET_STRING_t *transfer = &item_p->pDUSessionResourceModifyRequestTransfer; - msg->pdusession_modify_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); + msg->pdusession[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); + if (!decodePDUSessionResourceModify(&msg->pdusession[i].pdusessionTransfer, item_p->pDUSessionResourceModifyRequestTransfer)) { + NGAP_ERROR("Failed to decode pDUSessionResourceModifyRequestTransfer\n"); + return -1; + } } else { LOG_W(NGAP, "received pdu session modify with void content for UE %u, pdu session %lu\n", msg->gNB_ue_ngap_id, item_p->pDUSessionID); continue; @@ -1237,6 +1418,100 @@ static int ngap_gNB_handle_ng_ENDC_pdusession_modification_confirm(sctp_assoc_t return 0; } +static int ngap_gNB_handle_dl_ran_status_transfer(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + NGAP_DownlinkRANStatusTransfer_t *container = &pdu->choice.initiatingMessage->value.choice.DownlinkRANStatusTransfer; + NGAP_DownlinkRANStatusTransferIEs_t *ie = NULL; + + ngap_gNB_amf_data_t *amf_desc_p = ngap_gNB_get_AMF(NULL, assoc_id, 0); + if (!amf_desc_p) { + NGAP_ERROR("[SCTP %u] Received DL RAN Status Transfer for unknown AMF\n", assoc_id); + return -1; + } + + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id = 0; + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkRANStatusTransferIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID, true); + asn_INTEGER2ulong(&ie->value.choice.AMF_UE_NGAP_ID, &amf_ue_ngap_id); + + // RAN UE NGAP ID + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkRANStatusTransferIEs_t, ie, container, NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID, true); + NGAP_RAN_UE_NGAP_ID_t gnb_ue_ngap_id = ie->value.choice.RAN_UE_NGAP_ID; + + ngap_gNB_ue_context_t *ue_desc_p = ngap_get_ue_context(gnb_ue_ngap_id); + if (!ue_desc_p) { + NGAP_ERROR("No UE context for gNB_ue_ngap_id %lu\n", gnb_ue_ngap_id); + return -1; + } + + ue_desc_p->rx_stream = stream; + if (ue_desc_p->amf_ue_ngap_id != amf_ue_ngap_id) + NGAP_WARN("UE context mismatch: amf_ue_ngap_id (%lu != %lu)\n", ue_desc_p->amf_ue_ngap_id, amf_ue_ngap_id); + + // Transparent container + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkRANStatusTransferIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_RANStatusTransfer_TransparentContainer, + true); + NGAP_RANStatusTransfer_TransparentContainer_t *tcont = &ie->value.choice.RANStatusTransfer_TransparentContainer; + + MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_DL_RAN_STATUS_TRANSFER); + ngap_ran_status_transfer_t *msg = &NGAP_DL_RAN_STATUS_TRANSFER(message_p); + memset(msg, 0, sizeof(*msg)); + + msg->amf_ue_ngap_id = amf_ue_ngap_id; + msg->gnb_ue_ngap_id = gnb_ue_ngap_id; + + int nb = tcont->dRBsSubjectToStatusTransferList.list.count; + for (int i = 0; i < nb; ++i) { + NGAP_DRBsSubjectToStatusTransferItem_t *item = tcont->dRBsSubjectToStatusTransferList.list.array[i]; + ngap_drb_status_t *s = &msg->ran_status.drb_status_list[i]; + s->drb_id = item->dRB_ID; + + // UL COUNT + switch (item->dRBStatusUL.present) { + case NGAP_DRBStatusUL_PR_dRBStatusUL18: + s->ul_count.sn_len = NGAP_SN_LENGTH_18; + s->ul_count.pdcp_sn = item->dRBStatusUL.choice.dRBStatusUL18->uL_COUNTValue.pDCP_SN18; + s->ul_count.hfn = item->dRBStatusUL.choice.dRBStatusUL18->uL_COUNTValue.hFN_PDCP_SN18; + break; + case NGAP_DRBStatusUL_PR_dRBStatusUL12: + s->ul_count.sn_len = NGAP_SN_LENGTH_12; + s->ul_count.pdcp_sn = item->dRBStatusUL.choice.dRBStatusUL12->uL_COUNTValue.pDCP_SN12; + s->ul_count.hfn = item->dRBStatusUL.choice.dRBStatusUL12->uL_COUNTValue.hFN_PDCP_SN12; + break; + default: + NGAP_ERROR("Unknown dRBStatusUL.present=%d\n", item->dRBStatusUL.present); + break; + } + + // DL COUNT + switch (item->dRBStatusDL.present) { + case NGAP_DRBStatusDL_PR_dRBStatusDL18: + s->dl_count.sn_len = NGAP_SN_LENGTH_18; + s->dl_count.pdcp_sn = item->dRBStatusDL.choice.dRBStatusDL18->dL_COUNTValue.pDCP_SN18; + s->dl_count.hfn = item->dRBStatusDL.choice.dRBStatusDL18->dL_COUNTValue.hFN_PDCP_SN18; + break; + case NGAP_DRBStatusDL_PR_dRBStatusDL12: + s->dl_count.sn_len = NGAP_SN_LENGTH_12; + s->dl_count.pdcp_sn = item->dRBStatusDL.choice.dRBStatusDL12->dL_COUNTValue.pDCP_SN12; + s->dl_count.hfn = item->dRBStatusDL.choice.dRBStatusDL12->dL_COUNTValue.hFN_PDCP_SN12; + break; + default: + NGAP_ERROR("Unknown dRBStatusDL.present=%d\n", item->dRBStatusDL.present); + break; + } + + msg->ran_status.nb_drb++; + } + + itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); + return 0; +} + /* Handlers matrix. Only gNB related procedure present here */ const ngap_message_decoded_callback ngap_messages_callback[][3] = { {0, 0, 0}, /* AMFConfigurationUpdate */ @@ -1246,13 +1521,13 @@ const ngap_message_decoded_callback ngap_messages_callback[][3] = { {ngap_gNB_handle_nas_downlink, 0, 0}, /* DownlinkNASTransport */ {0, 0, 0}, /* DownlinkNonUEAssociatedNRPPaTransport */ {0, 0, 0}, /* DownlinkRANConfigurationTransfer */ - {0, 0, 0}, /* DownlinkRANStatusTransfer */ + {ngap_gNB_handle_dl_ran_status_transfer, 0, 0}, /* DownlinkRANStatusTransfer */ {0, 0, 0}, /* DownlinkUEAssociatedNRPPaTransport */ {ngap_gNB_handle_error_indication, 0, 0}, /* ErrorIndication */ - {0, 0, 0}, /* HandoverCancel */ + {0, ngap_gNB_handle_handover_cancel_ack, 0}, /* HandoverCancel */ {0, 0, 0}, /* HandoverNotification */ - {0, 0, 0}, /* HandoverPreparation */ - {0, 0, 0}, /* HandoverResourceAllocation */ + {0, ngap_gNB_handle_handover_command, 0}, /* HandoverPreparation */ + {ngap_gNB_handle_handover_request, 0, 0}, /* HandoverResourceAllocation */ {ngap_gNB_handle_initial_context_request, 0, 0}, /* InitialContextSetup */ {0, 0, 0}, /* InitialUEMessage */ {0, 0, 0}, /* LocationReportingControl */ diff --git a/openair3/NGAP/ngap_gNB_management_procedures.c b/openair3/NGAP/ngap_gNB_management_procedures.c index 6ffce99d9c..9d8748a88b 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.c +++ b/openair3/NGAP/ngap_gNB_management_procedures.c @@ -200,3 +200,11 @@ void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in) out->bits_unused = 0; } } + +void bitstring_to_tnl(transport_layer_addr_t *out, const BIT_STRING_t in) +{ + if (in.size) { + memcpy(out->buffer, in.buf, in.size); + out->length = in.size; + } +} diff --git a/openair3/NGAP/ngap_gNB_management_procedures.h b/openair3/NGAP/ngap_gNB_management_procedures.h index 365fd0dd9d..28f4b24e7e 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.h +++ b/openair3/NGAP/ngap_gNB_management_procedures.h @@ -50,4 +50,6 @@ void ngap_gNB_prepare_internal_data(void); void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in); +void bitstring_to_tnl(transport_layer_addr_t *out, const BIT_STRING_t in); + #endif /* NGAP_GNB_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair3/NGAP/ngap_gNB_mobility_management.c b/openair3/NGAP/ngap_gNB_mobility_management.c new file mode 100644 index 0000000000..95290f7bc3 --- /dev/null +++ b/openair3/NGAP/ngap_gNB_mobility_management.c @@ -0,0 +1,750 @@ +/* + * 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 +#include +#include +#include "conversions.h" +#include "ngap_common.h" +#include "ngap_msg_includes.h" +#include "ngap_gNB_defs.h" +#include "ngap_gNB_ue_context.h" +#include "oai_asn1.h" +#include "ngap_gNB_management_procedures.h" +#include "ngap_gNB_encoder.h" +#include "ngap_gNB_itti_messaging.h" +#include "conversions.h" + +/** @brief UE Mobility Management: encode Handover Required + * (9.2.3.1 of 3GPP TS 38.413) NG-RAN node → AMF */ +NGAP_NGAP_PDU_t *encode_ng_handover_required(const ngap_handover_required_t *msg) +{ + NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Prepare the NGAP message to encode */ + pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, head); + head->procedureCode = NGAP_ProcedureCode_id_HandoverPreparation; + head->criticality = NGAP_Criticality_reject; + head->value.present = NGAP_InitiatingMessage__value_PR_HandoverRequired; + NGAP_HandoverRequired_t *out = &head->value.choice.HandoverRequired; + + // AMF UE NGAP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequiredIEs_t, ie1); + ie1->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie1->criticality = NGAP_Criticality_reject; + ie1->value.present = NGAP_HandoverRequiredIEs__value_PR_AMF_UE_NGAP_ID; + asn_uint642INTEGER(&ie1->value.choice.AMF_UE_NGAP_ID, msg->amf_ue_ngap_id); + + // RAN UE NGAP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequiredIEs_t, ie2); + ie2->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie2->criticality = NGAP_Criticality_reject; + ie2->value.present = NGAP_HandoverRequiredIEs__value_PR_RAN_UE_NGAP_ID; + ie2->value.choice.RAN_UE_NGAP_ID = msg->gNB_ue_ngap_id; + + // Handover Type (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequiredIEs_t, ie3); + ie3->id = NGAP_ProtocolIE_ID_id_HandoverType; + ie3->criticality = NGAP_Criticality_reject; + ie3->value.present = NGAP_HandoverRequiredIEs__value_PR_HandoverType; + ie3->value.choice.HandoverType = msg->handoverType; + + // Cause (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequiredIEs_t, ie4); + ie4->id = NGAP_ProtocolIE_ID_id_Cause; + ie4->criticality = NGAP_Criticality_ignore; + ie4->value.present = NGAP_HandoverRequiredIEs__value_PR_Cause; + encode_ngap_cause(&ie4->value.choice.Cause, &msg->cause); + + // Target ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequiredIEs_t, ie5); + encode_ngap_target_id(ie5, &msg->target_gnb_id); + + // PDU Session Resource List (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequiredIEs_t, ie6); + ie6->id = NGAP_ProtocolIE_ID_id_PDUSessionResourceListHORqd; + ie6->criticality = NGAP_Criticality_reject; + ie6->value.present = NGAP_HandoverRequiredIEs__value_PR_PDUSessionResourceListHORqd; + for (int i = 0; i < msg->nb_of_pdusessions; ++i) { + asn1cSequenceAdd(ie6->value.choice.PDUSessionResourceListHORqd.list, NGAP_PDUSessionResourceItemHORqd_t, hoRequiredPduSession); + // PDU Session ID (M) + hoRequiredPduSession->pDUSessionID = msg->pdusessions[i].pdusession_id; + // Handover Required Transfer (M) - ASN.1 encoding of empty transfer structure + // This is a mandatory field in the NGAP Handover Required message, however it contains + // only Direct Forwarding Path Availability IE, which is optional and is not sent + NGAP_HandoverRequiredTransfer_t hoRequiredTransfer = {0}; + uint8_t ho_req_transfer_transparent_container_buffer[128] = {0}; + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NGAP_HandoverRequiredTransfer, &hoRequiredTransfer); + asn_enc_rval_t enc_rval = aper_encode_to_buffer(&asn_DEF_NGAP_HandoverRequiredTransfer, + NULL, + &hoRequiredTransfer, + ho_req_transfer_transparent_container_buffer, + 128); + AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded); + hoRequiredPduSession->handoverRequiredTransfer.buf = CALLOC(1, (enc_rval.encoded + 7) / 8); + memcpy(hoRequiredPduSession->handoverRequiredTransfer.buf, + ho_req_transfer_transparent_container_buffer, + (enc_rval.encoded + 7) / 8); + hoRequiredPduSession->handoverRequiredTransfer.size = (enc_rval.encoded + 7) / 8; + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_HandoverRequiredTransfer, &hoRequiredTransfer); + } + + // Source NG-RAN Node to Target NG-RAN Node Transparent Container (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequiredIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_SourceToTarget_TransparentContainer; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequiredIEs__value_PR_SourceToTarget_TransparentContainer; + + NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer_t *source2target = calloc_or_fail(1, sizeof(*source2target)); + + // RRC Container (M) (HandoverPreparationInformation) + source2target->rRCContainer.size = msg->source2target->handoverInfo.len; + source2target->rRCContainer.buf = malloc_or_fail(msg->source2target->handoverInfo.len); + memcpy(source2target->rRCContainer.buf, msg->source2target->handoverInfo.buf, source2target->rRCContainer.size); + + // PDU Session Resource Information List (O) + asn1cCalloc(source2target->pDUSessionResourceInformationList, pduSessionList); + for (uint16_t i = 0; i < msg->nb_of_pdusessions; ++i) { + const pdusession_resource_t *pduSession = &msg->pdusessions[i]; + NGAP_DEBUG("Handover Required: preparing PDU Session Resource Information List for PDU Session ID %d\n", + pduSession->pdusession_id); + asn1cSequenceAdd(pduSessionList->list, NGAP_PDUSessionResourceInformationItem_t, item); + // PDU Session ID (M) + item->pDUSessionID = msg->source2target->pdu_session_resource[i].pdusession_id; + // QoS Flow Information List (M) + for (int q = 0; q < msg->source2target->pdu_session_resource[i].nb_of_qos_flow; ++q) { + asn1cSequenceAdd(item->qosFlowInformationList.list, NGAP_QosFlowInformationItem_t, qosFlowInfo); + qosFlowInfo->qosFlowIdentifier = msg->source2target->pdu_session_resource[i].qos_flow_info[q].qfi; + } + } + + // Target Cell ID (NG-RAN CGI) (M) + source2target->targetCell_ID.present = NGAP_NGRAN_CGI_PR_nR_CGI; + asn1cCalloc(source2target->targetCell_ID.choice.nR_CGI, tNrCGI); + encode_ngap_nr_cgi(tNrCGI, &msg->target_gnb_id.plmn_identity, msg->source2target->targetCellId.nrCellIdentity); + + // UE history Information (M) + asn1cSequenceAdd(source2target->uEHistoryInformation.list, NGAP_LastVisitedCellItem_t, lastVisitedCell); + lastVisitedCell->iE_Extensions = NULL; + // Last Visited Cell Information (M) + lastVisitedCell->lastVisitedCellInformation.present = NGAP_LastVisitedCellInformation_PR_nGRANCell; + // CHOICE (M): NG-RAN Cell + asn1cCalloc(lastVisitedCell->lastVisitedCellInformation.choice.nGRANCell, lastVisitedNR); + // Cell Type (M) + lastVisitedNR->cellType.cellSize = msg->source2target->ue_history_info.type; + // Global Cell ID (M) + lastVisitedNR->globalCellID.present = NGAP_NGRAN_CGI_PR_nR_CGI; + asn1cCalloc(lastVisitedNR->globalCellID.choice.nR_CGI, lastVisitedNrCGI); + cell_id_t *cell = &msg->source2target->ue_history_info.id; + encode_ngap_nr_cgi(lastVisitedNrCGI, &cell->plmn_identity, cell->nrCellIdentity); + // HO Cause Value (O) + if (msg->source2target->ue_history_info.cause) { + asn1cCalloc(lastVisitedNR->hOCauseValue, lastVisitedCause); + encode_ngap_cause(lastVisitedCause, msg->source2target->ue_history_info.cause); + } + // Time UE Stayed in Cell (M) + lastVisitedNR->timeUEStayedInCell = msg->source2target->ue_history_info.time_in_cell; + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, source2target); + + uint8_t source_to_target_transparent_container_buf[16384] = {0}; + asn_enc_rval_t enc_rval = aper_encode_to_buffer(&asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, + NULL, + (void *)source2target, + (void *)&source_to_target_transparent_container_buf, + 16384); + ASN_STRUCT_FREE(asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, source2target); + if (enc_rval.encoded < 0) { + AssertFatal(enc_rval.encoded > 0, + "HO LOG: Source to Transparent ASN1 message encoding failed (%s, %lu)!\n", + enc_rval.failed_type->name, + enc_rval.encoded); + return NULL; + } + + int total_bytes = (enc_rval.encoded + 7) / 8; + int ret = OCTET_STRING_fromBuf(&ie->value.choice.SourceToTarget_TransparentContainer, + (const char *)&source_to_target_transparent_container_buf, + total_bytes); + if (ret != 0) { + LOG_E(NR_RRC, "HO LOG: Can not perform OCTET_STRING_fromBuf for the SourceToTarget_TransparentContainer"); + return NULL; + } + + return pdu; +} + +NGAP_NGAP_PDU_t *encode_ng_handover_failure(const ngap_handover_failure_t *msg) +{ + NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Prepare the NGAP message to encode */ + pdu->present = NGAP_NGAP_PDU_PR_unsuccessfulOutcome; + asn1cCalloc(pdu->choice.unsuccessfulOutcome, head); + head->procedureCode = NGAP_ProcedureCode_id_HandoverResourceAllocation; + head->criticality = NGAP_Criticality_reject; + head->value.present = NGAP_UnsuccessfulOutcome__value_PR_HandoverFailure; + NGAP_HandoverFailure_t *out = &head->value.choice.HandoverFailure; + + // AMF_UE_NGAP_ID (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverFailureIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverFailureIEs__value_PR_AMF_UE_NGAP_ID; + asn_uint642INTEGER(&ie->value.choice.AMF_UE_NGAP_ID, msg->amf_ue_ngap_id); + } + + // Cause (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverFailureIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_Cause; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverFailureIEs__value_PR_Cause; + encode_ngap_cause(&ie->value.choice.Cause, &msg->cause); + } + + return pdu; +} + +static void free_ng_handover_request(ngap_handover_request_t *msg) +{ + free_byte_array(msg->ue_ho_prep_info); + free_byte_array(msg->ue_cap); + free(msg->mobility_restriction); +} + +int decode_ng_handover_request(ngap_handover_request_t *out, const NGAP_NGAP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + NGAP_HandoverRequest_t *container = &pdu->choice.initiatingMessage->value.choice.HandoverRequest; + NGAP_HandoverRequestIEs_t *ie; + + // Handover Type (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_HandoverType, true); + out->ho_type = ie->value.choice.HandoverType; + if (out->ho_type != HANDOVER_TYPE_INTRA5GS) { + NGAP_ERROR("Only Intra5GS Handover is supported at the moment!\n"); + return -1; + } + + // AMF UE NGAP ID (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID, true); + asn_INTEGER2ulong(&(ie->value.choice.AMF_UE_NGAP_ID), &out->amf_ue_ngap_id); + + // GUAMI (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_GUAMI, true); + out->guami = decode_ngap_guami(&ie->value.choice.GUAMI); + + // UE Aggregate Maximum Bit Rate (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, true); + out->ue_ambr = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); + + // Allowed NSSAI (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AllowedNSSAI, true); + NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); + out->nb_allowed_nssais = ie->value.choice.AllowedNSSAI.list.count; + for (int i = 0; i < out->nb_allowed_nssais; i++) { + out->allowed_nssai[i] = decode_ngap_nssai(&ie->value.choice.AllowedNSSAI.list.array[i]->s_NSSAI); + } + + // UE Security Capabilities (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true); + out->security_capabilities = decode_ngap_security_capabilities(&ie->value.choice.UESecurityCapabilities); + + // Security Context (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityContext, true); + NGAP_SecurityContext_t *sc = &ie->value.choice.SecurityContext; + memcpy(&out->security_context.next_hop, sc->nextHopNH.buf, sc->nextHopNH.size); + out->security_context.next_hop_chain_count = sc->nextHopChainingCount; + + // Mobility Restriction List (O) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_MobilityRestrictionList, false); + if (ie != NULL) { + out->mobility_restriction = calloc_or_fail(1, sizeof(*out->mobility_restriction)); + *out->mobility_restriction = decode_ngap_mobility_restriction(&ie->value.choice.MobilityRestrictionList); + } + + // Cause (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_Cause, true); + out->cause = decode_ngap_cause(&ie->value.choice.Cause); + + // Source to Target Transparent Container + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_SourceToTarget_TransparentContainer, + true); + NGAP_SourceToTarget_TransparentContainer_t *choice = &ie->value.choice.SourceToTarget_TransparentContainer; + byte_array_t sourceToTargetTransparentContainer = create_byte_array(choice->size, choice->buf); + NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer_t *source2target = NULL; + asn_dec_rval_t dec_rval = aper_decode_complete(NULL, + &asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, + (void **)&source2target, + sourceToTargetTransparentContainer.buf, + sourceToTargetTransparentContainer.len); + + free_byte_array(sourceToTargetTransparentContainer); + if (dec_rval.code != RC_OK) { + free_ng_handover_request(out); + NGAP_ERROR("Failed to decode sourceToTargetTransparentContainer\n"); + return -1; + } + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, source2target); + + // Extract Cell Identity + BIT_STRING_TO_NR_CELL_IDENTITY(&source2target->targetCell_ID.choice.nR_CGI->nRCellIdentity, out->nr_cell_id); + + // Handover Preparation Information: store and decode + out->ue_ho_prep_info = create_byte_array(source2target->rRCContainer.size, source2target->rRCContainer.buf); + NR_HandoverPreparationInformation_t *hoPrepInformation = NULL; + asn_dec_rval_t hoPrep_dec_rval = uper_decode_complete(NULL, + &asn_DEF_NR_HandoverPreparationInformation, + (void **)&hoPrepInformation, + source2target->rRCContainer.buf, + source2target->rRCContainer.size); + AssertFatal(hoPrep_dec_rval.code == RC_OK && hoPrep_dec_rval.consumed > 0, "Handover Prep Info decode error\n"); + if (hoPrep_dec_rval.code != RC_OK && !hoPrep_dec_rval.consumed) { + NGAP_ERROR("Failed to decode HandoverPreparationInformation, abort Handover Request decoding\n"); + free_ng_handover_request(out); + ASN_STRUCT_FREE(asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, source2target); + return -1; + } + + ASN_STRUCT_FREE(asn_DEF_NGAP_SourceNGRANNode_ToTargetNGRANNode_TransparentContainer, source2target); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_HandoverPreparationInformation, hoPrepInformation); + + // Decode UE capabilities and store + NR_HandoverPreparationInformation_IEs_t *hpi = + hoPrepInformation->criticalExtensions.choice.c1->choice.handoverPreparationInformation; + const NR_UE_CapabilityRAT_ContainerList_t *ue_CapabilityRAT_ContainerList = &hpi->ue_CapabilityRAT_List; + out->ue_cap.len = uper_encode_to_new_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, + NULL, + ue_CapabilityRAT_ContainerList, + (void **)&out->ue_cap.buf); + + ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hoPrepInformation); + + if (out->ue_cap.len <= 0) { + free_ng_handover_request(out); + NGAP_ERROR("could not encode UE-CapabilityRAT-ContainerList\n"); + return -1; + } + + // PDU Session Resource Setup List (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListHOReq, + true); + out->nb_of_pdusessions = ie->value.choice.PDUSessionResourceSetupListHOReq.list.count; + for (int pduSesIdx = 0; pduSesIdx < out->nb_of_pdusessions; ++pduSesIdx) { + NGAP_PDUSessionResourceSetupItemHOReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListHOReq.list.array[pduSesIdx]; + // PDU Session ID (M) + ho_request_pdusession_t *setup = &out->pduSessionResourceSetupList[pduSesIdx]; + setup->pdusession_id = item_p->pDUSessionID; + setup->pdu_session_type = PDUSessionType_ipv4; + // S-NSSAI (M) + setup->nssai = decode_ngap_nssai(&item_p->s_NSSAI); + // Handover Request Transfer (M) + bool ret = decodePDUSessionResourceSetup(&setup->pdusessionTransfer, item_p->handoverRequestTransfer); + if (!ret) { + free_ng_handover_request(out); + NGAP_ERROR("Failed to decode pDUSessionResourceSetupRequestTransfer in NG Initial Context Setup Request\n"); + return -1; + } + } + return 0; +} + +NGAP_NGAP_PDU_t *encode_ng_handover_request_ack(ngap_handover_request_ack_t *msg) +{ + NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + pdu->present = NGAP_NGAP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, head); + head->procedureCode = NGAP_ProcedureCode_id_HandoverResourceAllocation; + head->criticality = NGAP_Criticality_reject; + head->value.present = NGAP_SuccessfulOutcome__value_PR_HandoverRequestAcknowledge; + NGAP_HandoverRequestAcknowledge_t *out = &head->value.choice.HandoverRequestAcknowledge; + + // AMF UE NGAP ID (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequestAcknowledgeIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverRequestAcknowledgeIEs__value_PR_AMF_UE_NGAP_ID; + asn_uint642INTEGER(&ie->value.choice.AMF_UE_NGAP_ID, msg->amf_ue_ngap_id); + } + + // RAN UE NGAP ID (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequestAcknowledgeIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverRequestAcknowledgeIEs__value_PR_RAN_UE_NGAP_ID; + ie->value.choice.RAN_UE_NGAP_ID = msg->gNB_ue_ngap_id; + } + + // Target to Source Transparent Container (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequestAcknowledgeIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_TargetToSource_TransparentContainer; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequestAcknowledgeIEs__value_PR_TargetToSource_TransparentContainer; + NGAP_TargetNGRANNode_ToSourceNGRANNode_TransparentContainer_t *t2s = calloc_or_fail(1, sizeof(*t2s)); + // RRC Container (M) + { + // Encode Handover Command + t2s->rRCContainer.size = msg->target2source.len; + t2s->rRCContainer.buf = malloc_or_fail(msg->target2source.len); + memcpy(t2s->rRCContainer.buf, msg->target2source.buf, msg->target2source.len); + byte_array_t ba = { .buf = NULL, .len = 0 }; + ba.len = aper_encode_to_new_buffer(&asn_DEF_NGAP_TargetNGRANNode_ToSourceNGRANNode_TransparentContainer, NULL, t2s, (void **)&ba.buf); + OCTET_STRING_fromBuf(&ie->value.choice.TargetToSource_TransparentContainer, (const char *)ba.buf, ba.len); + ASN_STRUCT_FREE(asn_DEF_NGAP_TargetNGRANNode_ToSourceNGRANNode_TransparentContainer, t2s); + free_byte_array(ba); + } + } + + // PDU Session Resource Admitted List (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverRequestAcknowledgeIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_PDUSessionResourceAdmittedList; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverRequestAcknowledgeIEs__value_PR_PDUSessionResourceAdmittedList; + + for (int pduSesIdx = 0; pduSesIdx < msg->nb_of_pdusessions; pduSesIdx++) { + asn1cSequenceAdd(ie->value.choice.PDUSessionResourceAdmittedList.list, NGAP_PDUSessionResourceAdmittedItem_t, item); + item->pDUSessionID = msg->pdusessions[pduSesIdx].pdu_session_id; + /* dLQosFlowPerTNLInformation */ + NGAP_HandoverRequestAcknowledgeTransfer_t transfer = {0}; + transfer.dL_NGU_UP_TNLInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc(transfer.dL_NGU_UP_TNLInformation.choice.gTPTunnel, tmp); + GTP_TEID_TO_ASN1(msg->pdusessions[pduSesIdx].ack_transfer.gtp_teid, &tmp->gTP_TEID); + tnl_to_bitstring(&tmp->transportLayerAddress, msg->pdusessions[pduSesIdx].ack_transfer.gNB_addr); + + for (int j = 0; j < msg->pdusessions[pduSesIdx].ack_transfer.nb_of_qos_flow; j++) { + asn1cSequenceAdd(transfer.qosFlowSetupResponseList.list, NGAP_QosFlowItemWithDataForwarding_t, qosItem); + qosItem->qosFlowIdentifier = msg->pdusessions[pduSesIdx].ack_transfer.qos_setup_list[j].qfi; + qosItem->dataForwardingAccepted = calloc_or_fail(1, sizeof(*qosItem->dataForwardingAccepted)); + *qosItem->dataForwardingAccepted = NGAP_DataForwardingAccepted_data_forwarding_accepted; + } + + void *buf; + ssize_t encoded = aper_encode_to_new_buffer(&asn_DEF_NGAP_HandoverRequestAcknowledgeTransfer, NULL, &transfer, &buf); + AssertFatal(encoded > 0, "ASN1 message encoding failed !\n"); + item->handoverRequestAcknowledgeTransfer.buf = buf; + item->handoverRequestAcknowledgeTransfer.size = encoded; + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_HandoverRequestAcknowledgeTransfer, &transfer); + } + } + + return pdu; +} + +void free_ng_handover_req_ack(ngap_handover_request_ack_t *msg) +{ + free_byte_array(msg->target2source); +} + +/** @brief Decoder for the NG Handover Command */ +int decode_ng_handover_command(ngap_handover_command_t *msg, NGAP_NGAP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + NGAP_HandoverCommandIEs_t *ie; + NGAP_HandoverCommand_t *container = &pdu->choice.successfulOutcome->value.choice.HandoverCommand; + + // AMF UE NGAP ID (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID, true); + asn_INTEGER2ulong(&(ie->value.choice.AMF_UE_NGAP_ID), &msg->amf_ue_ngap_id); + + // RAN UE NGAP ID (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID, true); + msg->gNB_ue_ngap_id = ie->value.choice.RAN_UE_NGAP_ID; + + // Handover Type (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_HandoverType, true); + if (ie->value.choice.HandoverType != HANDOVER_TYPE_INTRA5GS) { + NGAP_ERROR("Only Intra 5GS Handover is supported at the moment!\n"); + return -1; + } + + // PDU Session Resource Handover List (O) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_HandoverType, false); + if (ie != NULL) { + msg->nb_of_pdusessions = ie->value.choice.PDUSessionResourceHandoverList.list.count; + + for (int i = 0; i < msg->nb_of_pdusessions; ++i) { + NGAP_PDUSessionResourceHandoverItem_t *item = ie->value.choice.PDUSessionResourceHandoverList.list.array[i]; + + // PDU Session ID (M) + msg->pdu_sessions[i].pdusession_id = item->pDUSessionID; + + // Handover Command Transfer (M) + NGAP_HandoverCommandTransfer_t *hoCommandTransfer = NULL; + asn_dec_rval_t dec_rval = uper_decode_complete(NULL, + &asn_DEF_NGAP_HandoverCommandTransfer, + (void **)&hoCommandTransfer, + item->handoverCommandTransfer.buf, + item->handoverCommandTransfer.size); + if (dec_rval.code != RC_OK) { + NGAP_ERROR("Failed to decode handoverCommandTransfer\n"); + continue; + } + + // DL Forwarding UP TNL Information (O) + if (hoCommandTransfer->dLForwardingUP_TNLInformation) { + NGAP_UPTransportLayerInformation_t *up_tnl = hoCommandTransfer->dLForwardingUP_TNLInformation; + if (hoCommandTransfer->dLForwardingUP_TNLInformation->present == NGAP_UPTransportLayerInformation_PR_gTPTunnel) { + OCTET_STRING_TO_INT32(&(up_tnl->choice.gTPTunnel->gTP_TEID), msg->pdu_sessions[i].ho_command_transfer.gtp_teid); + bitstring_to_tnl(&msg->pdu_sessions[i].ho_command_transfer.gNB_addr, up_tnl->choice.gTPTunnel->transportLayerAddress); + } else { + NGAP_WARN("Missing DL Forwarding UP TNL Information\n"); + } + } + ASN_STRUCT_FREE(asn_DEF_NGAP_HandoverCommandTransfer, hoCommandTransfer); + } + } + + // Target to Source Transparent Container (M) + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_TargetToSource_TransparentContainer, + true); + NGAP_TargetToSource_TransparentContainer_t *target2source = &(ie->value.choice.TargetToSource_TransparentContainer); + NGAP_TargetNGRANNode_ToSourceNGRANNode_TransparentContainer_t *transparentContainer = NULL; + asn_dec_rval_t dec_rval = aper_decode_complete(NULL, + &asn_DEF_NGAP_TargetNGRANNode_ToSourceNGRANNode_TransparentContainer, + (void **)&transparentContainer, + target2source->buf, + target2source->size); + if (dec_rval.code != RC_OK) { + NGAP_ERROR("Failed to decode TargetToSource_TransparentContainer\n"); + return -1; + } + + msg->handoverCommand = create_byte_array(transparentContainer->rRCContainer.size, transparentContainer->rRCContainer.buf); + ASN_STRUCT_FREE(asn_DEF_NGAP_TargetNGRANNode_ToSourceNGRANNode_TransparentContainer, transparentContainer); + + return 0; +} + +void free_ng_handover_command(ngap_handover_command_t *msg) +{ + free_byte_array(msg->handoverCommand); +} + +NGAP_NGAP_PDU_t *encode_ng_handover_notify(const ngap_handover_notify_t *msg) +{ + NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + // Message Type (M) + pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, head); + head->procedureCode = NGAP_ProcedureCode_id_HandoverNotification; + head->criticality = NGAP_Criticality_ignore; + head->value.present = NGAP_InitiatingMessage__value_PR_HandoverNotify; + NGAP_HandoverNotify_t *out = &head->value.choice.HandoverNotify; + + // AMF UE NGAP ID (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverNotifyIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverNotifyIEs__value_PR_AMF_UE_NGAP_ID; + asn_uint642INTEGER(&ie->value.choice.AMF_UE_NGAP_ID, msg->amf_ue_ngap_id); + } + + // RAN UE NGAP ID (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverNotifyIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverNotifyIEs__value_PR_RAN_UE_NGAP_ID; + ie->value.choice.RAN_UE_NGAP_ID = msg->gNB_ue_ngap_id; + } + + // User Location Information (M) + { + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverNotifyIEs_t, ie); + ie->id = NGAP_ProtocolIE_ID_id_UserLocationInformation; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverNotifyIEs__value_PR_UserLocationInformation; + ie->value.choice.UserLocationInformation.present = NGAP_UserLocationInformation_PR_userLocationInformationNR; + asn1cCalloc(ie->value.choice.UserLocationInformation.choice.userLocationInformationNR, userinfo_nr_p); + // NR User Location Information + const target_ran_node_id_t *target = &msg->user_info.target_ng_ran; + // CGI (M) + MACRO_GNB_ID_TO_CELL_IDENTITY(target->targetgNBId, msg->user_info.nrCellIdentity, &userinfo_nr_p->nR_CGI.nRCellIdentity); + MCC_MNC_TO_TBCD(target->plmn_identity.mcc, + target->plmn_identity.mnc, + target->plmn_identity.mnc_digit_length, + &userinfo_nr_p->nR_CGI.pLMNIdentity); + // TAI (M) + INT24_TO_OCTET_STRING(target->tac, &userinfo_nr_p->tAI.tAC); + MCC_MNC_TO_PLMNID(target->plmn_identity.mcc, + target->plmn_identity.mnc, + target->plmn_identity.mnc_digit_length, + &userinfo_nr_p->tAI.pLMNIdentity); + } + + return pdu; +} + +/** @brief NGAP Handover Cancel encoding (9.2.3.11 3GPP TS 38.413 Handover Cancel) + * 8.4.5 Handover Cancellation (source NG-RAN -> AMF) */ +NGAP_NGAP_PDU_t *encode_ng_handover_cancel(const ngap_handover_cancel_t *msg) +{ + DevAssert(msg != NULL); + + NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, head); + head->procedureCode = NGAP_ProcedureCode_id_HandoverCancel; + head->criticality = NGAP_Criticality_reject; + head->value.present = NGAP_InitiatingMessage__value_PR_HandoverCancel; + NGAP_HandoverCancel_t *out = &head->value.choice.HandoverCancel; + + // AMF UE NGAP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverCancelIEs_t, ie1); + ie1->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie1->criticality = NGAP_Criticality_reject; + ie1->value.present = NGAP_HandoverCancelIEs__value_PR_AMF_UE_NGAP_ID; + asn_uint642INTEGER(&ie1->value.choice.AMF_UE_NGAP_ID, msg->amf_ue_ngap_id); + + // RAN UE NGAP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverCancelIEs_t, ie2); + ie2->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie2->criticality = NGAP_Criticality_reject; + ie2->value.present = NGAP_HandoverCancelIEs__value_PR_RAN_UE_NGAP_ID; + ie2->value.choice.RAN_UE_NGAP_ID = msg->gNB_ue_ngap_id; + + // Cause (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverCancelIEs_t, ie3); + ie3->id = NGAP_ProtocolIE_ID_id_Cause; + ie3->criticality = NGAP_Criticality_reject; + ie3->value.present = NGAP_HandoverCancelIEs__value_PR_Cause; + encode_ngap_cause(&ie3->value.choice.Cause, &msg->cause); + + return pdu; +} + +/** @brief Decode NGAP Handover Cancel Acknowledge (9.2.3.12 3GPP TS 38.413) */ +int decode_ng_handover_cancel_ack(ngap_handover_cancel_ack_t *out, const NGAP_NGAP_PDU_t *pdu) +{ + DevAssert(out != NULL); + DevAssert(pdu != NULL); + + NGAP_HandoverCancelAcknowledge_t *container = &pdu->choice.successfulOutcome->value.choice.HandoverCancelAcknowledge; + NGAP_HandoverCancelAcknowledgeIEs_t *ie; + + /* AMF UE NGAP ID (M) */ + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCancelAcknowledgeIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID, true); + asn_INTEGER2ulong(&ie->value.choice.AMF_UE_NGAP_ID, &out->amf_ue_ngap_id); + + /* RAN UE NGAP ID (M) */ + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCancelAcknowledgeIEs_t, ie, container, NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID, true); + out->gNB_ue_ngap_id = ie->value.choice.RAN_UE_NGAP_ID; + + return 0; +} + +/** @brief Encode NGAP UL RAN Status Transfer (9.2.3.14 of 3GPP TS 38.413) */ +NGAP_NGAP_PDU_t *encode_ng_ul_ran_status_transfer(const ngap_ran_status_transfer_t *msg) +{ + NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, head); + head->procedureCode = NGAP_ProcedureCode_id_UplinkRANStatusTransfer; + head->criticality = NGAP_Criticality_ignore; + head->value.present = NGAP_InitiatingMessage__value_PR_UplinkRANStatusTransfer; + NGAP_UplinkRANStatusTransfer_t *out = &head->value.choice.UplinkRANStatusTransfer; + + // AMF UE NGAP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_UplinkRANStatusTransferIEs_t, ie1); + ie1->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie1->criticality = NGAP_Criticality_reject; + ie1->value.present = NGAP_UplinkRANStatusTransferIEs__value_PR_AMF_UE_NGAP_ID; + asn_uint642INTEGER(&ie1->value.choice.AMF_UE_NGAP_ID, msg->amf_ue_ngap_id); + + // RAN UE NGAP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_UplinkRANStatusTransferIEs_t, ie2); + ie2->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie2->criticality = NGAP_Criticality_reject; + ie2->value.present = NGAP_UplinkRANStatusTransferIEs__value_PR_RAN_UE_NGAP_ID; + ie2->value.choice.RAN_UE_NGAP_ID = msg->gnb_ue_ngap_id; + + // RAN Status Transfer Transparent Container (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_UplinkRANStatusTransferIEs_t, ie3); + ie3->id = NGAP_ProtocolIE_ID_id_RANStatusTransfer_TransparentContainer; + ie3->criticality = NGAP_Criticality_reject; + ie3->value.present = NGAP_UplinkRANStatusTransferIEs__value_PR_RANStatusTransfer_TransparentContainer; + NGAP_RANStatusTransfer_TransparentContainer_t *container = &ie3->value.choice.RANStatusTransfer_TransparentContainer; + + for (int i = 0; i < msg->ran_status.nb_drb; ++i) { + const ngap_drb_status_t *s = &msg->ran_status.drb_status_list[i]; + asn1cSequenceAdd(container->dRBsSubjectToStatusTransferList.list, NGAP_DRBsSubjectToStatusTransferItem_t, drb_item); + drb_item->dRB_ID = s->drb_id; + + // UL COUNT + if (s->ul_count.sn_len == NGAP_SN_LENGTH_18) { + drb_item->dRBStatusUL.present = NGAP_DRBStatusUL_PR_dRBStatusUL18; + asn1cCalloc(drb_item->dRBStatusUL.choice.dRBStatusUL18, ul18); + ul18->uL_COUNTValue.pDCP_SN18 = s->ul_count.pdcp_sn; + ul18->uL_COUNTValue.hFN_PDCP_SN18 = s->ul_count.hfn; + } else { + drb_item->dRBStatusUL.present = NGAP_DRBStatusUL_PR_dRBStatusUL12; + asn1cCalloc(drb_item->dRBStatusUL.choice.dRBStatusUL12, ul12); + ul12->uL_COUNTValue.pDCP_SN12 = s->ul_count.pdcp_sn; + ul12->uL_COUNTValue.hFN_PDCP_SN12 = s->ul_count.hfn; + } + + // DL COUNT + if (s->dl_count.sn_len == NGAP_SN_LENGTH_18) { + drb_item->dRBStatusDL.present = NGAP_DRBStatusDL_PR_dRBStatusDL18; + asn1cCalloc(drb_item->dRBStatusDL.choice.dRBStatusDL18, dl18); + dl18->dL_COUNTValue.pDCP_SN18 = s->dl_count.pdcp_sn; + dl18->dL_COUNTValue.hFN_PDCP_SN18 = s->dl_count.hfn; + } else { + drb_item->dRBStatusDL.present = NGAP_DRBStatusDL_PR_dRBStatusDL12; + asn1cCalloc(drb_item->dRBStatusDL.choice.dRBStatusDL12, dl12); + dl12->dL_COUNTValue.pDCP_SN12 = s->dl_count.pdcp_sn; + dl12->dL_COUNTValue.hFN_PDCP_SN12 = s->dl_count.hfn; + } + } + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NGAP_RANStatusTransfer_TransparentContainer, &container); + + return pdu; +} diff --git a/openair3/NGAP/ngap_gNB_mobility_management.h b/openair3/NGAP/ngap_gNB_mobility_management.h new file mode 100644 index 0000000000..18aac7c61d --- /dev/null +++ b/openair3/NGAP/ngap_gNB_mobility_management.h @@ -0,0 +1,41 @@ +/* + * 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 NGAP_GNB_MOBILITY_MANAGEMENT_H_ +#define NGAP_GNB_MOBILITY_MANAGEMENT_H_ + +#include +#include "common/platform_types.h" +#include "ngap_messages_types.h" + +NGAP_NGAP_PDU_t *encode_ng_handover_required(const ngap_handover_required_t *msg); +NGAP_NGAP_PDU_t *encode_ng_handover_failure(const ngap_handover_failure_t *msg); +int decode_ng_handover_request(ngap_handover_request_t *out, const NGAP_NGAP_PDU_t *pdu); +NGAP_NGAP_PDU_t *encode_ng_handover_request_ack(ngap_handover_request_ack_t *msg); +void free_ng_handover_req_ack(ngap_handover_request_ack_t *msg); +int decode_ng_handover_command(ngap_handover_command_t *msg, NGAP_NGAP_PDU_t *pdu); +void free_ng_handover_command(ngap_handover_command_t *msg); +NGAP_NGAP_PDU_t *encode_ng_handover_notify(const ngap_handover_notify_t *msg); +NGAP_NGAP_PDU_t *encode_ng_ul_ran_status_transfer(const ngap_ran_status_transfer_t *msg); +NGAP_NGAP_PDU_t *encode_ng_handover_cancel(const ngap_handover_cancel_t *msg); +int decode_ng_handover_cancel_ack(ngap_handover_cancel_ack_t *out, const NGAP_NGAP_PDU_t *pdu); + +#endif /* NGAP_GNB_MOBILITY_MANAGEMENT_H_ */ diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index b00ce13f32..cff9cd0b72 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "BIT_STRING.h" #include "INTEGER.h" #include "ngap_msg_includes.h" @@ -57,6 +58,7 @@ #include "oai_asn1.h" #include "s1ap_messages_types.h" #include "xer_encoder.h" +#include "ds/byte_array.h" /** @brief Selects the AMF instance for a given UE based on identity information. * It attempts to select an AMF using the following prioritized criteria: @@ -72,23 +74,27 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng // Select the AMF corresponding to the GUAMI from the RegisteredAMF IE if (msg->ue_identity.presenceMask & NGAP_UE_IDENTITIES_guami) { const nr_guami_t *guami = &msg->ue_identity.guami; - NGAP_DEBUG("GUAMI is present: MCC=%03d MNC=%03d RegionID=%d SetID=%d Pointer=%d\n", - guami->mcc, - guami->mnc, - guami->amf_region_id, - guami->amf_set_id, - guami->amf_pointer); + LOG_D(NGAP, + "GUAMI is present: MCC=%03d MNC=%0*d RegionID=%d SetID=%d Pointer=%d\n", + guami->mcc, + guami->mnc_len, + guami->mnc, + guami->amf_region_id, + guami->amf_set_id, + guami->amf_pointer); amf = ngap_gNB_nnsf_select_amf_by_guami(instance_p, msg->establishment_cause, *guami); if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through GUAMI MCC %d MNC %d AMFRI %d AMFSI %d AMFPT %d\n", - msg->gNB_ue_ngap_id, - amf->amf_name, - amf->assoc_id, - guami->mcc, - guami->mnc, - guami->amf_region_id, - guami->amf_set_id, - guami->amf_pointer); + LOG_I(NGAP, + "UE %d: Selected AMF '%s' (assoc_id %d) through GUAMI MCC=%03d MNC=%0*d AMFRI %d AMFSI %d AMFPT %d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + guami->mcc, + guami->mnc_len, + guami->mnc, + guami->amf_region_id, + guami->amf_set_id, + guami->amf_pointer); return amf; } } @@ -99,13 +105,15 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng const fiveg_s_tmsi_t *fgs_tmsi = &msg->ue_identity.s_tmsi; amf = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, msg->establishment_cause, msg->plmn, fgs_tmsi->amf_set_id); if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN MCC %d MNC %d\n", - msg->gNB_ue_ngap_id, - amf->amf_name, - amf->assoc_id, - fgs_tmsi->amf_set_id, - msg->plmn.mcc, - msg->plmn.mnc); + LOG_I(NGAP, + "UE %d: Selected AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN MCC=%03d MNC=%0*d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + fgs_tmsi->amf_set_id, + msg->plmn.mcc, + msg->plmn.mnc_digit_length, + msg->plmn.mnc); return amf; } } @@ -115,19 +123,20 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng // Select the AMF based on the selected PLMN identity received through RRCSetupComplete amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->plmn); if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN MCC=%03d MNC=%0*d\n", - msg->gNB_ue_ngap_id, - amf->amf_name, - amf->assoc_id, - msg->plmn.mcc, - msg->plmn.mnc_digit_length, - msg->plmn.mnc); + LOG_I(NGAP, + "UE %d: Selected AMF '%s' (assoc_id %d) through selected PLMN MCC=%03d MNC=%0*d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + msg->plmn.mcc, + msg->plmn.mnc_digit_length, + msg->plmn.mnc); return amf; } else { // Select the AMF with the highest capacity amf = ngap_gNB_nnsf_select_amf(instance_p, msg->establishment_cause); if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", + NGAP_INFO("UE %d: Selected AMF '%s' (assoc_id %d) through highest relative capacity\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id); @@ -250,8 +259,11 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->value.choice.UEContextRequest = NGAP_UEContextRequest_requested; } - if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) + if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); DevMessage("Failed to encode initial UE message\n"); + return -1; + } /* Update the current NGAP UE state */ ue_desc_p.ue_state = NGAP_UE_WAITING_CSR; @@ -279,6 +291,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf /* Send encoded message over sctp */ ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p.tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } @@ -445,6 +458,7 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_ if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode uplink NAS transport\n"); /* Encode procedure has failed... */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } @@ -453,6 +467,7 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_ ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } @@ -526,6 +541,7 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance, if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode NAS NON delivery indication\n"); /* Encode procedure has failed... */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } @@ -534,9 +550,50 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } +/** @brief PDU Session Resource Setup Response Transfer encoding (9.3.4.2 3GPP TS 38.413) */ +static byte_array_t encode_ngap_pdusession_setup_response_transfer(const pdusession_setup_t *pdusession) +{ + NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; + byte_array_t out = {0}; + + // DL QoS Flow per TNL Information (Mandatory) + NGAP_QosFlowPerTNLInformation_t *dLQosFlowPerTNLInformation = &pdusessionTransfer.dLQosFlowPerTNLInformation; + + // UP Transport Layer Information (Mandatory) + dLQosFlowPerTNLInformation->uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; + asn1cCalloc(dLQosFlowPerTNLInformation->uPTransportLayerInformation.choice.gTPTunnel, gtp); + GTP_TEID_TO_ASN1(pdusession->n3_outgoing.teid, >p->gTP_TEID); + tnl_to_bitstring(>p->transportLayerAddress, pdusession->n3_outgoing.addr); + char ip_str[INET_ADDRSTRLEN] = {0}; + inet_ntop(AF_INET, gtp->transportLayerAddress.buf, ip_str, sizeof(ip_str)); + NGAP_DEBUG("Encoded PDU Session Transfer (%d): TEID=0x%08x, Addr=%s\n", + pdusession->pdusession_id, + pdusession->n3_outgoing.teid, + ip_str); + + // Associated QoS Flow List (Mandatory) + for (int j = 0; j < pdusession->nb_of_qos_flow; j++) { + asn1cSequenceAdd(dLQosFlowPerTNLInformation->associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, qos_item); + // QoS Flow Identifier (Mandatory) + qos_item->qosFlowIdentifier = pdusession->associated_qos_flows[j].qfi; + } + + // Encode + asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, + ATS_ALIGNED_CANONICAL_PER, + &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, + &pdusessionTransfer); + AssertFatal(res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + out.buf = res.buffer; + out.len = res.result.encoded; + return out; +} + //------------------------------------------------------------------------------ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_resp_t *initial_ctxt_resp_p) //------------------------------------------------------------------------------ @@ -606,39 +663,10 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r asn1cSequenceAdd(ie->value.choice.PDUSessionResourceSetupListCxtRes.list, NGAP_PDUSessionResourceSetupItemCxtRes_t, item); /* pDUSessionID */ item->pDUSessionID = initial_ctxt_resp_p->pdusessions[i].pdusession_id; - - /* dLQosFlowPerTNLInformation */ - NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; - - pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; - - asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); - GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].gtp_teid, &tmp->gTP_TEID); - tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); - - NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", - item->pDUSessionID, - tmp->transportLayerAddress.buf[0], - tmp->transportLayerAddress.buf[1], - tmp->transportLayerAddress.buf[2], - tmp->transportLayerAddress.buf[3], - tmp->transportLayerAddress.size, - initial_ctxt_resp_p->pdusessions[i].gtp_teid); - - /* associatedQosFlowList. number of 1? */ - for(int j=0; j < initial_ctxt_resp_p->pdusessions[i].nb_of_qos_flow; j++) { - asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); - /* qosFlowIdentifier */ - ass_qos_item_p->qosFlowIdentifier = initial_ctxt_resp_p->pdusessions[i].associated_qos_flows[j].qfi; - } - - void *pdusessionTransfer_buffer; - ssize_t encoded = aper_encode_to_new_buffer(&asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, NULL, &pdusessionTransfer, &pdusessionTransfer_buffer); - AssertFatal(encoded > 0, "ASN1 message encoding failed !\n"); - item->pDUSessionResourceSetupResponseTransfer.buf = pdusessionTransfer_buffer; - item->pDUSessionResourceSetupResponseTransfer.size = encoded; - - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + // PDU Session Resource Setup Response Transfer (Mandatory) + byte_array_t ba = encode_ngap_pdusession_setup_response_transfer(&initial_ctxt_resp_p->pdusessions[i]); + item->pDUSessionResourceSetupResponseTransfer.buf = ba.buf; + item->pDUSessionResourceSetupResponseTransfer.size = ba.len; } } /* optional */ @@ -677,13 +705,14 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r // ie->value.choice.CriticalityDiagnostics =; } - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, &pdu); } if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode InitialContextSetupResponse\n"); /* Encode procedure has failed... */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } @@ -691,6 +720,7 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r LOG_I(NR_RRC,"Send message to sctp: NGAP_InitialContextSetupResponse\n"); ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } @@ -759,12 +789,13 @@ int ngap_gNB_initial_ctxt_fail(instance_t instance, ngap_initial_context_setup_f ie->value.present = NGAP_InitialContextSetupFailureIEs__value_PR_Cause; encode_ngap_cause(&ie->value.choice.Cause, &initial_ctxt_fail->cause); } - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, &pdu); } if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode InitialContextSetupFailure\n"); /* Encode procedure has failed... */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } /* UE associated signalling -> use the allocated stream */ @@ -774,6 +805,7 @@ int ngap_gNB_initial_ctxt_fail(instance_t instance, ngap_initial_context_setup_f buffer, length, ue_context_p->tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } @@ -846,11 +878,13 @@ int ngap_gNB_ue_capabilities(instance_t instance, ngap_ue_cap_info_ind_t *ue_cap if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { /* Encode procedure has failed... */ NGAP_ERROR("Failed to encode UE radio capabilities indication\n"); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } /* UE associated signalling -> use the allocated stream */ ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } @@ -924,40 +958,10 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re /* pDUSessionID */ item->pDUSessionID = pdusession->pdusession_id; - /* dLQosFlowPerTNLInformation */ - NGAP_PDUSessionResourceSetupResponseTransfer_t pdusessionTransfer = {0}; - pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; - asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); - GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID); - tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->gNB_addr); - NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", - item->pDUSessionID, - tmp->transportLayerAddress.buf[0], - tmp->transportLayerAddress.buf[1], - tmp->transportLayerAddress.buf[2], - tmp->transportLayerAddress.buf[3], - tmp->transportLayerAddress.size, - pdusession->gtp_teid); - /* associatedQosFlowList. number of 1? */ - for(int j=0; j < pdusession_setup_resp_p->pdusessions[i].nb_of_qos_flow; j++) { - asn1cSequenceAdd(pdusessionTransfer.dLQosFlowPerTNLInformation.associatedQosFlowList.list, NGAP_AssociatedQosFlowItem_t, ass_qos_item_p); - - /* qosFlowIdentifier */ - ass_qos_item_p->qosFlowIdentifier = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qfi; - - /* qosFlowMappingIndication */ - // if(pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind != QOSFLOW_MAPPING_INDICATION_NON) { - // ass_qos_item_p->qosFlowMappingIndication = malloc(sizeof(*ass_qos_item_p->qosFlowMappingIndication)); - // *ass_qos_item_p->qosFlowMappingIndication = pdusession_setup_resp_p->pdusessions[i].associated_qos_flows[j].qos_flow_mapping_ind; - // } - } - - asn_encode_to_new_buffer_result_t res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); - AssertFatal (res.buffer, "ASN1 message encoding failed (%s, %lu)!\n", res.result.failed_type->name, res.result.encoded); - item->pDUSessionResourceSetupResponseTransfer.buf = res.buffer; - item->pDUSessionResourceSetupResponseTransfer.size = res.result.encoded; - - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &pdusessionTransfer); + // PDU Session Resource Setup Response Transfer (Mandatory) + byte_array_t ba = encode_ngap_pdusession_setup_response_transfer(pdusession); + item->pDUSessionResourceSetupResponseTransfer.buf = ba.buf; + item->pDUSessionResourceSetupResponseTransfer.size = ba.len; } } @@ -1000,11 +1004,13 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode uplink transport\n"); /* Encode procedure has failed... */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } /* UE associated signalling -> use the allocated stream */ ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } @@ -1138,12 +1144,14 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_ if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode uplink transport\n"); /* Encode procedure has failed... */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } /* UE associated signalling -> use the allocated stream */ ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } //------------------------------------------------------------------------------ @@ -1211,31 +1219,18 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { NGAP_ERROR("Failed to encode release response\n"); /* Encode procedure has failed... */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return -1; } /* UE associated signalling -> use the allocated stream */ ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream); - NGAP_INFO("pdusession_release_response sended gNB_UE_NGAP_ID %u amf_ue_ngap_id %lu nb_of_pdusessions_released %d nb_of_pdusessions_failed %d\n", + NGAP_INFO("pdusession_release_response sended gNB_UE_NGAP_ID %u amf_ue_ngap_id %lu nb_of_pdusessions_released %d \n", pdusession_release_resp_p->gNB_ue_ngap_id, (uint64_t)ue_context_p->amf_ue_ngap_id, - pdusession_release_resp_p->nb_of_pdusessions_released, - pdusession_release_resp_p->nb_of_pdusessions_failed); + pdusession_release_resp_p->nb_of_pdusessions_released); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu); return 0; } -int ngap_gNB_path_switch_req(instance_t instance, ngap_path_switch_req_t *path_switch_req_p) -//------------------------------------------------------------------------------ -{ - //TODO - - return 0; -} - -int ngap_gNB_generate_PDUSESSION_Modification_Indication(instance_t instance, ngap_pdusession_modification_ind_t *pdusession_modification_ind) -//----------------------------------------------------------------------------- -{ - //TODO - return 0; -} diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.h b/openair3/NGAP/ngap_gNB_nas_procedures.h index 3cd03838b4..5189e6b311 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.h +++ b/openair3/NGAP/ngap_gNB_nas_procedures.h @@ -63,10 +63,4 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_release_resp_t *pdusession_release_resp_p); -int ngap_gNB_path_switch_req(instance_t instance, - ngap_path_switch_req_t *path_switch_req_p); - -int ngap_gNB_generate_PDUSESSION_Modification_Indication( - instance_t instance, ngap_pdusession_modification_ind_t *pdusession_modification_ind); - #endif /* NGAP_GNB_NAS_PROCEDURES_H_ */ diff --git a/openair3/NGAP/ngap_gNB_ue_context.c b/openair3/NGAP/ngap_gNB_ue_context.c index d0949b88c2..994271d822 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.c +++ b/openair3/NGAP/ngap_gNB_ue_context.c @@ -76,6 +76,12 @@ struct ngap_gNB_ue_context_s *ngap_get_ue_context(uint32_t gNB_ue_ngap_id) return RB_FIND(ngap_ue_map, &ngap_ue_head, &temp); } +ngap_gNB_ue_context_t *ngap_get_ue_context_from_amf_ue_ngap_id(uint32_t amf_ue_ngap_id) +{ + ngap_gNB_ue_context_t temp = {.amf_ue_ngap_id = amf_ue_ngap_id}; + return RB_FIND(ngap_ue_map, &ngap_ue_head, &temp); +} + struct ngap_gNB_ue_context_s *ngap_detach_ue_context(uint32_t gNB_ue_ngap_id) { struct ngap_gNB_ue_context_s *tmp = ngap_get_ue_context(gNB_ue_ngap_id); diff --git a/openair3/NGAP/ngap_gNB_ue_context.h b/openair3/NGAP/ngap_gNB_ue_context.h index aaf9e83bbc..1022f2f4c3 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.h +++ b/openair3/NGAP/ngap_gNB_ue_context.h @@ -81,6 +81,7 @@ typedef struct ngap_gNB_ue_context_s { void ngap_store_ue_context(const ngap_gNB_ue_context_t *ue_desc_p); ngap_gNB_ue_context_t *ngap_get_ue_context(uint32_t gNB_ue_ngap_id); +ngap_gNB_ue_context_t *ngap_get_ue_context_from_amf_ue_ngap_id(uint32_t amf_ue_ngap_id); ngap_gNB_ue_context_t *ngap_detach_ue_context(uint32_t gNB_ue_ngap_id); #endif /* NGAP_GNB_UE_CONTEXT_H_ */ diff --git a/openair3/NGAP/ngap_msg_includes.h b/openair3/NGAP/ngap_msg_includes.h index c7ef77be6a..816cdfb979 100644 --- a/openair3/NGAP/ngap_msg_includes.h +++ b/openair3/NGAP/ngap_msg_includes.h @@ -71,5 +71,43 @@ #include "NGAP_UnsuccessfulOutcome.h" #include "NGAP_UserLocationInformationNR.h" #include "NGAP_asn_constant.h" +#include "NGAP_PDUSessionResourceSetupRequestTransfer.h" +#include "NGAP_QosFlowSetupRequestItem.h" +#include "NGAP_QosCharacteristics.h" +#include "NGAP_NonDynamic5QIDescriptor.h" +#include "NGAP_Dynamic5QIDescriptor.h" +#include "NGAP_PDUSessionResourceModifyRequestTransfer.h" +#include "NGAP_QosFlowAddOrModifyRequestItem.h" +#include "NGAP_PDUSessionResourceItemHORqd.h" +#include "NGAP_PDUSessionResourceInformationItem.h" +#include "NGAP_QosFlowInformationItem.h" +#include "NGAP_LastVisitedCellItem.h" +#include "NGAP_LastVisitedNGRANCellInformation.h" +#include "NGAP_PDUSessionResourceInformationList.h" +#include "NGAP_HandoverRequiredTransfer.h" +#include "NGAP_SourceNGRANNode-ToTargetNGRANNode-TransparentContainer.h" +#include "NGAP_PDUSessionResourceSetupItemHOReq.h" +#include "NGAP_HandoverCommand.h" +#include "NGAP_HandoverCommandTransfer.h" +#include "NGAP_TargetNGRANNode-ToSourceNGRANNode-TransparentContainer.h" +#include "NGAP_TargetToSource-TransparentContainer.h" +#include "NGAP_UEHistoryInformation.h" +#include "NGAP_Cause.h" +#include "NGAP_PDUSessionResourceHandoverItem.h" +#include "NGAP_SourceToTarget-TransparentContainer.h" +#include "NGAP_HandoverRequest.h" +#include "NGAP_PDUSessionResourceAdmittedList.h" +#include "NGAP_PDUSessionResourceAdmittedItem.h" +#include "NGAP_HandoverRequestAcknowledgeTransfer.h" +#include "NGAP_QosFlowItemWithDataForwarding.h" +#include "NR_HandoverPreparationInformation.h" +#include "NGAP_HandoverNotify.h" +#include "NGAP_DRBsSubjectToStatusTransferItem.h" +#include "NGAP_DRBStatusUL.h" +#include "NGAP_DRBStatusUL18.h" +#include "NGAP_DRBStatusUL12.h" +#include "NGAP_DRBStatusDL.h" +#include "NGAP_DRBStatusDL18.h" +#include "NGAP_DRBStatusDL12.h" #endif // NGAP_MSG_INCLUDES_H diff --git a/openair3/NRPPA/MESSAGES/ASN1/38455.cmake b/openair3/NRPPA/MESSAGES/ASN1/38455.cmake index d81f3db96c..7421d09e06 100644 --- a/openair3/NRPPA/MESSAGES/ASN1/38455.cmake +++ b/openair3/NRPPA/MESSAGES/ASN1/38455.cmake @@ -4,7 +4,6 @@ set(nrppa_source ANY_aper.c ANY_ber.c ANY.c -ANY_jer.c ANY_uper.c ANY_xer.c aper_decoder.c @@ -24,7 +23,6 @@ ber_decoder.c ber_tlv_length.c ber_tlv_tag.c BIT_STRING.c -BIT_STRING_jer.c BIT_STRING_print.c BIT_STRING_rfill.c BIT_STRING_uper.c @@ -33,7 +31,6 @@ constraints.c constr_CHOICE_aper.c constr_CHOICE_ber.c constr_CHOICE.c -constr_CHOICE_jer.c constr_CHOICE_print.c constr_CHOICE_rfill.c constr_CHOICE_uper.c @@ -41,11 +38,9 @@ constr_CHOICE_xer.c constr_SEQUENCE_aper.c constr_SEQUENCE_ber.c constr_SEQUENCE.c -constr_SEQUENCE_jer.c constr_SEQUENCE_OF_aper.c constr_SEQUENCE_OF_ber.c constr_SEQUENCE_OF.c -constr_SEQUENCE_OF_jer.c constr_SEQUENCE_OF_uper.c constr_SEQUENCE_OF_xer.c constr_SEQUENCE_print.c @@ -55,7 +50,6 @@ constr_SEQUENCE_xer.c constr_SET_OF_aper.c constr_SET_OF_ber.c constr_SET_OF.c -constr_SET_OF_jer.c constr_SET_OF_print.c constr_SET_OF_rfill.c constr_SET_OF_uper.c @@ -66,21 +60,17 @@ GraphicString.c INTEGER_aper.c INTEGER_ber.c INTEGER.c -INTEGER_jer.c INTEGER_print.c INTEGER_rfill.c INTEGER_uper.c INTEGER_xer.c -jer_encoder.c NativeEnumerated_aper.c NativeEnumerated.c -NativeEnumerated_jer.c NativeEnumerated_uper.c NativeEnumerated_xer.c NativeInteger_aper.c NativeInteger_ber.c NativeInteger.c -NativeInteger_jer.c NativeInteger_print.c NativeInteger_rfill.c NativeInteger_uper.c @@ -406,21 +396,18 @@ NRPPA_WLAN-RSSI.c NULL_aper.c NULL_ber.c NULL.c -NULL_jer.c NULL_print.c NULL_rfill.c NULL_uper.c NULL_xer.c ObjectDescriptor.c OBJECT_IDENTIFIER.c -OBJECT_IDENTIFIER_jer.c OBJECT_IDENTIFIER_print.c OBJECT_IDENTIFIER_rfill.c OBJECT_IDENTIFIER_xer.c OCTET_STRING_aper.c OCTET_STRING_ber.c OCTET_STRING.c -OCTET_STRING_jer.c OCTET_STRING_print.c OCTET_STRING_rfill.c OCTET_STRING_uper.c @@ -473,7 +460,6 @@ constr_TYPE.h der_encoder.h GraphicString.h INTEGER.h -jer_encoder.h NativeEnumerated.h NativeInteger.h NRPPA_AbortTransmission.h diff --git a/openair3/NRPPA/MESSAGES/CMakeLists.txt b/openair3/NRPPA/MESSAGES/CMakeLists.txt index 997fb70a9c..6581932024 100644 --- a/openair3/NRPPA/MESSAGES/CMakeLists.txt +++ b/openair3/NRPPA/MESSAGES/CMakeLists.txt @@ -12,7 +12,7 @@ include(ASN1/38455.cmake) run_asn1c(${CMAKE_CURRENT_SOURCE_DIR}/${NRPPA_GRAMMAR} "NRPPA_" OUTPUT ${nrppa_source} ${nrppa_headers} - OPTIONS -gen-APER -gen-UPER -no-gen-OER -fcompound-names -no-gen-example -findirect-choice -fno-include-deps + OPTIONS -gen-APER -gen-UPER -no-gen-OER -no-gen-JER -fcompound-names -no-gen-example -findirect-choice -fno-include-deps COMMENT "NRPPA source files" ) diff --git a/openair3/S1AP/s1ap_common.h b/openair3/S1AP/s1ap_common.h index 797bc7be8a..7ef7e589ca 100644 --- a/openair3/S1AP/s1ap_common.h +++ b/openair3/S1AP/s1ap_common.h @@ -52,8 +52,6 @@ #define S1AP_UE_ID_FMT "0x%06"PRIX32 -extern int asn1_xer_print; - #include "common/utils/LOG/log.h" #include "s1ap_eNB_default_values.h" #define S1AP_ERROR(x, args...) LOG_E(S1AP, x, ##args) @@ -89,10 +87,4 @@ extern int asn1_xer_print; **/ typedef int (*s1ap_message_decoded_callback)(sctp_assoc_t assoc_id, uint32_t stream, S1AP_S1AP_PDU_t *pdu); -/** \brief Handle criticality - \param criticality Criticality of the IE - @returns void - **/ -void s1ap_handle_criticality(S1AP_Criticality_t criticality); -/** @}*/ #endif /* S1AP_COMMON_H_ */ diff --git a/openair3/S1AP/s1ap_eNB_encoder.c b/openair3/S1AP/s1ap_eNB_encoder.c index 8317f02731..6ff837a7f1 100644 --- a/openair3/S1AP/s1ap_eNB_encoder.c +++ b/openair3/S1AP/s1ap_eNB_encoder.c @@ -129,7 +129,7 @@ int s1ap_eNB_encode_initiating(S1AP_S1AP_PDU_t *pdu, return -1; } - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_S1AP_S1AP_PDU, (void *)pdu); } @@ -183,7 +183,7 @@ int s1ap_eNB_encode_successfull_outcome(S1AP_S1AP_PDU_t *pdu, return -1; } - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_S1AP_S1AP_PDU, (void *)pdu); } @@ -214,7 +214,7 @@ int s1ap_eNB_encode_unsuccessfull_outcome(S1AP_S1AP_PDU_t *pdu, return -1; } - if (asn1_xer_print) { + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_S1AP_S1AP_PDU, (void *)pdu); } diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index a7cf27a1ff..3fb35adee2 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -57,7 +57,7 @@ #define NR_FC_ALG_KEY_DER (0x69) #define NR_FC_ALG_KEY_NG_RAN_STAR_DER (0x70) -static void log_hex_buffer(const char *label, const uint8_t *buf, const int len) +void log_hex_buffer(const char *label, const uint8_t *buf, const int len) { char hex_str[len * 2 + 1]; for (int i = 0; i < len; i++) { diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 0ab14ad51a..eff72c68bb 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -36,4 +36,6 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh); +void log_hex_buffer(const char *label, const uint8_t *buf, const int len); + #endif diff --git a/openair3/TEST/test_s1ap.c b/openair3/TEST/test_s1ap.c index 8e61c338ac..1ecb30d476 100644 --- a/openair3/TEST/test_s1ap.c +++ b/openair3/TEST/test_s1ap.c @@ -154,10 +154,6 @@ void doit (void) { int i; break_on_error = 1; - - // asn1_xer_print = 1; - // asn_debug = 1; - for (i = 0; i < sizeof(s1ap_test) / sizeof(s1ap_test_t); i++) { S1AP_S1AP_PDU_t pdu; uint8_t *buffer; diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index fd571e8d0e..9be1873612 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -11,6 +11,7 @@ extern "C" { #include #include "common/platform_types.h" +#include "common/utils/system.h" #include #include "common/utils/LOG/log.h" #include @@ -20,96 +21,104 @@ extern "C" { #include #include #include "openair2/SDAP/nr_sdap/nr_sdap.h" +#include "openair3/ocp-gtpu/gtpu_extensions.h" #include "sim.h" #pragma pack(1) typedef struct Gtpv1uMsgHeader { - uint8_t PN:1; - uint8_t S:1; - uint8_t E:1; - uint8_t spare:1; - uint8_t PT:1; - uint8_t version:3; + uint8_t PN: 1; + uint8_t S: 1; + uint8_t E: 1; + uint8_t spare: 1; + uint8_t PT: 1; + uint8_t version: 3; uint8_t msgType; uint16_t msgLength; teid_t teid; } __attribute__((packed)) Gtpv1uMsgHeaderT; -//TS 38.425, Figure 5.5.2.2-1 +// TS 38.425, Figure 5.5.2.2-1 typedef struct DlDataDeliveryStatus_flags { - uint8_t LPR:1; //Lost packet report - uint8_t FFI:1; //Final Frame Ind - uint8_t deliveredPdcpSn:1; //Highest Delivered NR PDCP SN Ind - uint8_t transmittedPdcpSn:1; //Highest Transmitted NR PDCP SN Ind - uint8_t pduType:4; //PDU type - uint8_t CR:1; //Cause Report - uint8_t deliveredReTxPdcpSn:1; //Delivered retransmitted NR PDCP SN Ind - uint8_t reTxPdcpSn:1; //Retransmitted NR PDCP SN Ind - uint8_t DRI:1; //Data Rate Indication - uint8_t deliveredPdcpSnRange:1; //Delivered NR PDCP SN Range Ind - uint8_t spare:3; - uint32_t drbBufferSize; //Desired buffer size for the data radio bearer + uint8_t LPR: 1; // Lost packet report + uint8_t FFI: 1; // Final Frame Ind + uint8_t deliveredPdcpSn: 1; // Highest Delivered NR PDCP SN Ind + uint8_t transmittedPdcpSn: 1; // Highest Transmitted NR PDCP SN Ind + uint8_t pduType: 4; // PDU type + uint8_t CR: 1; // Cause Report + uint8_t deliveredReTxPdcpSn: 1; // Delivered retransmitted NR PDCP SN Ind + uint8_t reTxPdcpSn: 1; // Retransmitted NR PDCP SN Ind + uint8_t DRI: 1; // Data Rate Indication + uint8_t deliveredPdcpSnRange: 1; // Delivered NR PDCP SN Range Ind + uint8_t spare: 3; + uint32_t drbBufferSize; // Desired buffer size for the data radio bearer } __attribute__((packed)) DlDataDeliveryStatus_flagsT; typedef struct Gtpv1uMsgHeaderOptFields { uint8_t seqNum1Oct; uint8_t seqNum2Oct; uint8_t NPDUNum; - uint8_t NextExtHeaderType; + uint8_t NextExtHeaderType; } __attribute__((packed)) Gtpv1uMsgHeaderOptFieldsT; #define DL_PDU_SESSION_INFORMATION 0 #define UL_PDU_SESSION_INFORMATION 1 - typedef struct PDUSessionContainer { - uint8_t spare:4; - uint8_t PDU_type:4; - uint8_t QFI:6; - uint8_t Reflective_QoS_activation:1; - uint8_t Paging_Policy_Indicator:1; +typedef struct PDUSessionContainer { + uint8_t spare: 4; + uint8_t PDU_type: 4; + uint8_t QFI: 6; + uint8_t Reflective_QoS_activation: 1; + uint8_t Paging_Policy_Indicator: 1; } __attribute__((packed)) PDUSessionContainerT; typedef struct Gtpv1uExtHeader { uint8_t ExtHeaderLen; PDUSessionContainerT pdusession_cntr; uint8_t NextExtHeaderType; -}__attribute__((packed)) Gtpv1uExtHeaderT; +} __attribute__((packed)) Gtpv1uExtHeaderT; + + typedef struct Gtpv1Error { + Gtpv1uMsgHeaderT h; + uint8_t teid_data_i; + teid_t teid; + uint8_t addr_data_i; + uint16_t addr_len; + } __attribute__((packed)) Gtpv1uError; #pragma pack() // TS 29.281, fig 5.2.1-3 -#define PDU_SESSION_CONTAINER (0x85) -#define NR_RAN_CONTAINER (0x84) +#define PDU_SESSION_CONTAINER (0x85) +#define NR_RAN_CONTAINER (0x84) // TS 29.281, 5.2.1 -#define EXT_HDR_LNTH_OCTET_UNITS (4) -#define NO_MORE_EXT_HDRS (0) +#define EXT_HDR_LNTH_OCTET_UNITS (4) +#define NO_MORE_EXT_HDRS (0) // TS 29.060, table 7.1 defines the possible message types // here are all the possible messages (3GPP R16) -#define GTP_ECHO_REQ (1) -#define GTP_ECHO_RSP (2) -#define GTP_ERROR_INDICATION (26) -#define GTP_SUPPORTED_EXTENSION_HEADER_INDICATION (31) -#define GTP_END_MARKER (254) -#define GTP_GPDU (255) +#define GTP_ECHO_REQ (1) +#define GTP_ECHO_RSP (2) +#define GTP_ERROR_INDICATION (26) +#define GTP_SUPPORTED_EXTENSION_HEADER_INDICATION (31) +#define GTP_END_MARKER (254) +#define GTP_GPDU (255) +// GTP bearer context: for sending data typedef struct gtpv1u_bearer_s { - /* TEID used in dl and ul */ - teid_t teid_incoming; ///< eNB TEID - teid_t teid_outgoing; ///< Remote TEID - in_addr_t outgoing_ip_addr; - struct in6_addr outgoing_ip6_addr; - tcp_udp_port_t outgoing_port; - uint16_t seqNum; - uint8_t npduNum; + int sock_fd; + struct sockaddr_storage ip; + teid_t teid_incoming; + teid_t teid_outgoing; + uint16_t seqNum; + uint8_t npduNum; + int32_t nru_sequence_number; int outgoing_qfi; } gtpv1u_bearer_t; typedef struct { map bearers; - teid_t outgoing_teid; } teidData_t; typedef struct { @@ -121,34 +130,43 @@ typedef struct { int pdusession_id; } ueidData_t; +typedef struct { + int h; + pthread_t t; +} gtpThread_t; + class gtpEndPoint { public: openAddr_t addr; uint8_t foundAddr[20]; int foundAddrLen; int ipVersion; + gtpThread_t thrData; map ue2te_mapping; // we use the same port number for source and destination address // this allow using non standard gtp port number (different from 2152) // and so, for example tu run 4G and 5G cores on one system - tcp_udp_port_t get_dstport() { + tcp_udp_port_t get_dstport() + { return (tcp_udp_port_t)atol(addr.destinationService); } }; class gtpEndPoints { public: - pthread_mutex_t gtp_lock=PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t gtp_lock = PTHREAD_MUTEX_INITIALIZER; // the instance id will be the Linux socket handler, as this is uniq map instances; map te2ue_mapping; - gtpEndPoints() { + gtpEndPoints() + { unsigned int seed; fill_random(&seed, sizeof(seed)); srandom(seed); } - ~gtpEndPoints() { + ~gtpEndPoints() + { // automatically close all sockets on quit for (const auto &p : instances) close(p.first); @@ -158,7 +176,8 @@ class gtpEndPoints { static gtpEndPoints globGtp; // note TEid 0 is reserved for specific usage: echo req/resp, error and supported extensions -static teid_t gtpv1uNewTeid(void) { +static teid_t gtpv1uNewTeid(void) +{ #ifdef GTPV1U_LINEAR_TEID_ALLOCATION g_gtpv1u_teid = g_gtpv1u_teid + 1; return g_gtpv1u_teid; @@ -167,133 +186,135 @@ static teid_t gtpv1uNewTeid(void) { #endif } -instance_t legacyInstanceMapping=0; -#define compatInst(a) ((a)==0 || (a)==INSTANCE_DEFAULT ? legacyInstanceMapping:a) +instance_t legacyInstanceMapping = 0; +#define compatInst(a) ((a) == 0 || (a) == INSTANCE_DEFAULT ? legacyInstanceMapping : a) -#define getInstRetVoid(insT) \ - auto instChk=globGtp.instances.find(compatInst(insT)); \ - if (instChk == globGtp.instances.end()) { \ - LOG_E(GTPU,"try to get a gtp-u not existing output\n"); \ - pthread_mutex_unlock(&globGtp.gtp_lock); \ - return; \ - } \ - gtpEndPoint * inst=&instChk->second; - -#define getInstRetInt(insT) \ - auto instChk=globGtp.instances.find(compatInst(insT)); \ - if (instChk == globGtp.instances.end()) { \ - LOG_E(GTPU,"try to get a gtp-u not existing output\n"); \ - pthread_mutex_unlock(&globGtp.gtp_lock); \ - return GTPNOK; \ - } \ - gtpEndPoint * inst=&instChk->second; +#define getInstRetVoid(insT) \ + auto instChk = globGtp.instances.find(compatInst(insT)); \ + if (instChk == globGtp.instances.end()) { \ + LOG_E(GTPU, "try to get a gtp-u not existing output\n"); \ + pthread_mutex_unlock(&globGtp.gtp_lock); \ + return; \ + } \ + gtpEndPoint *inst = &instChk->second; +#define getInstRetInt(insT) \ + auto instChk = globGtp.instances.find(compatInst(insT)); \ + if (instChk == globGtp.instances.end()) { \ + LOG_E(GTPU, "try to get a gtp-u not existing output\n"); \ + pthread_mutex_unlock(&globGtp.gtp_lock); \ + return GTPNOK; \ + } \ + gtpEndPoint *inst = &instChk->second; -#define getUeRetVoid(insT, Ue) \ - auto ptrUe=insT->ue2te_mapping.find(Ue); \ - \ - if ( ptrUe==insT->ue2te_mapping.end() ) { \ +#define getUeRetVoid(insT, Ue) \ + auto ptrUe = insT->ue2te_mapping.find(Ue); \ + \ + if (ptrUe == insT->ue2te_mapping.end()) { \ LOG_E(GTPU, "[%ld] %s failed: while getting ue id %ld in hashtable ue_mapping\n", instance, __func__, ue_id); \ - pthread_mutex_unlock(&globGtp.gtp_lock); \ - return; \ + pthread_mutex_unlock(&globGtp.gtp_lock); \ + return; \ } - -#define getUeRetInt(insT, Ue) \ - auto ptrUe=insT->ue2te_mapping.find(Ue); \ - \ - if ( ptrUe==insT->ue2te_mapping.end() ) { \ + +#define getUeRetInt(insT, Ue) \ + auto ptrUe = insT->ue2te_mapping.find(Ue); \ + \ + if (ptrUe == insT->ue2te_mapping.end()) { \ LOG_E(GTPU, "[%ld] %s failed: while getting ue id %ld in hashtable ue_mapping\n", instance, __func__, ue_id); \ - pthread_mutex_unlock(&globGtp.gtp_lock); \ - return GTPNOK; \ + pthread_mutex_unlock(&globGtp.gtp_lock); \ + return GTPNOK; \ } - + #define HDR_MAX 256 // 256 is supposed to be larger than any gtp header -static int gtpv1uCreateAndSendMsg(int h, - uint32_t peerIp, - uint16_t peerPort, +static int gtpv1uCreateAndSendMsg(gtpv1u_bearer_t *bearer, int msgType, - teid_t teid, uint8_t *Msg, int msgLen, bool seqNumFlag, bool npduNumFlag, - int seqNum, - int npduNum, - int extHdrType, - uint8_t *extensionHeader_buffer, - uint8_t extensionHeader_length) { - LOG_D(GTPU, "Peer IP:%u peer port:%u outgoing teid:%u \n", peerIp, peerPort, teid); - + gtpu_extension_header_t *extensions, + int extensions_count) +{ DevAssert(msgLen + HDR_MAX < 65536); // maximum size of UDP packet - uint8_t buffer[msgLen+HDR_MAX]; - uint8_t *curPtr=buffer; - Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)buffer ; + uint8_t buffer[msgLen + HDR_MAX]; + uint8_t *curPtr = buffer; + Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)buffer; // N should be 0 for us (it was used only in 2G and 3G) - msgHdr->PN=npduNumFlag; - msgHdr->S=seqNumFlag; - msgHdr->E = extHdrType != NO_MORE_EXT_HDRS; - msgHdr->spare=0; - //PT=0 is for GTP' TS 32.295 (charging) - msgHdr->PT=1; - msgHdr->version=1; - msgHdr->msgType=msgType; - msgHdr->teid=htonl(teid); + msgHdr->PN = npduNumFlag; + msgHdr->S = seqNumFlag; + msgHdr->E = extensions_count != 0; + msgHdr->spare = 0; + // PT=0 is for GTP' TS 32.295 (charging) + msgHdr->PT = 1; + msgHdr->version = 1; + msgHdr->msgType = msgType; + msgHdr->teid = htonl(bearer->teid_outgoing); - curPtr+=sizeof(Gtpv1uMsgHeaderT); + curPtr += sizeof(Gtpv1uMsgHeaderT); - if (seqNumFlag || (extHdrType != NO_MORE_EXT_HDRS) || npduNumFlag) { - *(uint16_t *)curPtr = seqNumFlag ? seqNum : 0x0000; - curPtr+=sizeof(uint16_t); - *(uint8_t *)curPtr = npduNumFlag ? npduNum : 0x00; + if (msgHdr->PN || msgHdr->S || msgHdr->E) { + *(uint16_t *)curPtr = seqNumFlag ? bearer->seqNum : 0x0000; + curPtr += sizeof(uint16_t); + *(uint8_t *)curPtr = npduNumFlag ? bearer->npduNum : 0x00; curPtr++; - *(uint8_t *)curPtr = extHdrType; + *curPtr = extensions_count ? serialize_gtpu_extension_type(extensions[0].type) : 0; curPtr++; } - // Bug: if there is more than one extension, infinite loop on extensionHeader_buffer - while (extHdrType != NO_MORE_EXT_HDRS) { - if (extensionHeader_length > 0) { - memcpy(curPtr, extensionHeader_buffer, extensionHeader_length); - curPtr += extensionHeader_length; - LOG_D(GTPU, "Extension Header for DDD added. The length is: %d, extension header type is: %x \n", extensionHeader_length, *((uint8_t *)(buffer + 11))); - extHdrType = extensionHeader_buffer[extensionHeader_length - 1]; - LOG_D(GTPU, "Next extension header type is: %x \n", *((uint8_t *)(buffer + 11))); - } else { - LOG_W(GTPU, "Extension header type not supported, returning... \n"); + for (int i = 0; i < extensions_count; i++) { + int available_size = sizeof(buffer) - (curPtr - buffer); + gtpu_extension_header_type_t next = i == extensions_count - 1 ? GTPU_EXT_NONE : extensions[i + 1].type; + int len = serialize_extension(&extensions[i], next, curPtr, available_size); + if (len == -1) { + LOG_E(GTPU, "GTP extension serialization: buffer too small\n"); + return GTPNOK; } + curPtr += len; } - if (Msg!= NULL){ + if (Msg != NULL) { + int available_size = sizeof(buffer) - (curPtr - buffer); + if (msgLen > available_size) { + LOG_E(GTPU, "GTP message creation: buffer too small\n"); + return GTPNOK; + } memcpy(curPtr, Msg, msgLen); - curPtr+=msgLen; + curPtr += msgLen; } - msgHdr->msgLength = htons(curPtr-(buffer+sizeof(Gtpv1uMsgHeaderT))); - AssertFatal(curPtr-(buffer+msgLen) < HDR_MAX, "fixed max size of all headers too short"); - // Fix me: add IPv6 support, using flag ipVersion - struct sockaddr_in to= {0}; - to.sin_family = AF_INET; - to.sin_port = htons(peerPort); - to.sin_addr.s_addr = peerIp ; - LOG_D(GTPU,"sending packet size: %ld to %s\n",curPtr-buffer, inet_ntoa(to.sin_addr) ); - int ret; + msgHdr->msgLength = htons(curPtr - (buffer + sizeof(Gtpv1uMsgHeaderT))); + AssertFatal(curPtr - (buffer + msgLen) < HDR_MAX, "fixed max size of all headers too short"); - if ((ret=sendto(h, (void *)buffer, curPtr-buffer, 0,(struct sockaddr *)&to, sizeof(to) )) != curPtr-buffer ) { - LOG_E(GTPU, "[SD %d] Failed to send data to " IPV4_ADDR " on port %d, buffer size %lu, ret: %d, errno: %d\n", - h, IPV4_ADDR_FORMAT(peerIp), peerPort, curPtr-buffer, ret, errno); + // Fix me: add IPv6 support + DevAssert(bearer->ip.ss_family == AF_INET); + struct sockaddr_in *to = (struct sockaddr_in *)&bearer->ip; + LOG_D(GTPU, + "Peer IP:" IPV4_ADDR " port:%u outgoing teid:%x\n", + IPV4_ADDR_FORMAT(to->sin_addr.s_addr), + htons(to->sin_port), + bearer->teid_outgoing); + int ret = sendto(bearer->sock_fd, buffer, curPtr - buffer, 0, (struct sockaddr *)to, sizeof(*to)); + if (ret != curPtr - buffer) { + LOG_E(GTPU, + "[SD %d] Failed to send data buffer size %lu, ret: %d, errno: %d\n", + bearer->sock_fd, + curPtr - buffer, + ret, + errno); return GTPNOK; } - return !GTPNOK; + return !GTPNOK; } -void gtpv1uSendDirect(instance_t instance, - ue_id_t ue_id, - int bearer_id, - uint8_t *buf, - size_t len, - bool seqNumFlag, - bool npduNumFlag) +static void _gtpv1uSendDirect(instance_t instance, + ue_id_t ue_id, + int bearer_id, + uint8_t *buf, + size_t len, + bool seqNumFlag, + bool npduNumFlag, + int32_t nru_seqnum) { pthread_mutex_lock(&globGtp.gtp_lock); getInstRetVoid(compatInst(instance)); @@ -324,203 +345,227 @@ void gtpv1uSendDirect(instance_t instance, ptr2->second.npduNum++; // copy to release the mutex - gtpv1u_bearer_t tmp = ptr2->second; + gtpv1u_bearer_t bearer = ptr2->second; pthread_mutex_unlock(&globGtp.gtp_lock); - if (tmp.outgoing_qfi != -1) { - Gtpv1uExtHeaderT ext = {0}; - ext.ExtHeaderLen = 1; // in quad bytes EXT_HDR_LNTH_OCTET_UNITS - ext.pdusession_cntr.spare = 0; - ext.pdusession_cntr.PDU_type = UL_PDU_SESSION_INFORMATION; - ext.pdusession_cntr.QFI = tmp.outgoing_qfi; - ext.pdusession_cntr.Reflective_QoS_activation = false; - ext.pdusession_cntr.Paging_Policy_Indicator = false; - ext.NextExtHeaderType = NO_MORE_EXT_HDRS; - - gtpv1uCreateAndSendMsg(compatInst(instance), - tmp.outgoing_ip_addr, - tmp.outgoing_port, - GTP_GPDU, - tmp.teid_outgoing, - buf, - len, - seqNumFlag, - npduNumFlag, - tmp.seqNum, - tmp.npduNum, - PDU_SESSION_CONTAINER, - (uint8_t *)&ext, - sizeof(ext)); - } else { - gtpv1uCreateAndSendMsg(compatInst(instance), - tmp.outgoing_ip_addr, - tmp.outgoing_port, - GTP_GPDU, - tmp.teid_outgoing, - buf, - len, - seqNumFlag, - npduNumFlag, - tmp.seqNum, - tmp.npduNum, - NO_MORE_EXT_HDRS, - NULL, - 0); + int extension_count = 0; + gtpu_extension_header_t ext[2]; + if (bearer.outgoing_qfi != -1) { + /* 29.281 Figure 5.2.1-3 note 4 says PDU Session Container must come first. + * GTPU_EXT_UL_PDU_SESSION_INFORMATION is within a PDU Session Container + * so it must be put before any other extension. + */ + ext[extension_count] = { + .type = GTPU_EXT_UL_PDU_SESSION_INFORMATION, + .ul_pdu_session_information = { + .qmp = false, + .dl_delay_ind = false, + .ul_delay_ind = false, + .snp = false, + .n3n9_delay_ind = false, + .new_ie_flag = false, + .qfi = bearer.outgoing_qfi + } + }; + extension_count++; } + + if (nru_seqnum != -1) { + ext[extension_count] = { + .type = GTPU_EXT_DL_USER_DATA, + .dl_user_data = { + .dl_discard_blocks = false, + .dl_flush = false, + .report_polling = false, + .request_out_of_seq_report = false, + .report_delivered = false, + .user_data_existence_flag = false, + .assistance_info_report_polling_flag = false, + .retransmission_flag = false, + .nru_sequence_number = (uint32_t)nru_seqnum + } + }; + extension_count++; + } + + DevAssert(compatInst(instance) == bearer.sock_fd); + gtpv1uCreateAndSendMsg(&bearer, + GTP_GPDU, + buf, + len, + seqNumFlag, + npduNumFlag, + ext, + extension_count); } -static void fillDlDeliveryStatusReport(extensionHeader_t *extensionHeader, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN){ - - extensionHeader->buffer[0] = (1+sizeof(DlDataDeliveryStatus_flagsT)+(NR_PDCP_PDU_SN>0?3:0)+(NR_PDCP_PDU_SN>0?1:0)+1)/4; - DlDataDeliveryStatus_flagsT DlDataDeliveryStatus; - DlDataDeliveryStatus.deliveredPdcpSn = 0; - DlDataDeliveryStatus.transmittedPdcpSn= NR_PDCP_PDU_SN>0?1:0; - DlDataDeliveryStatus.pduType = 1; - DlDataDeliveryStatus.drbBufferSize = htonl(RLC_buffer_availability); - memcpy(extensionHeader->buffer+1, &DlDataDeliveryStatus, sizeof(DlDataDeliveryStatus_flagsT)); - uint8_t offset = sizeof(DlDataDeliveryStatus_flagsT)+1; - - if(NR_PDCP_PDU_SN>0){ - extensionHeader->buffer[offset] = (NR_PDCP_PDU_SN >> 16) & 0xff; - extensionHeader->buffer[offset+1] = (NR_PDCP_PDU_SN >> 8) & 0xff; - extensionHeader->buffer[offset+2] = NR_PDCP_PDU_SN & 0xff; - LOG_D(GTPU, "Octets reporting NR_PDCP_PDU_SN, extensionHeader->buffer[offset]: %u, extensionHeader->buffer[offset+1]:%u, extensionHeader->buffer[offset+2]:%u \n", extensionHeader->buffer[offset], extensionHeader->buffer[offset+1],extensionHeader->buffer[offset+2]); - extensionHeader->buffer[offset+3] = 0x00; //Padding octet - offset = offset+3; - } - extensionHeader->buffer[offset] = 0x00; //No more extension headers - /*Total size of DDD_status PDU = size of mandatory part + - * 3 octets for highest transmitted/delivered PDCP SN + - * 1 octet for padding + 1 octet for next extension header type, - * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/ - extensionHeader->length = 1+sizeof(DlDataDeliveryStatus_flagsT)+ - (NR_PDCP_PDU_SN>0?3:0)+ - (NR_PDCP_PDU_SN>0?1:0)+1; +void gtpv1uSendDirect(instance_t instance, + ue_id_t ue_id, + int bearer_id, + uint8_t *buf, + size_t len, + bool seqNumFlag, + bool npduNumFlag) +{ + _gtpv1uSendDirect(instance, + ue_id, + bearer_id, + buf, + len, + seqNumFlag, + npduNumFlag, + -1); } -static void gtpv1uSendDlDeliveryStatus(instance_t instance, gtpv1u_DU_buffer_report_req_t *req){ - ue_id_t ue_id=req->ue_id; - int bearer_id=req->pdusession_id; +void gtpv1uSendDirectWithNRUSeqNum(instance_t instance, + ue_id_t ue_id, + int bearer_id, + uint8_t *buf, + size_t len) +{ pthread_mutex_lock(&globGtp.gtp_lock); getInstRetVoid(compatInst(instance)); getUeRetVoid(inst, ue_id); + auto ptr2 = ptrUe->second.bearers.find(bearer_id); - auto ptr2=ptrUe->second.bearers.find(bearer_id); - - if ( ptr2 == ptrUe->second.bearers.end() ) { - LOG_D(GTPU,"GTP-U instance: %ld sending a packet to a non existant UE ID:RAB: %lu/%x\n", instance, ue_id, bearer_id); + if (ptr2 == ptrUe->second.bearers.end()) { + LOG_E(GTPU, "[%ld] GTP-U instance: sending a packet to a non existant UE:RAB: %lx/%x\n", instance, ue_id, bearer_id); pthread_mutex_unlock(&globGtp.gtp_lock); return; } - extensionHeader_t *extensionHeader; - extensionHeader = (extensionHeader_t *) calloc(1, sizeof(extensionHeader_t)); - fillDlDeliveryStatusReport(extensionHeader, req->buffer_availability,0); + int32_t nru_seqnum = ptr2->second.nru_sequence_number; + ptr2->second.nru_sequence_number++; + ptr2->second.nru_sequence_number &= (1 << 24) - 1; - LOG_I(GTPU,"[%ld] GTP-U sending DL Data Delivery status to UE ID:RAB:teid %lu/%x/%x, oldseq %d, oldnum %d\n", - instance, ue_id, bearer_id,ptr2->second.teid_outgoing, ptr2->second.seqNum,ptr2->second.npduNum ); - // copy to release the mutex - gtpv1u_bearer_t tmp=ptr2->second; pthread_mutex_unlock(&globGtp.gtp_lock); - gtpv1uCreateAndSendMsg( - compatInst(instance), tmp.outgoing_ip_addr, tmp.outgoing_port, GTP_GPDU, tmp.teid_outgoing, NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER, extensionHeader->buffer, extensionHeader->length); + + _gtpv1uSendDirect(instance, + ue_id, + bearer_id, + buf, + len, + false, + false, + nru_seqnum); +} + +static void fillDlDeliveryStatusReport(gtpu_extension_header_t *ext, uint32_t RLC_buffer_availability, uint32_t NR_PDCP_PDU_SN) +{ + *ext = { + .type = GTPU_EXT_DL_DATA_DELIVERY_STATUS, + .dl_data_delivery_status = { + /* previous version of the code was sending highest_transmitted_nr_pdcp_sn if + * it is != 0, let's do the same for the moment */ + .highest_transmitted_nr_pdcp_sn_ind = NR_PDCP_PDU_SN != 0, + .highest_delivered_nr_pdcp_sn_ind = false, + .final_frame_ind = false, + .lost_packet_report = false, + .delivered_nr_pdcp_sn_range_ind = false, + .data_rate_ind = false, + .retransmitted_nr_pdcp_sn_ind = false, + .delivered_retransmitted_nr_pdcp_ind = false, + .cause_report = false, + .desired_buffer_size = RLC_buffer_availability, + .highest_transmitted_nr_pdcp_sn = NR_PDCP_PDU_SN + } + }; } static void gtpv1uEndTunnel(instance_t instance, gtpv1u_enb_end_marker_req_t *req) { - ue_id_t ue_id=req->rnti; - int bearer_id=req->rab_id; + ue_id_t ue_id = req->rnti; + int bearer_id = req->rab_id; pthread_mutex_lock(&globGtp.gtp_lock); getInstRetVoid(compatInst(instance)); getUeRetVoid(inst, ue_id); - auto ptr2=ptrUe->second.bearers.find(bearer_id); + auto ptr2 = ptrUe->second.bearers.find(bearer_id); - if ( ptr2 == ptrUe->second.bearers.end() ) { - LOG_E(GTPU,"[%ld] GTP-U sending a packet to a non existant UE:RAB: %lx/%x\n", instance, ue_id, bearer_id); + if (ptr2 == ptrUe->second.bearers.end()) { + LOG_E(GTPU, "[%ld] GTP-U sending a packet to a non existant UE:RAB: %lx/%x\n", instance, ue_id, bearer_id); pthread_mutex_unlock(&globGtp.gtp_lock); return; } - LOG_D(GTPU,"[%ld] sending a end packet packet to UE:RAB:teid %lx/%x/%x\n", - instance, ue_id, bearer_id,ptr2->second.teid_outgoing); - gtpv1u_bearer_t tmp=ptr2->second; + LOG_D(GTPU, + "[%ld] sending a end packet packet to UE:RAB:teid %lx/%x/%x\n", + instance, + ue_id, + bearer_id, + ptr2->second.teid_outgoing); + gtpv1u_bearer_t tmp = ptr2->second; pthread_mutex_unlock(&globGtp.gtp_lock); - Gtpv1uMsgHeaderT msgHdr; + Gtpv1uMsgHeaderT msgHdr; // N should be 0 for us (it was used only in 2G and 3G) - msgHdr.PN=0; - msgHdr.S=0; - msgHdr.E=0; - msgHdr.spare=0; - //PT=0 is for GTP' TS 32.295 (charging) - msgHdr.PT=1; - msgHdr.version=1; - msgHdr.msgType=GTP_END_MARKER; - msgHdr.msgLength=htons(0); - msgHdr.teid=htonl(tmp.teid_outgoing); - // Fix me: add IPv6 support, using flag ipVersion - static struct sockaddr_in to= {0}; - to.sin_family = AF_INET; - to.sin_port = htons(tmp.outgoing_port); - to.sin_addr.s_addr = tmp.outgoing_ip_addr; - char ip4[INET_ADDRSTRLEN]; - //char ip6[INET6_ADDRSTRLEN]; - LOG_D(GTPU,"[%ld] sending end packet to %s\n", instance, inet_ntoa(to.sin_addr) ); + msgHdr.PN = 0; + msgHdr.S = 0; + msgHdr.E = 0; + msgHdr.spare = 0; + // PT=0 is for GTP' TS 32.295 (charging) + msgHdr.PT = 1; + msgHdr.version = 1; + msgHdr.msgType = GTP_END_MARKER; + msgHdr.msgLength = htons(0); + msgHdr.teid = htonl(tmp.teid_outgoing); - if (sendto(compatInst(instance), (void *)&msgHdr, sizeof(msgHdr), 0,(struct sockaddr *)&to, sizeof(to) ) != sizeof(msgHdr)) { - LOG_E(GTPU, - "[%ld] Failed to send data to %s on port %d, buffer size %lu\n", - compatInst(instance), inet_ntop(AF_INET, &tmp.outgoing_ip_addr, ip4, INET_ADDRSTRLEN), tmp.outgoing_port, sizeof(msgHdr)); + // Fix me: add IPv6 support + DevAssert(instance == tmp.sock_fd); + DevAssert(tmp.ip.ss_family == AF_INET); + struct sockaddr_in *to = (struct sockaddr_in *)&tmp.ip; + LOG_D(GTPU, "[%ld] sending end packet to " IPV4_ADDR " port %d\n", instance, IPV4_ADDR_FORMAT(to->sin_addr.s_addr), htons(to->sin_port)); + + ssize_t ret = sendto(tmp.sock_fd, &msgHdr, sizeof(msgHdr), 0, (struct sockaddr *)to, sizeof(*to)); + if (ret != sizeof(msgHdr)) { + LOG_E(GTPU, "[%d] Failed to send data with buffer size %lu: ret %ld errno %d\n", tmp.sock_fd, sizeof(msgHdr), ret, errno); } } -static int udpServerSocket(openAddr_s addr) { +static int udpServerSocket(openAddr_s addr) +{ LOG_I(GTPU, "Initializing UDP for local address %s with port %s\n", addr.originHost, addr.originService); int status; - struct addrinfo hints= {0}, *servinfo, *p; + struct addrinfo hints = {0}, *servinfo, *p; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; if ((status = getaddrinfo(addr.originHost, addr.originService, &hints, &servinfo)) != 0) { - LOG_E(GTPU,"getaddrinfo error: %s\n", gai_strerror(status)); + LOG_E(GTPU, "getaddrinfo error: %s\n", gai_strerror(status)); return -1; } - int sockfd=-1; + int sockfd = -1; // loop through all the results and bind to the first we can - for(p = servinfo; p != NULL; p = p->ai_next) { - if ((sockfd = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) { - LOG_W(GTPU,"socket: %s\n", strerror(errno)); + for (p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + LOG_W(GTPU, "socket: %s\n", strerror(errno)); continue; } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); - LOG_W(GTPU,"bind: %s\n", strerror(errno)); + LOG_W(GTPU, "bind: %s\n", strerror(errno)); continue; } else { // We create the gtp instance on the socket - globGtp.instances[sockfd].addr=addr; + globGtp.instances[sockfd].addr = addr; if (p->ai_family == AF_INET) { - struct sockaddr_in *ipv4=(struct sockaddr_in *)p->ai_addr; - memcpy(globGtp.instances[sockfd].foundAddr, - &ipv4->sin_addr.s_addr, sizeof(ipv4->sin_addr.s_addr)); - globGtp.instances[sockfd].foundAddrLen=sizeof(ipv4->sin_addr.s_addr); - globGtp.instances[sockfd].ipVersion=4; + struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; + memcpy(globGtp.instances[sockfd].foundAddr, &ipv4->sin_addr.s_addr, sizeof(ipv4->sin_addr.s_addr)); + globGtp.instances[sockfd].foundAddrLen = sizeof(ipv4->sin_addr.s_addr); + globGtp.instances[sockfd].ipVersion = 4; break; } else if (p->ai_family == AF_INET6) { - LOG_W(GTPU,"Local address is IP v6\n"); - struct sockaddr_in6 *ipv6=(struct sockaddr_in6 *)p->ai_addr; - memcpy(globGtp.instances[sockfd].foundAddr, - &ipv6->sin6_addr.s6_addr, sizeof(ipv6->sin6_addr.s6_addr)); - globGtp.instances[sockfd].foundAddrLen=sizeof(ipv6->sin6_addr.s6_addr); - globGtp.instances[sockfd].ipVersion=6; + LOG_W(GTPU, "Local address is IP v6\n"); + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; + memcpy(globGtp.instances[sockfd].foundAddr, &ipv6->sin6_addr.s6_addr, sizeof(ipv6->sin6_addr.s6_addr)); + globGtp.instances[sockfd].foundAddrLen = sizeof(ipv6->sin6_addr.s6_addr); + globGtp.instances[sockfd].ipVersion = 6; } else - AssertFatal(false,"Local address is not IPv4 or IPv6"); + AssertFatal(false, "Local address is not IPv4 or IPv6"); } break; // if we get here, we must have connected successfully @@ -530,46 +575,78 @@ static int udpServerSocket(openAddr_s addr) { if (p == NULL) { // looped off the end of the list with no successful bind - LOG_E(GTPU,"failed to bind socket: %s %s \n", addr.originHost, addr.originService); + LOG_E(GTPU, "failed to bind socket: %s %s \n", addr.originHost, addr.originService); return -1; } - int sendbuff = 1000*1000*10; - AssertFatal(0==setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)),""); - LOG_D(GTPU,"[%d] Created listener for paquets to: %s:%s, send buffer size: %d\n", sockfd, addr.originHost, addr.originService,sendbuff); + int sendbuff = 1000 * 1000 * 10; + AssertFatal(0 == setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)), ""); + LOG_D(GTPU, + "[%d] Created listener for paquets to: %s:%s, send buffer size: %d\n", + sockfd, + addr.originHost, + addr.originService, + sendbuff); return sockfd; } -instance_t gtpv1Init(openAddr_t context) { +static void* gtpv1uReceiver(void *thr); +instance_t gtpv1Init(openAddr_t context) +{ pthread_mutex_lock(&globGtp.gtp_lock); - int id=udpServerSocket(context); + int id = udpServerSocket(context); - if (id>=0) { - itti_subscribe_event_fd(TASK_GTPV1_U, id); + if (id >= 0) { + LOG_I(GTPU, "Created gtpu instance id: %d\n", id); + getInstRetInt(compatInst(id)); + inst->thrData.h = id; + char name[32]; + snprintf(name, sizeof(name), "GTPrx_%d", id); + threadCreate(&inst->thrData.t, gtpv1uReceiver, &inst->thrData, name, -1, OAI_PRIORITY_RT); } else - LOG_E(GTPU,"can't create GTP-U instance\n"); + LOG_E(GTPU, "can't create GTP-U instance\n"); pthread_mutex_unlock(&globGtp.gtp_lock); - LOG_I(GTPU, "Created gtpu instance id: %d\n", id); return id; } -void GtpuUpdateTunnelOutgoingAddressAndTeid(instance_t instance, ue_id_t ue_id, ebi_t bearer_id, in_addr_t newOutgoingAddr, teid_t newOutgoingTeid) { +void GtpuUpdateTunnelOutgoingAddressAndTeid(instance_t instance, + ue_id_t ue_id, + ebi_t bearer_id, + in_addr_t newOutgoingAddr, + teid_t newOutgoingTeid) +{ pthread_mutex_lock(&globGtp.gtp_lock); getInstRetVoid(compatInst(instance)); getUeRetVoid(inst, ue_id); - auto ptr2=ptrUe->second.bearers.find(bearer_id); + auto ptr2 = ptrUe->second.bearers.find(bearer_id); - if ( ptr2 == ptrUe->second.bearers.end() ) { - LOG_E(GTPU,"[%ld] Update tunnel for a existing ue id %lu, but wrong bearer_id %u\n", instance, ue_id, bearer_id); + if (ptr2 == ptrUe->second.bearers.end()) { + LOG_E(GTPU, "[%ld] Update tunnel for a existing ue id %lu, but wrong bearer_id %u\n", instance, ue_id, bearer_id); pthread_mutex_unlock(&globGtp.gtp_lock); return; } - ptr2->second.outgoing_ip_addr = newOutgoingAddr; + struct sockaddr_in *sockaddr = (struct sockaddr_in *)&ptr2->second.ip; + sockaddr->sin_family = AF_INET; + memcpy(&sockaddr->sin_addr, &newOutgoingAddr, sizeof(newOutgoingAddr)); + AssertFatal(ptr2->second.ip.ss_family == AF_INET, "only IPv4 is supported\n"); ptr2->second.teid_outgoing = newOutgoingTeid; - LOG_I(GTPU, "[%ld] Tunnel Outgoing TEID updated to %x and address to %x\n", instance, ptr2->second.teid_outgoing, ptr2->second.outgoing_ip_addr); + char ip4[INET_ADDRSTRLEN]; + char ip6[INET6_ADDRSTRLEN]; + struct sockaddr_in *sa4 = (struct sockaddr_in *)sockaddr; + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sockaddr; + LOG_I(GTPU, + "[%ld] UE ID %ld: Update tunnel TEID incoming %x outgoing %x to remote IPv4 %s, IPv6 %s, port %d\n", + instance, + ue_id, + ptr2->second.teid_incoming, + ptr2->second.teid_outgoing, + inet_ntop(AF_INET, &sa4->sin_addr, ip4, INET_ADDRSTRLEN), + inet_ntop(AF_INET6, &sa6->sin6_addr, ip6, INET6_ADDRSTRLEN), + ntohs(sa4->sin_port)); + pthread_mutex_unlock(&globGtp.gtp_lock); return; } @@ -581,23 +658,23 @@ teid_t newGtpuCreateTunnel(instance_t instance, teid_t outgoing_teid, int outgoing_qfi, transport_layer_addr_t remoteAddr, - int port, gtpCallback callBack, - gtpCallbackSDAP callBackSDAP) { + gtpCallbackSDAP callBackSDAP) +{ pthread_mutex_lock(&globGtp.gtp_lock); getInstRetInt(compatInst(instance)); - auto it=inst->ue2te_mapping.find(ue_id); + auto it = inst->ue2te_mapping.find(ue_id); - if ( it != inst->ue2te_mapping.end() && it->second.bearers.find(outgoing_bearer_id) != it->second.bearers.end()) { - LOG_W(GTPU,"[%ld] Create a config for a already existing GTP tunnel (ue id %lu)\n", instance, ue_id); + if (it != inst->ue2te_mapping.end() && it->second.bearers.find(outgoing_bearer_id) != it->second.bearers.end()) { + LOG_W(GTPU, "[%ld] Create a config for a already existing GTP tunnel (ue id %lu)\n", instance, ue_id); inst->ue2te_mapping.erase(it); } - teid_t incoming_teid=gtpv1uNewTeid(); + teid_t incoming_teid = gtpv1uNewTeid(); while (globGtp.te2ue_mapping.find(incoming_teid) != globGtp.te2ue_mapping.end()) { LOG_W(GTPU, "[%ld] generated a random Teid that exists, re-generating (%x)\n", instance, incoming_teid); - incoming_teid=gtpv1uNewTeid(); + incoming_teid = gtpv1uNewTeid(); }; globGtp.te2ue_mapping[incoming_teid].ue_id = ue_id; @@ -607,71 +684,74 @@ teid_t newGtpuCreateTunnel(instance_t instance, globGtp.te2ue_mapping[incoming_teid].callBackSDAP = callBackSDAP; globGtp.te2ue_mapping[incoming_teid].pdusession_id = (uint8_t)outgoing_bearer_id; - gtpv1u_bearer_t *tmp=&inst->ue2te_mapping[ue_id].bearers[outgoing_bearer_id]; + gtpv1u_bearer_t bearer = { + .sock_fd = (int) compatInst(instance), // avoid warning on narrowing conversion: instance is long, sock_fd is int + .teid_incoming = incoming_teid, + .teid_outgoing = outgoing_teid, + .outgoing_qfi = outgoing_qfi, + }; int addrs_length_in_bytes = remoteAddr.length / 8; - + struct sockaddr_in *sa4 = (struct sockaddr_in *)&bearer.ip; + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&bearer.ip; switch (addrs_length_in_bytes) { case 4: - memcpy(&tmp->outgoing_ip_addr,remoteAddr.buffer,4); + memcpy(&sa4->sin_addr, remoteAddr.buffer, 4); + sa4->sin_family = AF_INET; + sa4->sin_port = htons(inst->get_dstport()); break; case 16: - memcpy(tmp->outgoing_ip6_addr.s6_addr,remoteAddr.buffer, - 16); + AssertFatal(false, "IPv6 not supported\n"); break; case 20: - memcpy(&tmp->outgoing_ip_addr,remoteAddr.buffer,4); - memcpy(tmp->outgoing_ip6_addr.s6_addr, - remoteAddr.buffer+4, - 16); + AssertFatal(false, "dual-IPv4/v6 not supported\n"); + break; default: AssertFatal(false, "SGW Address size impossible"); } - tmp->teid_incoming = incoming_teid; - tmp->outgoing_port=port; - tmp->teid_outgoing= outgoing_teid; - tmp->outgoing_qfi=outgoing_qfi; + inst->ue2te_mapping[ue_id].bearers[outgoing_bearer_id] = bearer; pthread_mutex_unlock(&globGtp.gtp_lock); char ip4[INET_ADDRSTRLEN]; char ip6[INET6_ADDRSTRLEN]; LOG_I(GTPU, - "[%ld] Created tunnel for UE ID %lu, teid for incoming: %x, teid for outgoing %x to remote IPv4: %s, IPv6 %s\n", + "[%ld] UE ID %ld: Create tunnel TEID incoming %x outgoing %x to remote IPv4 %s, IPv6 %s, port %d\n", instance, ue_id, - tmp->teid_incoming, - tmp->teid_outgoing, - inet_ntop(AF_INET, (void *)&tmp->outgoing_ip_addr, ip4, INET_ADDRSTRLEN), - inet_ntop(AF_INET6, (void *)&tmp->outgoing_ip6_addr.s6_addr, ip6, INET6_ADDRSTRLEN)); + bearer.teid_incoming, + bearer.teid_outgoing, + inet_ntop(AF_INET, &sa4->sin_addr, ip4, INET_ADDRSTRLEN), + inet_ntop(AF_INET6, &sa6->sin6_addr, ip6, INET6_ADDRSTRLEN), + ntohs(sa4->sin_port)); return incoming_teid; } int gtpv1u_create_s1u_tunnel(instance_t instance, - const gtpv1u_enb_create_tunnel_req_t *create_tunnel_req, + const gtpv1u_enb_create_tunnel_req_t *create_tunnel_req, gtpv1u_enb_create_tunnel_resp_t *create_tunnel_resp, gtpCallback callBack) { - LOG_D(GTPU, "[%ld] Start create tunnels for UE ID %u, num_tunnels %d, sgw_S1u_teid %x\n", + LOG_D(GTPU, + "[%ld] Start create tunnels for UE ID %u, num_tunnels %d, sgw_S1u_teid %x\n", instance, create_tunnel_req->rnti, create_tunnel_req->num_tunnels, create_tunnel_req->sgw_S1u_teid[0]); pthread_mutex_lock(&globGtp.gtp_lock); getInstRetInt(compatInst(instance)); - - tcp_udp_port_t dstport=inst->get_dstport(); + uint8_t addr[inst->foundAddrLen]; memcpy(addr, inst->foundAddr, inst->foundAddrLen); pthread_mutex_unlock(&globGtp.gtp_lock); - + for (int i = 0; i < create_tunnel_req->num_tunnels; i++) { AssertFatal(create_tunnel_req->eps_bearer_id[i] > 4, "From legacy code not clear, seems impossible (bearer=%d)\n", create_tunnel_req->eps_bearer_id[i]); - int incoming_rb_id=create_tunnel_req->eps_bearer_id[i]-4; + int incoming_rb_id = create_tunnel_req->eps_bearer_id[i] - 4; teid_t teid = newGtpuCreateTunnel(compatInst(instance), create_tunnel_req->rnti, incoming_rb_id, @@ -679,27 +759,26 @@ int gtpv1u_create_s1u_tunnel(instance_t instance, create_tunnel_req->sgw_S1u_teid[i], -1, // no pdu session in 4G create_tunnel_req->sgw_addr[i], - dstport, callBack, NULL); - create_tunnel_resp->status=0; - create_tunnel_resp->rnti=create_tunnel_req->rnti; - create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels; - create_tunnel_resp->enb_S1u_teid[i]=teid; + create_tunnel_resp->status = 0; + create_tunnel_resp->rnti = create_tunnel_req->rnti; + create_tunnel_resp->num_tunnels = create_tunnel_req->num_tunnels; + create_tunnel_resp->enb_S1u_teid[i] = teid; create_tunnel_resp->eps_bearer_id[i] = create_tunnel_req->eps_bearer_id[i]; - memcpy(create_tunnel_resp->enb_addr.buffer,addr,sizeof(addr)); - create_tunnel_resp->enb_addr.length= sizeof(addr); + memcpy(create_tunnel_resp->enb_addr.buffer, addr, sizeof(addr)); + create_tunnel_resp->enb_addr.length = sizeof(addr); } return !GTPNOK; } -int gtpv1u_update_s1u_tunnel( - const instance_t instance, - const gtpv1u_enb_create_tunnel_req_t *const create_tunnel_req, - const rnti_t prior_rnti -) { - LOG_D(GTPU, "[%ld] Start update tunnels for old RNTI %x, new RNTI %x, num_tunnels %d, sgw_S1u_teid %x, eps_bearer_id %x\n", +int gtpv1u_update_s1u_tunnel(const instance_t instance, + const gtpv1u_enb_create_tunnel_req_t *const create_tunnel_req, + const rnti_t prior_rnti) +{ + LOG_D(GTPU, + "[%ld] Start update tunnels for old RNTI %x, new RNTI %x, num_tunnels %d, sgw_S1u_teid %x, eps_bearer_id %x\n", instance, prior_rnti, create_tunnel_req->rnti, @@ -709,22 +788,28 @@ int gtpv1u_update_s1u_tunnel( pthread_mutex_lock(&globGtp.gtp_lock); getInstRetInt(compatInst(instance)); - if ( inst->ue2te_mapping.find(create_tunnel_req->rnti) == inst->ue2te_mapping.end() ) { - LOG_E(GTPU,"[%ld] Update not already existing tunnel (new rnti %x, old rnti %x)\n", - instance, create_tunnel_req->rnti, prior_rnti); + if (inst->ue2te_mapping.find(create_tunnel_req->rnti) == inst->ue2te_mapping.end()) { + LOG_E(GTPU, + "[%ld] Update not already existing tunnel (new rnti %x, old rnti %x)\n", + instance, + create_tunnel_req->rnti, + prior_rnti); } - auto it=inst->ue2te_mapping.find(prior_rnti); + auto it = inst->ue2te_mapping.find(prior_rnti); - if ( it != inst->ue2te_mapping.end() ) { + if (it != inst->ue2te_mapping.end()) { pthread_mutex_unlock(&globGtp.gtp_lock); - AssertFatal(false, "logic bug: update of non-existing tunnel (new ue id %u, old ue id %u)\n", create_tunnel_req->rnti, prior_rnti); + AssertFatal(false, + "logic bug: update of non-existing tunnel (new ue id %u, old ue id %u)\n", + create_tunnel_req->rnti, + prior_rnti); /* we don't know if we need 4G or 5G PDCP and can therefore not create a * new tunnel */ return 0; } - inst->ue2te_mapping[create_tunnel_req->rnti]=it->second; + inst->ue2te_mapping[create_tunnel_req->rnti] = it->second; inst->ue2te_mapping.erase(it); pthread_mutex_unlock(&globGtp.gtp_lock); return 0; @@ -736,7 +821,8 @@ int gtpv1u_create_ngu_tunnel(const instance_t instance, gtpCallback callBack, gtpCallbackSDAP callBackSDAP) { - LOG_D(GTPU, "[%ld] Start create tunnels for ue id %lu, num_tunnels %d, sgw_S1u_teid %x\n", + LOG_D(GTPU, + "[%ld] Start create tunnels for ue id %lu, num_tunnels %d, sgw_S1u_teid %x\n", instance, create_tunnel_req->ue_id, create_tunnel_req->num_tunnels, @@ -744,7 +830,6 @@ int gtpv1u_create_ngu_tunnel(const instance_t instance, pthread_mutex_lock(&globGtp.gtp_lock); getInstRetInt(compatInst(instance)); - tcp_udp_port_t dstport = inst->get_dstport(); uint8_t addr[inst->foundAddrLen]; memcpy(addr, inst->foundAddr, inst->foundAddrLen); pthread_mutex_unlock(&globGtp.gtp_lock); @@ -756,15 +841,14 @@ int gtpv1u_create_ngu_tunnel(const instance_t instance, create_tunnel_req->outgoing_teid[i], create_tunnel_req->outgoing_qfi[i], create_tunnel_req->dst_addr[i], - dstport, callBack, callBackSDAP); - create_tunnel_resp->status=0; - create_tunnel_resp->ue_id=create_tunnel_req->ue_id; - create_tunnel_resp->num_tunnels=create_tunnel_req->num_tunnels; - create_tunnel_resp->gnb_NGu_teid[i]=teid; - memcpy(create_tunnel_resp->gnb_addr.buffer,addr,sizeof(addr)); - create_tunnel_resp->gnb_addr.length= sizeof(addr); + create_tunnel_resp->status = 0; + create_tunnel_resp->ue_id = create_tunnel_req->ue_id; + create_tunnel_resp->num_tunnels = create_tunnel_req->num_tunnels; + create_tunnel_resp->gnb_NGu_teid[i] = teid; + memcpy(create_tunnel_resp->gnb_addr.buffer, addr, sizeof(addr)); + create_tunnel_resp->gnb_addr.length = sizeof(addr); create_tunnel_resp->pdusession_id[i] = create_tunnel_req->pdusession_id[i]; } @@ -799,11 +883,11 @@ int gtpv1u_update_ue_id(const instance_t instanceP, ue_id_t old_ue_id, ue_id_t n return !GTPNOK; } -int gtpv1u_create_x2u_tunnel( - const instance_t instanceP, - const gtpv1u_enb_create_x2u_tunnel_req_t *const create_tunnel_req_pP, - gtpv1u_enb_create_x2u_tunnel_resp_t *const create_tunnel_resp_pP) { - AssertFatal( false, "to be developped\n"); +int gtpv1u_create_x2u_tunnel(const instance_t instanceP, + const gtpv1u_enb_create_x2u_tunnel_req_t *const create_tunnel_req_pP, + gtpv1u_enb_create_x2u_tunnel_resp_t *const create_tunnel_resp_pP) +{ + AssertFatal(false, "to be developped\n"); } int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id) @@ -827,35 +911,33 @@ int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id) ue_it->second.bearers.erase(rb_id); pthread_mutex_unlock(&globGtp.gtp_lock); LOG_I(GTPU, "Deleted tunnel TEID %d (RB %d) for ue id %ld, remaining bearers:\n", teid, rb_id, ue_id); - for (auto b: ue_it->second.bearers) + for (auto b : ue_it->second.bearers) LOG_I(GTPU, "bearer %ld\n", b.first); return !GTPNOK; } -int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id) { - LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n", - instance, ue_id); +int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id) +{ + LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n", instance, ue_id); pthread_mutex_lock(&globGtp.gtp_lock); getInstRetInt(compatInst(instance)); getUeRetInt(inst, ue_id); - int nb=0; + int nb = 0; - for (auto j=ptrUe->second.bearers.begin(); - j!=ptrUe->second.bearers.end(); - ++j) { + for (auto j = ptrUe->second.bearers.begin(); j != ptrUe->second.bearers.end(); ++j) { globGtp.te2ue_mapping.erase(j->second.teid_incoming); nb++; } inst->ue2te_mapping.erase(ptrUe); pthread_mutex_unlock(&globGtp.gtp_lock); - LOG_I(GTPU, "[%ld] Deleted all tunnels for ue id %ld (%d tunnels deleted)\n", instance, ue_id, nb); + LOG_I(GTPU, "[%ld] UE ID %ld: Delete all tunnels (%d tunnels)\n", instance, ue_id, nb); return !GTPNOK; } -int gtpv1u_delete_s1u_tunnel( const instance_t instance, - const gtpv1u_enb_delete_tunnel_req_t *const req_pP) { +int gtpv1u_delete_s1u_tunnel(const instance_t instance, const gtpv1u_enb_delete_tunnel_req_t *const req_pP) +{ LOG_D(GTPU, "[%ld] Start delete tunnels for RNTI %x\n", instance, req_pP->rnti); pthread_mutex_lock(&globGtp.gtp_lock); auto inst = &globGtp.instances[compatInst(instance)]; @@ -897,26 +979,26 @@ int gtpv1u_delete_all_s1u_tunnel(const instance_t instance, const rnti_t rnti) return newGtpuDeleteAllTunnels(instance, rnti); } -int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id) { - LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n", - instance, ue_id); +int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id) +{ + LOG_D(GTPU, "[%ld] Start delete tunnels for ue id %lu\n", instance, ue_id); pthread_mutex_lock(&globGtp.gtp_lock); getInstRetInt(compatInst(instance)); getUeRetInt(inst, ue_id); - int nb=0; + int nb = 0; - for (int i=0; isecond.bearers.find(pdusession_id[i]); + for (int i = 0; i < nbTunnels; i++) { + auto ptr2 = ptrUe->second.bearers.find(pdusession_id[i]); - if ( ptr2 == ptrUe->second.bearers.end() ) { - LOG_E(GTPU,"[%ld] GTP-U instance: delete of not existing tunnel UE ID:RAB: %ld/%x\n", instance, ue_id, pdusession_id[i]); + if (ptr2 == ptrUe->second.bearers.end()) { + LOG_E(GTPU, "[%ld] GTP-U instance: delete of not existing tunnel UE ID:RAB: %ld/%x\n", instance, ue_id, pdusession_id[i]); } else { globGtp.te2ue_mapping.erase(ptr2->second.teid_incoming); nb++; } } - if (ptrUe->second.bearers.size() == 0 ) + if (ptrUe->second.bearers.size() == 0) // no tunnels on this ue id, erase the ue entry inst->ue2te_mapping.erase(ptrUe); @@ -925,56 +1007,76 @@ int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdus return !GTPNOK; } -int gtpv1u_delete_x2u_tunnel( const instance_t instanceP, - const gtpv1u_enb_delete_tunnel_req_t *const req_pP) { - LOG_E(GTPU,"x2 tunnel not implemented\n"); +int gtpv1u_delete_x2u_tunnel(const instance_t instanceP, const gtpv1u_enb_delete_tunnel_req_t *const req_pP) +{ + LOG_E(GTPU, "x2 tunnel not implemented\n"); return 0; } -int gtpv1u_delete_ngu_tunnel( const instance_t instance, - gtpv1u_gnb_delete_tunnel_req_t *req) { - return newGtpuDeleteTunnels(instance, req->ue_id, req->num_pdusession, req->pdusession_id); +int gtpv1u_delete_ngu_tunnel(const instance_t instance, gtpv1u_gnb_delete_tunnel_req_t *req) +{ + return newGtpuDeleteTunnels(instance, req->ue_id, req->num_pdusession, req->pdusession_id); } -static int Gtpv1uHandleEchoReq(int h, - uint8_t *msgBuf, - uint32_t msgBufLen, - uint16_t peerPort, - uint32_t peerIp) { - Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *) msgBuf; +static gtpv1u_bearer_t create_bearer(int socket, const struct sockaddr_in *addr, uint32_t teid, uint16_t seq) +{ + gtpv1u_bearer_t bearer = {.sock_fd = socket, .teid_outgoing = teid, .seqNum = seq}; + memcpy(&bearer.ip, addr, sizeof(*addr)); + return bearer; +} - if ( msgHdr->version != 1 || msgHdr->PT != 1 ) { +static int Gtpv1uHandleEchoReq(int h, uint8_t *msgBuf, uint32_t msgBufLen, const struct sockaddr_in *addr) +{ + Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)msgBuf; + + if (msgHdr->version != 1 || msgHdr->PT != 1) { LOG_E(GTPU, "[%d] Received a packet that is not GTP header\n", h); return GTPNOK; } - if ( msgHdr->S != 1 ) { + if (msgHdr->S != 1) { LOG_E(GTPU, "[%d] Received a echo request packet with no sequence number \n", h); return GTPNOK; } - uint16_t seq=ntohs(*(uint16_t *)(msgHdr+1)); + uint16_t seq = ntohs(*(uint16_t *)(msgHdr + 1)); LOG_D(GTPU, "[%d] Received a echo request, TEID: %d, seq: %hu\n", h, msgHdr->teid, seq); - uint8_t recovery[2]= {14,0}; - return gtpv1uCreateAndSendMsg(h, peerIp, peerPort, GTP_ECHO_RSP, ntohl(msgHdr->teid), recovery, sizeof recovery, true, false, seq, 0, NO_MORE_EXT_HDRS, NULL, 0); + uint8_t recovery[2] = {14, 0}; + gtpv1u_bearer_t bearer = create_bearer(h, addr, ntohl(msgHdr->teid), seq); + return gtpv1uCreateAndSendMsg(&bearer, + GTP_ECHO_RSP, + recovery, + sizeof recovery, + true, + false, + NULL, + 0); } -static int Gtpv1uHandleError(int h, - uint8_t *msgBuf, - uint32_t msgBufLen, - uint16_t peerPort, - uint32_t peerIp) { - LOG_E(GTPU, "Received GTP error indication (error handling is missing/not implemented)\n"); +static int Gtpv1uHandleError(int h, uint8_t *msgBuf, uint32_t msgBufLen, const struct sockaddr_in *addr) +{ + if (msgBufLen < sizeof(Gtpv1uError)) + LOG_E(GTPU, "Received GTP error indication with truncated size %u (mini size: %lu)\n", msgBufLen,sizeof(Gtpv1uError)+4); + Gtpv1uError *msg = ( Gtpv1uError *)msgBuf; + LOG_E(GTPU, "Received GTP error indication: \n" + " TEID %u (must be 0 from TS 29.281)\n" + " TV id for TEID %u (must be 16)\n" + " TEID in error %u (should be a TEID we sent)\n" + " TV id for GTP addr %u (should be 133)\n" + " len for addr of UPF %u (should be IPv4 or IPv6 len)" + " (TS 29.281 Sec 7.3.1 Error Handling not implemented)\n", + msg->h.teid, + msg->teid_data_i, + msg->teid, + msg->addr_data_i, + msg->addr_len); int rc = GTPNOK; return rc; } -static int Gtpv1uHandleSupportedExt(int h, - uint8_t *msgBuf, - uint32_t msgBufLen, - uint16_t peerPort, - uint32_t peerIp) { - LOG_E(GTPU,"Supported extensions to be dev\n"); +static int Gtpv1uHandleSupportedExt(int h, uint8_t *msgBuf, uint32_t msgBufLen, const sockaddr_in *addr) +{ + LOG_E(GTPU, "Supported extensions to be dev\n"); int rc = GTPNOK; return rc; } @@ -982,14 +1084,11 @@ static int Gtpv1uHandleSupportedExt(int h, // When end marker arrives, we notify the client with buffer size = 0 // The client will likely call "delete tunnel" // nevertheless we don't take the initiative -static int Gtpv1uHandleEndMarker(int h, - uint8_t *msgBuf, - uint32_t msgBufLen, - uint16_t peerPort, - uint32_t peerIp) { - Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *) msgBuf; +static int Gtpv1uHandleEndMarker(int h, uint8_t *msgBuf, uint32_t msgBufLen, const sockaddr_in *addr) +{ + Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)msgBuf; - if ( msgHdr->version != 1 || msgHdr->PT != 1 ) { + if (msgHdr->version != 1 || msgHdr->PT != 1) { LOG_E(GTPU, "[%d] Received a packet that is not GTP header\n", h); return GTPNOK; } @@ -1001,7 +1100,7 @@ static int Gtpv1uHandleEndMarker(int h, auto tunnel = globGtp.te2ue_mapping.find(ntohl(msgHdr->teid)); if (tunnel == globGtp.te2ue_mapping.end()) { - LOG_E(GTPU,"[%d] Received a incoming packet on unknown teid (%x) Dropping!\n", h, msgHdr->teid); + LOG_E(GTPU, "[%d] Received a incoming packet on unknown teid (%x) Dropping!\n", h, msgHdr->teid); pthread_mutex_unlock(&globGtp.gtp_lock); return GTPNOK; } @@ -1018,56 +1117,44 @@ static int Gtpv1uHandleEndMarker(int h, ctxt.subframe = 0; ctxt.eNB_index = 0; ctxt.brOption = 0; - const srb_flag_t srb_flag=SRB_FLAG_NO; - const rb_id_t rb_id=tunnel->second.incoming_rb_id; - const mui_t mui=RLC_MUI_UNDEFINED; - const confirm_t confirm=RLC_SDU_CONFIRM_NO; - const pdcp_transmission_mode_t mode=PDCP_TRANSMISSION_MODE_DATA; - const uint32_t sourceL2Id=0; - const uint32_t destinationL2Id=0; + const srb_flag_t srb_flag = SRB_FLAG_NO; + const rb_id_t rb_id = tunnel->second.incoming_rb_id; + const mui_t mui = RLC_MUI_UNDEFINED; + const confirm_t confirm = RLC_SDU_CONFIRM_NO; + const pdcp_transmission_mode_t mode = PDCP_TRANSMISSION_MODE_DATA; + const uint32_t sourceL2Id = 0; + const uint32_t destinationL2Id = 0; pthread_mutex_unlock(&globGtp.gtp_lock); - if ( !tunnel->second.callBack(&ctxt, - srb_flag, - rb_id, - mui, - confirm, - 0, - NULL, - mode, - &sourceL2Id, - &destinationL2Id) ) - LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h); + if (!tunnel->second.callBack(&ctxt, srb_flag, rb_id, mui, confirm, 0, NULL, mode, &sourceL2Id, &destinationL2Id)) + LOG_E(GTPU, "[%d] down layer refused incoming packet\n", h); - LOG_D(GTPU,"[%d] Received END marker packet for: teid:%x\n", h, ntohl(msgHdr->teid)); + LOG_D(GTPU, "[%d] Received END marker packet for: teid:%x\n", h, ntohl(msgHdr->teid)); return !GTPNOK; } -static int Gtpv1uHandleGpdu(int h, - uint8_t *msgBuf, - uint32_t msgBufLen, - uint16_t peerPort, - uint32_t peerIp) { - Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *) msgBuf; +static int Gtpv1uHandleGpdu(int h, uint8_t *msgBuf, uint32_t msgBufLen, const struct sockaddr_in *addr) +{ + Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)msgBuf; - if ( msgHdr->version != 1 || msgHdr->PT != 1 ) { + if (msgHdr->version != 1 || msgHdr->PT != 1) { LOG_E(GTPU, "[%d] Received a packet that is not GTP header\n", h); return GTPNOK; } pthread_mutex_lock(&globGtp.gtp_lock); - // the socket Linux file handler is the instance id - getInstRetInt(h); auto tunnel = globGtp.te2ue_mapping.find(ntohl(msgHdr->teid)); if (tunnel == globGtp.te2ue_mapping.end()) { - LOG_E(GTPU,"[%d] Received a incoming packet on unknown teid (%x) Dropping!\n", h, ntohl(msgHdr->teid)); + LOG_E(GTPU, "[%d] Received a incoming packet on unknown teid (%x) Dropping!\n", h, ntohl(msgHdr->teid)); pthread_mutex_unlock(&globGtp.gtp_lock); return GTPNOK; } + ueidData_t uedata = tunnel->second; + pthread_mutex_unlock(&globGtp.gtp_lock); /* see TS 29.281 5.1 */ - //Minimum length of GTP-U header if non of the optional fields are present + // Minimum length of GTP-U header if non of the optional fields are present unsigned int offset = sizeof(Gtpv1uMsgHeaderT); int8_t qfi = -1; @@ -1075,7 +1162,7 @@ static int Gtpv1uHandleGpdu(int h, uint32_t NR_PDCP_PDU_SN = 0; /* if E, S, or PN is set then there are 4 more bytes of header */ - if( msgHdr->E || msgHdr->S ||msgHdr->PN) + if (msgHdr->E || msgHdr->S || msgHdr->PN) offset += 4; if (msgHdr->E) { @@ -1086,53 +1173,53 @@ static int Gtpv1uHandleGpdu(int h, extension_header_length = msgBuf[offset]; switch (next_extension_header_type) { case PDU_SESSION_CONTAINER: { - if (offset + sizeof(PDUSessionContainerT) > msgBufLen ) { - LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n"); - return GTPNOK; - } + if (offset + sizeof(PDUSessionContainerT) > msgBufLen) { + LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n"); + return GTPNOK; + } PDUSessionContainerT *pdusession_cntr = (PDUSessionContainerT *)(msgBuf + offset + 1); qfi = pdusession_cntr->QFI; rqi = pdusession_cntr->Reflective_QoS_activation; break; } case NR_RAN_CONTAINER: { - if (offset + 1 > msgBufLen ) { - LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n"); - return GTPNOK; - } - uint8_t PDU_type = (msgBuf[offset+1]>>4) & 0x0f; - if (PDU_type == 0){ //DL USER Data Format - int additional_offset = 6; //Additional offset capturing the first non-mandatory octet (TS 38.425, Figure 5.5.2.1-1) - if(msgBuf[offset+1]>>2 & 0x1){ //DL Discard Blocks flag is present - LOG_I(GTPU, "DL User Data: DL Discard Blocks handling not enabled\n"); - additional_offset = additional_offset + 9; //For the moment ignore + if (offset + 1 > msgBufLen) { + LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n"); + return GTPNOK; + } + uint8_t PDU_type = (msgBuf[offset + 1] >> 4) & 0x0f; + if (PDU_type == 0) { // DL USER Data Format + int additional_offset = 6; // Additional offset capturing the first non-mandatory octet (TS 38.425, Figure 5.5.2.1-1) + if (msgBuf[offset + 1] >> 2 & 0x1) { // DL Discard Blocks flag is present + LOG_I(GTPU, "DL User Data: DL Discard Blocks handling not enabled\n"); + additional_offset = additional_offset + 9; // For the moment ignore } - if(msgBuf[offset+1]>>1 & 0x1){ //DL Flush flag is present + if (msgBuf[offset + 1] >> 1 & 0x1) { // DL Flush flag is present LOG_I(GTPU, "DL User Data: DL Flush handling not enabled\n"); - additional_offset = additional_offset + 3; //For the moment ignore + additional_offset = additional_offset + 3; // For the moment ignore } - if((msgBuf[offset+2]>>3)& 0x1){ //"Report delivered" enabled (TS 38.425, 5.4) + if ((msgBuf[offset + 2] >> 3) & 0x1) { //"Report delivered" enabled (TS 38.425, 5.4) /*Store the NR PDCP PDU SN for which a delivery status report shall be generated once the *PDU gets forwarded to the lower layers*/ - //NR_PDCP_PDU_SN = msgBuf[offset+6] << 16 | msgBuf[offset+7] << 8 | msgBuf[offset+8]; - NR_PDCP_PDU_SN = msgBuf[offset+additional_offset] << 16 | msgBuf[offset+additional_offset+1] << 8 | msgBuf[offset+additional_offset+2]; - LOG_D(GTPU, " NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN); + // NR_PDCP_PDU_SN = msgBuf[offset+6] << 16 | msgBuf[offset+7] << 8 | msgBuf[offset+8]; + NR_PDCP_PDU_SN = msgBuf[offset + additional_offset] << 16 | msgBuf[offset + additional_offset + 1] << 8 + | msgBuf[offset + additional_offset + 2]; + LOG_D(GTPU, " NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN); } - } - else{ + } else { LOG_W(GTPU, "NR-RAN container type: %d not supported \n", PDU_type); } break; } default: LOG_W(GTPU, "unhandled extension 0x%2.2x, skipping\n", next_extension_header_type); - break; + break; } offset += extension_header_length * EXT_HDR_LNTH_OCTET_UNITS; - if (offset > msgBufLen ) { - LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n"); - return GTPNOK; + if (offset > msgBufLen) { + LOG_E(GTPU, "gtp-u received header is malformed, ignore gtp packet\n"); + return GTPNOK; } next_extension_header_type = msgBuf[offset - 1]; } @@ -1141,148 +1228,109 @@ static int Gtpv1uHandleGpdu(int h, // This context is not good for gtp // frame, ... has no meaning // manyother attributes may come from create tunnel - protocol_ctxt_t ctxt; - ctxt.module_id = 0; - ctxt.enb_flag = 1; - ctxt.instance = inst->addr.originInstance; - ctxt.rntiMaybeUEid = tunnel->second.ue_id; - ctxt.frame = 0; - ctxt.subframe = 0; - ctxt.eNB_index = 0; - ctxt.brOption = 0; - const srb_flag_t srb_flag=SRB_FLAG_NO; - const rb_id_t rb_id=tunnel->second.incoming_rb_id; - const mui_t mui=RLC_MUI_UNDEFINED; - const confirm_t confirm=RLC_SDU_CONFIRM_NO; + protocol_ctxt_t ctxt = { .enb_flag = 1, .rntiMaybeUEid = uedata.ue_id, }; + const srb_flag_t srb_flag = SRB_FLAG_NO; + const rb_id_t rb_id = uedata.incoming_rb_id; + const mui_t mui = RLC_MUI_UNDEFINED; + const confirm_t confirm = RLC_SDU_CONFIRM_NO; const sdu_size_t sdu_buffer_size = msgBufLen - offset; - unsigned char *const sdu_buffer=msgBuf+offset; - const pdcp_transmission_mode_t mode=PDCP_TRANSMISSION_MODE_DATA; - const uint32_t sourceL2Id=0; - const uint32_t destinationL2Id=0; - pthread_mutex_unlock(&globGtp.gtp_lock); + unsigned char *const sdu_buffer = msgBuf + offset; + const pdcp_transmission_mode_t mode = PDCP_TRANSMISSION_MODE_DATA; + const uint32_t sourceL2Id = 0; + const uint32_t destinationL2Id = 0; if (sdu_buffer_size > 0) { - if (qfi != -1 && tunnel->second.callBackSDAP) { - if ( !tunnel->second.callBackSDAP(&ctxt, - tunnel->second.ue_id, - srb_flag, - rb_id, - mui, - confirm, - sdu_buffer_size, - sdu_buffer, - mode, - &sourceL2Id, - &destinationL2Id, - qfi, - rqi, - tunnel->second.pdusession_id) ) - LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h); + if (qfi != -1 && uedata.callBackSDAP) { + if (!uedata.callBackSDAP(&ctxt, + uedata.ue_id, + srb_flag, + rb_id, + mui, + confirm, + sdu_buffer_size, + sdu_buffer, + mode, + &sourceL2Id, + &destinationL2Id, + qfi, + rqi, + uedata.pdusession_id)) + LOG_E(GTPU, "[%d] down layer refused incoming packet\n", h); } else { - if ( !tunnel->second.callBack(&ctxt, - srb_flag, - rb_id, - mui, - confirm, - sdu_buffer_size, - sdu_buffer, - mode, - &sourceL2Id, - &destinationL2Id) ) - LOG_E(GTPU,"[%d] down layer refused incoming packet\n", h); + if (!uedata.callBack(&ctxt, srb_flag, rb_id, mui, confirm, sdu_buffer_size, sdu_buffer, mode, &sourceL2Id, &destinationL2Id)) + LOG_E(GTPU, "[%d] down layer refused incoming packet\n", h); } } - if(NR_PDCP_PDU_SN > 0 && NR_PDCP_PDU_SN %5 ==0){ - LOG_D (GTPU, "Create and send DL DATA Delivery status for the previously received PDU, NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN); + if (NR_PDCP_PDU_SN > 0 && NR_PDCP_PDU_SN % 5 == 0) { + LOG_D(GTPU, "Create and send DL DATA Delivery status for the previously received PDU, NR_PDCP_PDU_SN: %u \n", NR_PDCP_PDU_SN); int rlc_tx_buffer_space = nr_rlc_get_available_tx_space(ctxt.rntiMaybeUEid, rb_id + 3); LOG_D(GTPU, "Available buffer size in RLC for Tx: %d \n", rlc_tx_buffer_space); - /*Total size of DDD_status PDU = 1 octet to report extension header length - * size of mandatory part + 3 octets for highest transmitted/delivered PDCP SN - * 1 octet for padding + 1 octet for next extension header type, - * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/ - extensionHeader_t *extensionHeader; - extensionHeader = (extensionHeader_t *) calloc(1, sizeof(extensionHeader_t)) ; - extensionHeader->buffer[0] = (1+sizeof(DlDataDeliveryStatus_flagsT)+3+1+1)/4; - DlDataDeliveryStatus_flagsT DlDataDeliveryStatus; - DlDataDeliveryStatus.deliveredPdcpSn = 0; - DlDataDeliveryStatus.transmittedPdcpSn= 1; - DlDataDeliveryStatus.pduType = 1; - DlDataDeliveryStatus.drbBufferSize = htonl(rlc_tx_buffer_space); //htonl(10000000); //hardcoded for now but normally we should extract it from RLC - memcpy(extensionHeader->buffer+1, &DlDataDeliveryStatus, sizeof(DlDataDeliveryStatus_flagsT)); - uint8_t offset = sizeof(DlDataDeliveryStatus_flagsT)+1; - - extensionHeader->buffer[offset] = (NR_PDCP_PDU_SN >> 16) & 0xff; - extensionHeader->buffer[offset+1] = (NR_PDCP_PDU_SN >> 8) & 0xff; - extensionHeader->buffer[offset+2] = NR_PDCP_PDU_SN & 0xff; - LOG_D(GTPU, "Octets reporting NR_PDCP_PDU_SN, extensionHeader-> %u:%u:%u \n", - extensionHeader->buffer[offset], - extensionHeader->buffer[offset+1], - extensionHeader->buffer[offset+2]); - extensionHeader->buffer[offset+3] = 0x00; //Padding octet - extensionHeader->buffer[offset+4] = 0x00; //No more extension headers - /*Total size of DDD_status PDU = size of mandatory part + - * 3 octets for highest transmitted/delivered PDCP SN + - * 1 octet for padding + 1 octet for next extension header type, - * according to TS 38.425: Fig. 5.5.2.2-1 and section 5.5.3.24*/ - extensionHeader->length = 1+sizeof(DlDataDeliveryStatus_flagsT)+3+1+1; - gtpv1uCreateAndSendMsg( - h, peerIp, peerPort, GTP_GPDU, globGtp.te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid, NULL, 0, false, false, 0, 0, NR_RAN_CONTAINER, extensionHeader->buffer, extensionHeader->length); + gtpu_extension_header_t ext; + fillDlDeliveryStatusReport(&ext, rlc_tx_buffer_space, NR_PDCP_PDU_SN); + uint32_t teid = globGtp.te2ue_mapping[ntohl(msgHdr->teid)].outgoing_teid; + gtpv1u_bearer_t bearer = create_bearer(h, addr, teid, 0); + gtpv1uCreateAndSendMsg(&bearer, + GTP_GPDU, + NULL, + 0, + false, + false, + &ext, + 1); } - LOG_D(GTPU,"[%d] Received a %d bytes packet for: teid:%x\n", h, - msgBufLen-offset, - ntohl(msgHdr->teid)); + LOG_D(GTPU, "[%d] Received a %d bytes packet for: teid:%x\n", h, msgBufLen - offset, ntohl(msgHdr->teid)); return !GTPNOK; } -void gtpv1uReceiver(int h) { - uint8_t udpData[65536]; - int udpDataLen; - socklen_t from_len; +static void gtpv1uReceiveHandleMessage(int h) +{ + uint8_t udpData[65536]; + int udpDataLen; + socklen_t from_len; struct sockaddr_in addr; from_len = (socklen_t)sizeof(struct sockaddr_in); - if ((udpDataLen = recvfrom(h, udpData, sizeof(udpData), 0, - (struct sockaddr *)&addr, &from_len)) < 0) { + if ((udpDataLen = recvfrom(h, udpData, sizeof(udpData), 0, (struct sockaddr *)&addr, &from_len)) < 0) { LOG_E(GTPU, "[%d] Recvfrom failed (%s)\n", h, strerror(errno)); return; } else if (udpDataLen == 0) { LOG_W(GTPU, "[%d] Recvfrom returned 0\n", h); return; } else { - if ( udpDataLen < (int)sizeof(Gtpv1uMsgHeaderT) ) { + if (udpDataLen < (int)sizeof(Gtpv1uMsgHeaderT)) { LOG_W(GTPU, "[%d] received malformed gtp packet \n", h); return; } - Gtpv1uMsgHeaderT* msg=(Gtpv1uMsgHeaderT*) udpData; - if ( (int)(ntohs(msg->msgLength) + sizeof(Gtpv1uMsgHeaderT)) != udpDataLen ) { + Gtpv1uMsgHeaderT *msg = (Gtpv1uMsgHeaderT *)udpData; + if ((int)(ntohs(msg->msgLength) + sizeof(Gtpv1uMsgHeaderT)) != udpDataLen) { LOG_W(GTPU, "[%d] received malformed gtp packet length\n", h); return; } LOG_D(GTPU, "[%d] Received GTP data, msg type: %x\n", h, msg->msgType); - switch(msg->msgType) { + switch (msg->msgType) { case GTP_ECHO_RSP: break; case GTP_ECHO_REQ: - Gtpv1uHandleEchoReq( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr); + Gtpv1uHandleEchoReq(h, udpData, udpDataLen, &addr); break; case GTP_ERROR_INDICATION: - Gtpv1uHandleError( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr); + Gtpv1uHandleError(h, udpData, udpDataLen, &addr); break; case GTP_SUPPORTED_EXTENSION_HEADER_INDICATION: - Gtpv1uHandleSupportedExt( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr); + Gtpv1uHandleSupportedExt(h, udpData, udpDataLen, &addr); break; case GTP_END_MARKER: - Gtpv1uHandleEndMarker( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr); + Gtpv1uHandleEndMarker(h, udpData, udpDataLen, &addr); break; case GTP_GPDU: - Gtpv1uHandleGpdu( h, udpData, udpDataLen, htons(addr.sin_port), addr.sin_addr.s_addr); + Gtpv1uHandleGpdu(h, udpData, udpDataLen, &addr); break; default: @@ -1292,10 +1340,21 @@ void gtpv1uReceiver(int h) { } } +static void* gtpv1uReceiver(void *thr) +{ + gtpThread_t *gt = (gtpThread_t *)thr; + while (true) { + gtpv1uReceiveHandleMessage(gt->h); + } + LOG_W(GTPU, "exiting thread\n"); + return NULL; +} + #include -void *gtpv1uTask(void *args) { - while(1) { +void *gtpv1uTask(void *args) +{ + while (1) { /* Trying to fetch a message from the message queue. If the queue is empty, this function will block till a message is sent to the task. @@ -1303,19 +1362,14 @@ void *gtpv1uTask(void *args) { MessageDef *message_p = NULL; itti_receive_msg(TASK_GTPV1_U, &message_p); - if (message_p != NULL ) { - openAddr_t addr= {{0}}; + if (message_p != NULL) { + openAddr_t addr = {{0}}; const instance_t myInstance = ITTI_MSG_DESTINATION_INSTANCE(message_p); const int msgType = ITTI_MSG_ID(message_p); LOG_D(GTPU, "GTP-U received %s for instance %ld\n", messages_info[msgType].name, myInstance); switch (msgType) { // DATA TO BE SENT TO UDP - case GTPV1U_DU_BUFFER_REPORT_REQ:{ - gtpv1uSendDlDeliveryStatus(compatInst(myInstance), >PV1U_DU_BUFFER_REPORT_REQ(message_p)); - } - break; - case TERMINATE_MESSAGE: break; @@ -1339,8 +1393,8 @@ void *gtpv1uTask(void *args) { // to be dev: should be removed, to use API strcpy(addr.originHost, GTPV1U_REQ(message_p).localAddrStr); strcpy(addr.originService, GTPV1U_REQ(message_p).localPortStr); - strcpy(addr.destinationService,addr.originService); - AssertFatal((legacyInstanceMapping=gtpv1Init(addr))!=0,"Instance 0 reserved for legacy\n"); + strcpy(addr.destinationService, addr.originService); + AssertFatal((legacyInstanceMapping = gtpv1Init(addr)) != 0, "Instance 0 reserved for legacy\n"); break; default: @@ -1349,15 +1403,8 @@ void *gtpv1uTask(void *args) { break; } - AssertFatal(EXIT_SUCCESS==itti_free(TASK_GTPV1_U, message_p), "Failed to free memory!\n"); + AssertFatal(EXIT_SUCCESS == itti_free(TASK_GTPV1_U, message_p), "Failed to free memory!\n"); } - - struct epoll_event events[20]; - int nb_events = itti_get_events(TASK_GTPV1_U, events, 20); - - for (int i = 0; i < nb_events; i++) - if ((events[i].events&EPOLLIN)) - gtpv1uReceiver(events[i].data.fd); } return NULL; diff --git a/openair3/ocp-gtpu/gtp_itf.h b/openair3/ocp-gtpu/gtp_itf.h index d5226bb972..4fcb8190e4 100644 --- a/openair3/ocp-gtpu/gtp_itf.h +++ b/openair3/ocp-gtpu/gtp_itf.h @@ -1,16 +1,40 @@ #ifndef __GTPUNEW_ITF_H__ #define __GTPUNEW_ITF_H__ +#include +#include +#include +#include + #define GTPNOK -1 # define GTPU_HEADER_OVERHEAD_MAX 64 -#include "openair2/COMMON/gtpv1_u_messages_types.h" -#include "common/utils/hashtable/hashtable.h" +#include "common/platform_types.h" #ifdef __cplusplus extern "C" { #endif +/* forward declaration */ +struct protocol_ctxt_s; +typedef struct protocol_ctxt_s protocol_ctxt_t; +struct gtpv1u_enb_create_tunnel_req_s; +typedef struct gtpv1u_enb_create_tunnel_req_s gtpv1u_enb_create_tunnel_req_t; +struct gtpv1u_enb_create_tunnel_resp_s; +typedef struct gtpv1u_enb_create_tunnel_resp_s gtpv1u_enb_create_tunnel_resp_t; +struct gtpv1u_enb_delete_tunnel_req_s; +typedef struct gtpv1u_enb_delete_tunnel_req_s gtpv1u_enb_delete_tunnel_req_t; +struct gtpv1u_enb_create_x2u_tunnel_req_s; +typedef struct gtpv1u_enb_create_x2u_tunnel_req_s gtpv1u_enb_create_x2u_tunnel_req_t; +struct gtpv1u_enb_create_x2u_tunnel_resp_s; +typedef struct gtpv1u_enb_create_x2u_tunnel_resp_s gtpv1u_enb_create_x2u_tunnel_resp_t; +struct gtpv1u_gnb_create_tunnel_req_s; +typedef struct gtpv1u_gnb_create_tunnel_req_s gtpv1u_gnb_create_tunnel_req_t; +struct gtpv1u_gnb_create_tunnel_resp_s; +typedef struct gtpv1u_gnb_create_tunnel_resp_s gtpv1u_gnb_create_tunnel_resp_t; +struct gtpv1u_gnb_delete_tunnel_req_s; +typedef struct gtpv1u_gnb_delete_tunnel_req_s gtpv1u_gnb_delete_tunnel_req_t; + typedef bool (*gtpCallback)(protocol_ctxt_t *ctxt_pP, const srb_flag_t srb_flagP, const rb_id_t rb_idP, @@ -52,7 +76,6 @@ extern "C" { // the init function create a gtp instance and return the gtp instance id // the parameter originInstance will be sent back in each message from gtp to the creator - void gtpv1uReceiver(int h); void gtpv1uProcessTimeout(int handle,void *arg); int gtpv1u_create_s1u_tunnel(const instance_t instance, const gtpv1u_enb_create_tunnel_req_t *create_tunnel_req, @@ -91,7 +114,6 @@ extern "C" { teid_t teid, int outgoing_qfi, transport_layer_addr_t remoteAddr, - int port, gtpCallback callBack, gtpCallbackSDAP callBackSDAP); @@ -103,20 +125,20 @@ extern "C" { int newGtpuDeleteOneTunnel(instance_t instance, ue_id_t ue_id, int rb_id); int newGtpuDeleteAllTunnels(instance_t instance, ue_id_t ue_id); - int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, pdusessionid_t *pdusession_id); + int newGtpuDeleteTunnels(instance_t instance, ue_id_t ue_id, int nbTunnels, int *pdusession_id); void gtpv1uSendDirect(instance_t instance, ue_id_t ue_id, int bearer_id, uint8_t *buf, size_t len, bool seqNumFlag, bool npduNumFlag); + void gtpv1uSendDirectWithNRUSeqNum(instance_t instance, + ue_id_t ue_id, + int bearer_id, + uint8_t *buf, + size_t len); instance_t gtpv1Init(openAddr_t context); void *gtpv1uTask(void *args); - // Legacy to fix - typedef struct gtpv1u_data_s { - /* RB tree of UEs */ - hash_table_t *ue_mapping; - } gtpv1u_data_t; #define GTPV1U_BEARER_OFFSET 3 -#define GTPV1U_MAX_BEARERS_ID (max_val_LTE_DRB_Identity - GTPV1U_BEARER_OFFSET) +#define GTPV1U_MAX_BEARERS_ID (32 - GTPV1U_BEARER_OFFSET) /* max_val_LTE_DRB_Identity */ typedef enum { BEARER_DOWN = 0, BEARER_IN_CONFIG, diff --git a/openair3/ocp-gtpu/gtpu_extensions.c b/openair3/ocp-gtpu/gtpu_extensions.c new file mode 100644 index 0000000000..13f0cee053 --- /dev/null +++ b/openair3/ocp-gtpu/gtpu_extensions.c @@ -0,0 +1,167 @@ +/* + * 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 "gtpu_extensions.h" +#include "common/utils/assertions.h" +#include "common/utils/ds/byte_array_producer.h" +#include "LOG/log.h" + +/* 29.281 Figure 5.2.1-3 */ +#define NR_RAN_CONTAINER 0x84 +#define PDU_SESSION_CONTAINER 0x85 + +/* from an extension type, returns its "extension header type" + * as defined in 29.281 Figure 5.2.1-3 + */ +int serialize_gtpu_extension_type(gtpu_extension_header_type_t type) +{ + switch (type) { + case GTPU_EXT_NONE: + /* 0, no more extension */ + return 0; + case GTPU_EXT_UL_PDU_SESSION_INFORMATION: + return PDU_SESSION_CONTAINER; + case GTPU_EXT_DL_DATA_DELIVERY_STATUS: + case GTPU_EXT_DL_USER_DATA: + return NR_RAN_CONTAINER; + default: + AssertFatal(0, "unknown GTPU extension type %d\n", type); + } +} + +/* returns 0 on error, 1 on success */ +static int serialize_ul_pdu_session_information(byte_array_producer_t *b, ul_pdu_session_information_t *ext) +{ + /* see 38.415 5.5.2.2 */ + AssertFatal(!ext->qmp && !ext->dl_delay_ind && !ext->ul_delay_ind + && !ext->snp && !ext->n3n9_delay_ind && !ext->new_ie_flag, + "todo\n"); + + uint8_t b1 = (1 << 4) | (ext->qmp << 3) | (ext->dl_delay_ind << 2) | (ext->ul_delay_ind << 1) | ext->snp; + uint8_t b2 = (ext->n3n9_delay_ind << 7) | (ext->new_ie_flag << 6) | ext->qfi; + return byte_array_producer_put_byte(b, b1) && byte_array_producer_put_byte(b, b2); +} + +/* returns 0 on error, 1 on success */ +static int serialize_dl_data_delivery_status(byte_array_producer_t *b, dl_data_delivery_status_t *ext) +{ + /* see 38.425 5.5.2.2 */ + AssertFatal(!ext->highest_delivered_nr_pdcp_sn_ind && !ext->final_frame_ind + && !ext->lost_packet_report && !ext->delivered_nr_pdcp_sn_range_ind + && !ext->data_rate_ind && !ext->retransmitted_nr_pdcp_sn_ind + && !ext->delivered_retransmitted_nr_pdcp_ind && !ext->cause_report, + "todo\n"); + + uint8_t b1 = (1 << 4) + | (ext->highest_transmitted_nr_pdcp_sn_ind << 3) + | (ext->highest_delivered_nr_pdcp_sn_ind << 2) + | (ext->final_frame_ind << 1) + | ext->lost_packet_report; + uint8_t b2 = (ext->delivered_nr_pdcp_sn_range_ind << 4) + | (ext->data_rate_ind << 3) + | (ext->retransmitted_nr_pdcp_sn_ind << 2) + | (ext->delivered_retransmitted_nr_pdcp_ind << 1) + | ext->cause_report; + if (!byte_array_producer_put_byte(b, b1) || !byte_array_producer_put_byte(b, b2)) + return 0; + + if (!byte_array_producer_put_u32_be(b, ext->desired_buffer_size)) + return 0; + + if (ext->highest_transmitted_nr_pdcp_sn_ind) + if (!byte_array_producer_put_u24_be(b, ext->highest_transmitted_nr_pdcp_sn)) + return 0; + + return 1; +} + +/* returns 0 on error, 1 on success */ +static int serialize_dl_user_data(byte_array_producer_t *b, dl_user_data_t *ext) +{ + /* see 38.425 5.5.2.1 */ + AssertFatal(!ext->dl_discard_blocks && !ext->dl_flush && !ext->report_polling + && !ext->request_out_of_seq_report && !ext->report_delivered + && !ext->user_data_existence_flag && !ext->assistance_info_report_polling_flag + && !ext->retransmission_flag, + "todo\n"); + + uint8_t b1 = (0 << 4) | (ext->dl_discard_blocks << 2) | (ext->dl_flush << 1) | ext->report_polling; + uint8_t b2 = (ext->request_out_of_seq_report << 4) + | (ext->report_delivered << 3) + | (ext->user_data_existence_flag << 2) + | (ext->assistance_info_report_polling_flag << 1) + | ext->retransmission_flag; + if (!byte_array_producer_put_byte(b, b1) || !byte_array_producer_put_byte(b, b2)) + return 0; + + if (!byte_array_producer_put_u24_be(b, ext->nru_sequence_number)) + return 0; + + return 1; +} + +/* returns -1 on error, number of serialized bytes on success */ +int serialize_extension(gtpu_extension_header_t *ext, gtpu_extension_header_type_t next, uint8_t *out_buf, int out_len) +{ + byte_array_producer_t b; + + b = byte_array_producer_from_buffer(out_buf, out_len); + /* length - will be set later */ + if (!byte_array_producer_put_byte(&b, 0)) + goto error; + + switch (ext->type) { + case GTPU_EXT_UL_PDU_SESSION_INFORMATION: + if (!serialize_ul_pdu_session_information(&b, &ext->ul_pdu_session_information)) + goto error; + break; + case GTPU_EXT_DL_DATA_DELIVERY_STATUS: + if (!serialize_dl_data_delivery_status(&b, &ext->dl_data_delivery_status)) + goto error; + break; + case GTPU_EXT_DL_USER_DATA: + if (!serialize_dl_user_data(&b, &ext->dl_user_data)) + goto error; + break; + default: + LOG_E(GTPU, "unknown extension type %d\n", ext->type); + return -1; + } + + /* padding */ + while ((b.pos & 3) != 3) + if (!byte_array_producer_put_byte(&b, 0)) + goto error; + + /* next */ + if (!byte_array_producer_put_byte(&b, serialize_gtpu_extension_type(next))) + goto error; + + /* length is now know */ + DevAssert(b.pos / 4 <= 255); + out_buf[0] = b.pos / 4; + + return b.pos; + +error: + LOG_E(GTPU, "error serializing extension\n"); + return -1; +} diff --git a/openair3/ocp-gtpu/gtpu_extensions.h b/openair3/ocp-gtpu/gtpu_extensions.h new file mode 100644 index 0000000000..b621d27e14 --- /dev/null +++ b/openair3/ocp-gtpu/gtpu_extensions.h @@ -0,0 +1,91 @@ +/* + * 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 GTPU_EXTENSIONS_H +#define GTPU_EXTENSIONS_H + +#include +#include + +typedef enum { + GTPU_EXT_NONE, + /* 38.415 */ + GTPU_EXT_UL_PDU_SESSION_INFORMATION, + /* 38.425 */ + GTPU_EXT_DL_DATA_DELIVERY_STATUS, + GTPU_EXT_DL_USER_DATA, +} gtpu_extension_header_type_t; + +/* 38.415 */ +typedef struct { + /* not all fields are present, to be refined if needed */ + bool qmp; + bool dl_delay_ind; + bool ul_delay_ind; + bool snp; + bool n3n9_delay_ind; + bool new_ie_flag; + int qfi; +} ul_pdu_session_information_t; + +/* 38.425 */ +typedef struct { + /* not all fields are present, to be refined if needed */ + bool highest_transmitted_nr_pdcp_sn_ind; + bool highest_delivered_nr_pdcp_sn_ind; + bool final_frame_ind; + bool lost_packet_report; + bool delivered_nr_pdcp_sn_range_ind; + bool data_rate_ind; + bool retransmitted_nr_pdcp_sn_ind; + bool delivered_retransmitted_nr_pdcp_ind; + bool cause_report; + uint32_t desired_buffer_size; + uint32_t highest_transmitted_nr_pdcp_sn; +} dl_data_delivery_status_t; + +/* 38.425 */ +typedef struct { + /* not all fields are present, to be refined if needed */ + bool dl_discard_blocks; + bool dl_flush; + bool report_polling; + bool request_out_of_seq_report; + bool report_delivered; + bool user_data_existence_flag; + bool assistance_info_report_polling_flag; + bool retransmission_flag; + uint32_t nru_sequence_number; +} dl_user_data_t; + +typedef struct { + gtpu_extension_header_type_t type; + union { + ul_pdu_session_information_t ul_pdu_session_information; + dl_data_delivery_status_t dl_data_delivery_status; + dl_user_data_t dl_user_data; + }; +} gtpu_extension_header_t; + +int serialize_gtpu_extension_type(gtpu_extension_header_type_t type); +int serialize_extension(gtpu_extension_header_t *ext, gtpu_extension_header_type_t next, uint8_t *out_buf, int out_len); + +#endif /* GTPU_EXTENSIONS_H */ diff --git a/radio/AW2SORI/CMakeLists.txt b/radio/AW2SORI/CMakeLists.txt index e02d8a2721..134ab27b81 100644 --- a/radio/AW2SORI/CMakeLists.txt +++ b/radio/AW2SORI/CMakeLists.txt @@ -9,7 +9,7 @@ endif() add_library(aw2sori_transpro MODULE oaiori.c) target_compile_options(aw2sori_transpro PRIVATE -shared -fPIC -msse4 -g -ggdb -DLITE_COMPILATION) -target_link_libraries(aw2sori_transpro PRIVATE ori oai_eth_transpro) +target_link_libraries(aw2sori_transpro PRIVATE ori oai_eth_transpro log_headers) set_target_properties(aw2sori_transpro PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_command(TARGET aw2sori_transpro POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink libaw2sori_transpro.so libthirdparty_transpro.so diff --git a/radio/BLADERF/CMakeLists.txt b/radio/BLADERF/CMakeLists.txt index 5504eb4051..063c8cb21e 100644 --- a/radio/BLADERF/CMakeLists.txt +++ b/radio/BLADERF/CMakeLists.txt @@ -1,7 +1,7 @@ pkg_check_modules(bladeRF REQUIRED libbladeRF) add_library(oai_bladerfdevif MODULE bladerf_lib.c) target_link_libraries(oai_bladerfdevif PRIVATE bladeRF) -target_link_libraries(oai_bladerfdevif PRIVATE UTIL) +target_link_libraries(oai_bladerfdevif PRIVATE log_headers) set_target_properties(oai_bladerfdevif PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_command(TARGET oai_bladerfdevif POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink liboai_bladerfdevif.so liboai_device.so diff --git a/radio/BLADERF/bladerf_lib.c b/radio/BLADERF/bladerf_lib.c index e834f8377e..178fc2fff2 100644 --- a/radio/BLADERF/bladerf_lib.c +++ b/radio/BLADERF/bladerf_lib.c @@ -138,7 +138,7 @@ static int trx_brf_write(openair0_device *device, brf_state_t *brf = (brf_state_t*)device->priv; /* BRF has only 1 rx/tx chaine : is it correct? */ int16_t *samples = (int16_t*)buff[0]; - timestamp -= device->openair0_cfg->command_line_sample_advance - device->openair0_cfg->tx_sample_advance; + ptimestamp -= device->openair0_cfg->command_line_sample_advance - device->openair0_cfg->tx_sample_advance; //memset(&brf->meta_tx, 0, sizeof(brf->meta_tx)); // When BLADERF_META_FLAG_TX_NOW is used the timestamp is not used, so one can't schedule a tx if (brf->meta_tx.flags == 0 ) diff --git a/radio/CMakeLists.txt b/radio/CMakeLists.txt index 654fb037f0..1159416afa 100644 --- a/radio/CMakeLists.txt +++ b/radio/CMakeLists.txt @@ -38,7 +38,12 @@ if(OAI_USRP) add_subdirectory(USRP) endif() -add_boolean_option(VRTSIM_RADIO ON "Activate OAI's shared memory radio driver" OFF) -if(VRTSIM_RADIO) +add_boolean_option(OAI_VRTSIM ON "Activate OAI's shared memory radio driver" OFF) +if(OAI_VRTSIM) add_subdirectory(vrtsim) endif() + +add_boolean_option(OAI_RF_EMULATOR ON "Activate OAI's RF emulator" OFF) +if(OAI_RF_EMULATOR) + add_subdirectory(emulator) +endif() diff --git a/radio/COMMON/common_lib.c b/radio/COMMON/common_lib.c index 14b66d7060..670a9cc852 100644 --- a/radio/COMMON/common_lib.c +++ b/radio/COMMON/common_lib.c @@ -276,7 +276,7 @@ void openair0_write_reorder_clear_context(openair0_device *device) re_order_t *ctx = &device->reOrder; if (!ctx->initDone) return; - if (pthread_mutex_trylock(&ctx->mutex_write) == 0) + if (pthread_mutex_trylock(&ctx->mutex_write) != 0) LOG_E(HW, "write_reorder_clear_context call while still writing on the device\n"); pthread_mutex_destroy(&ctx->mutex_write); pthread_mutex_lock(&ctx->mutex_store); diff --git a/radio/COMMON/common_lib.h b/radio/COMMON/common_lib.h index 86d09b00fb..b87a6a8abf 100644 --- a/radio/COMMON/common_lib.h +++ b/radio/COMMON/common_lib.h @@ -198,14 +198,19 @@ typedef struct split7_config { } slot_dirs[160]; /*! this is the exponent in 2^X for the FFT size */ uint16_t fftSize; + + // M-plane related parameters + uint16_t dl_k0[5]; + uint16_t ul_k0[5]; + uint16_t cp_prefix0; + uint16_t cp_prefix_other; + } split7_config_t; /*! \brief RF frontend parameters set by application */ typedef struct openair0_config { //! Module ID for this configuration int Mod_id; - //! device log level - int log_level; //! duplexing mode duplex_mode_t duplex_mode; //! number of downlink resource blocks @@ -292,8 +297,6 @@ typedef struct openair0_config { double rx_sample_rate; //! the sample rate for transmit. double tx_sample_rate; - //! check for threequarter sampling rate - int8_t threequarter_fs; //! Flag to indicate this configuration is for NR int nr_flag; //! NR band number diff --git a/radio/ETHERNET/CMakeLists.txt b/radio/ETHERNET/CMakeLists.txt index 8c6590c6e9..3a9b9dc5cb 100644 --- a/radio/ETHERNET/CMakeLists.txt +++ b/radio/ETHERNET/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(oai_eth_transpro MODULE eth_udp.c eth_raw.c ) -target_link_libraries(oai_eth_transpro PRIVATE ${T_LIB}) +target_link_libraries(oai_eth_transpro PRIVATE log_headers) target_include_directories(oai_eth_transpro PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) set_target_properties(oai_eth_transpro PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_command(TARGET oai_eth_transpro POST_BUILD diff --git a/radio/ETHERNET/ethernet_lib.c b/radio/ETHERNET/ethernet_lib.c index eb23ef28cc..2a4d021afc 100644 --- a/radio/ETHERNET/ethernet_lib.c +++ b/radio/ETHERNET/ethernet_lib.c @@ -617,7 +617,6 @@ void dump_dev(openair0_device *device) eth_state_t *eth = (eth_state_t*)device->priv; printf("Ethernet device interface %i configuration:\n" ,device->openair0_cfg->Mod_id); - printf(" Log level is %i :\n" ,device->openair0_cfg->log_level); printf(" RB number: %i, sample rate: %lf \n" , device->openair0_cfg->num_rb_dl, device->openair0_cfg->sample_rate); printf(" RAU configured for %i tx/%i rx channels)\n", diff --git a/radio/LMSSDR/CMakeLists.txt b/radio/LMSSDR/CMakeLists.txt index 2df5c9a01f..bfe2a7f99f 100644 --- a/radio/LMSSDR/CMakeLists.txt +++ b/radio/LMSSDR/CMakeLists.txt @@ -1,7 +1,7 @@ find_package(LimeSuite REQUIRED) add_library(oai_lmssdrdevif MODULE lms_lib.cpp) -target_link_libraries(oai_lmssdrdevif LimeSuite ) +target_link_libraries(oai_lmssdrdevif LimeSuite log_headers) set_target_properties(oai_lmssdrdevif PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_command(TARGET oai_lmssdrdevif POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink liboai_lmssdrdevif.so liboai_device.so diff --git a/radio/USRP/CMakeLists.txt b/radio/USRP/CMakeLists.txt index 4e72d140f4..50d95ee7e5 100644 --- a/radio/USRP/CMakeLists.txt +++ b/radio/USRP/CMakeLists.txt @@ -5,7 +5,7 @@ add_library(oai_usrpdevif MODULE usrp_lib.cpp) #target_include_directories(oai_usrpdevif PRIVATE Boost::boost) target_link_libraries(oai_usrpdevif PRIVATE ${UHD_LIBRARIES}) target_include_directories(oai_usrpdevif PRIVATE ${UHD_INCLUDE_DIRS}) -target_link_libraries(oai_usrpdevif PRIVATE UTIL) +target_link_libraries(oai_usrpdevif PRIVATE log_headers) set_target_properties(oai_usrpdevif PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_custom_command(TARGET oai_usrpdevif POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink liboai_usrpdevif.so liboai_device.so diff --git a/radio/USRP/usrp_lib.cpp b/radio/USRP/usrp_lib.cpp index 8fbb561149..79c58b59f4 100644 --- a/radio/USRP/usrp_lib.cpp +++ b/radio/USRP/usrp_lib.cpp @@ -1161,79 +1161,6 @@ extern "C" { s->usrp = uhd::usrp::multi_usrp::make(args); - if (args.find("clock_source")==std::string::npos) { - if (openair0_cfg[0].clock_source == internal) { - s->usrp->set_clock_source("internal"); - LOG_I(HW,"Setting clock source to internal\n"); - } - else if (openair0_cfg[0].clock_source == external ) { - s->usrp->set_clock_source("external"); - LOG_I(HW,"Setting clock source to external\n"); - } - else if (openair0_cfg[0].clock_source==gpsdo) { - s->usrp->set_clock_source("gpsdo"); - LOG_I(HW,"Setting clock source to gpsdo\n"); - } - else { - LOG_W(HW,"Clock source set neither in usrp_args nor on command line, using default!\n"); - } - } - else { - if (openair0_cfg[0].clock_source != unset) { - LOG_W(HW,"Clock source set in both usrp_args and in clock_source, ingnoring the latter!\n"); - } - } - - if (args.find("time_source")==std::string::npos) { - if (openair0_cfg[0].time_source == internal) { - s->usrp->set_time_source("internal"); - LOG_I(HW,"Setting time source to internal\n"); - } - else if (openair0_cfg[0].time_source == external ) { - s->usrp->set_time_source("external"); - LOG_I(HW,"Setting time source to external\n"); - } - else if (openair0_cfg[0].time_source==gpsdo) { - s->usrp->set_time_source("gpsdo"); - LOG_I(HW,"Setting time source to gpsdo\n"); - } - else { - LOG_W(HW,"Time source set neither in usrp_args nor on command line, using default!\n"); - } - } - else { - if (openair0_cfg[0].clock_source != unset) { - LOG_W(HW,"Time source set in both usrp_args and in time_source, ingnoring the latter!\n"); - } - } - - - if (s->usrp->get_clock_source(0) == "gpsdo") { - s->use_gps = 1; - - if (sync_to_gps(device)==EXIT_SUCCESS) { - LOG_I(HW,"USRP synced with GPS!\n"); - } else { - LOG_I(HW,"USRP fails to sync with GPS. Exiting.\n"); - exit(EXIT_FAILURE); - } - } else { - if (s->usrp->get_time_source(0) == "external") { - usrp_sync_pps(s); - } else { - s->usrp->set_time_next_pps(uhd::time_spec_t(0.0)); - } - - if (s->usrp->get_clock_source(0) == "external") { - if (check_ref_locked(s,0)) { - LOG_I(HW,"USRP locked to external reference!\n"); - } else { - LOG_I(HW,"Failed to lock to external reference. Exiting.\n"); - exit(EXIT_FAILURE); - } - } - } - if (device->type==USRP_X300_DEV) { openair0_cfg[0].rx_gain_calib_table = calib_table_x310; std::cerr << "-- Using calibration table: calib_table_x310" << std::endl; @@ -1470,8 +1397,70 @@ extern "C" { } } - //s->usrp->set_clock_source("external"); - //s->usrp->set_time_source("external"); + if (args.find("clock_source") == std::string::npos) { + if (openair0_cfg[0].clock_source == internal) { + s->usrp->set_clock_source("internal"); + LOG_I(HW, "Setting clock source to internal\n"); + } else if (openair0_cfg[0].clock_source == external) { + s->usrp->set_clock_source("external"); + LOG_I(HW, "Setting clock source to external\n"); + } else if (openair0_cfg[0].clock_source == gpsdo) { + s->usrp->set_clock_source("gpsdo"); + LOG_I(HW, "Setting clock source to gpsdo\n"); + } else { + LOG_W(HW, "Clock source set neither in usrp_args nor on command line, using default!\n"); + } + } else { + if (openair0_cfg[0].clock_source != unset) { + LOG_W(HW, "Clock source set in both usrp_args and in clock_source, ingnoring the latter!\n"); + } + } + + if (args.find("time_source") == std::string::npos) { + if (openair0_cfg[0].time_source == internal) { + s->usrp->set_time_source("internal"); + LOG_I(HW, "Setting time source to internal\n"); + } else if (openair0_cfg[0].time_source == external) { + s->usrp->set_time_source("external"); + LOG_I(HW, "Setting time source to external\n"); + } else if (openair0_cfg[0].time_source == gpsdo) { + s->usrp->set_time_source("gpsdo"); + LOG_I(HW, "Setting time source to gpsdo\n"); + } else { + LOG_W(HW, "Time source set neither in usrp_args nor on command line, using default!\n"); + } + } else { + if (openair0_cfg[0].time_source != unset) { + LOG_W(HW, "Time source set in both usrp_args and in openair0_cfg[0].time_source, ignoring the latter!\n"); + } + } + + if (s->usrp->get_clock_source(0) == "gpsdo") { + s->use_gps = 1; + + if (sync_to_gps(device) == EXIT_SUCCESS) { + LOG_I(HW, "USRP synced with GPS!\n"); + } else { + LOG_I(HW, "USRP fails to sync with GPS. Exiting.\n"); + exit(EXIT_FAILURE); + } + } else { + if (s->usrp->get_time_source(0) == "external") { + usrp_sync_pps(s); + } else { + s->usrp->set_time_next_pps(uhd::time_spec_t(0.0)); + } + + if (s->usrp->get_clock_source(0) == "external") { + if (check_ref_locked(s, 0)) { + LOG_I(HW, "USRP locked to external reference!\n"); + } else { + LOG_I(HW, "Failed to lock to external reference. Exiting.\n"); + exit(EXIT_FAILURE); + } + } + } + // display USRP settings LOG_I(HW,"Actual master clock: %fMHz...\n",s->usrp->get_master_clock_rate()/1e6); LOG_I(HW,"Actual clock source %s...\n",s->usrp->get_clock_source(0).c_str()); diff --git a/radio/emulator/CMakeLists.txt b/radio/emulator/CMakeLists.txt new file mode 100644 index 0000000000..983d95986a --- /dev/null +++ b/radio/emulator/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(rf_emulator MODULE rf_emulator.c) +set_target_properties(rf_emulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(rf_emulator PRIVATE noise_device log_headers) diff --git a/radio/emulator/README.md b/radio/emulator/README.md new file mode 100644 index 0000000000..b3b58ba6a7 --- /dev/null +++ b/radio/emulator/README.md @@ -0,0 +1,25 @@ +# RF emulator library + +The RF emulator is a simple network stack terminator on the RF side. +It is meant to run the network stack without real radio and without RF simulation. +It simply drops TX signal and generate noise as an RX signal. +It can be used in `phy-test` mode to simply benchmark the network stack in a determined scenario. +It synchronizes the network stack on the real time clock of the host to guarantee a realistic behavior of the network stack. +It detects and report late samples reads and writes to assess the real time behavior of the network stack. + +## Building + +`librf_emulator.so` is built by default by the `build_oai.sh` script. +It is then located in the root build directory (usually `cmake_targets/ran_build/build`). + +## Usage + +### Enabling `rf_emulator` + +Use the option `--device.name rf_emulator` of the softmodem to use the RF emulator. + +### Options + +Two options are available to configure the RF emulator: +* `--rf_emulator.enable_noise ` Enables (enable = 1) or disables (enable = 0) noise generation on RX. By default noise generation is enabled. +* `--rf_emulator.noise_level_dBFS ` Sets the level of noise generated in dB. If omitted no noise is generated. diff --git a/radio/emulator/rf_emulator.c b/radio/emulator/rf_emulator.c new file mode 100644 index 0000000000..861daab2ba --- /dev/null +++ b/radio/emulator/rf_emulator.c @@ -0,0 +1,369 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file radio/emulator/rf_emulator.c + * \brief RF library that does nothing to be used in benchmarks with phy-test without RF + */ + +#include +#include + +#include +#include +#include "common/utils/threadPool/pthread_utils.h" +#include "common_lib.h" +#include "radio/vrtsim/noise_device.h" +#include "simde/x86/avx512.h" +#include "SIMULATION/TOOLS/sim.h" + +#define RF_EMULATOR_SECTION "rf_emulator" +// clang-format off +#define RF_EMULATOR_PARAMS_DESC \ + { \ + {"enable_noise", "Enable noise injection", 0, .iptr = &emulator_state->enable_noise, .defintval = 1, TYPE_INT, 0},\ + {"noise_level_dBFS", "Noise level", 0, .iptr = &emulator_state->noise_level_dBFS, .defintval = INVALID_DBFS_VALUE, TYPE_INT, 0},\ + }; +// clang-format on + +// structures and timing thread job for timing +typedef struct { + uint64_t timestamp; + pthread_mutex_t mutex; + pthread_cond_t cond; + uint64_t late_reads; + uint64_t late_writes; +} emulator_timestamp_t; + +typedef struct { + uint64_t last_received_sample; + double timescale; + double sample_rate; + emulator_timestamp_t emulator_timestamp; + pthread_t timing_thread; + bool run_timing_thread; + int enable_noise; + int noise_level_dBFS; +} emulator_state_t; + +static void *emulator_timing_job(void *arg) +{ + emulator_state_t *emulator_state = (emulator_state_t *)arg; + struct timespec timestamp; + if (clock_gettime(CLOCK_REALTIME, ×tamp)) { + LOG_E(UTIL, "clock_gettime failed\n"); + exit(1); + } + double leftover_samples = 0; + while (emulator_state->run_timing_thread) { + struct timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time)) { + LOG_E(UTIL, "clock_gettime failed\n"); + exit(1); + } + + emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp; + if (current_time.tv_sec != timestamp.tv_sec) { + if (emulator_timestamp->late_reads != 0) { + LOG_W(HW, "%ld RF reads were late\n", emulator_timestamp->late_reads); + } + emulator_timestamp->late_reads = 0; + if (emulator_timestamp->late_writes != 0) { + LOG_W(HW, "%ld RF writes were late\n", emulator_timestamp->late_writes); + } + emulator_timestamp->late_writes = 0; + } + + uint64_t diff = (current_time.tv_sec - timestamp.tv_sec) * 1000000000 + (current_time.tv_nsec - timestamp.tv_nsec); + timestamp = current_time; + double samples_to_produce = emulator_state->sample_rate * emulator_state->timescale * diff / 1e9; + + // Attempt to correct compounding rounding error + leftover_samples += samples_to_produce - (uint64_t)samples_to_produce; + if (leftover_samples > 1.0f) { + samples_to_produce += 1; + leftover_samples -= 1; + } + + mutexlock(emulator_timestamp->mutex); + emulator_timestamp->timestamp += samples_to_produce; + condbroadcast(emulator_timestamp->cond); + mutexunlock(emulator_timestamp->mutex); + + usleep(1); + } + return 0; +} + +/*! \brief Called to start the RF transceiver. Return 0 if OK, < 0 if error + * \param device pointer to the device structure specific to the RF hardware target + */ +static int emulator_start(openair0_device *device) +{ + // Start the timing thread and the noise device + emulator_state_t *emulator_state = (emulator_state_t *)device->priv; + if (!emulator_state->run_timing_thread) { + if (emulator_state->enable_noise > 0) { + float noise_level = emulator_state->noise_level_dBFS == INVALID_DBFS_VALUE + ? 0.0f + : (32767.0 / powf(10.0, .05 * -(emulator_state->noise_level_dBFS))); + init_noise_device(noise_level); + LOG_I(HW, "Using noise level with %d dBFS/%f\n", emulator_state->noise_level_dBFS, noise_level); + } + + emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp; + memset(emulator_timestamp, 0, sizeof(emulator_timestamp_t)); + + pthread_mutexattr_t mutex_attr; + pthread_condattr_t cond_attr; + int ret = pthread_mutexattr_init(&mutex_attr); + AssertFatal(ret == 0, "pthread_mutexattr_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_condattr_init(&cond_attr); + AssertFatal(ret == 0, "pthread_condattr_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED); + AssertFatal(ret == 0, "pthread_mutexattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED); + AssertFatal(ret == 0, "pthread_condattr_setpshared() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_mutex_init(&emulator_timestamp->mutex, &mutex_attr); + AssertFatal(ret == 0, "pthread_mutex_init() failed: errno %d, %s\n", errno, strerror(errno)); + + ret = pthread_cond_init(&emulator_timestamp->cond, &cond_attr); + AssertFatal(ret == 0, "pthread_cond_init() failed: errno %d, %s\n", errno, strerror(errno)); + + emulator_state->run_timing_thread = true; + ret = pthread_create(&emulator_state->timing_thread, NULL, emulator_timing_job, emulator_state); + AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); + } + + return 0; +} + +/*! \brief print the RF statistics + * \param device pointer to the device structure specific to the RF hardware target + * \returns 0 on success + */ +int emulator_get_stats(openair0_device *device) +{ + return (0); +} + +/*! \brief Reset the RF statistics + * \param device pointer to the device structure specific to the RF hardware target + * \returns 0 on success + */ +int emulator_reset_stats(openair0_device *device) +{ + return (0); +} + +/*! \brief Terminate operation of the RF transceiver -- free all associated resources (if any) + * \param pointer to the device structure specific to the RF hardware target + */ +static void emulator_end(openair0_device *device) +{ + // Stop the timing thread and the noise device + emulator_state_t *emulator_state = (emulator_state_t *)device->priv; + if (emulator_state->run_timing_thread) { + emulator_state->run_timing_thread = false; + int ret = pthread_join(emulator_state->timing_thread, NULL); + AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno)); + if (emulator_state->enable_noise > 0) { + free_noise_device(); + } + } +} + +/*! \brief Stop RF + * \param device pointer to the device structure specific to the RF hardware target + */ +int emulator_stop(openair0_device *device) +{ + return (0); +} + +/*! \brief Set Gains (TX/RX) + * \param device pointer to the device structure specific to the RF hardware target + * \param openair0_cfg RF frontend parameters set by application + * \returns 0 in success + */ +int emulator_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) +{ + return (0); +} + +/*! \brief Set frequencies (TX/RX). + * \param device pointer to the device structure specific to the RF hardware target + * \param openair0_cfg RF frontend parameters set by application + * \returns 0 in success + */ +int emulator_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) +{ + return (0); +} + +int emulator_write_init(openair0_device *device) +{ + return (0); +} + +/*! \brief Called to send samples to the RF target + * \param device pointer to the device structure specific to the RF hardware target + * \param timestamp The timestamp at which the first sample MUST be sent + * \param buff Buffer which holds the samples + * \param nsamps number of samples to be sent + * \param nbAnt number of antennas + * \param flags flags must be set to true if timestamp parameter needs to be applied + */ +static int emulator_write(openair0_device *device, openair0_timestamp timestamp, void **buff, int nsamps, int nbAnt, int flags) +{ + emulator_state_t *emulator_state = (emulator_state_t *)device->priv; + + // timestamp in the past + emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp; + uint64_t current_timestamp = emulator_timestamp->timestamp; + if (timestamp < current_timestamp) { + mutexlock(emulator_timestamp->mutex); + emulator_timestamp->late_writes++; + mutexunlock(emulator_timestamp->mutex); + } + + return 0; +} + +/*! \brief Store noise in the buffer buff + * \param[out] buff A buffer for received samples. + * The buffers must be large enough to hold the number of samples \ref nsamps. + * \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte. + */ +static void read_noise(void *buff, int nsamps) +{ + int aligned_nsamps = ceil_mod(nsamps, (512 / 8) / sizeof(cf_t)); + cf_t samples[aligned_nsamps] __attribute__((aligned(64))); + // Apply noise from global settings + get_noise_vector((float *)samples, nsamps * 2); + + // Convert to c16_t + c16_t samples_out[aligned_nsamps] __attribute__((aligned(64))); +#if defined(__AVX512F__) + for (int i = 0; i < aligned_nsamps / 8; i++) { + simde__m512 *in = (simde__m512 *)&samples[i * 8]; + simde__m256i *out = (simde__m256i *)&samples_out[i * 8]; + *out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in)); + } +#elif defined(__AVX2__) + for (int i = 0; i < aligned_nsamps / 4; i++) { + simde__m256 *in = (simde__m256 *)&samples[i * 4]; + simde__m128i *out = (simde__m128i *)&samples_out[i * 4]; + *out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in)); + } +#else + for (int i = 0; i < nsamps; i++) { + samples_out[i].r = lroundf(samples[i].r); + samples_out[i].i = lroundf(samples[i].i); + } +#endif + memcpy(buff, samples_out, nsamps * sizeof(c16_t)); +} + +/*! \brief Receive samples from hardware. + * Read \ref nsamps samples from each channel to buffers. buff[0] is the array for + * the first channel. + * \param[out] ptimestamp time at which the first sample was received. + * \param device pointer to the device structure specific to the RF hardware target + * \param[out] ptimestamp the time at which the first sample was received. + * \param[out] buff An array of pointers to buffers for received samples. The buffers must be large enough to hold the number of + * samples \ref nsamps. \param nsamps Number of samples. One sample is 2 byte I + 2 byte Q => 4 byte. + * \param nbAnt number of antennas + * \returns the number of samples read + */ +static int emulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **buff, int nsamps, int nbAnt) +{ + emulator_state_t *emulator_state = (emulator_state_t *)device->priv; + + emulator_timestamp_t *emulator_timestamp = &emulator_state->emulator_timestamp; + uint64_t timestamp = emulator_state->last_received_sample + nsamps; + uint64_t current_timestamp = emulator_timestamp->timestamp; + if (current_timestamp < timestamp) { + mutexlock(emulator_timestamp->mutex); + while (current_timestamp < timestamp) { + condwait(emulator_timestamp->cond, emulator_timestamp->mutex); + current_timestamp = emulator_timestamp->timestamp; + } + mutexunlock(emulator_timestamp->mutex); + } else { + mutexlock(emulator_timestamp->mutex); + emulator_timestamp->late_reads++; + mutexunlock(emulator_timestamp->mutex); + } + *ptimestamp = emulator_state->last_received_sample; + emulator_state->last_received_sample += nsamps; + + if (emulator_state->enable_noise > 0) { + for (int i = 0; i < nbAnt; i++) { + read_noise(buff[i], nsamps); + } + } else { + for (int i = 0; i < nbAnt; i++) { + memset(buff[i], 0, nsamps * sizeof(c16_t)); + } + } + + return nsamps; +} + +static void emulator_readconfig(emulator_state_t *emulator_state) +{ + paramdef_t emulator_params[] = RF_EMULATOR_PARAMS_DESC; + int ret = config_get(config_get_if(), emulator_params, sizeofArray(emulator_params), RF_EMULATOR_SECTION); + AssertFatal(ret >= 0, "configuration couldn't be performed\n"); +} + +int device_init(openair0_device *device, openair0_config_t *openair0_cfg) +{ + LOG_I(HW, "This is emulator RF that does nothing\n"); + + emulator_state_t *emulator_state = calloc_or_fail(1, sizeof(emulator_state_t)); + emulator_state->last_received_sample = 0; + emulator_state->timescale = 1.0; + emulator_state->sample_rate = openair0_cfg->sample_rate; + emulator_state->run_timing_thread = false; + + device->priv = emulator_state; + device->openair0_cfg = openair0_cfg; + device->trx_start_func = emulator_start; + device->trx_get_stats_func = emulator_get_stats; + device->trx_reset_stats_func = emulator_reset_stats; + device->trx_end_func = emulator_end; + device->trx_stop_func = emulator_stop; + device->trx_set_freq_func = emulator_set_freq; + device->trx_set_gains_func = emulator_set_gains; + device->trx_write_init = emulator_write_init; + device->type = RFSIMULATOR; + device->trx_write_func = emulator_write; + device->trx_read_func = emulator_read; + + emulator_readconfig(emulator_state); + + return 0; +} diff --git a/radio/fhi_72/CMakeLists.txt b/radio/fhi_72/CMakeLists.txt index a874d4cc01..f2161d06a8 100644 --- a/radio/fhi_72/CMakeLists.txt +++ b/radio/fhi_72/CMakeLists.txt @@ -16,8 +16,8 @@ add_library(oran_fhlib_5g MODULE oran-init.c ) -set(E_VERSION 5.1.5) -set(F_VERSION 6.1.3) +set(E_VERSION 5.1.6) +set(F_VERSION 6.1.4) find_package(xran REQUIRED) if(xran_VERSION VERSION_EQUAL E_VERSION) @@ -33,7 +33,8 @@ endif() add_compile_options(-Wno-packed-not-aligned) set_target_properties(oran_fhlib_5g PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") -target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa) +target_link_libraries(oran_fhlib_5g PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} pthread dl rt m numa) +target_link_libraries(oran_fhlib_5g PRIVATE log_headers) target_include_directories(oran_fhlib_5g PRIVATE ${dpdk_INCLUDE_DIRS}) if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") find_package(armral REQUIRED) diff --git a/radio/fhi_72/mplane/CMakeLists.txt b/radio/fhi_72/mplane/CMakeLists.txt index 65faa6dfbd..26bbb7939e 100644 --- a/radio/fhi_72/mplane/CMakeLists.txt +++ b/radio/fhi_72/mplane/CMakeLists.txt @@ -17,7 +17,7 @@ endif() add_compile_options(-Wno-packed-not-aligned) set_target_properties(oran_fhlib_5g_mplane PROPERTIES COMPILE_FLAGS "-fvisibility=hidden -march=native") -target_link_libraries(oran_fhlib_5g_mplane PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} ${T_LIB} pthread dl rt m numa) +target_link_libraries(oran_fhlib_5g_mplane PRIVATE xran::xran ${dpdk_LINK_LIBRARIES} log_headers pthread dl rt m numa) target_include_directories(oran_fhlib_5g_mplane PRIVATE ${dpdk_INCLUDE_DIRS}) target_compile_definitions(oran_fhlib_5g_mplane PRIVATE OAI_MPLANE) diff --git a/radio/fhi_72/mplane/config-mplane.c b/radio/fhi_72/mplane/config-mplane.c index 69ff1fd2b3..da28665023 100644 --- a/radio/fhi_72/mplane/config-mplane.c +++ b/radio/fhi_72/mplane/config-mplane.c @@ -21,14 +21,12 @@ #include "config-mplane.h" #include "rpc-send-recv.h" -#include "yang/get-yang.h" -#include "yang/create-yang-config.h" #include "common/utils/assertions.h" #include #include -bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus) +static bool edit_config_mplane(ru_session_t *ru_session, const char *content) { int timeout = CLI_RPC_REPLY_TIMEOUT; struct nc_rpc *rpc; @@ -39,37 +37,21 @@ bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const open NC_RPC_EDIT_TESTOPT test = NC_RPC_EDIT_TESTOPT_UNKNOWN; NC_RPC_EDIT_ERROPT err = NC_RPC_EDIT_ERROPT_UNKNOWN; - bool success = false; - - struct ly_ctx *ctx = NULL; - success = load_yang_models(ru_session, buffer, &ctx); - AssertError(success, return false, "[MPLANE] Unable to continue.\n"); - - char *content = NULL; - success = configure_ru_from_yang(&ctx, ru_session, oai, num_rus, &content); - AssertError(success, return false, "[MPLANE] Unable to create content for RPC.\n"); - MP_LOG_I("RPC request to RU \"%s\" = :\n%s\n", ru_session->ru_ip_add, content); rpc = nc_rpc_edit(target, op, test, err, content, param); AssertError(rpc != NULL, return false, "[MPLANE] RPC creation failed.\n"); - success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL); + bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL); AssertError(success, return false, "[MPLANE] Failed to edit configuration for the candidate datastore.\n"); MP_LOG_I("Successfully edited the candidate datastore for RU \"%s\".\n", ru_session->ru_ip_add); nc_rpc_free(rpc); - free(content); -#ifdef MPLANE_V1 - ly_ctx_destroy(ctx, NULL); -#elif defined MPLANE_V2 - ly_ctx_destroy(ctx); -#endif return true; } -bool validate_config_mplane(ru_session_t *ru_session) +static bool validate_config_mplane(ru_session_t *ru_session) { int timeout = CLI_RPC_REPLY_TIMEOUT; struct nc_rpc *rpc; @@ -92,7 +74,7 @@ bool validate_config_mplane(ru_session_t *ru_session) return true; } -bool commit_config_mplane(ru_session_t *ru_session) +static bool commit_config_mplane(ru_session_t *ru_session) { int timeout = CLI_RPC_REPLY_TIMEOUT; struct nc_rpc *rpc; @@ -109,9 +91,25 @@ bool commit_config_mplane(ru_session_t *ru_session) bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL); AssertError(success, return false, "[MPLANE] Failed to commit candidate datastore.\n"); - MP_LOG_I("Successfully commited CU-planes configuration into running datastore for RU \"%s\".\n", ru_session->ru_ip_add); + MP_LOG_I("Successfully commited configuration into running datastore for RU \"%s\".\n", ru_session->ru_ip_add); nc_rpc_free(rpc); return true; } + +bool edit_val_commmit_rpc(ru_session_t *ru_session, const char *content) +{ + bool success = false; + + success = edit_config_mplane(ru_session, content); + AssertError(success, return false, "[MPLANE] Unable to edit the RU configuration.\n"); + + success = validate_config_mplane(ru_session); + AssertError(success, return false, "[MPLANE] Unable to validate the RU configuration.\n"); + + success = commit_config_mplane(ru_session); + AssertError(success, return false, "[MPLANE] Unable to commit the RU configuration.\n"); + + return success; +} diff --git a/radio/fhi_72/mplane/config-mplane.h b/radio/fhi_72/mplane/config-mplane.h index c8451ca8a0..dae2dbea63 100644 --- a/radio/fhi_72/mplane/config-mplane.h +++ b/radio/fhi_72/mplane/config-mplane.h @@ -25,10 +25,6 @@ #include "ru-mplane-api.h" #include "radio/COMMON/common_lib.h" -bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus); - -bool validate_config_mplane(ru_session_t *ru_session); - -bool commit_config_mplane(ru_session_t *ru_session); +bool edit_val_commmit_rpc(ru_session_t *ru_session, const char *content); #endif /* CONFIGURE_MPLANE_H */ diff --git a/radio/fhi_72/mplane/connect-mplane.c b/radio/fhi_72/mplane/connect-mplane.c index 08b758bef1..9744ce01e8 100644 --- a/radio/fhi_72/mplane/connect-mplane.c +++ b/radio/fhi_72/mplane/connect-mplane.c @@ -20,6 +20,7 @@ */ #include "connect-mplane.h" +#include "init-mplane.h" #include "common/utils/assertions.h" #include @@ -37,9 +38,8 @@ static int my_auth_hostkey_check(const char *hostname, ssh_session session, void bool connect_mplane(ru_session_t *ru_session) { int port = NC_PORT_SSH; - char *user = "oranbenetel"; - nc_client_ssh_set_username(user); + nc_client_ssh_set_username(ru_session->username); nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); // ssh-key identification nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1); @@ -47,11 +47,11 @@ bool connect_mplane(ru_session_t *ru_session) nc_client_ssh_set_auth_hostkey_check_clb(my_auth_hostkey_check, "DATA"); // host-key identification - MP_LOG_I("RPC request to RU \"%s\" = with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port); + MP_LOG_I("RPC request to RU \"%s\" = with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, ru_session->username, port); ru_session->session = nc_connect_ssh(ru_session->ru_ip_add, port, NULL); AssertError(ru_session->session != NULL, return false, "[MPLANE] RU IP address %s unreachable. Maybe M-plane is disabled on the RU?\n", ru_session->ru_ip_add); - MP_LOG_I("Successfuly connected to RU \"%s\" with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port); + MP_LOG_I("Successfuly connected to RU \"%s\" with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, ru_session->username, port); return true; } @@ -64,9 +64,18 @@ void disconnect_mplane(void *rus_disconnect) ru_session_t *ru_session = &ru_session_list->ru_session[i]; if (ru_session->session == NULL) continue; + MP_LOG_I("Sending PM de-activation request for RU \"%s\".\n", ru_session->ru_ip_add); + bool success = pm_conf(ru_session, "false"); + if (success) + MP_LOG_I("Successfully de-activated PM for RU \"%s\".\n", ru_session->ru_ip_add); MP_LOG_I("Disconnecting from RU \"%s\".\n", ru_session->ru_ip_add); nc_session_free(ru_session->session, NULL); ru_session->session = NULL; +#ifdef MPLANE_V1 + ly_ctx_destroy((struct ly_ctx *)ru_session->ctx, NULL); +#elif defined MPLANE_V2 + ly_ctx_destroy((struct ly_ctx *)ru_session->ctx); +#endif } nc_client_destroy(); diff --git a/radio/fhi_72/mplane/init-mplane.c b/radio/fhi_72/mplane/init-mplane.c index 39e8cfb995..fc20ba5af4 100644 --- a/radio/fhi_72/mplane/init-mplane.c +++ b/radio/fhi_72/mplane/init-mplane.c @@ -25,6 +25,8 @@ #include "subscribe-mplane.h" #include "config-mplane.h" #include "xml/get-xml.h" +#include "yang/get-yang.h" +#include "yang/create-yang-config.h" #include #include @@ -94,11 +96,14 @@ bool init_mplane(ru_session_list_t *ru_session_list) char **ru_ip_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->strlistptr; int num_rus = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->numelt; + char **ru_usernames = gpd(fhip, nump, ORAN_CONFIG_RU_USERNAME)->strlistptr; + int num_ru_users = gpd(fhip, nump, ORAN_CONFIG_RU_USERNAME)->numelt; char **du_mac_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr; int num_dus = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt; int32_t *vlan_tag = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->iptr; int num_vlan_tags = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->numelt; + AssertError(num_rus == num_ru_users, return false, "[MPLANE] Number of RUs should be equal to the number of users, one for each.\n"); AssertError(num_dus == num_vlan_tags, return false, "[MPLANE] Number of DU MAC addresses should be equal to the number of VLAN tags.\n"); int num_cu_planes = num_dus / num_rus; @@ -110,6 +115,8 @@ bool init_mplane(ru_session_list_t *ru_session_list) ru_session->session = NULL; ru_session->ru_ip_add = calloc(strlen(ru_ip_addrs[i]) + 1, sizeof(char)); memcpy(ru_session->ru_ip_add, ru_ip_addrs[i], strlen(ru_ip_addrs[i]) + 1); + ru_session->username = calloc(strlen(ru_usernames[i]) + 1, sizeof(char)); + memcpy(ru_session->username, ru_usernames[i], strlen(ru_usernames[i]) + 1); // store DU MAC addresses and VLAN tags ru_session->ru_mplane_config.num_cu_planes = num_cu_planes; @@ -175,15 +182,21 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz success = get_uplane_info(operational_ds, &ru_session->ru_mplane_config); AssertError(success, return false, "[MPLANE] Unable to get U-plane info from RU operational datastore.\n"); + // Performance Management + success = get_pm_object_list(operational_ds, &ru_session->pm_stats); + AssertError(success, return false, "[MPLANE] Unable to retrieve performance measurement names from RU \"%s\".\n", ru_session->ru_ip_add); + + success = load_yang_models(ru_session, operational_ds); + AssertError(success, return false, "[MPLANE] Unable to load yang models.\n"); + if (ru_session->ru_notif.ptp_state) { - success = edit_config_mplane(ru_session, operational_ds, oai, num_rus); - AssertError(success, return false, "[MPLANE] Unable to edit the RU configuration.\n"); + char *content = NULL; + success = configure_ru_from_yang(ru_session, oai, num_rus, &content); + AssertError(success, return false, "[MPLANE] Unable to create content for RPC for start-up procedure.\n"); - success = validate_config_mplane(ru_session); - AssertError(success, return false, "[MPLANE] Unable to validate the RU configuration.\n"); - - success = commit_config_mplane(ru_session); - AssertError(success, return false, "[MPLANE] Unable to commit the RU configuration.\n"); + success = edit_val_commmit_rpc(ru_session, content); + AssertError(success, return false, "[MPLANE] Unable to continue.\n"); + free(content); } const char *usage_state = get_ru_xml_node(operational_ds, "usage-state"); @@ -203,3 +216,15 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz return true; } + +bool pm_conf(ru_session_t *ru_session, const char *active) +{ + char *content = get_pm_content(ru_session, active); + + bool success = edit_val_commmit_rpc(ru_session, content); + AssertError(success, return false, "[MPLANE] Cannot continue.\n"); + + free(content); + + return true; +} diff --git a/radio/fhi_72/mplane/init-mplane.h b/radio/fhi_72/mplane/init-mplane.h index 5077908d64..ef6e23610f 100644 --- a/radio/fhi_72/mplane/init-mplane.h +++ b/radio/fhi_72/mplane/init-mplane.h @@ -29,4 +29,6 @@ bool init_mplane(ru_session_list_t *ru_session_list); bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus); +bool pm_conf(ru_session_t *ru_session, const char *active); + #endif /* OAI_MPLANE_H */ diff --git a/radio/fhi_72/mplane/ru-mplane-api.c b/radio/fhi_72/mplane/ru-mplane-api.c index d387a40864..df4bf3b8ba 100644 --- a/radio/fhi_72/mplane/ru-mplane-api.c +++ b/radio/fhi_72/mplane/ru-mplane-api.c @@ -33,7 +33,7 @@ static void free_match_list(char **match_list, size_t count) free(match_list); } -static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t interface_mtu, const int16_t first_iq_width, const int max_num_ant) +static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t interface_mtu, const int16_t first_iq_width, const int max_num_ant, const char *model_name) { if (interface_mtu == 1500) { MP_LOG_I("Interface MTU %d unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600.\n", interface_mtu); @@ -50,6 +50,14 @@ static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t inter } xran_mplane->prach_offset = max_num_ant; + + if (strcasecmp(model_name, "RAN550") == 0) { + xran_mplane->max_tx_gain = 24.0; + } else if (strcasecmp(model_name, "RAN650") == 0) { + xran_mplane->max_tx_gain = 35.0; + } else { + assert(false && "[MPLANE] Unknown Benetel model name.\n"); + } } bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane) @@ -61,7 +69,7 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_ xran_mplane->ru_mac_addr = get_ru_xml_node(buffer, "mac-address"); // TODO: support for VVDN, as it defines multiple MAC addresses // MTU - const uint32_t interface_mtu = (uint32_t)atoi(get_ru_xml_node(buffer, "interface-mtu")); + const uint32_t interface_mtu = (uint32_t)atoi(get_ru_xml_node(buffer, "l2-mtu")); // IQ bitwidth char **match_list = NULL; @@ -91,8 +99,25 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_ // RU port ID xran_mplane->ru_port = 0; + // Frame structure + match_list = NULL; + count = 0; + get_ru_xml_list(buffer, "supported-frame-structures", &match_list, &count); + xran_mplane->frame_str = (int16_t)atoi((char *)match_list[0]); + free_match_list(match_list, count); + + // Managed delay support + const char *managed_delay = get_ru_xml_node(buffer, "managed-delay-support"); + xran_mplane->managed_delay = (strcasecmp(managed_delay, "NON_MANAGED") == 0) ? false : true; + + // Store the max gain + xran_mplane->max_tx_gain = (double)atof(get_ru_xml_node(buffer, "max-gain")); + + // Model name + const char *model_name = get_ru_xml_node(buffer, "model-name"); + if (strcasecmp(ru_vendor, "BENETEL") == 0 /* || strcmp(ru_vendor, "VVDN-LPRU") == 0 || strcmp(ru_vendor, "Metanoia") == 0 */) { - fix_benetel_setting(xran_mplane, interface_mtu, first_iq_width, max_num_ant); + fix_benetel_setting(xran_mplane, interface_mtu, first_iq_width, max_num_ant, model_name); } else { AssertError(false, return false, "[MPLANE] %s RU currently not supported.\n", ru_vendor); } @@ -109,7 +134,8 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_ DU port ID %d\n\ Band sector ID %d\n\ CC ID %d\n\ - RU port ID %d\n", + RU port ID %d\n\ + max Tx gain %.1f\n", xran_mplane->ru_mac_addr, xran_mplane->mtu, xran_mplane->iq_width, @@ -121,7 +147,8 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_ xran_mplane->du_port, xran_mplane->band_sector, xran_mplane->ccid, - xran_mplane->ru_port); + xran_mplane->ru_port, + xran_mplane->max_tx_gain); return true; } @@ -155,3 +182,23 @@ bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config) return true; } + +bool get_pm_object_list(const char *buffer, pm_stats_t *pm_stats) +{ + const char *ru_vendor = get_ru_xml_node(buffer, "mfg-name"); + if (strcasecmp(ru_vendor, "BENETEL") == 0) { + pm_stats->start_up_timing = false; + } else { + pm_stats->start_up_timing = true; + } + + // Rx window + get_ru_xml_list(buffer, "rx-window-objects", &pm_stats->rx_window_meas, &pm_stats->rx_num); + + // Tx + get_ru_xml_list(buffer, "tx-stats-objects", &pm_stats->tx_meas, &pm_stats->tx_num); + + MP_LOG_I("Successfully retreived all performance measurement names.\n"); + + return true; +} diff --git a/radio/fhi_72/mplane/ru-mplane-api.h b/radio/fhi_72/mplane/ru-mplane-api.h index 70857adea6..85fac5515c 100644 --- a/radio/fhi_72/mplane/ru-mplane-api.h +++ b/radio/fhi_72/mplane/ru-mplane-api.h @@ -57,6 +57,10 @@ typedef struct { uint8_t band_sector; uint8_t ccid; uint8_t ru_port; + int16_t frame_str; // might be needed in the future xran releases + bool managed_delay; + + double max_tx_gain; } xran_mplane_t; @@ -78,11 +82,26 @@ typedef struct { } ru_mplane_config_t; typedef struct { + // activation if required at start-up timing + bool start_up_timing; + + size_t rx_num; + char **rx_window_meas; + + size_t tx_num; + char **tx_meas; + +} pm_stats_t; + +typedef struct { + char *username; char *ru_ip_add; ru_mplane_config_t ru_mplane_config; void *session; + void *ctx; xran_mplane_t xran_mplane; ru_notif_t ru_notif; + pm_stats_t pm_stats; } ru_session_t; @@ -97,4 +116,6 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_ bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config); +bool get_pm_object_list(const char *buffer, pm_stats_t *pm_stats); + #endif /* RU_MPLANE_API_H */ diff --git a/radio/fhi_72/mplane/subscribe-mplane.c b/radio/fhi_72/mplane/subscribe-mplane.c index 9a8e28c4c1..bec7e28a68 100644 --- a/radio/fhi_72/mplane/subscribe-mplane.c +++ b/radio/fhi_72/mplane/subscribe-mplane.c @@ -54,6 +54,37 @@ static void notif_clb_v1(struct nc_session *session, const struct nc_notif *noti recv_notif_v1(notif, answer); } #elif MPLANE_V2 +static void log_v2_pm_info(const char *ru_ip_add, struct lyd_node_inner *stats) +{ + struct lyd_node *child, *field = NULL; + size_t len = 0; + char *meas_list[8], *count_list[8] = {}; + + LY_LIST_FOR(stats->child, child) { + // const char *type = child->schema->name; // e.g. "rx-window-stats", "tx-stats" + struct lyd_node_inner *stats_inner = (struct lyd_node_inner *)child; + LY_LIST_FOR(stats_inner->child, field) { + if (strcmp(field->schema->name, "measurement-object") == 0) { + meas_list[len] = (char *)lyd_get_value(field); + } else if (strcmp(field->schema->name, "count") == 0) { + count_list[len] = (char *)lyd_get_value(field); + len++; + } + } + } + + MP_LOG_I("[PM: \"%s\"][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s]\n", + ru_ip_add, + meas_list[0], count_list[0], + meas_list[1], count_list[1], + meas_list[2], count_list[2], + meas_list[3], count_list[3], + meas_list[4], count_list[4], + meas_list[5], count_list[5], + meas_list[6], count_list[6], + meas_list[7], count_list[7]); +} + static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer) { const char *notif = op->schema->name; @@ -92,9 +123,14 @@ static void notif_clb_v2(struct nc_session *session, const struct lyd_node *envp char *subs_reply = NULL; lyd_print_mem(&subs_reply, op, output_format, LYD_PRINT_WITHSIBLINGS); const char *ru_ip_add = nc_session_get_host(session); + struct lyd_node_inner *op_inner = (struct lyd_node_inner *)op; + if (strcmp(op_inner->schema->name, "measurement-result-stats") == 0) { + log_v2_pm_info(ru_ip_add, op_inner); + return; + } MP_LOG_I("Received notification from RU \"%s\" at (%s)\n%s\n", ru_ip_add, ((struct lyd_node_opaq *)lyd_child(envp))->value, subs_reply); - recv_notif_v2((struct lyd_node_inner *)op, answer); + recv_notif_v2(op_inner, answer); } #endif diff --git a/radio/fhi_72/mplane/xml/get-xml.c b/radio/fhi_72/mplane/xml/get-xml.c index 616d2e480f..6456219293 100644 --- a/radio/fhi_72/mplane/xml/get-xml.c +++ b/radio/fhi_72/mplane/xml/get-xml.c @@ -68,7 +68,8 @@ static void find_ru_xml_list(xmlNode *node, const char *filter, char ***match_li xmlNode *name_node = NULL; for (xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) { - if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) { + const char *name_node_str = (const char *)cur_node2->name; + if (cur_node2->type == XML_ELEMENT_NODE && (strcmp(name_node_str, "name") == 0 || strcmp(name_node_str, "measurement-object") == 0)) { name_node = cur_node2; break; } diff --git a/radio/fhi_72/mplane/yang/create-yang-config.c b/radio/fhi_72/mplane/yang/create-yang-config.c index 7276b9fae0..187fe5b7c1 100644 --- a/radio/fhi_72/mplane/yang/create-yang-config.c +++ b/radio/fhi_72/mplane/yang/create-yang-config.c @@ -23,13 +23,14 @@ #include "common/utils/nr/nr_common.h" #define VERIFY_SUCCESS(var, message, args...) AssertError(var, return false, message, ##args) +const char *scs_name[] = {"KHZ_15", "KHZ_30", "KHZ_60", "KHZ_120", "KHZ_240", NULL}; #ifdef MPLANE_V2 -static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root) +static bool create_cu_interface_v2(const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root) { LY_ERR ret = LY_SUCCESS; - ret = lyd_new_path(NULL, *ctx, "/ietf-interfaces:interfaces", NULL, 0, root); + ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/ietf-interfaces:interfaces", NULL, 0, root); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"interfaces\" node.\n"); struct lyd_node *interface_node = NULL; @@ -43,7 +44,7 @@ static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_s ret = lyd_new_term(interface_node, NULL, "enabled", "true", 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"enabled\" node.\n"); - const struct lys_module *oran_int_mod = ly_ctx_get_module_implemented(*ctx, "o-ran-interfaces"); + const struct lys_module *oran_int_mod = ly_ctx_get_module_implemented((struct ly_ctx *)ru_session->ctx, "o-ran-interfaces"); VERIFY_SUCCESS(oran_int_mod != NULL, "[MPLANE] Failed to get \"o-ran-interfaces\" module.\n"); struct lyd_node *base_int = NULL; @@ -63,11 +64,11 @@ static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_s return true; } -static bool create_proc_elem_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root) +static bool create_proc_elem_v2(const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root) { LY_ERR ret = LY_SUCCESS; - ret = lyd_new_path(NULL, *ctx, "/o-ran-processing-element:processing-elements", NULL, 0, root); + ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/o-ran-processing-element:processing-elements", NULL, 0, root); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"processing-elements\" node.\n"); ret = lyd_new_term(*root, NULL, "transport-session-type", "ETH-INTERFACE", 0, NULL); @@ -104,20 +105,42 @@ static bool create_proc_elem_v2(struct ly_ctx **ctx, const ru_session_t *ru_sess return true; } -static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx, struct lyd_node **root) +typedef enum { UP_CH_RX, UP_CH_TX } uplane_dir_t; + +static LY_ERR fill_uplane_ch_common_v2(const uplane_dir_t dir, const xran_mplane_t *xran_mplane, const openair0_config_t *oai, const size_t idx, struct lyd_node **root) { LY_ERR ret = LY_SUCCESS; - ret = lyd_new_term(*root, NULL, "cp-length", "0", 0, NULL); + char frame_str[8]; + snprintf(frame_str, sizeof(frame_str), "%d", (oai->split7.fftSize << 4) + oai->nr_scs_for_raster); // 3GPP TS 38.211 + ret = lyd_new_term(*root, NULL, "frame-structure", frame_str, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"frame-structure\" node.\n"); + + // EXTENDED not supported + // 3GPP TS 38.211 + const char cp_type[] = "NORMAL"; + ret = lyd_new_term(*root, NULL, "cp-type", cp_type, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-type\" node.\n"); + + char cp_len[8]; + snprintf(cp_len, sizeof(cp_len), "%d", oai->split7.cp_prefix0); + ret = lyd_new_term(*root, NULL, "cp-length", cp_len, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length\" node.\n"); - - ret = lyd_new_term(*root, NULL, "cp-length-other", "0", 0, NULL); + + char cp_len_other[8]; + snprintf(cp_len_other, sizeof(cp_len_other), "%d", oai->split7.cp_prefix_other); + ret = lyd_new_term(*root, NULL, "cp-length-other", cp_len_other, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length-other\" node.\n"); - - // to we actually store this from DU config file? - ret = lyd_new_term(*root, NULL, "offset-to-absolute-frequency-center", "0", 0, NULL); + + char freq_offset[8]; + if (dir == UP_CH_RX) { + snprintf(freq_offset, sizeof(freq_offset), "%d", oai->split7.ul_k0[oai->nr_scs_for_raster]); + } else { + snprintf(freq_offset, sizeof(freq_offset), "%d", oai->split7.dl_k0[oai->nr_scs_for_raster]); + } + ret = lyd_new_term(*root, NULL, "offset-to-absolute-frequency-center", freq_offset, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"offset-to-absolute-frequency-center\" node.\n"); - + struct lyd_node *compression_node = NULL; ret = lyd_new_inner(*root, NULL, "compression", 0, &compression_node); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression\" node.\n"); @@ -126,15 +149,15 @@ static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx snprintf(iq_width_str, sizeof(iq_width_str), "%d", xran_mplane->iq_width); ret = lyd_new_term(compression_node, NULL, "iq-bitwidth", iq_width_str, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"iq-bitwidth\" node.\n"); - + if (xran_mplane->iq_width < 16) { ret = lyd_new_term(compression_node, NULL, "compression-type", "STATIC", 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-type\" node.\n"); - + // ret = lyd_new_term(compression_node, NULL, "compression-method", "BLOCK_FLOATING_POINT", 0, NULL); // VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-method\" node.\n"); } - + struct lyd_node *eaxc_conf = NULL; ret = lyd_new_inner(*root, NULL, "e-axcid", 0, &eaxc_conf); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"e-axcid\" node.\n"); @@ -143,12 +166,12 @@ static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx snprintf(eaxc_id, sizeof(eaxc_id), "%ld", idx); ret = lyd_new_term(eaxc_conf, NULL, "eaxc-id", eaxc_id, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"eaxc-id\" node.\n"); - + char du_port_bitmask[16]; snprintf(du_port_bitmask, sizeof(du_port_bitmask), "%d", xran_mplane->du_port_bitmask); ret = lyd_new_term(eaxc_conf, NULL, "o-du-port-bitmask", du_port_bitmask, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"o-du-port-bitmask\" node.\n"); - + char band_sector_bitmask[8]; snprintf(band_sector_bitmask, sizeof(band_sector_bitmask), "%d", xran_mplane->band_sector_bitmask); ret = lyd_new_term(eaxc_conf, NULL, "band-sector-bitmask", band_sector_bitmask, 0, NULL); @@ -164,15 +187,50 @@ static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx ret = lyd_new_term(eaxc_conf, NULL, "ru-port-bitmask", ru_port_bitmask, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-port-bitmask\" node.\n"); + return LY_SUCCESS; +} + +static bool fill_uplane_ch_rx_v2(const xran_mplane_t *xran_mplane, const openair0_config_t *oai, const size_t idx, struct lyd_node **root) +{ + LY_ERR ret = LY_SUCCESS; + + ret = fill_uplane_ch_common_v2(UP_CH_RX, xran_mplane, oai, idx, root); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create common nodes.\n"); + + const char *managed_delay = xran_mplane->managed_delay ? "true" : "false"; + ret = lyd_new_term(*root, NULL, "non-time-managed-delay-enabled", managed_delay, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"non-time-managed-delay-enabled\" node.\n"); + + struct lyd_node *fft_offset = NULL; + ret = lyd_new_list(*root, NULL, "ul-fft-sampling-offsets", 0, &fft_offset, scs_name[oai->nr_scs_for_raster]); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ul-fft-sampling-offsets\" node.\n"); + + // Note: set of allowed values is restricted by SCS derived from values in supported-frame-structures. + char ul_fft_offset[8]; + const int frame = (oai->split7.fftSize << 4) + oai->nr_scs_for_raster; + snprintf(ul_fft_offset, sizeof(ul_fft_offset), "%d", frame - xran_mplane->frame_str); + ret = lyd_new_term(fft_offset, NULL, "ul-fft-sampling-offset", ul_fft_offset, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ul-fft-sampling-offset\" node.\n"); + return true; } -static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, const char *u_proc_elem, struct lyd_node **root) +static bool fill_uplane_ch_tx_v2(const xran_mplane_t *xran_mplane, const openair0_config_t *oai, const size_t idx, struct lyd_node **root) +{ + LY_ERR ret = LY_SUCCESS; + + ret = fill_uplane_ch_common_v2(UP_CH_TX, xran_mplane, oai, idx, root); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create common nodes.\n"); + + return true; +} + +static bool create_uplane_conf_v2(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, const char *u_proc_elem, struct lyd_node **root) { LY_ERR ret = LY_SUCCESS; bool success = true; - ret = lyd_new_path(NULL, *ctx, "/o-ran-uplane-conf:user-plane-configuration", NULL, 0, root); + ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/o-ran-uplane-conf:user-plane-configuration", NULL, 0, root); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"user-plane-configuration\" node.\n"); if (ru_session->ru_mplane_config.rx_carriers.num != 1 || ru_session->ru_mplane_config.tx_carriers.num !=1) @@ -204,7 +262,8 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se ret = lyd_new_term(rx_carrier_node, NULL, "downlink-sfn-offset", "0", 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-sfn-offset\" node.\n"); - // oai->rx_gain_offset is this the correction? if yes, test it later + // gain offset applied uniformly across all array elements or layers + // needs to be within ret = lyd_new_term(rx_carrier_node, NULL, "gain-correction", "0", 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain-correction\" node.\n"); @@ -234,8 +293,12 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se ret = lyd_new_term(tx_carrier_node, NULL, "channel-bandwidth", tx_bw, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"channel-bandwidth\" node.\n"); - // oai->tx_gain to be tested - ret = lyd_new_term(tx_carrier_node, NULL, "gain", "0", 0, NULL); + // oai->tx_gain takes the value of att_tx from the RU section of gNB config file + // we assume the same gain is applied to all channels; same as above for the frequency + const double tx_gain_value = ((oai->tx_gain[0] * 10000) < ru_session->xran_mplane.max_tx_gain) ? (oai->tx_gain[0] * 10000) : ru_session->xran_mplane.max_tx_gain; + char tx_gain_str[8]; + snprintf(tx_gain_str, sizeof(tx_gain_str), "%.f", tx_gain_value); + ret = lyd_new_term(tx_carrier_node, NULL, "gain", tx_gain_str, 0, NULL); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain\" node.\n"); ret = lyd_new_term(tx_carrier_node, NULL, "downlink-radio-frame-offset", "0", 0, NULL); @@ -254,7 +317,7 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &pusch_node, ru_session->ru_mplane_config.rx_endpoints.name[i]); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n"); - success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pusch_node); + success = fill_uplane_ch_rx_v2(&ru_session->xran_mplane, oai, i, &pusch_node); VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[i]); const size_t prach_endpoint_name_offset = i + (ru_session->ru_mplane_config.rx_endpoints.num / 2); @@ -262,7 +325,7 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &prach_node, ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n"); - success = fill_uplane_ch_v2(&ru_session->xran_mplane, i + ru_session->xran_mplane.prach_offset, &prach_node); + success = fill_uplane_ch_rx_v2(&ru_session->xran_mplane, oai, i + ru_session->xran_mplane.prach_offset, &prach_node); VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]); } @@ -273,7 +336,7 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se ret = lyd_new_list(*root, NULL, "low-level-tx-endpoints", 0, &pdsch_node, ru_session->ru_mplane_config.tx_endpoints.name[i]); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-endpoints\" node.\n"); - success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pdsch_node); + success = fill_uplane_ch_tx_v2(&ru_session->xran_mplane, oai, i, &pdsch_node); VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-tx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.tx_endpoints.name[i]); } @@ -333,9 +396,59 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se return true; } + +static +bool create_pm_conf_v2(const ru_session_t *ru_session, const char *active, struct lyd_node **root) +{ + LY_ERR ret = LY_SUCCESS; + + ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/o-ran-performance-management:performance-measurement-objects", NULL, 0, root); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"performance-measurement-objects\" node.\n"); + + ret = lyd_new_term(*root, NULL, "notification-interval", "10", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"notification-interval\" node.\n"); + + ret = lyd_new_term(*root, NULL, "rx-window-measurement-interval", "10", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-window-measurement-interval\" node.\n"); + + ret = lyd_new_term(*root, NULL, "tx-measurement-interval", "10", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-measurement-interval\" node.\n"); + + for (size_t i = 0; i < ru_session->pm_stats.rx_num; i++) { + struct lyd_node *rx_window_meas_objects = NULL; + ret = lyd_new_list(*root, NULL, "rx-window-measurement-objects", 0, &rx_window_meas_objects, ru_session->pm_stats.rx_window_meas[i]); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-window-measurement-objects\" node.\n"); + + ret = lyd_new_term(rx_window_meas_objects, NULL, "active", active, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n"); + + ret = lyd_new_term(rx_window_meas_objects, NULL, "object-unit", "RU", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"object-unit\" node.\n"); + + ret = lyd_new_term(rx_window_meas_objects, NULL, "report-info", "COUNT", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"report-info\" node.\n"); + } + + for (size_t i = 0; i < ru_session->pm_stats.tx_num; i++) { + struct lyd_node *tx_meas_objects = NULL; + ret = lyd_new_list(*root, NULL, "tx-measurement-objects", 0, &tx_meas_objects, ru_session->pm_stats.tx_meas[i]); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-measurement-objects\" node.\n"); + + ret = lyd_new_term(tx_meas_objects, NULL, "active", active, 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n"); + + ret = lyd_new_term(tx_meas_objects, NULL, "object-unit", "RU", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"object-unit\" node.\n"); + + ret = lyd_new_term(tx_meas_objects, NULL, "report-info", "COUNT", 0, NULL); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"report-info\" node.\n"); + } + + return true; +} #endif -bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result) +bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result) { bool success = false; @@ -357,12 +470,12 @@ bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, struct lyd_node *cu_interface = NULL; char int_name[12]; snprintf(int_name, sizeof(int_name), "INTERFACE_%ld", i); - success = create_cu_interface_v2(ctx, ru_session, i, int_name, &cu_interface); + success = create_cu_interface_v2(ru_session, i, int_name, &cu_interface); VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane interface.\n"); // struct lyd_node *proc_elem = NULL; - success = create_proc_elem_v2(ctx, ru_session, i, int_name, &proc_elem); + success = create_proc_elem_v2(ru_session, i, int_name, &proc_elem); VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane processing element.\n"); ret = lyd_merge_siblings(&all_merge, cu_interface, 0); @@ -376,17 +489,49 @@ bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, // struct lyd_node *uplane_conf = NULL; - success = create_uplane_conf_v2(ctx, ru_session, oai, num_rus, "PLANE_0", &uplane_conf); + success = create_uplane_conf_v2(ru_session, oai, num_rus, "PLANE_0", &uplane_conf); VERIFY_SUCCESS(success, "[MPLANE] Cannot create U-plane configuration.\n"); - - ret = lyd_merge_siblings(&uplane_conf, all_merge, 0); + + ret = lyd_merge_siblings(&all_merge, uplane_conf, 0); VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element and U-plane configuration.\n"); - lyd_print_mem(result, uplane_conf, LYD_XML, LYD_PRINT_WITHSIBLINGS); + // + struct lyd_node *pm_conf = NULL; + if (ru_session->pm_stats.start_up_timing) { + success = create_pm_conf_v2(ru_session, "true", &pm_conf); + VERIFY_SUCCESS(success, "[MPLANE] Cannot create PM activation.\n"); + } else { + success = create_pm_conf_v2(ru_session, "false", &pm_conf); + VERIFY_SUCCESS(success, "[MPLANE] Cannot create PM deactivation.\n"); + } + + ret = lyd_merge_siblings(&all_merge, pm_conf, 0); + VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element, U-plane configuration and PM configuration.\n"); + + lyd_print_mem(result, all_merge, LYD_XML, LYD_PRINT_WITHSIBLINGS); lyd_free_siblings(all_merge); lyd_free_siblings(uplane_conf); + lyd_free_siblings(pm_conf); #endif return true; } + +char *get_pm_content(const ru_session_t *ru_session, const char *active) +{ + bool success = false; + char *content = NULL; + +#ifdef MPLANE_V1 + VERIFY_SUCCESS(success, "[MPLANE] To be implemented and tested.\n"); +#elif defined MPLANE_V2 + struct lyd_node *pm_conf = NULL; + success = create_pm_conf_v2(ru_session, active, &pm_conf); + AssertError(success, return false, "[MPLANE] Cannot create PM configuration.\n"); + lyd_print_mem(&content, pm_conf, LYD_XML, LYD_PRINT_WITHSIBLINGS); + lyd_free_siblings(pm_conf); +#endif + + return content; +} diff --git a/radio/fhi_72/mplane/yang/create-yang-config.h b/radio/fhi_72/mplane/yang/create-yang-config.h index 9e06bdc923..2f03a3f774 100644 --- a/radio/fhi_72/mplane/yang/create-yang-config.h +++ b/radio/fhi_72/mplane/yang/create-yang-config.h @@ -27,6 +27,8 @@ #include -bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result); +bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result); + +char *get_pm_content(const ru_session_t *ru_session, const char *active); #endif /* CREATE_MPLANE_YANG_CONFIG_H */ diff --git a/radio/fhi_72/mplane/yang/get-yang.c b/radio/fhi_72/mplane/yang/get-yang.c index c27454136f..60131b34cf 100644 --- a/radio/fhi_72/mplane/yang/get-yang.c +++ b/radio/fhi_72/mplane/yang/get-yang.c @@ -95,8 +95,10 @@ static bool load_from_operational_ds(xmlNode *node, ru_session_t *ru_session, st return false; } -bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx) +bool load_yang_models(ru_session_t *ru_session, const char *buffer) { + struct ly_ctx **ctx = (struct ly_ctx **)&ru_session->ctx; + // Initialize the xml file size_t len = strlen(buffer) + 1; xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0); @@ -114,7 +116,7 @@ bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ct 1) the yang models order is not good - the dependancy models have to be loaded first 2) earlier O-RAN yang versions (e.g. v4) is not properly defined (i.e. optional parameters should not be included by default) */ const char *yang_dir = YANG_MODELS; - const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf"}; + const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf", "ietf-netconf-acm", "ietf-crypto-types", "o-ran-file-management", "o-ran-performance-management"}; #ifdef MPLANE_V1 *ctx = ly_ctx_new(yang_dir, 0); diff --git a/radio/fhi_72/mplane/yang/get-yang.h b/radio/fhi_72/mplane/yang/get-yang.h index 5956bde203..7ca191d234 100644 --- a/radio/fhi_72/mplane/yang/get-yang.h +++ b/radio/fhi_72/mplane/yang/get-yang.h @@ -26,6 +26,6 @@ #include -bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx); +bool load_yang_models(ru_session_t *ru_session, const char *buffer); #endif /* GET_MPLANE_YANG_MODELS_H */ diff --git a/radio/fhi_72/mplane/yang/models/ietf-crypto-types.yang b/radio/fhi_72/mplane/yang/models/ietf-crypto-types.yang new file mode 100644 index 0000000000..1b94b03176 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/ietf-crypto-types.yang @@ -0,0 +1,1783 @@ +module ietf-crypto-types { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-crypto-types"; + prefix ct; + + import ietf-yang-types { + prefix yang; + reference + "RFC 6991: Common YANG Data Types"; + } + + import ietf-netconf-acm { + prefix nacm; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: + WG List: + Author: Kent Watsen + Author: Wang Haiguang "; + + description + "This module defines common YANG types for cryptographic + applications. + + Copyright (c) 2019 IETF Trust and the persons identified + as authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with + or without modification, is permitted pursuant to, and + subject to the license terms contained in, the Simplified + BSD License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC XXXX + (https://www.rfc-editor.org/info/rfcXXXX); see the RFC + itself for full legal notices.; + + The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', + 'SHALL NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', + 'NOT RECOMMENDED', 'MAY', and 'OPTIONAL' in this document + are to be interpreted as described in BCP 14 (RFC 2119) + (RFC 8174) when, and only when, they appear in all + capitals, as shown here."; + + revision 2019-04-29 { + description + "Initial version"; + reference + "RFC XXXX: Common YANG Data Types for Cryptography"; + } + + /**************************************/ + /* Identities for Hash Algorithms */ + /**************************************/ + + identity hash-algorithm { + description + "A base identity for hash algorithm verification."; + } + + identity sha-224 { + base hash-algorithm; + description + "The SHA-224 algorithm."; + reference + "RFC 6234: US Secure Hash Algorithms."; + } + identity sha-256 { + base hash-algorithm; + description + "The SHA-256 algorithm."; + reference + "RFC 6234: US Secure Hash Algorithms."; + } + + identity sha-384 { + base hash-algorithm; + description + "The SHA-384 algorithm."; + reference + "RFC 6234: US Secure Hash Algorithms."; + } + + identity sha-512 { + base hash-algorithm; + description + "The SHA-512 algorithm."; + reference + "RFC 6234: US Secure Hash Algorithms."; + } + + /***********************************************/ + /* Identities for Asymmetric Key Algorithms */ + /***********************************************/ + + identity asymmetric-key-algorithm { + description + "Base identity from which all asymmetric key + encryption Algorithm."; + } + + identity rsa1024 { + base asymmetric-key-algorithm; + description + "The RSA algorithm using a 1024-bit key."; + reference + "RFC 8017: + PKCS #1: RSA Cryptography Specifications Version 2.2."; + } + + identity rsa2048 { + base asymmetric-key-algorithm; + description + "The RSA algorithm using a 2048-bit key."; + reference + "RFC 8017: + PKCS #1: RSA Cryptography Specifications Version 2.2."; + } + + identity rsa3072 { + base asymmetric-key-algorithm; + description + "The RSA algorithm using a 3072-bit key."; + reference + "RFC 8017: + PKCS #1: RSA Cryptography Specifications Version 2.2."; + } + + identity rsa4096 { + base asymmetric-key-algorithm; + description + "The RSA algorithm using a 4096-bit key."; + reference + "RFC 8017: + PKCS #1: RSA Cryptography Specifications Version 2.2."; + } + + identity rsa7680 { + base asymmetric-key-algorithm; + description + "The RSA algorithm using a 7680-bit key."; + reference + "RFC 8017: + PKCS #1: RSA Cryptography Specifications Version 2.2."; + } + + identity rsa15360 { + base asymmetric-key-algorithm; + description + "The RSA algorithm using a 15360-bit key."; + reference + "RFC 8017: + PKCS #1: RSA Cryptography Specifications Version 2.2."; + } + + identity secp192r1 { + base asymmetric-key-algorithm; + description + "The ECDSA algorithm using a NIST P256 Curve."; + reference + "RFC 6090: + Fundamental Elliptic Curve Cryptography Algorithms."; + } + identity secp224r1 { + base asymmetric-key-algorithm; + description + "The ECDSA algorithm using a NIST P256 Curve."; + reference + "RFC 6090: + Fundamental Elliptic Curve Cryptography Algorithms."; + } + + identity secp256r1 { + base asymmetric-key-algorithm; + description + "The ECDSA algorithm using a NIST P256 Curve."; + reference + "RFC 6090: + Fundamental Elliptic Curve Cryptography Algorithms."; + } + + identity secp384r1 { + base asymmetric-key-algorithm; + description + "The ECDSA algorithm using a NIST P256 Curve."; + reference + "RFC 6090: + Fundamental Elliptic Curve Cryptography Algorithms."; + } + + identity secp521r1 { + base asymmetric-key-algorithm; + description + "The ECDSA algorithm using a NIST P256 Curve."; + reference + "RFC 6090: + Fundamental Elliptic Curve Cryptography Algorithms."; + } + + /*************************************/ + /* Identities for MAC Algorithms */ + /*************************************/ + + identity mac-algorithm { + description + "A base identity for mac generation."; + } + + identity hmac-sha1 { + base mac-algorithm; + description + "Generating MAC using SHA1 hash function"; + reference + "RFC 3174: US Secure Hash Algorithm 1 (SHA1)"; + } + + identity hmac-sha1-96 { + base mac-algorithm; + description + "Generating MAC using SHA1 hash function"; + reference + "RFC 2404: The Use of HMAC-SHA-1-96 within ESP and AH"; + } + + identity hmac-sha2-224 { + base mac-algorithm; + description + "Generating MAC using SHA2 hash function"; + reference + "RFC 6234: + US Secure Hash Algorithms (SHA and SHA-based HMAC and + HKDF)"; + } + + identity hmac-sha2-256 { + base mac-algorithm; + description + "Generating MAC using SHA2 hash function"; + reference + "RFC 6234: + US Secure Hash Algorithms (SHA and SHA-based HMAC and + HKDF)"; + } + + identity hmac-sha2-256-128 { + base mac-algorithm; + description + "Generating a 256 bits MAC using SHA2 hash function and + truncate it to 128 bits"; + reference + "RFC 4868: + Using HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 + with IPsec"; + } + + identity hmac-sha2-384 { + base mac-algorithm; + description + "Generating MAC using SHA2 hash function"; + reference + "RFC 6234: + US Secure Hash Algorithms (SHA and SHA-based HMAC and + HKDF)"; + } + + identity hmac-sha2-384-192 { + base mac-algorithm; + description + "Generating a 384 bits MAC using SHA2 hash function and + truncate it to 192 bits"; + reference + "RFC 4868: + Using HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 with + IPsec"; + } + + identity hmac-sha2-512 { + base mac-algorithm; + description + "Generating MAC using SHA2 hash function"; + reference + "RFC 6234: + US Secure Hash Algorithms (SHA and SHA-based HMAC and + HKDF)"; + } + + identity hmac-sha2-512-256 { + base mac-algorithm; + description + "Generating a 512 bits MAC using SHA2 hash function and + truncating it to 256 bits"; + reference + "RFC 4868: + Using HMAC-SHA-256, HMAC-SHA-384, and HMAC-SHA-512 with + IPsec"; + } + + identity aes-128-gmac { + base mac-algorithm; + description + "Generating MAC using the Advanced Encryption Standard (AES) + Galois Message Authentication Code (GMAC) as a mechanism to + provide data origin authentication"; + reference + "RFC 4543: + The Use of Galois Message Authentication Code (GMAC) in + IPsec ESP and AH"; + } + + identity aes-192-gmac { + base mac-algorithm; + description + "Generating MAC using the Advanced Encryption Standard (AES) + Galois Message Authentication Code (GMAC) as a mechanism to + provide data origin authentication"; + reference + "RFC 4543: + The Use of Galois Message Authentication Code (GMAC) in + IPsec ESP and AH"; + } + + identity aes-256-gmac { + base mac-algorithm; + description + "Generating MAC using the Advanced Encryption Standard (AES) + Galois Message Authentication Code (GMAC) as a mechanism to + provide data origin authentication"; + reference + "RFC 4543: + The Use of Galois Message Authentication Code (GMAC) in + IPsec ESP and AH"; + } + + identity aes-cmac-96 { + base mac-algorithm; + description + "Generating MAC using Advanced Encryption Standard (AES) + Cipher-based Message Authentication Code (CMAC)"; + reference + "RFC 4494: The AES-CMAC-96 Algorithm and its Use with IPsec"; + } + + identity aes-cmac-128 { + base mac-algorithm; + description + "Generating MAC using Advanced Encryption Standard (AES) + Cipher-based Message Authentication Code (CMAC)"; + reference + "RFC 4493: The AES-CMAC Algorithm"; + } + + /********************************************/ + /* Identities for Encryption Algorithms */ + /********************************************/ + + identity encryption-algorithm { + description + "A base identity for encryption algorithm."; + } + + identity aes-128-cbc { + base encryption-algorithm; + description + "Encrypt message with AES algorithm in CBC mode with a key + length of 128 bits"; + reference + "RFC 3565: + Use of the Advanced Encryption Standard (AES) Encryption + Algorithm in Cryptographic Message Syntax (CMS)"; + } + + identity aes-192-cbc { + base encryption-algorithm; + description + "Encrypt message with AES algorithm in CBC mode with a key + length of 192 bits"; + reference + "RFC 3565: + Use of the Advanced Encryption Standard (AES) Encryption + Algorithm in Cryptographic Message Syntax (CMS)"; + } + + identity aes-256-cbc { + base encryption-algorithm; + description + "Encrypt message with AES algorithm in CBC mode with a key + length of 256 bits"; + reference + "RFC 3565: + Use of the Advanced Encryption Standard (AES) Encryption + Algorithm in Cryptographic Message Syntax (CMS)"; + } + + identity aes-128-ctr { + base encryption-algorithm; + description + "Encrypt message with AES algorithm in CTR mode with a key + length of 128 bits"; + reference + "RFC 3686: + Using Advanced Encryption Standard (AES) Counter Mode with + IPsec Encapsulating Security Payload (ESP)"; + } + identity aes-192-ctr { + base encryption-algorithm; + description + "Encrypt message with AES algorithm in CTR mode with a key + length of 192 bits"; + reference + "RFC 3686: + Using Advanced Encryption Standard (AES) Counter Mode with + IPsec Encapsulating Security Payload (ESP)"; + } + + identity aes-256-ctr { + base encryption-algorithm; + description + "Encrypt message with AES algorithm in CTR mode with a key + length of 256 bits"; + reference + "RFC 3686: + Using Advanced Encryption Standard (AES) Counter Mode with + IPsec Encapsulating Security Payload (ESP)"; + } + + /****************************************************/ + /* Identities for Encryption and MAC Algorithms */ + /****************************************************/ + + identity encryption-and-mac-algorithm { + description + "A base identity for encryption and MAC algorithm."; + } + + identity aes-128-ccm { + base encryption-and-mac-algorithm; + description + "Encrypt message with AES algorithm in CCM mode with a key + length of 128 bits; it can also be used for generating MAC"; + reference + "RFC 4309: + Using Advanced Encryption Standard (AES) CCM Mode with + IPsec Encapsulating Security Payload (ESP)"; + } + + identity aes-192-ccm { + base encryption-and-mac-algorithm; + description + "Encrypt message with AES algorithm in CCM mode with a key + length of 192 bits; it can also be used for generating MAC"; + reference + "RFC 4309: + Using Advanced Encryption Standard (AES) CCM Mode with + IPsec Encapsulating Security Payload (ESP)"; + } + + identity aes-256-ccm { + base encryption-and-mac-algorithm; + description + "Encrypt message with AES algorithm in CCM mode with a key + length of 256 bits; it can also be used for generating MAC"; + reference + "RFC 4309: + Using Advanced Encryption Standard (AES) CCM Mode with + IPsec Encapsulating Security Payload (ESP)"; + } + + identity aes-128-gcm { + base encryption-and-mac-algorithm; + description + "Encrypt message with AES algorithm in GCM mode with a key + length of 128 bits; it can also be used for generating MAC"; + reference + "RFC 4106: + The Use of Galois/Counter Mode (GCM) in IPsec Encapsulating + Security Payload (ESP)"; + } + + identity aes-192-gcm { + base encryption-and-mac-algorithm; + description + "Encrypt message with AES algorithm in GCM mode with a key + length of 192 bits; it can also be used for generating MAC"; + reference + "RFC 4106: + The Use of Galois/Counter Mode (GCM) in IPsec Encapsulating + Security Payload (ESP)"; + } + + identity mac-aes-256-gcm { + base encryption-and-mac-algorithm; + description + "Encrypt message with AES algorithm in GCM mode with a key + length of 128 bits; it can also be used for generating MAC"; + reference + "RFC 4106: + The Use of Galois/Counter Mode (GCM) in IPsec Encapsulating + Security Payload (ESP)"; + } + identity chacha20-poly1305 { + base encryption-and-mac-algorithm; + description + "Encrypt message with chacha20 algorithm and generate MAC with + POLY1305; it can also be used for generating MAC"; + reference + "RFC 8439: ChaCha20 and Poly1305 for IETF Protocols"; + } + + /******************************************/ + /* Identities for signature algorithm */ + /******************************************/ + + identity signature-algorithm { + description + "A base identity for asymmetric key encryption algorithm."; + } + + identity dsa-sha1 { + base signature-algorithm; + description + "The signature algorithm using DSA algorithm with SHA1 hash + algorithm"; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity rsassa-pkcs1-sha1 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PKCS1-v1_5 with the SHA1 + hash algorithm."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity rsassa-pkcs1-sha256 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PKCS1-v1_5 with the + SHA256 hash algorithm."; + reference + "RFC 8332: + Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell + (SSH) Protocol + RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + identity rsassa-pkcs1-sha384 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PKCS1-v1_5 with the + SHA384 hash algorithm."; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity rsassa-pkcs1-sha512 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PKCS1-v1_5 with the + SHA512 hash algorithm."; + reference + "RFC 8332: + Use of RSA Keys with SHA-256 and SHA-512 in the Secure Shell + (SSH) Protocol + RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity rsassa-pss-rsae-sha256 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PSS with mask generation + function 1 and SHA256 hash algorithm. If the public key is + carried in an X.509 certificate, it MUST use the rsaEncryption + OID"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity rsassa-pss-rsae-sha384 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PSS with mask generation + function 1 and SHA384 hash algorithm. If the public key is + carried in an X.509 certificate, it MUST use the rsaEncryption + OID"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity rsassa-pss-rsae-sha512 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PSS with mask generation + function 1 and SHA512 hash algorithm. If the public key is + carried in an X.509 certificate, it MUST use the rsaEncryption + OID"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity rsassa-pss-pss-sha256 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PSS with mask generation + function 1 and SHA256 hash algorithm. If the public key is + carried in an X.509 certificate, it MUST use the RSASSA-PSS + OID"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity rsassa-pss-pss-sha384 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PSS with mask generation + function 1 and SHA256 hash algorithm. If the public key is + carried in an X.509 certificate, it MUST use the RSASSA-PSS + OID"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity rsassa-pss-pss-sha512 { + base signature-algorithm; + description + "The signature algorithm using RSASSA-PSS with mask generation + function 1 and SHA256 hash algorithm. If the public key is + carried in an X.509 certificate, it MUST use the RSASSA-PSS + OID"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity ecdsa-secp256r1-sha256 { + base signature-algorithm; + description + "The signature algorithm using ECDSA with curve name secp256r1 + and SHA256 hash algorithm."; + reference + "RFC 5656: Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer + RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity ecdsa-secp384r1-sha384 { + base signature-algorithm; + description + "The signature algorithm using ECDSA with curve name secp384r1 + and SHA384 hash algorithm."; + reference + "RFC 5656: Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer + RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity ecdsa-secp521r1-sha512 { + base signature-algorithm; + description + "The signature algorithm using ECDSA with curve name secp521r1 + and SHA512 hash algorithm."; + reference + "RFC 5656: Elliptic Curve Algorithm Integration in the + Secure Shell Transport Layer + RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity ed25519 { + base signature-algorithm; + description + "The signature algorithm using EdDSA as defined in RFC 8032 or + its successors."; + reference + "RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)"; + } + + identity ed448 { + base signature-algorithm; + description + "The signature algorithm using EdDSA as defined in RFC 8032 or + its successors."; + reference + "RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)"; + } + + identity eccsi { + base signature-algorithm; + description + "The signature algorithm using ECCSI signature as defined in + RFC 6507."; + reference + "RFC 6507: + Elliptic Curve-Based Certificateless Signatures for + Identity-based Encryption (ECCSI)"; + } + + /**********************************************/ + /* Identities for key exchange algorithms */ + /**********************************************/ + + identity key-exchange-algorithm { + description + "A base identity for Diffie-Hellman based key exchange + algorithm."; + } + + identity psk-only { + base key-exchange-algorithm; + description + "Using Pre-shared key for authentication and key exchange"; + reference + "RFC 4279: + Pre-Shared Key cipher suites for Transport Layer Security + (TLS)"; + } + + identity dhe-ffdhe2048 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with 2048 bit + finite field"; + reference + "RFC 7919: + Negotiated Finite Field Diffie-Hellman Ephemeral Parameters + for Transport Layer Security (TLS)"; + } + + identity dhe-ffdhe3072 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with 3072 bit finite + field"; + reference + "RFC 7919: + Negotiated Finite Field Diffie-Hellman Ephemeral Parameters + for Transport Layer Security (TLS)"; + } + + identity dhe-ffdhe4096 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with 4096 bit + finite field"; + reference + "RFC 7919: + Negotiated Finite Field Diffie-Hellman Ephemeral Parameters + for Transport Layer Security (TLS)"; + } + + identity dhe-ffdhe6144 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with 6144 bit + finite field"; + reference + "RFC 7919: + Negotiated Finite Field Diffie-Hellman Ephemeral Parameters + for Transport Layer Security (TLS)"; + } + + identity dhe-ffdhe8192 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with 8192 bit + finite field"; + reference + "RFC 7919: + Negotiated Finite Field Diffie-Hellman Ephemeral Parameters + for Transport Layer Security (TLS)"; + } + + identity psk-dhe-ffdhe2048 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with Diffie-Hellman key + generation mechanism, where the DH group is FFDHE2048"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity psk-dhe-ffdhe3072 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with Diffie-Hellman key + generation mechanism, where the DH group is FFDHE3072"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity psk-dhe-ffdhe4096 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with Diffie-Hellman key + generation mechanism, where the DH group is FFDHE4096"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity psk-dhe-ffdhe6144 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with Diffie-Hellman key + generation mechanism, where the DH group is FFDHE6144"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity psk-dhe-ffdhe8192 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with Diffie-Hellman key + generation mechanism, where the DH group is FFDHE8192"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity ecdhe-secp256r1 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with elliptic group + over curve secp256r1"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity ecdhe-secp384r1 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with elliptic group + over curve secp384r1"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity ecdhe-secp521r1 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with elliptic group + over curve secp521r1"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity ecdhe-x25519 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with elliptic group + over curve x25519"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity ecdhe-x448 { + base key-exchange-algorithm; + description + "Ephemeral Diffie Hellman key exchange with elliptic group + over curve x448"; + reference + "RFC 8422: + Elliptic Curve Cryptography (ECC) Cipher Suites for + Transport Layer Security (TLS) Versions 1.2 and Earlier"; + } + + identity psk-ecdhe-secp256r1 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with elliptic group-based + Ephemeral Diffie Hellman key exchange over curve secp256r1"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity psk-ecdhe-secp384r1 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with elliptic group-based + Ephemeral Diffie Hellman key exchange over curve secp384r1"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity psk-ecdhe-secp521r1 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with elliptic group-based + Ephemeral Diffie Hellman key exchange over curve secp521r1"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity psk-ecdhe-x25519 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with elliptic group-based + Ephemeral Diffie Hellman key exchange over curve x25519"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity psk-ecdhe-x448 { + base key-exchange-algorithm; + description + "Key exchange using pre-shared key with elliptic group-based + Ephemeral Diffie Hellman key exchange over curve x448"; + reference + "RFC 8446: + The Transport Layer Security (TLS) Protocol Version 1.3"; + } + + identity diffie-hellman-group14-sha1 { + base key-exchange-algorithm; + description + "Using DH group14 and SHA1 for key exchange"; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer Protocol"; + } + + identity diffie-hellman-group14-sha256 { + base key-exchange-algorithm; + description + "Using DH group14 and SHA256 for key exchange"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity diffie-hellman-group15-sha512 { + base key-exchange-algorithm; + description + "Using DH group15 and SHA512 for key exchange"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity diffie-hellman-group16-sha512 { + base key-exchange-algorithm; + description + "Using DH group16 and SHA512 for key exchange"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity diffie-hellman-group17-sha512 { + base key-exchange-algorithm; + description + "Using DH group17 and SHA512 for key exchange"; + + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity diffie-hellman-group18-sha512 { + base key-exchange-algorithm; + description + "Using DH group18 and SHA512 for key exchange"; + reference + "RFC 8268: + More Modular Exponentiation (MODP) Diffie-Hellman (DH) + Key Exchange (KEX) Groups for Secure Shell (SSH)"; + } + + identity ecdh-sha2-secp256r1 { + base key-exchange-algorithm; + description + "Elliptic curve-based Diffie Hellman key exchange over curve + secp256r1 and using SHA2 for MAC generation"; + reference + "RFC 6239: Suite B Cryptographic Suites for Secure Shell + (SSH)"; + } + + identity ecdh-sha2-secp384r1 { + base key-exchange-algorithm; + description + "Elliptic curve-based Diffie Hellman key exchange over curve + secp384r1 and using SHA2 for MAC generation"; + reference + "RFC 6239: Suite B Cryptographic Suites for Secure Shell + (SSH)"; + } + + identity rsaes-oaep { + base key-exchange-algorithm; + description + "RSAES-OAEP combines the RSAEP and RSADP primitives with the + EME-OAEP encoding method"; + reference + "RFC 8017: + PKCS #1: RSA Cryptography Specifications Version 2.2."; + } + + identity rsaes-pkcs1-v1_5 { + base key-exchange-algorithm; + description + " RSAES-PKCS1-v1_5 combines the RSAEP and RSADP primitives + with the EME-PKCS1-v1_5 encoding method"; + reference + "RFC 8017: + PKCS #1: RSA Cryptography Specifications Version 2.2."; + } + + /**********************************************************/ + /* Typedefs for identityrefs to above base identities */ + /**********************************************************/ + + typedef hash-algorithm-ref { + type identityref { + base hash-algorithm; + } + description + "This typedef enables importing modules to easily define an + identityref to the 'hash-algorithm' base identity."; + } + + typedef signature-algorithm-ref { + type identityref { + base signature-algorithm; + } + description + "This typedef enables importing modules to easily define an + identityref to the 'signature-algorithm' base identity."; + } + + typedef mac-algorithm-ref { + type identityref { + base mac-algorithm; + } + description + "This typedef enables importing modules to easily define an + identityref to the 'mac-algorithm' base identity."; + } + + typedef encryption-algorithm-ref { + type identityref { + base encryption-algorithm; + } + description + "This typedef enables importing modules to easily define an + identityref to the 'encryption-algorithm' + base identity."; + } + + typedef encryption-and-mac-algorithm-ref { + type identityref { + base encryption-and-mac-algorithm; + } + description + "This typedef enables importing modules to easily define an + identityref to the 'encryption-and-mac-algorithm' + base identity."; + } + + typedef asymmetric-key-algorithm-ref { + type identityref { + base asymmetric-key-algorithm; + } + description + "This typedef enables importing modules to easily define an + identityref to the 'asymmetric-key-algorithm' + base identity."; + } + + typedef key-exchange-algorithm-ref { + type identityref { + base key-exchange-algorithm; + } + description + "This typedef enables importing modules to easily define an + identityref to the 'key-exchange-algorithm' base identity."; + } + + /***************************************************/ + /* Typedefs for ASN.1 structures from RFC 5280 */ + /***************************************************/ + + typedef x509 { + type binary; + description + "A Certificate structure, as specified in RFC 5280, + encoded using ASN.1 distinguished encoding rules (DER), + as specified in ITU-T X.690."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + typedef crl { + type binary; + description + "A CertificateList structure, as specified in RFC 5280, + encoded using ASN.1 distinguished encoding rules (DER), + as specified in ITU-T X.690."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + /***********************************************/ + /* Typedefs for ASN.1 structures from 5652 */ + /***********************************************/ + + typedef cms { + type binary; + description + "A ContentInfo structure, as specified in RFC 5652, + encoded using ASN.1 distinguished encoding rules (DER), + as specified in ITU-T X.690."; + reference + "RFC 5652: + Cryptographic Message Syntax (CMS) + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + + typedef data-content-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + data content type, as described by Section 4 in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef signed-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + signed-data content type, as described by Section 5 in + RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef enveloped-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + enveloped-data content type, as described by Section 6 + in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef digested-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + digested-data content type, as described by Section 7 + in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef encrypted-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + encrypted-data content type, as described by Section 8 + in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + typedef authenticated-data-cms { + type cms; + description + "A CMS structure whose top-most content type MUST be the + authenticated-data content type, as described by Section 9 + in RFC 5652."; + reference + "RFC 5652: Cryptographic Message Syntax (CMS)"; + } + + /***************************************************/ + /* Typedefs for structures related to RFC 4253 */ + /***************************************************/ + + typedef ssh-host-key { + type binary; + description + "The binary public key data for this SSH key, as + specified by RFC 4253, Section 6.6, i.e.: + + string certificate or public key format + identifier + byte[n] key/certificate data."; + reference + "RFC 4253: The Secure Shell (SSH) Transport Layer + Protocol"; + } + + /*********************************************************/ + /* Typedefs for ASN.1 structures related to RFC 5280 */ + /*********************************************************/ + + typedef trust-anchor-cert-x509 { + type x509; + description + "A Certificate structure that MUST encode a self-signed + root certificate."; + } + + typedef end-entity-cert-x509 { + type x509; + description + "A Certificate structure that MUST encode a certificate + that is neither self-signed nor having Basic constraint + CA true."; + } + + /*********************************************************/ + /* Typedefs for ASN.1 structures related to RFC 5652 */ + /*********************************************************/ + + typedef trust-anchor-cert-cms { + type signed-data-cms; + description + "A CMS SignedData structure that MUST contain the chain of + X.509 certificates needed to authenticate the certificate + presented by a client or end-entity. + + The CMS MUST contain only a single chain of certificates. + The client or end-entity certificate MUST only authenticate + to last intermediate CA certificate listed in the chain. + + In all cases, the chain MUST include a self-signed root + certificate. In the case where the root certificate is + itself the issuer of the client or end-entity certificate, + only one certificate is present. + + This CMS structure MAY (as applicable where this type is + used) also contain suitably fresh (as defined by local + policy) revocation objects with which the device can + verify the revocation status of the certificates. + + This CMS encodes the degenerate form of the SignedData + structure that is commonly used to disseminate X.509 + certificates and revocation objects (RFC 5280)."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile."; + } + + typedef end-entity-cert-cms { + type signed-data-cms; + description + "A CMS SignedData structure that MUST contain the end + entity certificate itself, and MAY contain any number + of intermediate certificates leading up to a trust + anchor certificate. The trust anchor certificate + MAY be included as well. + + The CMS MUST contain a single end entity certificate. + The CMS MUST NOT contain any spurious certificates. + + This CMS structure MAY (as applicable where this type is + used) also contain suitably fresh (as defined by local + policy) revocation objects with which the device can + verify the revocation status of the certificates. + + This CMS encodes the degenerate form of the SignedData + structure that is commonly used to disseminate X.509 + certificates and revocation objects (RFC 5280)."; + reference + "RFC 5280: + Internet X.509 Public Key Infrastructure Certificate + and Certificate Revocation List (CRL) Profile."; + } + + /**********************************************/ + /* Groupings for keys and/or certificates */ + /**********************************************/ + + grouping public-key-grouping { + description + "A public key. + + The 'algorithm' and 'public-key' nodes are not + mandatory because they MAY be defined in . + Implementations SHOULD assert that these values are + either configured or that they exist in ."; + leaf algorithm { + nacm:default-deny-write; + type asymmetric-key-algorithm-ref; + must '../public-key'; + description + "Identifies the key's algorithm. More specifically, + this leaf specifies how the 'public-key' binary leaf + is encoded."; + reference + "RFC CCCC: Common YANG Data Types for Cryptography"; + } + leaf public-key { + nacm:default-deny-write; + type binary; + must '../algorithm'; + description + "A binary that contains the value of the public key. The + interpretation of the content is defined by the key + algorithm. For example, a DSA key is an integer, an RSA + key is represented as RSAPublicKey as defined in + RFC 8017, and an Elliptic Curve Cryptography (ECC) key + is represented using the 'publicKey' described in + RFC 5915."; + reference + "RFC 8017: Public-Key Cryptography Standards (PKCS) #1: + RSA Cryptography Specifications Version 2.2. + RFC 5915: Elliptic Curve Private Key Structure."; + } + } + + grouping asymmetric-key-pair-grouping { + description + "A private/public key pair. + The 'algorithm', 'public-key', and 'private-key' nodes are + not mandatory because they MAY be defined in . + Implementations SHOULD assert that these values are either + configured or that they exist in ."; + uses public-key-grouping; + leaf private-key { + nacm:default-deny-all; + type union { + type binary; + type enumeration { + enum permanently-hidden { + description + "The private key is inaccessible due to being + protected by the system (e.g., a cryptographic + hardware module). + + How such keys are backed-up and restored, if + at all, is implementation specific. + + Servers MUST fail any attempt by a client to + configure this value directly. This value is + not set by clients, but rather is set by the + 'generate-hidden-key' and 'install-hidden-key' + actions."; + } + } + } + must '../public-key'; + description + "A binary that contains the value of the private key. The + interpretation of the content is defined by the key + algorithm. For example, a DSA key is an integer, an RSA + key is represented as RSAPrivateKey as defined in + RFC 8017, and an Elliptic Curve Cryptography (ECC) key + is represented as ECPrivateKey as defined in RFC 5915."; + reference + "RFC 8017: Public-Key Cryptography Standards (PKCS) #1: + RSA Cryptography Specifications Version 2.2. + RFC 5915: Elliptic Curve Private Key Structure."; + } // private-key + + action generate-hidden-key { + nacm:default-deny-all; + description + "Requests the device to generate a hidden key using the + specified asymmetric key algorithm. This action is + used to request the system to generate a key that is + 'permanently-hidden', perhaps protected by a cryptographic + hardware module. The resulting asymmetric key values are + considered operational state and hence present only in + and bound to the lifetime of the parent + 'config true' node. Subsequent invocations of this or + the 'install-hidden-key' action are denied with error-tag + 'data-exists'."; + input { + leaf algorithm { + type asymmetric-key-algorithm-ref; + mandatory true; + description + "The algorithm to be used when generating the + asymmetric key."; + reference + "RFC CCCC: Common YANG Data Types for Cryptography"; + } + } + } // generate-hidden-key + + action install-hidden-key { + nacm:default-deny-all; + description + "Requests the device to load the specified values into + a hidden key. The resulting asymmetric key values are + considered operational state and hence present only in + and bound to the lifetime of the parent + 'config true' node. Subsequent invocations of this + or the 'generate-hidden-key' action are denied with + error-tag 'data-exists'."; + input { + leaf algorithm { + type asymmetric-key-algorithm-ref; + mandatory true; + description + "The algorithm to be used when generating the + asymmetric key."; + reference + "RFC CCCC: Common YANG Data Types for Cryptography"; + } + leaf public-key { + type binary; + description + "A binary that contains the value of the public key. + The interpretation of the content is defined by the key + algorithm. For example, a DSA key is an integer, an + RSA key is represented as RSAPublicKey as defined in + RFC 8017, and an Elliptic Curve Cryptography (ECC) key + is represented using the 'publicKey' described in + RFC 5915."; + reference + "RFC 8017: Public-Key Cryptography Standards (PKCS) #1: + RSA Cryptography Specifications Version 2.2. + RFC 5915: Elliptic Curve Private Key Structure."; + } + leaf private-key { + type binary; + description + "A binary that contains the value of the private key. + The interpretation of the content is defined by the key + algorithm. For example, a DSA key is an integer, an RSA + key is represented as RSAPrivateKey as defined in + RFC 8017, and an Elliptic Curve Cryptography (ECC) key + is represented as ECPrivateKey as defined in RFC 5915."; + reference + "RFC 8017: Public-Key Cryptography Standards (PKCS) #1: + RSA Cryptography Specifications Version 2.2. + RFC 5915: Elliptic Curve Private Key Structure."; + } + } + } // install-hidden-key + } // asymmetric-key-pair-grouping + + + grouping trust-anchor-cert-grouping { + description + "A trust anchor certificate, and a notification for when + it is about to (or already has) expire."; + leaf cert { + nacm:default-deny-write; + type trust-anchor-cert-cms; + description + "The binary certificate data for this certificate."; + reference + "RFC YYYY: Common YANG Data Types for Cryptography"; + } + notification certificate-expiration { + description + "A notification indicating that the configured certificate + is either about to expire or has already expired. When to + send notifications is an implementation specific decision, + but it is RECOMMENDED that a notification be sent once a + month for 3 months, then once a week for four weeks, and + then once a day thereafter until the issue is resolved."; + leaf expiration-date { + type yang:date-and-time; + mandatory true; + description + "Identifies the expiration date on the certificate."; + } + } + } + + grouping trust-anchor-certs-grouping { + description + "A list of trust anchor certificates, and a notification + for when one is about to (or already has) expire."; + leaf-list cert { + nacm:default-deny-write; + type trust-anchor-cert-cms; + description + "The binary certificate data for this certificate."; + reference + "RFC YYYY: Common YANG Data Types for Cryptography"; + } + notification certificate-expiration { + description + "A notification indicating that the configured certificate + is either about to expire or has already expired. When to + send notifications is an implementation specific decision, + but it is RECOMMENDED that a notification be sent once a + month for 3 months, then once a week for four weeks, and + then once a day thereafter until the issue is resolved."; + leaf expiration-date { + type yang:date-and-time; + mandatory true; + description + "Identifies the expiration date on the certificate."; + } + } + } + + grouping end-entity-cert-grouping { + description + "An end entity certificate, and a notification for when + it is about to (or already has) expire."; + leaf cert { + nacm:default-deny-write; + type end-entity-cert-cms; + description + "The binary certificate data for this certificate."; + reference + "RFC YYYY: Common YANG Data Types for Cryptography"; + } + notification certificate-expiration { + description + "A notification indicating that the configured certificate + is either about to expire or has already expired. When to + send notifications is an implementation specific decision, + but it is RECOMMENDED that a notification be sent once a + month for 3 months, then once a week for four weeks, and + then once a day thereafter until the issue is resolved."; + leaf expiration-date { + type yang:date-and-time; + mandatory true; + description + "Identifies the expiration date on the certificate."; + } + } + } + + grouping end-entity-certs-grouping { + description + "A list of end entity certificates, and a notification for + when one is about to (or already has) expire."; + leaf-list cert { + nacm:default-deny-write; + type end-entity-cert-cms; + description + "The binary certificate data for this certificate."; + reference + "RFC YYYY: Common YANG Data Types for Cryptography"; + } + notification certificate-expiration { + description + "A notification indicating that the configured certificate + is either about to expire or has already expired. When to + send notifications is an implementation specific decision, + but it is RECOMMENDED that a notification be sent once a + month for 3 months, then once a week for four weeks, and + then once a day thereafter until the issue is resolved."; + leaf expiration-date { + type yang:date-and-time; + mandatory true; + description + "Identifies the expiration date on the certificate."; + } + } + } + + grouping asymmetric-key-pair-with-cert-grouping { + description + "A private/public key pair and an associated certificate."; + uses asymmetric-key-pair-grouping; + uses end-entity-cert-grouping; + + action generate-certificate-signing-request { + nacm:default-deny-all; + description + "Generates a certificate signing request structure for + the associated asymmetric key using the passed subject + and attribute values. The specified assertions need + to be appropriate for the certificate's use. For + example, an entity certificate for a TLS server + SHOULD have values that enable clients to satisfy + RFC 6125 processing."; + input { + leaf subject { + type binary; + mandatory true; + description + "The 'subject' field per the CertificationRequestInfo + structure as specified by RFC 2986, Section 4.1 + encoded using the ASN.1 distinguished encoding + rules (DER), as specified in ITU-T X.690."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax + Specification Version 1.7. + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + leaf attributes { + type binary; + description + "The 'attributes' field from the structure + CertificationRequestInfo as specified by RFC 2986, + Section 4.1 encoded using the ASN.1 distinguished + encoding rules (DER), as specified in ITU-T X.690."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax + Specification Version 1.7. + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + } + output { + leaf certificate-signing-request { + type binary; + mandatory true; + description + "A CertificationRequest structure as specified by + RFC 2986, Section 4.2 encoded using the ASN.1 + distinguished encoding rules (DER), as specified + in ITU-T X.690."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax + Specification Version 1.7. + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + } + } // generate-certificate-signing-request + } // asymmetric-key-pair-with-cert-grouping + + + grouping asymmetric-key-pair-with-certs-grouping { + description + "A private/public key pair and associated certificates."; + uses asymmetric-key-pair-grouping; + container certificates { + nacm:default-deny-write; + description + "Certificates associated with this asymmetric key. + More than one certificate supports, for instance, + a TPM-protected asymmetric key that has both IDevID + and LDevID certificates associated."; + list certificate { + key "name"; + description + "A certificate for this asymmetric key."; + leaf name { + type string; + description + "An arbitrary name for the certificate. If the name + matches the name of a certificate that exists + independently in (i.e., an IDevID), + then the 'cert' node MUST NOT be configured."; + } + uses end-entity-cert-grouping; + } + } // certificates + + action generate-certificate-signing-request { + nacm:default-deny-all; + description + "Generates a certificate signing request structure for + the associated asymmetric key using the passed subject + and attribute values. The specified assertions need + to be appropriate for the certificate's use. For + example, an entity certificate for a TLS server + SHOULD have values that enable clients to satisfy + RFC 6125 processing."; + input { + leaf subject { + type binary; + mandatory true; + description + "The 'subject' field per the CertificationRequestInfo + structure as specified by RFC 2986, Section 4.1 + encoded using the ASN.1 distinguished encoding + rules (DER), as specified in ITU-T X.690."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax + Specification Version 1.7. + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + leaf attributes { + type binary; + description + "The 'attributes' field from the structure + CertificationRequestInfo as specified by RFC 2986, + Section 4.1 encoded using the ASN.1 distinguished + encoding rules (DER), as specified in ITU-T X.690."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax + Specification Version 1.7. + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + } + output { + leaf certificate-signing-request { + type binary; + mandatory true; + description + "A CertificationRequest structure as specified by + RFC 2986, Section 4.2 encoded using the ASN.1 + distinguished encoding rules (DER), as specified + in ITU-T X.690."; + reference + "RFC 2986: + PKCS #10: Certification Request Syntax + Specification Version 1.7. + ITU-T X.690: + Information technology - ASN.1 encoding rules: + Specification of Basic Encoding Rules (BER), + Canonical Encoding Rules (CER) and Distinguished + Encoding Rules (DER)."; + } + } + } // generate-certificate-signing-request + } // asymmetric-key-pair-with-certs-grouping +} diff --git a/radio/fhi_72/mplane/yang/models/ietf-netconf-acm.yang b/radio/fhi_72/mplane/yang/models/ietf-netconf-acm.yang new file mode 100644 index 0000000000..ec9687a9d7 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/ietf-netconf-acm.yang @@ -0,0 +1,440 @@ +module ietf-netconf-acm { + + namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm"; + + prefix nacm; + + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: + WG List: + Author: Andy Bierman + + Author: Martin Bjorklund + "; + + description + "Network Configuration Access Control Model. + Copyright (c) 2012 - 2018 IETF Trust and the persons + identified as authors of the code. All rights reserved. + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD + License set forth in Section 4.c of the IETF Trust's + Legal Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info). + This version of this YANG module is part of RFC 8341; see + the RFC itself for full legal notices."; + + revision "2018-02-14" { + description + "Added support for YANG 1.1 actions and notifications tied to + data nodes. Clarified how NACM extensions can be used by + other data models."; + reference + "RFC 8341: Network Configuration Access Control Model"; + } + + revision "2012-02-22" { + description + "Initial version."; + reference + "RFC 6536: Network Configuration Protocol (NETCONF) + Access Control Model"; + } + + /* + * Extension statements + */ + + extension default-deny-write { + description + "Used to indicate that the data model node + represents a sensitive security system parameter. + If present, the NETCONF server will only allow the designated + 'recovery session' to have write access to the node. An + explicit access control rule is required for all other users. + If the NACM module is used, then it must be enabled (i.e., + /nacm/enable-nacm object equals 'true'), or this extension + is ignored. + The 'default-deny-write' extension MAY appear within a data + definition statement. It is ignored otherwise."; + } + + extension default-deny-all { + description + "Used to indicate that the data model node + controls a very sensitive security system parameter. + If present, the NETCONF server will only allow the designated + 'recovery session' to have read, write, or execute access to + the node. An explicit access control rule is required for all + other users. + If the NACM module is used, then it must be enabled (i.e., + /nacm/enable-nacm object equals 'true'), or this extension + is ignored. + The 'default-deny-all' extension MAY appear within a data + definition statement, 'rpc' statement, or 'notification' + statement. It is ignored otherwise."; + } + + /* + * Derived types + */ + + typedef user-name-type { + type string { + length "1..max"; + } + description + "General-purpose username string."; + } + + typedef matchall-string-type { + type string { + pattern '\*'; + } + description + "The string containing a single asterisk '*' is used + to conceptually represent all possible values + for the particular leaf using this data type."; + } + + typedef access-operations-type { + type bits { + bit create { + description + "Any protocol operation that creates a + new data node."; + } + bit read { + description + "Any protocol operation or notification that + returns the value of a data node."; + } + bit update { + description + "Any protocol operation that alters an existing + data node."; + } + bit delete { + description + "Any protocol operation that removes a data node."; + } + bit exec { + description + "Execution access to the specified protocol operation."; + } + } + description + "Access operation."; + } + + typedef group-name-type { + type string { + length "1..max"; + pattern '[^\*].*'; + } + description + "Name of administrative group to which + users can be assigned."; + } + + typedef action-type { + type enumeration { + enum permit { + description + "Requested action is permitted."; + } + enum deny { + description + "Requested action is denied."; + } + } + description + "Action taken by the server when a particular + rule matches."; + } + + typedef node-instance-identifier { + type yang:xpath1.0; + description + "Path expression used to represent a special + data node, action, or notification instance-identifier + string. + A node-instance-identifier value is an + unrestricted YANG instance-identifier expression. + All the same rules as an instance-identifier apply, + except that predicates for keys are optional. If a key + predicate is missing, then the node-instance-identifier + represents all possible server instances for that key. + This XML Path Language (XPath) expression is evaluated in the + following context: + o The set of namespace declarations are those in scope on + the leaf element where this type is used. + o The set of variable bindings contains one variable, + 'USER', which contains the name of the user of the + current session. + o The function library is the core function library, but + note that due to the syntax restrictions of an + instance-identifier, no functions are allowed. + o The context node is the root node in the data tree. + The accessible tree includes actions and notifications tied + to data nodes."; + } + + /* + * Data definition statements + */ + + container nacm { + nacm:default-deny-all; + + description + "Parameters for NETCONF access control model."; + + leaf enable-nacm { + type boolean; + default "true"; + description + "Enables or disables all NETCONF access control + enforcement. If 'true', then enforcement + is enabled. If 'false', then enforcement + is disabled."; + } + + leaf read-default { + type action-type; + default "permit"; + description + "Controls whether read access is granted if + no appropriate rule is found for a + particular read request."; + } + + leaf write-default { + type action-type; + default "deny"; + description + "Controls whether create, update, or delete access + is granted if no appropriate rule is found for a + particular write request."; + } + + leaf exec-default { + type action-type; + default "permit"; + description + "Controls whether exec access is granted if no appropriate + rule is found for a particular protocol operation request."; + } + + leaf enable-external-groups { + type boolean; + default "true"; + description + "Controls whether the server uses the groups reported by the + NETCONF transport layer when it assigns the user to a set of + NACM groups. If this leaf has the value 'false', any group + names reported by the transport layer are ignored by the + server."; + } + + leaf denied-operations { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that a + protocol operation request was denied."; + } + + leaf denied-data-writes { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that a + protocol operation request to alter + a configuration datastore was denied."; + } + + leaf denied-notifications { + type yang:zero-based-counter32; + config false; + mandatory true; + description + "Number of times since the server last restarted that + a notification was dropped for a subscription because + access to the event type was denied."; + } + + container groups { + description + "NETCONF access control groups."; + + list group { + key name; + + description + "One NACM group entry. This list will only contain + configured entries, not any entries learned from + any transport protocols."; + + leaf name { + type group-name-type; + description + "Group name associated with this entry."; + } + + leaf-list user-name { + type user-name-type; + description + "Each entry identifies the username of + a member of the group associated with + this entry."; + } + } + } + + list rule-list { + key name; + ordered-by user; + description + "An ordered collection of access control rules."; + + leaf name { + type string { + length "1..max"; + } + description + "Arbitrary name assigned to the rule-list."; + } + leaf-list group { + type union { + type matchall-string-type; + type group-name-type; + } + description + "List of administrative groups that will be + assigned the associated access rights + defined by the 'rule' list. + The string '*' indicates that all groups apply to the + entry."; + } + + list rule { + key name; + ordered-by user; + description + "One access control rule. + Rules are processed in user-defined order until a match is + found. A rule matches if 'module-name', 'rule-type', and + 'access-operations' match the request. If a rule + matches, the 'action' leaf determines whether or not + access is granted."; + + leaf name { + type string { + length "1..max"; + } + description + "Arbitrary name assigned to the rule."; + } + + leaf module-name { + type union { + type matchall-string-type; + type string; + } + default "*"; + description + "Name of the module associated with this rule. + This leaf matches if it has the value '*' or if the + object being accessed is defined in the module with the + specified module name."; + } + choice rule-type { + description + "This choice matches if all leafs present in the rule + match the request. If no leafs are present, the + choice matches all requests."; + case protocol-operation { + leaf rpc-name { + type union { + type matchall-string-type; + type string; + } + description + "This leaf matches if it has the value '*' or if + its value equals the requested protocol operation + name."; + } + } + case notification { + leaf notification-name { + type union { + type matchall-string-type; + type string; + } + description + "This leaf matches if it has the value '*' or if its + value equals the requested notification name."; + } + } + + case data-node { + leaf path { + type node-instance-identifier; + mandatory true; + description + "Data node instance-identifier associated with the + data node, action, or notification controlled by + this rule. + Configuration data or state data + instance-identifiers start with a top-level + data node. A complete instance-identifier is + required for this type of path value. + The special value '/' refers to all possible + datastore contents."; + } + } + } + + leaf access-operations { + type union { + type matchall-string-type; + type access-operations-type; + } + default "*"; + description + "Access operations associated with this rule. + This leaf matches if it has the value '*' or if the + bit corresponding to the requested operation is set."; + } + + leaf action { + type action-type; + mandatory true; + description + "The access control action associated with the + rule. If a rule has been determined to match a + particular request, then this object is used + to determine whether to permit or deny the + request."; + } + + leaf comment { + type string; + description + "A textual description of the access rule."; + } + } + } + } +} diff --git a/radio/fhi_72/mplane/yang/models/o-ran-file-management.yang b/radio/fhi_72/mplane/yang/models/o-ran-file-management.yang new file mode 100644 index 0000000000..ee07645a44 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/o-ran-file-management.yang @@ -0,0 +1,213 @@ +module o-ran-file-management { + yang-version 1.1; + namespace "urn:o-ran:file-management:1.0"; + prefix "o-ran-file-mgmt"; + + import ietf-crypto-types { + prefix "ct"; + } + + + organization "O-RAN Alliance"; + + contact + "www.o-ran.org"; + + description + "This module defines the configuration and operations for handling upload. + + Copyright 2019 the O-RAN Alliance. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the above disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the above disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the Members of the O-RAN Alliance nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission."; + + revision "2019-07-03" { + description + "version 1.1.0 + + 1) backward compatible changes to correct sFTP Server Authentication . + 2) minor fixes according to lack of descriptions + 3) backward compatible changes to introduce groupings"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + revision "2019-02-04" { + description + "version 1.0.0 + + 1) imported model from xRAN + 2) changed namespace and reference from xran to o-ran"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + grouping file-path-grouping { + description "Complete logical path of the file to upload/download + (no wildcard is allowed) ex : /o-RAN/log/syslog.1"; + + leaf local-logical-file-path { + type string; + mandatory true; + description "Local logical file path"; + } + + leaf remote-file-path { + type string; + mandatory true; + description "URI specifying the remote-file-path on O-DU/NMS. + Format:sftp://@[:port]/path"; + } + } + + grouping output-status-grouping { + description "Status grouping"; + + leaf status { + type enumeration { + enum SUCCESS { + description "";} + enum FAILURE { + description "";} + } + description "Operation status"; + } + + leaf reject-reason { + when "../status = 'FAILURE'"; + type string; + description ""; + } + } + + grouping credential-information { + description "Type of authentication to use for SFTP upload or download."; + choice credentials { + case password { + container password { + presence true; + leaf password { + type string; + mandatory true; + description + "password needed for O-RU authentication."; + } + description + "password for O-RU authentication method in use"; + } + container server { + list keys { + key algorithm; + ordered-by user; + uses ct:public-key-grouping; + description + "List of allowed algorithms with its keys"; + } + description + "Key for sFTP server authentication"; + } + } + case certificate { + container certificate { + presence true; + description + "certificate authentication method in use"; + } + } + description ""; + } + } + + grouping retrieve-input { + description "Grouping for information retrieval RPC input"; + leaf logical-path { + type string; + mandatory true; + description "O-RAN unit of which the files are to be listed. + ex : O-RAN/log, o-RAN/PM, O-RAN/transceiver"; + } + leaf file-name-filter { + type string; + description "Filter which are to be applied on the result list of file names (* is allowed as wild-card)."; + } + } + + grouping retrieve-output { + description "Grouping for information retrieval RPC output"; + uses output-status-grouping; + leaf-list file-list { + when "../status = 'SUCCESS'"; + type string; + description "List of files in the unit with the filter applied."; + } + } + +// RPCs + + rpc file-upload { + description "File upload over SFTP from equipment to NETCONF client"; + input { + uses file-path-grouping; + uses credential-information; + } + output { + uses output-status-grouping; + } + } + + rpc retrieve-file-list { + description "List all the files in the logical O-RAN unit (* is allowed as wild-card)."; + input { + uses retrieve-input; + + } + output { + uses retrieve-output; + } + } + + notification file-upload-notification { + uses file-path-grouping; + uses output-status-grouping; + description ""; + } + + rpc file-download { + description + "Management plane triggered to generate the download file of O-RU."; + input { + uses file-path-grouping; + uses credential-information; + } + output { + uses output-status-grouping; + } + } + + notification file-download-event { + uses file-path-grouping; + uses output-status-grouping; + description ""; + } +} diff --git a/radio/fhi_72/mplane/yang/models/o-ran-performance-management.yang b/radio/fhi_72/mplane/yang/models/o-ran-performance-management.yang new file mode 100644 index 0000000000..fb8298f663 --- /dev/null +++ b/radio/fhi_72/mplane/yang/models/o-ran-performance-management.yang @@ -0,0 +1,1168 @@ +module o-ran-performance-management { + yang-version 1.1; + namespace "urn:o-ran:performance-management:1.0"; + prefix "o-ran-pm"; + + import ietf-yang-types { + prefix "yang-types"; + revision-date 2013-07-15; + } + + // import idetifier for O-RU + import ietf-hardware { + prefix "hw"; + } + + // import ietf-interface + import ietf-interfaces { + prefix "if"; + } + + // import ietf-inet-type + import ietf-inet-types { + prefix "inet"; + } + + // import port-number + import o-ran-interfaces { + prefix "o-ran-int"; + } + + // import ru-mac-address, o-du-mac-address and vlan-id + import o-ran-processing-element { + prefix "o-ran-elements"; + } + + import o-ran-file-management { + prefix "o-ran-fm"; + } + + import iana-hardware { + prefix ianahw; + } + + organization "O-RAN Alliance"; + + contact + "www.o-ran.org"; + + description + "This module defines the configuration for performance measurement for + transceiver and rx-window measurement objects. + + NOTE, whereas this YANG model may define support of schema nodes associated + with O-RU measurements as optional, the CU-Plane specification may further + specify whether, according to a particular version of the CU plane + specification, which specific measurements are mandatory to support + from an O-RU perspective. In such a situation, the definition of mandatory + performance counters in sub-section 7.1 of the CU-plane specification shall + take precedence. + + Copyright 2020 the O-RAN Alliance. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the above disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the above disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the Members of the O-RAN Alliance nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission."; + + revision "2020-04-17" { + description + "version 3.0.0 + + 1) updated top level model description concerning optionality of measurements + 2) added new rx window counters + 3) added new TX stats measurements + 4) added new EPE measurements + 5) fixed typo in enumeration - TX_POPWER + 6) introduced config false data indicating which type of measurmeents are supported"; + + reference "ORAN-WG4.M.0-v03.00"; + } + + revision "2019-07-03" { + description + "version 2.0.0 + + 1) added new measurement objects for QSFP + 2) backward compatible changes to correct sFTP Server Authentication. + 3) simplifying file management and authentication to reuse from o-ran-file-management module + 4) minor fixes according to lack of descriptions and reference + 5) added to descriptions to indicate applicability of leafs and Containers + to separate O-RAN use cases + 6) backward compatible changes to introduce groupings."; + + reference "ORAN-WG4.M.0-v02.00"; + } + + revision "2019-02-04" { + description + "version 1.0.0 + + 1) imported model from xRAN + 2) changed namespace and reference from xran to o-ran"; + + reference "ORAN-WG4.M.0-v01.00"; + } + + + feature GRANULARITY-TRANSPORT-MEASUREMENT { + description + "This feature indicates that the O-RU supports an optional object-unit TRANSPORT in rx-window-measurement."; + } + + feature GRANULARITY-EAXC-ID-MEASUREMENT { + description + "This feature indicates that the O-RU supports an optional object-unit EAXC_ID in rx-window-measurement."; + } + + grouping start-and-end-time { + description + "Definition for start and end time for an event"; + + leaf start-time { + type yang-types:date-and-time; + description + "Start time for measurement of object stats"; + } + leaf end-time { + type yang-types:date-and-time; + description + "End time for measurement of object stats"; + } + } + + grouping epe-measurement-result-grouping { + description + "energy, power and environmental measurement-result are listed for O-RU"; + + list epe-measurement-result { + key "object-unit-id"; + config false; + leaf object-unit-id { + type leafref { + path "/hw:hardware/hw:component/hw:class"; + } + + description + "the hardware component type is used for the object-unit-id for the + EPE measurements. For example, the object-unit-id will be set to + or-hw:O-RAN-RADIO if the measurement applies to the complete O-RU + self-contained sub-system. + + Other hardware-classes include: or-hw:O-RU-POWER-AMPLIFIER, + ianahw:power-supply, ianahw:fan, ianahw:cpu"; + } + leaf min { + type decimal64 { + fraction-digits 4; + } + + description + "minimum value for the measurment-object"; + } + leaf max { + type decimal64 { + fraction-digits 4; + } + description + "maximum value for the measurment-object"; + } + leaf average { + type decimal64 { + fraction-digits 4; + } + description + "average value of the measurement-object"; + } + } + } + + grouping transceiver-measurement-result-grouping { + description + "transceiver-measurement-result are listed per port-number"; + + list transceiver-measurement-result { + key "object-unit-id"; + config false; + leaf object-unit-id { + type leafref { + path "/if:interfaces/if:interface/o-ran-int:port-reference/o-ran-int:port-number"; + } + + description + "port-number is used for the object-unit-id for the + transceiver-measurement-result, for which object-unit is + PORT_NUMBER only"; + } + container min { + description + "minimum value with recorded time are included for the + measurement-object"; + + leaf value { + type decimal64 { + fraction-digits 4; + } + + description + "minimum value for the measurment-object"; + } + leaf time { + type yang-types:date-and-time; + + description + "recorded time for the minimum value"; + } + } + container max { + description + "maximum value with recorded time are included for the + measurement-object"; + + leaf value { + type decimal64 { + fraction-digits 4; + } + + description + "maximum value for the measurment-object"; + } + leaf time { + type yang-types:date-and-time; + + description + "recorded time for the maximum value"; + } + } + container first { + description + "first value with the recorded time are included for the + measurement-object"; + + leaf value { + type decimal64 { + fraction-digits 4; + } + + description + "first value of the measurement-object"; + } + leaf time { + type yang-types:date-and-time; + + description + "recorded time for the first value"; + } + } + container latest { + description + "latest value with the recorded time are included for the + measurement-object"; + + leaf value { + type decimal64 { + fraction-digits 4; + } + + description + "latest value of the measurement-object"; + } + leaf time { + type yang-types:date-and-time; + + description + "recorded time for the latest value"; + } + } + leaf-list frequeny-table { + type uint32; + + description + "frequency-table for the measurment-object are included per bin. + The configuration parameters for this frequency-table are defined + by bin-count, lower-bound and upper-bound"; + } + + description + "List of transceiver measurement results"; + } + } + + grouping rx-window-measurement-result-grouping{ + description + "Group of measurement reasults for rx window measurements"; + + choice object-unit-id { + config false; + case RU { + leaf name{ + type leafref { + path "/hw:hardware/hw:component/hw:name"; + } + + description + "the name of O-RU module or one of its child ports + in ietf-hardware/component is used when O-RU is selected as + object-unit for the reception window stats."; + } + leaf count { + type uint64; + mandatory true; + + description + "the number of data packet are counted for the reception + window stats per O-RU."; + } + } + + case TRANSPORT { + list tr-measured-result{ + leaf name{ + type leafref{ + path "/o-ran-elements:processing-elements/o-ran-elements:ru-elements/o-ran-elements:name"; + } + + description + "the name of ru-elements in o-ran-processing-elements + when TRANSPORT is selected as object-unit for the reception + window stats."; + } + leaf count { + type uint64; + mandatory true; + + description + "the number of data packet are counted for the reception + window stats."; + } + + description + "the number of data packet are counted for the reception + window stats per TRANSPORT."; + } + } + + case EAXC_ID { + list eaxc-measured-result { + leaf eaxc-id{ + type uint16; + + description + "eaxc-id is used + when EAXC_ID is selected as object-unit for the reception + window stats. + EAXC_ID consists of DU-Port-Id, Band-Selector, CC-id and + RU-Port-Id to be used in header of C/U-plane data packet."; + } + leaf count { + type uint64; + mandatory true; + + description + "the number of data packet are counted for the reception + window stats."; + } + leaf transport-name { + type leafref{ + path "/o-ran-elements:processing-elements/o-ran-elements:ru-elements/o-ran-elements:name"; + } + + description + "the name of ru-elements in o-ran-processing-elements for the + transport information corresponding to this eaxc-id"; + } + + description + "the number of data packet are counted for the reception + window stats per EAXC-ID."; + } + } + + description + "measurement-result for the reception window stats depends on the + configured object-unit, RU, TRANSPORT or EAXC_ID"; + } + } + + grouping tx-measurement-result-grouping{ + description + "Group of measurement reasults for tx stats"; + + choice object-unit-id { + config false; + case RU { + leaf name{ + type leafref { + path "/hw:hardware/hw:component/hw:name"; + } + + description + "the name of O-RU module or one of its child ports + in ietf-hardware/component is used when O-RU is selected as + object-unit for the reception window stats."; + } + leaf count { + type uint64; + mandatory true; + + description + "the number of data packet are counted for the tx stats per O-RU."; + } + } + + case TRANSPORT { + list tr-measured-result{ + leaf name{ + type leafref{ + path "/o-ran-elements:processing-elements/o-ran-elements:ru-elements/o-ran-elements:name"; + } + + description + "the name of ru-elements in o-ran-processing-elements + when TRANSPORT is selected as object-unit for the tx stats."; + } + leaf count { + type uint64; + mandatory true; + + description + "the number of data packet are counted for the tx stats."; + } + + description + "the number of data packet are counted for the tx stats per TRANSPORT."; + } + } + + case EAXC_ID { + list eaxc-measured-result { + leaf eaxc-id{ + type uint16; + + description + "eaxc-id is used + when EAXC_ID is selected as object-unit for the tx stats. + EAXC_ID consists of DU-Port-Id, Band-Selector, CC-id and + RU-Port-Id to be used in header of C/U-plane data packet."; + } + leaf count { + type uint64; + mandatory true; + + description + "the number of data packet are counted for the tx stats."; + } + leaf transport-name { + type leafref{ + path "/o-ran-elements:processing-elements/o-ran-elements:ru-elements/o-ran-elements:name"; + } + + description + "the name of ru-elements in o-ran-processing-elements for the + transport information corresponding to this eaxc-id"; + } + + description + "the number of data packet are counted for the tx stats per EAXC-ID."; + } + } + + description + "measurement-result for the tx stats depends on the + configured object-unit, RU, TRANSPORT or EAXC_ID"; + } + } + + + grouping measurement-group { + description + "Group of measurement results"; + + uses measurement-capabilities; + leaf enable-SFTP-upload { + type boolean; + default false; + description + "Flag to enable upload of performance measurement result files."; + } + + leaf enable-random-file-upload { + type boolean; + default false; + description + "Flag to enable upload of performance measurement result files at + random within file-upload-interval."; + } + + list remote-SFTP-uploads { + key remote-SFTP-upload-path; + description + "SFTP upload can be done to one or more than one SFTP servers"; + + leaf remote-SFTP-upload-path { + type inet:uri; + description + "URI specifying the remote location where the files are to uploaded. + The following format is possible: + sftp://@[:]/path"; + } + + uses o-ran-fm:credential-information; + } + +// transceiver measurements applicable to all O-RAN HW functions + + leaf transceiver-measurement-interval { + type uint16; + units seconds; + description + "measurement interval to measure the performance of transceiver + measurement objects periodically."; + } + +// EPE measurements applicable to all O-RAN HW functions + + leaf epe-measurement-interval { + type uint16; + units seconds; + description + "measurement interval to measure the energy, power and environmental + measurement objects periodically."; + } + +// RX Window measurements applicable to O-RAN WG4 defined functions + + leaf rx-window-measurement-interval { + type uint16; + units seconds; + description + "measurement interval to measure the performance of reception + window measurement objects periodically."; + } + + leaf tx-measurement-interval { + type uint16; + units seconds; + description + "measurement interval to measure the tx (outbound) + window measurement objects periodically."; + } + + leaf notification-interval { + type uint16; + units seconds; + description + "notification interval for the measurement result to be notified + periodically."; + } + + leaf file-upload-interval { + type uint16; + units seconds; + description + "file upload interval for the measurement result file to be + uploaded periodically."; + } + + leaf max-bin-count{ + type uint16; + config false; + mandatory true; + description + "indicates the maximum value of configurable bin-count for frequency + table in transceiver-measurement-objects as one of module + capabilities."; + } + + list transceiver-measurement-objects { + key "measurement-object"; + description + "optional list used to report transceiver measurements + applicable to any O-RAN defined hardware function"; + leaf measurement-object { + type enumeration { + enum RX_POWER { + description + "Measured Rx input power in mW for SFP or lane 1 of QSFP"; + } + enum RX_POWER_LANE_2 { + description + "Measured Rx input power in mW for lane 2 of QSFP"; + } + enum RX_POWER_LANE_3 { + description + "Measured Rx input power in mW for lane 3 of QSFP"; + } + enum RX_POWER_LANE_4 { + description + "Measured Rx input power in mW for lane 4 of QSFP"; + } + enum TX_POPWER { + status deprecated; + description + "Measured Tx input power in mW."; + } + enum TX_POWER { + description + "Measured Tx input power in mW."; + } + enum TX_POWER_LANE_2 { + description + "Measured Tx input power in mW for lane 2 of QSFP"; + } + enum TX_POWER_LANE_3 { + description + "Measured Tx input power in mW for lane 3 of QSFP"; + } + enum TX_POWER_LANE_4 { + description + "Measured Tx input power in mW for lane 4 of QSFP"; + } + enum TX_BIAS_COUNT { + description + "Internally measured Tx Bias Current in mA for SFP or lane 1 of QSFP"; + } + enum TX_BIAS_COUNT_LANE_2 { + description + "Internally measured Tx Bias Current in mA for lane 2 of QSFP"; + } + enum TX_BIAS_COUNT_LANE_3 { + description + "Internally measured Tx Bias Current in mA for lane 3 of QSFP"; + } + enum TX_BIAS_COUNT_LANE_4 { + description + "Internally measured Tx Bias Current in mA for lane 4 of QSFP"; + } + enum VOLTAGE { + description + "Internally measured transceiver supply voltage in mV"; + } + enum TEMPERATURE { + description + "Internally measured optional laser temperature in degrees Celsius."; + } + } + description "Target metric to measure the performance"; + } + + leaf active { + type boolean; + default false; + description + "Enable/disable the performance measurement per Object"; + } + + leaf-list report-info { + type enumeration { + enum MAXIMUM { + description + "to report maximum value and its recorded time within the + measurement-interval for the measurement-object."; + } + enum MINIMUM { + description + "to report minimum value and its recorded time within the + measurement-interval for the measurement-object."; + } + enum FIRST { + description + "to report first value and its recorded time within the + measurement-interval for the measurement-object."; + } + enum LATEST { + description + "to report latest value and its recorded time within the + measurement-interval for the measurement-object."; + } + enum FREQUENCY_TABLE { + description + "to report frequency bin table within the + measurement-interval for the measurement-object."; + } + } + description "The reporting info to the measurement object."; + } + + leaf object-unit { + type enumeration { + enum PORT_NUMBER { + description + "unit to measure the performance per object-id"; + } + } + mandatory true; + description "unit to measure the performance per object-id."; + } + + leaf function { + type enumeration { + enum RAW { + description + "the value is expressed by real value."; + } + enum LOG_10 { + description + "the value is expressed by logarithm with base 10."; + } + } + + description + "the value to be recorded for transceiver-measurement + by real value or log 10."; + } + + leaf bin-count { + type uint16; + + description + "the number of bin for the frequency table. + This value shall be less than max-bin-count"; + } + + leaf lower-bound { + type decimal64 { + fraction-digits 4; + } + + description + "the lower value of the first bin of frequency table."; + } + + leaf upper-bound { + type decimal64 { + fraction-digits 4; + } + + description + "the upper value of the last bin of frequency table."; + } + uses transceiver-measurement-result-grouping; +// configuration and measurement result for the transceiver-measurement + + } + + list rx-window-measurement-objects { + key "measurement-object"; + description + "optional list used to report RX Window measurements + applicable to O-RAN WG4 define O-RU functions"; + leaf measurement-object { + type enumeration { + enum RX_ON_TIME { + description + "the number of data packets, received on time within + the reception window."; + } + enum RX_EARLY { + description + "the number of data packets, received before + the reception window."; + } + enum RX_LATE { + description + "the number of data packets, received after + the reception window."; + } + enum RX_CORRUPT { + description + "the number of data packets, which are corrupt or whose header + is incorrect."; + } + enum RX_DUPL { + status deprecated; + description + "the number of data packets, which is duplicated with other packets, + received within the measurement period."; + } + enum RX_TOTAL { + description + "the total number of received packets (data and control) within the measurement period."; + } + enum RX_ON_TIME_C { + description + "the number of control packets, received on time within + the reception window."; + } + enum RX_EARLY_C { + description + "the number of control packets, received before + the reception window."; + } + enum RX_LATE_C { + description + "the number of control packets, received after + the reception window."; + } + enum RX_SEQID_ERR { + description + "the number of data packets, received with an erroneous sequence ID."; + } + enum RX_SEQID_ERR_C { + description + "the number of control packets, received with an erroneous sequence ID."; + } + enum RX_ERR_DROP { + description + "The total number of inbound messages which are discarded by the receiving + O-RAN entity for any reason."; + } + } + description + "target reception window metric to measure the performance."; + } + + leaf active { + type boolean; + default false; + description + "Enable/disable the performance measurement per reception window + measurement object."; + } + + leaf object-unit { + type enumeration { + enum RU { + description + "the reception window stats are counted per hardware component. + This may be the parent 'module' or child 'port' component."; + } + enum TRANSPORT { + if-feature GRANULARITY-TRANSPORT-MEASUREMENT; + description + "the reception window stats are counted per transport flow. + When there are multiple transport flows between O-DU and O-RU, + e.g. multiple sets of o-du mac address, ru mac address and + vlan-id, the reception window stats per transport flow + are counted in this case. + This configuration is allowed only when O-RU supports + a feature GRANULARITY-TRANSPORT-MEASUREMENT."; + } + enum EAXC_ID { + if-feature GRANULARITY-EAXC-ID-MEASUREMENT; + + description + "the reception window stats are counted per eAxC ID, which is + used in the header of receivd data packet. + This configuration is allowed only when O-RU supports + a feature GRANULARITY-EAXC-ID-MEASUREMENT."; + } + } + description + "unit to measure the performance per object-id."; + } + + leaf report-info { + type enumeration { + enum COUNT { + description + "the number of data packet are counted for the reception + window stats."; + } + } + description + "The reporting info to the measurement object."; + } + + uses rx-window-measurement-result-grouping; +// configuration and measurement result for the reception window stats + + } + + + list tx-measurement-objects { + key "measurement-object"; + description + "optional list used to report TX measurements + applicable to O-RAN WG4 define O-RU functions"; + leaf measurement-object { + type enumeration { + enum TX_TOTAL { + description + "the number of outbound packets (data and control), transmitted within + the measurement period"; + } + enum TX_TOTAL_C { + description + "the number of outbound control packets, transmitted within + the measurement period. + This counter is required only if RU supports LAA/LBT capabilities."; + } + } + description + "CU-plane transmission counters"; + } + + leaf active { + type boolean; + default false; + description + "Enable/disable the measurement per measurement object."; + } + + leaf object-unit { + type enumeration { + enum RU { + description + "the transmission stats are counted per hardware component. + This may be the parent 'module' or child 'port' component."; + } + enum TRANSPORT { + if-feature GRANULARITY-TRANSPORT-MEASUREMENT; + description + "the transmission stats are counted per transport flow. + When there are multiple transport flows between O-DU and O-RU, + e.g. multiple sets of o-du mac address, ru mac address and + vlan-id, the transmission stats per transport flow + are counted in this case. + This configuration is allowed only when O-RU supports + a feature GRANULARITY-TRANSPORT-MEASUREMENT."; + } + enum EAXC_ID { + if-feature GRANULARITY-EAXC-ID-MEASUREMENT; + + description + "the transmission stats are counted per eAxC ID, which is + used in the header of receivd data packet. + This configuration is allowed only when O-RU supports + a feature GRANULARITY-EAXC-ID-MEASUREMENT."; + } + } + description + "unit to measure the performance per object-id."; + } + + leaf report-info { + type enumeration { + enum COUNT { + description + "the number of data packet are counted for the reception + window stats."; + } + } + description + "The reporting info to the measurement object."; + } + + uses tx-measurement-result-grouping; + // configuration and measurement result for the tx stats + + } + + list epe-measurement-objects { + key "measurement-object"; + description + "optional list used to report energy, power and environmental + measurements applicable to any O-RAN defined hardware function"; + leaf measurement-object { + type enumeration { + enum TEMPERATURE { + description + "Measured temperature in degrees celcius"; + } + enum POWER { + description + "Measured power consumed, in watts (W)"; + } + } + description "Target metric to measure the performance"; + } + + leaf active { + type boolean; + default false; + description + "Enable/disable the performance measurement per Object"; + } + + leaf-list report-info { + type enumeration { + enum MAXIMUM { + description + "to report maximum value and its recorded time within the + measurement-interval for the measurement-object."; + } + enum MINIMUM { + description + "to report minimum value and its recorded time within the + measurement-interval for the measurement-object."; + } + enum AVERAGE { + description + "to report average value within the + measurement-interval for the measurement-object."; + } + } + description "The reporting info to the measurement object."; + } + + + uses epe-measurement-result-grouping; + // configuration and measurement result for the epe-measurement + + } + + + } + + grouping measurement-capabilities { + container measurement-capabilitites { + config false; + description "the type of measurement objects supported by the O-RU"; + + list transceiver-objects { + key measurement-object; + leaf measurement-object { + type leafref { + path "/performance-measurement-objects/transceiver-measurement-objects/measurement-object"; + } + } + } + list rx-window-objects { + key measurement-object; + leaf measurement-object { + type leafref { + path "/performance-measurement-objects/rx-window-measurement-objects/measurement-object"; + } + } + } + list tx-stats-objects { + key measurement-object; + leaf measurement-object { + type leafref { + path "/performance-measurement-objects/tx-measurement-objects/measurement-object"; + } + } + } + list epe-stats-objects { + key "measurement-object"; + description + "An optional list describing the energy, power and environmental measurements supported + by the O-RU. Measurements are defined per hardware component."; + leaf measurement-object { + type leafref { + path "/performance-measurement-objects/epe-measurement-objects/measurement-object"; + } + } + leaf-list component-class { + type identityref { + base ianahw:hardware-class; + } + description + "An indication of the general hardware type of the + component for which EPE measurements are supported."; + + } + } + } + } + + grouping measurement-notification { + list transceiver-stats { + key "measurement-object"; + leaf measurement-object { + type leafref { + path "/performance-measurement-objects/transceiver-measurement-objects/measurement-object"; + } + + description + "measurement-object for the transceiver-measurement"; + } + + uses start-and-end-time; + uses transceiver-measurement-result-grouping; + + description + "measurement result of transceiver-measurement per measurement-object"; + } + + list rx-window-stats { + key "measurement-object"; + leaf measurement-object { + type leafref { + path "/performance-measurement-objects/rx-window-measurement-objects/measurement-object"; + } + + description + "measurement-object for the reception window measurement"; + } + uses start-and-end-time; + uses rx-window-measurement-result-grouping; + + description + "measurement result for the reception window measurement per + measurement-object"; + + } + + list tx-stats { + key "measurement-object"; + leaf measurement-object { + type leafref { + path "/performance-measurement-objects/tx-measurement-objects/measurement-object"; + } + + description + "measurement-object for the tx stats measurement"; + } + uses start-and-end-time; + uses tx-measurement-result-grouping; + + description + "measurement result for the tx stats measurement per + measurement-object"; + + } + + container epe-stats { + description + "container for the epe stats measurement"; + + uses start-and-end-time; + uses epe-measurement-result-grouping; + + + } + + description + "notification may contain measurement result for transceiver-stats + and/or rx-window-stats"; + } + + // Top level container + + container performance-measurement-objects { + description + "configuration for performance management and measurement-result are + included"; + uses measurement-group; + } + +// Notifications + + notification measurement-result-stats { + description + "Notification may contain measurement results for transceiver-stats + and/or rx-window-stats"; + uses measurement-notification; + } +} diff --git a/radio/fhi_72/oaioran.c b/radio/fhi_72/oaioran.c index 7ac4998e40..fc9f58a492 100644 --- a/radio/fhi_72/oaioran.c +++ b/radio/fhi_72/oaioran.c @@ -35,7 +35,6 @@ #include "xran_sync_api.h" #include "oran_isolate.h" #include "oran-init.h" -#include "xran_common.h" #include "oaioran.h" #include @@ -43,6 +42,8 @@ #include "common/utils/threadPool/notified_fifo.h" +#define N_SC_PER_PRB 12 + #if OAI_FHI72_USE_POLLING #define USE_POLLING #endif @@ -67,49 +68,37 @@ volatile oran_sync_info_t oran_sync_info = {0}; void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) { struct xran_cb_tag *callback_tag = (struct xran_cb_tag *)pCallbackTag; - uint64_t second; - uint32_t tti; - uint32_t frame; - uint32_t subframe; - uint32_t slot, slot2; - uint32_t rx_sym; static int32_t last_slot = -1; static int32_t last_frame = -1; - /* xran context contains the same xran_fh_init struct info, - but xran_fh_config struct info is RU specific only */ - struct xran_device_ctx *xran_ctx = xran_dev_get_ctx(); - const struct xran_fh_init *fh_init = &xran_ctx->fh_init; + const struct xran_fh_init *fh_init = get_xran_fh_init(); int num_ports = fh_init->xran_ports; /* assuming all RUs have the same numerology */ - const int slots_per_subframe = 1 << xran_ctx->fh_cfg.frame_conf.nNumerology; + const struct xran_fh_config *fh_cfg = get_xran_fh_config(0); + const int slots_in_sf = 1 << fh_cfg->frame_conf.nNumerology; + const int sf_in_frame = 10; static int rx_RU[XRAN_PORTS_NUM][160] = {0}; - uint32_t rx_tti = callback_tag->slotiId; + uint32_t tti = callback_tag->slotiId; + uint32_t frame = XranGetFrameNum(tti, 0, sf_in_frame, slots_in_sf); + uint32_t subframe = XranGetSubFrameNum(tti, slots_in_sf, sf_in_frame); + uint32_t slot = XranGetSlotNum(tti, slots_in_sf); - tti = xran_get_slot_idx_from_tti(rx_tti, &frame, &subframe, &slot, &second); - - rx_sym = callback_tag->symbol & 0xFF; + uint32_t rx_sym = callback_tag->symbol & 0xFF; uint32_t ru_id = callback_tag->oXuId; - LOG_D(HW, - "rx_callback frame %d, subframe %d, slot %d, second %lld, rx_sym %d ru_id %d\n", - frame, - subframe, - slot, - (unsigned long long)second, - rx_sym, - ru_id); + LOG_D(HW, "rx_callback at %4d.%3d (subframe %d), rx_sym %d ru_id %d\n", frame, slot, subframe, rx_sym, ru_id); + if (rx_sym == 7) { // in F release this value is defined as XRAN_FULL_CB_SYM (full slot (offset + 7)) #ifdef F_RELEASE for (int ru_idx = 0; ru_idx < num_ports; ru_idx++) { - struct xran_device_ctx *xran_ctx_per_ru = xran_dev_get_ctx_by_id(ru_idx); - struct xran_fh_config *fh_config = &xran_ctx_per_ru->fh_cfg; + struct xran_fh_config *fh_config = get_xran_fh_config(ru_idx); + oran_buf_list_t *bufs = get_xran_buffers(ru_idx); for (uint16_t cc_id = 0; cc_id < 1 /* fh_config->nCC */; cc_id++) { // OAI does not support multiple CC yet. for(uint32_t ant_id = 0; ant_id < fh_config->neAxc; ant_id++) { - struct xran_prb_map *pRbMap = (struct xran_prb_map *)xran_ctx_per_ru->sFrontHaulRxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id].sBufferList.pBuffers->pData; + struct xran_prb_map *pRbMap = (struct xran_prb_map *)bufs->dstcp[ant_id][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; AssertFatal(pRbMap != NULL, "(%d:%d:%d)pRbMap == NULL. Aborting.\n", cc_id, tti % XRAN_N_FE_BUF_LEN, ant_id); for (uint32_t sym_id = 0; sym_id < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_id++) { @@ -127,7 +116,7 @@ void oai_xran_fh_rx_callback(void *pCallbackTag, xran_status_t status) // would see periodic output with only "0" in stats counters if (!first_call_set) return; - slot2 = slot + (subframe * slots_per_subframe); + uint32_t slot2 = slot + (subframe * slots_in_sf); rx_RU[ru_id][slot2] = 1; if (last_frame > 0 && frame > 0 && ((slot2 > 0 && last_frame != frame) || (slot2 == 0 && last_frame != ((1024 + frame - 1) & 1023)))) @@ -181,29 +170,27 @@ static int read_prach_data(ru_info_t *ru, int frame, int slot) /* calculate tti and subframe_id from frame, slot num */ int sym_idx = 0; - struct xran_device_ctx *xran_ctx = xran_dev_get_ctx(); - struct xran_prach_cp_config *pPrachCPConfig = &(xran_ctx->PrachCPConfig); - struct xran_ru_config *ru_conf = &(xran_ctx->fh_cfg.ru_conf); - int slots_per_frame = 10 << xran_ctx->fh_cfg.frame_conf.nNumerology; - int slots_per_subframe = 1 << xran_ctx->fh_cfg.frame_conf.nNumerology; + struct xran_fh_init *fh_init = get_xran_fh_init(); + struct xran_fh_config *fh_cfg = get_xran_fh_config(0); + int prach_sym = get_prach_conf_duration(0); + struct xran_ru_config *ru_conf = &fh_cfg->ru_conf; + int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology; + int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology; int tti = slots_per_frame * (frame) + (slot); uint32_t subframe = slot / slots_per_subframe; uint32_t is_prach_slot = xran_is_prach_slot(0, subframe, (slot % slots_per_subframe)); - int nb_rx_per_ru = ru->nb_rx / xran_ctx->fh_init.xran_ports; + int nb_rx_per_ru = ru->nb_rx / fh_init->xran_ports; /* If it is PRACH slot, copy prach IQ from XRAN PRACH buffer to OAI PRACH buffer */ if (is_prach_slot) { - for (sym_idx = 0; sym_idx < pPrachCPConfig->numSymbol; sym_idx++) { + for (sym_idx = 0; sym_idx < prach_sym; sym_idx++) { for (int aa = 0; aa < ru->nb_rx; aa++) { int16_t *dst, *src; int idx = 0; - xran_ctx = xran_dev_get_ctx_by_id(aa / nb_rx_per_ru); + oran_buf_list_t *bufs = get_xran_buffers(aa / nb_rx_per_ru); dst = ru->prach_buf[aa]; // + (sym_idx*576)); - src = (int16_t *)((uint8_t *)xran_ctx->sFHPrachRxBbuIoBufCtrlDecomp[tti % XRAN_N_FE_BUF_LEN][0][aa % nb_rx_per_ru] - .sBufferList.pBuffers[sym_idx] - .pData); - + src = (int16_t *)bufs->prachdstdecomp[aa % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx].pData; /* convert Network order to host order */ if (ru_conf->compMeth_PRACH == XRAN_COMPMETHOD_NONE) { if (sym_idx == 0) { @@ -328,16 +315,16 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) #endif // return(0); - struct xran_device_ctx *xran_ctx = xran_dev_get_ctx(); - int slots_per_frame = 10 << xran_ctx->fh_cfg.frame_conf.nNumerology; + struct xran_fh_config *fh_cfg = get_xran_fh_config(0); + int slots_per_frame = 10 << fh_cfg->frame_conf.nNumerology; int tti = slots_per_frame * (*frame) + (*slot); read_prach_data(ru, *frame, *slot); - const struct xran_fh_init *fh_init = &xran_ctx->fh_init; - int nPRBs = xran_ctx->fh_cfg.nULRBs; - int fftsize = 1 << xran_ctx->fh_cfg.ru_conf.fftSize; + const struct xran_fh_init *fh_init = get_xran_fh_init(); + int nPRBs = fh_cfg->nULRBs; + int fftsize = 1 << fh_cfg->ru_conf.fftSize; int slot_offset_rxdata = 3 & (*slot); uint32_t slot_size = 4 * 14 * fftsize; @@ -348,8 +335,7 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) for (uint8_t ant_id = 0; ant_id < ru->nb_rx; ant_id++) { rx_data = (uint8_t *)ru->rxdataF[ant_id]; start_ptr = rx_data + (slot_size * slot_offset_rxdata); - xran_ctx = xran_dev_get_ctx_by_id(ant_id / nb_rx_per_ru); - const struct xran_frame_config *frame_conf = &xran_ctx->fh_cfg.frame_conf; + const struct xran_frame_config *frame_conf = &get_xran_fh_config(ant_id / nb_rx_per_ru)->frame_conf; // skip processing this slot is TX (no RX in this slot) if (is_tdd_dl_guard_slot(frame_conf, *slot)) continue; @@ -361,8 +347,8 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) continue; uint8_t *pData; - uint8_t *pPrbMapData = xran_ctx->sFrontHaulRxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_rx_per_ru] - .sBufferList.pBuffers->pData; + oran_buf_list_t *bufs = get_xran_buffers(ant_id / nb_rx_per_ru); + uint8_t *pPrbMapData = bufs->dstcp[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData; struct xran_prb_elm *pRbElm = &pPrbMap->prbMap[0]; @@ -374,8 +360,8 @@ int xran_fh_rx_read_slot(ru_info_t *ru, int *frame, int *slot) uint32_t one_rb_size = (((pRbElm->iqWidth == 0) || (pRbElm->iqWidth == 16)) ? (N_SC_PER_PRB * 2 * 2) : (3 * pRbElm->iqWidth + 1)); if (fh_init->mtu < pRbElm->nRBSize * one_rb_size) - pData = xran_ctx->sFrontHaulRxBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_rx_per_ru] - .sBufferList.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT] + pData = bufs->dst[ant_id % nb_rx_per_ru][tti % XRAN_N_FE_BUF_LEN] + .pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT] .pData; else pData = p_sec_desc->pData; @@ -493,22 +479,20 @@ int xran_fh_tx_send_slot(ru_info_t *ru, int frame, int slot, uint64_t timestamp) int32_t *pos = NULL; int idx = 0; - struct xran_device_ctx *xran_ctx = xran_dev_get_ctx(); - const struct xran_fh_init *fh_init = &xran_ctx->fh_init; - int nPRBs = xran_ctx->fh_cfg.nDLRBs; - int fftsize = 1 << xran_ctx->fh_cfg.ru_conf.fftSize; + const struct xran_fh_init *fh_init = get_xran_fh_init(); + const struct xran_fh_config *fh_cfg = get_xran_fh_config(0); + int nPRBs = fh_cfg->nDLRBs; + int fftsize = 1 << fh_cfg->ru_conf.fftSize; int nb_tx_per_ru = ru->nb_tx / fh_init->xran_ports; for (uint16_t cc_id = 0; cc_id < 1 /*nSectorNum*/; cc_id++) { // OAI does not support multiple CC yet. for (uint8_t ant_id = 0; ant_id < ru->nb_tx; ant_id++) { - xran_ctx = xran_dev_get_ctx_by_id(ant_id / nb_tx_per_ru); + oran_buf_list_t *bufs = get_xran_buffers(ant_id / nb_tx_per_ru); // This loop would better be more inner to avoid confusion and maybe also errors. for (int32_t sym_idx = 0; sym_idx < XRAN_NUM_OF_SYMBOL_PER_SLOT; sym_idx++) { - uint8_t *pData = xran_ctx->sFrontHaulTxBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_tx_per_ru] - .sBufferList.pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT] - .pData; - uint8_t *pPrbMapData = xran_ctx->sFrontHaulTxPrbMapBbuIoBufCtrl[tti % XRAN_N_FE_BUF_LEN][cc_id][ant_id % nb_tx_per_ru] - .sBufferList.pBuffers->pData; + uint8_t *pData = + bufs->src[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers[sym_idx % XRAN_NUM_OF_SYMBOL_PER_SLOT].pData; + uint8_t *pPrbMapData = bufs->srccp[ant_id % nb_tx_per_ru][tti % XRAN_N_FE_BUF_LEN].pBuffers->pData; struct xran_prb_map *pPrbMap = (struct xran_prb_map *)pPrbMapData; ptr = pData; pos = &ru->txdataF_BF[ant_id][sym_idx * fftsize]; diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index 891634dbfc..89c1838fa3 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -461,6 +461,11 @@ static uint64_t get_u64_mask(const paramdef_t *pd) return mask; } +#ifdef F_RELEASE +char bbdev_dev[32] = ""; +char bbdev_vfio_vf_token[64] = ""; +#endif + static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, int nump, const int num_rus) { DevAssert(fhip != NULL); @@ -474,8 +479,44 @@ static bool set_fh_io_cfg(struct xran_io_cfg *io_cfg, const paramdef_t *fhip, in for (int i = 0; i < num_dev; ++i) { io_cfg->dpdk_dev[i] = strdup(gpd(fhip, nump, ORAN_CONFIG_DPDK_DEVICES)->strlistptr[i]); // VFs devices } +#ifdef F_RELEASE + io_cfg->bbdev_dev[0] = NULL; // BBDev dev name; max devices = 1 + io_cfg->bbdev_vfio_vf_token[0] = NULL; // BBDev dev token; max devices = 1 + char *shlibversion = NULL; // version of the LDPC coding library + paramdef_t LoaderParams_shlibversion[] = {{"shlibversion", NULL, 0, .strptr = &shlibversion, .defstrval = NULL, TYPE_STRING, 0, NULL}}; + config_get(config_get_if(), LoaderParams_shlibversion, sizeofArray(LoaderParams_shlibversion), "loader.ldpc"); + if (shlibversion != NULL && strncmp(shlibversion, "_aal", 4) == 0) { + uint32_t is_t2 = 0; // If not 0 then include the BBDEV device in the EAL init for FHI + char *dpdk_dev = NULL; // PCI address of the card + char *vfio_vf_token = NULL; // vfio token for the bbdev card + paramdef_t LoaderParams[] = { + {"is_t2", NULL, 0, .uptr = &is_t2, .defuintval = 0, TYPE_UINT, 0, NULL}, + {"dpdk_dev", NULL, 0, .strptr = &dpdk_dev, .defstrval = NULL, TYPE_STRING, 0, NULL}, + {"vfio_vf_token", NULL, 0, .strptr = &vfio_vf_token, .defstrval = NULL, TYPE_STRING, 0, NULL} + }; + config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_aal"); + + if (!is_t2) { + AssertFatal(dpdk_dev!=NULL, "nrLDPC_coding_aal.dpdk_dev was not provided"); + snprintf(&bbdev_dev[0], sizeof(bbdev_dev), "%s", dpdk_dev); + io_cfg->bbdev_dev[0] = &bbdev_dev[0]; // BBDev dev name; max devices = 1 + if(vfio_vf_token != NULL) { + snprintf(&bbdev_vfio_vf_token[0], sizeof(bbdev_vfio_vf_token), "%s", vfio_vf_token); + io_cfg->bbdev_vfio_vf_token[0] = &bbdev_vfio_vf_token[0]; // BBDev dev token; max devices = 1 + } else { + io_cfg->bbdev_vfio_vf_token[0] = NULL; // BBDev dev token; max devices = 1 + } + io_cfg->bbdev_mode = XRAN_BBDEV_MODE_HW_ON; // DPDK for BBDev + } else { + io_cfg->bbdev_mode = XRAN_BBDEV_NOT_USED; // DPDK for BBDev + } + } else { + io_cfg->bbdev_mode = XRAN_BBDEV_NOT_USED; // DPDK for BBDev + } +#elif defined(E_RELEASE) io_cfg->bbdev_dev[0] = NULL; // BBDev dev name; max devices = 1 io_cfg->bbdev_mode = XRAN_BBDEV_NOT_USED; // DPDK for BBDev +#endif int dpdk_iova_mode_idx = config_paramidx_fromname((paramdef_t *)fhip, nump, ORAN_CONFIG_DPDK_IOVA_MODE); AssertFatal(dpdk_iova_mode_idx >= 0,"Index for dpdk_iova_mode config option not found!"); io_cfg->dpdkIoVaMode = config_get_processedint(config_get_if(), (paramdef_t *)&fhip[dpdk_iova_mode_idx]); // IOVA mode @@ -843,8 +884,6 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c for (int i = 1; i < oai0->rx_num_channels; ++i) DevAssert(oai0->rx_freq[0] == oai0->rx_freq[i]); DevAssert(oai0->nr_band > 0); - AssertFatal(oai0->threequarter_fs == 0, "cannot use three-quarter sampling with O-RAN 7.2 split\n"); - paramdef_t FHconfigs[] = ORAN_FH_DESC; paramlist_def_t FH_ConfigList = {CONFIG_STRING_ORAN_FH}; char aprefix[MAX_OPTNAME_SIZE] = {0}; diff --git a/radio/fhi_72/oran-init.c b/radio/fhi_72/oran-init.c index 38e766805a..07517dcf18 100644 --- a/radio/fhi_72/oran-init.c +++ b/radio/fhi_72/oran-init.c @@ -30,7 +30,9 @@ #include "common/utils/assertions.h" #include "common/utils/LOG/log.h" +#include "common/utils/nr/nr_common.h" #include "common_lib.h" +#include "openair2/LAYER2/NR_MAC_COMMON/nr_prach_config.h" /* PRACH data samples are 32 bits wide (16bits for I/Q). Each packet contains * 840 samples for long sequence or 144 for short sequence. The payload length @@ -46,6 +48,10 @@ static oran_port_instance_t gPortInst[XRAN_PORTS_NUM][XRAN_MAX_SECTOR_NR]; void *gxran_handle; +static struct xran_fh_init g_fh_init = {0}; +static struct xran_fh_config g_fh_config[XRAN_PORTS_NUM] = {0}; +static uint32_t g_prach_conf_duration[XRAN_PORTS_NUM] = {0}; + static uint32_t get_nSW_ToFpga_FTH_TxBufferLen(int mu, int sections) { uint32_t xran_max_sections_per_slot = RTE_MAX(sections, XRAN_MIN_SECTIONS_PER_SLOT); @@ -460,7 +466,47 @@ int *oai_oran_initialize(struct xran_fh_init *xran_fh_init, struct xran_fh_confi printf("xran_reg_physide_cb failed %d\n", xret); exit(-1); } + + // retrieve and store prach duration + uint8_t idx = xran_fh_config[o_xu_id].prach_conf.nPrachConfIdx; + const struct xran_frame_config *fc = &xran_fh_config[o_xu_id].frame_conf; + g_prach_conf_duration[o_xu_id] = + get_nr_prach_occasion_info_from_index(idx, + fc->nNumerology > 2 ? FR2 : FR1, + fc->nFrameDuplexType == XRAN_FDD ? duplex_mode_FDD : duplex_mode_TDD) + .N_dur; } + // store config after xran initialization -- xran makes modifications to + // these structs during initialization + memcpy(&g_fh_init, xran_fh_init, sizeof(*xran_fh_init)); + memcpy(&g_fh_config, xran_fh_config, sizeof(*xran_fh_config) * xran_fh_init->xran_ports); + return (void *)gxran_handle; } + +oran_buf_list_t *get_xran_buffers(uint32_t port_id) +{ + struct xran_fh_init *fh_init = get_xran_fh_init(); + DevAssert(port_id < fh_init->xran_ports); + return gPortInst[port_id][0].buf_list; +} + +struct xran_fh_init *get_xran_fh_init(void) +{ + return &g_fh_init; +} + +struct xran_fh_config *get_xran_fh_config(uint32_t port_id) +{ + struct xran_fh_init *fh_init = get_xran_fh_init(); + DevAssert(port_id < fh_init->xran_ports); + return &g_fh_config[port_id]; +} + +uint32_t get_prach_conf_duration(uint32_t port_id) +{ + struct xran_fh_init *fh_init = get_xran_fh_init(); + DevAssert(port_id < fh_init->xran_ports); + return g_prach_conf_duration[port_id]; +} diff --git a/radio/fhi_72/oran-init.h b/radio/fhi_72/oran-init.h index b9f31d9889..e56b683a9f 100644 --- a/radio/fhi_72/oran-init.h +++ b/radio/fhi_72/oran-init.h @@ -59,4 +59,9 @@ extern void *gxran_handle; int *oai_oran_initialize(struct xran_fh_init *fh_init, struct xran_fh_config *fh_config); +oran_buf_list_t *get_xran_buffers(uint32_t port_id); +struct xran_fh_init *get_xran_fh_init(void); +struct xran_fh_config *get_xran_fh_config(uint32_t port_id); +uint32_t get_prach_conf_duration(uint32_t port_id); + #endif /* ORAN_INIT_H */ diff --git a/radio/fhi_72/oran-params.h b/radio/fhi_72/oran-params.h index 42aabd99bb..baeefbc68d 100644 --- a/radio/fhi_72/oran-params.h +++ b/radio/fhi_72/oran-params.h @@ -35,6 +35,7 @@ #define ORAN_CONFIG_DU_ADDR "du_addr" // only needed for M-plane #define ORAN_CONFIG_VLAN_TAG "vlan_tag" // only needed for M-plane #define ORAN_CONFIG_RU_ADDR "ru_addr" // not needed if M-plane used +#define ORAN_CONFIG_RU_USERNAME "ru_username" // only needed for M-plane #define ORAN_CONFIG_RU_IP_ADDR "ru_ip_addr" // only needed for M-plane #define ORAN_CONFIG_MTU "mtu" // not needed if M-plane used #define ORAN_CONFIG_FILE_PREFIX "file_prefix" @@ -56,6 +57,7 @@ {ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ {ORAN_CONFIG_VLAN_TAG, "VLAN tag\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ + {ORAN_CONFIG_RU_USERNAME, "Username of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ {ORAN_CONFIG_RU_IP_ADDR, "IP addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \ {ORAN_CONFIG_MTU, "MTU of Eth interface\n", 0, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \ {ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \ @@ -82,6 +84,7 @@ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ { .s3a = { config_checkstr_assign_integer, \ {"PA", "VA"}, {0, 1}, 2} }, \ { .s5 = { NULL } }, \ diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 7ceec513c6..3bdbe1df12 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -103,6 +103,11 @@ int trx_oran_set_gains(openair0_device *device, openair0_config_t *openair0_cfg) int trx_oran_get_stats(openair0_device *device) { + uint64_t total_time, used_time; + uint32_t num_core_used, core_used[64]; + uint32_t ret = xran_get_time_stats(&total_time, &used_time, &num_core_used, &core_used[0], 0); + if (ret == 0) + LOG_I(HW, "xran_get_time_stats(): total thread time %ld, total time essential tasks %ld, num cores used %d\n", total_time, used_time, num_core_used); printf("ORAN: %s\n", __FUNCTION__); return (0); } @@ -333,6 +338,11 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d if (!ru_ready[i] && ru_session->ru_notif.config_change && ru_session->ru_notif.rx_carrier_state && ru_session->ru_notif.tx_carrier_state) { MP_LOG_I("RU \"%s\" is now ready.\n", ru_session->ru_ip_add); ru_ready[i] = true; + if (!ru_session->pm_stats.start_up_timing) { + success = pm_conf(ru_session, "true"); + if (success) + MP_LOG_I("Sucessfully activated PM after start-up procedure for RU \"%s\".\n", ru_session->ru_ip_add); + } } else { all_rus_ready = false; break; diff --git a/radio/rfsimulator/CMakeLists.txt b/radio/rfsimulator/CMakeLists.txt index efba710bad..ad4d92f108 100644 --- a/radio/rfsimulator/CMakeLists.txt +++ b/radio/rfsimulator/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(rfsimulator MODULE apply_channelmod.c ../../openair1/PHY/TOOLS/signal_energy.c ) -target_link_libraries(rfsimulator PRIVATE SIMU) +target_link_libraries(rfsimulator PRIVATE SIMU log_headers) set_target_properties(rfsimulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_executable(replay_node stored_node.c) diff --git a/radio/rfsimulator/README.md b/radio/rfsimulator/README.md index ae46034cec..40688b755a 100644 --- a/radio/rfsimulator/README.md +++ b/radio/rfsimulator/README.md @@ -79,7 +79,6 @@ The RF simulator is using the configuration module, and its parameters are defin |`--rfsimulator.IQfile ` | path to a file to store the IQ samples to (only with `saviq`) | `/tmp/rfsimulator.iqs` | |`--rfsimulator.prop_delay` | simulated receive-path (gNB: UL, UE: DL) propagation delay in ms | 0 | |`--rfsimulator.wait_timeout` | wait timeout when no UE is connected | 1 | -|`--rfismulator.hanging-workaround`| Enable workaround to de-block potentially hanging server on new client connection. | 0 | Please refer to this document [`SIMULATION/TOOLS/DOC/channel_simulation.md`](../../openair1/SIMULATION/TOOLS/DOC/channel_simulation.md) for information about using the RFSimulator options to run the simulator with a channel model. diff --git a/radio/rfsimulator/apply_channelmod.c b/radio/rfsimulator/apply_channelmod.c index efeb03b25c..a976c63264 100644 --- a/radio/rfsimulator/apply_channelmod.c +++ b/radio/rfsimulator/apply_channelmod.c @@ -25,6 +25,7 @@ #include #include #include +#include "openair2/LAYER2/NR_MAC_gNB/mac_config.h" #include "rfsimulator.h" /* @@ -95,7 +96,13 @@ void rxAddInput(const c16_t *input_sig, const double vel_ue_sat = (vel_sat_x * dir_ue_sat_x + vel_sat_y * dir_ue_sat_y + vel_sat_z * dir_ue_sat_z) / dist_ue_sat; double dist_sat_gnb = 0; + double vel_sat_gnb = 0; + double acc_sat_gnb = 0; if (channelDesc->modelid == SAT_LEO_TRANS) { + const double acc_sat_x = 0; + const double acc_sat_y = -w_sat * w_sat * radius_sat * sin(w_sat * t); + const double acc_sat_z = -w_sat * w_sat * radius_sat * cos(w_sat * t); + const double pos_gnb_x = 0; const double pos_gnb_y = 0; const double pos_gnb_z = radius_earth; @@ -105,6 +112,8 @@ void rxAddInput(const c16_t *input_sig, const double dir_sat_gnb_z = pos_gnb_z - pos_sat_z; dist_sat_gnb = sqrt(dir_sat_gnb_x * dir_sat_gnb_x + dir_sat_gnb_y * dir_sat_gnb_y + dir_sat_gnb_z * dir_sat_gnb_z); + vel_sat_gnb = (vel_sat_x * dir_sat_gnb_x + vel_sat_y * dir_sat_gnb_y + vel_sat_z * dir_sat_gnb_z) / dist_sat_gnb; + acc_sat_gnb = (acc_sat_x * dir_sat_gnb_x + acc_sat_y * dir_sat_gnb_y + acc_sat_z * dir_sat_gnb_z) / dist_sat_gnb; } const double prop_delay = (dist_ue_sat + dist_sat_gnb) / c; @@ -117,8 +126,33 @@ void rxAddInput(const c16_t *input_sig, if(TS - last_TS >= channelDesc->sampling_rate) { last_TS = TS; - LOG_D(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); - LOG_D(HW, "Uplink delay %f ms, Doppler shift UE->SAT %f kHz\n", prop_delay * 1000, f_Doppler_shift_ue_sat / 1000); + LOG_I(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); + LOG_I(HW, "Uplink delay %f ms, Doppler shift UE->SAT %f kHz\n", prop_delay * 1000, f_Doppler_shift_ue_sat / 1000); + LOG_I(HW, "Satellite velocity towards gNB: %f m/s, acceleration towards gNB: %f m/s²\n", vel_sat_gnb, acc_sat_gnb); + } + + const int samples_per_subframe = channelDesc->sampling_rate / 1000; + const int abs_subframe = TS / samples_per_subframe; + if (abs_subframe % 10 == 0) { // update SIB19 information for the next frame + gnb_sat_position_update_t sat_position = { + .sfn = (abs_subframe / 10 + 1) % 1024, + .subframe = 0, + .delay = 2 * dist_sat_gnb / (c * 4.072e-9), + .drift = 2 * -vel_sat_gnb / (c * 0.2e-9), + .accel = 2 * acc_sat_gnb / (c * 0.2e-10), + .position.X = pos_sat_x / 1.3, + .position.Y = pos_sat_y / 1.3, + .position.Z = pos_sat_z / 1.3, + .velocity.X = vel_sat_x / 0.06, + .velocity.Y = vel_sat_y / 0.06, + .velocity.Z = vel_sat_z / 0.06, + }; + // Here we update the SIB19 information directly in the gNB MAC layer. + // Without rf-simulaor, in a real system or with an external channel emulator, the SIB19 updates would + // be provided via an external interface (e.g. O-RAN E2 interface) to the MAC layer (in the O-DU). + // We do it directly here, because we can, and an E2 Interface implementation (e.g using FlexRIC) + // would pull too many dependencies into rf-simulator, just for updating SIB19. + nr_update_sib19(&sat_position); } } else { const double dir_sat_ue_x = pos_ue_x - pos_sat_x; @@ -151,8 +185,8 @@ void rxAddInput(const c16_t *input_sig, if(TS - last_TS >= channelDesc->sampling_rate) { last_TS = TS; - LOG_D(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); - LOG_D(HW, "Downlink delay %f ms, Doppler shift SAT->UE %f kHz\n", prop_delay * 1000, f_Doppler_shift_sat_ue / 1000); + LOG_I(HW, "Satellite orbit: time %f s, Position = (%f, %f, %f), Velocity = (%f, %f, %f)\n", t, pos_sat_x, pos_sat_y, pos_sat_z, vel_sat_x, vel_sat_y, vel_sat_z); + LOG_I(HW, "Downlink delay %f ms, Doppler shift SAT->UE %f kHz\n", prop_delay * 1000, f_Doppler_shift_sat_ue / 1000); } } } diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index 32648758c8..13a414fed6 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -1,26 +1,25 @@ /* -* 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 -* -* Author and copyright: Laurent Thomas, open-cells.com -* -* 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 -*/ - + * 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 + * + * Author and copyright: Laurent Thomas, open-cells.com + * + * 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 + */ /* * Open issues and limitations @@ -51,7 +50,7 @@ #include #include "rfsimulator.h" -#define PORT 4043 //default TCP port for this simulator +#define PORT 4043 // default TCP port for this simulator // // CirSize defines the number of samples inquired for a read cycle // It is bounded by a slot read capability (which depends on bandwidth and numerology) @@ -65,8 +64,8 @@ // The previous value is kept below in comment it was computed for 100ms 1x 20MHz // #define CirSize 6144000 // 100ms SiSo 20MHz LTE #define minCirSize 460800 // 10ms SiSo 40Mhz 3/4 sampling NR78 FR1 -#define sampleToByte(a,b) ((a)*(b)*sizeof(sample_t)) -#define byteToSample(a,b) ((a)/(sizeof(sample_t)*(b))) +#define sampleToByte(a, b) ((a) * (b) * sizeof(sample_t)) +#define byteToSample(a, b) ((a) / (sizeof(sample_t) * (b))) #define GENERATE_CHANNEL 10 // each frame (or slot?) in DL #define MAX_FD_RFSIMU 250 @@ -77,40 +76,40 @@ typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole; // -#define RFSIMU_SECTION "rfsimulator" +#define RFSIMU_SECTION "rfsimulator" #define RFSIMU_OPTIONS_PARAMNAME "options" - -#define RFSIM_CONFIG_HELP_OPTIONS " list of comma separated options to enable rf simulator functionalities. Available options: \n"\ - " chanmod: enable channel modelisation\n"\ +#define RFSIM_CONFIG_HELP_OPTIONS \ + " list of comma separated options to enable rf simulator functionalities. Available options: \n" \ + " chanmod: enable channel modelisation\n" \ " saviq: enable saving written iqs to a file\n" -#define CONFIG_HELP_HANG_WORKAROUND "Enable workaroud for server mode hanging on new client connection.\n" +// clang-format off /*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -/* configuration parameters for the rfsimulator device */ +/* configuration parameters for the rfsimulator device */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ /*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define simOpt PARAMFLAG_NOFREE|PARAMFLAG_CMDLINE_NOPREFIXENABLED +#define simOpt PARAMFLAG_NOFREE | PARAMFLAG_CMDLINE_NOPREFIXENABLED #define RFSIMULATOR_PARAMS_DESC { \ {"serveraddr", "\n", simOpt, .strptr=&rfsimulator->ip, .defstrval="127.0.0.1", TYPE_STRING, 0 },\ - {"serverport", "\n", simOpt, .u16ptr=&(rfsimulator->port), .defuintval=PORT, TYPE_UINT16, 0 },\ - {RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS, 0, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST,0 },\ + {"serverport", "\n", simOpt, .u16ptr = &(rfsimulator->port), .defuintval = PORT, TYPE_UINT16, 0}, \ + {RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS, 0, .strlistptr = NULL, .defstrlistval = NULL, TYPE_STRINGLIST, 0}, \ {"IQfile", "\n",simOpt, .strptr=&saveF, .defstrval="/tmp/rfsimulator.iqs",TYPE_STRING, 0 },\ - {"modelname", "\n", simOpt, .strptr=&modelname, .defstrval="AWGN", TYPE_STRING, 0 },\ - {"ploss", "\n", simOpt, .dblptr=&(rfsimulator->chan_pathloss), .defdblval=0, TYPE_DOUBLE, 0 },\ + {"modelname", "\n", simOpt, .strptr = &modelname, .defstrval = "AWGN", TYPE_STRING, 0}, \ + {"ploss", "\n", simOpt, .dblptr = &(rfsimulator->chan_pathloss), .defdblval = 0, TYPE_DOUBLE, 0}, \ {"forgetfact", "\n", simOpt, .dblptr=&(rfsimulator->chan_forgetfact),.defdblval=0, TYPE_DOUBLE, 0 },\ - {"offset", "\n", simOpt, .u64ptr=&(rfsimulator->chan_offset), .defint64val=0, TYPE_UINT64, 0 },\ + {"offset", "\n", simOpt, .u64ptr = &(rfsimulator->chan_offset), .defint64val = 0, TYPE_UINT64, 0}, \ {"prop_delay", "\n", simOpt, .dblptr=&(rfsimulator->prop_delay_ms), .defdblval=0.0, TYPE_DOUBLE, 0 },\ {"wait_timeout", "\n", simOpt, .iptr=&(rfsimulator->wait_timeout), .defintval=1, TYPE_INT, 0 },\ - {"hanging-workaround", CONFIG_HELP_HANG_WORKAROUND, simOpt, .iptr=&rfsimulator->hanging_workaround, .defintval=0, TYPE_INT, 0 },\ }; - +// clang-format on static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt); extern int get_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt); // in random_channel.c static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg); static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg); static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg); static int rfsimu_vtime_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg); +// clang-format off static telnetshell_cmddef_t rfsimu_cmdarray[] = { {"show models", "", (cmdfunc_t)rfsimu_setchanmod_cmd, {(webfunc_t)getset_currentchannels_type}, TELNETSRV_CMDFLAG_WEBSRVONLY | TELNETSRV_CMDFLAG_GETWEBTBLDATA, NULL}, {"setmodel", " ", (cmdfunc_t)rfsimu_setchanmod_cmd, {NULL}, TELNETSRV_CMDFLAG_PUSHINTPOOLQ | TELNETSRV_CMDFLAG_TELNETONLY, NULL}, @@ -119,14 +118,11 @@ static telnetshell_cmddef_t rfsimu_cmdarray[] = { {"vtime", "", (cmdfunc_t)rfsimu_vtime_cmd, {NULL}, TELNETSRV_CMDFLAG_PUSHINTPOOLQ | TELNETSRV_CMDFLAG_AUTOUPDATE}, {"", "", NULL}, }; +// clang-format on static telnetshell_cmddef_t *setmodel_cmddef = &(rfsimu_cmdarray[1]); static telnetshell_vardef_t rfsimu_vardef[] = {{"", 0, 0, NULL}}; -pthread_mutex_t Sockmutex; -unsigned int nb_ue = 0; - static uint64_t CirSize = minCirSize; - typedef c16_t sample_t; // 2*16 bits complex number typedef struct buffer_s { @@ -144,6 +140,8 @@ typedef struct buffer_s { typedef struct { int listen_sock, epollfd; + pthread_mutex_t Sockmutex; + unsigned int nb_cnx; openair0_timestamp nextRxTstamp; openair0_timestamp lastWroteTS; simuRole role; @@ -165,31 +163,33 @@ typedef struct { poll_telnetcmdq_func_t poll_telnetcmdq; int wait_timeout; double prop_delay_ms; - int hanging_workaround; } rfsimulator_state_t; +static bool flushInput(rfsimulator_state_t *t, int timeout, bool first_time); + static buffer_t *allocCirBuf(rfsimulator_state_t *bridge, int sock) { uint64_t buff_index = bridge->next_buf++ % MAX_FD_RFSIMU; - buffer_t *ptr=&bridge->buf[buff_index]; + buffer_t *ptr = &bridge->buf[buff_index]; + bridge->nb_cnx++; ptr->circularBuf = calloc(1, sampleToByte(CirSize, 1)); if (ptr->circularBuf == NULL) { LOG_E(HW, "malloc(%lu) failed\n", sampleToByte(CirSize, 1)); return NULL; } - ptr->circularBufEnd=((char *)ptr->circularBuf)+sampleToByte(CirSize,1); - ptr->conn_sock=sock; - ptr->lastReceivedTS=0; - ptr->headerMode=true; - ptr->trashingPacket=false; - ptr->transferPtr=(char *)&ptr->th; - ptr->remainToTransfer=sizeof(samplesBlockHeader_t); + ptr->circularBufEnd = ((char *)ptr->circularBuf) + sampleToByte(CirSize, 1); + ptr->conn_sock = sock; + ptr->lastReceivedTS = 0; + ptr->headerMode = true; + ptr->trashingPacket = true; + ptr->transferPtr = (char *)&ptr->th; + ptr->remainToTransfer = sizeof(samplesBlockHeader_t); int sendbuff = SEND_BUFF_SIZE; if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)) != 0) { LOG_E(HW, "setsockopt(SO_SNDBUF) failed\n"); return NULL; } - struct epoll_event ev= {0}; + struct epoll_event ev = {0}; ev.events = EPOLLIN | EPOLLRDHUP; ev.data.ptr = ptr; if (epoll_ctl(bridge->epollfd, EPOLL_CTL_ADD, sock, &ev) != 0) { @@ -197,24 +197,28 @@ static buffer_t *allocCirBuf(rfsimulator_state_t *bridge, int sock) return NULL; } - if ( bridge->channelmod > 0) { + if (bridge->channelmod > 0) { // create channel simulation model for this mode reception - static bool init_done=false; + static bool init_done = false; if (!init_done) { uint64_t rand; - FILE *h=fopen("/dev/random","r"); + FILE *h = fopen("/dev/random", "r"); - if ( 1 != fread(&rand,sizeof(rand),1,h) ) + if (1 != fread(&rand, sizeof(rand), 1, h)) LOG_W(HW, "Can't read /dev/random\n"); fclose(h); randominit(rand); tableNor(rand); - init_done=true; + init_done = true; } char modelname[30]; - snprintf(modelname, sizeofArray(modelname), "rfsimu_channel_%s%d", (bridge->role == SIMU_ROLE_SERVER) ? "ue" : "enB", nb_ue); + snprintf(modelname, + sizeofArray(modelname), + "rfsimu_channel_%s%d", + (bridge->role == SIMU_ROLE_SERVER) ? "ue" : "enB", + bridge->nb_cnx - 1); ptr->channel_model = find_channel_desc_fromname(modelname); // path_loss in dB if (!ptr->channel_model) { // Use legacy method to find channel model - this will use the same channel model for all clients @@ -228,7 +232,7 @@ static buffer_t *allocCirBuf(rfsimulator_state_t *bridge, int sock) set_channeldesc_owner(ptr->channel_model, RFSIMU_MODULEID); set_channeldesc_direction(ptr->channel_model, bridge->role == SIMU_ROLE_SERVER); - random_channel(ptr->channel_model,false); + random_channel(ptr->channel_model, false); LOG_I(HW, "Random channel %s in rfsimulator activated\n", modelname); } return ptr; @@ -246,7 +250,7 @@ static void removeCirBuf(rfsimulator_state_t *bridge, buffer_t *buf) // free(bridge->buf[sock].channel_model); memset(buf, 0, sizeof(buffer_t)); buf->conn_sock = -1; - nb_ue--; + bridge->nb_cnx--; } static void socketError(rfsimulator_state_t *bridge, buffer_t *buf) @@ -273,7 +277,7 @@ static int setblocking(int sock, enum blocking_t active) return -1; } - if (active==blocking) + if (active == blocking) opts = opts & ~O_NONBLOCK; else opts = opts | O_NONBLOCK; @@ -286,11 +290,9 @@ static int setblocking(int sock, enum blocking_t active) return 0; } -static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps); - static void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) { if (t->saveIQfile != -1) { - if (write(t->saveIQfile, _buf, count) != count ) + if (write(t->saveIQfile, _buf, count) != count) LOG_E(HW, "write() in save iq file failed (%d)\n", errno); } @@ -301,12 +303,12 @@ static void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) l = write(fd, buf, count); if (l == 0) { - LOG_E(HW, "write() failed, returned 0\n"); - return; + LOG_E(HW, "write() failed, returned 0\n"); + return; } if (l < 0) { - if (errno==EINTR) + if (errno == EINTR) continue; if (errno == EAGAIN) { @@ -325,8 +327,8 @@ static void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) } static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) { - char *saveF=NULL; - char *modelname=NULL; + char *saveF = NULL; + char *modelname = NULL; paramdef_t rfsimu_params[] = RFSIMULATOR_PARAMS_DESC; int p = config_paramidx_fromname(rfsimu_params, sizeofArray(rfsimu_params), RFSIMU_OPTIONS_PARAMNAME); int ret = config_get(config_get_if(), rfsimu_params, sizeofArray(rfsimu_params), RFSIMU_SECTION); @@ -334,11 +336,11 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) { rfsimulator->saveIQfile = -1; - for(int i=0; isaveIQfile=open(saveF,O_APPEND| O_CREAT|O_TRUNC | O_WRONLY, 0666); + for (int i = 0; i < rfsimu_params[p].numelt; i++) { + if (strcmp(rfsimu_params[p].strlistptr[i], "saviq") == 0) { + rfsimulator->saveIQfile = open(saveF, O_APPEND | O_CREAT | O_TRUNC | O_WRONLY, 0666); - if ( rfsimulator->saveIQfile != -1 ) + if (rfsimulator->saveIQfile != -1) LOG_I(HW, "Will save written IQ samples in %s\n", saveF); else { LOG_E(HW, "open(%s) failed for IQ saving, errno(%d)\n", saveF, errno); @@ -346,24 +348,16 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) { } break; - } else if (strcmp(rfsimu_params[p].strlistptr[i],"chanmod") == 0) { + } else if (strcmp(rfsimu_params[p].strlistptr[i], "chanmod") == 0) { init_channelmod(); load_channellist(rfsimulator->tx_num_channels, rfsimulator->rx_num_channels, rfsimulator->sample_rate, rfsimulator->rx_freq, rfsimulator->tx_bw); - rfsimulator->channelmod=true; + rfsimulator->channelmod = true; } else { fprintf(stderr, "unknown rfsimulator option: %s\n", rfsimu_params[p].strlistptr[i]); exit(-1); } } - /* for compatibility keep environment variable usage */ - if ( getenv("RFSIMULATOR") != NULL ) { - rfsimulator->ip=getenv("RFSIMULATOR"); - LOG_W(HW, "The RFSIMULATOR environment variable is deprecated and support will be removed in the future. Instead, add parameter --rfsimulator.serveraddr %s to set the server address. Note: the default is \"server\"; for the gNB/eNB, you don't have to set any configuration.\n", rfsimulator->ip); - LOG_I(HW, "Remove RFSIMULATOR environment variable to get rid of this message and the sleep.\n"); - sleep(10); - } - if ( strncasecmp(rfsimulator->ip,"enb",3) == 0 || strncasecmp(rfsimulator->ip,"server",3) == 0 ) rfsimulator->role = SIMU_ROLE_SERVER; @@ -372,8 +366,8 @@ static void rfsimulator_readconfig(rfsimulator_state_t *rfsimulator) { } static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg) { - char *modelname=NULL; - char *modeltype=NULL; + char *modelname = NULL; + char *modeltype = NULL; rfsimulator_state_t *t = (rfsimulator_state_t *)arg; if (t->channelmod == false) { prnt("%s: ERROR channel modelisation disabled...\n", __func__); @@ -385,23 +379,23 @@ static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, } if (debug) prnt("%s: rfsimu_setchanmod_cmd buffer \"%s\"\n", __func__, buff); - int s = sscanf(buff,"%m[^ ] %ms\n",&modelname, &modeltype); + int s = sscanf(buff, "%m[^ ] %ms\n", &modelname, &modeltype); if (s == 2) { - int channelmod=modelid_fromstrtype(modeltype); + int channelmod = modelid_fromstrtype(modeltype); - if (channelmod<0) + if (channelmod < 0) prnt("%s: ERROR: model type %s unknown\n", __func__, modeltype); else { rfsimulator_state_t *t = (rfsimulator_state_t *)arg; - int found=0; + int found = 0; for (int i = 0; i < MAX_FD_RFSIMU; i++) { - buffer_t *b=&t->buf[i]; - if ( b->channel_model==NULL) + buffer_t *b = &t->buf[i]; + if (b->channel_model == NULL) continue; - if (b->channel_model->model_name==NULL) + if (b->channel_model->model_name == NULL) continue; - if (b->conn_sock >= 0 && (strcmp(b->channel_model->model_name,modelname)==0)) { + if (b->conn_sock >= 0 && (strcmp(b->channel_model->model_name, modelname) == 0)) { channel_desc_t *newmodel = new_channel_desc_scm(t->tx_num_channels, t->rx_num_channels, channelmod, @@ -417,17 +411,17 @@ static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, 0); // noise_power set_channeldesc_owner(newmodel, RFSIMU_MODULEID); set_channeldesc_direction(newmodel, t->role == SIMU_ROLE_SERVER); - set_channeldesc_name(newmodel,modelname); - random_channel(newmodel,false); - channel_desc_t *oldmodel=b->channel_model; - b->channel_model=newmodel; + set_channeldesc_name(newmodel, modelname); + random_channel(newmodel, false); + channel_desc_t *oldmodel = b->channel_model; + b->channel_model = newmodel; free_channel_desc_scm(oldmodel); prnt("%s: New model type %s applied to channel %s connected to sock %d\n", __func__, modeltype, modelname, i); - found=1; + found = 1; break; } } /* for */ - if (found==0) + if (found == 0) prnt("%s: Channel %s not found or not currently used\n", __func__, modelname); } } else { @@ -450,25 +444,6 @@ static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdat get_currentchannels_type("modify type", debug, tdata, prnt); } } -/*getset_currentchannels_type */ - -//static void print_cirBuf(struct complex16 *circularBuf, -// uint64_t firstSample, -// uint32_t cirSize, -// int neg, -// int pos, -// int nbTx) -//{ -// for (int i = -neg; i < pos ; ++i) { -// for (int txAnt = 0; txAnt < nbTx; txAnt++) { -// const int idx = ((firstSample + i) * nbTx + txAnt + cirSize) % cirSize; -// if (i == 0) -// printf("->"); -// printf("%08x%08x\n", circularBuf[idx].r, circularBuf[idx].i); -// } -// } -// printf("\n"); -//} static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg) { @@ -477,7 +452,7 @@ static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt char *modelname; int distance; - int s = sscanf(buff,"%m[^ ] %d\n", &modelname, &distance); + int s = sscanf(buff, "%m[^ ] %d\n", &modelname, &distance); if (s != 2) { prnt("%s: require exact two parameters\n", __func__); return CMDSTATUS_VARNOTFOUND; @@ -487,8 +462,8 @@ static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt const double sample_rate = t->sample_rate; const double c = 299792458; /* 3e8 */ - const uint64_t new_offset = (double) distance * sample_rate / c; - const double new_distance = (double) new_offset * c / sample_rate; + const uint64_t new_offset = (double)distance * sample_rate / c; + const double new_distance = (double)new_offset * c / sample_rate; const double new_delay_ms = new_offset * 1000.0 / sample_rate; prnt("\n%s: new_offset %lu, new (exact) distance %.3f m, new delay %f ms\n", __func__, new_offset, new_distance, new_delay_ms); @@ -497,7 +472,7 @@ static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt /* Set distance in rfsim and channel model, update channel and ringbuffer */ for (int i = 0; i < MAX_FD_RFSIMU; i++) { - buffer_t *b=&t->buf[i]; + buffer_t *b = &t->buf[i]; if (b->conn_sock <= 0 || b->channel_model == NULL || b->channel_model->model_name == NULL || strcmp(b->channel_model->model_name, modelname) != 0) { if (b->channel_model != NULL && b->channel_model->model_name != NULL) prnt(" %s: model %s unmodified\n", __func__, b->channel_model->model_name); @@ -523,13 +498,13 @@ static int rfsimu_getdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt const double c = 299792458; /* 3e8 */ for (int i = 0; i < MAX_FD_RFSIMU; i++) { - buffer_t *b=&t->buf[i]; + buffer_t *b = &t->buf[i]; if (b->conn_sock <= 0 || b->channel_model == NULL || b->channel_model->model_name == NULL) continue; channel_desc_t *cd = b->channel_model; const uint64_t offset = cd->channel_offset; - const double distance = (double) offset * c / sample_rate; + const double distance = (double)offset * c / sample_rate; prnt("%s: %s offset %lu distance %.3f m\n", __func__, cd->model_name, offset, distance); } prnt("%s: offset %lu delay %f ms\n", __func__, t->chan_offset, t->prop_delay_ms); @@ -550,7 +525,7 @@ static int startServer(openair0_device *device) { int sock = -1; struct addrinfo *results = NULL; - struct addrinfo *rp= NULL; + struct addrinfo *rp = NULL; rfsimulator_state_t *t = (rfsimulator_state_t *)device->priv; t->role = SIMU_ROLE_SERVER; @@ -559,9 +534,9 @@ static int startServer(openair0_device *device) snprintf(port, sizeof(port), "%d", t->port); struct addrinfo hints = { - .ai_family = AF_INET6, - .ai_socktype = SOCK_STREAM, - .ai_flags = AI_PASSIVE, + .ai_family = AF_INET6, + .ai_socktype = SOCK_STREAM, + .ai_flags = AI_PASSIVE, }; int s = getaddrinfo(NULL, port, &hints, &results); @@ -628,8 +603,8 @@ static int client_try_connect(const char *host, uint16_t port) snprintf(dport, sizeof(dport), "%d", port); struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, }; s = getaddrinfo(host, dport, &hints, &result); @@ -678,43 +653,57 @@ static int startClient(openair0_device *device) if (setblocking(sock, notBlocking) == -1) { return -1; } - return allocCirBuf(t, sock) == NULL ? -1 : 0; + buffer_t *b = allocCirBuf(t, sock); + if (!b) + return -1; + // read a 1 sample block to initialize the current time + bool have_to_wait; + do { + have_to_wait = true; + flushInput(t, 3, true); + if (b->lastReceivedTS) + have_to_wait = false; + } while (have_to_wait); + if (b->lastReceivedTS > 0) + b->lastReceivedTS--; + t->nextRxTstamp = b->lastReceivedTS; + LOG_D(HW, "Client got first timestamp: starting at %lu\n", t->nextRxTstamp); + if (b->channel_model) + b->channel_model->start_TS = t->nextRxTstamp; + return 0; } -static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags, bool alreadyLocked) { - if (!alreadyLocked) - pthread_mutex_lock(&Sockmutex); - +static int rfsimulator_write_internal(rfsimulator_state_t *t, + openair0_timestamp timestamp, + void **samplesVoid, + int nsamps, + int nbAnt, + int flags) +{ + mutexlock(t->Sockmutex); LOG_D(HW, "Sending %d samples at time: %ld, nbAnt %d\n", nsamps, timestamp, nbAnt); for (int i = 0; i < MAX_FD_RFSIMU; i++) { - buffer_t *b=&t->buf[i]; + buffer_t *b = &t->buf[i]; - if (b->conn_sock >= 0 ) { + if (b->conn_sock >= 0) { samplesBlockHeader_t header = {nsamps, nbAnt, timestamp}; - fullwrite(b->conn_sock,&header, sizeof(header), t); - sample_t tmpSamples[nsamps][nbAnt]; - + fullwrite(b->conn_sock, &header, sizeof(header), t); if (nbAnt == 1) { - if (b->conn_sock >= 0) { - fullwrite(b->conn_sock, samplesVoid[0], sampleToByte(nsamps, nbAnt), t); - } + fullwrite(b->conn_sock, samplesVoid[0], sampleToByte(nsamps, nbAnt), t); } else { + sample_t tmpSamples[nsamps][nbAnt]; for (int a = 0; a < nbAnt; a++) { sample_t *in = (sample_t *)samplesVoid[a]; - for (int s = 0; s < nsamps; s++) tmpSamples[s][a] = in[s]; } - - if (b->conn_sock >= 0) { - fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps, nbAnt), t); - } + fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps, nbAnt), t); } } } - if ( t->lastWroteTS != 0 && fabs((double)t->lastWroteTS-timestamp) > (double)CirSize) + if (t->lastWroteTS != 0 && fabs((double)t->lastWroteTS - timestamp) > (double)CirSize) LOG_W(HW, "Discontinuous TX gap too large Tx:%lu, %lu\n", t->lastWroteTS, timestamp); if (t->lastWroteTS > timestamp) @@ -727,10 +716,8 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, timestamp - t->lastWroteTS); - t->lastWroteTS=timestamp+nsamps; - - if (!alreadyLocked) - pthread_mutex_unlock(&Sockmutex); + t->lastWroteTS = timestamp + nsamps; + mutexunlock(t->Sockmutex); LOG_D(HW, "Sent %d samples at time: %ld->%ld, energy in first antenna: %d\n", @@ -738,210 +725,227 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, timestamp + nsamps, signal_energy(samplesVoid[0], nsamps)); + + /* trace only first antenna */ + T(T_USRP_TX_ANT0, T_INT(timestamp), T_BUFFER(samplesVoid[0], sampleToByte(nsamps, 1))); + return nsamps; } -static int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { +static int rfsimulator_write(openair0_device *device, + openair0_timestamp timestamp, + void **samplesVoid, + int nsamps, + int nbAnt, + int flags) +{ timestamp -= device->openair0_cfg->command_line_sample_advance; - return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags, false); // false = with lock - // return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags, true); + return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags); } -static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) { +static bool add_client(rfsimulator_state_t *t) +{ + struct sockaddr_storage sa = {0}; + socklen_t socklen = sizeof(sa); + int conn_sock = accept(t->listen_sock, (struct sockaddr *)&sa, &socklen); + if (conn_sock == -1) { + LOG_E(HW, "accept() failed, errno(%d)\n", errno); + return false; + } + if (setblocking(conn_sock, notBlocking)) { + return false; + } + mutexlock(t->Sockmutex); + buffer_t *new_buf = allocCirBuf(t, conn_sock); + if (new_buf == NULL) { + mutexunlock(t->Sockmutex); + return false; + } + new_buf->lastReceivedTS = t->lastWroteTS; + char ip[INET6_ADDRSTRLEN]; + getnameinfo((struct sockaddr *)&sa, socklen, ip, sizeof(ip), NULL, 0, NI_NUMERICHOST); + uint16_t port = ((struct sockaddr_in *)&sa)->sin_port; + LOG_I(HW, "Client connects from %s:%d\n", ip, port); + c16_t v = {0}; + void *samplesVoid[t->tx_num_channels]; + for (int i = 0; i < t->tx_num_channels; i++) + samplesVoid[i] = (void *)&v; + samplesBlockHeader_t header = {1, t->tx_num_channels, t->lastWroteTS}; + fullwrite(conn_sock, &header, sizeof(header), t); + fullwrite(conn_sock, samplesVoid, sampleToByte(1, t->tx_num_channels), t); + + if (new_buf->channel_model) + new_buf->channel_model->start_TS = t->lastWroteTS; + mutexunlock(t->Sockmutex); + return true; +} + +static void process_recv_header(rfsimulator_state_t *t, buffer_t *b, bool first_time) +{ + // check the header and start block transfer + if (b->remainToTransfer != 0) + return; + + b->headerMode = false; // We got the header + + if (first_time) { + b->lastReceivedTS = b->th.timestamp; + b->trashingPacket = true; + } else { + if (b->lastReceivedTS < b->th.timestamp) { + // We have a transmission hole to fill, like TDD + // we create no signal samples up to the beginning of this reception + int nbAnt = b->th.nbAnt; + if (b->th.timestamp - b->lastReceivedTS < CirSize) { + // case we wrap at circular buffer end + for (uint64_t index = b->lastReceivedTS; index < b->th.timestamp; index++) { + for (int a = 0; a < nbAnt; a++) { + b->circularBuf[(index * nbAnt + a) % CirSize] = (c16_t){0}; + } + } + } else { + // case no circular buffer wrap + memset(b->circularBuf, 0, sampleToByte(CirSize, 1)); + } + b->lastReceivedTS = b->th.timestamp; + } else if (b->lastReceivedTS > b->th.timestamp) { + LOG_W(HW, "Received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); + b->trashingPacket = true; + } + // verify the time gap is not too large + mutexlock(t->Sockmutex); + if (t->lastWroteTS != 0 && (fabs((double)t->lastWroteTS - b->lastReceivedTS) > (double)CirSize)) + LOG_W(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->conn_sock, t->lastWroteTS, b->lastReceivedTS); + mutexunlock(t->Sockmutex); + } + // move back the pointer to overwrite the header, we don't need it anymore + b->transferPtr = (char *)&b->circularBuf[(b->lastReceivedTS * b->th.nbAnt) % CirSize]; + // we now need to read the samples + b->remainToTransfer = sampleToByte(b->th.size, b->th.nbAnt); + return; +} + +static void process_recv(rfsimulator_state_t *t, buffer_t *b, bool first_time) +{ + if (b->transferPtr == b->circularBufEnd) + b->transferPtr = (char *)b->circularBuf; + + if (!b->trashingPacket) { + b->lastReceivedTS = b->th.timestamp + b->th.size - byteToSample(b->remainToTransfer, b->th.nbAnt); + LOG_D(HW, "UEsock: %d Set b->lastReceivedTS %ld\n", b->conn_sock, b->lastReceivedTS); + } + + if (b->remainToTransfer == 0) { + LOG_D(HW, "UEsock: %d Completed block reception: %ld\n", b->conn_sock, b->lastReceivedTS); + b->headerMode = true; + b->transferPtr = (char *)&b->th; + b->remainToTransfer = sizeof(samplesBlockHeader_t); + b->trashingPacket = false; + } +} + +static bool flushInput(rfsimulator_state_t *t, int timeout, bool first_time) +{ // Process all incoming events on sockets // store the data in lists struct epoll_event events[MAX_FD_RFSIMU] = {{0}}; int nfds = epoll_wait(t->epollfd, events, MAX_FD_RFSIMU, timeout); - if ( nfds==-1 ) { - if ( errno==EINTR || errno==EAGAIN ) { - return false; - } else { + if (nfds == -1) { + if (!(errno == EINTR || errno == EAGAIN)) LOG_W(HW, "epoll_wait() failed, errno(%d)\n", errno); - return false; - } + return false; } for (int nbEv = 0; nbEv < nfds; ++nbEv) { buffer_t *b = events[nbEv].data.ptr; if (events[nbEv].events & EPOLLIN && b == NULL) { - int conn_sock; - conn_sock = accept(t->listen_sock, NULL, NULL); - if (conn_sock == -1) { - LOG_E(HW, "accept() failed, errno(%d)\n", errno); - return false; - } - if (setblocking(conn_sock, notBlocking)) { - return false; - } - buffer_t *new_buf = allocCirBuf(t, conn_sock); - if (new_buf == NULL) { - return false; - } - LOG_I(HW, "A client connects, sending the current time\n"); - c16_t v= {0}; - nb_ue++; - void *samplesVoid[t->tx_num_channels]; - - for ( int i=0; i < t->tx_num_channels; i++) - samplesVoid[i]=(void *)&v; - - rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS - 1 : 0, samplesVoid, 1, t->tx_num_channels, 1, false); - - if (new_buf->channel_model) - new_buf->channel_model->start_TS = t->lastWroteTS; + bool ret = add_client(t); + if (!ret) + return ret; + continue; } else { - if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) { + if (events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP)) { socketError(t, b); continue; } - if ( b->circularBuf == NULL ) { - LOG_E(HW, "Received data on not connected socket %d\n", events[nbEv].data.fd); - continue; - } - - ssize_t blockSz; - - if ( b->headerMode) - blockSz=b->remainToTransfer; - else - blockSz= b->transferPtr + b->remainToTransfer <= b->circularBufEnd ? - b->remainToTransfer : - b->circularBufEnd - b->transferPtr ; - - ssize_t sz = recv(b->conn_sock, b->transferPtr, blockSz, MSG_DONTWAIT); - - if ( sz < 0 ) { - if ( errno != EAGAIN ) { - LOG_E(HW, "recv() failed, errno(%d)\n", errno); - //abort(); - } - } else if ( sz == 0 ) - continue; - - LOG_D(HW, "Socket rcv %zd bytes\n", sz); - b->remainToTransfer -= sz; - b->transferPtr+=sz; - - if (b->transferPtr==b->circularBufEnd ) - b->transferPtr=(char *)b->circularBuf; - - // check the header and start block transfer - if ( b->headerMode==true && b->remainToTransfer==0) { - b->headerMode = false; - - if (t->nextRxTstamp == 0) { // First block in UE, resync with the gNB current TS - t->nextRxTstamp=b->th.timestamp> nsamps_for_initial ? - b->th.timestamp - nsamps_for_initial : - 0; - b->lastReceivedTS=b->th.timestamp> nsamps_for_initial ? - b->th.timestamp : - nsamps_for_initial; - LOG_D(HW, "UE got first timestamp: starting at %lu\n", t->nextRxTstamp); - b->trashingPacket=true; - if (b->channel_model) - b->channel_model->start_TS = t->nextRxTstamp; - } else if (b->lastReceivedTS < b->th.timestamp) { - int nbAnt= b->th.nbAnt; - - if ( b->th.timestamp-b->lastReceivedTS < CirSize ) { - for (uint64_t index=b->lastReceivedTS; index < b->th.timestamp; index++ ) { - for (int a=0; a < nbAnt; a++) { - b->circularBuf[(index*nbAnt+a)%CirSize].r = 0; - b->circularBuf[(index*nbAnt+a)%CirSize].i = 0; - } - } - } else { - memset(b->circularBuf, 0, sampleToByte(CirSize,1)); - } - - b->lastReceivedTS=b->th.timestamp; - } else if (b->lastReceivedTS > b->th.timestamp && b->th.size == 1) { - LOG_W(HW, "Received Rx/Tx synchro out of order\n"); - b->trashingPacket=true; - } else if (b->lastReceivedTS == b->th.timestamp) { - // normal case - } else { - LOG_W(HW, "Received data in past: current is %lu, new reception: %lu!\n", b->lastReceivedTS, b->th.timestamp); - b->trashingPacket=true; - } - - pthread_mutex_lock(&Sockmutex); - - if (t->lastWroteTS != 0 && (fabs((double)t->lastWroteTS-b->lastReceivedTS) > (double)CirSize)) - LOG_W(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->conn_sock, t->lastWroteTS, b->lastReceivedTS); - - pthread_mutex_unlock(&Sockmutex); - b->transferPtr=(char *)&b->circularBuf[(b->lastReceivedTS*b->th.nbAnt)%CirSize]; - b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt); - } - - if ( b->headerMode==false ) { - if ( ! b->trashingPacket ) { - b->lastReceivedTS=b->th.timestamp+b->th.size-byteToSample(b->remainToTransfer,b->th.nbAnt); - LOG_D(HW, "UEsock: %d Set b->lastReceivedTS %ld\n", b->conn_sock, b->lastReceivedTS); - } - - if ( b->remainToTransfer==0) { - LOG_D(HW, "UEsock: %d Completed block reception: %ld\n", b->conn_sock, b->lastReceivedTS); - b->headerMode=true; - b->transferPtr=(char *)&b->th; - b->remainToTransfer = sizeof(samplesBlockHeader_t); - b->trashingPacket=false; - } - } } - } - return nfds>0; + if (b->circularBuf == NULL) { + LOG_E(HW, "Received data on not connected socket %d\n", events[nbEv].data.fd); + continue; + } + + ssize_t blockSz; + if (b->headerMode) + blockSz = b->remainToTransfer; + else + blockSz = + b->transferPtr + b->remainToTransfer <= b->circularBufEnd ? b->remainToTransfer : b->circularBufEnd - b->transferPtr; + + ssize_t sz = recv(b->conn_sock, b->transferPtr, blockSz, MSG_DONTWAIT); + if (sz <= 0) { + if (sz < 0 && errno != EAGAIN) + LOG_E(HW, "recv() failed, errno(%d)\n", errno); + continue; + } + LOG_D(HW, "Socket rcv %zd bytes\n", sz); + b->remainToTransfer -= sz; + b->transferPtr += sz; + if (b->headerMode) + process_recv_header(t, b, first_time); + else + process_recv(t, b, first_time); + } + return nfds > 0; } static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) { rfsimulator_state_t *t = device->priv; - LOG_D(HW, "Enter rfsimulator_read, expect %d samples, will release at TS: %ld, nbAnt %d\n", nsamps, t->nextRxTstamp+nsamps, nbAnt); + LOG_D(HW, + "Enter rfsimulator_read, expect %d samples, will release at TS: %ld, nbAnt %d\n", + nsamps, + t->nextRxTstamp + nsamps, + nbAnt); // deliver data from received data // check if a UE is connected int first_sock; for (first_sock = 0; first_sock < MAX_FD_RFSIMU; first_sock++) - if (t->buf[first_sock].circularBuf != NULL ) + if (t->buf[first_sock].circularBuf != NULL) break; if (first_sock == MAX_FD_RFSIMU) { // no connected device (we are eNB, no UE is connected) - if ( t->nextRxTstamp == 0) + if (t->nextRxTstamp == 0) LOG_I(HW, "No connected device, generating void samples...\n"); - if (!flushInput(t, t->wait_timeout, nsamps)) { - for (int x=0; x < nbAnt; x++) - memset(samplesVoid[x],0,sampleToByte(nsamps,1)); + if (!flushInput(t, t->wait_timeout, false)) { + for (int x = 0; x < nbAnt; x++) + memset(samplesVoid[x], 0, sampleToByte(nsamps, 1)); - t->nextRxTstamp+=nsamps; + t->nextRxTstamp += nsamps; - if ( ((t->nextRxTstamp/nsamps)%100) == 0) + if (((t->nextRxTstamp / nsamps) % 100) == 0) LOG_D(HW, "No UE, Generating void samples for Rx: %ld\n", t->nextRxTstamp); - *ptimestamp = t->nextRxTstamp-nsamps; + *ptimestamp = t->nextRxTstamp - nsamps; return nsamps; } } else { bool have_to_wait; - int loops = 0; do { - have_to_wait=false; - + have_to_wait = false; buffer_t *b = NULL; for (int sock = 0; sock < MAX_FD_RFSIMU; sock++) { b = &t->buf[sock]; - - if ( b->circularBuf ) - if ( t->nextRxTstamp+nsamps > b->lastReceivedTS ) { - have_to_wait=true; + if (b->circularBuf && (t->nextRxTstamp + nsamps) > b->lastReceivedTS) { + have_to_wait = true; break; - } + } } if (have_to_wait) { @@ -949,63 +953,55 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest "Waiting on socket, current last ts: %ld, expected at least : %ld\n", b->lastReceivedTS, t->nextRxTstamp + nsamps); - flushInput(t, 3, nsamps); - } - if (t->hanging_workaround && loops++ > 10 && t->role == SIMU_ROLE_SERVER && nb_ue > 1) { - // Just start producing samples. The clients will catch up. - have_to_wait = false; - LOG_W(HW, - "No longer waiting for clients to catch up, starting to produce samples\n"); + flushInput(t, 3, false); } } while (have_to_wait); } - struct timespec start_time; int ret = clock_gettime(CLOCK_REALTIME, &start_time); AssertFatal(ret == 0, "clock_gettime() failed: errno %d, %s\n", errno, strerror(errno)); // Clear the output buffer - for (int a=0; abuf[sock]; + buffer_t *ptr = &t->buf[sock]; - if ( ptr->circularBuf ) { - bool reGenerateChannel=false; + if (ptr->circularBuf && !ptr->trashingPacket) { + bool reGenerateChannel = false; - //fixme: when do we regenerate - // it seems legacy behavior is: never in UL, each frame in DL + // fixme: when do we regenerate + // it seems legacy behavior is: never in UL, each frame in DL if (reGenerateChannel) - random_channel(ptr->channel_model,0); + random_channel(ptr->channel_model, 0); if (t->poll_telnetcmdq) - t->poll_telnetcmdq(t->telnetcmd_qid,t); + t->poll_telnetcmdq(t->telnetcmd_qid, t); - for (int a=0; achannel_model != NULL ) { // apply a channel model + for (int a_rx = 0; a_rx < nbAnt; a_rx++) { // loop over number of Rx antennas + if (ptr->channel_model != NULL) { // apply a channel model if (num_chanmod_channels == 0) { memset(temp_array, 0, sizeof(temp_array)); } num_chanmod_channels++; rxAddInput(ptr->circularBuf, - temp_array[a], - a, + temp_array[a_rx], + a_rx, ptr->channel_model, nsamps, t->nextRxTstamp, CirSize, apply_noise_per_channel); - } - else { // no channel modeling + } else { // no channel modeling int nbAnt_tx = ptr->th.nbAnt; // number of Tx antennas int firstIndex = (CirSize + t->nextRxTstamp - t->chan_offset) % CirSize; - sample_t *out = (sample_t *)samplesVoid[a]; - if ((nbAnt_tx == 1) && ((nb_ue == 1) || (t->role == SIMU_ROLE_CLIENT))) { // optimized for 1 Tx and 1 UE + sample_t *out = (sample_t *)samplesVoid[a_rx]; + if (nbAnt_tx == 1 && t->nb_cnx == 1) { // optimized for 1 Tx and 1 UE sample_t *firstSample = (sample_t *)&(ptr->circularBuf[firstIndex]); if (firstIndex + nsamps > CirSize) { int tailSz = CirSize - firstIndex; @@ -1016,16 +1012,16 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest } } else { // SIMD (with simde) optimization might be added here later - double H_awgn_mimo[4][4] = {{1.0, 0.2, 0.1, 0.05}, // rx 0 - {0.2, 1.0, 0.2, 0.1}, // rx 1 - {0.1, 0.2, 1.0, 0.2}, // rx 2 - {0.05, 0.1, 0.2, 1.0}}; // rx 3 - - LOG_D(HW, "nbAnt_tx %d\n", nbAnt_tx); + LOG_D(HW, "nbAnt_tx %d nbAnt %d\n", nbAnt_tx, nbAnt); + double H_awgn_mimo_coeff[nbAnt_tx]; + for (int a_tx = 0; a_tx < nbAnt_tx; a_tx++) { + uint32_t ant_diff = abs(a_tx - a_rx); + H_awgn_mimo_coeff[a_tx] = ant_diff ? (0.2 / ant_diff) : 1.0; + } for (int i = 0; i < nsamps; i++) { // loop over nsamps for (int a_tx = 0; a_tx < nbAnt_tx; a_tx++) { // sum up signals from nbAnt_tx antennas - out[i].r += (short)(ptr->circularBuf[((firstIndex + i) * nbAnt_tx + a_tx) % CirSize].r * H_awgn_mimo[a][a_tx]); - out[i].i += (short)(ptr->circularBuf[((firstIndex + i) * nbAnt_tx + a_tx) % CirSize].i * H_awgn_mimo[a][a_tx]); + out[i].r += (short)(ptr->circularBuf[((firstIndex + i) * nbAnt_tx + a_tx) % CirSize].r * H_awgn_mimo_coeff[a_tx]); + out[i].i += (short)(ptr->circularBuf[((firstIndex + i) * nbAnt_tx + a_tx) % CirSize].i * H_awgn_mimo_coeff[a_tx]); } // end for a_tx } // end for i (number of samps) } // end of 1 tx antenna optimization @@ -1059,20 +1055,24 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest AssertFatal(ret == 0, "clock_gettime() failed: errno %d, %s\n", errno, strerror(errno)); double diff_ns = (end_time.tv_sec - start_time.tv_sec) * 1000000000 + (end_time.tv_nsec - start_time.tv_nsec); static double average = 0.0; - average = (average * 0.98) + ( nsamps / (diff_ns / 1e9) * 0.02); + average = (average * 0.98) + (nsamps / (diff_ns / 1e9) * 0.02); static int calls = 0; if (calls++ % 10000 == 0) { LOG_D(HW, "Rfsimulator: velocity %.2f Msps, realtime requirements %.2f Msps\n", average / 1e6, t->sample_rate / 1e6); } *ptimestamp = t->nextRxTstamp; // return the time of the first sample - t->nextRxTstamp+=nsamps; + t->nextRxTstamp += nsamps; LOG_D(HW, "Rx to upper layer: %d from %ld to %ld, energy in first antenna %d\n", nsamps, *ptimestamp, t->nextRxTstamp, signal_energy(samplesVoid[0], nsamps)); + + /* trace only first antenna */ + T(T_USRP_RX_ANT0, T_INT(t->nextRxTstamp), T_BUFFER(samplesVoid[0], sampleToByte(nsamps, 1))); + return nsamps; } @@ -1083,10 +1083,10 @@ static int rfsimulator_reset_stats(openair0_device *device) { return 0; } static void rfsimulator_end(openair0_device *device) { - rfsimulator_state_t* s = device->priv; + rfsimulator_state_t *s = device->priv; for (int i = 0; i < MAX_FD_RFSIMU; i++) { buffer_t *b = &s->buf[i]; - if (b->conn_sock >= 0 ) + if (b->conn_sock >= 0) removeCirBuf(s, b); } close(s->epollfd); @@ -1094,7 +1094,7 @@ static void rfsimulator_end(openair0_device *device) { } static void stopServer(openair0_device *device) { - rfsimulator_state_t *t = (rfsimulator_state_t *) device->priv; + rfsimulator_state_t *t = (rfsimulator_state_t *)device->priv; DevAssert(t != NULL); close(t->listen_sock); rfsimulator_end(device); @@ -1104,7 +1104,7 @@ static int rfsimulator_stop(openair0_device *device) { return 0; } static int rfsimulator_set_freq(openair0_device *device, openair0_config_t *openair0_cfg) { - rfsimulator_state_t* s = device->priv; + rfsimulator_state_t *s = device->priv; s->rx_freq = openair0_cfg->rx_freq[0]; return 0; } @@ -1121,11 +1121,11 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { // --log_config.hw_log_level debug rfsimulator_state_t *rfsimulator = calloc(sizeof(rfsimulator_state_t), 1); // initialize channel simulation - rfsimulator->tx_num_channels=openair0_cfg->tx_num_channels; - rfsimulator->rx_num_channels=openair0_cfg->rx_num_channels; - rfsimulator->sample_rate=openair0_cfg->sample_rate; - rfsimulator->rx_freq=openair0_cfg->rx_freq[0]; - rfsimulator->tx_bw=openair0_cfg->tx_bw; + rfsimulator->tx_num_channels = openair0_cfg->tx_num_channels; + rfsimulator->rx_num_channels = openair0_cfg->rx_num_channels; + rfsimulator->sample_rate = openair0_cfg->sample_rate; + rfsimulator->rx_freq = openair0_cfg->rx_freq[0]; + rfsimulator->tx_bw = openair0_cfg->tx_bw; rfsimulator_readconfig(rfsimulator); if (rfsimulator->prop_delay_ms > 0.0) rfsimulator->chan_offset = ceil(rfsimulator->sample_rate * rfsimulator->prop_delay_ms / 1000); @@ -1137,29 +1137,29 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { rfsimulator->prop_delay_ms = rfsimulator->chan_offset * 1000 / rfsimulator->sample_rate; LOG_I(HW, "propagation delay %f ms, %lu samples\n", rfsimulator->prop_delay_ms, rfsimulator->chan_offset); } - pthread_mutex_init(&Sockmutex, NULL); + mutexinit(rfsimulator->Sockmutex); LOG_I(HW, "Running as %s\n", rfsimulator->role == SIMU_ROLE_SERVER ? "server waiting opposite rfsimulators to connect" : "client: will connect to a rfsimulator server side"); device->trx_start_func = rfsimulator->role == SIMU_ROLE_SERVER ? startServer : startClient; - device->trx_get_stats_func = rfsimulator_get_stats; + device->trx_get_stats_func = rfsimulator_get_stats; device->trx_reset_stats_func = rfsimulator_reset_stats; - device->trx_end_func = rfsimulator->role == SIMU_ROLE_SERVER ? stopServer : rfsimulator_end; - device->trx_stop_func = rfsimulator_stop; - device->trx_set_freq_func = rfsimulator_set_freq; - device->trx_set_gains_func = rfsimulator_set_gains; - device->trx_write_func = rfsimulator_write; - device->trx_read_func = rfsimulator_read; + device->trx_end_func = rfsimulator->role == SIMU_ROLE_SERVER ? stopServer : rfsimulator_end; + device->trx_stop_func = rfsimulator_stop; + device->trx_set_freq_func = rfsimulator_set_freq; + device->trx_set_gains_func = rfsimulator_set_gains; + device->trx_write_func = rfsimulator_write; + device->trx_read_func = rfsimulator_read; /* let's pretend to be a b2x0 */ device->type = RFSIMULATOR; openair0_cfg[0].rx_gain[0] = 0; - device->openair0_cfg=&openair0_cfg[0]; + device->openair0_cfg = &openair0_cfg[0]; device->priv = rfsimulator; device->trx_write_init = rfsimulator_write_init; for (int i = 0; i < MAX_FD_RFSIMU; i++) - rfsimulator->buf[i].conn_sock=-1; + rfsimulator->buf[i].conn_sock = -1; rfsimulator->next_buf = 0; AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1, "epoll_create1() failed, errno(%d)", errno); @@ -1170,11 +1170,11 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) { add_telnetcmd_func_t addcmd = (add_telnetcmd_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_ADDCMD_FNAME); if (addcmd != NULL) { - rfsimulator->poll_telnetcmdq = (poll_telnetcmdq_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_POLLCMDQ_FNAME); - addcmd("rfsimu",rfsimu_vardef,rfsimu_cmdarray); + rfsimulator->poll_telnetcmdq = (poll_telnetcmdq_func_t)get_shlibmodule_fptr("telnetsrv", TELNET_POLLCMDQ_FNAME); + addcmd("rfsimu", rfsimu_vardef, rfsimu_cmdarray); - for(int i=0; rfsimu_cmdarray[i].cmdfunc != NULL; i++) { - if ( rfsimu_cmdarray[i].qptr != NULL) { + for (int i = 0; rfsimu_cmdarray[i].cmdfunc != NULL; i++) { + if (rfsimu_cmdarray[i].qptr != NULL) { rfsimulator->telnetcmd_qid = rfsimu_cmdarray[i].qptr; break; } diff --git a/radio/vrtsim/CMakeLists.txt b/radio/vrtsim/CMakeLists.txt index 79eb4d88da..998b791653 100644 --- a/radio/vrtsim/CMakeLists.txt +++ b/radio/vrtsim/CMakeLists.txt @@ -1,4 +1,31 @@ -add_library(vrtsim MODULE vrtsim.c noise_device.c) +add_library(noise_device STATIC noise_device.c) +target_link_libraries(noise_device PRIVATE log_headers) + +add_library(vrtsim MODULE vrtsim.c) set_target_properties(vrtsim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor) -add_dependencies(vrtsim generate_T) +target_link_libraries(vrtsim PRIVATE SIMU shm_td_iq_channel actor noise_device log_headers) + +add_boolean_option(OAI_VRTSIM_TAPS_CLIENT OFF "Enable taps client" ON) +if (OAI_VRTSIM_TAPS_CLIENT) + target_link_libraries(vrtsim PRIVATE taps_client) + file(DOWNLOAD + "https://gitlab.eurecom.fr/oai/raytracing-channel-emulator/-/raw/59589ad2a534881810b2aa7dd81e63066245bb8d/server/api/taps.fbs?inline=false" + ${CMAKE_SOURCE_DIR}/taps.fbs + ) + + set(TAPS_IF_PATH ${CMAKE_SOURCE_DIR}/taps.fbs) + set(TAPS_API_HEADER taps_generated.h) + + add_custom_command(OUTPUT ${TAPS_API_HEADER} + COMMAND flatc -c ${TAPS_IF_PATH} + DEPENDS ${TAPS_IF_PATH} + COMMENT "Generating flatbuffers API from ${TAPS_IF_PATH}" + ) + add_library(taps_api INTERFACE) + target_include_directories(taps_api INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) + + add_library(taps_client taps_client.cpp ${TAPS_API_HEADER}) + target_include_directories(taps_client PUBLIC .) + find_package(Flatbuffers REQUIRED) + target_link_libraries(taps_client PUBLIC flatbuffers taps_api SIMU nanomsg) +endif() diff --git a/radio/vrtsim/README.md b/radio/vrtsim/README.md index 71455175c3..2cd90e7886 100644 --- a/radio/vrtsim/README.md +++ b/radio/vrtsim/README.md @@ -4,12 +4,24 @@ This implements a shared memory realtime and near-realtime radio interface. This is performed using `shm_td_iq_channel` which handles the shared memory interface. +# Architecture + +The `vrtsim` architecture follows a server-client model: + +- **Server (gNB)**: On startup, the server writes a file, default location is + `/tmp/vrtsim_connection`. This file contains information required by the client + to establish communication. +- **Client (UE)**: The client reads this file from, verifies its contents, and uses + the provided information to open and connect to the shared memory channel. +- **Shared Memory Channel**: Both server and client use the `shm_td_iq_channel` to + exchange IQ samples and control data in real time or near-real time. + +## Channel modelling: + + # Limitations - Only 1gNB to 1nrUE: gNB as a server, UE as a client. - - Server only accepts connections during device bringup. This means that - restarting the client will not make it reconnect, the server has to be - restarted as well. # Usage @@ -21,5 +33,63 @@ is the default and means realtime. Channel modelling can be enabled by adding `vrtsim.chanmod 1` to the command line and should work the same as channel modelling in rfsimulator, -see rfsimulator [documentation](../rfsimulator/README.md), provided that your -CPU is fast enough. +see rfsimulator [documentation](../rfsimulator/README.md) with a slight difference: +channel modelling is done on transmission instead of reception. To refect this, +the model names are slightly different: the server expects a model named +`server_tx_channel_model` while the client expects a model named `client_tx_channel_model` + +Additionally, `taps_client` is available in vrtsim. This allows to connect to +channel emulation server and receive external taps (or channel impulse responses). +To use external taps, use `--taps-socket` and provide a nanomsg PUB socket address +that will publish the taps. + +# Debugging + +## Realtime issues + +Realtime issues can prevent the UE from connecting to the gNB, especially with +channel modelling enabled. Consider adjusting `timescale` parameter until +the UE can connect reliably. + +On exit, vrtsim will output a histogram of the measured transmission budget, which +is defined as the number of microseconds before the transmitted samples could be +read by peer. + +Example: + +``` +[HW] VRTSIM: Average TX budget 939.210 uS (more is better) +[HW] VRTSIM: TX budget histogram: 216 samples +[HW] Bin 0 [0.0 - 100.0uS]: 0 +[HW] Bin 1 [100.0 - 200.0uS]: 0 +[HW] Bin 2 [200.0 - 300.0uS]: 0 +[HW] Bin 3 [300.0 - 400.0uS]: 0 +[HW] Bin 4 [400.0 - 500.0uS]: 0 +[HW] Bin 5 [500.0 - 600.0uS]: 0 +[HW] Bin 6 [600.0 - 700.0uS]: 0 +[HW] Bin 7 [700.0 - 800.0uS]: 0 +[HW] Bin 8 [800.0 - 900.0uS]: 0 +[HW] Bin 9 [900.0 - 1000.0uS]: 117 +[HW] Bin 10 [1000.0 - 1100.0uS]: 0 +[HW] Bin 11 [1100.0 - 1200.0uS]: 0 +[HW] Bin 12 [1200.0 - 1300.0uS]: 0 +[HW] Bin 13 [1300.0 - 1400.0uS]: 0 +[HW] Bin 14 [1400.0 - 1500.0uS]: 0 +[HW] Bin 15 [1500.0 - 1600.0uS]: 0 +[HW] Bin 16 [1600.0 - 1700.0uS]: 0 +[HW] Bin 17 [1700.0 - 1800.0uS]: 0 +[HW] Bin 18 [1800.0 - 1900.0uS]: 0 +[HW] Bin 19 [1900.0 - 2000.0uS]: 0 +[HW] Bin 20 [2000.0 - 2100.0uS]: 0 +[HW] Bin 21 [2100.0 - 2200.0uS]: 0 +[HW] Bin 22 [2200.0 - 2300.0uS]: 0 +[HW] Bin 23 [2300.0 - 2400.0uS]: 0 +[HW] Bin 24 [2400.0 - 2500.0uS]: 0 +[HW] Bin 25 [2500.0 - 2600.0uS]: 0 +[HW] Bin 26 [2600.0 - 2700.0uS]: 0 +[HW] Bin 27 [2700.0 - 2800.0uS]: 0 +[HW] Bin 28 [2800.0 - 2900.0uS]: 0 +[HW] Bin 29 [2900.0 - 3000.0uS]: 0 +``` + +Samples in bin 0 indicate realtime issues. diff --git a/radio/vrtsim/noise_device.c b/radio/vrtsim/noise_device.c index 2e15944d4a..acb3a2b5da 100644 --- a/radio/vrtsim/noise_device.c +++ b/radio/vrtsim/noise_device.c @@ -18,6 +18,7 @@ * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ +#include "assertions.h" #include #include #include "noise_device.h" @@ -74,7 +75,8 @@ void init_noise_device(float noise_power) void free_noise_device(void) { state.running = false; - pthread_join(state.noise_device_thread, NULL); + int ret = pthread_join(state.noise_device_thread, NULL); + AssertFatal(ret == 0, "pthread_join failed: %d, errno %d (%s)\n", ret, errno, strerror(errno)); } void get_noise_vector(float *noise_vector, int length) diff --git a/radio/vrtsim/taps_client.cpp b/radio/vrtsim/taps_client.cpp new file mode 100644 index 0000000000..c314c3981c --- /dev/null +++ b/radio/vrtsim/taps_client.cpp @@ -0,0 +1,203 @@ +/* + * 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 +#include +#include +#include +#include +#include "pthread.h" +#include "taps_generated.h" +#include "SIMULATION/TOOLS/sim.h" +extern "C" { +#include "assertions.h" +#include "common/utils/LOG/log.h" +#include "sim.h" +#include "utils.h" +} +#include + +#define NUM_TAPS_BUFFERS 4 +#define MAX_TAPS_LEN 100 +#define MAX_TAPS_MSG_SIZE (sizeof(struct complexf) * MAX_TAPS_LEN * 4 * 4 + 20) + +static pthread_t client_thread; +static bool should_run = true; +typedef struct { + int id; + int sock; + uint32_t num_tx_antennas; + uint32_t num_rx_antennas; + channel_desc_t **channel_desc; +} client_thread_args_t; + +typedef struct { + void *taps_msg; + channel_desc_t *channel_desc; +} taps_buffer_t; + +typedef struct { + taps_buffer_t taps_buffers[NUM_TAPS_BUFFERS]; + int current_buffer; +} taps_storage_t; + +void ascii_line_plot(const float *data, size_t size, char *buffer) +{ + const char levels[] = "_.-=#"; // ASCII characters for different levels + size_t num_levels = sizeof(levels) - 1; // Number of levels (excluding the null terminator) + + // Calculate min and max values from the data + float min_val = FLT_MAX; + float max_val = FLT_MIN; + for (size_t i = 0; i < size; i++) { + if (data[i] < min_val) + min_val = data[i]; + if (data[i] > max_val) + max_val = data[i]; + } + + // Handle edge case where all values are the same + if (min_val == max_val) { + min_val -= 1.0f; + max_val += 1.0f; + } + + // Normalize and map data to levels + for (size_t i = 0; i < size; i++) { + float normalized = (data[i] - min_val) / (max_val - min_val); // Normalize to [0, 1] + size_t level_index = (size_t)(normalized * num_levels); // Map to level index + if (level_index > num_levels) + level_index = num_levels; // Clamp to valid range + snprintf(buffer + i, 2, "%c", levels[level_index]); + } +} + +static void init_taps_storage(taps_storage_t *storage, int num_tx_antennas, int num_rx_antennas) +{ + for (int i = 0; i < NUM_TAPS_BUFFERS; i++) { + storage->taps_buffers[i].taps_msg = calloc_or_fail(1, MAX_TAPS_MSG_SIZE); + storage->taps_buffers[i].channel_desc = (channel_desc_t *)calloc_or_fail(1, sizeof(channel_desc_t)); + storage->taps_buffers[i].channel_desc->ch_ps = + (struct complexf **)calloc_or_fail(num_rx_antennas * num_tx_antennas, sizeof(struct complexf *)); + } + storage->current_buffer = 0; +} + +static taps_storage_t taps_storage; + +void *client_thread_func(void *args) +{ + client_thread_args_t *client_thread_args = (client_thread_args_t *)args; + while (should_run) { + int next_buffer = (taps_storage.current_buffer + 1) % NUM_TAPS_BUFFERS; + taps_buffer_t *taps_buffer = &taps_storage.taps_buffers[next_buffer]; + int ret = nn_recv(client_thread_args->sock, taps_buffer->taps_msg, MAX_TAPS_MSG_SIZE, NN_DONTWAIT); + if (ret < 0) { + if (errno == EAGAIN) { + // Timeout: no message available, sleep briefly and continue + usleep(100); + continue; + } + LOG_E(HW, "nn_recv() failed: errno: %d, %s\n", errno, strerror(errno)); + continue; + } + auto taps_message = Phy::GetTaps(taps_buffer->taps_msg); + if (taps_message->num_rx_antennas() != client_thread_args->num_rx_antennas + || taps_message->num_tx_antennas() != client_thread_args->num_tx_antennas) { + LOG_E(HW, + "Number of antennas mismatch: expected %d x %d, got %d x %d\n", + client_thread_args->num_rx_antennas, + client_thread_args->num_tx_antennas, + taps_message->num_rx_antennas(), + taps_message->num_tx_antennas()); + continue; + } + channel_desc_t *channel_desc = taps_buffer->channel_desc; + const flatbuffers::Vector *taps = taps_message->taps(); + struct complexf *base_pointer = (struct complexf *)taps->data(); + int taps_len = taps_message->taps_len(); + AssertFatal(taps_len < MAX_TAPS_LEN, "Too many samples in the taps array, taps_len = %d\n", taps_len); + for (unsigned int aarx = 0U; aarx < client_thread_args->num_rx_antennas; aarx++) { + for (unsigned int aatx = 0U; aatx < client_thread_args->num_tx_antennas; aatx++) { + channel_desc->ch_ps[aarx + (client_thread_args->num_rx_antennas * aatx)] = + &base_pointer[(aarx + (client_thread_args->num_rx_antennas * aatx)) * taps_len]; + } + } + channel_desc->path_loss_dB = 0; + channel_desc->channel_length = taps_len; + *client_thread_args->channel_desc = channel_desc; + taps_storage.current_buffer = next_buffer; + LOG_A(HW, "Receved new taps message, channel_length %d, buffer %d\n", channel_desc->channel_length, next_buffer); + for (unsigned int aarx = 0; aarx < client_thread_args->num_rx_antennas; aarx++) { + for (unsigned int aatx = 0; aatx < client_thread_args->num_tx_antennas; aatx++) { + char buffer[MAX_TAPS_LEN + 1]; + memset(buffer, 0, sizeof(buffer)); + float magnitudes[MAX_TAPS_LEN]; + cf_t *channel = channel_desc->ch_ps[aarx + (client_thread_args->num_rx_antennas * aatx)]; + for (int i = 0; i < channel_desc->channel_length; i++) { + magnitudes[i] = sqrtf(powf(channel[i].r, 2) + powf(channel[i].i, 2)); + } + ascii_line_plot(magnitudes, channel_desc->channel_length, buffer); + LOG_A(HW, "Taps message %d, channel %d x %d: %s\n", client_thread_args->id, aarx, aatx, buffer); + } + } + } + return NULL; +} + +extern "C" void taps_client_connect(int id, + const char *socket_path, + int num_tx_antennas, + int num_rx_antennas, + channel_desc_t **channel_desc) +{ + // Create a socket + int sock = nn_socket(AF_SP, NN_SUB); + AssertFatal(sock >= 0, "nn_socket() failed: errno: %d, %s\n", errno, strerror(errno)); + + int ret = nn_connect(sock, socket_path); + AssertFatal(ret >= 0, "nn_connect() failed: errno: %d, %s\n", errno, strerror(errno)); + + // Subscribe to all messages + ret = nn_setsockopt(sock, NN_SUB, NN_SUB_SUBSCRIBE, "", 0); + AssertFatal(ret == 0, "nn_setsockopt() failed, errno %d, %s\n", errno, strerror(errno)); + + init_taps_storage(&taps_storage, num_tx_antennas, num_rx_antennas); + + client_thread_args_t *client_thread_args = static_cast(malloc(sizeof(client_thread_args_t))); + client_thread_args->id = id; + client_thread_args->sock = sock; + client_thread_args->num_rx_antennas = num_rx_antennas; + client_thread_args->num_tx_antennas = num_tx_antennas; + client_thread_args->channel_desc = channel_desc; + ret = pthread_create(&client_thread, NULL, client_thread_func, client_thread_args); + AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); +} + +extern "C" void taps_client_stop() +{ + should_run = false; + pthread_join(client_thread, NULL); + for (int i = 0; i < NUM_TAPS_BUFFERS; i++) { + free(taps_storage.taps_buffers[i].taps_msg); + free(taps_storage.taps_buffers[i].channel_desc->ch_ps); + free(taps_storage.taps_buffers[i].channel_desc); + } +} diff --git a/openair3/S1AP/s1ap_common.c b/radio/vrtsim/taps_client.h similarity index 75% rename from openair3/S1AP/s1ap_common.c rename to radio/vrtsim/taps_client.h index d31c6e5839..c0a577c787 100644 --- a/openair3/S1AP/s1ap_common.c +++ b/radio/vrtsim/taps_client.h @@ -19,23 +19,20 @@ * contact@openairinterface.org */ -/*! \file s1ap_common.c - * \brief s1ap procedures for both eNB and MME - * \author Sebastien ROUX and Navid Nikaein - * \email navid.nikaein@eurecom.fr - * \date 2012-2015 - * \version 0.1 - */ +#ifndef TAPS_CLIENT_H +#define TAPS_CLIENT_H -#include +#ifdef __cplusplus +extern "C" { +#endif -#include "s1ap_common.h" -#include "S1AP_S1AP-PDU.h" +#include "sim.h" +void taps_client_connect(int id, const char *socket_path, int num_tx_antennas, int num_rx_antennas, channel_desc_t **channel_desc); +void taps_client_stop(); -int asn1_xer_print = 0; - - -void s1ap_handle_criticality(S1AP_Criticality_t criticality) -{ +#ifdef __cplusplus } +#endif + +#endif diff --git a/radio/vrtsim/vrtsim.c b/radio/vrtsim/vrtsim.c index f0e0151aa6..9e678a5305 100644 --- a/radio/vrtsim/vrtsim.c +++ b/radio/vrtsim/vrtsim.c @@ -19,6 +19,7 @@ * contact@openairinterface.org */ +#include "PHY/TOOLS/tools_defs.h" #include #include #include @@ -34,6 +35,7 @@ #include #include #include +#include #include #include @@ -46,11 +48,13 @@ #include "actor.h" #include "noise_device.h" #include "simde/x86/avx512.h" +#include "taps_client.h" // Simulator role typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; -#define NUM_CHANMOD_THREADS 1 +#define MAX_NUM_ANTENNAS_TX 4 +#define MAX_CHANNEL_LENGTH (1 << 20) #define ROLE_CLIENT_STRING "client" #define ROLE_SERVER_STRING "server" @@ -58,14 +62,21 @@ typedef enum { ROLE_SERVER = 1, ROLE_CLIENT } role; #define VRTSIM_SECTION "vrtsim" #define TIME_SCALE_HLP \ "sample time scale. 1.0 means realtime. Values > 1 mean faster than realtime. Values < 1 mean slower than realtime\n" +#define TAPS_SOCKET_HLP "Socket to connect to the channel emulation server\n" +#define CLIENT_NUM_RX_HLP "Number of RX antennas of the client, specified on the server\n" +#define CONNECTION_DESCRIPTOR_HLP "Path to the file written by the server that the client can use to connect." +#define DEFAULT_CHANNEL_NAME "vrtsim_channel" +#define DEFAULT_DESCRIPTOR "/tmp/vrtsim_connection" // clang-format off #define VRTSIM_PARAMS_DESC \ { \ - {"channel_name", "shared memory channel name\n", 0, .strptr = &channel_name, .defstrval = "vrtsim_channel", TYPE_STRING, 0}, \ - {"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \ - {"timescale", TIME_SCALE_HLP, 0, .dblptr = &vrtsim_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \ - {"chanmod", "Enable channel modelling", 0, .iptr = &vrtsim_state->chanmod, .defintval = 0, TYPE_INT, 0}, \ + {"connection_descriptor", CONNECTION_DESCRIPTOR_HLP, 0, .strptr = &vrtsim_state->connection_descriptor, .defstrval = DEFAULT_DESCRIPTOR, TYPE_STRING, 0}, \ + {"role", "either client or server\n", 0, .strptr = &role, .defstrval = ROLE_CLIENT_STRING, TYPE_STRING, 0}, \ + {"timescale", TIME_SCALE_HLP, 0, .dblptr = &vrtsim_state->timescale, .defdblval = 1.0, TYPE_DOUBLE, 0}, \ + {"chanmod", "Enable channel modelling", 0, .iptr = &vrtsim_state->chanmod, .defintval = 0, TYPE_INT, 0}, \ + {"taps-socket", TAPS_SOCKET_HLP, 0, .strptr = &vrtsim_state->taps_socket, .defstrval = NULL, TYPE_STRING, 0}, \ + {"client-num-rx-antennas", CLIENT_NUM_RX_HLP, 0, .iptr = &vrtsim_state->client_num_rx_antennas, .defintval = 1, TYPE_INT, 0}, \ }; // clang-format on @@ -91,7 +102,7 @@ typedef struct tx_timing_s { typedef struct { int role; - char channel_name[40]; + char *connection_descriptor; ShmTDIQChannel *channel; uint64_t last_received_sample; pthread_t timing_thread; @@ -110,8 +121,13 @@ typedef struct { int rx_num_channels; channel_desc_t *channel_desc; Actor_t *channel_modelling_actors; + char *taps_socket; + int client_num_rx_antennas; } vrtsim_state_t; +// Sample history for channel impulse response +static c16_t saved_samples[MAX_NUM_ANTENNAS_TX][MAX_CHANNEL_LENGTH] __attribute__((aligned(32))) = {0}; + static void histogram_add(histogram_t *histogram, double diff) { histogram->num_samples++; @@ -149,18 +165,26 @@ static void load_channel_model(vrtsim_state_t *vrtsim_state) vrtsim_state->tx_bw); char *model_name = vrtsim_state->role == ROLE_CLIENT ? "client_tx_channel_model" : "server_tx_channel_model"; vrtsim_state->channel_desc = find_channel_desc_fromname(model_name); + AssertFatal(vrtsim_state->channel_desc != NULL, + "Could not find model name %s. Make sure it is present in the config file", + model_name); + LOG_I(HW, + "Channel model %s parameters: path_loss_dB=%.2f, nb_tx=%d, nb_rx=%d, channel_length=%d\n", + model_name, + vrtsim_state->channel_desc->path_loss_dB, + vrtsim_state->channel_desc->nb_tx, + vrtsim_state->channel_desc->nb_rx, + vrtsim_state->channel_desc->channel_length); random_channel(vrtsim_state->channel_desc, 0); AssertFatal(vrtsim_state->channel_desc != NULL, "Could not find channel model %s\n", model_name); } static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state) { - char *channel_name = NULL; char *role = NULL; paramdef_t vrtsim_params[] = VRTSIM_PARAMS_DESC; int ret = config_get(config_get_if(), vrtsim_params, sizeofArray(vrtsim_params), VRTSIM_SECTION); AssertFatal(ret >= 0, "configuration couldn't be performed\n"); - strncpy(vrtsim_state->channel_name, channel_name, sizeof(vrtsim_state->channel_name) - 1); if (strncmp(role, ROLE_CLIENT_STRING, strlen(ROLE_CLIENT_STRING)) == 0) { vrtsim_state->role = ROLE_CLIENT; } else if (strncmp(role, ROLE_SERVER_STRING, strlen(ROLE_SERVER_STRING)) == 0) { @@ -168,6 +192,15 @@ static void vrtsim_readconfig(vrtsim_state_t *vrtsim_state) } else { AssertFatal(false, "Invalid role configuration\n"); } +#ifdef ENABLE_TAPS_CLIENT + if (vrtsim_state->taps_socket) { + LOG_A(HW, "VRTSIM: will use taps socket %s\n", vrtsim_state->taps_socket); + } +#else + if (vrtsim_state->taps_socket) { + AssertFatal(false, "Invalid configuration: Build with ENABLE_TAPS_CLIENT to use taps socket\n"); + } +#endif } static void *vrtsim_timing_job(void *arg) @@ -195,128 +228,105 @@ static void *vrtsim_timing_job(void *arg) samples_to_produce += 1; leftover_samples -= 1; } + AssertFatal(samples_to_produce >= 0, "Negative samples to produce: %f\n", samples_to_produce); shm_td_iq_channel_produce_samples(vrtsim_state->channel, samples_to_produce); usleep(1); } return 0; } +typedef struct client_info_s { + int server_num_rx_antennas; + int client_num_rx_antennas; +} client_info_t; + /** - * @brief Exchanges peer information between the server and the client. + * @brief Publishes the client information information to a file for the client to read. * - * This function sets up a Unix domain socket server, waits for a client to connect, - * and exchanges peer information (number of RX antennas) with the client. + * The server writes its client_info (number of RX antennas) to a file, which the client reads. + * The server does not wait for the client to write back; the client can connect at any point. * - * @param peer_info The peer information to send to the client. - * @return The peer information received from the client. - * - * @note This function will block until a client connects and the information is exchanged. + * @param client_info The client information to publish. + * @return The peer information (same as input, server is authoritative). */ -static peer_info_t server_exchange_peer_info(peer_info_t peer_info) +static void server_publish_client_info(client_info_t client_info, char *descriptor_file) { - int server_fd, client_fd; - - // Create a Unix domain socket - server_fd = socket(AF_UNIX, SOCK_STREAM, 0); - AssertFatal(server_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno)); - - // Bind the socket to a file path - struct sockaddr_un addr = {.sun_family = AF_UNIX}; - strncpy(addr.sun_path, "/tmp/vrtsim_socket", sizeof(addr.sun_path) - 1); - unlink(addr.sun_path); // Ensure the path does not already exist - int ret = bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)); - AssertFatal(ret == 0, "bind() failed: errno: %d, %s\n", errno, strerror(errno)); - - // Listen for incoming connections - ret = listen(server_fd, 1); - AssertFatal(ret == 0, "listen() failed: errno: %d, %s\n", errno, strerror(errno)); - - // Accept a connection from a client - socklen_t addr_len = sizeof(addr); - client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); - AssertFatal(client_fd >= 0, "accept() failed: errno: %d, %s\n", errno, strerror(errno)); - - // Send the antenna info to the server - ssize_t bytes_sent = send(client_fd, &peer_info, sizeof(peer_info), 0); - AssertFatal(bytes_sent == sizeof(peer_info), "send() failed: errno: %d, %s\n", errno, strerror(errno)); - - ssize_t bytes_received = recv(client_fd, &peer_info, sizeof(peer_info), 0); - AssertFatal(bytes_received == sizeof(peer_info), "recv() failed: errno: %d, %s\n", errno, strerror(errno)); - - LOG_I(HW, "Received client info: RX %d\n", peer_info.num_rx_antennas); - - // Close the client and server sockets - close(client_fd); - close(server_fd); - return peer_info; + FILE *fp = fopen(descriptor_file, "wb"); + AssertFatal(fp != NULL, "Failed to open client info file for writing: %s\n", strerror(errno)); + size_t written = fwrite(&client_info, sizeof(client_info), 1, fp); + AssertFatal(written == 1, "Failed to write client info to file\n"); + fclose(fp); } -/** - * @brief Exchanges peer information between the client and the server. - * - * This function connects to a Unix domain socket server, exchanges peer information - * (number of RX antennas) with the server, and returns the peer information received - * from the server. - * - * @param peer_info The peer information to send to the server. - * @return The peer information received from the server. - * - * @note This function will block until the information is exchanged. - */ -static peer_info_t client_exchange_peer_info(peer_info_t peer_info) +static client_info_t client_read_info(char *descriptor_file) { - int client_fd; - - // Create a Unix domain socket - client_fd = socket(AF_UNIX, SOCK_STREAM, 0); - AssertFatal(client_fd >= 0, "socket() failed: errno: %d, %s\n", errno, strerror(errno)); - - // Connect to the server - struct sockaddr_un addr = {.sun_family = AF_UNIX}; - strncpy(addr.sun_path, "/tmp/vrtsim_socket", sizeof(addr.sun_path) - 1); - int ret = -1; + client_info_t client_info; int tries = 0; - while (ret != 0 && tries < 10) { - ret = connect(client_fd, (struct sockaddr *)&addr, sizeof(addr)); - tries++; + while (tries < 10) { + FILE *fp = fopen(descriptor_file, "rb"); + if (fp) { + size_t read = fread(&client_info, sizeof(client_info), 1, fp); + fclose(fp); + if (read == 1) { + return client_info; + } + } sleep(1); + tries++; } - AssertFatal(ret == 0, "connect() failed: errno: %d, %s\n", errno, strerror(errno)); - - peer_info_t peer_info_received; - ssize_t bytes_received = recv(client_fd, &peer_info_received, sizeof(peer_info_received), 0); - AssertFatal(bytes_received == sizeof(peer_info_received), "recv() failed: errno: %d, %s\n", errno, strerror(errno)); - - // Send the antenna info to the server - ssize_t bytes_sent = send(client_fd, &peer_info, sizeof(peer_info), 0); - AssertFatal(bytes_sent == sizeof(peer_info), "send() failed: errno: %d, %s\n", errno, strerror(errno)); - - LOG_I(HW, "Received peer info: RX %d\n", peer_info_received.num_rx_antennas); - - // Close the client socket - close(client_fd); - return peer_info_received; + AssertFatal(0, "Timeout waiting for client info\n"); + return client_info; } static int vrtsim_connect(openair0_device *device) { vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; - // Exchange peer info - peer_info_t peer_info = {.num_rx_antennas = device->openair0_cfg[0].rx_num_channels}; + + // Setup a shared memory channel if (vrtsim_state->role == ROLE_SERVER) { - vrtsim_state->peer_info = server_exchange_peer_info(peer_info); + vrtsim_state->peer_info.num_rx_antennas = vrtsim_state->client_num_rx_antennas; + vrtsim_state->channel = shm_td_iq_channel_create(DEFAULT_CHANNEL_NAME, + vrtsim_state->peer_info.num_rx_antennas, + device->openair0_cfg[0].rx_num_channels); + // Exchange peer info + client_info_t client_info = { + .server_num_rx_antennas = device->openair0_cfg[0].rx_num_channels, + .client_num_rx_antennas = vrtsim_state->client_num_rx_antennas, + }; + server_publish_client_info(client_info, vrtsim_state->connection_descriptor); + + vrtsim_state->run_timing_thread = true; + int ret = pthread_create(&vrtsim_state->timing_thread, NULL, vrtsim_timing_job, vrtsim_state); + AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); } else { - vrtsim_state->peer_info = client_exchange_peer_info(peer_info); + client_info_t client_info = client_read_info(vrtsim_state->connection_descriptor); + AssertFatal(client_info.server_num_rx_antennas > 0, "Server did not publish valid client info, aborting client connection\n"); + AssertFatal( + client_info.client_num_rx_antennas == device->openair0_cfg[0].rx_num_channels, + "Server expects different number of RX antennas. %d != %d. Use server command line option --client-num-rx-antennas\n", + client_info.client_num_rx_antennas, + device->openair0_cfg[0].rx_num_channels); + vrtsim_state->channel = shm_td_iq_channel_connect(DEFAULT_CHANNEL_NAME, 10); + vrtsim_state->peer_info.num_rx_antennas = client_info.server_num_rx_antennas; + vrtsim_state->last_received_sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel); } // Handle channel modelling after number of RX antennas are known int num_tx_stats = 1; - if (vrtsim_state->chanmod) { + if (vrtsim_state->chanmod || vrtsim_state->taps_socket) { vrtsim_state->channel_modelling_actors = calloc_or_fail(vrtsim_state->peer_info.num_rx_antennas, sizeof(Actor_t)); for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) { init_actor(&vrtsim_state->channel_modelling_actors[i], "chanmod", -1); } - load_channel_model(vrtsim_state); + if (vrtsim_state->taps_socket) { + taps_client_connect(0, + vrtsim_state->taps_socket, + device->openair0_cfg[0].tx_num_channels, + vrtsim_state->peer_info.num_rx_antennas, + &vrtsim_state->channel_desc); + } else { + load_channel_model(vrtsim_state); + } num_tx_stats = vrtsim_state->peer_info.num_rx_antennas; } vrtsim_state->tx_timing = calloc_or_fail(num_tx_stats, sizeof(tx_timing_t)); @@ -326,22 +336,6 @@ static int vrtsim_connect(openair0_device *device) vrtsim_state->tx_timing[i].tx_histogram.range = 3000.0; } - // Setup a shared memory channel - if (vrtsim_state->role == ROLE_SERVER) { - vrtsim_state->channel = shm_td_iq_channel_create(vrtsim_state->channel_name, - vrtsim_state->peer_info.num_rx_antennas, - device->openair0_cfg[0].rx_num_channels); - vrtsim_state->run_timing_thread = true; - while (!shm_td_iq_channel_is_connected(vrtsim_state->channel)) { - LOG_I(HW, "Waiting for client\n"); - sleep(1); - } - int ret = pthread_create(&vrtsim_state->timing_thread, NULL, vrtsim_timing_job, vrtsim_state); - AssertFatal(ret == 0, "pthread_create() failed: errno: %d, %s\n", errno, strerror(errno)); - } else { - vrtsim_state->channel = shm_td_iq_channel_connect(vrtsim_state->channel_name, 10); - } - return 0; } @@ -376,7 +370,7 @@ static int vrtsim_write_internal(vrtsim_state_t *vrtsim_state, typedef struct { vrtsim_state_t *vrtsim_state; openair0_timestamp timestamp; - c16_t *samples[4]; + c16_t *samples[MAX_NUM_ANTENNAS_TX]; int nsamps; int nbAnt; int flags; @@ -386,6 +380,7 @@ typedef struct { static void perform_channel_modelling(void *arg) { channel_modelling_args_t *channel_modelling_args = arg; + vrtsim_state_t *vrtsim_state = channel_modelling_args->vrtsim_state; int nsamps = channel_modelling_args->nsamps; int aarx = channel_modelling_args->aarx; int nb_tx_ant = channel_modelling_args->nbAnt; @@ -396,31 +391,43 @@ static void perform_channel_modelling(void *arg) // Apply noise from global settings get_noise_vector((float *)samples, nsamps * 2); - channel_desc_t *channel_desc = channel_modelling_args->vrtsim_state->channel_desc; - const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0); + channel_desc_t *channel_desc = vrtsim_state->channel_desc; + + if (channel_desc == NULL) { + return; + } - // Convert channel impulse response to float + apply pathloss cf_t channel_impulse_response[nb_tx_ant][channel_desc->channel_length]; - for (int aatx = 0; aatx < nb_tx_ant; aatx++) { - const struct complexd *channelModel = channel_desc->ch[aarx + (aatx * channel_desc->nb_rx)]; - for (int i = 0; i < channel_desc->channel_length; i++) { - channel_impulse_response[aatx][i].r = channelModel[i].r * pathloss_linear; - channel_impulse_response[aatx][i].i = channelModel[i].i * pathloss_linear; + cf_t *channel_impulse_response_p[nb_tx_ant]; + if (!vrtsim_state->taps_socket) { + const float pathloss_linear = powf(10, channel_desc->path_loss_dB / 20.0); + // Convert channel impulse response to float + apply pathloss + for (int aatx = 0; aatx < nb_tx_ant; aatx++) { + const struct complexd *channelModel = channel_desc->ch[aarx + (aatx * channel_desc->nb_rx)]; + for (int i = 0; i < channel_desc->channel_length; i++) { + channel_impulse_response[aatx][i].r = channelModel[i].r * pathloss_linear; + channel_impulse_response[aatx][i].i = channelModel[i].i * pathloss_linear; + } + channel_impulse_response_p[aatx] = channel_impulse_response[aatx]; + } + } else { + for (int aatx = 0; aatx < nb_tx_ant; aatx++) { + struct complexf *channelModel = channel_desc->ch_ps[aarx + (aatx * channel_desc->nb_rx)]; + channel_impulse_response_p[aatx] = channelModel; } } for (int aatx = 0; aatx < nb_tx_ant; aatx++) { + c16_t *previous_samples = saved_samples[aatx]; for (int i = 0; i < nsamps; i++) { - cf_t *impulse_response = channel_impulse_response[aatx]; + cf_t *impulse_response = channel_impulse_response_p[aatx]; for (int l = 0; l < channel_desc->channel_length; l++) { int idx = i - l; - // TODO: Use AVX512 for this - // TODO: What are the previously sent samples (for impulse response) - if (idx >= 0) { - c16_t tx_input = input_samples[aatx][idx]; - samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i; - samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i; - } + // TODO: Use AVX2 for this + c16_t tx_input = idx >= 0 ? input_samples[aatx][idx] + : previous_samples[(channel_modelling_args->timestamp + i + idx) % MAX_CHANNEL_LENGTH]; + samples[i].r += tx_input.r * impulse_response[l].r - tx_input.i * impulse_response[l].i; + samples[i].i += tx_input.i * impulse_response[l].r + tx_input.r * impulse_response[l].i; } } } @@ -462,6 +469,7 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, int nbAnt, int flags) { + AssertFatal(nbAnt < MAX_NUM_ANTENNAS_TX, "Number of antennas %d exceeds maximum %d\n", nbAnt, MAX_NUM_ANTENNAS_TX); for (int aarx = 0; aarx < vrtsim_state->peer_info.num_rx_antennas; aarx++) { notifiedFIFO_elt_t *task = newNotifiedFIFO_elt(sizeof(channel_modelling_args_t), 0, NULL, perform_channel_modelling); channel_modelling_args_t *args = (channel_modelling_args_t *)NotifiedFifoData(task); @@ -476,21 +484,68 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, } pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task); } + int start_index = timestamp % MAX_CHANNEL_LENGTH; + int end_index = min(start_index + nsamps, MAX_CHANNEL_LENGTH); + int cp_nsamps = end_index - start_index; + for (int aatx = 0; aatx < nbAnt; aatx++) { + c16_t *samples = (c16_t *)samplesVoid[aatx]; + memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps); + } + + if (end_index < start_index + nsamps) { + // wrap around condition, write at beginning of buffer + cp_nsamps = nsamps - cp_nsamps; // remaining samples + start_index = 0; + for (int aatx = 0; aatx < nbAnt; aatx++) { + c16_t *samples = (c16_t *)samplesVoid[aatx]; + memcpy(&saved_samples[aatx][start_index], &samples[0], sizeof(c16_t) * cp_nsamps); + } + } return nsamps; } static int vrtsim_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { + AssertFatal(nsamps > 0, "Number of samples must be greater than 0\n"); + AssertFatal(nbAnt > 0 && nbAnt <= MAX_NUM_ANTENNAS_TX, + "Number of antennas %d must be between 1 and %d\n", + nbAnt, + MAX_NUM_ANTENNAS_TX); + AssertFatal(timestamp >= 0, "Timestamp must be non-negative, got %ld\n", timestamp); timestamp -= device->openair0_cfg->command_line_sample_advance; vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; - return vrtsim_state->chanmod ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags) - : vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0); + bool channel_modelling = vrtsim_state->chanmod || vrtsim_state->taps_socket; + return channel_modelling ? vrtsim_write_with_chanmod(vrtsim_state, timestamp, samplesVoid, nsamps, nbAnt, flags) + : vrtsim_write_internal(vrtsim_state, timestamp, (c16_t *)samplesVoid[0], nsamps, 0, flags, 0); } static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp, void **samplesVoid, int nsamps, int nbAnt) { vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; - shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps); + if (shm_td_iq_channel_is_aborted(vrtsim_state->channel)) { + return 0; + } + if (vrtsim_state->role == ROLE_SERVER) { + uint64_t timeout_uS = 0; // 0 means no timeout + shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps, timeout_uS); + } else { + uint64_t start_sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel); + uint64_t timeout_uS = 2 * 1000 * 1000; // 2 seconds timeout waiting for sample number to change + // + while (shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps, timeout_uS) == 1) { + uint64_t sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel); + if (sample == start_sample) { + LOG_E(HW, + "VRTSIM: Read timeout waiting for sample %lu to change, aborting channel\n", + vrtsim_state->last_received_sample + nsamps); + shm_td_iq_channel_abort(vrtsim_state->channel); + break; + } else { + start_sample = sample; + } + } + } + int ret = shm_td_iq_channel_rx(vrtsim_state->channel, vrtsim_state->last_received_sample, nsamps, 0, samplesVoid[0]); if (ret == CHANNEL_ERROR_TOO_LATE) { vrtsim_state->rx_samples_late += nsamps; @@ -506,14 +561,14 @@ static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp, static void vrtsim_end(openair0_device *device) { vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; - if (vrtsim_state->role == ROLE_SERVER) { + if (vrtsim_state->role == ROLE_SERVER && vrtsim_state->run_timing_thread) { vrtsim_state->run_timing_thread = false; int ret = pthread_join(vrtsim_state->timing_thread, NULL); AssertFatal(ret == 0, "pthread_join() failed: errno: %d, %s\n", errno, strerror(errno)); } tx_timing_t *tx_timing = vrtsim_state->tx_timing; - if (vrtsim_state->chanmod) { + if (vrtsim_state->chanmod || vrtsim_state->taps_socket) { for (int i = 0; i < vrtsim_state->peer_info.num_rx_antennas; i++) { shutdown_actor(&vrtsim_state->channel_modelling_actors[i]); } @@ -526,9 +581,12 @@ static void vrtsim_end(openair0_device *device) tx_timing->tx_samples_total += tx_timing[i].tx_samples_total; } tx_timing->average_tx_budget /= vrtsim_state->peer_info.num_rx_antennas; + free_noise_device(); + if (vrtsim_state->taps_socket) { + taps_client_stop(); + } } - // produce 1 second of extra samples so threads can finish - shm_td_iq_channel_produce_samples(vrtsim_state->channel, vrtsim_state->sample_rate); + shm_td_iq_channel_abort(vrtsim_state->channel); sleep(1); shm_td_iq_channel_destroy(vrtsim_state->channel); @@ -540,9 +598,18 @@ static void vrtsim_end(openair0_device *device) "VRTSIM: Read/write too early (suspected radio implementaton error) TX: %lu, RX: %lu\n", tx_timing->tx_early, vrtsim_state->rx_early); - LOG_I(HW, "VRTSIM: Average TX budget %.3lf uS\n", tx_timing->average_tx_budget); + LOG_I(HW, "VRTSIM: Average TX budget %.3lf uS (more is better)\n", tx_timing->average_tx_budget); histogram_print(&tx_timing->tx_histogram); free(vrtsim_state->tx_timing); + + if (vrtsim_state->role == ROLE_SERVER) { + int ret = remove(vrtsim_state->connection_descriptor); + if (ret != 0) { + LOG_E(HW, "Failed to remove connection descriptor file %s: %s\n", vrtsim_state->connection_descriptor, strerror(errno)); + } else { + LOG_A(HW, "Removed connection descriptor file %s\n", vrtsim_state->connection_descriptor); + } + } } static int vrtsim_stub(openair0_device *device) @@ -588,10 +655,11 @@ __attribute__((__visibility__("default"))) int device_init(openair0_device *devi vrtsim_state->tx_num_channels = openair0_cfg->tx_num_channels; vrtsim_state->rx_num_channels = openair0_cfg->rx_num_channels; - if (vrtsim_state->chanmod) { + if (vrtsim_state->chanmod || vrtsim_state->taps_socket) { init_channelmod(); int noise_power_dBFS = get_noise_power_dBFS(); int16_t noise_power = noise_power_dBFS == INVALID_DBFS_VALUE ? 0 : (int16_t)(32767.0 / powf(10.0, .05 * -noise_power_dBFS)); + LOG_A(HW, "VRTSIM: Noise power %d sample value\n", noise_power); init_noise_device(noise_power); } return 0; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf index ef39165e42..de96c77bcb 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/benetel-5g.conf @@ -85,9 +85,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 2; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/cu.lte.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/cu.lte.conf deleted file mode 100644 index e486be3605..0000000000 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/cu.lte.conf +++ /dev/null @@ -1,196 +0,0 @@ -Active_eNBs = ( "eNB-CU-Eurecom-LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = ( - { - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB-CU-Eurecom-LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = 1; - plmn_list = ( { mcc = 208; mnc = 95; mnc_length = 2; } ) - - nr_cellid = 12345678L - - tr_s_preference = "f1" - - remote_s_address = "192.168.12.4"; - local_s_address = "192.168.12.45"; - local_s_portc = 501; - remote_s_portc = 500; - local_s_portd = 601; - remote_s_portd = 600; - - ////////// Physical parameters: - - component_carriers = ( - { - node_function = "3GPP_eNodeB"; - node_timing = "synch_to_ext_device"; - node_synch_ref = 0; - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2665000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 50; - pbch_repetition = "FALSE"; - prach_root = 0; - prach_config_index = 0; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 1; - prach_freq_offset = 2; - pucch_delta_shift = 1; - pucch_nRB_CQI = 0; - pucch_nCS_AN = 0; - pucch_n1_AN = 0; - pdsch_referenceSignalPower = -27; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 0; - pusch_groupHoppingEnable = "ENABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* - srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =; - */ - - pusch_p0_Nominal = -96; - pusch_alpha = "AL1"; - pucch_p0_Nominal = -104; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 64; - rach_preamblesGroupAConfig = "DISABLE"; - /* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; - */ - rach_powerRampingStep = 4; - rach_preambleInitialReceivedTargetPower = -108; - rach_preambleTransMax = 10; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff= 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - ue_TransmissionMode = 1; - - //Parameters for SIB18 - rxPool_sc_CP_Len = "normal"; - rxPool_sc_Period = "sf40"; - rxPool_data_CP_Len = "normal"; - rxPool_ResourceConfig_prb_Num = 20; - rxPool_ResourceConfig_prb_Start = 5; - rxPool_ResourceConfig_prb_End = 44; - rxPool_ResourceConfig_offsetIndicator_present = "prSmall"; - rxPool_ResourceConfig_offsetIndicator_choice = 0; - rxPool_ResourceConfig_subframeBitmap_present = "prBs40"; - rxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "00000000000000000000"; - rxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; - rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; - /* - rxPool_dataHoppingConfig_hoppingParameter = 0; - rxPool_dataHoppingConfig_numSubbands = "ns1"; - rxPool_dataHoppingConfig_rbOffset = 0; - rxPool_commTxResourceUC-ReqAllowed = "TRUE"; - */ - - // Parameters for SIB19 - discRxPool_cp_Len = "normal" - discRxPool_discPeriod = "rf32" - discRxPool_numRetx = 1; - discRxPool_numRepetition = 2; - discRxPool_ResourceConfig_prb_Num = 5; - discRxPool_ResourceConfig_prb_Start = 3; - discRxPool_ResourceConfig_prb_End = 21; - discRxPool_ResourceConfig_offsetIndicator_present = "prSmall"; - discRxPool_ResourceConfig_offsetIndicator_choice = 0; - discRxPool_ResourceConfig_subframeBitmap_present = "prBs40"; - discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf = "f0ffffffff"; - discRxPool_ResourceConfig_subframeBitmap_choice_bs_size = 5; - discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused = 0; - } - ); - - - srb1_parameters : - { - # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500] - timer_poll_retransmit = 80; - - # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200] - timer_reordering = 35; - - # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500] - timer_status_prohibit = 0; - - # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)] - poll_pdu = 4; - - # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)] - poll_byte = 99999; - - # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32] - max_retx_threshold = 4; - } - - # ------- SCTP definitions - SCTP : - { - # Number of streams to use in input/output - SCTP_INSTREAMS = 2; - SCTP_OUTSTREAMS = 2; - }; - - - ////////// MME parameters: - mme_ip_address = ({ ipv4 = "127.0.1.10"; }); - - NETWORK_INTERFACES : { - ENB_IPV4_ADDRESS_FOR_S1_MME = "127.0.1.30/24"; - ENB_IPV4_ADDRESS_FOR_S1U = "127.0.1.30/24"; - ENB_PORT_FOR_S1U = 2152; # Spec 2152 - ENB_IPV4_ADDRESS_FOR_X2C = "127.0.1.30/24"; - ENB_PORT_FOR_X2C = 36422; # Spec 36422 - }; - } -); - -log_config = { - global_log_level = "info"; - pdcp_log_level = "info"; - rrc_log_level = "info"; - gtp_log_level = "info"; -}; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/du.lte.band7.10MHz.if4p5.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/du.lte.band7.10MHz.if4p5.conf deleted file mode 100644 index f66bc1b29e..0000000000 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/du.lte.band7.10MHz.if4p5.conf +++ /dev/null @@ -1,102 +0,0 @@ -Active_eNBs = ( "eNB-Eurecom-DU"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - ////////// Identification parameters: - eNB_CU_ID = 0xe00; - - eNB_name = "eNB-Eurecom-DU"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = 1; - plmn_list = ( { mcc = 208; mnc = 95; mnc_length = 2; } ) - - nr_cellid = 12345678L - - ////////// Physical parameters: - - component_carriers = ( - { - node_function = "3GPP_eNODEB"; - node_timing = "synch_to_ext_device"; - node_synch_ref = 0; - frame_type = "FDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 7; - downlink_frequency = 2665000000L; - uplink_frequency_offset = -120000000; - Nid_cell = 0; - N_RB_DL = 50; - Nid_cell_mbsfn = 0; - nb_antenna_ports = 1; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - tx_gain = 90; - rx_gain = 125; - - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - } - ); - - - # ------- SCTP definitions - SCTP : - { - # Number of streams to use in input/output - SCTP_INSTREAMS = 2; - SCTP_OUTSTREAMS = 2; - }; - } -); - -MACRLCs = ( - { - num_cc = 1; - tr_s_preference = "local_L1"; - tr_n_preference = "f1"; - remote_n_address = "127.0.0.4"; - local_n_address = "127.0.0.3"; - local_n_portc = 500; - remote_n_portc = 501; - local_n_portd = 600; - remote_n_portd = 601; - } -); - -L1s = ( - { - num_cc = 1; - tr_n_preference = "local_mac"; - } -); - -RUs = ( - { - local_rf = "yes"; - nb_tx = 1; - nb_rx = 1; - att_tx = 10; - att_rx = 10; - bands = [7]; - max_pdschReferenceSignalPower = -27; - max_rxgain = 125; - eNB_instances = [0]; - } -); - -log_config = { - global_log_level = "info"; - hw_log_level = "info"; - phy_log_level = "info"; - mac_log_level = "info"; - rlc_log_level = "info"; -}; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf index f44a412b3c..12f56ca617 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpn300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 7; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf index 3c0feb2ddc..0a8c5f802e 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.32PRB.usrpx300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 7; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf index fa2dca082f..a77a65ab0a 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band257.tm1.66PRB.usrpn300.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf index 8ded185653..565e83c6a8 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band261.tm1.32PRB.usrpn300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 7; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf index 260c844b25..8de8f20cfb 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpn300.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf index 67ea04255c..07c0f76f6e 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.106PRB.usrpx300.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.24PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.24PRB.usrpx300.conf index ea1e70fa87..d794e222cb 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.24PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.24PRB.usrpx300.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpn300.conf index 58adeb991e..e83011d03a 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpn300.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpx300.conf index 227f06bd8b..10812dc846 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band66.tm1.25PRB.usrpx300.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf index d863f36409..ddd31a810e 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.30kHz,usrpb2x0.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf index 0dcd0b95e4..77863ab39a 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.106PRB.slave.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf index ef95a53a7d..ffc7b1b21c 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.slave.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf index 554b886010..2d2a103d43 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.PTRS.usrpx300.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; - #ra_ReponseWindow - #1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -147,8 +144,8 @@ gNBs = ); - # Dedicated Serving Cell Configuration - servingCellConfigDedicated = ( + # PTRS Configuration + phaseTrackingRS = ( { # DL PTRS related parameters. # 3GPP TS 38.331 PTRS-DownlinkConfig diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf index b3d3775208..e6805d7a92 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpb210.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf index dd9b571b33..1a31985d8b 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpn300.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf index 49108d242b..c0786bd56a 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.106PRB.usrpx300.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf index 1246e44b2b..82973bef95 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpn300.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf index e4f2fb8699..bcd16eda2a 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.217PRB.usrpx300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf index 7dfbb5ee95..295a7ab6f1 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpb210.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf index ad610601a0..27a0fc0a84 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpn300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf index 8107c5ffc6..f681e5723a 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.24PRB.usrpx300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf index 167ad9b802..4054d851c2 100644 --- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/gnb.band78.tm1.273PRB.usrpn300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf index 1666ea4a70..3261f716c7 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/cu_gnb.conf @@ -22,9 +22,7 @@ gNBs = local_s_address = "127.0.0.4"; remote_s_address = "127.0.0.3"; - local_s_portc = 501; local_s_portd = 2152; - remote_s_portc = 500; remote_s_portd = 2152; # ------- SCTP definitions diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf index 02b1e89b88..0c053aeda2 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/du_gnb.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -168,9 +165,7 @@ MACRLCs = ( tr_n_preference = "f1"; local_n_address = "127.0.0.3"; remote_n_address = "127.0.0.4"; - local_n_portc = 500; local_n_portd = 2152; - remote_n_portc = 501; remote_n_portd = 2152; } diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf index f57725cc9b..102c23018e 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf @@ -17,12 +17,9 @@ gNBs = tr_s_preference = "f1"; - local_s_if_name = "lo"; local_s_address = "127.0.0.3"; remote_s_address = "0.0.0.0"; # multiple DUs - local_s_portc = 501; local_s_portd = 2152; - remote_s_portc = 500; remote_s_portd = 2152; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci0.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci0.conf index c2e28725bd..1d3e0e70d0 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci0.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci0.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -163,12 +160,9 @@ MACRLCs = ({ num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "f1"; - local_n_if_name = "lo"; local_n_address = "127.0.0.4"; remote_n_address = "127.0.0.3"; - local_n_portc = 500; local_n_portd = 2152; - remote_n_portc = 501; remote_n_portd = 2152; pusch_FailureThres = 1000; }); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci1.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci1.conf index c5c84c9919..cdcd1a59fd 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci1.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band66.25prb.rfsim.pci1.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -163,12 +160,9 @@ MACRLCs = ({ num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "f1"; - local_n_if_name = "lo"; local_n_address = "127.0.0.5"; remote_n_address = "127.0.0.3"; - local_n_portc = 500; local_n_portd = 2152; - remote_n_portc = 501; remote_n_portd = 2152; pusch_FailureThres = 1000; }); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-benetel650.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-benetel650.conf index a267d2e864..7a6becbd8c 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-benetel650.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.4x4-benetel650.conf @@ -88,9 +88,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 3; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -172,12 +169,9 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "f1"; - local_n_if_name = "enp193s0f0"; local_n_address = "172.21.16.51"; remote_n_address = "172.21.6.90"; - local_n_portc = 500; local_n_portd = 2153; - remote_n_portc = 501; remote_n_portd = 2153; pusch_TargetSNRx10 = 170; pucch_TargetSNRx10 = 230; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf index 28f9baf6f8..3dd36be9c7 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf @@ -88,9 +88,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 3; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -172,12 +169,9 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "f1"; - local_n_if_name = "enp193s0f0"; local_n_address = "172.21.16.51"; remote_n_address = "172.21.6.90"; - local_n_portc = 500; local_n_portd = 2153; - remote_n_portc = 501; remote_n_portd = 2153; pusch_TargetSNRx10 = 120; pucch_TargetSNRx10 = 200; @@ -211,7 +205,7 @@ RUs = ( local_rf = "no"; nb_tx = 8; nb_rx = 8; - att_tx = 0; + att_tx = 35; att_rx = 0; bands = [77]; max_pdschReferenceSignalPower = -27; @@ -246,6 +240,7 @@ fhi_72 = { du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa"); du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69"); vlan_tag = (5, 5, 6, 6); + ru_username = ("oranbenetel", "oranbenetel"); ru_ip_addr = ("192.168.80.5", "192.168.80.6"); fh_config = ( # RAN650 #1 diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650.conf index 18f885945f..18829188e3 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650.conf @@ -88,9 +88,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 3; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -172,12 +169,9 @@ MACRLCs = ( num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "f1"; - local_n_if_name = "enp193s0f0"; local_n_address = "172.21.16.51"; remote_n_address = "172.21.6.90"; - local_n_portc = 500; local_n_portd = 2153; - remote_n_portc = 501; remote_n_portd = 2153; pusch_TargetSNRx10 = 120; pucch_TargetSNRx10 = 200; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf index 3221813bef..09eb99a6b2 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf @@ -80,9 +80,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -160,12 +157,9 @@ MACRLCs = ({ num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "f1"; - local_n_if_name = "lo"; local_n_address = "127.0.0.4"; remote_n_address = "127.0.0.3"; - local_n_portc = 500; local_n_portd = 2152; - remote_n_portc = 501; remote_n_portd = 2152; pusch_FailureThres = 1000; }); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf index c7d8cb3269..d2998de712 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf @@ -80,9 +80,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -160,12 +157,9 @@ MACRLCs = ({ num_cc = 1; tr_s_preference = "local_L1"; tr_n_preference = "f1"; - local_n_if_name = "lo"; local_n_address = "127.0.0.5"; remote_n_address = "127.0.0.3"; - local_n_portc = 500; local_n_portd = 2152; - remote_n_portc = 501; remote_n_portd = 2152; pusch_FailureThres = 1000; }); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.106prb.nfapi.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.106prb.nfapi.conf index bb4aed3dfe..aea3176456 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.106prb.nfapi.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.106prb.nfapi.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.aerial.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.aerial.conf index aa7c380e51..7b88ad23c4 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.aerial.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.aerial.conf @@ -105,9 +105,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.nfapi.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.nfapi.conf index 7cfc66748b..750f8580b1 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.nfapi.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.nfapi.conf @@ -83,13 +83,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen - ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; -#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.cbrs.aerial.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.cbrs.aerial.conf index 5f2293cfb9..e104f82131 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.cbrs.aerial.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.cbrs.aerial.conf @@ -87,9 +87,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf index b958ed809d..2081c86674 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.106PRB.2x2.usrpn310.conf @@ -37,7 +37,7 @@ gNBs = ////////// Physical parameters: - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_XP = 2; pusch_AntennaPorts = 2; min_rxtxtime_pdsch = 5; ul_prbblacklist = "51,52,53,54" @@ -114,9 +114,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf index a7010921bb..76ba815e13 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.162PRB.2x2.usrpn310.conf @@ -37,7 +37,7 @@ gNBs = ////////// Physical parameters: - pdsch_AntennaPorts = 1; + pdsch_AntennaPorts_XP = 2; pusch_AntennaPorts = 2; #pusch_TargetSNRx10 = 200; #pucch_TargetSNRx10 = 200; @@ -118,9 +118,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band1.u0.52PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band1.u0.52PRB.usrpb210.conf index e270dd690d..f30c2d445f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band1.u0.52PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band1.u0.52PRB.usrpb210.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band254.ntn.mu1.24prb.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band254.ntn.mu1.24prb.rfsim.conf index dd3307d32c..a6ca5decbe 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band254.ntn.mu1.24prb.rfsim.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band254.ntn.mu1.24prb.rfsim.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band255.ntn.mu0.25prb.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band255.ntn.mu0.25prb.rfsim.conf index 7c2c3805ee..c811f0d64e 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band255.ntn.mu0.25prb.rfsim.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band255.ntn.mu0.25prb.rfsim.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band256.ntn.mu0.25prb.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band256.ntn.mu0.25prb.rfsim.conf index b720d6d720..3a472ff7a2 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band256.ntn.mu0.25prb.rfsim.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band256.ntn.mu0.25prb.rfsim.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band257.u3.32prb.usrpx410.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band257.u3.32prb.usrpx410.conf index 667b15b10f..933cddfcb9 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band257.u3.32prb.usrpx410.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band257.u3.32prb.usrpx410.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf index a5e9841772..42ac3185f0 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.106PRB.usrpb210.conf @@ -79,9 +79,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.52PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.52PRB.usrpb210.conf index b72ca5dc32..a02394b5b2 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.52PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band41.fr1.52PRB.usrpb210.conf @@ -85,9 +85,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf index 1d9693edb1..6b460b0b59 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpn300.conf @@ -80,9 +80,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpx300.conf index b666616764..afd7e6d96f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.106PRB.usrpx300.conf @@ -96,9 +96,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.24PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.24PRB.usrpx300.conf index 013ca6663b..6b9b104bc0 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.24PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.24PRB.usrpx300.conf @@ -100,9 +100,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf index c9dfd6c58a..560b33b0e9 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.fr1.25PRB.usrpx300.conf @@ -100,9 +100,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.u0.25prb.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.u0.25prb.rfsim.conf index f51bb977e0..9458c2b272 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.u0.25prb.rfsim.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band66.u0.25prb.rfsim.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.106prb.fhi72.4x4-vvdn.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.106prb.fhi72.4x4-vvdn.conf index 7622e508bc..753670a9eb 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.106prb.fhi72.4x4-vvdn.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.106prb.fhi72.4x4-vvdn.conf @@ -86,9 +86,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 2; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.162prb.usrpn310.4x4.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.162prb.usrpn310.4x4.conf index ba427f747e..1890e60516 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.162prb.usrpn310.4x4.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.162prb.usrpn310.4x4.conf @@ -88,9 +88,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-vvdn.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-vvdn.conf index ce2a75d529..38580730f2 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-vvdn.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.2x2-vvdn.conf @@ -84,9 +84,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 2; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf index 55a78fd901..d55bc6dbda 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf @@ -86,9 +86,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 2; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.2x2.usrpn300.conf index f4c31e3ee7..5bfce9a2d9 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.2x2.usrpn300.conf @@ -85,9 +85,6 @@ gNBs = ( # powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; - # ra_ReponseWindow - # 1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; # ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR # 1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.usrpx300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.usrpx300.conf index fcda4d3cc0..f6e571078e 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.usrpx300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.fr1.273PRB.usrpx300.conf @@ -85,9 +85,6 @@ gNBs = ( # powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; - # ra_ReponseWindow - # 1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; # ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR # 1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf index 8c419177d5..3dc33707f3 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.106PRB.usrpb210.RA_2-Step.conf @@ -80,9 +80,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel550.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel550.conf index b66012c619..75fe0e6fdd 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel550.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel550.conf @@ -85,9 +85,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 3; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf index 6fa4c200dc..ed996cac27 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550-mplane.conf @@ -87,9 +87,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 3; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -211,7 +208,7 @@ RUs = ( local_rf = "no"; nb_tx = 4; nb_rx = 4; - att_tx = 0; + att_tx = 24; att_rx = 0; bands = [78]; max_pdschReferenceSignalPower = -27; @@ -263,6 +260,7 @@ fhi_72 = { du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa"); du_addr = ("00:11:22:33:44:68","00:11:22:33:44:69"); vlan_tag = (11, 11); + ru_username = ("oranbenetel"); ru_ip_addr = ("192.168.80.10"); fh_config = ({ T1a_cp_dl = (419, 470); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf index 3d584fdaba..d8ca02a3be 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-benetel550.conf @@ -87,9 +87,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 3; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-foxconn.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-foxconn.conf index bd4cd59f06..e26e446f46 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-foxconn.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-foxconn.conf @@ -73,7 +73,7 @@ gNBs = initialULBWPsubcarrierSpacing = 1; #rach-ConfigCommon #rach-ConfigGeneric - prach_ConfigurationIndex = 151;# testMAC 158; OAI gNB 98 + prach_ConfigurationIndex = 152 #prach_msg1_FDM #0 = one, 1=two, 2=four, 3=eight prach_msg1_FDM = 0; @@ -85,13 +85,10 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen - ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; -#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; #ra_ContentionResolutionTimer #(0..7) 8,16,24,32,40,48,56,64 diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf index 43f6f9cef8..3c9780130f 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf @@ -86,9 +86,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 2; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-metanoia.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-metanoia.conf index b6c940c78b..13617fb578 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-metanoia.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-metanoia.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf index b4aa830dd5..ddf866b0fd 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.2x2.usrpn300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci0.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci0.rfsim.conf new file mode 100644 index 0000000000..b486b52dec --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci0.rfsim.conf @@ -0,0 +1,251 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + @include "neighbour-config-rfsim.conf" + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + do_CSIRS = 1; + do_SRS = 1; + + #uess_agg_levels = [0,1,2,2,1] + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 641280; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 640008; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "192.168.70.132"; }); + + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 150; + pucch_TargetSNRx10 = 200; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 100; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +} +); + +RUs = ( +{ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 12; + att_rx = 12; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + clock_src = "internal"; +} +); + + +rfsimulator : +{ + serveraddr = "server"; + serverport = 4043; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs"; +}; + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="debug"; + f1ap_log_level ="debug"; +}; + +e2_agent = { + near_ric_ip_addr = "127.0.0.1"; + #sm_dir = "/path/where/the/SMs/are/located/" + sm_dir = "/usr/local/lib/flexric/" +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf new file mode 100644 index 0000000000..c649c8b0f8 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf @@ -0,0 +1,251 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xb00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + @include "neighbour-config-rfsim.conf" + + nr_cellid = 720898; + + ////////// Physical parameters: + + do_CSIRS = 1; + do_SRS = 1; + + #uess_agg_levels = [0,1,2,2,1] + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 1; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB = 621312; + dl_frequencyBand = 78; + # this is 3600 MHz + dl_absoluteFrequencyPointA = 620040; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 106; + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952 +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 106; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 28875; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 13; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "192.168.70.132"; }); + + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 150; + pucch_TargetSNRx10 = 200; +} +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 120; + pucch0_dtx_threshold = 100; + ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0 +} +); + +RUs = ( +{ + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 12; + att_rx = 12; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 114; + eNB_instances = [0]; + clock_src = "internal"; +} +); + + +rfsimulator : +{ + serveraddr = "server"; + serverport = 4043; + options = (); #("saviq"); or/and "chanmod" + modelname = "AWGN"; + IQfile = "/tmp/rfsimulator.iqs"; +}; + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + +log_config : +{ + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + ngap_log_level ="debug"; + f1ap_log_level ="debug"; +}; + +e2_agent = { + near_ric_ip_addr = "127.0.0.1"; + #sm_dir = "/path/where/the/SMs/are/located/" + sm_dir = "/usr/local/lib/flexric/" +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.2pattern.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.2pattern.conf index 89a1bb23c6..a8d65df77a 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.2pattern.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.2pattern.conf @@ -78,9 +78,6 @@ gNBs = # powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; - # ra_ReponseWindow - # 1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; # ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR # 1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; @@ -111,7 +108,6 @@ gNBs = # ssb_PositionsInBurs_BitmapPR # 1=short, 2=medium, 3=long - ssb_PositionsInBurst_PR = 2; ssb_PositionsInBurst_Bitmap = 1; # ssb_periodicityServingCell diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf index d2f9dc0005..641c2228a4 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.4layer.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index 7f7054db31..7f750d7259 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -81,9 +81,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.redcap.yaml b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.redcap.yaml index 01c40ca3d7..725b85a31e 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.redcap.yaml +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.redcap.yaml @@ -19,6 +19,12 @@ gNBs: # Physical parameters: do_CSIRS: 1 do_SRS: 1 + first_active_bwp: 1; + bwp_list: + - + scs: 1 + bwpStart: 0 + bwpSize: 106 #uess_agg_levels: [0,1,1,1,1] servingCellConfigCommon: #spCellConfigCommon @@ -76,9 +82,6 @@ gNBs: #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep: 1 - #ra_ReponseWindow - #1,2,4,8,10,20,40,80 - ra_ResponseWindow: 5 #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4 @@ -135,17 +138,6 @@ gNBs: ssPBCH_BlockPower: -25 - servingCellConfigDedicated: - - dl_bwp-Id_1: 1 - dl_bwp1_locationAndBandwidth: 28875 - dl_bwp1_subcarrierSpacing: 1 - firstActiveDownlinkBWP-Id: 1 - defaultDownlinkBWP-Id: 1 - ul_bwp-Id_1: 1 - ul_bwp1_locationAndBandwidth: 28875 - ul_bwp1_subcarrierSpacing: 1 - firstActiveUplinkBWP-Id: 1 - RedCap: cellBarredRedCap1Rx_r17: 1 cellBarredRedCap2Rx_r17: 1 diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf index 46964ad72d..373ea830e0 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.sabox.conf @@ -80,9 +80,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.yaml b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.yaml index 87ad6080a0..8608ccd290 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.yaml +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.yaml @@ -76,9 +76,6 @@ gNBs: #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep: 1 - #ra_ReponseWindow - #1,2,4,8,10,20,40,80 - ra_ResponseWindow: 4 #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4 diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf index 129b687c1a..30e95f83ec 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.162PRB.2x2.usrpn300.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.189PRB.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.189PRB.rfsim.conf index 5270587271..22047cf06c 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.189PRB.rfsim.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.189PRB.rfsim.conf @@ -86,9 +86,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf index 9802cc0acd..09117464b0 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.217PRB.2x2.usrpn300.conf @@ -82,9 +82,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf index d3852e236a..1398020417 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf @@ -80,9 +80,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band261.fr2.64PRB.usrpx310.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band261.fr2.64PRB.usrpx310.conf index fbc77bf957..c51a969208 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band261.fr2.64PRB.usrpx310.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band261.fr2.64PRB.usrpx310.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 7; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; #one (0..15) 4,8,12,16,...60,64 diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf index f0ea334f7e..d64bd8e472 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf @@ -118,9 +118,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band261.fr2.64PRB.usrpx310.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band261.fr2.64PRB.usrpx310.conf index 143345f275..f04fcc8efc 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band261.fr2.64PRB.usrpx310.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band261.fr2.64PRB.usrpx310.conf @@ -83,9 +83,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 7; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band78.fr1.106PRB.usrpx310.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band78.fr1.106PRB.usrpx310.conf index c8c1582584..bc8af31818 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band78.fr1.106PRB.usrpx310.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb1.prs.band78.fr1.106PRB.usrpx310.conf @@ -117,9 +117,6 @@ gNBs = #powerRampingStep # 0=dB0,1=dB2,2=dB4,3=dB6 powerRampingStep = 1; -#ra_ReponseWindow -#1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/neighbour-config-rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/neighbour-config-rfsim.conf new file mode 100644 index 0000000000..cff9d2b293 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/neighbour-config-rfsim.conf @@ -0,0 +1,78 @@ +############################################################ +# gNB-to-gNB neighbour list + measurement configuration # +# for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) # +############################################################ + +neighbour_list = ( + ########################################################## + # Entry USED BY gNB_ID = 0xe00 (nr_cellid = 12345678L) # + ########################################################## + { + nr_cellid = 12345678L; # Serving cell of gNB 0xe00 + neighbour_cell_configuration = ( + { + gNB_ID = 0xb00; + nr_cellid = 720898; # Cell served by gNB 0xb00 + physical_cellId = 1; + absoluteFrequencySSB= 621312; + subcarrierSpacing = 1; # 30 kHz + band = 78; + plmn = { mcc = 001; mnc = 01; mnc_length = 2 }; + tracking_area_code = 1; + } + ); + }, + + ########################################################## + # Entry USED BY gNB_ID = 0xb00 (nr_cellid = 720898) # + ########################################################## + { + nr_cellid = 720898; # Serving cell of gNB 0xb00 + neighbour_cell_configuration = ( + { + gNB_ID = 0xe00; + nr_cellid = 12345678L; # Cell served by gNB 0xe00 + physical_cellId = 0; + absoluteFrequencySSB= 641280; + subcarrierSpacing = 1; # 30 kHz + band = 78; + plmn = { mcc = 001; mnc = 01; mnc_length = 2 }; + tracking_area_code = 1; + } + ); + } +); + +############################################################ +# Common NR measurement-event configuration # +############################################################ + +nr_measurement_configuration = { + Periodical = { + enable = 1; + includeBeamMeasurements = 1; + maxNrofRS_IndexesToReport = 4; + }; + + A2 = { + enable = 1; + threshold = 60; + timeToTrigger = 1; + }; + + A3 = ( + { + cell_id = 720898; # neighbour of gNB 0xe00 + offset = 10; + hysteresis = 0; + timeToTrigger = 1; + }, + { + cell_id = 12345678; # neighbour of gNB 0xb00 + offset = 5; + hysteresis = 1; + timeToTrigger = 2; + } + ); +}; + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000000..cefa52d456 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(nr-cuup) diff --git a/tests/nr-cuup/CMakeLists.txt b/tests/nr-cuup/CMakeLists.txt new file mode 100644 index 0000000000..02becb2496 --- /dev/null +++ b/tests/nr-cuup/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(nr-cuup-load-test nr-cuup-load-test.c) +target_link_libraries(nr-cuup-load-test PRIVATE GTPV1U ${T_LIB} utils ITTI e1ap + SCTP_CLIENT) +target_link_libraries(nr-cuup-load-test PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) # ITTI diff --git a/tests/nr-cuup/README.md b/tests/nr-cuup/README.md new file mode 100644 index 0000000000..3095e5f600 --- /dev/null +++ b/tests/nr-cuup/README.md @@ -0,0 +1,78 @@ +This is a simple tester for the CU-UP. It configures the CU-UP via E1, and can +stream data via GTP in uplink and downlink directions. + +[[_TOC_]] + +# Overview + +From a schematic point of view, the tester/CU-UP interaction looks like this: + +``` + +-------+ ++------>| CU-UP |<------+ +| +-------+ | +| | | +| F1-U | E1 | NG-U +| (data) | (control) | (data) +| | | +| +-------+ | ++------>|tester |<------+ + +-------+ +``` + +The tester is for performance testing of a CU-UP, and behaves like an +integrated DU/CU-CP/UPF from the CU-UP's point of view. + +The tester and CU-UP have an E1 connection through which control information is +exchanged, e.g., configuration of UEs/bearers and associated information. In +other words, towards the CU-UP, the tester appears like a CU-CP. + +Further, for each UE/bearer, CU-UP is configured with GTP IP information and +the corresponding TEID. The CU-UP will forward downlink data arriving on NG-U +on the F1-U interface, and uplink data arriving on F1-U on the NG-U interface. +In other words, on the F1-U interface, the tester appears like a DU to the +CU-UP, and on the NG-U interface, the tester appears like a UPF to the CU-UP. + +A test scenario is fixed to these steps: + +1. The tester sets up a number of UEs via the E1 interface (it is possible to + see the message exchange in Wireshark). +2. The tester streams data in downlink/uplink (from the CU-UP's point of view) + and measures how much data is lost. +3. The tester releases all the UEs via the E1 interface, and disconnects from + the CU-UP. + +Note: The tester uses the same GTP module as the CU-UP. Thus, data might not +only be lost at the GTP interface of the CU-UP, but also at the tester. + +# Usage + +You can build the CU-UP and the tester like so: + + cd ~/openairinterface5g + mkdir build && cd build && cmake .. -GNinja && ninja nr-cuup nr-cuup-load-test params_libconfig + ./tests/nr-cuup/nr-cuup-load-test + ./nr-cuup -O ../tests/nr-cuup/load-test.conf + +This builds both tester and CU-UP in the directory `build/`, then starts the +load tester with default values + +- 1 UE +- 10s of Test +- 60 Mbps of traffic in both downlik/uplink with a packet size of 1400 bytes + +To see the available options, run + + ./tests/nr-cuup/nr-cuup-load-test -h + +The configuration file [`load-test.conf`](./load-test.conf) matches the default +tester configuration (F1-U GTP traffic over non-standard port 2153, NG-U GTP +over 2152, tests on localhost). The configuration file includes this +non-standard port 2153 as the GTP module, as of now, cannot bind on the same +interface and port for both F1-U and NG-U due to internal limitations. + +# Limitations + +- The tester does not yet create/remove UEs during a traffic test. +- It might be possible to integrate with an external GTP traffic generator, + but we did not test this. diff --git a/tests/nr-cuup/load-test.conf b/tests/nr-cuup/load-test.conf new file mode 100644 index 0000000000..9829640a02 --- /dev/null +++ b/tests/nr-cuup/load-test.conf @@ -0,0 +1,58 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_CU_UP_ID = 0xe00; + +# cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ mcc = 222; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) }); + + + tr_s_preference = "f1"; + + local_s_address = "127.0.0.6"; + remote_s_address = "127.0.0.1"; + local_s_portc = 501; + local_s_portd = 2153; + remote_s_portc = 500; + remote_s_portd = 2153; + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + E1_INTERFACE = + ( + { + type = "up"; + ipv4_cucp = "127.0.0.1"; + ipv4_cuup = "127.0.0.6"; + } + ) + + NETWORK_INTERFACES : + { + GNB_IPV4_ADDRESS_FOR_NG_AMF = "172.21.16.109"; + GNB_IPV4_ADDRESS_FOR_NGU = "127.0.0.7"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + } +); + +log_config: { + global_log_level = "info"; +}; diff --git a/tests/nr-cuup/nr-cuup-load-test.c b/tests/nr-cuup/nr-cuup-load-test.c new file mode 100644 index 0000000000..0c417ca5aa --- /dev/null +++ b/tests/nr-cuup/nr-cuup-load-test.c @@ -0,0 +1,673 @@ +/* + * 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 +#include +#include + +#include "common/utils/LOG/log.h" +#include "common/utils/ocp_itti/intertask_interface.h" // this pulls in all of OAI+4G+5G +#include "openair3/SCTP/sctp_eNB_task.h" +#include "openair2/E1AP/e1ap.h" +#include "openair3/ocp-gtpu/gtp_itf.h" + +configmodule_interface_t *uniqCfg; + +#define DL 0 +#define UL 1 + +int nr_rlc_get_available_tx_space(const rnti_t rntiP, const logical_chan_id_t channel_idP) { abort(); return 0; } /* in GTP */ +softmodem_params_t *get_softmodem_params(void) { static softmodem_params_t p = {0}; return &p; }; /* in ITTI */ +void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } /* CU-UP */ +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } /* CU-UP */ +void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); } /* CU-UP */ +void e1_reset(void) { abort(); } /* CU-UP */ +instance_t *N3GTPUInst = NULL; /* CU-UP */ +instance_t CUuniqInstance=0; /* CU-UP */ + +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + LOG_E(GNB_APP, "error at %s:%d:%s: %s\n", file, line, function, s); + abort(); +} + +/* @brief Dummy function to pass a fptr to ITTI for staring RRC queue, without + * actually handling any messages. Functions called by main() will send/receive + * ITTI messages to E1, as if it was RRC. */ +static void *cuup_tester_rrc(void *) +{ + itti_mark_task_ready(TASK_RRC_GNB); + LOG_I(GNB_APP, "created RRC queue\n"); + return NULL; +} + +/* @brief Initialize E1 interface (as if it was CU-CP) */ +static void init_e1() +{ + net_ip_address_t ip = {.ipv4 = 1, .ipv4_address = "127.0.0.1" }; + e1ap_net_config_t conf = { .CUCP_e1_ip_address = ip }; + MessageDef *msg = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_REGISTER_REQ); + e1ap_net_config_t *e1ap_nc = &E1AP_REGISTER_REQ(msg).net_config; + *e1ap_nc = conf; + itti_send_msg_to_task(TASK_CUCP_E1, 0, msg); +} + +/* @brief Setup CU-UP connection and retrieve parameters for further + * connection. + * + * Waits for E1 Setup Request, sends response, and returns SCTP association ID + * and NSSAI used by this CU-UP. + */ +static void setup_cuup(sctp_assoc_t *assoc_id, e1ap_nssai_t *nssai) +{ + /* Wait for E1AP setup request, store CU-UP info */ + MessageDef *itti_req = NULL; + itti_receive_msg(TASK_RRC_GNB, &itti_req); + MessagesIds id = ITTI_MSG_ID(itti_req); + AssertFatal(id == E1AP_SETUP_REQ, "expected E1AP setup request, received %s instead\n", itti_get_message_name(id)); + *assoc_id = itti_req->ittiMsgHeader.originInstance; + e1ap_setup_req_t *req = &E1AP_SETUP_REQ(itti_req); + long t_id = req->transac_id; + DevAssert(req->supported_plmns = 1); + DevAssert(req->plmn[0].slice != NULL); + *nssai = *req->plmn[0].slice; + DevAssert(assoc_id != 0); + itti_free(TASK_GNB_APP, itti_req); + + // acknowledge the E1 setup request with a response + MessageDef *itti_resp = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_SETUP_RESP); + itti_resp->ittiMsgHeader.originInstance = *assoc_id; + e1ap_setup_resp_t *resp = &E1AP_SETUP_RESP(itti_resp); + resp->transac_id = t_id; + itti_send_msg_to_task(TASK_CUCP_E1, 0, itti_resp); +} + +/* @brief get E1AP bearer setup request based on parameters */ +static e1ap_bearer_setup_req_t get_breq(uint32_t ue_id, long pdu_id, long drb_id, const e1ap_nssai_t *nssai, const UP_TL_information_t *tnl) +{ + e1ap_bearer_setup_req_t bearer_req = { + .gNB_cu_cp_ue_id = ue_id, + .secInfo.cipheringAlgorithm = 0, /* no ciphering/NEA0 */ + .secInfo.integrityProtectionAlgorithm = 0, /* no integrity/NIA0 */ + /* encryptionKey not needed */ + /* integrityProtectionKey not needed */ + .numPDUSessions = 1, + }; + pdu_session_to_setup_t *pdu = &bearer_req.pduSession[0]; + pdu->sessionId = pdu_id; + pdu->nssai = *nssai; + pdu->securityIndication.integrityProtectionIndication = SECURITY_NOT_NEEDED; + pdu->securityIndication.confidentialityProtectionIndication = SECURITY_NOT_NEEDED; + pdu->UP_TL_information = *tnl; + pdu->numDRB2Setup = 1; + DRB_nGRAN_to_setup_t *drb = &pdu->DRBnGRanList[0]; + drb->id = drb_id; + drb->numQosFlow2Setup = 1; + drb->numCellGroups = 1; + + return bearer_req; +} + +/* @brief check for packet loss by verifing the sequence number. Can handle + * packet losses and reordering. + * @param payload the sequence number of the current packet + * @param expected the expected sequence number + * @param [inout] pointer to number of lost packets, which will be updated by + * the difference between payload and expected. + * @return the next expected packet number. */ +static uint32_t estimate_packetloss(const uint32_t payload, uint32_t expected, uint32_t *lost) +{ + if (payload == expected) { + /* all good */ + return expected + 1; + } else if (payload > expected) { + /* there was packet loss, assume all packets in between have been lost */ + uint32_t diff = payload - expected; + *lost += diff; + LOG_W(GNB_APP, "packet loss: expected %d received %d diff %d (total loss %d)\n", expected, payload, diff, *lost); + return payload + 1; + } else { /* payload < expected */ + /* reordered: we assumed current packet to be lost, so reduce the + * loss for this packet as it arrived in the end. */ + *lost -= 1; + LOG_W(GNB_APP, "packet reordering occurred: expected %d received %d\n", expected, payload); + return expected; /* we still wait for the next packet */ + } +} + +static struct ue_stat { + uint32_t count; + uint32_t lost; + uint64_t received; +} ue_stat[10][2] = {0}; +/* @brief ulReceived callback for F1-U + * + * Checks for packet loss by verifying that the first 4 bytes are corresponding + * to a continuous 4-byte (word) enumeration. */ +static bool recv_ng(protocol_ctxt_t *ctxt, + const ue_id_t ue_id, + const srb_flag_t flag, + const rb_id_t rb, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t size, + unsigned char *const buf, + const pdcp_transmission_mode_t modeP, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id, + const uint8_t qfi, + const bool rqi, + const int pdusession_id) +{ + uint32_t *payload = (uint32_t *) buf; + DevAssert(size % 4 == 0); + struct ue_stat *s = &ue_stat[ue_id][UL]; + s->count = estimate_packetloss(*payload, s->count, &s->lost); + s->received += size; + + return true; +} + +/* @brief Set up the NG-U (north-bound) GTP tunnel, and inform CU-UP via E1 */ +static up_params_t setup_cuup_ue_ng(sctp_assoc_t assoc_id, const e1ap_nssai_t *nssai, uint32_t ue_id, instance_t gtp_inst, const char *ip) +{ + long pdu_id = 1; + long drb_id = pdu_id + 3; + in_addr_t addr_lo; + inet_pton(AF_INET, ip, &addr_lo); + + /* create the local tunnel (i.e., as if we were UPF) */ + transport_layer_addr_t null_addr = {.length = 32}; + teid_t teid_lo = newGtpuCreateTunnel(gtp_inst, ue_id, pdu_id, pdu_id, -1, -1, null_addr, NULL, recv_ng); + UP_TL_information_t tnl = {.teId = teid_lo}; + memcpy(&tnl.tlAddress, &addr_lo, 4); + + /* Create a new bearer */ + MessageDef *itti_breq = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_BEARER_CONTEXT_SETUP_REQ); + itti_breq->ittiMsgHeader.originInstance = assoc_id; + e1ap_bearer_setup_req_t *breq = &E1AP_BEARER_CONTEXT_SETUP_REQ(itti_breq); + *breq = get_breq(ue_id, pdu_id, drb_id, nssai, &tnl); + itti_send_msg_to_task(TASK_CUCP_E1, 0, itti_breq); + + /* Wait for the ack */ + MessageDef *itti_bresp; + itti_receive_msg(TASK_RRC_GNB, &itti_bresp); + MessagesIds id = ITTI_MSG_ID(itti_bresp); + AssertFatal(id == E1AP_BEARER_CONTEXT_SETUP_RESP, "expected E1AP bearer context setup response, received %s instead\n", itti_get_message_name(id)); + DevAssert(assoc_id == itti_bresp->ittiMsgHeader.originInstance); + e1ap_bearer_setup_resp_t *bresp = &E1AP_BEARER_CONTEXT_SETUP_RESP(itti_bresp); + DevAssert(bresp->gNB_cu_cp_ue_id == ue_id); + DevAssert(bresp->gNB_cu_up_ue_id == ue_id); + DevAssert(bresp->numPDUSessions == 1); + teid_t teid_rm = bresp->pduSession[0].tl_info.teId; + in_addr_t addr_rm; + memcpy(&addr_rm, &bresp->pduSession[0].tl_info.tlAddress, 4); + DevAssert(bresp->pduSession[0].numDRBSetup == 1); + DRB_nGRAN_setup_t *drb = &bresp->pduSession[0].DRBnGRanList[0]; + DevAssert(drb->id == drb_id); + DevAssert(drb->numUpParam == 1); + up_params_t f1_up = drb->UpParamList[0]; + itti_free(TASK_GNB_APP, itti_bresp); + + /* print diagnostics */ + char ip_lo[32] = {0}; + inet_ntop(AF_INET, &addr_lo, ip_lo, sizeof(ip_lo)); + char ip_rm[32] = {0}; + inet_ntop(AF_INET, &addr_rm, ip_rm, sizeof(ip_rm)); + GtpuUpdateTunnelOutgoingAddressAndTeid(gtp_inst, ue_id, pdu_id, addr_rm, teid_rm); + LOG_I(GNB_APP, "CU-UP created NG-U, local %s/%x remote %s/%x\n", ip_lo, teid_lo, ip_rm, teid_rm); + + inet_ntop(AF_INET, &f1_up.tl_info.tlAddress, ip_rm, sizeof(ip_rm)); + LOG_I(GNB_APP, "CU-UP created F1-U, remove %s/%x\n", ip_rm, f1_up.tl_info.teId); + return f1_up; +} + +/* @brief get E1AP bearer modification request based on parameters */ +static e1ap_bearer_mod_req_t get_bmod(uint32_t ue_id, long pdu_id, up_params_t up) +{ + e1ap_bearer_mod_req_t bearer_mod = { + .gNB_cu_cp_ue_id = ue_id, + .gNB_cu_up_ue_id = ue_id, + .numPDUSessionsMod = 1, + }; + pdu_session_to_mod_t *pdum = &bearer_mod.pduSessionMod[0]; + pdum->sessionId = pdu_id; + pdum->numDRB2Modify = 1; + DRB_nGRAN_to_mod_t *drb = &pdum->DRBnGRanModList[0]; + drb->id = 4; + drb->numDlUpParam = 1; + drb->DlUpParamList[0] = up; + + return bearer_mod; +} + +/* @brief Received callback for F1-U + * + * Checks for packet loss by verifying that the first 4 bytes are corresponding + * to a continuous 4-byte (word) enumeration. */ +static bool recv_f1(protocol_ctxt_t *ctxt, + const srb_flag_t flag, + const rb_id_t rb, + const mui_t mui, + const confirm_t confirm, + const sdu_size_t size, + unsigned char *const buf, + const pdcp_transmission_mode_t modeP, + const uint32_t *sourceL2Id, + const uint32_t *destinationL2Id) +{ + int skip_bytes = 2; + uint32_t *payload = (uint32_t *) &buf[skip_bytes]; + DevAssert((size - skip_bytes) % 4 == 0); + int ue_id = ctxt->rntiMaybeUEid; + struct ue_stat *s = &ue_stat[ue_id][DL]; + s->count = estimate_packetloss(*payload, s->count, &s->lost); + s->received += size - skip_bytes; + + return true; +} + +/* @brief Set up the F1-U (south-bound) GTP tunnel, and inform CU-UP via E1 */ +static void setup_cuup_ue_f1(sctp_assoc_t assoc_id, uint32_t ue_id, instance_t gtp_inst, const char *ip, up_params_t rm) +{ + int pdu_id = 1; + int drb_id = pdu_id + 3; + + /* create tunnel (i.e., as if we were DU) */ + transport_layer_addr_t addr = {.length = 32}; + memcpy(addr.buffer, &rm.tl_info.tlAddress, 4); + teid_t teid_lo = newGtpuCreateTunnel(gtp_inst, ue_id, drb_id, drb_id, rm.tl_info.teId, -1, addr, recv_f1, NULL); + + up_params_t lo = {.tl_info.teId = teid_lo, .cell_group_id = rm.cell_group_id}; + inet_pton(AF_INET, ip, &lo.tl_info.tlAddress); + + /* modify existing tunnel via E1 to pass in F1-U TEID */ + MessageDef *itti_bmod = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_BEARER_CONTEXT_MODIFICATION_REQ); + itti_bmod->ittiMsgHeader.originInstance = assoc_id; + e1ap_bearer_mod_req_t *bmod = &E1AP_BEARER_CONTEXT_MODIFICATION_REQ(itti_bmod); + *bmod = get_bmod(ue_id, pdu_id, lo); + itti_send_msg_to_task(TASK_CUCP_E1, 0, itti_bmod); + + /* Wait for the ack */ + MessageDef *itti_bmodr; + itti_receive_msg(TASK_RRC_GNB, &itti_bmodr); + MessagesIds id = ITTI_MSG_ID(itti_bmodr); + AssertFatal(id == E1AP_BEARER_CONTEXT_MODIFICATION_RESP, "expected E1AP bearer context modification response, received %s instead\n", itti_get_message_name(id)); + //DevAssert(assoc_id == itti_bmodr->ittiMsgHeader.originInstance); + itti_free(TASK_GNB_APP, itti_bmodr); + + /* print diagnostics */ + char ip_lo[32] = {0}; + inet_ntop(AF_INET, &lo.tl_info.tlAddress, ip_lo, sizeof(ip_lo)); + char ip_rm[32] = {0}; + inet_ntop(AF_INET, &rm.tl_info.tlAddress, ip_rm, sizeof(ip_rm)); + LOG_I(GNB_APP, "CU-UP created F1-U, local %s/%x remote %s/%x\n", ip_lo, lo.tl_info.teId, ip_rm, rm.tl_info.teId); +} + +/* @brief release the UE over E1, and delete corresponding GTP tunnels */ +static void e1_release_ue(sctp_assoc_t assoc_id, uint32_t ue_id, instance_t f1_inst, instance_t ng_inst) +{ + MessageDef *itti_cmd = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_BEARER_CONTEXT_RELEASE_CMD); + itti_cmd->ittiMsgHeader.originInstance = assoc_id; + e1ap_bearer_release_cmd_t *cmd = &E1AP_BEARER_CONTEXT_RELEASE_CMD(itti_cmd); + cmd->gNB_cu_cp_ue_id = cmd->gNB_cu_up_ue_id = ue_id; + cmd->cause.type = E1AP_CAUSE_RADIO_NETWORK; + cmd->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE; + itti_send_msg_to_task(TASK_CUCP_E1, 0, itti_cmd); + + /* Wait for the ack */ + MessageDef *itti_cplt; + itti_receive_msg(TASK_RRC_GNB, &itti_cplt); + MessagesIds id = ITTI_MSG_ID(itti_cplt); + AssertFatal(id == E1AP_BEARER_CONTEXT_RELEASE_CPLT, "expected E1AP bearer context release complete, received %s instead\n", itti_get_message_name(id)); + itti_free(TASK_GNB_APP, itti_cplt); + + newGtpuDeleteAllTunnels(f1_inst, ue_id); + newGtpuDeleteAllTunnels(ng_inst, ue_id); +} + +/* @brief initialize GTP interface for IP:port */ +static instance_t init_gtp(const char *ip, uint16_t port) +{ + openAddr_t iface = {0}; + DevAssert(strlen(ip) <= sizeof(iface.originHost)); + strcpy(iface.originHost, ip); + snprintf(iface.originService, sizeof(iface.originService), "%d", port); + snprintf(iface.destinationService, sizeof(iface.destinationService), "%d", port); + return gtpv1Init(iface); +} + +/* @brief calculate time difference of two struct timespec */ +static float time_diff(struct timespec s, struct timespec e) +{ + //printf("start %ld.%ld end %ld.%ld\n", s.tv_sec, s.tv_nsec, e.tv_sec, e.tv_nsec); + float dur = e.tv_sec - s.tv_sec + (e.tv_nsec - s.tv_nsec) / 1000000000.f; + //printf("duration %f s %f us\n", dur, dur * 1000000.f); + return dur * 1000000.f; +} + +enum pdcp_len {PDCP_SN_LEN_12, PDCP_SN_LEN_18}; +/* @brief generate hardcoded PDCP header in case of UL transmission */ +static void write_pdcp_header(uint32_t sn, enum pdcp_len len, uint8_t *buf) +{ + DevAssert(len == PDCP_SN_LEN_12); + /* see nr_pdcp_entity_process_sdu() or 38.323 sec 6.2.2.2 */ + buf[0] = 0x80 | ((sn >> 8) & 0xf); + buf[1] = sn & 0xff; + //printf("%02x %02x\n", buf[0], buf[1]); +} + +/* @brief the configuration for a thread to send GTP traffic */ +struct thr_data { + /// pthread ID to join this thread + pthread_t t; + + /* in */ + /// GTP instance to send on + instance_t inst; + /// UE ID to be used + ue_id_t ue_id; + /// flag to decide if PDCP/SDAP header is to be prepended + bool is_ul; + /// length of data packet + unsigned int data_len; + /// target throughput to reach + uint64_t throughput; + /// duration of the data traffic to last + unsigned int duration; + + /* out */ + /// exact measured transmission time + float total_time; + /// exact measured data that has been sent + uint64_t total_data; +}; +/* @brief Main traffic generation/transmission function. + * + * The function calculates the amount of packets to be sent during each TTI + * (one millisecond) (as a float, to send the exact amount of packets). It then + * enters a loop, in which (1) it sends the packets of the current TTI, possibly + * including additional packets if they could not be sent in the last TTI, (2) + * measure the time since the last TTI boundary, and sleep, if necessary, to + * adjust to the exact throughput (3) update for additional packets to send if + * the last TTI took too long. The last point ensure that we send exactly an + * exact amount of data, possibly taking longer than specified. + * + * @param v pointer to generation function of type `struct thr_data`. + * @return always NULL */ +static void *sender_thread(void *v) +{ + struct thr_data *d = v; + + size_t oh = d->is_ul ? 3 : 0; + size_t packet_len = d->data_len + oh; + uint8_t buf[packet_len]; + memset(buf, 0, packet_len); + uint32_t *payload = (uint32_t *)(buf + oh); + uint64_t to_send = (float)d->throughput / 8.0 * d->duration; + const float pps_1ms = (float) d->throughput / 8.0 / d->data_len / 1000; + float pps_1ms_nextwin = pps_1ms; + int bearer = d->is_ul ? 4 : 1; + + + //printf("sending %ld Mbps for %ld s => data %ld, %.3f pps\n", (float) d->throughput / 1000000.0, d->duration, to_send, pps_1ms); + + int i_1ms = 0; + struct timespec start; + clock_gettime(CLOCK_MONOTONIC, &start); + size_t packet_count = 0; + while (true) { + int pps_now = pps_1ms_nextwin; + pps_1ms_nextwin = pps_1ms + pps_1ms_nextwin - (float) pps_now; + //printf("this window send %d packets next window %.3f (pps_1ms %.3f)\n", pps_now, pps_1ms_nextwin, pps_1ms); + for (uint32_t i = 0; i < pps_now; ++i) { + if (d->is_ul) + write_pdcp_header(packet_count, PDCP_SN_LEN_12, buf); + *payload = packet_count++; + gtpv1uSendDirect(d->inst, d->ue_id, bearer, (uint8_t *)buf, packet_len, false, false); + d->total_data += d->data_len; + } + + struct timespec t; + clock_gettime(CLOCK_MONOTONIC, &t); + float diff_us = time_diff(start, t); + int us_passed = diff_us - i_1ms*1000; + int iter_advance = us_passed / 1000 + 1; + int wait_usec = 1000 - us_passed; + //printf("diff %.3fus i_1ms %d us_passed %d iter %d wait %d (%.3f %%)\n", diff_us, i_1ms, us_passed, iter_advance, wait_usec, 100.0 * d->total_data / to_send); + DevAssert(iter_advance > 0); + if (wait_usec > 0) + usleep(wait_usec); + + if (iter_advance > 1) /* we have to send more in the next window */ + pps_1ms_nextwin += (iter_advance - 1) * pps_1ms_nextwin; + i_1ms += iter_advance; + if (d->total_data >= to_send) + break; + } + struct timespec end; + clock_gettime(CLOCK_MONOTONIC, &end); + d->total_time = time_diff(start, end) / 1000000.f; + return NULL; +} + +/* @brief print statistics of a UE (amount of data, achieved rate, if data was + * lost). */ +static bool print_stats(const char *pref, int ue_id, uint64_t total_data, float duration, const struct ue_stat *s) +{ + float tthr = 8.0 * total_data / duration / 1000000.f; + float rthr = 8.0 * s->received / duration / 1000000.f; + LOG_I(GNB_APP, "%d %s sent %ld in %.3f s received %ld bytes => rates [Mbps] transmit %.3f receive %.3f\n", + ue_id, + pref, + total_data, + duration, + s->received, + tthr, + rthr); + if (total_data == s->received) { + DevAssert(s->lost == 0); + LOG_A(GNB_APP, "%d %s received all data sent\n", ue_id, pref); + return true; + } else { + uint64_t m = total_data - s->received; + LOG_W(GNB_APP, "%d %s warning: missing %ld bytes (%.3f %%, %d packets)\n", ue_id, pref, m, 100.f * m / total_data, s->lost); + return false; + } +} + +/* @brief start a thread if specified through template, and in direction of + * given GTP bearer. + * @param template specifies if thread is to be started (throughput and + * duration are positive). If so, the template data is stored inside the + * thread. + * @param thr place to store thread data + * @param b the GTP bearer to use */ +static struct thr_data *start_thread(const struct thr_data *template, struct thr_data *thr, instance_t inst, ue_id_t ue_id) +{ + if (template->throughput == 0 || template->duration == 0) + return NULL; + + *thr = *template; + thr->inst = inst; + thr->ue_id = ue_id; + pthread_create(&thr->t, NULL, sender_thread, thr); + return thr; +} + +/* @brief print progress of a thread specified in thr_data, and prepend DL/UL + * based on dir. data access to thread data is not private, but we only read, + * so don't care. */ +static bool print_progress(const int dir, const struct thr_data *obs) +{ + if (!obs) + return false; + + uint64_t target = (uint64_t) obs->throughput / 8 * obs->duration; + float progress = (float)obs->total_data / target; + printf(" %s sent %3.f %%", dir == DL ? "DL" : "UL", 100.0 * progress); + return progress < 0.99; +} + +int main(int argc, char *argv[]) +{ + if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + logInit(); + itti_init(TASK_MAX, tasks_info); + + unsigned int n_ue; + unsigned int duration_s; + unsigned int packet_size; + uint64_t target_rate_dl; + uint64_t target_rate_ul; + char *ng_ip = malloc_or_fail(100); + uint16_t ng_port; + char *f1_ip = malloc_or_fail(100); + uint16_t f1_port; + + paramdef_t param_def[] = { + {"n", "number of UEs\n", 0, .uptr = &n_ue, .defuintval = 1, TYPE_UINT}, + {"t", "duration of test (s)\n", 0, .uptr = &duration_s, .defuintval = 10, TYPE_UINT}, + {"p", "packet size\n", 0, .uptr = &packet_size, .defuintval = 1400, TYPE_UINT}, + {"d", "DL target rate (Mbps, per UE)\n", 0, .u64ptr = &target_rate_dl, .defint64val = 60, TYPE_UINT64}, + {"u", "UL target rate (Mbps, per UE)\n", 0, .u64ptr = &target_rate_ul, .defint64val = 60, TYPE_UINT64}, + {"ng-ip", "Tester NG-U IP\n", 0, .strptr = &ng_ip, .defstrval = "127.0.0.1", TYPE_STRING, 100}, + {"ng-port", "Tester NG-U port\n", 0, .u16ptr = &ng_port, .defuintval = 2152, TYPE_UINT16}, + {"f1-ip", "Tester F1-U IP\n", 0, .strptr = &f1_ip, .defstrval = "127.0.0.1", TYPE_STRING, 100}, + {"f1-port", "Tester F1-U port\n", 0, .u16ptr = &f1_port, .defuintval = 2153, TYPE_UINT16}, + }; + config_get(uniqCfg, param_def, sizeofArray(param_def), NULL); + // on command line, target rate is in Mbps, convert to bps + target_rate_dl *= 1000000LL; + target_rate_ul *= 1000000LL; + LOG_I(GNB_APP, + "CU-UP load tester: running test for\n" + "- Number of UEs %d\n" + "- Duration %d seconds\n" + "- Packet size %d\n" + "- Target DL rate %.3f Mbps (per UE)\n" + "- Target UL rate %.3f Mbps (per UE)\n" + "- Tester endpoint for CU-UP NG-U: %s:%d\n" + "- Tester endpoint for CU-UP F1-U: %s:%d\n", + n_ue, duration_s, packet_size, + (float) target_rate_dl / 1e6, + (float) target_rate_ul / 1e6, + ng_ip, ng_port, f1_ip, f1_port); + + struct thr_data dl_template = {.is_ul = false, .data_len = packet_size, .throughput = target_rate_dl, .duration = duration_s}; + struct thr_data ul_template = {.is_ul = true, .data_len = packet_size, .throughput = target_rate_ul, .duration = duration_s}; + + /* init GTP for NG-U comm with CU-UP */ + instance_t ng_inst = init_gtp(ng_ip, ng_port); + AssertFatal(ng_inst > 0, "could not initialize GTP interface on %s:%d towards CU-UP NG-U\n", ng_ip, ng_port); + + /* init GTP for F1-U comm with CU-UP */ + instance_t f1_inst = init_gtp(f1_ip, f1_port); + AssertFatal(f1_inst > 0, "could not initialize GTP interface on %s:%d towards CU-UP F1-U\n", f1_ip, f1_port); + + /* Start relevant services: SCTP, CUCP_E1: E1; GTP not actively used; RRC to + * register the queue so we can receive what E1 sends us back */ + int rc; + rc = itti_create_task(TASK_SCTP, sctp_eNB_task, NULL); + AssertFatal(rc >= 0, "Create task for SCTP failed\n"); + rc = itti_create_task(TASK_CUCP_E1, E1AP_CUCP_task, NULL); + AssertFatal(rc >= 0, "Create task for CUUP E1 failed\n"); + rc = itti_create_task(TASK_GTPV1_U, gtpv1uTask, NULL); + AssertFatal(rc >= 0, "Create task for GTPV1U failed\n"); + rc = itti_create_task(TASK_RRC_GNB, cuup_tester_rrc, NULL); + AssertFatal(rc >= 0, "Create task for RRC failed\n"); + init_e1(); + + /* Set up CU-UP connection: waits for CU-UP-initiated SCTP+E1 setup request */ + sctp_assoc_t assoc_id; + e1ap_nssai_t nssai; + setup_cuup(&assoc_id, &nssai); + + /* Set up UE contexts in CU-UP. the below two calls correspond to + * - setup_cuup_ue_ng(): E1 bearer context setup <=> completely sets up NG-U + * in CU-UP, gets TEID for F1-U UL + * - setup_cuup_ue_f1(): E1 bearer context modification <=> send TEID for + * F1-U DL (as if we had talked to the DU in the middle) */ + for (int ue = 0; ue < n_ue; ++ue) { + up_params_t f1_up = setup_cuup_ue_ng(assoc_id, &nssai, ue, ng_inst, ng_ip); + setup_cuup_ue_f1(assoc_id, ue, f1_inst, f1_ip, f1_up); + } + + usleep(1000); + + /* for each UE, start DL&UL data streams in dedicated thread, if configured */ + struct thr_data thrd[n_ue][2]; + memset(thrd, 0, sizeof(thrd)); + struct thr_data *obs_dl = NULL, *obs_ul = NULL; + for (int ue = 0; ue < n_ue; ++ue) { + obs_dl = start_thread(&dl_template, &thrd[ue][DL], ng_inst, ue); + obs_ul = start_thread(&ul_template, &thrd[ue][UL], f1_inst, ue); + } + /* show progress of one thread (all take the same time) */ + while (obs_dl || obs_ul) { + bool dlrunning = print_progress(DL, obs_dl); + bool ulrunning = print_progress(UL, obs_ul); + printf("\r"); + fflush(stdout); + if (!dlrunning && !ulrunning) + break; + usleep(100000); + } + /* join threads, if applicable */ + for (int ue = 0; ue < n_ue; ++ue) { + struct thr_data *dl = &thrd[ue][DL]; + if (dl->t) + pthread_join(dl->t, NULL); + struct thr_data *ul = &thrd[ue][UL]; + if (ul->t) + pthread_join(ul->t, NULL); + } + + /* wait a bit, to ensure all data is received after having sent it above */ + sleep(1); + + for (int ue = 0; ue < n_ue; ++ue) { + e1_release_ue(assoc_id, ue, f1_inst, ng_inst); + } + + /* show stats of all threads */ + bool success = true; + for (int ue = 0; ue < n_ue; ++ue) { + struct thr_data *thrddl = &thrd[ue][DL]; + struct ue_stat *statdl = &ue_stat[ue][DL]; + if (thrddl->t) + if (!print_stats("DL", ue, thrddl->total_data, thrddl->total_time, statdl)) + success = false; + struct thr_data *thrdul = &thrd[ue][UL]; + struct ue_stat *statul = &ue_stat[ue][UL]; + if (thrdul->t) + if (!print_stats("UL", ue, thrdul->total_data, thrdul->total_time, statul)) + success = false; + } + + if (success) + LOG_A(GNB_APP, "test succeeded\n"); + else + LOG_W(GNB_APP, "TEST FAILED\n"); + return success ? 0 : 1; +} diff --git a/tools/docker-dev-env/README.md b/tools/docker-dev-env/README.md index 5dcb15eb5c..63bd598725 100644 --- a/tools/docker-dev-env/README.md +++ b/tools/docker-dev-env/README.md @@ -2,7 +2,7 @@ ## Description -This contains bash scripts for managing a ubuntu22 dockerized development enviroment for OAI. No need to install any +This contains bash scripts for managing a ubuntu24 dockerized development enviroment for OAI. No need to install any tools on host machines except for docker - `bootstrap.sh` - build development environment image and install the following bash aliases in `~/.bash_aliases`: diff --git a/tools/docker-dev-env/bootstrap.sh b/tools/docker-dev-env/bootstrap.sh index 8c21554dcf..e56be3fa91 100755 --- a/tools/docker-dev-env/bootstrap.sh +++ b/tools/docker-dev-env/bootstrap.sh @@ -11,7 +11,7 @@ fi if ! docker images | grep -q "ran-base"; then echo "ran-base:latest image not found. Building the image..." - docker build -f ../../docker/Dockerfile.base.ubuntu22 -t ran-base:latest ../../ + docker build -f ../../docker/Dockerfile.base.ubuntu -t ran-base:latest ../../ else echo "ran-base:latest image found." fi