diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e8758cea3..5d9ca49a4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -709,14 +709,15 @@ target_link_libraries(SCHED_LIB PRIVATE asn1_lte_rrc_hdrs) set(SCHED_NR_SRC ${OPENAIR1_DIR}/SCHED_NR/phy_procedures_nr_gNB.c ${OPENAIR1_DIR}/SCHED_NR/nr_prach_procedures.c + ${OPENAIR1_DIR}/SCHED_NR/nr_ru_procedures.c ${OPENAIR1_DIR}/SCHED_NR/phy_frame_config_nr.c ) add_library(SCHED_NR_LIB ${SCHED_NR_SRC}) target_link_libraries(SCHED_NR_LIB PRIVATE asn1_nr_rrc_hdrs UTIL) +target_link_libraries(SCHED_NR_LIB PRIVATE NFAPI_LIB) # some FAPI messages pack "subPDUs" set(SCHED_SRC_RU ${OPENAIR1_DIR}/SCHED/ru_procedures.c - ${OPENAIR1_DIR}/SCHED_NR/nr_ru_procedures.c ${OPENAIR1_DIR}/SCHED/prach_procedures.c ) add_library(SCHED_RU_LIB ${SCHED_SRC_RU}) @@ -752,6 +753,7 @@ set(NFAPI_SRC 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) +target_link_libraries(NFAPI_LIB PRIVATE z) if(OAI_WLS) target_compile_definitions(NFAPI_LIB PRIVATE ENABLE_WLS) @@ -877,6 +879,10 @@ set(PHY_SRC ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pilots_mbsfn.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_coding.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dlsch_modulation.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/pbch.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci.c @@ -893,22 +899,22 @@ set(PHY_SRC ) set(PHY_SRC_RU - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/if4_tools.c + ${OPENAIR1_DIR}/PHY/if4_tools.c ${OPENAIR1_DIR}/PHY/LTE_UE_TRANSPORT/drs_modulation.c - ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation.c - ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c - ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c - ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_ul.c - ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_nr.c ${OPENAIR1_DIR}/PHY/MODULATION/ul_7_5_kHz.c ${OPENAIR1_DIR}/PHY/MODULATION/gen_75KHz.cpp ${OPENAIR1_DIR}/PHY/MODULATION/beamforming.c ${OPENAIR1_DIR}/PHY/MODULATION/compute_bf_weights.c ${OPENAIR1_DIR}/PHY/INIT/lte_init_ru.c - ${OPENAIR1_DIR}/PHY/INIT/nr_init_ru.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/prach.c + ) +set(NR_PHY_SRC_RU + ${OPENAIR1_DIR}/PHY/MODULATION/nr_beamforming.c + ${OPENAIR1_DIR}/PHY/MODULATION/slot_fep_nr.c + ${OPENAIR1_DIR}/PHY/INIT/nr_init_ru.c + ${OPENAIR1_DIR}/PHY/if4_tools.c ) set(PHY_SRC_UE @@ -1068,7 +1074,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 nr_fapi_p5 polar smallblock) +target_link_libraries(PHY_NR nr_phy_common nr_common nr_fapi_p5 polar smallblock ds) add_library(PHY_NR_NO_AVX_256 ${PHY_NR_SRC}) target_link_libraries(PHY_NR_NO_AVX_256 nr_phy_common nr_common) @@ -1080,6 +1086,8 @@ target_link_libraries(PHY_NR_UE PRIVATE asn1_nr_rrc_hdrs nr_phy_common nr_common add_library(PHY_RU ${PHY_SRC_RU}) target_link_libraries(PHY_RU PRIVATE asn1_lte_rrc_hdrs UTIL) +add_library(NR_PHY_RU ${NR_PHY_SRC_RU}) + #Layer 2 library ##################### set(MAC_DIR ${OPENAIR2_DIR}/LAYER2/MAC) @@ -1742,7 +1750,7 @@ target_link_libraries(lte-softmodem PRIVATE lte_rrc nr_rrc s1ap m2ap x2ap m3ap GTPV1U SECURITY UTIL SCTP_CLIENT MME_APP SCHED_LIB SCHED_RU_LIB PHY_COMMON PHY PHY_RU L2 L2_LTE NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB MISC_NFAPI_LTE_LIB ${NAS_UE_LIB} ITTI SIMU radio_common softmodem_common - -Wl,--end-group z dl) + -Wl,--end-group dl) target_link_libraries(lte-softmodem PRIVATE pthread m CONFIG_LIB rt) target_link_libraries(lte-softmodem PRIVATE ${T_LIB}) @@ -1757,13 +1765,17 @@ add_executable(oairu ${OPENAIR_DIR}/executables/lte-ru.c ${OPENAIR_DIR}/executables/ru_control.c ${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_ul_channel_estimation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/freq_equalization.c + ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/ulsch_demodulation.c + ${OPENAIR1_DIR}/PHY/LTE_ESTIMATION/lte_adjust_sync_eNB.c ${OPENAIR_DIR}/executables/main_ru.c ${OPENAIR_DIR}/common/utils/lte/prach_utils.c ) target_link_libraries(oairu PRIVATE -Wl,--start-group SCHED_RU_LIB PHY_COMMON PHY_RU UTIL radio_common softmodem_common - -Wl,--end-group z dl) + -Wl,--end-group dl) target_link_libraries(oairu PRIVATE pthread m CONFIG_LIB rt ${T_LIB}) target_link_libraries(oairu PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) @@ -1792,7 +1804,7 @@ target_link_libraries(lte-uesoftmodem PRIVATE SECURITY UTIL SCTP_CLIENT MME_APP SCHED_RU_LIB SCHED_UE_LIB PHY_COMMON PHY_UE PHY_RU L2_UE L2_LTE SIMU NFAPI_LIB NFAPI_PNF_LIB NFAPI_USER_LIB MISC_NFAPI_LTE_LIB ${NAS_UE_LIB} ITTI radio_common softmodem_common - -Wl,--end-group z dl) + -Wl,--end-group dl) target_link_libraries(lte-uesoftmodem PRIVATE pthread m CONFIG_LIB rt) target_link_libraries(lte-uesoftmodem PRIVATE ${T_LIB}) @@ -1808,11 +1820,12 @@ add_executable(nr-oru ${OPENAIR_DIR}/openair1/PHY/INIT/nr_parms.c ${OPENAIR_DIR}/openair1/SCHED_NR/phy_frame_config_nr.c ${OPENAIR_DIR}/openair1/SCHED_NR/nr_prach_procedures.c + ${OPENAIR_DIR}/openair1/SCHED_NR/nr_ru_procedures.c ${OPENAIR_DIR}/openair1/SCHED/phy_procedures_lte_common.c ${OPENAIR_DIR}/executables/main_nr_ru.c ) target_link_libraries(nr-oru PRIVATE - UTIL SCHED_RU_LIB PHY_COMMON PHY_RU PHY_NR shlib_loader z dl + UTIL NR_PHY_RU PHY_NR shlib_loader dl radio_common softmodem_common) target_link_libraries(nr-oru PRIVATE pthread m CONFIG_LIB rt ${T_LIB} utils barrier actor) @@ -1836,12 +1849,12 @@ add_executable(nr-softmodem target_link_libraries(nr-softmodem PRIVATE -Wl,--start-group - UTIL SCTP_CLIENT SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_NR_COMMON PHY_RU GTPV1U SECURITY - ITTI ${NAS_UE_LIB} lte_rrc nr_rrc + UTIL SCTP_CLIENT SCHED_LIB SCHED_NR_LIB PHY_NR PHY PHY_NR_COMMON NR_PHY_RU GTPV1U SECURITY + ITTI ${NAS_UE_LIB} nr_rrc ngap s1ap L2_LTE_NR L2_NR MAC_NR_COMMON NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB SIMU x2ap f1ap m2ap m3ap e1ap radio_common time_management softmodem_common - -Wl,--end-group z dl) + -Wl,--end-group dl) target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt) target_link_libraries(nr-softmodem PRIVATE ${T_LIB}) @@ -1881,7 +1894,7 @@ target_link_libraries(nr-cuup PRIVATE GTPV1U e1ap f1ap time_management softmodem_common alg - z dl pthread ${T_LIB}) + dl pthread ${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) @@ -1905,11 +1918,11 @@ add_executable(nr-uesoftmodem target_link_libraries(nr-uesoftmodem PRIVATE -Wl,--start-group - nr_rrc SECURITY UTIL SCHED_RU_LIB SCHED_NR_UE_LIB - PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB + nr_rrc SECURITY UTIL SCHED_NR_UE_LIB + PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB ITTI SIMU radio_common time_management softmodem_common - -Wl,--end-group z dl) + -Wl,--end-group dl) target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_meas) target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB}) @@ -1983,14 +1996,14 @@ target_link_libraries(physim_common PRIVATE UTIL) add_executable(nr_dlschsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlschsim.c) target_link_libraries(nr_dlschsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group m pthread ${T_LIB} ITTI dl physim_common ) target_link_libraries(nr_dlschsim PRIVATE asn1_nr_rrc_hdrs) add_executable(nr_pbchsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/pbchsim.c) target_link_libraries(nr_pbchsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group m pthread ${T_LIB} ITTI dl physim_common ) target_link_libraries(nr_pbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) @@ -2000,14 +2013,14 @@ add_executable(nr_psbchsim ${NFAPI_USER_DIR}/nfapi.c ) target_link_libraries(nr_psbchsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB -Wl,--end-group + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB -Wl,--end-group m pthread ${T_LIB} ITTI dl physim_common softmodem_common ) target_link_libraries(nr_psbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_pucchsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/pucchsim.c) target_link_libraries(nr_pucchsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group m pthread ${T_LIB} ITTI dl physim_common ) target_link_libraries(nr_pucchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) @@ -2019,15 +2032,15 @@ add_executable(nr_dlsim ${PHY_INTERFACE_DIR}/queue_t.c ) target_link_libraries(nr_dlsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -Wl,--end-group - m pthread ${T_LIB} ITTI dl nr_ue_phy_meas physim_common + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -Wl,--end-group + m pthread ${T_LIB} ITTI dl nr_ue_phy_meas physim_common NR_L2_UE softmodem_common ) target_link_libraries(nr_dlsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) add_executable(nr_prachsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/prachsim.c) target_link_libraries(nr_prachsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_RU PHY_NR_UE MAC_NR_COMMON SCHED_NR_LIB CONFIG_LIB -Wl,--end-group + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR NR_PHY_RU PHY_NR_UE MAC_NR_COMMON SCHED_NR_LIB CONFIG_LIB -Wl,--end-group m pthread ${T_LIB} ITTI dl physim_common) target_link_libraries(nr_prachsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) @@ -2035,7 +2048,7 @@ add_executable(nr_ulschsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/ulschsim.c ) target_link_libraries(nr_ulschsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB CONFIG_LIB MAC_NR_COMMON -Wl,--end-group m pthread ${T_LIB} ITTI dl physim_common ) target_link_libraries(nr_ulschsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) @@ -2048,8 +2061,8 @@ add_executable(nr_ulsim ) target_link_libraries(nr_ulsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -Wl,--end-group - m pthread ${T_LIB} ITTI dl nr_ue_phy_meas physim_common softmodem_common + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -Wl,--end-group + m pthread ${T_LIB} ITTI dl nr_ue_phy_meas physim_common softmodem_common NR_L2_UE ) target_link_libraries(nr_ulsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) @@ -2059,7 +2072,7 @@ add_executable(nr_srssim ) target_link_libraries(nr_srssim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON -Wl,--end-group + -Wl,--start-group UTIL SIMU PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON -Wl,--end-group m pthread ITTI dl nr_ue_phy_meas physim_common softmodem_common ) @@ -2128,7 +2141,7 @@ if (${T_TRACER}) 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 - PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU + PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU NR_PHY_RU L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE MAC_NR_COMMON MAC_UE_NR ngap GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE SIMU dfts config_internals nr_common crc_byte) diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container index d75b1888d4..721c89b77f 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Container +++ b/ci-scripts/Jenkinsfile-GitLab-Container @@ -219,28 +219,6 @@ pipeline { } } } - stage ("cppcheck") { - steps { - script { - triggerSlaveJob ('RAN-cppcheck', 'cppcheck') - } - } - post { - always { - script { - // Using a unique variable name for each test stage to avoid overwriting on a global variable - // due to parallel-time concurrency - cppcheckStatus = finalizeSlaveJob('RAN-cppcheck') - } - } - failure { - script { - currentBuild.result = 'FAILURE' - failingStages += cppcheckStatus - } - } - } - } stage ("ARM-Cross-Compile") { steps { script { diff --git a/ci-scripts/args_parse.py b/ci-scripts/args_parse.py index 6206c67d69..16e23113ab 100644 --- a/ci-scripts/args_parse.py +++ b/ci-scripts/args_parse.py @@ -22,7 +22,7 @@ import constants as CONST #----------------------------------------------------------- -def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): +def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,CLUSTER): force_local = False date_fmt = None @@ -53,7 +53,6 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): RAN.ranRepository=matchReg.group(1) HTML.ranRepository=matchReg.group(1) CONTAINERS.ranRepository=matchReg.group(1) - SCA.ranRepository=matchReg.group(1) CLUSTER.ranRepository=matchReg.group(1) elif re.match(r'^\-\-eNB_AllowMerge=(.+)$|^\-\-ranAllowMerge=(.+)$', myArgv, re.IGNORECASE): if re.match(r'^\-\-eNB_AllowMerge=(.+)$', myArgv, re.IGNORECASE): @@ -66,7 +65,6 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): RAN.ranAllowMerge=True HTML.ranAllowMerge=True CONTAINERS.ranAllowMerge=True - SCA.ranAllowMerge=True CLUSTER.ranAllowMerge=True elif re.match(r'^\-\-eNBBranch=(.+)$|^\-\-ranBranch=(.+)$', myArgv, re.IGNORECASE): if re.match(r'^\-\-eNBBranch=(.+)$', myArgv, re.IGNORECASE): @@ -77,7 +75,6 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): RAN.ranBranch=matchReg.group(1) HTML.ranBranch=matchReg.group(1) CONTAINERS.ranBranch=matchReg.group(1) - SCA.ranBranch=matchReg.group(1) CLUSTER.ranBranch=matchReg.group(1) elif re.match(r'^\-\-eNBCommitID=(.*)$|^\-\-ranCommitID=(.*)$', myArgv, re.IGNORECASE): if re.match(r'^\-\-eNBCommitID=(.*)$', myArgv, re.IGNORECASE): @@ -88,7 +85,6 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): RAN.ranCommitID=matchReg.group(1) HTML.ranCommitID=matchReg.group(1) CONTAINERS.ranCommitID=matchReg.group(1) - SCA.ranCommitID=matchReg.group(1) CLUSTER.ranCommitID=matchReg.group(1) elif re.match(r'^\-\-eNBTargetBranch=(.*)$|^\-\-ranTargetBranch=(.*)$', myArgv, re.IGNORECASE): if re.match(r'^\-\-eNBTargetBranch=(.*)$', myArgv, re.IGNORECASE): @@ -99,7 +95,6 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): RAN.ranTargetBranch=matchReg.group(1) HTML.ranTargetBranch=matchReg.group(1) CONTAINERS.ranTargetBranch=matchReg.group(1) - SCA.ranTargetBranch=matchReg.group(1) CLUSTER.ranTargetBranch=matchReg.group(1) elif re.match(r'^\-\-eNBIPAddress=(.+)$|^\-\-eNB[1-2]IPAddress=(.+)$', myArgv, re.IGNORECASE): print("parameters --eNB*IPAddress ignored") @@ -112,7 +107,6 @@ def ArgsParse(argvs,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER): matchReg = re.match(r'^\-\-eNBSourceCodePath=(.+)$', myArgv, re.IGNORECASE) RAN.eNBSourceCodePath=matchReg.group(1) CONTAINERS.eNBSourceCodePath=matchReg.group(1) - SCA.eNBSourceCodePath=matchReg.group(1) CLUSTER.eNBSourceCodePath=matchReg.group(1) elif re.match(r'^\-\-eNB1SourceCodePath=(.+)$', myArgv, re.IGNORECASE): print("parameter --eNB1SourceCodePath ignored") diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index c7831136e2..461c64d133 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -184,11 +184,6 @@ class Containerize(): self.services = '' self.deploymentTag = '' - self.cli = '' - self.cliBuildOptions = '' - self.dockerfileprefix = '' - self.host = '' - self.num_attempts = 1 self.flexricTag = '' @@ -203,18 +198,7 @@ class Containerize(): cmd = cls_cmd.getConnection(node) log_files = [] - # Checking the hostname to get adapted on cli and dockerfileprefixes - cmd.run('hostnamectl') - result = re.search('Ubuntu|Red Hat', cmd.getBefore()) - self.host = result.group(0) - if self.host == 'Ubuntu': - self.cli = 'docker' - self.dockerfileprefix = '.ubuntu' - self.cliBuildOptions = '' - elif self.host == 'Red Hat': - self.cli = 'sudo podman' - self.dockerfileprefix = '.rhel9' - self.cliBuildOptions = '--disable-compression' + dockerfileprefix = '.ubuntu' # we always build the ran-build image with all targets # Creating a tupple with the imageName, the DockerFile prefix pattern, targetName and sanitized option @@ -232,23 +216,20 @@ class Containerize(): imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup', '')) imageNames.append(('oai-lte-ue', 'lteUE', 'oai-lte-ue', '')) imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', '')) - if self.host == 'Red Hat': - imageNames.append(('oai-physim', 'phySim', 'oai-physim', '')) - if self.host == 'Ubuntu': - imageNames.append(('oai-lte-ru', 'lteRU', 'oai-lte-ru', '')) - # Building again the 5G images with Address Sanitizer - imageNames.append(('ran-build', 'build', 'ran-build-asan', '--build-arg "BUILD_OPTION=--sanitize"')) - imageNames.append(('oai-enb', 'eNB', 'oai-enb-asan', '--build-arg "BUILD_OPTION=--sanitize"')) - imageNames.append(('oai-gnb', 'gNB', 'oai-gnb-asan', '--build-arg "BUILD_OPTION=--sanitize"')) - imageNames.append(('oai-lte-ue', 'lteUE', 'oai-lte-ue-asan', '--build-arg "BUILD_OPTION=--sanitize"')) - imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue-asan', '--build-arg "BUILD_OPTION=--sanitize"')) - imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup-asan', '--build-arg "BUILD_OPTION=--sanitize"')) - imageNames.append(('ran-build-fhi72', 'build.fhi72', 'ran-build-fhi72', '')) - imageNames.append(('oai-gnb', 'gNB.fhi72', 'oai-gnb-fhi72', '')) - imageNames.append(('oai-nr-oru', 'nrORU.fhi72', 'oai-nr-oru', '')) + imageNames.append(('oai-lte-ru', 'lteRU', 'oai-lte-ru', '')) + # Building again the 5G images with Address Sanitizer + imageNames.append(('ran-build', 'build', 'ran-build-asan', '--build-arg "BUILD_OPTION=--sanitize"')) + imageNames.append(('oai-enb', 'eNB', 'oai-enb-asan', '--build-arg "BUILD_OPTION=--sanitize"')) + imageNames.append(('oai-gnb', 'gNB', 'oai-gnb-asan', '--build-arg "BUILD_OPTION=--sanitize"')) + imageNames.append(('oai-lte-ue', 'lteUE', 'oai-lte-ue-asan', '--build-arg "BUILD_OPTION=--sanitize"')) + imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue-asan', '--build-arg "BUILD_OPTION=--sanitize"')) + imageNames.append(('oai-nr-cuup', 'nr-cuup', 'oai-nr-cuup-asan', '--build-arg "BUILD_OPTION=--sanitize"')) + imageNames.append(('ran-build-fhi72', 'build.fhi72', 'ran-build-fhi72', '')) + imageNames.append(('oai-gnb', 'gNB.fhi72', 'oai-gnb-fhi72', '')) + imageNames.append(('oai-nr-oru', 'nrORU.fhi72', 'oai-nr-oru', '')) result = re.search('build_cross_arm64', self.imageKind) if result is not None: - self.dockerfileprefix = '.ubuntu.cross-arm64' + dockerfileprefix = '.ubuntu.cross-arm64' result = re.search('native_armv9', self.imageKind) if result is not None: imageNames.append(('oai-gnb', 'gNB', 'oai-gnb', '')) @@ -263,10 +244,6 @@ class Containerize(): imageNames.append(('oai-nr-ue', 'nrUE', 'oai-nr-ue', '')) cmd.cd(lSourcePath) - # if asterix, copy the entitlement and subscription manager configurations - if self.host == 'Red Hat': - cmd.run('mkdir -p ./etc-pki-entitlement') - cmd.run('cp /etc/pki/entitlement/*.pem ./etc-pki-entitlement/') baseImage = 'ran-base' baseTag = 'develop' @@ -275,7 +252,7 @@ class Containerize(): if (self.ranAllowMerge): imageTag = 'ci-temp' if self.ranTargetBranch == 'develop': - cmd.run(f'git diff HEAD..origin/develop -- cmake_targets/build_oai cmake_targets/tools/build_helper docker/Dockerfile.base{self.dockerfileprefix} | grep --colour=never -i INDEX') + cmd.run(f'git diff HEAD..origin/develop -- cmake_targets/build_oai cmake_targets/tools/build_helper docker/Dockerfile.base{dockerfileprefix} | grep --colour=never -i INDEX') result = re.search('index', cmd.getBefore()) if result is not None: forceBaseImageBuild = True @@ -289,31 +266,30 @@ class Containerize(): forceBaseImageBuild = True # Let's remove any previous run artifacts if still there - cmd.run(f"{self.cli} image prune --force") + cmd.run(f"docker image prune --force") for image,pattern,name,option in imageNames: - cmd.run(f"{self.cli} image rm {name}:{imageTag}", reportNonZero=False) + cmd.run(f"docker image rm {name}:{imageTag}", reportNonZero=False) cmd.run(f'docker login -u oaicicd -p oaicicd {DEFAULT_REGISTRY}') ubuntuImage = "ubuntu:noble" # 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"docker image rm {baseImage}:{baseTag}") logfile = f'{lSourcePath}/cmake_targets/log/ran-base.docker.log' - if self.host == 'Ubuntu': - option = f" --build-arg UBUNTU_IMAGE={DEFAULT_REGISTRY}/{ubuntuImage}" - cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} {option} . &> {logfile}", timeout=1600) + option = f" --build-arg UBUNTU_IMAGE={DEFAULT_REGISTRY}/{ubuntuImage}" + cmd.run(f"docker build --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{dockerfileprefix} {option} . &> {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}") + ret = cmd.run(f"docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}") allImagesSize = {} if ret.returncode != 0: logging.error('\u001B[1m Could not build properly ran-base\u001B[0m') # Recover the name of the failed container? - cmd.run(f"{self.cli} ps --quiet --filter \"status=exited\" -n1 | xargs --no-run-if-empty {self.cli} rm -f") - cmd.run(f"{self.cli} image prune --force") + cmd.run(f"docker ps --quiet --filter \"status=exited\" -n1 | xargs --no-run-if-empty docker rm -f") + cmd.run(f"docker image prune --force") cmd.close() logging.error('\u001B[1m Building OAI Images Failed\u001B[0m') HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK) @@ -333,32 +309,31 @@ class Containerize(): for image,pattern,name,option in imageNames: # 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}') - cmd.run(f'sed -i -e "s#{baseImage}:latest#{baseImage}:{baseTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}') + cmd.run(f'git checkout -- docker/Dockerfile.{pattern}{dockerfileprefix}') + cmd.run(f'sed -i -e "s#{baseImage}:latest#{baseImage}:{baseTag}#" docker/Dockerfile.{pattern}{dockerfileprefix}') # target images should use the proper ran-build image if image != 'ran-build' and "-asan" in name: - cmd.run(f'sed -i -e "s#ran-build:latest#ran-build-asan:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}') + cmd.run(f'sed -i -e "s#ran-build:latest#ran-build-asan:{imageTag}#" docker/Dockerfile.{pattern}{dockerfileprefix}') elif "fhi72" in name or name == "oai-nr-oru": - cmd.run(f'sed -i -e "s#ran-build-fhi72:latest#ran-build-fhi72:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}') + cmd.run(f'sed -i -e "s#ran-build-fhi72:latest#ran-build-fhi72:{imageTag}#" docker/Dockerfile.{pattern}{dockerfileprefix}') elif image != 'ran-build': - cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{self.dockerfileprefix}') + cmd.run(f'sed -i -e "s#ran-build:latest#ran-build:{imageTag}#" docker/Dockerfile.{pattern}{dockerfileprefix}') if image == 'oai-gnb-aerial': cmd.run('cp -f /opt/nvidia-ipc/nvipc_src.2026.01.07.tar.gz .') logfile = f'{lSourcePath}/cmake_targets/log/{name}.docker.log' - if self.host == 'Ubuntu': - option = option + f" --build-arg UBUNTU_IMAGE={DEFAULT_REGISTRY}/{ubuntuImage}" - 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) + option = option + f" --build-arg UBUNTU_IMAGE={DEFAULT_REGISTRY}/{ubuntuImage}" + ret = cmd.run(f'docker build --target {image} --tag {name}:{imageTag} --file docker/Dockerfile.{pattern}{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.2026.01.07.tar.gz') # check the status of the build - ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}") + ret = cmd.run(f"docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' {name}:{imageTag}") if ret.returncode != 0: logging.error('\u001B[1m Could not build properly ' + name + '\u001B[0m') status = False # Here we should check if the last container corresponds to a failed command and destroy it - cmd.run(f"{self.cli} ps --quiet --filter \"status=exited\" -n1 | xargs --no-run-if-empty {self.cli} rm -f") + cmd.run(f"docker ps --quiet --filter \"status=exited\" -n1 | xargs --no-run-if-empty docker rm -f") allImagesSize[name] = 'N/A -- Build Failed' break else: @@ -372,16 +347,16 @@ class Containerize(): logging.debug(f'{name} size is unknown') allImagesSize[name] = 'unknown' # Now pruning dangling images in between target builds - cmd.run(f"{self.cli} image prune --force") + cmd.run(f"docker image prune --force") cmd.run(f'docker logout {DEFAULT_REGISTRY}') # Remove all intermediate build images and clean up - cmd.run(f"{self.cli} image rm ran-build:{imageTag} ran-build-asan:{imageTag} ran-build-fhi72:{imageTag} || true") - cmd.run(f"{self.cli} volume prune --force") + cmd.run(f"docker image rm ran-build:{imageTag} ran-build-asan:{imageTag} ran-build-fhi72:{imageTag} || true") + cmd.run(f"docker volume prune --force") # Remove some cached artifacts to prevent out of diskspace problem logging.debug(cmd.run("df -h").stdout) logging.debug(cmd.run("docker system df").stdout) - cmd.run(f"{self.cli} buildx prune --filter until=1h --force") + cmd.run(f"docker buildx prune --filter until=1h --force") logging.debug(cmd.run("df -h").stdout) logging.debug(cmd.run("docker system df").stdout) @@ -489,20 +464,12 @@ class Containerize(): cmd = cls_cmd.getConnection(node) cmd.cd(lSourcePath) - ret = cmd.run('hostnamectl') - result = re.search('Ubuntu', ret.stdout) - host = result.group(0) - if host != 'Ubuntu': - cmd.close() - raise Exception("Can build unit tests only on Ubuntu server") - logging.debug('running on Ubuntu as expected') - # check that ran-base image exists as we expect it baseImage = 'ran-base' baseTag = 'develop' if self.ranAllowMerge: if self.ranTargetBranch == 'develop': - cmd.run(f'git diff HEAD..origin/develop -- cmake_targets/build_oai cmake_targets/tools/build_helper docker/Dockerfile.base{self.dockerfileprefix} | grep --colour=never -i INDEX') + cmd.run(f'git diff HEAD..origin/develop -- cmake_targets/build_oai cmake_targets/tools/build_helper docker/Dockerfile.base.ubuntu | grep --colour=never -i INDEX') result = re.search('index', cmd.getBefore()) if result is not None: baseTag = 'ci-temp' diff --git a/ci-scripts/cls_oai_html.py b/ci-scripts/cls_oai_html.py index 2f59ae1852..66d4b804ae 100644 --- a/ci-scripts/cls_oai_html.py +++ b/ci-scripts/cls_oai_html.py @@ -379,90 +379,6 @@ class HTMLManagement(): self.htmlFile.write(' \n') self.htmlFile.close() - def CreateHtmlTestRowCppCheckResults(self, CCR): - if (self.htmlFooterCreated or (not self.htmlHeaderCreated)): - return - self.htmlFile = open('test_results.html', 'a') - vId = 0 - for version in CCR.versions: - self.htmlFile.write(' \n') - self.htmlFile.write(' Results for cppcheck v ' + version + ' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' NB ERRORS\n') - if CCR.nbErrors[vId] == 0: - myColor = 'lightgreen' - elif CCR.nbErrors[vId] < 20: - myColor = 'orange' - else: - myColor = 'lightcoral' - self.htmlFile.write(' ' + str(CCR.nbErrors[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' NB WARNINGS\n') - if CCR.nbWarnings[vId] == 0: - myColor = 'lightgreen' - elif CCR.nbWarnings[vId] < 20: - myColor = 'orange' - else: - myColor = 'lightcoral' - self.htmlFile.write(' ' + str(CCR.nbWarnings[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' ----------------- \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Memory leak\n') - self.htmlFile.write(' ' + str(CCR.nbMemLeaks[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Possible null pointer deference\n') - self.htmlFile.write(' ' + str(CCR.nbNullPtrs[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Uninitialized variable\n') - self.htmlFile.write(' ' + str(CCR.nbUninitVars[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Undefined behaviour shifting\n') - self.htmlFile.write(' ' + str(CCR.nbTooManyBitsShift[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Signed integer overflow\n') - self.htmlFile.write(' ' + str(CCR.nbIntegerOverflow[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Printf formatting issues\n') - self.htmlFile.write(' ' + str(CCR.nbInvalidPrintf[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Modulo result is predetermined\n') - self.htmlFile.write(' ' + str(CCR.nbModuloAlways[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Opposite Condition -> dead code\n') - self.htmlFile.write(' ' + str(CCR.nbOppoInnerCondition[vId]) + '\n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' \n') - self.htmlFile.write(' Wrong Scanf Nb Args\n') - self.htmlFile.write(' ' + str(CCR.nbWrongScanfArg[vId]) + '\n') - self.htmlFile.write(' \n') - vId += 1 - def CreateHtmlTestRowPhySimTestResult(self, testSummary, testResult): if (self.htmlFooterCreated or (not self.htmlHeaderCreated)): return diff --git a/ci-scripts/cls_static_code_analysis.py b/ci-scripts/cls_static_code_analysis.py index 603df581e3..3b4ee10f9b 100644 --- a/ci-scripts/cls_static_code_analysis.py +++ b/ci-scripts/cls_static_code_analysis.py @@ -27,160 +27,30 @@ import constants as CONST import cls_cmd from cls_ci_helper import archiveArtifact -#----------------------------------------------------------- -# Class Declaration -#----------------------------------------------------------- -class CppCheckResults(): - - def __init__(self): - - self.variants = ['bionic', 'focal'] - self.versions = ['',''] - self.nbErrors = [0,0] - self.nbWarnings = [0,0] - self.nbNullPtrs = [0,0] - self.nbMemLeaks = [0,0] - self.nbUninitVars = [0,0] - self.nbInvalidPrintf = [0,0] - self.nbModuloAlways = [0,0] - self.nbTooManyBitsShift = [0,0] - self.nbIntegerOverflow = [0,0] - self.nbWrongScanfArg = [0,0] - self.nbPtrAddNotNull = [0,0] - self.nbOppoInnerCondition = [0,0] - class StaticCodeAnalysis(): - def __init__(self): - - self.ranRepository = '' - self.ranBranch = '' - self.ranAllowMerge = False - self.ranCommitID = '' - self.ranTargetBranch = '' - self.eNBSourceCodePath = '' - - def CppCheckAnalysis(self, ctx, node, HTML): - if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '': - HELP.GenericHelp(CONST.Version) - sys.exit('Insufficient Parameter') - lSourcePath = self.eNBSourceCodePath - - if not lSourcePath or not node: - raise ValueError(f"{lSourcePath=} {node=}") - logging.debug('Building on server: ' + node) - cmd = cls_cmd.getConnection(node) - # on RedHat/CentOS .git extension is mandatory - result = re.search(r'([a-zA-Z0-9\:\-\.\/])+\.git', self.ranRepository) - if result is not None: - full_ran_repo_name = self.ranRepository.replace('git/', 'git') - else: - full_ran_repo_name = self.ranRepository + '.git' - - cmd.cd(lSourcePath) - 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') - cmd.run(f'docker build --tag oai-cppcheck:bionic --file {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.bionic . > {logDir}/cppcheck-bionic.txt 2>&1') - cmd.run(f'sed -e "s@xenial@focal@" {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.xenial > {lSourcePath}/ci-scripts/docker/Dockerfile.cppcheck.focal') - 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') - - 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: - 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(filename, 'r') as logfile: - for line in logfile: - ret = re.search(r'cppcheck version="(?P[0-9\.]+)"', str(line)) - if ret is not None: - CCR.versions[vId] = ret.group('version') - if re.search('RUN cat cmake_targets/log/cppcheck.xml', str(line)) is not None: - xmlStart = True - if xmlStart: - if re.search('severity="error"', str(line)) is not None: - CCR.nbErrors[vId] += 1 - if re.search('severity="warning"', str(line)) is not None: - CCR.nbWarnings[vId] += 1 - if re.search('id="memleak"', str(line)) is not None: - CCR.nbMemLeaks[vId] += 1 - if re.search('id="nullPointer"', str(line)) is not None: - CCR.nbNullPtrs[vId] += 1 - if re.search('id="uninitvar"', str(line)) is not None: - CCR.nbUninitVars[vId] += 1 - if re.search('id="invalidPrintfArgType_sint"|id="invalidPrintfArgType_uint"', str(line)) is not None: - CCR.nbInvalidPrintf[vId] += 1 - if re.search('id="moduloAlwaysTrueFalse"', str(line)) is not None: - CCR.nbModuloAlways[vId] += 1 - if re.search('id="shiftTooManyBitsSigned"', str(line)) is not None: - CCR.nbTooManyBitsShift[vId] += 1 - if re.search('id="integerOverflow"', str(line)) is not None: - CCR.nbIntegerOverflow[vId] += 1 - if re.search('id="wrongPrintfScanfArgNum"|id="invalidScanfArgType_int"', str(line)) is not None: - CCR.nbWrongScanfArg[vId] += 1 - if re.search('id="pointerAdditionResultNotNull"', str(line)) is not None: - CCR.nbPtrAddNotNull[vId] += 1 - if re.search('id="oppositeInnerCondition"', str(line)) is not None: - CCR.nbOppoInnerCondition[vId] += 1 - vMsg = '' - vMsg += '======== Variant ' + variant + ' - ' + CCR.versions[vId] + ' ========\n' - vMsg += ' ' + str(CCR.nbErrors[vId]) + ' errors\n' - vMsg += ' ' + str(CCR.nbWarnings[vId]) + ' warnings\n' - vMsg += ' -- Details --\n' - vMsg += ' Memory leak: ' + str(CCR.nbMemLeaks[vId]) + '\n' - vMsg += ' Possible null pointer deference: ' + str(CCR.nbNullPtrs[vId]) + '\n' - vMsg += ' Uninitialized variable: ' + str(CCR.nbUninitVars[vId]) + '\n' - vMsg += ' Undefined behaviour shifting: ' + str(CCR.nbTooManyBitsShift[vId]) + '\n' - vMsg += ' Signed integer overflow: ' + str(CCR.nbIntegerOverflow[vId]) + '\n' - vMsg += '\n' - vMsg += ' Printf formatting issue: ' + str(CCR.nbInvalidPrintf[vId]) + '\n' - vMsg += ' Modulo result is predetermined: ' + str(CCR.nbModuloAlways[vId]) + '\n' - vMsg += ' Opposite Condition -> dead code: ' + str(CCR.nbOppoInnerCondition[vId]) + '\n' - vMsg += ' Wrong Scanf Nb Args: ' + str(CCR.nbWrongScanfArg[vId]) + '\n' - for vLine in vMsg.split('\n'): - logging.debug(vLine) - vId += 1 - - HTML.CreateHtmlTestRow('N/A', 'OK', CONST.ALL_PROCESSES_OK) - HTML.CreateHtmlTestRowCppCheckResults(CCR) - logging.info('\u001B[1m Static Code Analysis Pass\u001B[0m') - - return True - - def LicenceAndFormattingCheck(self, ctx, node, HTML): + def LicenceAndFormattingCheck(ctx, node, HTML, d, branch, allowMerge, targetBranch): # 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 - lSourcePath = self.eNBSourceCodePath - if not node or not lSourcePath: - raise ValueError(f"{lSourcePath=} {node=}") + if not node or not d: + raise ValueError(f"{d=} {node=}") logging.debug('Building on server: ' + node) cmd = cls_cmd.getConnection(node) check_options = '' - if self.ranAllowMerge: - check_options = f'--build-arg MERGE_REQUEST=true --build-arg SRC_BRANCH={self.ranBranch}' - if self.ranTargetBranch == '': - if self.ranBranch != 'develop' and self.ranBranch != 'origin/develop': + if allowMerge: + check_options = f'--build-arg MERGE_REQUEST=true --build-arg SRC_BRANCH={branch}' + if targetBranch == '': + if branch != 'develop' and branch != 'origin/develop': check_options += ' --build-arg TARGET_BRANCH=develop' else: - check_options += f' --build-arg TARGET_BRANCH={self.ranTargetBranch}' + check_options += f' --build-arg TARGET_BRANCH={targetBranch}' - logDir = f'{lSourcePath}/cmake_targets/log/' + logDir = f'{d}/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.ubuntu {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 {d}/ci-scripts/docker/Dockerfile.formatting.ubuntu {d} > {logDir}/oai-formatting-check.txt 2>&1') cmd.run('docker image rm oai-formatting-check:latest') cmd.run('docker image prune --force') 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 015d77cacc..8460983d2b 100644 --- a/ci-scripts/conf_files/gnb-cu.sa.band78.106prb.conf +++ b/ci-scripts/conf_files/gnb-cu.sa.band78.106prb.conf @@ -17,6 +17,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 }) }); + cu_sibs = ( 2, 3, 4 ); @include "neighbour-config.conf" nr_cellid = 12345678L; diff --git a/ci-scripts/conf_files/neighbour-config.conf b/ci-scripts/conf_files/neighbour-config.conf index fe91ff2f08..57aa55f772 100644 --- a/ci-scripts/conf_files/neighbour-config.conf +++ b/ci-scripts/conf_files/neighbour-config.conf @@ -5,6 +5,57 @@ # for the 2-cell rfsim setup (gNB_ID 0xe00 & 0xb00) # ############################################################ +############################################################ +# SIB2 # +############################################################ + +sib2_config : { + q_Hyst = 0; + cellReselectionPriority = 0; + threshServingLowP = 0; + threshServingLowQ = 0; + s_NonIntraSearchP = -1; + s_NonIntraSearchQ = -1; + q_RxLevMin = -56; + q_QualMin = -1; + s_IntraSearchP = 22; + s_IntraSearchQ = -1; + t_ReselectionNR = 1; + deriveSSB_IndexFromCell = 1; + + speed_t_Evaluation = 0; + speed_t_HystNormal = 0; + speed_n_CellChangeMedium = 1; + speed_n_CellChangeHigh = 2; + speed_sf_Medium = 1; + speed_sf_High = 0; +}; + +############################################################ +# Per-frequency SIB4 inter-frequency configuration # +############################################################ + +frequency_list = ( + { + absoluteFrequencySSB = 621312; + subcarrierSpacing = 1; # 30 kHz + band = 78; + + frequency_config = ( + { + cellReselectionPriority = 5; + threshX_HighP = 10; + threshX_LowP = 6; + threshX_HighQ = -1; + threshX_LowQ = -1; + q_OffsetFreq = 0; + q_RxLevMin = -56; + t_ReselectionNR = 1; + } + ); + } +); + neighbour_list = ( ########################################################## # Entry USED BY gNB_ID = 0xe00 (nr_cellid = 1) # @@ -21,6 +72,9 @@ neighbour_list = ( band = 78; plmn = { mcc = 208; mnc = 99; mnc_length = 2 }; tracking_area_code = 1; + q_OffsetCell = 2; + q_RxLevMinOffsetCell= 2; + q_QualMinOffsetCell = 1; } ); }, @@ -40,6 +94,9 @@ neighbour_list = ( band = 78; plmn = { mcc = 208; mnc = 99; mnc_length = 2 }; tracking_area_code = 1; + q_OffsetCell = 2; + q_RxLevMinOffsetCell= 2; + q_QualMinOffsetCell = 1; } ); } diff --git a/ci-scripts/docker/Dockerfile.cppcheck.xenial b/ci-scripts/docker/Dockerfile.cppcheck.xenial deleted file mode 100644 index fcb7f814ae..0000000000 --- a/ci-scripts/docker/Dockerfile.cppcheck.xenial +++ /dev/null @@ -1,41 +0,0 @@ -# SPDX-License-Identifier: LicenseRef-CSSL-1.0 - -#--------------------------------------------------------------------- -# -# Dockerfile for the Open-Air-Interface BUILD service -# Valid for Ubuntu 22.04 -# -#--------------------------------------------------------------------- -FROM ubuntu:xenial AS oai-cppcheck - - -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && \ - apt-get upgrade --yes && \ - apt-get install --yes \ - build-essential \ - vim \ - cppcheck - -WORKDIR /oai-ran -COPY . . - -WORKDIR /oai-ran/common/utils/T -RUN make - -WORKDIR /oai-ran -RUN mkdir -p cmake_targets/log && \ - cppcheck --enable=warning --force --xml --xml-version=2 \ - --inline-suppr \ - -i openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c \ - --suppressions-list=ci-scripts/cppcheck_suppressions.list \ - -I common/utils \ - -I openair3/NAS/COMMON/UTIL \ - -j`nproc` . 2> cmake_targets/log/cppcheck.xml 1> cmake_targets/log/cppcheck_build.txt - -RUN grep -E -c 'severity="error' cmake_targets/log/cppcheck.xml - -RUN grep -E -c 'severity="warning' cmake_targets/log/cppcheck.xml - -RUN cat cmake_targets/log/cppcheck.xml diff --git a/ci-scripts/main.py b/ci-scripts/main.py index 27cf36bcf8..66e8b2091b 100644 --- a/ci-scripts/main.py +++ b/ci-scripts/main.py @@ -22,7 +22,7 @@ import constants as CONST import cls_oaicitest #main class for OAI CI test framework import cls_containerize #class Containerize for all container-based operations on RAN/UE objects -import cls_static_code_analysis #class for static code analysis +import cls_static_code_analysis as SCA 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 @@ -64,7 +64,6 @@ def ExecuteActionWithParam(action, ctx, node): global RAN global HTML global CONTAINERS - global SCA global CLUSTER 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') @@ -196,10 +195,7 @@ def ExecuteActionWithParam(action, ctx, node): success = CONTAINERS.Create_Workspace(node, HTML) elif action == 'LicenceAndFormattingCheck': - success = SCA.LicenceAndFormattingCheck(ctx, node, HTML) - - elif action == 'Cppcheck_Analysis': - success = SCA.CppCheckAnalysis(ctx, node, HTML) + success = SCA.StaticCodeAnalysis.LicenceAndFormattingCheck(ctx, node, HTML, RAN.eNBSourceCodePath, RAN.ranBranch, RAN.ranAllowMerge, RAN.ranTargetBranch) elif action == 'Push_Local_Registry': tag_prefix = test.findtext('tag_prefix') or "" @@ -297,7 +293,6 @@ CiTestObj = cls_oaicitest.OaiCiTest() RAN = ran.RANManagement() HTML = cls_oai_html.HTMLManagement() CONTAINERS = cls_containerize.Containerize() -SCA = cls_static_code_analysis.StaticCodeAnalysis() CLUSTER = cls_cluster.Cluster() #----------------------------------------------------------- @@ -307,7 +302,7 @@ CLUSTER = cls_cluster.Cluster() import args_parse # Force local execution, move all execution targets to localhost force_local = False -mode, force_local, date_fmt = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,CONTAINERS,HELP,SCA,CLUSTER) +mode, force_local, date_fmt = args_parse.ArgsParse(sys.argv,CiTestObj,RAN,HTML,CONTAINERS,HELP,CLUSTER) fmt = "%(levelname)8s: %(message)s" if date_fmt: fmt = "[%(asctime)s] %(levelname)s %(message)s" diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml index 52b44e0e96..d762c4b316 100755 --- a/ci-scripts/xml_class_list.yml +++ b/ci-scripts/xml_class_list.yml @@ -23,7 +23,6 @@ - Deploy_Object - Stop_Object - Undeploy_Object - - Cppcheck_Analysis - Deploy_Run_OC_PhySim - Build_Deploy_PhySim - LicenceAndFormattingCheck diff --git a/ci-scripts/xml_files/cppcheck.xml b/ci-scripts/xml_files/cppcheck.xml deleted file mode 100644 index 061c39b5b8..0000000000 --- a/ci-scripts/xml_files/cppcheck.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - build-tab - CPPCHECK Analysis - wrench - - - Create_Workspace - Create new Workspace - carabe - - - - Cppcheck_Analysis - Static Code Analysis with cppcheck - carabe - - - 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 7bc7a4d8cc..6813e13b10 100644 --- a/ci-scripts/yaml_files/4g_l2sim_fdd/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_l2sim_fdd/docker-compose.yml @@ -166,7 +166,7 @@ services: retries: 5 trf_gen: - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest privileged: true container_name: l2sim4g-trf-gen networks: diff --git a/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/docker-compose.yml b/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/docker-compose.yml index a88f36fbc0..53793a924b 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_rfsimulator_fdd_05MHz/docker-compose.yml @@ -166,7 +166,7 @@ services: retries: 5 trf_gen: - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest privileged: true container_name: rfsim4g-trf-gen networks: diff --git a/ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz/docker-compose.yml b/ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz/docker-compose.yml index 2b19d5bbb7..f61c077b70 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_rfsimulator_fdd_10MHz/docker-compose.yml @@ -166,7 +166,7 @@ services: retries: 5 trf_gen: - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest privileged: true container_name: rfsim4g-trf-gen networks: diff --git a/ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz/docker-compose.yml b/ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz/docker-compose.yml index 0e6caffb13..81362b26d1 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_rfsimulator_fdd_20MHz/docker-compose.yml @@ -166,7 +166,7 @@ services: retries: 5 trf_gen: - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest privileged: true container_name: rfsim4g-trf-gen networks: diff --git a/ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz/docker-compose.yml b/ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz/docker-compose.yml index b795350642..35672381cc 100644 --- a/ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz/docker-compose.yml +++ b/ci-scripts/yaml_files/4g_rfsimulator_tdd_05MHz/docker-compose.yml @@ -166,7 +166,7 @@ services: retries: 5 trf_gen: - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest privileged: true container_name: rfsim4g-trf-gen networks: 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 58b5748668..a606c50ccc 100644 --- a/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_f1_rfsimulator/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris @@ -75,7 +75,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ 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 f43c8aaa03..9d1a35a249 100644 --- a/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_fdd_rfsimulator/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris @@ -74,7 +74,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ diff --git a/ci-scripts/yaml_files/5g_rfsimulator/README.md b/ci-scripts/yaml_files/5g_rfsimulator/README.md index d2ef888771..6090b4b918 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator/README.md +++ b/ci-scripts/yaml_files/5g_rfsimulator/README.md @@ -38,11 +38,11 @@ Password: Now pull images. ```bash -$ docker pull mysql:8.0 -$ 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 mysql:9.6 +$ docker pull oaisoftwarealliance/oai-amf:v2.2.1 +$ docker pull oaisoftwarealliance/oai-smf:v2.2.1 +$ docker pull oaisoftwarealliance/oai-upf:v2.2.1 +$ docker pull oaisoftwarealliance/trf-gen-cn5g:latest $ docker pull oaisoftwarealliance/oai-gnb:develop $ docker pull oaisoftwarealliance/oai-nr-ue:develop @@ -570,7 +570,7 @@ runs the gnb service with modified gNB executable. ```bash docker compose -f docker-compose.yaml -f local-override.yaml up -d oai-gnb ``` -This command rebuilds both the gNB & nrUE and runs the oai-nr-ue container with +This command rebuilds both the gNB & nrUE and runs the oai-nr-ue container with modified nrUE executable. ```bash docker compose -f docker-compose.yaml -f local-override.yaml up -d oai-nr-ue diff --git a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml index cf7d5b5f85..a668adc840 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ./oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris @@ -74,7 +74,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ 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 299ebbc543..0ae419fb4c 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris @@ -74,7 +74,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ 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 8b4c02da2e..d22850b214 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_2x2/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris @@ -74,7 +74,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ 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 0f03a33c82..a78f2ef897 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_e1/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris diff --git a/ci-scripts/yaml_files/5g_rfsimulator_fr2_66prb/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_fr2_66prb/docker-compose.yaml index 9ed90c8b2d..b27cd57a06 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_fr2_66prb/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_fr2_66prb/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris @@ -74,7 +74,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ diff --git a/ci-scripts/yaml_files/5g_rfsimulator_multiue/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_multiue/docker-compose.yaml index 5e376f650e..313d36bbfb 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_multiue/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_multiue/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -23,7 +23,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -35,7 +35,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -47,7 +47,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -70,7 +70,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest 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" 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 index 9fe4bdc25f..5e11c8cb3c 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_n2_ho/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -23,7 +23,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:ci-tmp-pr-372-26c14bcd + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -35,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.2.1 environment: - TZ=Europe/Paris volumes: @@ -47,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.2.1 environment: - TZ=Europe/Paris volumes: @@ -70,7 +70,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest 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" 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 785402c3f7..42899ae248 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 @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris @@ -74,7 +74,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ 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 fd57881969..c7343e9a25 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 @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -25,7 +25,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -37,7 +37,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -49,7 +49,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -72,7 +72,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest 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" 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 581c2362fe..60ca044f94 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 @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris @@ -74,7 +74,7 @@ services: oai-ext-dn: privileged: true container_name: rfsim5g-oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest init: true entrypoint: /bin/bash -c \ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ diff --git a/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml b/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml index 357444be73..85303fe749 100644 --- a/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_vrtsim_chanmod/docker-compose.yaml @@ -3,7 +3,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -26,7 +26,7 @@ services: ipv4_address: 192.168.71.131 oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -38,7 +38,7 @@ services: ipv4_address: 192.168.71.132 oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -50,7 +50,7 @@ services: ipv4_address: 192.168.71.133 oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris diff --git a/ci-scripts/yaml_files/5g_vrtsim_cirdb/docker-compose.yaml b/ci-scripts/yaml_files/5g_vrtsim_cirdb/docker-compose.yaml index 183c244018..7ab1020d01 100644 --- a/ci-scripts/yaml_files/5g_vrtsim_cirdb/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_vrtsim_cirdb/docker-compose.yaml @@ -12,7 +12,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -36,7 +36,7 @@ services: oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -49,7 +49,7 @@ services: oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -62,7 +62,7 @@ services: oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris diff --git a/ci-scripts/yaml_files/5g_vrtsim_multiue/docker-compose.yaml b/ci-scripts/yaml_files/5g_vrtsim_multiue/docker-compose.yaml index 49f2e9a4cc..349c61ff24 100644 --- a/ci-scripts/yaml_files/5g_vrtsim_multiue/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_vrtsim_multiue/docker-compose.yaml @@ -12,7 +12,7 @@ services: mysql: container_name: "rfsim5g-mysql" - image: mysql:8.0 + image: mysql:9.6 init: true volumes: - ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql @@ -36,7 +36,7 @@ services: oai-amf: container_name: "rfsim5g-oai-amf" - image: oaisoftwarealliance/oai-amf:v2.1.10 + image: oaisoftwarealliance/oai-amf:v2.2.1 environment: - TZ=Europe/paris volumes: @@ -49,7 +49,7 @@ services: oai-smf: container_name: "rfsim5g-oai-smf" - image: oaisoftwarealliance/oai-smf:v2.1.10 + image: oaisoftwarealliance/oai-smf:v2.2.1 environment: - TZ=Europe/Paris volumes: @@ -62,7 +62,7 @@ services: oai-upf: container_name: "rfsim5g-oai-upf" - image: oaisoftwarealliance/oai-upf:v2.1.10 + image: oaisoftwarealliance/oai-upf:v2.2.1 init: true environment: - TZ=Europe/Paris diff --git a/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml b/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml index ee1f5c2110..3ab53378d9 100644 --- a/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml +++ b/ci-scripts/yaml_files/fr1_epc_20897/docker-compose.yml @@ -184,7 +184,7 @@ services: retries: 5 trf_gen: - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest privileged: true container_name: prod-trf-gen networks: diff --git a/ci-scripts/yaml_files/magma_lte_20892/docker-compose.yml b/ci-scripts/yaml_files/magma_lte_20892/docker-compose.yml index d025588de7..535561be8c 100644 --- a/ci-scripts/yaml_files/magma_lte_20892/docker-compose.yml +++ b/ci-scripts/yaml_files/magma_lte_20892/docker-compose.yml @@ -168,7 +168,7 @@ services: retries: 5 trf_gen: - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest privileged: true container_name: prod-trf-gen networks: diff --git a/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml b/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml index 636f416bfb..5005a53de3 100644 --- a/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml +++ b/ci-scripts/yaml_files/magma_nsa_20897/docker-compose.yml @@ -168,7 +168,7 @@ services: retries: 5 trf_gen: - image: oaisoftwarealliance/trf-gen-cn5g:focal + image: oaisoftwarealliance/trf-gen-cn5g:latest privileged: true container_name: prod-trf-gen networks: diff --git a/common/config/config_paramdesc.h b/common/config/config_paramdesc.h index 51c8626116..efb5c956d2 100644 --- a/common/config/config_paramdesc.h +++ b/common/config/config_paramdesc.h @@ -48,8 +48,8 @@ typedef union checkedparam { int num_okintval; /* number of valid values in the checkingval array */ } s1a; struct { - int (*f2)(configmodule_interface_t *cfg, - paramdef_t *param); /* check an integer against an authorized range, defined by its min and max value */ + int (*f2)(const configmodule_interface_t *cfg, + const paramdef_t *param); /* check an integer against an authorized range, defined by its min and max value */ int okintrange[CONFIG_MAX_NUMCHECKVAL]; /* integer array, store min and max values */ } s2; diff --git a/common/config/config_userapi.c b/common/config/config_userapi.c index 76f9722d0a..c009187800 100644 --- a/common/config/config_userapi.c +++ b/common/config/config_userapi.c @@ -183,14 +183,35 @@ int config_check_intval(configmodule_interface_t *cfg, paramdef_t *param) return -1; } - for ( int i=0; ichkPptr->s1.num_okintval ; i++) { - if( *(param->uptr) == param->chkPptr->s1.okintval[i] ) { - return 0; + if (param->type == TYPE_INT32 || param->type == TYPE_INT) { + if (param->iptr == NULL) { + fprintf(stderr, "[CONFIG] config_check_intval: %s: NULL iptr\n", param->optname); + return -1; } + const int v = *param->iptr; + for (int i = 0; i < param->chkPptr->s1.num_okintval; i++) { + if (v == param->chkPptr->s1.okintval[i]) + return 0; + } + fprintf(stderr, "[CONFIG] config_check_intval: %s: %i invalid value, authorized values:\n ", param->optname, v); + for (int i = 0; i < param->chkPptr->s1.num_okintval; i++) { + fprintf(stderr, " %i", param->chkPptr->s1.okintval[i]); + } + fprintf(stderr, " \n"); + return -1; + } else { + if (param->uptr == NULL) { + fprintf(stderr, "[CONFIG] config_check_intval: %s: NULL uptr\n", param->optname); + return -1; + } + for (int i = 0; i < param->chkPptr->s1.num_okintval; i++) { + if (*(param->uptr) == (uint32_t)param->chkPptr->s1.okintval[i]) { + return 0; + } + } + print_intvalueerror(param, "config_check_intval", param->chkPptr->s1.okintval, param->chkPptr->s1.num_okintval); + return -1; } - - print_intvalueerror(param,"config_check_intval", param->chkPptr->s1.okintval,param->chkPptr->s1.num_okintval); - return -1; } int config_check_modify_integer(configmodule_interface_t *cfg, paramdef_t *param) @@ -211,15 +232,38 @@ int config_check_modify_integer(configmodule_interface_t *cfg, paramdef_t *param return -1; } -int config_check_intrange(configmodule_interface_t *cfg, paramdef_t *param) +int config_check_intrange(const configmodule_interface_t *cfg, const paramdef_t *param) { UNUSED(cfg); if( *(param->iptr) >= param->chkPptr->s2.okintrange[0] && *(param->iptr) <= param->chkPptr->s2.okintrange[1] ) { return 0; } - fprintf(stderr,"[CONFIG] config_check_intrange: %s: %i invalid value, authorized range: %i %i\n", - param->optname, (int)*(param->uptr), param->chkPptr->s2.okintrange[0], param->chkPptr->s2.okintrange[1]); + fprintf(stderr, + "[CONFIG] config_check_intrange: %s: %i invalid value, authorized range: %i %i\n", + param->optname, + (int)*(param->iptr), + param->chkPptr->s2.okintrange[0], + param->chkPptr->s2.okintrange[1]); + return -1; +} + +int config_check_uintrange(const configmodule_interface_t *cfg, const paramdef_t *param) +{ + (void)cfg; + const uint32_t *v = param->uptr; + const int *range = param->chkPptr->s2.okintrange; + + if (*v >= (uint32_t)range[0] && *v <= (uint32_t)range[1]) { + return 0; + } + + fprintf(stderr, + "[CONFIG] config_check_uintrange: %s: %u invalid, authorized range: %i %i\n", + param->optname, + *v, + range[0], + range[1]); return -1; } diff --git a/common/config/config_userapi.h b/common/config/config_userapi.h index fafbd81019..b959cb57fe 100644 --- a/common/config/config_userapi.h +++ b/common/config/config_userapi.h @@ -51,7 +51,8 @@ int config_get_processedint(configmodule_interface_t *cfg, paramdef_t *cfgoption /* functions to be used in parameters definition, to check parameters values */ int config_check_intval(configmodule_interface_t *cfg, paramdef_t *param); int config_check_modify_integer(configmodule_interface_t *cfg, paramdef_t *param); -int config_check_intrange(configmodule_interface_t *cfg, paramdef_t *param); +int config_check_intrange(const configmodule_interface_t *cfg, const paramdef_t *param); +int config_check_uintrange(const configmodule_interface_t *cfg, const paramdef_t *param); int config_check_strval(configmodule_interface_t *cfg, paramdef_t *param); int config_checkstr_assign_integer(configmodule_interface_t *cfg, paramdef_t *param); const paramdef_t *config_get_paramdef_from_name(const paramdef_t *pd, int num, const char *name); diff --git a/common/platform_constants.h b/common/platform_constants.h index d7cf6f9ed6..26894fd82b 100644 --- a/common/platform_constants.h +++ b/common/platform_constants.h @@ -66,7 +66,6 @@ #define RETURNok (0) #define RETURNerror (-1) #define DEFAULT_NAS_PATH "PWD" -#define UNUSED_VARIABLE(vARIABLE) (void)(vARIABLE) #define NUM_PRACH_RX_FOR_NOISE_ESTIMATE 100 // SDAP diff --git a/common/utils/CMakeLists.txt b/common/utils/CMakeLists.txt index 3196b39868..fc113ffa46 100644 --- a/common/utils/CMakeLists.txt +++ b/common/utils/CMakeLists.txt @@ -16,7 +16,7 @@ add_subdirectory(nr) add_subdirectory(LOG) add_subdirectory(threadPool) add_subdirectory(time_manager) -add_library(utils utils.c system.c time_meas.c time_stat.c tuntap_if.c reverse_bits.c) +add_library(utils utils.c system.c time_meas.c time_stat.c tuntap_if.c reverse_bits.c fsn.c) target_include_directories(utils PUBLIC .) target_link_libraries(utils PRIVATE ${T_LIB}) add_subdirectory(barrier) diff --git a/common/utils/T/DOC/T/basic.md b/common/utils/T/DOC/T/basic.md index 0103c30de7..ff54c7efc6 100644 --- a/common/utils/T/DOC/T/basic.md +++ b/common/utils/T/DOC/T/basic.md @@ -67,18 +67,26 @@ the T tracer and only output on the terminal). The default is ## Run a tracer -Go into the directory `common/utils/T/tracer` (or -`cmake_targets/ran_build/build/common/utils/T/tracer`) and run for example the +Go into the directory `common/utils/T/tracer` and run for example the `enb` tracer: ```shell +#in common/utils/T/tracer directory ./enb -d ../T_messages.txt ``` +You can also run it from `cmake_targets/ran_build/build/` directory: + +```shell +# in cmake_targets/ran_build/build directory +./common/utils/T/tracer/enb -d ../../../common/utils/T/T_messages.txt +``` + To trace a remote program, use the `-ip` option. For example, if you want to trace a program running on `192.168.12.148` do: ```shell +# in common/utils/T/tracer directory ./enb -d ../T_messages.txt -ip 192.168.12.148 ``` diff --git a/common/utils/T/DOC/T/record_db.md b/common/utils/T/DOC/T/record_db.md index 2c3825252f..27444fa87c 100644 --- a/common/utils/T/DOC/T/record_db.md +++ b/common/utils/T/DOC/T/record_db.md @@ -44,6 +44,7 @@ Or, from an existing build directory using cmake: ```shell cd cmake_targets/ran_build/build cmake -DT_RECORD_DB=ON . +# use make or ninja make T_tools ``` @@ -53,6 +54,9 @@ The binary is then available in: cmake_targets/ran_build/build/common/utils/T/tracer/record_db ``` +**NOTE*: Unlike other docs on T Tracer for `record_db` we are building in cmake +directory rather than in the directory of T. + ## Prerequisites - a running ClickHouse server reachable from `record_db` @@ -84,8 +88,8 @@ To enable all events except the most verbose groups and write them to ClickHouse: ```shell -cd cmake_targets/ran_build/build/common/utils/T/tracer -./record_db -d ../T_messages.txt \ +cd cmake_targets/ran_build/build/ +./common/utils/T/tracer/record_db -d ../../../common/utils/T/T_messages.txt \ -ON \ -off VCD \ -off HEAVY \ @@ -108,7 +112,7 @@ The event selection rules are the same as for [`record`](./record.md): These options are processed in order. For example: ```shell -./record_db -d ../T_messages.txt -OFF -on GNB_PHY_UL_FD_PUSCH_IQ -on GNB_PHY_UL_PAYLOAD_RX_BITS +./common/utils/T/tracer/record_db -d ../../../common/utils/T/T_messages.txt -OFF -on GNB_PHY_UL_FD_PUSCH_IQ -on GNB_PHY_UL_PAYLOAD_RX_BITS ``` This starts from everything disabled and enables only the two listed diff --git a/common/utils/actor/actor.h b/common/utils/actor/actor.h index 3d7760356c..d49bd88c65 100644 --- a/common/utils/actor/actor.h +++ b/common/utils/actor/actor.h @@ -4,7 +4,7 @@ #ifndef ACTOR_H #define ACTOR_H -#include "notified_fifo.h" +#include "common/utils/threadPool/notified_fifo.h" #define INIT_ACTOR(ptr, name, core_affinity) init_actor((Actor_t *)ptr, name, core_affinity); diff --git a/common/utils/ds/CMakeLists.txt b/common/utils/ds/CMakeLists.txt index 7007d77fac..6f7053a1be 100644 --- a/common/utils/ds/CMakeLists.txt +++ b/common/utils/ds/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(ds OBJECT seq_arr.c hashtable.c obj_hashtable.c + spsc_q.c ) target_include_directories(ds PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/common/utils/ds/hashtable.c b/common/utils/ds/hashtable.c index c84d332973..78a62f570c 100644 --- a/common/utils/ds/hashtable.c +++ b/common/utils/ds/hashtable.c @@ -10,36 +10,6 @@ #include "assertions.h" -//------------------------------------------------------------------------------------------------------------------------------- -char *hashtable_rc_code2string(hashtable_rc_t rcP) -//------------------------------------------------------------------------------------------------------------------------------- -{ - switch (rcP) { - case HASH_TABLE_OK: - return "HASH_TABLE_OK"; - break; - - case HASH_TABLE_INSERT_OVERWRITTEN_DATA: - return "HASH_TABLE_INSERT_OVERWRITTEN_DATA"; - break; - - case HASH_TABLE_KEY_NOT_EXISTS: - return "HASH_TABLE_KEY_NOT_EXISTS"; - break; - - case HASH_TABLE_KEY_ALREADY_EXISTS: - return "HASH_TABLE_KEY_ALREADY_EXISTS"; - break; - - case HASH_TABLE_BAD_PARAMETER_HASHTABLE: - return "HASH_TABLE_BAD_PARAMETER_HASHTABLE"; - break; - - default: - return "UNKNOWN hashtable_rc_t"; - } -} -//------------------------------------------------------------------------------------------------------------------------------- /* * free int function * hash_free_int_func() is used when this hashtable is used to store int values as data (pointer = value). @@ -147,41 +117,6 @@ hashtable_rc_t hashtable_is_key_exists (const hash_table_t *const hashtblP, cons return HASH_TABLE_KEY_NOT_EXISTS; } -//------------------------------------------------------------------------------------------------------------------------------- -hashtable_rc_t hashtable_dump_content (const hash_table_t *const hashtblP, char *const buffer_pP, int *const remaining_bytes_in_buffer_pP ) -//------------------------------------------------------------------------------------------------------------------------------- -{ - hash_node_t *node = NULL; - unsigned int i = 0; - - if (hashtblP == NULL) { - *remaining_bytes_in_buffer_pP = snprintf( - buffer_pP, - *remaining_bytes_in_buffer_pP, - "HASH_TABLE_BAD_PARAMETER_HASHTABLE"); - return HASH_TABLE_BAD_PARAMETER_HASHTABLE; - } - - while ((i < hashtblP->size) && (*remaining_bytes_in_buffer_pP > 0)) { - if (hashtblP->nodes[i] != NULL) { - node=hashtblP->nodes[i]; - - while(node) { - *remaining_bytes_in_buffer_pP = snprintf( - buffer_pP, - *remaining_bytes_in_buffer_pP, - "Key 0x%"PRIx64" Element %p\n", - node->key, - node->data); - node=node->next; - } - } - - i += 1; - } - - return HASH_TABLE_OK; -} //------------------------------------------------------------------------------------------------------------------------------- /* diff --git a/common/utils/ds/hashtable.h b/common/utils/ds/hashtable.h index ba43b0230f..fd8fe013c3 100644 --- a/common/utils/ds/hashtable.h +++ b/common/utils/ds/hashtable.h @@ -44,12 +44,10 @@ typedef struct hash_table_iterator_s { const hash_table_t* const hashtbl; } hash_table_iterator_s; -char *hashtable_rc_code2string(hashtable_rc_t rcP); void hash_free_int_func(void *memoryP); hash_table_t *hashtable_create (const hash_size_t size, hash_size_t (*hashfunc)(const hash_key_t ), void (*freefunc)(void *)); hashtable_rc_t hashtable_destroy(hash_table_t **hashtbl); hashtable_rc_t hashtable_is_key_exists (const hash_table_t *const hashtbl, const uint64_t key); -hashtable_rc_t hashtable_dump_content (const hash_table_t *const hashtblP, char *const buffer_pP, int *const remaining_bytes_in_buffer_pP ); hashtable_rc_t hashtable_insert (hash_table_t *const hashtbl, const hash_key_t key, void *data); hashtable_rc_t hashtable_remove (hash_table_t *const hashtbl, const hash_key_t key); hashtable_rc_t hashtable_get (const hash_table_t *const hashtbl, const hash_key_t key, void **dataP); diff --git a/common/utils/ds/spsc_q.c b/common/utils/ds/spsc_q.c new file mode 100644 index 0000000000..6f05a19865 --- /dev/null +++ b/common/utils/ds/spsc_q.c @@ -0,0 +1,90 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +#include +#include +#include + +#include "spsc_q.h" + +spsc_q_t spsc_q_alloc(size_t cnt, size_t elsiz) +{ + /* internally, use one element more: the ringbuffer is full if + * (write_idx + 1) % cnt == read_idx, so it's full if one element is still + * free (because otherwise write_idx == read_idx, but this is the empty + * condition) */ + cnt += 1; + spsc_q_t rb = {.cnt = cnt, .elsiz = elsiz}; + rb.buf = calloc(cnt, elsiz); + return rb; +} + +void spsc_q_free(spsc_q_t *rb) +{ + free(rb->buf); + memset(rb, 0, sizeof(*rb)); +} + +bool spsc_q_put(spsc_q_t *rb, const void *src, size_t elsiz) +{ + assert(elsiz == rb->elsiz); + size_t w = atomic_load_explicit(&rb->write_idx, memory_order_relaxed); + size_t r = atomic_load_explicit(&rb->read_idx, memory_order_acquire); + if ((w + 1) % rb->cnt == r) { + return false; + } + + uint8_t *bufpos = &rb->buf[w * rb->elsiz]; + memcpy(bufpos, src, elsiz); + atomic_store_explicit(&rb->write_idx, (w + 1) % rb->cnt, memory_order_release); + return true; +} + +bool spsc_q_get_if(spsc_q_t *rb, pred p, void *user, void *dest, size_t elsiz) +{ + assert(elsiz == rb->elsiz); + size_t w = atomic_load_explicit(&rb->write_idx, memory_order_acquire); + size_t r = atomic_load_explicit(&rb->read_idx, memory_order_relaxed); + if (w == r) { + return false; + } + + uint8_t *bufpos = &rb->buf[rb->read_idx * rb->elsiz]; + if (!p(bufpos, user)) { + return false; + } + + if (dest) + memcpy(dest, bufpos, elsiz); + atomic_store_explicit(&rb->read_idx, (r + 1) % rb->cnt, memory_order_release); + return true; +} + +static bool always(const void *data, void *user) +{ + (void) data; + (void) user; + return true; +} +bool spsc_q_get(spsc_q_t *rb, void *dest, size_t elsiz) +{ + return spsc_q_get_if(rb, always, NULL, dest, elsiz); +} + +int spsc_q_get_while(spsc_q_t *rb, pred p, void *user, void *dest, size_t elsiz, size_t max_len) +{ + assert(elsiz == rb->elsiz); + size_t count = 0; + while (count < max_len && spsc_q_get_if(rb, p, user, dest + elsiz * count, elsiz)) + count++; + return count; +} + +int spsc_q_drop_while(spsc_q_t *rb, pred p, void *user) +{ + size_t dropped = 0; + while (spsc_q_get_if(rb, p, user, NULL, rb->elsiz)) + dropped++; + return dropped; +} diff --git a/common/utils/ds/spsc_q.h b/common/utils/ds/spsc_q.h new file mode 100644 index 0000000000..7fd968b2f0 --- /dev/null +++ b/common/utils/ds/spsc_q.h @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +#ifndef SPSC_Q_H_ +#define SPSC_Q_H_ + +#include +#include +#include + +#if defined(__cplusplus) +// use atomic_size_t to help interworking with C++ +using std::atomic_size_t; +#endif + +typedef struct spsc_q { + uint8_t *buf; + size_t elsiz; + size_t cnt; + + atomic_size_t write_idx; + atomic_size_t read_idx; +} spsc_q_t; + +spsc_q_t spsc_q_alloc(size_t cnt, size_t elsiz); +void spsc_q_free(spsc_q_t *rb); + +bool spsc_q_put(spsc_q_t *rb, const void *src, size_t elsiz); +bool spsc_q_get(spsc_q_t *rb, void *dest, size_t elsiz); + +typedef bool (*pred)(const void *data, void *user); +bool spsc_q_get_if(spsc_q_t *rb, pred p, void *user, void *dest, size_t elsiz); +int spsc_q_drop_while(spsc_q_t *rb, pred p, void *user); +int spsc_q_get_while(spsc_q_t *rb, pred p, void *user, void *dest, size_t elsiz, size_t max_len); + +#endif /* SPSC_Q_H_ */ diff --git a/common/utils/ds/tests/CMakeLists.txt b/common/utils/ds/tests/CMakeLists.txt index a38cf159cb..1a2e5277a1 100644 --- a/common/utils/ds/tests/CMakeLists.txt +++ b/common/utils/ds/tests/CMakeLists.txt @@ -8,5 +8,11 @@ add_test(NAME test_seq_arr COMMAND test_seq_arr) # no options required add_executable(test_hashtable test_hashtable.cpp) add_dependencies(tests test_hashtable) target_link_libraries(test_hashtable PRIVATE ds GTest::gtest) -add_test(NAME test_hashtable - COMMAND ./test_hashtable) +add_test(NAME test_hashtable COMMAND ./test_hashtable) + +add_executable(test_spsc_q test_spsc_q.cpp) +target_link_libraries(test_spsc_q ds GTest::gtest) +add_dependencies(tests test_spsc_q) +add_test(NAME test_spsc_q COMMAND test_spsc_q) +add_executable(test_spsc_q_perf test_spsc_q_perf.cpp) +target_link_libraries(test_spsc_q_perf PRIVATE ds benchmark::benchmark) diff --git a/common/utils/ds/tests/test_spsc_q.cpp b/common/utils/ds/tests/test_spsc_q.cpp new file mode 100644 index 0000000000..0c1638d490 --- /dev/null +++ b/common/utils/ds/tests/test_spsc_q.cpp @@ -0,0 +1,135 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +#include "gtest/gtest.h" +extern "C" { +#include "spsc_q.h" +} + +TEST(spsc_q, basic_test) { + spsc_q_t rb = spsc_q_alloc(2, sizeof(int)); + + int a = 1; + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + EXPECT_FALSE(spsc_q_put(&rb, &a, sizeof(a))); + + int b; + EXPECT_TRUE(spsc_q_get(&rb, &b, sizeof(b))); + EXPECT_EQ(a, b); + EXPECT_TRUE(spsc_q_get(&rb, &b, sizeof(b))); + EXPECT_EQ(a, b); + EXPECT_FALSE(spsc_q_get(&rb, &b, sizeof(b))); + + spsc_q_free(&rb); +} + +TEST(spsc_q, cont_write) { + spsc_q_t rb = spsc_q_alloc(10, sizeof(int)); + + int a = 1; + for (int i = 0; i < 1111; ++i) { + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + a++; + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + a++; + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + a++; + + int b; + EXPECT_TRUE(spsc_q_get(&rb, &b, sizeof(b))); + EXPECT_EQ(b, a - 3); + EXPECT_TRUE(spsc_q_get(&rb, &b, sizeof(b))); + EXPECT_EQ(b, a - 2); + EXPECT_TRUE(spsc_q_get(&rb, &b, sizeof(b))); + EXPECT_EQ(b, a - 1); + } + + spsc_q_free(&rb); +} + +bool count(const void *data, void *user) +{ + EXPECT_TRUE(data != NULL); + int *c = (int *)user; + (*c)++; + return true; /* count all */ +} +TEST(spsc_q, iterator) { + spsc_q_t rb = spsc_q_alloc(10, sizeof(int)); + int n = 8; + for (int i = 0; i < n; ++i) + EXPECT_TRUE(spsc_q_put(&rb, &i, sizeof(i))); + + int c = 0; + int results[n]; + int ret = spsc_q_get_while(&rb, count, &c, results, sizeof(*results), n); + EXPECT_EQ(c, n); + EXPECT_EQ(ret, n); + for (int i = 0; i < n; ++i) + EXPECT_EQ(results[i], i); + + int b; + EXPECT_FALSE(spsc_q_get(&rb, &b, sizeof(b))); /* empty! */ + + spsc_q_free(&rb); +} + +bool drop(const void *data, void *user) +{ + const int *e = (const int *)data; + int *c = (int *)user; + EXPECT_EQ(*e, *c); + (*c)++; + return true; /* drop all */ +} +TEST(spsc_q, drop) { + spsc_q_t rb = spsc_q_alloc(10, sizeof(int)); + int n = 8; + for (int i = 0; i < n; ++i) + EXPECT_TRUE(spsc_q_put(&rb, &i, sizeof(i))); + + int c = 0; + int ret = spsc_q_drop_while(&rb, drop, &c); + EXPECT_EQ(c, n); + EXPECT_EQ(ret, n); + + int b; + EXPECT_FALSE(spsc_q_get(&rb, &b, sizeof(b))); /* empty! */ + + spsc_q_free(&rb); +} + + +TEST(spsc_q, full) { + int n = 3; + spsc_q_t rb = spsc_q_alloc(n, sizeof(int)); + int a = 1; + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + a++; + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + a++; + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + a++; + EXPECT_FALSE(spsc_q_put(&rb, &a, sizeof(a))); /* full! */ + + int b; + EXPECT_TRUE(spsc_q_get(&rb, &b, sizeof(b))); + EXPECT_EQ(b, a - n); + + EXPECT_TRUE(spsc_q_put(&rb, &a, sizeof(a))); + a++; + EXPECT_FALSE(spsc_q_put(&rb, &a, sizeof(a))); /* full! */ + + EXPECT_TRUE(spsc_q_get(&rb, &b, sizeof(b))); + EXPECT_EQ(b, a - n); + + spsc_q_free(&rb); +} + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/common/utils/ds/tests/test_spsc_q_perf.cpp b/common/utils/ds/tests/test_spsc_q_perf.cpp new file mode 100644 index 0000000000..6487e9e6c3 --- /dev/null +++ b/common/utils/ds/tests/test_spsc_q_perf.cpp @@ -0,0 +1,75 @@ +#include "benchmark/benchmark.h" +#include "stdio.h" +#include "assert.h" +#include "pthread.h" + +extern "C" { +#include "spsc_q.h" +} + +typedef struct q_args { + spsc_q_t q; + int range; +} q_args_t; + +static void *producer(void *arg) +{ + q_args_t *a = (q_args_t *) arg; + int i = 0; + while (i <= a->range) { + if (spsc_q_put(&a->q, &i, sizeof(i))) + i++; + } + return NULL; +} + +static void *consumer(void *arg) +{ + q_args_t *a = (q_args_t *) arg; + int i = 0; + while (i != a->range) { + int r; + if (spsc_q_get(&a->q, &r, sizeof(r))) { + assert(r == i); + i++; + } + } + return NULL; +} + +static void run_test(int range, int q_size) +{ + q_args_t args = { + .q = spsc_q_alloc(q_size, sizeof(int)), + .range = range, + }; + + pthread_t p, c; + int ret; + // start + ret = pthread_create(&p, NULL, producer, &args); + assert(ret == 0); + ret = pthread_create(&c, NULL, consumer, &args); + assert(ret == 0); + + ret = pthread_join(p, NULL); + assert(ret == 0); + ret = pthread_join(c, NULL); + assert(ret == 0); + // stop + // data/time => throughput + + spsc_q_free(&args.q); +} + +static void BM_spsc_q(benchmark::State &state) +{ + int range = 500000; + int q_size = state.range(0); + for (auto _ : state) + run_test(range, q_size); +} + +BENCHMARK(BM_spsc_q)->RangeMultiplier(2)->Range(10, 160); + +BENCHMARK_MAIN(); diff --git a/common/utils/fsn.c b/common/utils/fsn.c new file mode 100644 index 0000000000..e8566a2da9 --- /dev/null +++ b/common/utils/fsn.c @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +#include "fsn.h" + +#include + +static int num_slots[5] = {10, 20, 40, 80, 160}; + +fsn_t fsn_add_delta(fsn_t fsn, uint32_t delta) +{ + const int slots_frame = num_slots[fsn.mu]; + int next_f = fsn.f + delta / slots_frame; + int next_s = fsn.s + delta % slots_frame; + fsn_t res = { + .f = (next_f + next_s / slots_frame) % 1024, + .s = next_s % slots_frame, + .mu = fsn.mu, + }; + return res; +} + +int fsn_get_diff(fsn_t a, fsn_t b) +{ + assert(a.mu == b.mu); + const int slots_frame = num_slots[a.mu]; + 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 fsn_get_max(fsn_t a, fsn_t b) +{ + if (fsn_get_diff(a, b) <= 0) { + return b; + } else { + return a; + } +} + +bool fsn_equal(fsn_t a, fsn_t b) +{ + assert(a.mu == b.mu); + return a.f == b.f && a.s == b.s && a.mu == b.mu; +} + +bool fsn_in_the_past(fsn_t old, fsn_t new) +{ + int diff = fsn_get_diff(old, new); + return diff < 0; +} diff --git a/common/utils/fsn.h b/common/utils/fsn.h new file mode 100644 index 0000000000..dfa126bc85 --- /dev/null +++ b/common/utils/fsn.h @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +#ifndef FSN_H_ +#define FSN_H_ + +#include +#include + +/// helper type to encapsulate a frame/slot combination in a single type. +typedef struct fsn { + uint16_t f; /// frame + uint16_t s; /// slot + uint8_t mu; /// numerology +} fsn_t; + +/* \brief Add delta slots to fsn. Note that this depends also on the stored + * numerology inside fsn. */ +fsn_t fsn_add_delta(fsn_t fsn, uint32_t delta); + +/* \brief Get difference of slots for a and b. + * \note asserts if numerology not the same. */ +int fsn_get_diff(fsn_t a, fsn_t b); + +/* \brief Gets the larger of two fsns */ +fsn_t fsn_get_max(fsn_t a, fsn_t b); + +/* \brief Compare if both fsn_t's are equal */ +bool fsn_equal(fsn_t a, fsn_t b); + +/* \brief Determine if told is in the past of tnew. The threshold is 512 + * frames. */ +bool fsn_in_the_past(fsn_t told, fsn_t tnew); + +#endif /* FSN_H_ */ diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 8580a0491b..228e51feb2 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -13,6 +13,7 @@ #include #include "assertions.h" #include "common/utils/utils.h" +#include "common/utils/ds/byte_array.h" #define MAX_SI_GROUPS 3 #define NR_MAX_PDSCH_TBS 3824 @@ -79,10 +80,32 @@ static inline const char *rnti_types(nr_rnti_type_t rr) // the total shift is 2 * 15, in dB scale thats 10log10(2^(15*2)) #define SQ15_SQUARED_NORM_FACTOR_DB 90.3089986992 +typedef enum { + NR_SIB_1 = 1, + NR_SIB_2, + NR_SIB_3, + NR_SIB_4, + NR_SIB_5, + NR_SIB_6, + NR_SIB_7, + NR_SIB_8, + NR_SIB_9, + NR_SIB_10, + NR_SIB_11, + NR_SIB_12, + NR_SIB_13, + NR_SIB_14, + NR_SIB_15, + NR_SIB_16, + NR_SIB_17, + NR_SIB_18, + NR_SIB_19, + NR_SIB_20, + NR_SIB_21, +} nr_sib_type_t; + typedef struct { - uint8_t *SIB_buffer; - int SIB_size; - int SIB_type; + nr_sib_type_t SIB_type; } nr_SIBs_t; typedef struct nr_bandentry_s { diff --git a/common/utils/tests/CMakeLists.txt b/common/utils/tests/CMakeLists.txt index e3c310fed9..14d2f83d7a 100644 --- a/common/utils/tests/CMakeLists.txt +++ b/common/utils/tests/CMakeLists.txt @@ -2,3 +2,10 @@ add_executable(test_tpool_vs_actors test_tpool_vs_actors.c) target_link_libraries(test_tpool_vs_actors PRIVATE thread-pool pthread LOG minimal_lib actor) +add_test(NAME test_tpool_vs_actors COMMAND ./test_tpool_vs_actors) +add_dependencies(tests test_tpool_vs_actors) + +add_executable(test_fsn test_fsn.cpp) +add_dependencies(tests test_fsn) +target_link_libraries(test_fsn PRIVATE utils GTest::gtest) +add_test(NAME test_fsn COMMAND ./test_fsn) diff --git a/common/utils/tests/test_fsn.cpp b/common/utils/tests/test_fsn.cpp new file mode 100644 index 0000000000..3cbe34dfb2 --- /dev/null +++ b/common/utils/tests/test_fsn.cpp @@ -0,0 +1,84 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +#include +extern "C" { +#include "fsn.h" +} + +TEST(fsn, test_mu0_fsn_add) { + fsn_t current = {123, 5, 0}; + fsn_t next = current; + + next = fsn_add_delta(next, 12); + EXPECT_EQ(next.f, 124); + EXPECT_EQ(next.s, 7); + EXPECT_EQ(next.mu, 0); + + next = fsn_add_delta(next, 10); + EXPECT_EQ(next.f, 125); + EXPECT_EQ(next.s, 7); + EXPECT_EQ(next.mu, 0); + + next = fsn_add_delta(next, 10 * 1024); + EXPECT_EQ(next.f, 125); + EXPECT_EQ(next.s, 7); + EXPECT_EQ(next.mu, 0); +} + +TEST(fsn, test_mu0_get_diff) { + fsn_t current = {123, 5, 0}; + fsn_t next = fsn_add_delta(current, 12); + int diff; + + diff = fsn_get_diff(current, next); + EXPECT_EQ(diff, -12); + + diff = fsn_get_diff(next, current); + EXPECT_EQ(diff, 12); +} + +TEST(fsn, test_mu0_get_max) { + fsn_t current = {123, 5, 0}; + fsn_t next = {125, 7, 0}; + + fsn_t max = fsn_get_max(current, next); + EXPECT_EQ(max.f, next.f); + EXPECT_EQ(max.s, next.s); + EXPECT_EQ(max.mu, next.mu); +} + +TEST(fsn, test_mu0_equal) { + fsn_t a = {123, 5, 0}; + fsn_t b = a; + fsn_t c = {123, 6, 0}; + + EXPECT_TRUE(fsn_equal(a, b)); + EXPECT_FALSE(fsn_equal(a, c)); +} + +TEST(fsn, test_mu0_in_the_past) { + fsn_t a = {0, 0, 0}; + fsn_t n = {100, 9, 0}; + fsn_t b_bef = {511, 9, 0}; + fsn_t b_ex = {512, 0, 0}; + fsn_t b_aft = {512, 1, 0}; + + // a is in the past of n + EXPECT_TRUE(fsn_in_the_past(a, n)); + // similarly, a is in the past of b_bef + EXPECT_TRUE(fsn_in_the_past(a, b_bef)); + // difference "to both sides" is 512 frames, so we consider a still in the + // past of b_ex + EXPECT_TRUE(fsn_in_the_past(a, b_ex)); + // (b_aft - a) < (a - b_aft) => b_aft is in the past of a because of + // wrap-around + EXPECT_TRUE(fsn_in_the_past(b_aft, a)); +} + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/doc/Doxyfile b/doc/Doxyfile index fad5807544..7c09e6272e 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1967,7 +1967,7 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/LTE_TRANSPORT/dci_NB_IoT.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/LTE_TRANSPORT/group_hopping.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/LTE_TRANSPORT/if4_tools.h \ +@CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/if4_tools.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/LTE_TRANSPORT/uci_tools.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/LTE_TRANSPORT/prach.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/LTE_TRANSPORT/edci.c \ diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 95aa32166f..bc6ba6b4a3 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -154,7 +154,7 @@ These modes of operation are supported: - RedCap SIB1 v17 IEs supported - Coexistence of RedCap and Normal UEs - Handling of RedCap capability for small PDCP/RLC SN size -- Scheduling of other SIBs (2, 19) +- Scheduling of other SIBs (2, 3, 4, 19) - NTN - Support downlinkHARQ-FeedbackDisabled-r17 - Support for 32 PDSCH and PUSCH HARQ processes per UE @@ -194,7 +194,7 @@ These modes of operation are supported: - NR RRC (38.331) Rel 17 messages using new [asn1c](https://github.com/mouse07410/asn1c) - LTE RRC (36.331) also updated to Rel 15 -- Generation of system information (SIB2) +- Generation of system information (SIB2, SIB3, SIB4) - RRC can configure PDCP and SDAP (through E1), and RLC and MAC (through F1) - Interface with GTP-U (tunnel creation/handling for S1-U (NSA), N3 (SA), F1 interfaces) - Integration of RRC messages and procedures supporting UE 5G SA connection @@ -380,7 +380,7 @@ These modes of operation are supported: - MIB processing - Scheduling of system information block 1 (SIB1) reception * Other system information - - Scheduling of other system information blocks reception + - Scheduling of other system information blocks reception (SIB2, SIB3, SIB4) * Random access procedure (needs improvement, there is still not a clear separation between MAC and PHY) - Mapping SSBs to multiple ROs - Scheduling of PRACH diff --git a/doc/README.md b/doc/README.md index 37fe2a980d..d1dfc2dc4d 100644 --- a/doc/README.md +++ b/doc/README.md @@ -135,6 +135,7 @@ The other SDRs (AW2S, LimeSDR, ...) have no READMEs. - [clang-format.md](./clang-format.md): how to format the code. See also the next entry for an error detection tool. - [formatting](../tools/formatting/README.md) is a clang-format error detection tool +- [cppcheck](../tools/cppcheck/README.md) for static code analysis - [sanitizers.md](./dev_tools/sanitizers.md): how to run with ASan/UBSan/MemSAN/TSan - [iwyu](../tools/iwyu/README.md) is a tool to detect `#include` errors - [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 eee1b861fa..a218997d3a 100644 --- a/doc/RRC/rrc-dev.md +++ b/doc/RRC/rrc-dev.md @@ -633,6 +633,98 @@ sequenceDiagram Note over TargetCU: Then: encode Handover Command, send NGAP HANDOVER REQUEST ACKNOWLEDGE ``` +### Neighbour cells + +#### SIB3/SIB4 and measurement-gap implementation + +The following section documents the implementation-level control flow +for SIB3/SIB4 and measurement-gap handling in current OAI, using the configured +neighbor cell list as a shared input model. + +Briefly, the three procedures are: +- SIB3: CU derives and provides intra-frequency neighbour SI, which DU broadcasts + and UE uses for autonomous idle/inactive intra-frequency reselection. +- SIB4: CU derives and provides inter-frequency carrier/neighbour SI, which DU + broadcasts and UE uses for autonomous idle/inactive inter-frequency reselection. +- MeasGap: CU/DU coordinate dedicated `MeasGapConfig` in UE `MeasConfig`, DU + scheduler interrupts transmission (`nr_measgap_scheduling()`) for the UE to + apply the MeasGap configuration in connected mode for gap-based measurements that + are sent as `MeasurementReport` and processed at CU-CP (`rrc_gNB_process_MeasurementReport()`). + Event-driven reports (for example A3) are used by CU-side mobility logic and can + trigger handover procedures. + +### MeasGap + +```mermaid +sequenceDiagram + participant DM as Data model (neighbour_cell_configuration) + participant CU as CU-CP (RRC) + participant DU as DU (MAC/RRC) + participant UE as UE + + CU-->>DM: Read serving + neighbour frequency/PCI/band data + DM-->>CU: Provide neighbour/frequency inputs for MeasConfig + CU->>CU: nr_rrc_get_measconfig + Note over CU: Build UE MeasConfig + CU->>CU: get_meas_timing_config (cell.mtc, ue.measConfig) + Note over CU: Check distinct ssbFrequency + alt one frequency only + Note over CU: returns NULL, no meas_timing_config sent to DU + else multiple frequencies + CU->>DU: F1AP UE Context Setup Request + Note over CU,DU: Includes cu_to_du_rrc_info.meas_timing_config + DU->>DU: create_measgap_config + DU->>DU: encode_measgap_config + DU-->>CU: F1AP UE Context Setup Response + Note over DU,CU: Includes du_to_cu_rrc_info.meas_gap_config + CU->>CU: get_meas_gap_config + Note over CU: Decode/store gap in UE MeasConfig (UE.measConfig.measGapConfig) + CU->>UE: RRCReconfiguration + Note over CU,UE: Includes MeasConfig.measGapConfig + rect rgba(210, 235, 255, 0.35) + Note over DU,UE: Measurement-gap window + DU->>DU: nr_measgap_scheduling + Note over DU: Interrupt transmission for meas gap + UE->>UE: nr_rrc_handle_meas_indication + Note over UE: Perform gap-based neighbour/inter-frequency measurements + UE-->>CU: MeasurementReport + end + Note over UE,CU: UL-DCCH MeasurementReport for configured events (e.g. A3) + CU->>CU: rrc_gNB_process_MeasurementReport + Note over CU: Run mobility decision logic (may trigger handover) + end +``` + +### SIB3/SIB4 + +```mermaid +sequenceDiagram + participant DM as Data model (neighbour_cell_configuration) + participant CU as CU-CP (RRC) + participant DU as DU + participant UE as UE + + CU->>CU: cp_f1_served_cell_info_to_cell + CU->>DM: get_cell_neighbour_list + DM-->>CU: neighbour_cell_configuration for serving cell + CU->>CU: get_ssb_arfcn + Note over CU: Derive serving_ssb_arfcn from cell MTC + loop for each configured neighbour + Note over CU: Compare neighbour.absoluteFrequencySSB vs serving_ssb_arfcn + alt equal + CU->>CU: get_sib3_intra_freq_neighbors + else different + CU->>CU: get_sib4_inter_freq_neighbors + end + end + CU-->>DU: F1AP F1 Setup Response + DU-->>UE: BCCH-DL-SCH-Message + Note over DU,UE: Broadcast SystemInformation including configured SIB3/SIB4 + UE->>UE: nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message + Note over UE: Evaluate idle/inactive reselection criteria and timers + Note over UE,DU: After reselection, access/registration continues on selected cell DU as needed +``` + ## UE Context UE context information is stored in `gNB_RRC_UE_t`, which includes: diff --git a/doc/RRC/rrc-usage.md b/doc/RRC/rrc-usage.md index 46ff9f061c..e828001d1b 100644 --- a/doc/RRC/rrc-usage.md +++ b/doc/RRC/rrc-usage.md @@ -94,7 +94,81 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration. deactivated, a transparent SDAP header is prepended to packets, but no further processing is being done. - `cu_sibs` (default: `[]`) list of SIBs to give to the DU for transmission. - Currently, SIB2 is supported. + Currently supported: + - SIB2: serving-cell reselection parameters (configured in `sib2_config`) + - SIB3: intra-frequency neighbour cell list (neighbours on the same SSB ARFCN as the serving cell) + - SIB4: inter-frequency carriers + neighbour lists, grouped per `(absoluteFrequencySSB, subcarrierSpacing)`. Per-frequency fields (e.g. `cellReselectionPriority`, `threshX_HighP`, `threshX_LowP`, `q_OffsetFreq`) come from `frequency_list` + +Example activation: +``` +cu_sibs = ( 2, 3, 4 ); +``` +SIB2 is configured per-gNB in `sib2_config` (see below). SIB3/SIB4 are derived from the neighbour configuration: +- `neighbour_list` / `neighbour_cell_configuration`: neighbour identity + per-neighbour offsets (`q_OffsetCell`, etc.) +- `frequency_list`: per-frequency SIB4 reselection parameters (priority/thresholds/`q_OffsetFreq`) + +Example `gNBs.[0].sib2_config`: +``` +cu_sibs = ( 2 ); + +sib2_config : { + q_Hyst = 0; + cellReselectionPriority = 0; + threshServingLowP = 0; + threshServingLowQ = 4; + s_NonIntraSearchP = 10; + s_NonIntraSearchQ = 8; + q_RxLevMin = -56; + q_QualMin = -18; + s_IntraSearchP = 22; + s_IntraSearchQ = 20; + t_ReselectionNR = 1; + deriveSSB_IndexFromCell = 1; + + speed_t_Evaluation = 0; + speed_t_HystNormal = 0; + speed_n_CellChangeMedium = 1; + speed_n_CellChangeHigh = 2; + speed_sf_Medium = 1; + speed_sf_High = 0; +}; +``` + +#### SIB3/SIB4 and measurement gaps + +This section summarizes how SIB3/SIB4 and measurement gaps relate in NR and how OAI currently implements them. + +From 3GPP TS 38.331: + +- `SIB3` carries intra-frequency reselection information (`intraFreqNeighCellList`). +- `SIB4` carries inter-frequency reselection information (`interFreqCarrierFreqList` + and per-carrier neighbour lists). +- `MeasGapConfig` is part of dedicated `MeasConfig` (typically sent in + `RRCReconfiguration`) and controls measurement gaps in connected mode. + +In other words: + +- SIB3/SIB4 are broadcast SI for idle/inactive (`RRC_IDLE` / `RRC_INACTIVE`) + reselection behavior: UE performs autonomous cell reselection using broadcast + SI (SIB3 for intra-frequency, SIB4 for inter-frequency). +- `MeasGapConfig` is a dedicated UE measurement behavior and applies to + connected mode (`RRC_CONNECTED`): the network configures what the UE + measures and reports (periodic and event-based, e.g., A3), and those reports + are used by CU-CP mobility logic (including handover decisions). + +MeasGap does not depend on SIB3/SIB4, however they share the same underlying +neighbour/frequency data model, which is the common source of serving + +neighbour frequency information (see also [Neighbor-gNB configuration](#neighbour-gnb-configuration)): + +- SIB3/SIB4 generation is done on the CU-CP side (inside `rrc_gNB_du.c`) from + neighbour/frequency configuration and serving-cell MTC-derived ARFCN. +- Measurement-gap configuration also starts from the same neighbour/frequency + model: CU uses neighbour fields (frequency/PCI/band) to build UE + `MeasConfig` measurement objects, then DU derives/encodes gap parameters + from CU-provided timing (`meas_timing_config`) and returns `meas_gap_config` + for CU forwarding in dedicated `RRCReconfiguration`. + +Detailed implementation flow and sequence diagrams are documented in [`rrc-dev.md`](./rrc-dev.md). #### UE-specific configuration @@ -105,12 +179,64 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration. Refer to the [handover tutorial](../handover-tutorial.md) for detailed information about gNB neighbors and handover procedures. +##### Configuration structure and key semantics + +The neighbour configuration is a 2-level structure: + +- Outer list: `neighbour_list` + - Key: `nr_cellid` of the serving cell + - One entry per serving cell +- Inner list: `neighbour_cell_configuration` + - Actual neighbour cells for that serving cell + - Contains neighbour fields such as `gNB_ID`, neighbour `nr_cellid`, `physical_cellId`, frequency, PLMN, etc. + +This same core configuration model is reused by multiple RRC procedures. + +- SIB3/SIB4 generation: uses neighbour identity/frequency/offset fields to derive + intra/inter-frequency SI. +- Connected-mode measurement config: uses neighbour frequency/PCI/band fields to build + UE `MeasConfig` measurement objects. +- Handover-related procedures: reuse neighbour identity fields (e.g., cell ID/PCI/PLMN + TAC, gNB ID) for target selection and for populating target-cell information carried + in NGAP handover messages. + +Conceptually, for each serving cell the RRC keeps: + +- A per-frequency table (`inter_freqs`): one entry per `(absoluteFrequencySSB, + subcarrierSpacing)` used for SIB4, containing the SIB4 per-frequency fields + (priority, thresholds, `q_OffsetFreq`, `q_RxLevMin`, `t_ReselectionNR`). +- A per-neighbour list (`neighbour_cells`): one entry per neighbour, with + identity (cell ID, PCI, PLMN, TAC), frequency (`absoluteFrequencySSB`, + `subcarrierSpacing`, `band`), and SIB3/SIB4 per-neighbour offsets + (`q_OffsetCell`, `q_RxLevMinOffsetCell`, `q_QualMinOffsetCell`). +- A link from neighbours to frequencies: each neighbour implicitly points to + the matching `inter_freqs` entry via its `(absoluteFrequencySSB, + subcarrierSpacing)`; if no such frequency exists, it is treated as having no + SIB4 per-frequency configuration. + +Notes: + +- In `neighbour_list`, only `nr_cellid` is used as the key for lookup. +- `physical_cellId` belongs to neighbour-cell entries in `neighbour_cell_configuration` (inner list). +- `nr_cellid` entries in `neighbour_list` should be unique to avoid ambiguous lookup. +- Intra-frequency neighbours (SIB3) are derived only from the per-cell + `neighbour_cell_configuration` on the serving carrier. + +At configuration time (`gnb_config.c`), neighbours are parsed into `neighbour_cells`, +per-neighbour SIB3/SIB4 offsets are validated, and a per-frequency array `inter_freqs` +is built by grouping neighbours by `(absoluteFrequencySSB, subcarrierSpacing)` and +in-range SIB4 per-frequency fields (`cellReselectionPriority`, `threshX_HighP/L`, +`q_OffsetFreq`) across neighbours on the same ARFCN. At SIB4 build time, the RRC uses +`inter_freqs` to create one `InterFreqCarrierFreqInfo` per ARFCN for inter-frequency +carriers (ARFCN different from the serving SSB ARFCN) and attaches all neighbours whose +`inter_freq_idx` points to that frequency entry. + ##### Required configuration parameters -To define a neighbor cell in the configuration file, the following parameters are required: +To define a neighbour 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`) +- `gNB_ID` - identifier of the neighbour gNB (e.g., `0xe01`) +- `nr_cellid` - cell identifier of the neighbour 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 @@ -123,19 +249,45 @@ To define a neighbor cell in the configuration file, the following parameters ar Example configuration structure: ``` +# Per-frequency SIB4 configuration (one entry per ARFCN), shared by all cells +frequency_list = ( + { + absoluteFrequencySSB = 643296; + subcarrierSpacing = 1; # 30 kHz + band = 78; + + frequency_config = ( + { + cellReselectionPriority = 5; + threshX_HighP = 10; + threshX_LowP = 6; + q_OffsetFreq = 0; + # Optional: threshX_HighQ, threshX_LowQ, etc. + } + ); + } +); + +# Per-cell neighbour configuration; neighbours reference frequency_list via ARFCN/SCS neighbour_list = ( { nr_cellid = 12345678; + neighbour_cell_configuration = ( { gNB_ID = 0xe01; nr_cellid = 11111111; physical_cellId = 1; - absoluteFrequencySSB = 643296; - subcarrierSpacing = 1; # 30 kHz + absoluteFrequencySSB = 643296; # ARFCN used to look up matching entry in frequency_list + subcarrierSpacing = 1; # 30 kHz band = 78; plmn = { mcc = 001; mnc = 01; mnc_length = 2 }; tracking_area_code = 1; + + # Example per-neighbour offsets (SIB3/SIB4) + q_OffsetCell = 0; + q_RxLevMinOffsetCell = -1; + q_QualMinOffsetCell = -1; } ); } diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md index d348ffe355..361d774215 100644 --- a/doc/TESTBenches.md +++ b/doc/TESTBenches.md @@ -96,10 +96,6 @@ information on how the images are built. - orion: Cross-compilation from Intel to ARM - 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 - - performs static code analysis, currently not actively enforced - [RAN-RHEL8-Cluster-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-RHEL8-Cluster-Image-Builder/) ~BUILD-ONLY ~4G-LTE ~5G-NR ~nrUE - cluster (`Asterix-OC-oaicicd-session` resource): RHEL image build using the OpenShift Cluster (using gcc/clang) diff --git a/doc/handover-tutorial.md b/doc/handover-tutorial.md index 68e685c83d..02736da931 100644 --- a/doc/handover-tutorial.md +++ b/doc/handover-tutorial.md @@ -512,8 +512,16 @@ configuration, e.g. [neighbour-config-rfsim.conf](../../ci-scripts/conf_files/ne 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 neighbor configuration is nested: + +- `neighbour_list` outer entries are keyed by serving `nr_cellid` +- each outer entry contains `neighbour_cell_configuration`, i.e., the list of neighbor cells for that serving cell + +In this model: + +- outer `nr_cellid` entries should be unique +- neighbor `physical_cellId` values are defined in inner neighbor entries +- the same serving-cell keyed neighbor mapping is used for both F1 and N2 handover logic See the example above for `neighbour-config-ho.conf`. The same configuration is for both F1 and N2 handover. diff --git a/doc/tutorial_resources/oai-cn5g/docker-compose-positioning.yaml b/doc/tutorial_resources/oai-cn5g/docker-compose-positioning.yaml index 6b75c22b6b..c3b9d937c1 100644 --- a/doc/tutorial_resources/oai-cn5g/docker-compose-positioning.yaml +++ b/doc/tutorial_resources/oai-cn5g/docker-compose-positioning.yaml @@ -1,7 +1,7 @@ services: mysql: container_name: "mysql" - image: mysql:8.0 + image: mysql:9.6 volumes: - ./database/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ./healthscripts/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -172,7 +172,7 @@ services: privileged: true init: true container_name: oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:jammy + image: oaisoftwarealliance/trf-gen-cn5g:latest entrypoint: /bin/bash -c \ "ip route add 10.0.0.0/16 via 192.168.70.134 dev eth0; ip route; sleep infinity" command: ["/bin/bash", "-c", "trap : SIGTERM SIGINT; sleep infinity & wait"] diff --git a/doc/tutorial_resources/oai-cn5g/docker-compose.yaml b/doc/tutorial_resources/oai-cn5g/docker-compose.yaml index 0baf032fbb..d99eadb844 100644 --- a/doc/tutorial_resources/oai-cn5g/docker-compose.yaml +++ b/doc/tutorial_resources/oai-cn5g/docker-compose.yaml @@ -1,7 +1,7 @@ services: mysql: container_name: "mysql" - image: mysql:8.0 + image: mysql:9.6 volumes: - ./database/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql - ./healthscripts/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh @@ -154,9 +154,9 @@ services: privileged: true init: true container_name: oai-ext-dn - image: oaisoftwarealliance/trf-gen-cn5g:jammy + image: oaisoftwarealliance/trf-gen-cn5g:latest entrypoint: /bin/bash -c \ - "ip route add 10.0.0.0/16 via 192.168.70.134 dev eth0; ip route; sleep infinity" + "ip route add 10.0.0.0/16 via 192.168.70.134 dev eth0; ip route; iperf3 -s -D; sleep infinity" command: ["/bin/bash", "-c", "trap : SIGTERM SIGINT; sleep infinity & wait"] healthcheck: test: /bin/bash -c "ip r | grep 10.0.0" diff --git a/docker/Dockerfile.clang.rhel9 b/docker/Dockerfile.clang.rhel9 index 81fd8ccc83..4fae70955f 100644 --- a/docker/Dockerfile.clang.rhel9 +++ b/docker/Dockerfile.clang.rhel9 @@ -25,4 +25,4 @@ RUN /bin/sh oaienv && \ CFLAGS="-Werror" CXXFLAGS="-Werror -Wno-vla-cxx-extension" \ ./build_oai --phy_simulators --gNB --eNB --nrUE --UE \ --ninja --build-tool-opt -k10 \ - --noavx512 --disable-T-Tracer -c + --noavx512 -c diff --git a/docker/Dockerfile.phySim.rhel9 b/docker/Dockerfile.phySim.rhel9 index ac1c8680ca..31ca26adef 100644 --- a/docker/Dockerfile.phySim.rhel9 +++ b/docker/Dockerfile.phySim.rhel9 @@ -24,6 +24,7 @@ RUN /bin/sh oaienv && \ -DAVX512=OFF -DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror \ -DENABLE_PHYSIM_TESTS=ON \ -DSANITIZE_ADDRESS=ON -DSANITIZE_UNDEFINED=ON \ + -DT_TRACER=OFF \ -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/opt/oai-physim/bin && \ ninja -k10 -j36 diff --git a/executables/lte-enb.c b/executables/lte-enb.c index b62815b70a..c735934c1a 100644 --- a/executables/lte-enb.c +++ b/executables/lte-enb.c @@ -20,7 +20,7 @@ #include "nfapi/oai_integration/vendor_ext.h" #include "radio/COMMON/common_lib.h" -#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/if4_tools.h" #include "PHY/LTE_ESTIMATION/lte_estimation.h" #include "PHY/phy_extern.h" diff --git a/executables/lte-ru.c b/executables/lte-ru.c index 91470d8f63..a0a82deabd 100644 --- a/executables/lte-ru.c +++ b/executables/lte-ru.c @@ -28,7 +28,7 @@ #include "PHY/phy_extern.h" #include "PHY/LTE_ESTIMATION/lte_estimation.h" #include "PHY/LTE_REFSIG/lte_refsig.h" -#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/if4_tools.h" #include "PHY/LTE_TRANSPORT/transport_proto.h" #include "SCHED/sched_common.h" #include "common/utils/LOG/log.h" diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index abbfa05df1..1b27b2e4e6 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -161,7 +161,12 @@ static void rx_func(processingData_L1_t *info) NR_UL_IND_t UL_INFO = {.frame = frame_rx, .slot = slot_rx, .module_id = gNB->Mod_id, .CC_id = gNB->CC_id}; // Do PRACH RU processing UL_INFO.rach_ind.pdu_list = UL_INFO.prach_pdu_indication_list; - L1_nr_prach_procedures(gNB, frame_rx, slot_rx, &UL_INFO.rach_ind); + UL_INFO.rach_ind.number_of_pdus = 0; + // even if processing is late, we might collect all PRACH + // the last PRACH's frame/slot is when all UE's appear to have accessed + prach_item_t p; + while (spsc_q_get(&gNB->prach_l1rx_queue, &p, sizeof(p))) + L1_nr_prach_procedures(gNB, &p, &UL_INFO.rach_ind); //WA: comment rotation in tx/rx if (gNB->phase_comp) { diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 7554c8a9a6..b66d4976c9 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -15,12 +15,13 @@ #include "common/utils/nr/nr_common.h" #include "common/utils/assertions.h" #include "common/utils/system.h" +#include "common/utils/fsn.h" #include "common/ran_context.h" #include "radio/COMMON/common_lib.h" #include "radio/ETHERNET/ethernet_lib.h" -#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/if4_tools.h" #include "PHY/defs_nr_common.h" #include "PHY/phy_extern.h" @@ -980,11 +981,16 @@ void *ru_thread(void *param) proc->tti_rx * gNB->frame_parms.samples_per_slot_wCP); // Do PRACH RU processing - prach_item_t *p = - find_nr_prach(&gNB->prach_list, proc->frame_rx, proc->tti_rx, gNB->frame_parms.nb_antennas_rx, NR_SEARCH_EXIST); - if (p) { + fsn_t now = {.f = proc->frame_rx, .s = proc->tti_rx, .mu = fp->numerology_index}; + prach_item_t p; + while (get_next_nr_prach(&gNB->prach_ru_queue, &now, &p)) { // need to extract RACH data for later processing by rx_nr_prach() - rx_nr_prach_ru(p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset); + rx_nr_prach_ru(&p, ru->common.rxdata, ru->nr_frame_parms, ru->N_TA_offset); + bool success = spsc_q_put(&gNB->prach_l1rx_queue, &p, sizeof(p)); + // assume prach_l1rx_queue never full: prach_ru_queue filled at + // constant pace, but prach_l1rx_queue emptied as fast as possible, + // see rx_func() + DevAssert(success); } // end if (prach_id >= 0) } // end if (ru->feprx) } // end if (slot_type == NR_UPLINK_SLOT || slot_type == NR_MIXED_SLOT) { diff --git a/executables/ru_control.c b/executables/ru_control.c index 11a3ef0f14..1852a67afb 100644 --- a/executables/ru_control.c +++ b/executables/ru_control.c @@ -27,7 +27,7 @@ #include "radio/COMMON/common_lib.h" #include "radio/ETHERNET/ethernet_lib.h" -#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/if4_tools.h" #include "PHY/LTE_TRANSPORT/transport_proto.h" #include "SCHED/sched_eNB.h" diff --git a/nfapi/oai_integration/wls_integration/wls_pnf.c b/nfapi/oai_integration/wls_integration/wls_pnf.c index 42c09b4845..738f15a1a1 100644 --- a/nfapi/oai_integration/wls_integration/wls_pnf.c +++ b/nfapi/oai_integration/wls_integration/wls_pnf.c @@ -183,7 +183,7 @@ bool wls_pnf_nr_send_p5_message(pnf_t *pnf, nfapi_nr_p4_p5_message_header_t *msg 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); + UNUSED(msg_len); if (pnf_p7->terminate) { // don't send any further P7 messages after terminating return false; diff --git a/nfapi/oai_integration/wls_integration/wls_vnf.c b/nfapi/oai_integration/wls_integration/wls_vnf.c index a250188c78..7249bae551 100644 --- a/nfapi/oai_integration/wls_integration/wls_vnf.c +++ b/nfapi/oai_integration/wls_integration/wls_vnf.c @@ -410,7 +410,7 @@ int wls_fapi_nr_vnf_start(nfapi_vnf_config_t *cfg) 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); + UNUSED(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); diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index 59bdd7012d..35b27468f6 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -50,6 +50,8 @@ int l1_north_init_gNB() NR_gNB_PHY_STATS_t *get_phy_stats(PHY_VARS_gNB *gNB, uint16_t rnti) { + // TODO reimplement with hashtable? also called from both UL/DL => not + // thread-safe NR_gNB_PHY_STATS_t *stats; int first_free = -1; for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) { @@ -141,16 +143,6 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) init_DLSCH_struct(gNB); - gNB->nr_srs_info = (nr_srs_info_t **)malloc16_clear(gNB->max_nb_srs * sizeof(nr_srs_info_t*)); - for (int id = 0; id < gNB->max_nb_srs; id++) { - gNB->nr_srs_info[id] = (nr_srs_info_t *)malloc16_clear(sizeof(nr_srs_info_t)); - gNB->nr_srs_info[id]->srs_generated_signal = malloc16_clear(MAX_NUM_NR_SRS_AP * sizeof(c16_t *)); - for(int ap=0; apnr_srs_info[id]->srs_generated_signal[ap] = - malloc16_clear(fp->ofdm_symbol_size * MAX_NUM_NR_SRS_SYMBOLS * sizeof(c16_t)); - } - } - /* Do NOT allocate per-antenna rxdataF: the gNB gets a pointer to the * RU to copy/recover freq-domain memory from there */ common_vars->rxdataF = (c16_t ***)malloc16(common_vars->num_beams_period * sizeof(c16_t**)); @@ -174,7 +166,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) common_vars->debugBuff_sample_offset = 0; // PRACH - init_prach_list(&gNB->prach_list); + init_nr_prach(gNB); int N_RB_UL = cfg->carrier_config.ul_grid_size[cfg->ssb_config.scs_common.value].value; int n_buf = Prx*max_ul_mimo_layers; @@ -212,19 +204,11 @@ void phy_free_nr_gNB(PHY_VARS_gNB *gNB) PHY_MEASUREMENTS_gNB *meas = &gNB->measurements; free_and_zero(meas->n0_subband_power); - for (int id = 0; id < gNB->max_nb_srs; id++) { - for(int i=0; inr_srs_info[id]->srs_generated_signal[i]); - } - free_and_zero(gNB->nr_srs_info[id]->srs_generated_signal); - free_and_zero(gNB->nr_srs_info[id]); - } - free_and_zero(gNB->nr_srs_info); - free_ul_reference_signal_sequences(); free_gnb_lowpapr_sequences(); reset_nr_transport(gNB); + reset_nr_prach(gNB); destroy_DLSCH_struct(gNB); @@ -437,18 +421,14 @@ void init_nr_transport(PHY_VARS_gNB *gNB) else buffer_ul_slots = (nb_ul_slots_period < slot_ahead) ? nb_ul_slots_period : slot_ahead; - gNB->max_nb_pucch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1; gNB->max_nb_pusch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1; - gNB->max_nb_srs = buffer_ul_slots ? buffer_ul_slots << 1 : 1; // assuming at most 2 SRS per slot - gNB->pucch = (NR_gNB_PUCCH_t *)malloc16(gNB->max_nb_pucch * sizeof(NR_gNB_PUCCH_t)); - for (int i = 0; i < gNB->max_nb_pucch; i++) { - memset(&gNB->pucch[i], 0, sizeof(gNB->pucch[i])); - } + int max_nb_pucch = buffer_ul_slots ? MAX_MOBILES_PER_GNB * buffer_ul_slots : 1; + gNB->pucch_queue = spsc_q_alloc(max_nb_pucch, sizeof(NR_gNB_PUCCH_job_t)); + gNB->pusch_queue = spsc_q_alloc(gNB->max_nb_pusch, sizeof(NR_gNB_PUSCH_job_t)); - gNB->srs = (NR_gNB_SRS_t *)malloc16(gNB->max_nb_srs * sizeof(NR_gNB_SRS_t)); - for (int i = 0; i < gNB->max_nb_srs; i++) - gNB->srs[i].active = 0; + int max_nb_srs = buffer_ul_slots ? buffer_ul_slots << 1 : 1; // assuming at most 2 SRS per slot + gNB->srs_queue = spsc_q_alloc(max_nb_srs, sizeof(NR_gNB_SRS_job_t)); gNB->ulsch = (NR_gNB_ULSCH_t *)malloc16(gNB->max_nb_pusch * sizeof(NR_gNB_ULSCH_t)); for (int i = 0; i < gNB->max_nb_pusch; i++) { @@ -465,8 +445,9 @@ void reset_nr_transport(PHY_VARS_gNB *gNB) { const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - free(gNB->pucch); - free(gNB->srs); + spsc_q_free(&gNB->pucch_queue); + spsc_q_free(&gNB->pusch_queue); + spsc_q_free(&gNB->srs_queue); for (int i = 0; i < gNB->max_nb_pusch; i++) free_gNB_ulsch(&gNB->ulsch[i], fp->N_RB_UL); diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 0cbb679f82..71ad18ab62 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -3,7 +3,6 @@ */ #include "PHY/phy_extern.h" -#include "SCHED/sched_common.h" #include "assertions.h" #include #include "openair1/PHY/defs_RU.h" diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index d7d73e1c01..cccf4cf3a8 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -251,8 +251,6 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) ue->nr_csi_info->csi_rs_generated_signal[i] = malloc16_clear(fp->samples_per_slot_wCP * sizeof(**ue->nr_csi_info->csi_rs_generated_signal)); } - - ue->nr_srs_info = malloc16_clear(sizeof(nr_srs_info_t)); } ue->init_averaging = 1; @@ -301,8 +299,6 @@ void term_nr_ue_signal(PHY_VARS_NR_UE *ue) free_and_zero(ue->nr_csi_info->csi_rs_generated_signal); free_and_zero(ue->nr_csi_info); - free_and_zero(ue->nr_srs_info); - free_and_zero(ue->prach_vars[gNB_id]); } diff --git a/openair1/PHY/LTE_TRANSPORT/prach.c b/openair1/PHY/LTE_TRANSPORT/prach.c index b821aa758e..6751f68da0 100644 --- a/openair1/PHY/LTE_TRANSPORT/prach.c +++ b/openair1/PHY/LTE_TRANSPORT/prach.c @@ -7,9 +7,7 @@ */ #include "PHY/sse_intrin.h" #include "PHY/defs_eNB.h" -//#include "PHY/phy_extern.h" -//#include "prach.h" -#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/if4_tools.h" #include "SCHED/sched_eNB.h" #include "common/utils/LOG/vcd_signal_dumper.h" diff --git a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c index 2f04a0eeaf..b85b05277d 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/dci_tools_ue.c @@ -4255,7 +4255,7 @@ int generate_ue_ulsch_params_from_dci(void *dci_pdu, LOG_D(PHY,"Format 0 DCI :ulsch (ue): cshift %d\n",ulsch->harq_processes[harq_pid]->n_DMRS2); LOG_D(PHY,"Format 0 DCI :ulsch (ue): phich status %d\n",ulsch->harq_processes[harq_pid]->status); #else - UNUSED_VARIABLE(dai); + UNUSED(dai); #endif return(0); } else { @@ -4889,7 +4889,7 @@ int generate_eNB_ulsch_params_from_dci(PHY_VARS_eNB *eNB, printf("ulsch (eNB): Nsymb_pusch %d\n",ulsch->harq_processes[harq_pid]->Nsymb_pusch); printf("ulsch (eNB): cshift %d\n",ulsch->harq_processes[harq_pid]->n_DMRS2); #else - UNUSED_VARIABLE(dai); + UNUSED(dai); #endif return(0); } else { diff --git a/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c b/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c index 62268ef930..b5abfdea92 100644 --- a/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c +++ b/openair1/PHY/LTE_UE_TRANSPORT/prach_ue.c @@ -10,7 +10,7 @@ #include "executables/lte-softmodem.h" #include "PHY/phy_extern_ue.h" //#include "prach.h" -#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/if4_tools.h" #include "SCHED_UE/sched_UE.h" #include "SCHED/sched_common_extern.h" diff --git a/openair1/PHY/MODULATION/beamforming.c b/openair1/PHY/MODULATION/beamforming.c index 56def37b41..f65a1bac48 100644 --- a/openair1/PHY/MODULATION/beamforming.c +++ b/openair1/PHY/MODULATION/beamforming.c @@ -9,7 +9,6 @@ #include "PHY/CODING/lte_interleaver_inline.h" #include "PHY/LTE_TRANSPORT/transport_eNB.h" #include "modulation_eNB.h" -#include "nr_modulation.h" #include "common/utils/LOG/vcd_signal_dumper.h" int beam_precoding(int32_t **txdataF, @@ -80,25 +79,3 @@ int beam_precoding_one_eNB(int32_t **txdataF, } return 0; } - - -void nr_beam_precoding(c16_t **txdataF, - c16_t **txdataF_BF, - NR_DL_FRAME_PARMS *frame_parms, - int32_t ***beam_weights, - int symbol, - int aa, - int nb_antenna_ports, - int offset) -{ - // clear txdata_BF[aa][re] for each call of ue_spec_beamforming - memset(&txdataF_BF[aa][symbol*frame_parms->ofdm_symbol_size], 0, sizeof(c16_t) *(frame_parms->ofdm_symbol_size)); - - for (int p = 0; p < nb_antenna_ports; p++) { - multadd_cpx_vector((c16_t *)&txdataF[p][(symbol * frame_parms->ofdm_symbol_size) + offset], - (c16_t *)beam_weights[p][aa], - (c16_t *)&txdataF_BF[aa][symbol * frame_parms->ofdm_symbol_size], - frame_parms->ofdm_symbol_size, - 15); - } -} diff --git a/openair1/PHY/MODULATION/nr_beamforming.c b/openair1/PHY/MODULATION/nr_beamforming.c new file mode 100644 index 0000000000..a10b95d6d2 --- /dev/null +++ b/openair1/PHY/MODULATION/nr_beamforming.c @@ -0,0 +1,27 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +#include "nr_modulation.h" +#include "openair1/PHY/TOOLS/tools_defs.h" + +void nr_beam_precoding(c16_t **txdataF, + c16_t **txdataF_BF, + NR_DL_FRAME_PARMS *frame_parms, + int32_t ***beam_weights, + int symbol, + int aa, + int nb_antenna_ports, + int offset) +{ + // clear txdata_BF[aa][re] for each call of ue_spec_beamforming + memset(&txdataF_BF[aa][symbol*frame_parms->ofdm_symbol_size], 0, sizeof(c16_t) *(frame_parms->ofdm_symbol_size)); + + for (int p = 0; p < nb_antenna_ports; p++) { + multadd_cpx_vector((c16_t *)&txdataF[p][(symbol * frame_parms->ofdm_symbol_size) + offset], + (c16_t *)beam_weights[p][aa], + (c16_t *)&txdataF_BF[aa][symbol * frame_parms->ofdm_symbol_size], + frame_parms->ofdm_symbol_size, + 15); + } +} diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index e3afd9b93f..8a1349b648 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -3,6 +3,7 @@ */ #include "nr_modulation.h" +#include "openair1/PHY/TOOLS/tools_defs.h" #include "PHY/NR_REFSIG/nr_mod_table.h" #include "executables/softmodem-common.h" #include @@ -688,12 +689,12 @@ c16_t nr_layer_precoder_cm(int n_layers, int symSz, c16_t datatx_F_precoding[n_layers][symSz], int ap, - nfapi_nr_pm_pdu_t *pmi_pdu, + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS], int offset) { c16_t precodatatx_F = {0}; for (int al = 0; al < n_layers; al++) { - c16_t prec_weight = pmi_pdu->weights[al][ap]; + c16_t prec_weight = weights[al][ap]; precodatatx_F = c16maddShift(datatx_F_precoding[al][offset], prec_weight, precodatatx_F, 15); } return precodatatx_F; @@ -803,15 +804,15 @@ static inline __attribute__((always_inline)) __m128i cmac_prec128(__m128i y, __m #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 w_c##Rank = Instruct(c16toI32(c16conj(weights[Rank][ant]))); \ + const Type w_s##Rank = Instruct(c16toI32(c16swap(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], const int ant, - const nfapi_nr_pm_pdu_t *pmi_pdu, + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS], const int sc_offset, const int re_cnt, c16_t *txdataF_precoded) diff --git a/openair1/PHY/MODULATION/nr_modulation.h b/openair1/PHY/MODULATION/nr_modulation.h index ef834db509..769bf43da1 100644 --- a/openair1/PHY/MODULATION/nr_modulation.h +++ b/openair1/PHY/MODULATION/nr_modulation.h @@ -7,7 +7,6 @@ #include #include "PHY/defs_nr_common.h" -#include "PHY/defs_gNB.h" #define DMRS_MOD_ORDER 2 /*Precoding matices: W[pmi][antenna_port][layer]*/ @@ -127,7 +126,7 @@ c16_t nr_layer_precoder_cm(int n_layers, int symSz, c16_t datatx_F_precoding[n_layers][symSz], int ap, - nfapi_nr_pm_pdu_t *pmi_pdu, + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS], int offset); /*! \brief Precoding with SIMDe, txdataF_precoded[] = prec_matrix[] * txdataF_res_mapped[] @@ -140,7 +139,7 @@ void nr_layer_precoder_simd(const int n_layers, const int symSz, const c16_t txdataF_res_mapped[n_layers][symSz], const int ant, - const nfapi_nr_pm_pdu_t *pmi_pdu, + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS], const int sc_offset, const int re_cnt, c16_t *txdataF_precoded); diff --git a/openair1/PHY/MODULATION/tests/test_nr_modulation.cpp b/openair1/PHY/MODULATION/tests/test_nr_modulation.cpp index d232c442bf..7a66696384 100644 --- a/openair1/PHY/MODULATION/tests/test_nr_modulation.cpp +++ b/openair1/PHY/MODULATION/tests/test_nr_modulation.cpp @@ -15,7 +15,6 @@ 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] @@ -25,7 +24,7 @@ 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, + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS], int offset); // Forward declare the function but hide the Variable-Length Array (VLA) feature from C not available in C++ @@ -33,7 +32,7 @@ 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, + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS], int offset, int re_cnt, c16_t *dataF_out); @@ -65,15 +64,15 @@ TEST(NrLayerPrecoderTest, Basic) 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}; + // Create and populate the weights + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS]; for (int layer = 0; layer < n_layers; ++layer) { - pmi_pdu.weights[layer][ant] = (c16_t){-SHRT_MAX, 0}; + 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); + dataF_out[ant][symbol] = nr_layer_precoder_cm(n_layers, symbol_size, dataF_in, ant, weights, symbol); // You can calculate the expected value manually or test rough correctness for (int symbol = 0; symbol < re_cnt; symbol++) { @@ -110,14 +109,14 @@ TEST(NrLayerPrecoderTest, SIMD) 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}; + // Create and populate the weights + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS]; for (int layer = 0; layer < n_layers; ++layer) { - pmi_pdu.weights[layer][ant] = (c16_t){-SHRT_MAX, 0}; + 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]); + nr_layer_precoder_simd(n_layers, symbol_size, dataF_in, ant, weights, 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++) { @@ -156,15 +155,14 @@ TEST(NrLayerPrecoderTest, Compare_CM_SIMD) 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; + // Create and populate the weights + c16_t weights[NR_MAX_NB_LAYERS][NR_MAX_CSI_PORTS]; 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}; + weights[layer][0] = (c16_t){-SHRT_MAX, 0}; + weights[layer][1] = (c16_t){0, -SHRT_MAX}; } // Get the results for all the antenna @@ -172,10 +170,10 @@ TEST(NrLayerPrecoderTest, Compare_CM_SIMD) // 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); + dataF_out_cm[ant][symbol] = nr_layer_precoder_cm(n_layers, symbol_size, dataF_in, ant, weights, 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]); + nr_layer_precoder_simd(n_layers, symbol_size, dataF_in, ant, weights, 0, re_cnt, dataF_out_simd[ant]); // Compare the result from both C function for (int symbol = 0; symbol < re_cnt; symbol++) { diff --git a/openair1/PHY/NR_ESTIMATION/nr_freq_equalization.c b/openair1/PHY/NR_ESTIMATION/nr_freq_equalization.c index fd7530b0d9..75589c75f8 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_freq_equalization.c +++ b/openair1/PHY/NR_ESTIMATION/nr_freq_equalization.c @@ -2,7 +2,6 @@ * SPDX-License-Identifier: LicenseRef-CSSL-1.0 */ -#include "PHY/defs_eNB.h" #include "PHY/sse_intrin.h" #include "PHY/NR_ESTIMATION/nr_ul_estimation.h" diff --git a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c index a901f8dba1..1f8be0fa38 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c +++ b/openair1/PHY/NR_ESTIMATION/nr_measurements_gNB.c @@ -123,12 +123,12 @@ void dump_nr_I0_stats(FILE *fd, PHY_VARS_gNB *gNB) fprintf(fd, "\nPRACH I0 = %d.%d dB\n", gNB->measurements.prach_I0 / 10, gNB->measurements.prach_I0 % 10); } -void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_symb, uint32_t rb_mask_ul[14][9]) +void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_symb, uint32_t rb_mask_ul[14][MAX_BWP_SIZE]) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; NR_gNB_COMMON *common_vars = &gNB->common_vars; PHY_MEASUREMENTS_gNB *measurements = &gNB->measurements; - int nb_symb[275]={0}; + int nb_symb[MAX_BWP_SIZE] = {0}; unsigned int tmp_n0_subband[frame_parms->nb_antennas_rx][frame_parms->N_RB_UL]; memset(tmp_n0_subband, 0, sizeof(tmp_n0_subband)); @@ -137,7 +137,7 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy for (int s = first_symb; s < first_symb + num_symb; s++) { int offset0 = ((slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot + s) * frame_parms->ofdm_symbol_size; for (int rb = 0; rb < frame_parms->N_RB_UL; rb++) { - if ((rb_mask_ul[s][rb >> 5] & (1U << (rb & 31))) == 0 && // check that rb was not used in this subframe + if (rb_mask_ul[s][rb] == 0 && // check that rb was not used in this subframe !(I0_SKIP_DC && rb == frame_parms->N_RB_UL >> 1)) { // skip middle PRB because of artificial noise possibly created by FFT int offset = offset0 + (frame_parms->first_carrier_offset + (rb*12))%frame_parms->ofdm_symbol_size; nb_symb[rb]++; @@ -162,6 +162,7 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy int32_t n0_subband_tot_perANT[frame_parms->nb_antennas_rx]; memset(n0_subband_tot_perANT, 0, sizeof(n0_subband_tot_perANT)); + bool init_meas = measurements->n0_subband_power == NULL; allocCast2D(n0_subband_power, unsigned int, measurements->n0_subband_power, @@ -174,6 +175,9 @@ void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_sy if (nb_symb[rb] > 0) { for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { tmp_n0_subband[aarx][rb] /= nb_symb[rb]; + // Initialize n0_subband_power from the first measurement before EMA + if (init_meas) + n0_subband_power[aarx][rb] = tmp_n0_subband[aarx][rb]; // apply exponential moving average to smooth noise measurements n0_subband_power[aarx][rb] = 0.9 * n0_subband_power[aarx][rb] + 0.1 * tmp_n0_subband[aarx][rb]; n0_subband_tot_perPRB += n0_subband_power[aarx][rb]; diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 4d70db6f02..a5190997fa 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -34,7 +34,7 @@ typedef struct puschAntennaProc_s { int aarx; int beam_nb; int numAntennas; - nfapi_nr_pusch_pdu_t *pusch_pdu; + const nfapi_nr_pusch_pdu_t *pusch_pdu; int *max_ch; c16_t *pilot; int *nest_count; @@ -82,7 +82,7 @@ static void nr_pusch_antenna_processing(void *arg) int aarx = rdata->aarx; int numAntennas = rdata->numAntennas; unsigned short bwp_start_subcarrier = rdata->bwp_start_subcarrier; - nfapi_nr_pusch_pdu_t *pusch_pdu = rdata->pusch_pdu; + const nfapi_nr_pusch_pdu_t *pusch_pdu = rdata->pusch_pdu; int *max_ch = rdata->max_ch; c16_t *pilot = rdata->pilot; uint64_t noise_amp2 = *(rdata->noise_amp2); @@ -452,10 +452,10 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, int nl, unsigned short p, unsigned char symbol, - int ul_id, + NR_gNB_PUSCH *pusch_vars, int beam_nb, unsigned short bwp_start_subcarrier, - nfapi_nr_pusch_pdu_t *pusch_pdu, + const nfapi_nr_pusch_pdu_t *pusch_pdu, int *max_ch, uint32_t *nvar, c16_t *pusch_dmrs_slot_mem, @@ -534,7 +534,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, int nest_count = 0; uint64_t noise_amp2 = 0; - delay_t *delay = &gNB->ulsch[ul_id].delay; + delay_t *delay = &pusch_vars->delay; memset(delay, 0, sizeof(*delay)); int nb_antennas_rx = fp->nb_antennas_rx; @@ -579,7 +579,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, rdata->delay = &delay_arr[rdata->aarx]; rdata->beam_nb = beam_nb; rdata->frame_parms = fp; - rdata->pusch_vars = &gNB->pusch_vars[ul_id]; + rdata->pusch_vars = pusch_vars; rdata->chest_freq = gNB->chest_freq; rdata->rxdataF = gNB->common_vars.rxdataF; rdata->scope = gNB->scopeData; @@ -628,7 +628,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, * * PARAMETERS : gNB : gNB data structure * rel15_ul : UL parameters - * UE_id : UE ID + * pusch_vars : PUSCH data * nr_tti_rx : slot rx TTI * dmrs_symbol_flag: DMRS Symbol Flag * symbol : OFDM Symbol @@ -646,25 +646,22 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, // #define DEBUG_UL_PTRS void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, - nfapi_nr_pusch_pdu_t *rel15_ul, - uint8_t ulsch_id, + const nfapi_nr_pusch_pdu_t *rel15_ul, + NR_gNB_PUSCH *pusch_vars, uint8_t nr_tti_rx, unsigned char symbol, uint32_t nb_re_pusch) { - NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ulsch_id]; int32_t *ptrs_re_symbol = NULL; int8_t ret = 0; uint8_t symbInSlot = rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols; - uint8_t *startSymbIndex = &rel15_ul->start_symbol_index; - uint8_t *nbSymb = &rel15_ul->nr_of_symbols; - uint8_t *L_ptrs = &rel15_ul->pusch_ptrs.ptrs_time_density; - uint8_t *K_ptrs = &rel15_ul->pusch_ptrs.ptrs_freq_density; - uint16_t *dmrsSymbPos = &rel15_ul->ul_dmrs_symb_pos; - uint16_t *ptrsSymbPos = &pusch_vars->ptrs_symbols; - uint8_t *ptrsSymbIdx = &pusch_vars->ptrs_symbol_index; - uint16_t *nb_rb = &rel15_ul->rb_size; - uint8_t *ptrsReOffset = &rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset; + uint8_t startSymbIndex = rel15_ul->start_symbol_index; + uint8_t nbSymb = rel15_ul->nr_of_symbols; + uint8_t L_ptrs = rel15_ul->pusch_ptrs.ptrs_time_density; + uint8_t K_ptrs = rel15_ul->pusch_ptrs.ptrs_freq_density; + uint16_t dmrsSymbPos = rel15_ul->ul_dmrs_symb_pos; + uint16_t nb_rb = rel15_ul->rb_size; + uint8_t ptrsReOffset = rel15_ul->pusch_ptrs.ptrs_ports_list[0].ptrs_re_offset; /* loop over antennas */ for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { @@ -673,7 +670,7 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, *ptrs_re_symbol = 0; phase_per_symbol[symbol].i = 0; /* set DMRS estimates to 0 angle with magnitude 1 */ - if (is_dmrs_symbol(symbol, *dmrsSymbPos)) { + if (is_dmrs_symbol(symbol, dmrsSymbPos)) { /* set DMRS real estimation to 32767 */ phase_per_symbol[symbol].r = INT16_MAX; // 32767 #ifdef DEBUG_UL_PTRS @@ -683,17 +680,13 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, phase_per_symbol[symbol].r = 0; } - if (symbol == *startSymbIndex) { - *ptrsSymbPos = 0; - set_ptrs_symb_idx(ptrsSymbPos, *nbSymb, *startSymbIndex, 1 << *L_ptrs, *dmrsSymbPos); + if (symbol == startSymbIndex) { + pusch_vars->ptrs_symbols = 0; + set_ptrs_symb_idx(&pusch_vars->ptrs_symbols, nbSymb, startSymbIndex, 1 << L_ptrs, dmrsSymbPos); } - /* if not PTRS symbol set current ptrs symbol index to zero*/ - *ptrsSymbIdx = 0; - /* Check if current symbol contains PTRS */ - if (is_ptrs_symbol(symbol, *ptrsSymbPos)) { - *ptrsSymbIdx = symbol; + if (is_ptrs_symbol(symbol, pusch_vars->ptrs_symbols)) { /*------------------------------------------------------------------------------------------------------- */ /* 1) Estimate common phase error per PTRS symbol */ /*------------------------------------------------------------------------------------------------------- */ @@ -703,9 +696,9 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, rel15_ul->scid, nr_tti_rx, symbol); - nr_ptrs_cpe_estimation(*K_ptrs, - *ptrsReOffset, - *nb_rb, + nr_ptrs_cpe_estimation(K_ptrs, + ptrsReOffset, + nb_rb, rel15_ul->rnti, frame_parms->ofdm_symbol_size, &pusch_vars->rxdataF_comp[aarx][(symbol * nb_re_pusch)], @@ -720,8 +713,8 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, /* 2) Interpolate PTRS estimated value in TD */ /*------------------------------------------------------------------------------------------------------- */ /* If L-PTRS is > 0 then we need interpolation */ - if (*L_ptrs > 0) { - ret = nr_ptrs_process_slot(*dmrsSymbPos, *ptrsSymbPos, (int16_t *)phase_per_symbol, *startSymbIndex, *nbSymb); + if (L_ptrs > 0) { + ret = nr_ptrs_process_slot(dmrsSymbPos, pusch_vars->ptrs_symbols, (int16_t *)phase_per_symbol, startSymbIndex, nbSymb); if (ret != 0) { LOG_W(PHY, "[PTRS] Compensation is skipped due to error in PTRS slot processing !!\n"); } @@ -730,17 +723,17 @@ void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, /*------------------------------------------------------------------------------------------------------- */ /* 3) Compensated DMRS based estimated signal with PTRS estimation */ /*--------------------------------------------------------------------------------------------------------*/ - for (uint8_t i = *startSymbIndex; i < symbInSlot; i++) { + for (uint8_t i = startSymbIndex; i < symbInSlot; i++) { /* DMRS Symbol has 0 phase so no need to rotate the respective symbol */ /* Skip rotation if the slot processing is wrong */ - if ((!is_dmrs_symbol(i, *dmrsSymbPos)) && (ret == 0)) { + if ((!is_dmrs_symbol(i, dmrsSymbPos)) && (ret == 0)) { #ifdef DEBUG_UL_PTRS printf("[PHY][UL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r, phase_per_symbol[i].i); #endif rotate_cpx_vector(&pusch_vars->rxdataF_comp[aarx][i * nb_re_pusch], &phase_per_symbol[i], &pusch_vars->rxdataF_comp[aarx][i * nb_re_pusch], - ((*nb_rb) * NR_NB_SC_PER_RB), + (nb_rb * NR_NB_SC_PER_RB), 15); } // if not DMRS Symbol } // symbol loop diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h index 540a04ec52..34bf64cc51 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_estimation.h @@ -17,7 +17,7 @@ \param Ns slot number (0..19) \param p \param symbol symbol within slot -\param ul_id +\param pusch_vars lower-phy PUSCH info \param bwp_start_subcarrier first allocated subcarrier \param pusch_pdu \param max_ch maximum value of estimated channel @@ -29,10 +29,10 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, int nl, unsigned short p, unsigned char symbol, - int ul_id, + NR_gNB_PUSCH *pusch_vars, int beam_nb, unsigned short bwp_start_subcarrier, - nfapi_nr_pusch_pdu_t *pusch_pdu, + const nfapi_nr_pusch_pdu_t *pusch_pdu, int *max_ch, uint32_t *nvar, c16_t *pusch_dmrs_slot_mem, @@ -40,7 +40,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, void dump_nr_I0_stats(FILE *fd,PHY_VARS_gNB *gNB); -void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_symb, uint32_t rb_mask_ul[14][9]); +void gNB_I0_measurements(PHY_VARS_gNB *gNB, int slot, int first_symb, int num_symb, uint32_t rb_mask_ul[14][MAX_BWP_SIZE]); void nr_est_srs_timing_advance_offset(uint16_t ofdm_symbol_size, const c16_t srs_estimated_channel_time[][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], @@ -52,8 +52,8 @@ void nr_est_srs_timing_advance_offset(uint16_t ofdm_symbol_size, void nr_pusch_ptrs_processing(PHY_VARS_gNB *gNB, NR_DL_FRAME_PARMS *frame_parms, - nfapi_nr_pusch_pdu_t *rel15_ul, - uint8_t ulsch_id, + const nfapi_nr_pusch_pdu_t *rel15_ul, + NR_gNB_PUSCH *pusch_vars, uint8_t nr_tti_rx, unsigned char symbol, uint32_t nb_re_pusch); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index d227148353..8f1bb827be 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -438,7 +438,7 @@ static inline void do_txdataF(c16_t **txdataF, symbol_sz, txdataF_precoding, ant, - pmi_pdu, + pmi_pdu->weights, subCarrier, re_cnt, &txdataF[ant][txdataF_offset_per_symbol]); diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index c54c9ccc29..dc3cb1950d 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -12,72 +12,73 @@ #include "PHY/NR_TRANSPORT/nr_transport_common_proto.h" #include "openair1/PHY/NR_TRANSPORT/nr_prach.h" -void init_prach_list(prach_list_t *l) +void init_nr_prach(PHY_VARS_gNB *gNB) { - pthread_mutex_init(&l->prach_list_mutex, NULL); - memset(l->list, 0, sizeof(l->list)); + int num_prach = 8; + gNB->prach_ru_queue = spsc_q_alloc(num_prach, sizeof(prach_item_t)); + gNB->prach_l1rx_queue = spsc_q_alloc(num_prach, sizeof(prach_item_t)); } -void free_nr_prach_entry(prach_list_t *l, prach_item_t *p) +void reset_nr_prach(PHY_VARS_gNB *gNB) { - pthread_mutex_lock(&l->prach_list_mutex); - if (p->frame == -1) - LOG_E(NR_PHY_RACH, "Freeing a not allocated prach entry\n"); - *p = (prach_item_t){.frame = -1, .slot = -1, .num_slots = -1, .nb_rx = p->nb_rx, .prach_buf = (void *)(p + 1)}; - pthread_mutex_unlock(&l->prach_list_mutex); + spsc_q_free(&gNB->prach_ru_queue); + spsc_q_free(&gNB->prach_l1rx_queue); } -prach_item_t *find_nr_prach(prach_list_t *l, int frame, int slot, int nb_rx, nr_find_type_t type) +void free_nr_prach_entry(prach_item_t *p) { - pthread_mutex_lock(&l->prach_list_mutex); - AssertFatal(nb_rx, "Error! Number of antennas set to 0.\n"); - prach_item_t **p = l->list; - prach_item_t **end = p + NUMBER_OF_NR_PRACH_MAX; - for (; p < end; p++) - if ((*p) && (*p)->frame == frame && ((*p)->slot + (*p)->num_slots - 1) == slot) - break; - if (p == end) { - if (type == NR_SEARCH_EXIST) { - pthread_mutex_unlock(&l->prach_list_mutex); - return NULL; - } - for (p = l->list; p < end; p++) - if (!(*p) || ((*p)->frame == -1 && (*p)->slot == -1)) - break; - } - if (p == end) { - pthread_mutex_unlock(&l->prach_list_mutex); - return NULL; - } - // mark it used, it will be filled later - if (*p && (*p)->nb_rx != nb_rx) { - LOG_W(PHY, "rach procedure nb_rx ant changed from %d to %d\n", (*p)->nb_rx, nb_rx); - free(*p); - *p = NULL; - } - if (!(*p)) { - *p = calloc(1, sizeof(prach_item_t) + sizeof(c16_t) * nb_rx * NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX * NR_PRACH_SEQ_LEN_L); - (*p)->prach_buf = (void *)((*p) + 1); - } - (*p)->nb_rx = nb_rx; - (*p)->frame = frame; - pthread_mutex_unlock(&l->prach_list_mutex); - return (*p); + free(p->prach_buf); } -prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +static bool drop_old_prach(const void *data, void *user) +{ + const prach_item_t *p = data; + const fsn_t *now = user; + const fsn_t t = {p->frame, p->slot, now->mu}; + bool drop = fsn_in_the_past(t, *now); + if (drop) + LOG_E(NR_PHY, "%4d.%2d PRACH job is in the past (%4d.%2d)\n", now->f, now->s, t.f, t.s); + return drop; +} + +static bool get_current_prach(const void *data, void *user) +{ + const prach_item_t *p = data; + const fsn_t *now = user; + const fsn_t t = {p->frame, p->slot, now->mu}; + return fsn_equal(t, *now); +} + +bool get_next_nr_prach(spsc_q_t *q, const fsn_t *now, prach_item_t *p) +{ + spsc_q_drop_while(q, drop_old_prach, (void *)now); + return spsc_q_get_if(q, get_current_prach, (void *)now, p, sizeof(*p)); +} + +void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { - prach_item_t *prach = find_nr_prach(&gNB->prach_list, SFN, Slot, gNB->frame_parms.nb_antennas_rx, NR_SEARCH_EXIST_OR_FREE); - if (!prach) { - LOG_W(PHY, "no free space for a new detected rach, discarding\n"); - return NULL; - } const int fmt = prach_pdu->prach_format; - NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; - // we set only elements as the whole structure has been cleaned when we release it - prach->frame = SFN; - prach->slot = Slot; - prach->num_slots = fmt < 4 ? get_long_prach_dur(fmt, fp->numerology_index) : 1; + const NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + const nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config; + const nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra]; + prach_item_t prach = { + .frame = SFN, + .slot = Slot, + .num_slots = fmt < 4 ? get_long_prach_dur(fmt, fp->numerology_index) : 1, + .pdu = *prach_pdu, + .rootSequenceIndex = occ->prach_root_sequence_index.value, + .numrootSequenceIndex = occ->num_root_sequences.value, + .msg1_frequencystart = occ->k1.value, + .mu = cfg->prach_sub_c_spacing.value, + .prach_sequence_length = cfg->prach_sequence_length.value, + .restricted_set = cfg->restricted_set_config.value, + .numerology_index = fp->numerology_index, + .nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value, + .Xu = gNB->X_u, + .rx_prach = &gNB->rx_prach, + // TODO can be made permanently allocated? + .prach_buf = calloc_or_fail(1, sizeof(c16_t) * prach.nb_rx * NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX * NR_PRACH_SEQ_LEN_L), + }; if (gNB->common_vars.beam_id) { int n_symb = get_nr_prach_duration(prach_pdu->prach_format); AssertFatal(prach_pdu->beamforming.dig_bf_interface < NFAPI_MAX_NUM_BG_IF, @@ -87,7 +88,7 @@ prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_n int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx; int start_symb = prach_pdu->prach_start_symbol + i * n_symb; int bitmap = SL_to_bitmap(start_symb, n_symb); - prach->beams[i] = beam_index_allocation(gNB->enable_analog_das, + prach.beams[i] = beam_index_allocation(gNB->enable_analog_das, fapi_beam_idx, &gNB->common_vars, Slot, @@ -95,20 +96,9 @@ prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_n bitmap); } } - prach->pdu = *prach_pdu; - nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config; - nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra]; - prach->rootSequenceIndex = occ->prach_root_sequence_index.value; - prach->numrootSequenceIndex = occ->num_root_sequences.value; - prach->msg1_frequencystart = occ->k1.value; - prach->mu = cfg->prach_sub_c_spacing.value; - prach->prach_sequence_length = cfg->prach_sequence_length.value; - prach->restricted_set = cfg->restricted_set_config.value; - prach->numerology_index = fp->numerology_index; - prach->nb_rx = gNB->gNB_config.carrier_config.num_rx_ant.value; - prach->Xu = gNB->X_u; - prach->rx_prach = &gNB->rx_prach; - return prach; + bool found = spsc_q_put(&gNB->prach_ru_queue, &prach, sizeof(prach)); + if (!found) + LOG_W(NR_PHY, "%4d.%2d PRACH occ queue is full: dropping PRACH request\n", SFN, Slot); } static void rx_nr_prach_ru_internal(prach_item_t *p, diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index f7497a148a..863903c242 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -11,6 +11,7 @@ #include "PHY/defs_nr_common.h" #include "PHY/defs_gNB.h" +#include "common/utils/fsn.h" #define NR_PBCH_PDU_BITS 24 @@ -85,11 +86,19 @@ void free_gNB_dlsch(NR_gNB_DLSCH_t *dlsch, uint16_t N_RB, const NR_DL_FRAME_PARM - LLR computation This function supports TM1, 2, 3, 5, and 6. @param ue Pointer to PHY variables - @param UE_id id of current UE + @param pusch_vars ULSCH PUSCH data + @param rel15_ul FAPI message to process + @param unav_res unav_res result @param frame Frame number @param slot Slot number */ -int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, uint8_t ulsch_id, uint32_t frame, uint8_t slot, int beam_nb); +int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, + NR_gNB_PUSCH *pusch_vars, + const nfapi_nr_pusch_pdu_t *rel15_ul, + uint32_t *ret_unav_res, + uint32_t frame, + uint8_t slot, + int beam_nb); /*! \brief This function implements the idft transform precoding in PUSCH @@ -159,7 +168,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu); -prach_item_t *nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); +void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); typedef struct rx_prach_out { uint16_t max_preamble; @@ -170,12 +179,6 @@ rx_prach_out_t rx_nr_prach(const prach_item_t *, int occasion); void rx_nr_prach_ru(prach_item_t *, int32_t **, NR_DL_FRAME_PARMS *frame_parms, int N_TA_offset); -typedef enum { - NR_SEARCH_EXIST = 0, - NR_SEARCH_EXIST_OR_FREE -} nr_find_type_t; - -prach_item_t *find_nr_prach(prach_list_t *, int frame, int slot, int nb_rx, nr_find_type_t type); void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, @@ -189,30 +192,32 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, int nr_get_srs_signal(PHY_VARS_gNB *gNB, c16_t **rxdataF, slot_t slot, - nfapi_nr_srs_pdu_t *srs_pdu, + const 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_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_symbols)]); -void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, +nr_srs_info_t nr_srs_rx_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, uint8_t nb_antennas_rx, uint8_t N_ap, uint8_t N_symb_SRS, uint16_t ofdm_symbol_size, - NR_gNB_SRS_t *srs, - nr_srs_info_t *nr_srs_info, + const NR_gNB_SRS_job_t *srs, int *srs_est, + int8_t *snr, c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], - c16_t srs_estimated_channel_time[][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], int16_t *snr_per_rb, uint16_t *timing_advance_offset, int16_t *timing_advance_offset_nsec); int get_nr_prach_duration(uint8_t prach_format); -void free_nr_prach_entry(prach_list_t *, prach_item_t *); +void init_nr_prach(PHY_VARS_gNB *gNB); +void reset_nr_prach(PHY_VARS_gNB *gNB); +void free_nr_prach_entry(prach_item_t *); +bool get_next_nr_prach(spsc_q_t *q, const fsn_t *now, prach_item_t *p); void nr_decode_pucch1(PHY_VARS_gNB *gNB, c16_t **rxdataF, @@ -227,14 +232,14 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_uci_pucch_pdu_format_2_3_4_t* uci_pdu, - nfapi_nr_pucch_pdu_t* pucch_pdu); + const nfapi_nr_pucch_pdu_t* pucch_pdu); void nr_decode_pucch0(PHY_VARS_gNB *gNB, c16_t **rxdataF, int frame, int slot, nfapi_nr_uci_pucch_pdu_format_0_1_t* uci_pdu, - nfapi_nr_pucch_pdu_t* pucch_pdu); + const nfapi_nr_pucch_pdu_t* pucch_pdu); #endif /*__NR_TRANSPORT__H__*/ diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 2d7727b55a..51d885cc1e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -11,30 +11,6 @@ #include "PHY/NR_TRANSPORT/nr_ulsch.h" #include "SCHED_NR/sched_nr.h" -static NR_gNB_ULSCH_t *find_nr_ulsch(PHY_VARS_gNB *gNB, uint16_t rnti, int pid) -{ - int16_t first_free_index = -1; - AssertFatal(gNB != NULL, "gNB is null\n"); - NR_gNB_ULSCH_t *ulsch = NULL; - - for (int i = 0; i < gNB->max_nb_pusch; i++) { - ulsch = &gNB->ulsch[i]; - AssertFatal(ulsch, "gNB->ulsch[%d] is null\n", i); - if (!ulsch->active) { - if (first_free_index == -1) - first_free_index = i; - } else { - // if there is already an active ULSCH for this RNTI and HARQ_PID - if ((ulsch->harq_pid == pid) && (ulsch->rnti == rnti)) - return ulsch; - } - } - if (first_free_index != -1) - ulsch = &gNB->ulsch[first_free_index]; - - return ulsch; -} - static void dump_pusch_pdu(int instance, int frame, int slot, nfapi_nr_pusch_pdu_t *pusch_pdu) { LOG_D(PHY, @@ -117,49 +93,28 @@ static void dump_pusch_pdu(int instance, int frame, int slot, nfapi_nr_pusch_pdu void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu) { dump_pusch_pdu(gNB->Mod_id, frame, slot, ulsch_pdu); - int harq_pid = ulsch_pdu->pusch_data.harq_process_id; - NR_gNB_ULSCH_t *ulsch = find_nr_ulsch(gNB, ulsch_pdu->rnti, harq_pid); - if (ulsch == NULL) { - LOG_E(NR_PHY, "No ulsch_id found for rnti %04x\n", ulsch_pdu->rnti); - return; - } + LOG_D(NR_PHY, + "%4d.%2d Programming ULSCH RNTI %04x HARQ PID %d new data indicator %d\n", + frame, + slot, + ulsch_pdu->rnti, + ulsch_pdu->pusch_data.harq_process_id, + ulsch_pdu->pusch_data.new_data_indicator); - ulsch->rnti = ulsch_pdu->rnti; - ulsch->harq_pid = harq_pid; - ulsch->handled = 0; - ulsch->active = true; - ulsch->beam_nb = 0; + NR_gNB_PUSCH_job_t pusch = {.frame = frame, .slot = slot, .pusch_pdu = *ulsch_pdu}; if (gNB->common_vars.beam_id) { int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols); - ulsch->beam_nb = beam_index_allocation(gNB->enable_analog_das, + pusch.beam_nb = beam_index_allocation(gNB->enable_analog_das, fapi_beam_idx, &gNB->common_vars, slot, gNB->frame_parms.symbols_per_slot, bitmap); } - ulsch->frame = frame; - ulsch->slot = slot; - - NR_UL_gNB_HARQ_t *harq = ulsch->harq_process; - if (ulsch_pdu->pusch_data.new_data_indicator) - harq->harq_to_be_cleared = true; - LOG_D(NR_PHY, - "NEW ULSCH %d.%d RNTI %x HARQ PID %d new data indicator %d\n", - frame, - slot, - ulsch_pdu->rnti, - harq_pid, - ulsch_pdu->pusch_data.new_data_indicator); - - if (ulsch_pdu->pusch_data.new_data_indicator) - harq->round = 0; - else - harq->round++; - - memcpy(&ulsch->harq_process->ulsch_pdu, ulsch_pdu, sizeof(ulsch->harq_process->ulsch_pdu)); - LOG_D(PHY, "Initializing nFAPI for ULSCH, harq_pid %d, layers %d\n", harq_pid, ulsch_pdu->nrOfLayers); + bool done = spsc_q_put(&gNB->pusch_queue, &pusch, sizeof(pusch)); + if (!done) + LOG_W(NR_PHY, "PUSCH queue is full: dropping PUSCH UE %04x\n", ulsch_pdu->rnti); } void reset_active_ulsch(PHY_VARS_gNB *gNB, int frame) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h index b1e932f60d..816ce9a16a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.h +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.h @@ -23,7 +23,6 @@ NR_gNB_ULSCH_t new_gNB_ulsch(uint8_t max_ldpc_iterations, uint16_t N_RB_UL); @param frame_parms, Pointer to frame descriptor structure @param frame, current received frame @param nr_tti_rx, current received TTI - @param G @param ULSCH_ids, array of ULSCH ids @param nb_pusch, number of uplink shared channels */ @@ -32,8 +31,7 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, NR_DL_FRAME_PARMS *frame_parms, uint32_t frame, uint8_t nr_tti_rx, - uint32_t *G, - uint8_t *ULSCH_ids, + int *ULSCH_ids, int nb_pusch); /*! \brief Perform PUSCH unscrambling. TS 38.211 V15.4.0 subclause 6.3.1.1 diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c index 29a53ec5a0..9cb6e22c03 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_decoding.c @@ -93,8 +93,7 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, NR_DL_FRAME_PARMS *frame_parms, uint32_t frame, uint8_t nr_tti_rx, - uint32_t *G, - uint8_t *ULSCH_ids, + int *ULSCH_ids, int nb_pusch) { nrLDPC_TB_decoding_parameters_t TBs[nb_pusch]; @@ -112,17 +111,29 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, NR_gNB_ULSCH_t *ulsch = &phy_vars_gNB->ulsch[ULSCH_id]; NR_gNB_PUSCH *pusch = &phy_vars_gNB->pusch_vars[ULSCH_id]; NR_UL_gNB_HARQ_t *harq_process = ulsch->harq_process; - nfapi_nr_pusch_pdu_t *pusch_pdu = &harq_process->ulsch_pdu; + const nfapi_nr_pusch_pdu_t *pusch_pdu = &harq_process->ulsch_pdu; nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pusch_id]; - TB_parameters->G = G[pusch_id]; - if (!harq_process) { LOG_E(PHY, "ulsch_decoding.c: NULL harq_process pointer\n"); return -1; } + uint8_t number_dmrs_symbols = count_bits64_with_mask(pusch_pdu->ul_dmrs_symb_pos, pusch_pdu->start_symbol_index, pusch_pdu->nr_of_symbols); + int factor = pusch_pdu->dmrs_config_type == pusch_dmrs_type1 ? 6 : 4; + int nb_re_dmrs = factor * pusch_pdu->num_dmrs_cdm_grps_no_data; + uint32_t G = nr_get_G(pusch_pdu->rb_size, + pusch_pdu->nr_of_symbols, + nb_re_dmrs, + number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs + ulsch->unav_res, + pusch_pdu->qam_mod_order, + pusch_pdu->nrOfLayers); + DevAssert(G > 0); + TB_parameters->G = G; + + // The harq_pid is not unique among the active HARQ processes in the instance so we use ULSCH_id instead TB_parameters->harq_unique_pid = ULSCH_id; @@ -134,10 +145,9 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, // ------------------------------------------------------------------ TB_parameters->processedSegments = &harq_process->processedSegments; - harq_process->TBS = pusch_pdu->pusch_data.tb_size; TB_parameters->BG = pusch_pdu->maintenance_parms_v3.ldpcBaseGraph; - TB_parameters->A = (harq_process->TBS) << 3; + TB_parameters->A = pusch_pdu->pusch_data.tb_size << 3; NR_gNB_PHY_STATS_t *stats = get_phy_stats(phy_vars_gNB, ulsch->rnti); if (stats) { stats->frame = frame; @@ -149,7 +159,7 @@ int nr_ulsch_decoding(PHY_VARS_gNB *phy_vars_gNB, if (!harq_process->harq_to_be_cleared) { stats->ulsch_stats.current_Qm = TB_parameters->Qm; stats->ulsch_stats.current_RI = TB_parameters->nb_layers; - stats->ulsch_stats.total_bytes_tx += harq_process->TBS; + stats->ulsch_stats.total_bytes_tx += pusch_pdu->pusch_data.tb_size; } } diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 82d6b0d99d..684e65699e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -80,7 +80,7 @@ static void nr_ulsch_extract_rbs(c16_t* const rxdataF, int rxoffset, int choffset, int is_dmrs_symbol, - nfapi_nr_pusch_pdu_t *pusch_pdu, + const nfapi_nr_pusch_pdu_t *pusch_pdu, NR_DL_FRAME_PARMS *frame_parms) { uint8_t delta = 0; @@ -160,7 +160,7 @@ static void nr_ulsch_extract_rbs(c16_t* const rxdataF, } } -static int get_nb_re_pusch (NR_DL_FRAME_PARMS *frame_parms, nfapi_nr_pusch_pdu_t *rel15_ul,int symbol) +static int get_nb_re_pusch (NR_DL_FRAME_PARMS *frame_parms, const nfapi_nr_pusch_pdu_t *rel15_ul, int symbol) { uint8_t dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; if (dmrs_symbol_flag == 1) { @@ -186,7 +186,7 @@ static void nr_ulsch_channel_compensation(uint32_t buffer_length, c16_t **rxComp, int nb_layers, c16_t rho[][nb_layers][buffer_length], - nfapi_nr_pusch_pdu_t *rel15_ul, + const nfapi_nr_pusch_pdu_t *rel15_ul, uint32_t symbol, uint32_t output_shift) { @@ -857,11 +857,10 @@ static uint8_t nr_ulsch_mmse_2layers(c16_t **rxdataF_comp, } static void inner_rx(PHY_VARS_gNB *gNB, - int ulsch_id, int slot, NR_DL_FRAME_PARMS *frame_parms, NR_gNB_PUSCH *pusch_vars, - nfapi_nr_pusch_pdu_t *rel15_ul, + const nfapi_nr_pusch_pdu_t *rel15_ul, c16_t **rxF, int16_t **llr, int soffset, @@ -952,7 +951,7 @@ static void inner_rx(PHY_VARS_gNB *gNB, nr_pusch_ptrs_processing(gNB, frame_parms, rel15_ul, - ulsch_id, + pusch_vars, slot, symbol, buffer_length); @@ -1003,8 +1002,8 @@ static void inner_rx(PHY_VARS_gNB *gNB, typedef struct puschSymbolProc_s { PHY_VARS_gNB *gNB; NR_DL_FRAME_PARMS *frame_parms; - nfapi_nr_pusch_pdu_t *rel15_ul; - int ulsch_id; + const nfapi_nr_pusch_pdu_t *rel15_ul; + NR_gNB_PUSCH *pusch_vars; int slot; int startSymbol; int numSymbols; @@ -1023,12 +1022,11 @@ static void nr_pusch_symbol_processing(void *arg) PHY_VARS_gNB *gNB = rdata->gNB; NR_DL_FRAME_PARMS *frame_parms = rdata->frame_parms; - nfapi_nr_pusch_pdu_t *rel15_ul = rdata->rel15_ul; - int ulsch_id = rdata->ulsch_id; + const nfapi_nr_pusch_pdu_t *rel15_ul = rdata->rel15_ul; int slot = rdata->slot; - NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ulsch_id]; + NR_gNB_PUSCH *pusch_vars = rdata->pusch_vars; for (int symbol = rdata->startSymbol; symbol < rdata->startSymbol + rdata->numSymbols; symbol++) { - if (gNB->pusch_vars[ulsch_id].ul_valid_re_per_slot[symbol] == 0) + if (pusch_vars->ul_valid_re_per_slot[symbol] == 0) continue; int soffset = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; int buffer_length = ceil_mod(pusch_vars->ul_valid_re_per_slot[symbol] * NR_NB_SC_PER_RB, 16); @@ -1038,7 +1036,6 @@ static void nr_pusch_symbol_processing(void *arg) llrss[l] = llrs[l]; inner_rx(gNB, - ulsch_id, slot, frame_parms, pusch_vars, @@ -1047,12 +1044,12 @@ static void nr_pusch_symbol_processing(void *arg) llrss, soffset, symbol, - gNB->pusch_vars[ulsch_id].log2_maxh, + pusch_vars->log2_maxh, 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]; + int nb_re_pusch = pusch_vars->ul_valid_re_per_slot[symbol]; // layer de-mapping int16_t *llr_ptr = llrs[0]; if (rel15_ul->nrOfLayers != 1) { @@ -1098,12 +1095,16 @@ static uint32_t average_u32(const uint32_t *x, uint16_t size) return (uint32_t)(sum_x / size); } -int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, uint8_t ulsch_id, uint32_t frame, uint8_t slot, int beam_nb) +int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, + NR_gNB_PUSCH *pusch_vars, + const nfapi_nr_pusch_pdu_t *rel15_ul, + uint32_t *ret_unav_res, + uint32_t frame, + uint8_t slot, + int beam_nb) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - nfapi_nr_pusch_pdu_t *rel15_ul = &gNB->ulsch[ulsch_id].harq_process->ulsch_pdu; - NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ulsch_id]; uint32_t bwp_start_subcarrier = ((rel15_ul->rb_start + rel15_ul->bwp_start) * NR_NB_SC_PER_RB + frame_parms->first_carrier_offset) % frame_parms->ofdm_symbol_size; 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); @@ -1159,7 +1160,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, uint8_t ulsch_id, uint32_t frame, uint8_t nl, get_dmrs_port(nl, rel15_ul->dmrs_ports), symbol, - ulsch_id, + pusch_vars, beam_nb, bwp_start_subcarrier, rel15_ul, @@ -1261,7 +1262,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, uint8_t ulsch_id, uint32_t frame, uint8_t unav_res, rel15_ul->qam_mod_order, rel15_ul->nrOfLayers); - gNB->ulsch[ulsch_id].unav_res = unav_res; + *ret_unav_res = unav_res; // initialize scrambling sequence // int16_t scramblingSequence[G + 96] __attribute__((aligned(32))); @@ -1378,7 +1379,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, uint8_t ulsch_id, uint32_t frame, uint8_t rdata->startSymbol = symbol; // Last task processes remainder symbols rdata->numSymbols = task_index == loop_iter - 1 ? rel15_ul->nr_of_symbols - (loop_iter - 1) * numSymbols : numSymbols; - rdata->ulsch_id = ulsch_id; + rdata->pusch_vars = pusch_vars; rdata->llr = pusch_vars->llr; rdata->scramblingSequence = scramblingSequence; rdata->nvar = nvar; diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index 8017fb0bc9..fd6bd8ea42 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -33,40 +33,32 @@ //#define DEBUG_NR_PUCCH_RX 1 void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu) { - for (int i = 0; i < gNB->max_nb_pucch; i++) { - NR_gNB_PUCCH_t *pucch = &gNB->pucch[i]; - if (pucch->active == false) { - pucch->frame = frame; - pucch->slot = slot; - pucch->active = true; - pucch->beam_nb = 0; - if (gNB->common_vars.beam_id) { - int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); - pucch->beam_nb = beam_index_allocation(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->common_vars, - slot, - gNB->frame_parms.symbols_per_slot, - bitmap); - } - memcpy((void *)&pucch->pucch_pdu, (void *)pucch_pdu, sizeof(nfapi_nr_pucch_pdu_t)); - LOG_D(PHY, - "Programming PUCCH[%d] for %d.%d, format %d, nb_harq %d, nb_sr %d, nb_csi %d\n", - i, - pucch->frame, - pucch->slot, - pucch->pucch_pdu.format_type, - pucch->pucch_pdu.bit_len_harq, - pucch->pucch_pdu.sr_flag, - pucch->pucch_pdu.bit_len_csi_part1); - return; - } + LOG_D(PHY, + "%4d.%2d UE %04x Programming PUCCH format %d, nb_harq %d, nb_sr %d, nb_csi %d\n", + frame, + slot, + pucch_pdu->rnti, + pucch_pdu->format_type, + pucch_pdu->bit_len_harq, + pucch_pdu->sr_flag, + pucch_pdu->bit_len_csi_part1); + NR_gNB_PUCCH_job_t pucch = {.frame = frame, .slot = slot, .pucch_pdu = *pucch_pdu}; + if (gNB->common_vars.beam_id) { + int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; + int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); + pucch.beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, + &gNB->common_vars, + slot, + gNB->frame_parms.symbols_per_slot, + bitmap); } - LOG_W(PHY, "PUCCH list is full\n"); + bool found = spsc_q_put(&gNB->pucch_queue, &pucch, sizeof(pucch)); + if (!found) + LOG_W(NR_PHY, "PUCCH list is full: dropping PUCCH UE %04x\n", pucch_pdu->rnti); } -int get_pucch0_cs_lut_index(PHY_VARS_gNB *gNB, nfapi_nr_pucch_pdu_t *pucch_pdu) +int get_pucch0_cs_lut_index(PHY_VARS_gNB *gNB, const nfapi_nr_pucch_pdu_t *pucch_pdu) { int i = 0; @@ -129,7 +121,7 @@ void nr_decode_pucch0(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu, - nfapi_nr_pucch_pdu_t *pucch_pdu) + const nfapi_nr_pucch_pdu_t *pucch_pdu) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; int soffset = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; @@ -1132,7 +1124,7 @@ void nr_decode_pucch2(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu, - nfapi_nr_pucch_pdu_t *pucch_pdu) + const nfapi_nr_pucch_pdu_t *pucch_pdu) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; // pucch_GroupHopping_t pucch_GroupHopping = pucch_pdu->group_hop_flag + (pucch_pdu->sequence_hop_flag<<1); diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index fb6f5f648e..b0436cb2d7 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -29,37 +29,27 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu_t *srs_pdu) { - bool found = false; - for (int i = 0; i < gNB->max_nb_srs; i++) { - NR_gNB_SRS_t *srs = &gNB->srs[i]; - if (srs->active == false) { - found = true; - srs->frame = frame; - srs->slot = slot; - srs->active = true; - srs->beam_nb = 0; - if (gNB->common_vars.beam_id) { - const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position; - int bitmap = SL_to_bitmap(l0, 1 << srs_pdu->num_symbols); - int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - srs->beam_nb = beam_index_allocation(gNB->enable_analog_das, - fapi_beam_idx, - &gNB->common_vars, - slot, - gNB->frame_parms.symbols_per_slot, - bitmap); - } - memcpy((void *)&srs->srs_pdu, (void *)srs_pdu, sizeof(nfapi_nr_srs_pdu_t)); - break; - } + NR_gNB_SRS_job_t srs = {.frame = frame, .slot = slot, .srs_pdu = *srs_pdu}; + if (gNB->common_vars.beam_id) { + const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position; + int bitmap = SL_to_bitmap(l0, 1 << srs_pdu->num_symbols); + int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; + srs.beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, + &gNB->common_vars, + slot, + gNB->frame_parms.symbols_per_slot, + bitmap); } - AssertFatal(found, "SRS list is full\n"); + bool found = spsc_q_put(&gNB->srs_queue, &srs, sizeof(srs)); + if (!found) + LOG_W(NR_PHY, "SRS list is full: dropping SRS UE %04x\n", srs_pdu->rnti); } int nr_get_srs_signal(PHY_VARS_gNB *gNB, c16_t **rxdataF, slot_t slot, - nfapi_nr_srs_pdu_t *srs_pdu, + const 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_noise[][gNB->frame_parms.ofdm_symbol_size * (1 << srs_pdu->num_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 32d03c1010..7de87cc2ee 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -148,11 +148,11 @@ void nr_tx_rotation_and_ofdm_mod(const uint8_t slot, bool was_symbol_used[NR_SYMBOLS_PER_SLOT], bool no_phase_pre_comp); -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_SYMBOLS_PER_SLOT]); +void ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, + const UE_nr_rxtx_proc_t *proc, + c16_t **txdataF, + const fapi_nr_ul_config_srs_pdu *srs_config_pdu, + bool was_symbol_used[NR_SYMBOLS_PER_SLOT]); void clean_UE_harq(PHY_VARS_NR_UE *UE); diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index a6fb9d8890..3e627c38cd 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -19,6 +19,7 @@ #include "nfapi_nr_interface_scf.h" #include "common/utils/threadPool/task_ans.h" #include "openair1/PHY/defs_RU.h" +#include "common/utils/ds/spsc_q.h" #define MAX_NUM_RU_PER_gNB 8 #define MAX_PUCCH0_NID 8 @@ -45,14 +46,6 @@ typedef struct { c16_t (*prach_buf)[NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX][NR_PRACH_SEQ_LEN_L]; } prach_item_t; -typedef struct { - /// prach commands - prach_item_t *list[NUMBER_OF_NR_PRACH_MAX]; - /// mutex for prach_list access - pthread_mutex_t prach_list_mutex; -} prach_list_t; -void init_prach_list(prach_list_t *); - typedef struct { int nb_id; int Nid[MAX_PUCCH0_NID]; @@ -127,7 +120,7 @@ typedef struct { typedef struct { /// Nfapi ULSCH PDU - nfapi_nr_pusch_pdu_t ulsch_pdu; + nfapi_nr_pusch_pdu_t ulsch_pdu; // !! /// Index of current HARQ round for this DLSCH uint8_t round; bool new_rx; @@ -135,8 +128,6 @@ typedef struct { /// flag used to clear d properly (together with d_to_be_cleared below) /// set to true in nr_fill_ulsch() when new_data_indicator is received bool harq_to_be_cleared; - /// Transport block size (This is A from 38.212 V15.4.0 section 5.1) - uint32_t TBS; /// Pointer to the payload (38.212 V15.4.0 section 5.1) uint8_t *b; /// Pointers to code blocks after code block segmentation and CRC attachment (38.212 V15.4.0 section 5.2.2) @@ -184,13 +175,20 @@ typedef struct { int8_t last_iteration_cnt; /// Status Flag indicating for this ULSCH bool active; - /// Flag to indicate that the UL configuration has been handled. Used to remove a stale ULSCH when frame wraps around - uint8_t handled; - delay_t delay; } NR_gNB_ULSCH_t; typedef struct { - bool active; + // identifier for concurrent beams + int beam_nb; + /// Frame where current PUSCH pdu was sent + uint32_t frame; + /// Slot where current PUSCH pdu was sent + uint32_t slot; + /// ULSCH PDU + nfapi_nr_pusch_pdu_t pusch_pdu; +} NR_gNB_PUSCH_job_t; + +typedef struct { // identifier for concurrent beams int beam_nb; /// Frame where current PUCCH pdu was sent @@ -199,21 +197,18 @@ typedef struct { uint32_t slot; /// ULSCH PDU nfapi_nr_pucch_pdu_t pucch_pdu; -} NR_gNB_PUCCH_t; +} NR_gNB_PUCCH_job_t; typedef struct { - bool active; // identifier for concurrent beams int beam_nb; /// Frame where current SRS pdu was received uint32_t frame; /// Slot where current SRS pdu was received uint32_t slot; - /// Measured SNR - int8_t snr; /// ULSCH PDU nfapi_nr_srs_pdu_t srs_pdu; -} NR_gNB_SRS_t; +} NR_gNB_SRS_job_t; typedef struct { /// \brief Pointers (dynamic) to the received data in the frequency domain. @@ -275,6 +270,8 @@ typedef struct { int llr_offset[14]; /// flag to indicate DTX on reception int DTX; + /// delay estimation + delay_t delay; } NR_gNB_PUSCH; /// Context data structure for RX/TX portion of slot processing @@ -369,26 +366,23 @@ typedef struct PHY_VARS_gNB_s { nfapi_nr_ul_tti_request_t UL_tti_req; - int max_nb_pucch; - int max_nb_srs; int max_nb_pdsch; int max_nb_pusch; NR_gNB_COMMON common_vars; - prach_list_t prach_list; + spsc_q_t prach_ru_queue; + spsc_q_t prach_l1rx_queue; // TODO: can we remove c from NR_gNB_DLSCH_t and put it on the stack? NR_gNB_DLSCH_t *dlsch; NR_gNB_PRS prs_vars; NR_gNB_PUSCH *pusch_vars; - NR_gNB_PUCCH_t *pucch; - NR_gNB_SRS_t *srs; + spsc_q_t pucch_queue; + spsc_q_t pusch_queue; + spsc_q_t srs_queue; NR_gNB_ULSCH_t *ulsch; NR_gNB_PHY_STATS_t phy_stats[MAX_MOBILES_PER_GNB]; t_nrPolar_params **polarParams; - /// SRS variables - nr_srs_info_t **nr_srs_info; - // reference amplitude for TX int16_t TX_AMP; diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index 63771f7125..3f4c29bdaf 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -28,8 +28,8 @@ #include "common_lib.h" #include "fapi_nr_ue_interface.h" #include "assertions.h" -#include "barrier.h" -#include "actor.h" +#include "common/utils/barrier/barrier.h" +#include "common/utils/actor/actor.h" //#include "openair1/SCHED_NR_UE/defs.h" #define msg(aRGS...) LOG_D(PHY, ##aRGS) @@ -402,9 +402,6 @@ typedef struct PHY_VARS_NR_UE_s { nrLDPC_coding_interface_t nrLDPC_coding_interface; uint8_t max_ldpc_iterations; - /// SRS variables - nr_srs_info_t *nr_srs_info; - /// CSI variables nr_csi_info_t *nr_csi_info; diff --git a/openair1/PHY/defs_nr_common.h b/openair1/PHY/defs_nr_common.h index 7cd439bcee..8b50f36290 100644 --- a/openair1/PHY/defs_nr_common.h +++ b/openair1/PHY/defs_nr_common.h @@ -77,8 +77,6 @@ typedef enum{ 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; - bool is_signal_generated; int B_SRS; int C_SRS; int b_hop; diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.c b/openair1/PHY/if4_tools.c similarity index 99% rename from openair1/PHY/LTE_TRANSPORT/if4_tools.c rename to openair1/PHY/if4_tools.c index 66097fc87f..5c5428db90 100644 --- a/openair1/PHY/LTE_TRANSPORT/if4_tools.c +++ b/openair1/PHY/if4_tools.c @@ -3,7 +3,6 @@ */ #include -//#include "PHY/defs_eNB.h" #include "PHY/defs_RU.h" #include "PHY/TOOLS/alaw_lut.h" //#include "PHY/phy_extern.h" diff --git a/openair1/PHY/LTE_TRANSPORT/if4_tools.h b/openair1/PHY/if4_tools.h similarity index 96% rename from openair1/PHY/LTE_TRANSPORT/if4_tools.h rename to openair1/PHY/if4_tools.h index 3cc30f7710..367ccfa859 100644 --- a/openair1/PHY/LTE_TRANSPORT/if4_tools.h +++ b/openair1/PHY/if4_tools.h @@ -4,7 +4,7 @@ #ifndef __IF4_TOOLS_H__ #define __IF4_TOOLS_H__ -#include "PHY/defs_eNB.h" +#include "openair1/PHY/defs_RU.h" /// Macro for IF4 packet type #define IF4p5_PACKET_TYPE 0x080A 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 index 76ad47a4e2..3bd4746c92 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common_srs.c @@ -203,7 +203,7 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms, 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); + float amp_sqrt_N_ap = amp / sqrt(N_ap); int n_b[nr_srs_info->B_SRS + 1]; // Find index of table which is for this SRS length @@ -298,14 +298,16 @@ bool generate_srs_nr(const NR_DL_FRAME_PARMS *frame_parms, 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}; + cf_t shift = {cosf(alpha_i * k), sinf(alpha_i * k)}; + const c16_t r_overbar = rv_ul_ref_sig[u][v][M_sc_b_SRS_index][k]; // 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)}; + cf_t r = (cf_t) { + .r = shift.r * r_overbar.r - shift.i * r_overbar.i, + .i = shift.r * r_overbar.i + shift.i * r_overbar.r, + }; + c16_t r_amp = {(((int32_t)(amp_sqrt_N_ap * r.r)) >> 15), + (((int32_t)(amp_sqrt_N_ap * r.i)) >> 15)}; #ifdef SRS_DEBUG int subcarrier_log = subcarrier-subcarrier_offset; diff --git a/openair1/SCHED/nfapi_lte_dummy.c b/openair1/SCHED/nfapi_lte_dummy.c index 1c22057064..55c339d7c8 100644 --- a/openair1/SCHED/nfapi_lte_dummy.c +++ b/openair1/SCHED/nfapi_lte_dummy.c @@ -16,18 +16,6 @@ int slot_ahead = 6; //uint8_t nfapi_mode=0; NR_IF_Module_t *NR_IF_Module_init(int Mod_id) {return NULL;} -void nr_fill_ulsch(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_pusch_pdu_t *ulsch_pdu){} -void nr_fill_pucch(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_pucch_pdu_t *pucch_pdu){} -void nr_schedule_rx_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) -{ -} - void nr_phy_config_request(NR_PHY_Config_t *gNB){} void nr_dump_frame_parms(NR_DL_FRAME_PARMS *fp){} @@ -70,59 +58,6 @@ 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; -} - - -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) -{ - -} - -void wls_fapi_nr_pnf_stop() -{ -} - -void wls_pnf_close(pthread_t p5_thread) -{ -} - -void wls_vnf_send_stop_request() -{ -} - -void wls_vnf_stop() -{ -} - void socket_nfapi_nr_pnf_stop() { } diff --git a/openair1/SCHED/ru_procedures.c b/openair1/SCHED/ru_procedures.c index 065c66d14c..8162d11699 100644 --- a/openair1/SCHED/ru_procedures.c +++ b/openair1/SCHED/ru_procedures.c @@ -10,7 +10,7 @@ #include "PHY/defs_eNB.h" #include "SCHED/sched_eNB.h" #include "PHY/MODULATION/modulation_eNB.h" -#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/if4_tools.h" #include "PHY/LTE_TRANSPORT/transport_common_proto.h" #include "PHY/LTE_TRANSPORT/transport_proto.h" #include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h" diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index fcaf2f1c1b..929bf476f3 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -21,20 +21,14 @@ int get_nr_prach_duration(uint8_t prach_format) return val[prach_format]; } -void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind) +void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, prach_item_t *prach_id, nfapi_nr_rach_indication_t *rach_ind) { + const frame_t frame = prach_id->frame; + const slot_t slot = prach_id->slot; rach_ind->sfn = frame; rach_ind->slot = slot; - rach_ind->number_of_pdus = 0; - - prach_item_t *prach_id = find_nr_prach(&gNB->prach_list, frame, slot, gNB->frame_parms.nb_antennas_rx, NR_SEARCH_EXIST); - if (!prach_id) { - return; - } - nfapi_nr_prach_pdu_t *prach_pdu = &prach_id->pdu; LOG_D(NR_PHY_RACH, "%d.%d, prachstart slot %d prach entry occas %d\n", frame, slot, prach_id->slot, prach_pdu->num_prach_ocas); - const int prach_start_slot = prach_id->slot; int N_dur = get_nr_prach_duration(prach_pdu->prach_format); for (int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) { @@ -63,7 +57,7 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac "[RAPROC] %d.%d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol " "%u freq index %u\n", frame, - prach_start_slot, + slot, res.max_preamble, res.max_preamble_energy / 10, res.max_preamble_energy % 10, @@ -100,7 +94,6 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac if (gNB->prach_energy_counter < NUM_PRACH_RX_FOR_NOISE_ESTIMATE) gNB->prach_energy_counter++; } // if prach_id>0 - rach_ind->slot = prach_start_slot; LOG_D(NR_PHY_RACH, "Freeing PRACH entry\n"); - free_nr_prach_entry(&gNB->prach_list, prach_id); + free_nr_prach_entry(prach_id); } diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 7a5af5b070..58d9ad398a 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -2,6 +2,7 @@ * SPDX-License-Identifier: LicenseRef-CSSL-1.0 */ +#include "common/utils/fsn.h" #include "PHY/defs_gNB.h" #include "sched_nr.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" @@ -26,22 +27,14 @@ //#define DEBUG_RXDATA //#define SRS_IND_DEBUG -static void nr_fill_indication(PHY_VARS_gNB *gNB, - int frame, - int slot_rx, - int UE_id, - uint8_t harq_pid, - uint8_t crc_flag, - int dtx_flag, - nfapi_nr_crc_t *crc, - nfapi_nr_rx_data_pdu_t *pdu); -static void nr_fill_indication(PHY_VARS_gNB *gNB, +static void nr_fill_indication(const PHY_VARS_gNB *gNB, int frame, int slot_rx, - int ULSCH_id, - uint8_t harq_pid, - uint8_t crc_flag, + const NR_gNB_PUSCH *pusch, + const nfapi_nr_pusch_pdu_t *pusch_pdu, + NR_gNB_PHY_STATS_t *stats, + uint8_t *payload, int dtx_flag, nfapi_nr_crc_t *crc, nfapi_nr_rx_data_pdu_t *pdu); @@ -322,91 +315,33 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, stop_meas(&gNB->phase_comp_stats); } -static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, bool *ulsch_to_decode, NR_UL_IND_t *UL_INFO) +static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, int *ulsch_to_decode, int nb_pusch, NR_UL_IND_t *UL_INFO) { + DevAssert(nb_pusch > 0); NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - - int nb_pusch = 0; - for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { - if (ulsch_to_decode[ULSCH_id]) { - nb_pusch++; - } - } - - if (nb_pusch == 0) { - return 0; - } - - uint8_t ULSCH_ids[nb_pusch]; - uint32_t G[nb_pusch]; - int pusch_id = 0; - for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { - - if (ulsch_to_decode[ULSCH_id]) { - - ULSCH_ids[pusch_id] = ULSCH_id; - - nfapi_nr_pusch_pdu_t *pusch_pdu = &gNB->ulsch[ULSCH_id].harq_process->ulsch_pdu; - - uint16_t nb_re_dmrs; - uint16_t start_symbol = pusch_pdu->start_symbol_index; - uint16_t number_symbols = pusch_pdu->nr_of_symbols; - - uint8_t number_dmrs_symbols = 0; - for (int l = start_symbol; l < start_symbol + number_symbols; l++) - number_dmrs_symbols += ((pusch_pdu->ul_dmrs_symb_pos)>>l)&0x01; - - if (pusch_pdu->dmrs_config_type==pusch_dmrs_type1) - nb_re_dmrs = 6*pusch_pdu->num_dmrs_cdm_grps_no_data; - else - nb_re_dmrs = 4*pusch_pdu->num_dmrs_cdm_grps_no_data; - - G[pusch_id] = nr_get_G(pusch_pdu->rb_size, - number_symbols, - nb_re_dmrs, - number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs - gNB->ulsch[ULSCH_id].unav_res, - pusch_pdu->qam_mod_order, - pusch_pdu->nrOfLayers); - AssertFatal(G[pusch_id]>0,"G is 0 : rb_size %u, number_symbols %d, nb_re_dmrs %d, number_dmrs_symbols %d, qam_mod_order %u, nrOfLayer %u\n", - pusch_pdu->rb_size, - number_symbols, - nb_re_dmrs, - number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs - pusch_pdu->qam_mod_order, - pusch_pdu->nrOfLayers); - LOG_D(PHY,"rb_size %d, number_symbols %d, nb_re_dmrs %d, dmrs symbol positions %d, number_dmrs_symbols %d, qam_mod_order %d, nrOfLayer %d\n", - pusch_pdu->rb_size, - number_symbols, - nb_re_dmrs, - pusch_pdu->ul_dmrs_symb_pos, - number_dmrs_symbols, // number of dmrs symbols irrespective of single or double symbol dmrs - pusch_pdu->qam_mod_order, - pusch_pdu->nrOfLayers); - pusch_id++; - } - } //---------------------------------------------------------- //--------------------- ULSCH decoding --------------------- //---------------------------------------------------------- - int ret_nr_ulsch_decoding = nr_ulsch_decoding(gNB, frame_parms, frame_rx, slot_rx, G, ULSCH_ids, nb_pusch); + int ret_nr_ulsch_decoding = nr_ulsch_decoding(gNB, frame_parms, frame_rx, slot_rx, ulsch_to_decode, nb_pusch); // CRC check per uplink shared channel - for (pusch_id = 0; pusch_id < nb_pusch; pusch_id++) { - uint8_t ULSCH_id = ULSCH_ids[pusch_id]; + for (int pusch_id = 0; pusch_id < nb_pusch; pusch_id++) { + uint8_t ULSCH_id = ulsch_to_decode[pusch_id]; NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; NR_gNB_PUSCH *pusch = &gNB->pusch_vars[ULSCH_id]; NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process; - nfapi_nr_pusch_pdu_t *pusch_pdu = &ulsch_harq->ulsch_pdu; + NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, ulsch->rnti); + const nfapi_nr_pusch_pdu_t *pusch_pdu = &ulsch_harq->ulsch_pdu; bool crc_valid = false; // if all segments are done if (ulsch_harq->processedSegments == ulsch_harq->C) { if (ulsch_harq->C > 1) { - crc_valid = check_crc(ulsch_harq->b, lenWithCrc(1, (ulsch_harq->TBS) << 3), crcType(1, (ulsch_harq->TBS) << 3)); + int tbs = pusch_pdu->pusch_data.tb_size; + crc_valid = check_crc(ulsch_harq->b, lenWithCrc(1, tbs << 3), crcType(1, tbs << 3)); } else { // When the number of code blocks is 1 (C = 1) and ulsch_harq->processedSegments = 1, we can assume a good TB because of the // CRC check made by the LDPC for early termination, so, no need to perform CRC check twice for a single code block @@ -471,8 +406,8 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo 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 + T_INT((pusch_pdu->pusch_data.tb_size << 3)), // number_of_bits + T_BUFFER((uint8_t *)((ulsch_harq->b)), pusch_pdu->pusch_data.tb_size)); // data } #endif @@ -491,9 +426,9 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo pusch_pdu->pusch_data.new_data_indicator, ulsch->active, ulsch_harq->round, - ulsch_harq->TBS, + pusch_pdu->pusch_data.tb_size, ulsch->max_ldpc_iterations); - nr_fill_indication(gNB, ulsch->frame, ulsch->slot, ULSCH_id, ulsch->harq_pid, 0, 0, crc, pdu); + nr_fill_indication(gNB, ulsch->frame, ulsch->slot, pusch, pusch_pdu, stats, ulsch->harq_process->b, 0, crc, pdu); LOG_D(PHY, "ULSCH received ok \n"); ulsch->active = false; ulsch_harq->round = 0; @@ -512,10 +447,9 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo ulsch_harq->ulsch_pdu.pusch_data.rv_index, ulsch_harq->ulsch_pdu.rb_start, ulsch_harq->ulsch_pdu.rb_size, - ulsch_harq->TBS); - nr_fill_indication(gNB, ulsch->frame, ulsch->slot, ULSCH_id, ulsch->harq_pid, 1, 0, crc, pdu); + pusch_pdu->pusch_data.tb_size); + nr_fill_indication(gNB, ulsch->frame, ulsch->slot, pusch, pusch_pdu, stats, NULL, 0, crc, pdu); gNBdumpScopeData(gNB, ulsch->slot, ulsch->frame, "ULSCH_NACK"); - ulsch->handled = 1; LOG_D(PHY, "ULSCH %d in error\n",ULSCH_id); ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations; // Setting to max_ldpc_iterations is sufficient given that this variable is only used for checking for failure } @@ -524,24 +458,19 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo return ret_nr_ulsch_decoding; } -static void nr_fill_indication(PHY_VARS_gNB *gNB, +static void nr_fill_indication(const PHY_VARS_gNB *gNB, int frame, int slot_rx, - int ULSCH_id, - uint8_t harq_pid, - uint8_t crc_flag, + const NR_gNB_PUSCH *pusch, + const nfapi_nr_pusch_pdu_t *pusch_pdu, + NR_gNB_PHY_STATS_t *stats, + uint8_t *payload, int dtx_flag, nfapi_nr_crc_t *crc, nfapi_nr_rx_data_pdu_t *pdu) { - NR_UL_gNB_HARQ_t *harq_process = gNB->ulsch[ULSCH_id].harq_process; - NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, gNB->ulsch[ULSCH_id].rnti); - NR_gNB_PUSCH *pusch = &gNB->pusch_vars[ULSCH_id]; - - nfapi_nr_pusch_pdu_t *pusch_pdu = &harq_process->ulsch_pdu; - // Get estimated timing advance for MAC - const int sync_pos = gNB->ulsch[ULSCH_id].delay.est_delay; + const int sync_pos = pusch->delay.est_delay; // scale the 16 factor in N_TA calculation in 38.213 section 4.2 according to the used FFT size uint16_t bw_scaling = 16 * gNB->frame_parms.ofdm_symbol_size / 2048; @@ -562,14 +491,6 @@ static void nr_fill_indication(PHY_VARS_gNB *gNB, timing_advance_update = max(timing_advance_update, 0); timing_advance_update = min(timing_advance_update, 63); - if (crc_flag == 0) - LOG_D(PHY, - "%d.%d : Received PUSCH : Estimated timing advance PUSCH is = %d, timing_advance_update is %d \n", - frame, - slot_rx, - sync_pos, - timing_advance_update); - // estimate UL_CQI for MAC int SNRtimes10 = dB_fixed_x10(pusch->ulsch_power_tot) - dB_fixed_x10(pusch->ulsch_noise_power_tot); @@ -589,8 +510,8 @@ static void nr_fill_indication(PHY_VARS_gNB *gNB, crc->handle = pusch_pdu->handle; crc->rnti = pusch_pdu->rnti; - crc->harq_id = harq_pid; - crc->tb_crc_status = crc_flag; + crc->harq_id = pusch_pdu->pusch_data.harq_process_id; + crc->tb_crc_status = payload == NULL; // 222.10.02/04: pass 0, fail 1 crc->num_cb = pusch_pdu->pusch_data.num_cb; crc->ul_cqi = cqi; crc->timing_advance = timing_advance_update; @@ -599,92 +520,62 @@ static void nr_fill_indication(PHY_VARS_gNB *gNB, pdu->handle = pusch_pdu->handle; pdu->rnti = pusch_pdu->rnti; - pdu->harq_id = harq_pid; + pdu->harq_id = pusch_pdu->pusch_data.harq_process_id; pdu->ul_cqi = cqi; pdu->timing_advance = timing_advance_update; pdu->rssi = crc->rssi; - if (crc_flag) - pdu->pdu_length = 0; - else { - pdu->pdu_length = harq_process->TBS; - pdu->pdu = harq_process->b; - } + pdu->pdu_length = payload != NULL ? pusch_pdu->pusch_data.tb_size : 0; + pdu->pdu = payload; } // Function to fill UL RB mask to be used for N0 measurements static void fill_ul_rb_mask(PHY_VARS_gNB *gNB, - int frame_rx, - int slot_rx, - uint32_t rb_mask_ul[14][9], - nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf) + fsn_t now, + uint32_t rb_mask_ul[14][MAX_BWP_SIZE], + const NR_gNB_PUCCH_job_t *pucch, + int n_pucch, + const NR_gNB_PUSCH_job_t *pusch, + int n_pusch, + const NR_gNB_SRS_job_t *srs, + int n_srs) { for (int symbol = 0; symbol < 14; symbol++) { - for (int m = 0; m < 9; m++) { - rb_mask_ul[symbol][m] = 0; - for (int i = 0; i < 32; i++) { - int prbpos = (m * 32) + i; - if (prbpos > gNB->frame_parms.N_RB_UL) - break; - rb_mask_ul[symbol][m] |= (gNB->ulprbbl[prbpos] > 0 ? 1U : 0) << i; - } + for (int prb = 0; prb < MAX_BWP_SIZE; prb++) { + rb_mask_ul[symbol][prb] = gNB->ulprbbl[prb] > 0; } } - for (int i = 0; i < gNB->max_nb_pucch; i++){ - const NR_gNB_PUCCH_t *pucch = gNB->pucch + i; - if (!(pucch && pucch->active && pucch->frame == frame_rx && pucch->slot == slot_rx)) - continue; - const nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; + for (int i = 0; i < n_pucch; ++i) { + const nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch[i].pucch_pdu; const int start = pucch_pdu->start_symbol_index; - LOG_D(PHY, - "%d.%d pucch %d : start_symbol %d, nb_symbols %d, prb_size %d\n", - frame_rx, - slot_rx, - i, - start, - pucch_pdu->nr_of_symbols, - pucch_pdu->prb_size); - for (int symbol = start; symbol < (start + pucch_pdu->nr_of_symbols); symbol++) { - if (gNB->frame_parms.frame_type == FDD || (gNB->frame_parms.frame_type == TDD && slot_conf[symbol].slot_config.value == 1)) { - for (int rb = 0; rb < pucch_pdu->prb_size; rb++) { - int rb2 = - rb + pucch_pdu->bwp_start - + ((symbol < start + (pucch_pdu->nr_of_symbols >> 1)) || (pucch_pdu->freq_hop_flag == 0) ? pucch_pdu->prb_start - : pucch_pdu->second_hop_prb); - rb_mask_ul[symbol][rb2 >> 5] |= 1U << (rb2 & 31); - } + for (int symbol = start; symbol < start + pucch_pdu->nr_of_symbols; symbol++) { + bool first_hop = symbol < start + (pucch_pdu->nr_of_symbols >> 1); + int prb_first_second = first_hop || pucch_pdu->freq_hop_flag == 0 ? pucch_pdu->prb_start : pucch_pdu->second_hop_prb; + for (int rb = 0; rb < pucch_pdu->prb_size; rb++) { + int prb = rb + pucch_pdu->bwp_start + prb_first_second; + rb_mask_ul[symbol][prb] = 1; } } } - for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { - NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; - NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process; - AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid); - if (!(ulsch->active && ulsch->frame == frame_rx && ulsch->slot == slot_rx && !ulsch->handled)) - continue; - uint8_t symbol_start = ulsch_harq->ulsch_pdu.start_symbol_index; - uint8_t symbol_end = symbol_start + ulsch_harq->ulsch_pdu.nr_of_symbols; + for (int i = 0; i < n_pusch; i++) { + const nfapi_nr_pusch_pdu_t *pusch_pdu = &pusch[i].pusch_pdu; + uint8_t symbol_start = pusch_pdu->start_symbol_index; + uint8_t symbol_end = symbol_start + pusch_pdu->nr_of_symbols; for (int symbol = symbol_start; symbol < symbol_end; symbol++) { - if (gNB->frame_parms.frame_type == FDD || (gNB->frame_parms.frame_type == TDD && slot_conf[symbol].slot_config.value == 1)) { - LOG_D(PHY, "symbol %d Filling rb_mask_ul rb_size %d\n", symbol, ulsch_harq->ulsch_pdu.rb_size); - for (int rb = 0; rb < ulsch_harq->ulsch_pdu.rb_size; rb++) { - int rb2 = rb + ulsch_harq->ulsch_pdu.rb_start + ulsch_harq->ulsch_pdu.bwp_start; - rb_mask_ul[symbol][rb2 >> 5] |= 1U << (rb2 & 31); - } + for (int rb = 0; rb < pusch_pdu->rb_size; rb++) { + int prb = rb + pusch_pdu->rb_start + pusch_pdu->bwp_start; + rb_mask_ul[symbol][prb] = 1; } } } - for (int i = 0; i < gNB->max_nb_srs; i++) { - NR_gNB_SRS_t *srs = &gNB->srs[i]; - if (!(srs && srs->active && srs->frame == frame_rx && srs->slot == slot_rx)) - continue; - nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + for (int i = 0; i < n_srs; i++) { + const nfapi_nr_srs_pdu_t *srs_pdu = &srs[i].srs_pdu; const uint8_t l0 = gNB->frame_parms.symbols_per_slot - 1 - srs_pdu->time_start_position; for (int symbol = 0; symbol < (1 << srs_pdu->num_symbols); symbol++) { for (int rb = srs_pdu->bwp_start; rb < (srs_pdu->bwp_start + srs_pdu->bwp_size); rb++) { - rb_mask_ul[l0 + symbol][rb >> 5] |= 1U << (rb & 31); + rb_mask_ul[l0 + symbol][rb] = 1; } } } @@ -712,56 +603,50 @@ static int fill_srs_reported_symbol(nfapi_nr_srs_reported_symbol_t *reported_sym return 0; } -static int fill_srs_channel_matrix( - nfapi_nr_srs_normalized_channel_iq_matrix_t *nr_srs_channel_iq_matrix, - const nfapi_nr_srs_pdu_t *srs_pdu, - const nr_srs_info_t *nr_srs_info, - const uint8_t normalized_iq_representation, - const uint16_t num_gnb_antenna_elements, - const uint16_t num_ue_srs_ports, - const uint16_t prg_size, - const uint16_t num_prgs, - const NR_DL_FRAME_PARMS *frame_parms, - const c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports] - [frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)]) +static int fill_srs_channel_matrix(nfapi_nr_srs_normalized_channel_iq_matrix_t *nr_srs_channel_iq_matrix, + const nfapi_nr_srs_pdu_t *srs_pdu, + const nr_srs_info_t *nr_srs_info, + const NR_DL_FRAME_PARMS *frame_parms, + const c16_t srs_estimated_channel_freq[][1 << srs_pdu->num_ant_ports][frame_parms->ofdm_symbol_size * (1 << srs_pdu->num_symbols)]) { + const uint16_t num_gnb_antenna_elements = frame_parms->nb_antennas_rx; + const uint16_t num_ue_srs_ports = srs_pdu->srs_parameters_v4.num_total_ue_antennas; + const uint8_t normalized_iq_representation = srs_pdu->srs_parameters_v4.iq_representation; + const uint16_t prg_size = srs_pdu->srs_parameters_v4.prg_size; + const uint16_t num_prgs = srs_pdu->srs_parameters_v4.srs_bandwidth_size / srs_pdu->srs_parameters_v4.prg_size; + const uint64_t first_subcarrier = + (frame_parms->first_carrier_offset - (frame_parms->ofdm_symbol_size >> 1)) + srs_pdu->bwp_start * NR_NB_SC_PER_RB; + const uint16_t step = prg_size * NR_NB_SC_PER_RB; + nr_srs_channel_iq_matrix->normalized_iq_representation = normalized_iq_representation; nr_srs_channel_iq_matrix->num_gnb_antenna_elements = num_gnb_antenna_elements; nr_srs_channel_iq_matrix->num_ue_srs_ports = num_ue_srs_ports; nr_srs_channel_iq_matrix->prg_size = prg_size; nr_srs_channel_iq_matrix->num_prgs = num_prgs; + uint8_t *channel_matrix = nr_srs_channel_iq_matrix->channel_matrix; - const uint64_t subcarrier_offset = frame_parms->first_carrier_offset + srs_pdu->bwp_start*NR_NB_SC_PER_RB; - const uint16_t step = prg_size*NR_NB_SC_PER_RB; + c16_t *channel_matrix16 = (c16_t *)channel_matrix; + c8_t *channel_matrix8 = (c8_t *)channel_matrix; - c16_t *channel_matrix16 = (c16_t*)channel_matrix; - c8_t *channel_matrix8 = (c8_t*)channel_matrix; + for (int uI = 0; uI < num_ue_srs_ports; uI++) { + for (int gI = 0; gI < num_gnb_antenna_elements; gI++) { - for(int uI = 0; uI < num_ue_srs_ports; uI++) { - for(int gI = 0; gI < num_gnb_antenna_elements; gI++) { + // channel_matrix8 or channel_matrix16 will only be populated for the symbol 0 + uint16_t subcarrier_abs = first_subcarrier + nr_srs_info->k_0_p[uI][0]; - uint16_t subcarrier = subcarrier_offset + nr_srs_info->k_0_p[uI][0]; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; - } - - for(int pI = 0; pI < num_prgs; pI++) { - const c16_t *srs_estimated_channel16 = srs_estimated_channel_freq[gI][uI] + subcarrier; - uint16_t index = uI*num_gnb_antenna_elements*num_prgs + gI*num_prgs + pI; + for (int pI = 0; pI < num_prgs; pI++) { + const c16_t *srs_estimated_channel16 = srs_estimated_channel_freq[gI][uI] + subcarrier_abs; + uint16_t index = uI * num_gnb_antenna_elements * num_prgs + gI * num_prgs + pI; if (normalized_iq_representation == 0) { - channel_matrix8[index].r = (int8_t)(srs_estimated_channel16->r>>8); - channel_matrix8[index].i = (int8_t)(srs_estimated_channel16->i>>8); + channel_matrix8[index].r = (int8_t)(srs_estimated_channel16->r >> 8); + channel_matrix8[index].i = (int8_t)(srs_estimated_channel16->i >> 8); } else { channel_matrix16[index].r = srs_estimated_channel16->r; channel_matrix16[index].i = srs_estimated_channel16->i; } - // Subcarrier increment - subcarrier += step; - if (subcarrier >= frame_parms->ofdm_symbol_size) { - subcarrier -= frame_parms->ofdm_symbol_size; - } + subcarrier_abs += step; } } } @@ -791,66 +676,46 @@ static void copy_srs_info(const nfapi_nr_srs_pdu_t *srs_config_pdu, nr_srs_info_ 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; - } - return false; -} - -void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, +nr_srs_info_t nr_srs_rx_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, uint8_t nb_antennas_rx, uint8_t N_ap, uint8_t N_symb_SRS, uint16_t ofdm_symbol_size, - NR_gNB_SRS_t *srs, - nr_srs_info_t *nr_srs_info, + const NR_gNB_SRS_job_t *srs, int *srs_est, + int8_t *snr, c16_t srs_estimated_channel_freq[][N_ap][ofdm_symbol_size * N_symb_SRS], - c16_t srs_estimated_channel_time[][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size], int16_t *snr_per_rb, uint16_t *timing_advance_offset, int16_t *timing_advance_offset_nsec) { NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; - nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + const nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + + c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size] + __attribute__((aligned(32))); c16_t srs_received_signal[nb_antennas_rx][ofdm_symbol_size * N_symb_SRS]; c16_t srs_received_noise[nb_antennas_rx][ofdm_symbol_size * N_symb_SRS]; c16_t srs_estimated_channel_time_shifted[nb_antennas_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size]; start_meas(&gNB->generate_srs_stats); - if (check_and_configure_srs_info(srs_pdu, nr_srs_info)) { + nr_srs_info_t nr_srs_info = {0}; + copy_srs_info(srs_pdu, &nr_srs_info); + + // TODO permanently allocate? + c16_t srs_generated_signal_tmp[N_ap][ofdm_symbol_size * MAX_NUM_NR_SRS_SYMBOLS]; + c16_t *srs_generated_signal[N_ap]; + for (int i = 0; i < N_ap; ++i) + srs_generated_signal[i] = srs_generated_signal_tmp[i]; + if (true) { generate_srs_nr(frame_parms, - nr_srs_info->srs_generated_signal, + srs_generated_signal, 0, srs_pdu->bwp_start, - nr_srs_info, + &nr_srs_info, AMP, frame_rx, slot_rx, @@ -860,7 +725,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, stop_meas(&gNB->generate_srs_stats); c16_t **rxdataF = gNB->common_vars.rxdataF[srs->beam_nb]; start_meas(&gNB->get_srs_signal_stats); - *srs_est = nr_get_srs_signal(gNB, rxdataF, slot_rx, srs_pdu, nr_srs_info, srs_received_signal, srs_received_noise); + *srs_est = nr_get_srs_signal(gNB, rxdataF, slot_rx, srs_pdu, &nr_srs_info, srs_received_signal, srs_received_noise); stop_meas(&gNB->get_srs_signal_stats); uint32_t signal_power_avg = 0; @@ -879,8 +744,8 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, frame_parms->first_carrier_offset, N_symb_SRS, srs_pdu, - nr_srs_info, - nr_srs_info->srs_generated_signal[p_ind], + &nr_srs_info, + srs_generated_signal[p_ind], srs_received_signal[ant_rx_ind], srs_ls_estimated_channel[ant_rx_ind][p_ind], &delay_aux); @@ -898,7 +763,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, frame_parms->first_carrier_offset, N_symb_SRS, srs_pdu, - nr_srs_info, + &nr_srs_info, srs_ls_estimated_channel[ant_rx_ind][p_ind], delay.est_delay, srs_received_noise[ant_rx_ind], @@ -943,7 +808,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, frame_parms->first_carrier_offset, N_symb_SRS, srs_pdu, - nr_srs_info, + &nr_srs_info, signal_power_avg, srs_received_noise[ant_rx_ind], &noise_power_per_ant, @@ -952,7 +817,7 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, } noise_power_avg /= nb_antennas_rx; - gNB->srs->snr = dB_fixed(signal_power_avg) - dB_fixed(max(noise_power_avg, 1)); + *snr = dB_fixed(signal_power_avg) - dB_fixed(max(noise_power_avg, 1)); const uint16_t m_SRS_b = get_m_srs(srs_pdu->config_index, srs_pdu->bandwidth_index); for (int rb = 0; rb < m_SRS_b; rb++) { @@ -987,29 +852,362 @@ void nr_srs_rx_procedures(PHY_VARS_gNB *gNB, T_INT(slot_rx), T_BUFFER(timing_advance_offset_nsec, nb_antennas_rx * sizeof(int16_t))); } + return nr_srs_info; +} + +static void handle_srs(fsn_t now, PHY_VARS_gNB *gNB, const NR_gNB_SRS_job_t *srs, nfapi_nr_srs_indication_pdu_t *srs_indication) +{ + const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; + const uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; + const uint16_t ofdm_symbol_size = frame_parms->ofdm_symbol_size; + const nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; + + uint8_t N_symb_SRS = 1 << srs_pdu->num_symbols; + uint8_t N_ap = 1 << srs_pdu->num_ant_ports; + int16_t snr_per_rb[srs_pdu->bwp_size]; + uint16_t timing_advance_offset; + int16_t timing_advance_offset_nsec[nb_antennas_rx]; + int srs_est; + + c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); + + int8_t snr; + nr_srs_info_t srs_info = nr_srs_rx_procedures(gNB, + now.f, + now.s, + nb_antennas_rx, + N_ap, + N_symb_SRS, + ofdm_symbol_size, + srs, + &srs_est, + &snr, + srs_estimated_channel_freq, + snr_per_rb, + &timing_advance_offset, + timing_advance_offset_nsec); + + if ((snr * 10) < gNB->srs_thres) { + srs_est = -1; + } + + srs_indication->handle = srs_pdu->handle; + srs_indication->rnti = srs_pdu->rnti; + srs_indication->timing_advance_offset = srs_est >= 0 ? timing_advance_offset : 0xFFFF; + // TODO: currently we fill timing_advance_offset_nsec for antenna 0. Need to extend it for other antennas + srs_indication->timing_advance_offset_nsec = srs_est >= 0 ? timing_advance_offset_nsec[0] : 0x8000; + switch (srs_pdu->srs_parameters_v4.usage) { + case 0: + LOG_W(NR_PHY, "SRS report was not requested by MAC\n"); + return; + case 1 << NFAPI_NR_SRS_BEAMMANAGEMENT: + srs_indication->srs_usage = NFAPI_NR_SRS_BEAMMANAGEMENT; + break; + case 1 << NFAPI_NR_SRS_CODEBOOK: + srs_indication->srs_usage = NFAPI_NR_SRS_CODEBOOK; + break; + case 1 << NFAPI_NR_SRS_NONCODEBOOK: + srs_indication->srs_usage = NFAPI_NR_SRS_NONCODEBOOK; + break; + case 1 << NFAPI_NR_SRS_ANTENNASWITCH: + srs_indication->srs_usage = NFAPI_NR_SRS_ANTENNASWITCH; + break; + default: + LOG_E(NR_PHY, "Invalid srs_pdu->srs_parameters_v4.usage %i\n", srs_pdu->srs_parameters_v4.usage); + } + srs_indication->report_type = srs_pdu->srs_parameters_v4.report_type[0]; + + nfapi_srs_report_tlv_t *report_tlv = &srs_indication->report_tlv; + report_tlv->tag = 0; + report_tlv->length = 0; + + start_meas(&gNB->srs_report_tlv_stats); + switch (srs_indication->srs_usage) { + case NFAPI_NR_SRS_BEAMMANAGEMENT: { + start_meas(&gNB->srs_beam_report_stats); + nfapi_nr_srs_beamforming_report_t nr_srs_bf_report; + nr_srs_bf_report.prg_size = srs_pdu->beamforming.prg_size; + nr_srs_bf_report.num_symbols = N_symb_SRS; + nr_srs_bf_report.wide_band_snr = srs_est >= 0 ? (snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid + nr_srs_bf_report.num_reported_symbols = N_symb_SRS; + AssertFatal(nr_srs_bf_report.num_reported_symbols == 1, + "nr_srs_bf_report.num_reported_symbols %i not handled yet!\n", + nr_srs_bf_report.num_reported_symbols); + fill_srs_reported_symbol(&nr_srs_bf_report.reported_symbol_list[0], srs_pdu, snr_per_rb, srs_est); + + report_tlv->length = pack_nr_srs_beamforming_report(&nr_srs_bf_report, report_tlv->value, sizeof(report_tlv->value)); + stop_meas(&gNB->srs_beam_report_stats); + break; + } + + case NFAPI_NR_SRS_CODEBOOK: { + start_meas(&gNB->srs_iq_matrix_stats); + nfapi_nr_srs_normalized_channel_iq_matrix_t nr_srs_channel_iq_matrix; + fill_srs_channel_matrix(&nr_srs_channel_iq_matrix, + srs_pdu, + &srs_info, + frame_parms, + srs_estimated_channel_freq); + + report_tlv->length = + pack_nr_srs_normalized_channel_iq_matrix(&nr_srs_channel_iq_matrix, report_tlv->value, sizeof(report_tlv->value)); + stop_meas(&gNB->srs_iq_matrix_stats); + break; + } + + case NFAPI_NR_SRS_NONCODEBOOK: + case NFAPI_NR_SRS_ANTENNASWITCH: + LOG_W(NR_PHY, "PHY procedures for this SRS usage are not implemented yet!\n"); + break; + + default: + AssertFatal(1 == 0, "Invalid SRS usage\n"); + } + stop_meas(&gNB->srs_report_tlv_stats); +} + +static void handle_pucch(PHY_VARS_gNB *gNB, c16_t **rxdataF, const NR_gNB_PUCCH_job_t *pucch, nfapi_nr_uci_t *uci) +{ + const nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; + + switch (pucch_pdu->format_type) { + case 0: + uci->pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; + uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); + nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci->pucch_pdu_format_0_1; + nr_decode_pucch0(gNB, rxdataF, pucch->frame, pucch->slot, uci_pdu_format0, pucch_pdu); + break; + case 2: + uci->pdu_type = NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE; + uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_2_3_4_t); + nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu_format2 = &uci->pucch_pdu_format_2_3_4; + nr_decode_pucch2(gNB, rxdataF, pucch->frame, pucch->slot, uci_pdu_format2, pucch_pdu); + break; + default: + AssertFatal(1 == 0, "Only PUCCH formats 0 and 2 are currently supported\n"); + } +} + +static bool handle_pusch_decode_trigger(PHY_VARS_gNB *gNB, NR_gNB_PUSCH *pusch_vars, NR_gNB_ULSCH_t *ulsch, NR_UL_IND_t *UL_INFO, int *pusch_DTX) +{ + NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process; + AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid); + const nfapi_nr_pusch_pdu_t *pdu = &ulsch_harq->ulsch_pdu; + +#ifdef DEBUG_RXDATA + RU_t *ru = gNB->RU_list[0]; + int slot_offset = frame_parms->get_samples_slot_timestamp(ulsch->slot, frame_parms, 0); + slot_offset -= ru->N_TA_offset; + int32_t sample_offset = gNB->common_vars.debugBuff_sample_offset; + int16_t buf = (int16_t *)&gNB->common_vars.debugBuff[offset]; + buf[0] = (int16_t)ulsch->rnti; + buf[1] = (int16_t)pdu->rb_size; + buf[2] = (int16_t)pdu->rb_start; + buf[3] = (int16_t)pdu->nr_of_symbols; + buf[4] = (int16_t)pdu->start_symbol_index; + buf[5] = (int16_t)pdu->mcs_index; + buf[6] = (int16_t)pdu->pusch_data.rv_index; + buf[7] = (int16_t)ulsch->harq_pid; + memcpy(&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset + 4], + &ru->common.rxdata[0][slot_offset], + frame_parms->get_samples_per_slot(ulsch->slot, frame_parms) * sizeof(int32_t)); + gNB->common_vars.debugBuff_sample_offset += (frame_parms->get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 4); + if (gNB->common_vars.debugBuff_sample_offset > ((frame_parms->get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 2) * 20)) { + FILE *f; + f = fopen("rxdata_buff.raw", "w"); + if (f == NULL) + exit(1); + fwrite((int16_t *)gNB->common_vars.debugBuff, + 2, + (frame_parms->get_samples_per_slot(ulsch->slot, frame_parms) + 1000 + 4) * 20 * 2, + f); + fclose(f); + exit(-1); + } +#endif + + start_meas(&gNB->rx_pusch_stats); + nr_rx_pusch_tp(gNB, pusch_vars, pdu, &ulsch->unav_res, ulsch->frame, ulsch->slot, ulsch->beam_nb); + pusch_vars->ulsch_power_tot = 0; + pusch_vars->ulsch_noise_power_tot = 0; + for (int aarx = 0; aarx < gNB->frame_parms.nb_antennas_rx; aarx++) { + pusch_vars->ulsch_power_tot += pusch_vars->ulsch_power[aarx]; + pusch_vars->ulsch_noise_power_tot += pusch_vars->ulsch_noise_power[aarx]; + } + if (dB_fixed_x10(pusch_vars->ulsch_power_tot) < dB_fixed_x10(pusch_vars->ulsch_noise_power_tot) + gNB->pusch_thres) { + NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, ulsch->rnti); + + LOG_D(PHY, + "PUSCH not detected in %d.%d (%d,%d,%d)\n", + ulsch->frame, + ulsch->slot, + dB_fixed_x10(pusch_vars->ulsch_power_tot), + dB_fixed_x10(pusch_vars->ulsch_noise_power_tot), + gNB->pusch_thres); + pusch_vars->ulsch_power_tot = pusch_vars->ulsch_noise_power_tot; + pusch_vars->DTX = 1; + if (stats) + stats->ulsch_stats.DTX++; + if (!get_softmodem_params()->phy_test) { + /* in case of phy_test mode, we still want to decode to measure execution time. + Therefore, we don't yet call nr_fill_indication, it will be called later */ + nfapi_nr_crc_t *crc = &UL_INFO->crc_ind.crc_list[UL_INFO->crc_ind.number_crcs++]; + nfapi_nr_rx_data_pdu_t *rx = &UL_INFO->rx_ind.pdu_list[UL_INFO->rx_ind.number_of_pdus++]; + nr_fill_indication(gNB, ulsch->frame, ulsch->slot, pusch_vars, pdu, stats, NULL, 1, crc, rx); + (*pusch_DTX)++; + gNBdumpScopeData(gNB, ulsch->slot, ulsch->frame, "ULSCH_DTX"); + return false; + } + } else { + LOG_D(PHY, + "PUSCH detected in %d.%d (%d,%d,%d)\n", + ulsch->frame, + ulsch->slot, + dB_fixed_x10(pusch_vars->ulsch_power_tot), + dB_fixed_x10(pusch_vars->ulsch_noise_power_tot), + gNB->pusch_thres); + + pusch_vars->DTX = 0; + } + stop_meas(&gNB->rx_pusch_stats); + + return true; +} + +static bool drop_old_pucch(const void *data, void *user) +{ + const NR_gNB_PUCCH_job_t *pucch = data; + const fsn_t *now = user; + const fsn_t t = {pucch->frame, pucch->slot, now->mu}; + bool drop = fsn_in_the_past(t, *now); + if (drop) + LOG_E(NR_PHY, "%4d.%2d PUCCH job for UE %04x is in the past (%4d.%2d)\n", now->f, now->s, pucch->pucch_pdu.rnti, t.f, t.s); + return drop; +} + +static bool get_current_pucch(const void *data, void *user) +{ + const NR_gNB_PUCCH_job_t *pucch = data; + const fsn_t *now = user; + const fsn_t t = {pucch->frame, pucch->slot, now->mu}; + return fsn_equal(t, *now); +} + +static bool drop_old_pusch(const void *data, void *user) +{ + const NR_gNB_PUSCH_job_t *pusch = data; + const fsn_t *now = user; + const fsn_t t = {pusch->frame, pusch->slot, now->mu}; + bool drop = fsn_in_the_past(t, *now); + if (drop) + LOG_E(NR_PHY, "%4d.%2d PUSCH job for UE %04x is in the past (%4d.%2d)\n", now->f, now->s, pusch->pusch_pdu.rnti, t.f, t.s); + return drop; +} + +static bool get_current_pusch(const void *data, void *user) +{ + const NR_gNB_PUSCH_job_t *pusch = data; + const fsn_t *now = user; + const fsn_t t = {pusch->frame, pusch->slot, now->mu}; + return fsn_equal(t, *now); +} + +static bool drop_old_srs(const void *data, void *user) +{ + const NR_gNB_SRS_job_t *srs = data; + const fsn_t *now = user; + const fsn_t t = {srs->frame, srs->slot, now->mu}; + bool drop = fsn_in_the_past(t, *now); + if (drop) + LOG_E(NR_PHY, "%4d.%2d SRS job for UE %04x is in the past (%4d.%2d)\n", now->f, now->s, srs->srs_pdu.rnti, t.f, t.s); + return drop; +} + +static bool get_current_srs(const void *data, void *user) +{ + const NR_gNB_SRS_job_t *srs = data; + const fsn_t *now = user; + const fsn_t t = {srs->frame, srs->slot, now->mu}; + return fsn_equal(t, *now); +} + +static int find_nr_ulsch_idx(PHY_VARS_gNB *gNB, uint16_t rnti, int pid) +{ + AssertFatal(gNB != NULL, "gNB is null\n"); + + int16_t first_free_index = -1; + for (int i = 0; i < gNB->max_nb_pusch; i++) { + const NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[i]; + AssertFatal(ulsch, "gNB->ulsch[%d] is null\n", i); + if (!ulsch->active) { + if (first_free_index == -1) + first_free_index = i; + } else { + // if there is already an active ULSCH for this RNTI and HARQ_PID + if ((ulsch->harq_pid == pid) && (ulsch->rnti == rnti)) + return i; + } + } + return first_free_index; +} +static int handle_pusch_job_trigger(PHY_VARS_gNB *gNB, const NR_gNB_PUSCH_job_t *job) +{ + const nfapi_nr_pusch_pdu_t *pdu = &job->pusch_pdu; + int pid = pdu->pusch_data.harq_process_id; + int ULSCH_id = find_nr_ulsch_idx(gNB, pdu->rnti, pid); + if (ULSCH_id < 0) { + LOG_E(NR_PHY, "%4d.%2d cannot handle PUSCH job of RNTI %04x: no space\n", job->frame, job->slot, pdu->rnti); + return -1; + } + /* (re-)initialize this PUSCH context from job data */ + NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; + ulsch->active = true; + ulsch->frame = job->frame; + ulsch->slot = job->slot; + ulsch->rnti = pdu->rnti; + ulsch->harq_pid = pid; + ulsch->beam_nb = job->beam_nb; + ulsch->harq_process->ulsch_pdu = job->pusch_pdu; + if (pdu->pusch_data.new_data_indicator) { + ulsch->harq_process->harq_to_be_cleared = true; + ulsch->harq_process->round = 0; + } else { + ulsch->harq_process->round++; + } + return ULSCH_id; } int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO) { /* those variables to log T_GNB_PHY_PUCCH_PUSCH_IQ only when we try to decode */ - int pucch_decode_done = 0; - int pusch_decode_done = 0; int pusch_DTX = 0; const NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms; const uint16_t ofdm_symbol_size = frame_parms->ofdm_symbol_size; - const uint8_t nb_antennas_rx = frame_parms->nb_antennas_rx; + + fsn_t now = {frame_rx, slot_rx, frame_parms->numerology_index}; + + spsc_q_drop_while(&gNB->pucch_queue, drop_old_pucch, &now); + NR_gNB_PUCCH_job_t pucch[MAX_NUM_NR_UCI_PDUS]; + int n_pucch = spsc_q_get_while(&gNB->pucch_queue, get_current_pucch, &now, pucch, sizeof(*pucch), MAX_NUM_NR_UCI_PDUS); + + spsc_q_drop_while(&gNB->pusch_queue, drop_old_pusch, &now); + NR_gNB_PUSCH_job_t pusch[MAX_UL_PDUS_PER_SLOT]; + int n_pusch_jobs = spsc_q_get_while(&gNB->pusch_queue, get_current_pusch, &now, pusch, sizeof(*pusch), MAX_UL_PDUS_PER_SLOT); + + spsc_q_drop_while(&gNB->srs_queue, drop_old_srs, &now); + NR_gNB_SRS_job_t srs[MAX_NUM_NR_SRS_PDUS]; + int n_srs = spsc_q_get_while(&gNB->srs_queue, get_current_srs, &now, srs, sizeof(*srs), MAX_NUM_NR_SRS_PDUS); + LOG_D(PHY,"phy_procedures_gNB_uespec_RX frame %d, slot %d\n",frame_rx,slot_rx); { // Mask of occupied RBs, per symbol and PRB - uint32_t rb_mask_ul[14][9]; - nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf = NULL; - if (frame_parms->frame_type == TDD) - slot_conf = gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list; - fill_ul_rb_mask(gNB, frame_rx, slot_rx, rb_mask_ul, slot_conf); + uint32_t rb_mask_ul[14][MAX_BWP_SIZE] = {0}; + fill_ul_rb_mask(gNB, now, rb_mask_ul, pucch, n_pucch, pusch, n_pusch_jobs, srs, n_srs); int first_symb = 0, num_symb = 0; - if (frame_parms->frame_type == TDD) + if (frame_parms->frame_type == TDD) { + const nfapi_nr_max_num_of_symbol_per_slot_t *slot_conf = gNB->gNB_config.tdd_table.max_tdd_periodicity_list[slot_rx].max_num_of_symbol_per_slot_list; for (int symbol_count = 0; symbol_count < frame_parms->symbols_per_slot; symbol_count++) { if (slot_conf[symbol_count].slot_config.value == 1) { if (num_symb == 0) @@ -1017,51 +1215,21 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N num_symb++; } } - else + } else { num_symb = frame_parms->symbols_per_slot; + } gNB_I0_measurements(gNB, slot_rx, first_symb, num_symb, rb_mask_ul); } - const int soffset = (slot_rx & 3) * frame_parms->symbols_per_slot * ofdm_symbol_size; start_meas(&gNB->phy_proc_rx); - - for (int i = 0; i < gNB->max_nb_pucch; i++) { - NR_gNB_PUCCH_t *pucch = &gNB->pucch[i]; - if (!(pucch && pucch->active && pucch->frame == frame_rx && pucch->slot == slot_rx)) - continue; + UL_INFO->uci_ind.uci_list = UL_INFO->uci_pdu_list; + UL_INFO->uci_ind.sfn = frame_rx; + UL_INFO->uci_ind.slot = slot_rx; + UL_INFO->uci_ind.num_ucis = n_pucch; + nfapi_nr_uci_t *uci = UL_INFO->uci_ind.uci_list; + for (int i = 0; i < n_pucch; ++i) { c16_t **rxdataF = gNB->common_vars.rxdataF[pucch->beam_nb]; - pucch_decode_done = 1; - nfapi_nr_pucch_pdu_t *pucch_pdu = &pucch->pucch_pdu; - UL_INFO->uci_ind.uci_list = UL_INFO->uci_pdu_list; - nfapi_nr_uci_t *uci = UL_INFO->uci_ind.uci_list + UL_INFO->uci_ind.num_ucis; - UL_INFO->uci_ind.sfn = frame_rx; - UL_INFO->uci_ind.slot = slot_rx; - switch (pucch_pdu->format_type) { - case 0: - uci->pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE; - uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t); - nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_pdu_format0 = &uci->pucch_pdu_format_0_1; - int offset = - pucch_pdu->start_symbol_index * ofdm_symbol_size + (frame_parms->first_carrier_offset + pucch_pdu->prb_start * 12); - LOG_D(NR_PHY, - "frame %d, slot %d: PUCCH signal energy %d\n", - frame_rx, - slot_rx, - signal_energy_nodc(&rxdataF[0][soffset + offset], 12)); - nr_decode_pucch0(gNB, rxdataF, frame_rx, slot_rx, uci_pdu_format0, pucch_pdu); - break; - case 2: - uci->pdu_type = NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE; - uci->pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_2_3_4_t); - nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_pdu_format2 = &uci->pucch_pdu_format_2_3_4; - LOG_D(PHY, "%d.%d Calling nr_decode_pucch2\n", frame_rx, slot_rx); - nr_decode_pucch2(gNB, rxdataF, frame_rx, slot_rx, uci_pdu_format2, pucch_pdu); - break; - default: - AssertFatal(1 == 0, "Only PUCCH formats 0 and 2 are currently supported\n"); - } - UL_INFO->uci_ind.num_ucis += 1; - pucch->active = false; + handle_pucch(gNB, rxdataF, &pucch[i], uci++); } UL_INFO->crc_ind.sfn = frame_rx; @@ -1070,95 +1238,16 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N UL_INFO->rx_ind.sfn = frame_rx; UL_INFO->rx_ind.slot = slot_rx; UL_INFO->rx_ind.pdu_list = UL_INFO->rx_pdu_list; - bool ulsch_to_decode[gNB->max_nb_pusch]; - bzero(ulsch_to_decode, sizeof(ulsch_to_decode)); - for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { - NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; - NR_UL_gNB_HARQ_t *ulsch_harq = ulsch->harq_process; - AssertFatal(ulsch_harq != NULL, "harq_pid %d is not allocated\n", ulsch->harq_pid); - if (!(ulsch->active && ulsch->frame == frame_rx && ulsch->slot == slot_rx && !ulsch->handled)) + int ulsch_idx_to_decode[MAX_UL_PDUS_PER_SLOT]; + int num_pusch = 0; + for (int i = 0; i < n_pusch_jobs; ++i) { + int ULSCH_id = handle_pusch_job_trigger(gNB, &pusch[i]); + if (ULSCH_id < 0) continue; - 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); - -#ifdef DEBUG_RXDATA - RU_t *ru = gNB->RU_list[0]; - 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; - int16_t buf = (int16_t *)&gNB->common_vars.debugBuff[offset]; - buf[0] = (int16_t)ulsch->rnti; - buf[1] = (int16_t)pdu->rb_size; - buf[2] = (int16_t)pdu->rb_start; - buf[3] = (int16_t)pdu->nr_of_symbols; - buf[4] = (int16_t)pdu->start_symbol_index; - buf[5] = (int16_t)pdu->mcs_index; - buf[6] = (int16_t)pdu->pusch_data.rv_index; - buf[7] = (int16_t)ulsch->harq_pid; - memcpy(&gNB->common_vars.debugBuff[gNB->common_vars.debugBuff_sample_offset + 4], - &ru->common.rxdata[0][slot_offset], - get_samples_per_slot(slot_rx, frame_parms) * sizeof(int32_t)); - gNB->common_vars.debugBuff_sample_offset += (get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4); - if (gNB->common_vars.debugBuff_sample_offset > ((get_samples_per_slot(slot_rx, frame_parms) + 1000 + 2) * 20)) { - FILE *f; - f = fopen("rxdata_buff.raw", "w"); - if (f == NULL) - exit(1); - fwrite((int16_t *)gNB->common_vars.debugBuff, 2, (get_samples_per_slot(slot_rx, frame_parms) + 1000 + 4) * 20 * 2, f); - fclose(f); - exit(-1); - } -#endif - - pusch_decode_done = 1; - - start_meas(&gNB->rx_pusch_stats); - nr_rx_pusch_tp(gNB, ULSCH_id, frame_rx, slot_rx, ulsch->beam_nb); NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[ULSCH_id]; - pusch_vars->ulsch_power_tot = 0; - pusch_vars->ulsch_noise_power_tot = 0; - for (int aarx = 0; aarx < nb_antennas_rx; aarx++) { - pusch_vars->ulsch_power_tot += pusch_vars->ulsch_power[aarx]; - pusch_vars->ulsch_noise_power_tot += pusch_vars->ulsch_noise_power[aarx]; - } - if (dB_fixed_x10(pusch_vars->ulsch_power_tot) < dB_fixed_x10(pusch_vars->ulsch_noise_power_tot) + gNB->pusch_thres) { - NR_gNB_PHY_STATS_t *stats = get_phy_stats(gNB, ulsch->rnti); - - LOG_D(PHY, - "PUSCH not detected in %d.%d (%d,%d,%d)\n", - frame_rx, - slot_rx, - dB_fixed_x10(pusch_vars->ulsch_power_tot), - dB_fixed_x10(pusch_vars->ulsch_noise_power_tot), - gNB->pusch_thres); - pusch_vars->ulsch_power_tot = pusch_vars->ulsch_noise_power_tot; - pusch_vars->DTX = 1; - if (stats) - stats->ulsch_stats.DTX++; - if (!get_softmodem_params()->phy_test) { - /* in case of phy_test mode, we still want to decode to measure execution time. - Therefore, we don't yet call nr_fill_indication, it will be called later */ - 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++]; - nr_fill_indication(gNB, frame_rx, slot_rx, ULSCH_id, ulsch->harq_pid, 1, 1, crc, pdu); - pusch_DTX++; - gNBdumpScopeData(gNB, ulsch->slot, ulsch->frame, "ULSCH_DTX"); - continue; - } - } else { - LOG_D(PHY, - "PUSCH detected in %d.%d (%d,%d,%d)\n", - frame_rx, - slot_rx, - dB_fixed_x10(pusch_vars->ulsch_power_tot), - dB_fixed_x10(pusch_vars->ulsch_noise_power_tot), - gNB->pusch_thres); - - pusch_vars->DTX = 0; - } - ulsch_to_decode[ULSCH_id] = true; - stop_meas(&gNB->rx_pusch_stats); - // LOG_M("rxdataF_comp.m","rxF_comp",gNB->pusch_vars[0]->rxdataF_comp[0],6900,1,1); - // LOG_M("rxdataF_ext.m","rxF_ext",gNB->pusch_vars[0]->rxdataF_ext[0],6900,1,1); + NR_gNB_ULSCH_t *ulsch = &gNB->ulsch[ULSCH_id]; + if (handle_pusch_decode_trigger(gNB, pusch_vars, ulsch, UL_INFO, &pusch_DTX)) + ulsch_idx_to_decode[num_pusch++] = ULSCH_id; } /* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1 @@ -1168,9 +1257,10 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N if (gNB->max_nb_pusch == 1) start_meas(&gNB->ulsch_decoding_stats); - int const ret_nr_ulsch_procedures = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ulsch_to_decode, UL_INFO); - if (ret_nr_ulsch_procedures != 0) { - LOG_E(PHY,"Error in nr_ulsch_procedures, returned %d\n",ret_nr_ulsch_procedures); + if (num_pusch > 0) { + int ret_nr_ulsch_procedures = nr_ulsch_procedures(gNB, frame_rx, slot_rx, ulsch_idx_to_decode, num_pusch, UL_INFO); + if (ret_nr_ulsch_procedures != 0) + LOG_E(PHY,"Error in nr_ulsch_procedures, returned %d\n",ret_nr_ulsch_procedures); } /* Do ULSCH decoding time measurement only when number of PUSCH is limited to 1 @@ -1180,208 +1270,20 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N if (gNB->max_nb_pusch == 1) stop_meas(&gNB->ulsch_decoding_stats); - for (int i = 0; i < gNB->max_nb_srs; i++) { - NR_gNB_SRS_t *srs = &gNB->srs[i]; - if (!(srs && srs->active && srs->frame == frame_rx && srs->slot == slot_rx)) - continue; - LOG_D(NR_PHY, "(%d.%d) gNB is waiting for SRS, id = %i\n", frame_rx, slot_rx, i); - + UL_INFO->srs_ind.sfn = frame_rx; + UL_INFO->srs_ind.slot = slot_rx; + UL_INFO->srs_ind.pdu_list = UL_INFO->srs_pdu_list; + UL_INFO->srs_ind.number_of_pdus = n_srs; + for (int i = 0; i < n_srs; ++i) { start_meas(&gNB->rx_srs_stats); - - uint8_t N_symb_SRS = 1 << srs->srs_pdu.num_symbols; - uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports; - int16_t snr_per_rb[srs->srs_pdu.bwp_size]; - nfapi_nr_srs_pdu_t *srs_pdu = &srs->srs_pdu; - uint16_t timing_advance_offset; - int16_t timing_advance_offset_nsec[nb_antennas_rx]; - int srs_est; - - c16_t srs_estimated_channel_freq[nb_antennas_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); - c16_t srs_estimated_channel_time[nb_antennas_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size] - __attribute__((aligned(32))); - - nr_srs_rx_procedures(gNB, - frame_rx, - slot_rx, - nb_antennas_rx, - N_ap, - N_symb_SRS, - ofdm_symbol_size, - srs, - gNB->nr_srs_info[i], - &srs_est, - srs_estimated_channel_freq, - srs_estimated_channel_time, - snr_per_rb, - &timing_advance_offset, - timing_advance_offset_nsec); - - if ((gNB->srs->snr * 10) < gNB->srs_thres) { - srs_est = -1; - } - - UL_INFO->srs_ind.sfn = frame_rx; - UL_INFO->srs_ind.slot = slot_rx; - - // data model difficult to understand, nfapi do malloc for this pointer - UL_INFO->srs_ind.pdu_list = UL_INFO->srs_pdu_list; - nfapi_nr_srs_indication_pdu_t *srs_indication = UL_INFO->srs_pdu_list + UL_INFO->srs_ind.number_of_pdus++; - srs_indication->handle = srs_pdu->handle; - srs_indication->rnti = srs_pdu->rnti; - srs_indication->timing_advance_offset = srs_est >= 0 ? timing_advance_offset : 0xFFFF; - // TODO: currently we fill timing_advance_offset_nsec for antenna 0. Need to extend it for other antennas - srs_indication->timing_advance_offset_nsec = srs_est >= 0 ? timing_advance_offset_nsec[0] : 0x8000; - switch (srs_pdu->srs_parameters_v4.usage) { - case 0: - LOG_W(NR_PHY, "SRS report was not requested by MAC\n"); - return 0; - case 1 << NFAPI_NR_SRS_BEAMMANAGEMENT: - srs_indication->srs_usage = NFAPI_NR_SRS_BEAMMANAGEMENT; - break; - case 1 << NFAPI_NR_SRS_CODEBOOK: - srs_indication->srs_usage = NFAPI_NR_SRS_CODEBOOK; - break; - case 1 << NFAPI_NR_SRS_NONCODEBOOK: - srs_indication->srs_usage = NFAPI_NR_SRS_NONCODEBOOK; - break; - case 1 << NFAPI_NR_SRS_ANTENNASWITCH: - srs_indication->srs_usage = NFAPI_NR_SRS_ANTENNASWITCH; - break; - default: - LOG_E(NR_PHY, "Invalid srs_pdu->srs_parameters_v4.usage %i\n", srs_pdu->srs_parameters_v4.usage); - } - srs_indication->report_type = srs_pdu->srs_parameters_v4.report_type[0]; - -#ifdef SRS_IND_DEBUG - LOG_I(NR_PHY, "UL_INFO->srs_ind.sfn = %i\n", UL_INFO->srs_ind.sfn); - LOG_I(NR_PHY, "UL_INFO->srs_ind.slot = %i\n", UL_INFO->srs_ind.slot); - LOG_I(NR_PHY, "srs_indication->rnti = %04x\n", srs_indication->rnti); - LOG_I(NR_PHY, "srs_indication->timing_advance = %i\n", srs_indication->timing_advance_offset); - LOG_I(NR_PHY, "srs_indication->timing_advance_offset_nsec = %i\n", srs_indication->timing_advance_offset_nsec); - LOG_I(NR_PHY, "srs_indication->srs_usage = %i\n", srs_indication->srs_usage); - LOG_I(NR_PHY, "srs_indication->report_type = %i\n", srs_indication->report_type); -#endif - - nfapi_srs_report_tlv_t *report_tlv = &srs_indication->report_tlv; - report_tlv->tag = 0; - report_tlv->length = 0; - - start_meas(&gNB->srs_report_tlv_stats); - switch (srs_indication->srs_usage) { - case NFAPI_NR_SRS_BEAMMANAGEMENT: { - start_meas(&gNB->srs_beam_report_stats); - nfapi_nr_srs_beamforming_report_t nr_srs_bf_report; - nr_srs_bf_report.prg_size = srs_pdu->beamforming.prg_size; - nr_srs_bf_report.num_symbols = N_symb_SRS; - nr_srs_bf_report.wide_band_snr = - srs_est >= 0 ? (gNB->srs->snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid - nr_srs_bf_report.num_reported_symbols = N_symb_SRS; - AssertFatal(nr_srs_bf_report.num_reported_symbols == 1, - "nr_srs_bf_report.num_reported_symbols %i not handled yet!\n", - nr_srs_bf_report.num_reported_symbols); - fill_srs_reported_symbol(&nr_srs_bf_report.reported_symbol_list[0], srs_pdu, snr_per_rb, srs_est); - -#ifdef SRS_IND_DEBUG - LOG_I(NR_PHY, "nr_srs_bf_report.prg_size = %i\n", nr_srs_bf_report.prg_size); - LOG_I(NR_PHY, "nr_srs_bf_report.num_symbols = %i\n", nr_srs_bf_report.num_symbols); - LOG_I(NR_PHY, - "nr_srs_bf_report.wide_band_snr = %i (%i dB)\n", - nr_srs_bf_report.wide_band_snr, - (nr_srs_bf_report.wide_band_snr >> 1) - 64); - LOG_I(NR_PHY, "nr_srs_bf_report.num_reported_symbols = %i\n", nr_srs_bf_report.num_reported_symbols); - LOG_I(NR_PHY, - "nr_srs_bf_report.reported_symbol_list[0].num_prgs = %i\n", - nr_srs_bf_report.reported_symbol_list[0].num_prgs); - for (int prg_idx = 0; prg_idx < nr_srs_bf_report.reported_symbol_list[0].num_prgs; prg_idx++) { - LOG_I(NR_PHY, - "nr_srs_beamforming_report.reported_symbol_list[0].prg_list[%3i].rb_snr = %i (%i dB)\n", - prg_idx, - nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr, - (nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr >> 1) - 64); - } -#endif - - report_tlv->length = pack_nr_srs_beamforming_report(&nr_srs_bf_report, report_tlv->value, sizeof(report_tlv->value)); - stop_meas(&gNB->srs_beam_report_stats); - break; - } - - case NFAPI_NR_SRS_CODEBOOK: { - start_meas(&gNB->srs_iq_matrix_stats); - nfapi_nr_srs_normalized_channel_iq_matrix_t nr_srs_channel_iq_matrix; - fill_srs_channel_matrix(&nr_srs_channel_iq_matrix, - srs_pdu, - gNB->nr_srs_info[i], - srs_pdu->srs_parameters_v4.iq_representation, - nb_antennas_rx, - srs_pdu->srs_parameters_v4.num_total_ue_antennas, - srs_pdu->srs_parameters_v4.prg_size, - srs_pdu->srs_parameters_v4.srs_bandwidth_size / srs_pdu->srs_parameters_v4.prg_size, - frame_parms, - srs_estimated_channel_freq); - -#ifdef SRS_IND_DEBUG - LOG_I(NR_PHY, - "nr_srs_channel_iq_matrix.normalized_iq_representation = %i\n", - nr_srs_channel_iq_matrix.normalized_iq_representation); - LOG_I(NR_PHY, - "nr_srs_channel_iq_matrix.num_gnb_antenna_elements = %i\n", - nr_srs_channel_iq_matrix.num_gnb_antenna_elements); - LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.num_ue_srs_ports = %i\n", nr_srs_channel_iq_matrix.num_ue_srs_ports); - LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.prg_size = %i\n", nr_srs_channel_iq_matrix.prg_size); - LOG_I(NR_PHY, "nr_srs_channel_iq_matrix.num_prgs = %i\n", nr_srs_channel_iq_matrix.num_prgs); - c16_t *channel_matrix16 = (c16_t *)nr_srs_channel_iq_matrix.channel_matrix; - c8_t *channel_matrix8 = (c8_t *)nr_srs_channel_iq_matrix.channel_matrix; - for (int uI = 0; uI < nr_srs_channel_iq_matrix.num_ue_srs_ports; uI++) { - for (int gI = 0; gI < nr_srs_channel_iq_matrix.num_gnb_antenna_elements; gI++) { - for (int pI = 0; pI < nr_srs_channel_iq_matrix.num_prgs; pI++) { - uint16_t index = uI * nr_srs_channel_iq_matrix.num_gnb_antenna_elements * nr_srs_channel_iq_matrix.num_prgs - + gI * nr_srs_channel_iq_matrix.num_prgs + pI; - LOG_I( - NR_PHY, - "(uI %i, gI %i, pI %i) channel_matrix --> real %i, imag %i\n", - uI, - gI, - pI, - nr_srs_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].r : channel_matrix16[index].r, - nr_srs_channel_iq_matrix.normalized_iq_representation == 0 ? channel_matrix8[index].i - : channel_matrix16[index].i); - } - } - } -#endif - - report_tlv->length = - pack_nr_srs_normalized_channel_iq_matrix(&nr_srs_channel_iq_matrix, report_tlv->value, sizeof(report_tlv->value)); - stop_meas(&gNB->srs_iq_matrix_stats); - break; - } - - case NFAPI_NR_SRS_NONCODEBOOK: - case NFAPI_NR_SRS_ANTENNASWITCH: - LOG_W(NR_PHY, "PHY procedures for this SRS usage are not implemented yet!\n"); - break; - - default: - AssertFatal(1 == 0, "Invalid SRS usage\n"); - } - stop_meas(&gNB->srs_report_tlv_stats); - -#ifdef SRS_IND_DEBUG - LOG_I(NR_PHY, "report_tlv->tag = %i\n", report_tlv->tag); - LOG_I(NR_PHY, "report_tlv->length = %i\n", report_tlv->length); - char *value = (char *)report_tlv->value; - for (int b = 0; b < report_tlv->length; b++) { - LOG_I(NR_PHY, "value[%i] = 0x%02x\n", b, value[b] & 0xFF); - } -#endif - srs->active = false; + handle_srs(now, gNB, &srs[i], &UL_INFO->srs_ind.pdu_list[i]); stop_meas(&gNB->rx_srs_stats); } stop_meas(&gNB->phy_proc_rx); - if (pucch_decode_done || pusch_decode_done) { + if (n_pucch > 0 || num_pusch > 0) { + UNUSED(ofdm_symbol_size); // only used if T activated T(T_GNB_PHY_PUCCH_PUSCH_IQ, T_INT(frame_rx), T_INT(slot_rx), @@ -1417,9 +1319,7 @@ void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req break; case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE: { nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; - prach_item_t *prach = nr_schedule_rx_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); - if (!prach) - LOG_W(NR_PHY_RACH, "Error in scheduling rach\n"); + nr_schedule_rx_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); } break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: nr_fill_srs(gNB, UL_tti_req->SFN, UL_tti_req->Slot, &UL_tti_req->pdus_list[i].srs_pdu); diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 7ff044b46c..ba1d00457b 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -18,7 +18,7 @@ void phy_procedures_gNB_TX(PHY_VARS_gNB *gNB, int slot); void nr_save_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti_req); int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, NR_UL_IND_t *UL_INFO); -void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind); +void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, prach_item_t *prach_id, nfapi_nr_rach_indication_t *rach_ind); void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame,int slot, const nfapi_nr_dl_tti_ssb_pdu *ssb_pdu); void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx); void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa); diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index 225634937b..f9c8f38b56 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -243,7 +243,7 @@ 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) +static void configure_srs_info(const 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; @@ -272,25 +272,17 @@ static void configure_srs_info(fapi_nr_ul_config_srs_pdu *srs_config_pdu, nr_srs * 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 * *********************************************************************/ -bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, +void 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, + const fapi_nr_ul_config_srs_pdu *srs_config_pdu, bool was_symbol_used[NR_SYMBOLS_PER_SLOT]) { - if(phy_data->srs_vars.active == false) { - return false; - } - NR_DL_FRAME_PARMS *frame_parms = &(ue->frame_parms); - fapi_nr_ul_config_srs_pdu *srs_config_pdu = &phy_data->srs_vars.srs_config_pdu; const uint8_t l0 = 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}; @@ -326,18 +318,20 @@ bool ue_srs_procedures_nr(PHY_VARS_NR_UE *ue, 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_srs_info_t nr_srs_info = {0}; + configure_srs_info(srs_config_pdu, &nr_srs_info); uint16_t symbol_offset = l0 * frame_parms->ofdm_symbol_size; bool generated = generate_srs_nr(frame_parms, txdataF, symbol_offset, srs_config_pdu->bwp_start, - ue->nr_srs_info, + &nr_srs_info, AMP, proc->frame_tx, proc->nr_slot_tx, frame_parms->nb_antennas_tx); - return generated; + DevAssert(generated); // if we can't generate despite the SRS config, there + // is a problem } 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) @@ -365,7 +359,8 @@ void phy_procedures_nrUE_TX(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, n nr_ue_ulsch_procedures(ue, frame_tx, slot_tx, phy_data, (c16_t **)&txdataF, was_symbol_used); - ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF, phy_data, was_symbol_used); + if (phy_data->srs_vars.active) + ue_srs_procedures_nr(ue, proc, (c16_t **)&txdataF, &phy_data->srs_vars.srs_config_pdu, was_symbol_used); pucch_procedures_ue_nr(ue, proc, phy_data, (c16_t **)&txdataF, was_symbol_used); diff --git a/openair1/SIMULATION/NR_PHY/nr_unitary_common.c b/openair1/SIMULATION/NR_PHY/nr_unitary_common.c index 9a595a9295..4f76749c8d 100644 --- a/openair1/SIMULATION/NR_PHY/nr_unitary_common.c +++ b/openair1/SIMULATION/NR_PHY/nr_unitary_common.c @@ -56,40 +56,6 @@ void handle_nr_slot_ind(uint16_t sfn, uint16_t slot) UNUSED(slot); } -int pack_nr_srs_beamforming_report(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen) -{ - UNUSED(pMessageBuf); - UNUSED(pPackedBuf); - UNUSED(packedBufLen); - return 0; -} -int unpack_nr_srs_beamforming_report(void *pMessageBuf, uint32_t messageBufLen, void *pUnpackedBuf, uint32_t unpackedBufLen) -{ - UNUSED(pMessageBuf); - UNUSED(messageBufLen); - UNUSED(pUnpackedBuf); - UNUSED(unpackedBufLen); - return 0; -} -int pack_nr_srs_normalized_channel_iq_matrix(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen) -{ - UNUSED(pMessageBuf); - UNUSED(pPackedBuf); - UNUSED(packedBufLen); - return 0; -} -int unpack_nr_srs_normalized_channel_iq_matrix(void *pMessageBuf, - uint32_t messageBufLen, - void *pUnpackedBuf, - uint32_t unpackedBufLen) -{ - UNUSED(pMessageBuf); - UNUSED(messageBufLen); - UNUSED(pUnpackedBuf); - UNUSED(unpackedBufLen); - return 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) { UNUSED(vnf_ip_addr); @@ -102,117 +68,3 @@ void configure_nr_nfapi_vnf(eth_params_t params) { UNUSED(params); } -int nfapi_nr_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t *config) -{ - UNUSED(pMessageBuf); - UNUSED(pPackedBuf); - UNUSED(packedBufLen); - UNUSED(config); - return 0; -} -bool nfapi_nr_p7_message_unpack(void *pMessageBuf, - uint32_t messageBufLen, - void *pUnpackedBuf, - uint32_t unpackedBufLen, - nfapi_p7_codec_config_t *config) -{ - UNUSED(pMessageBuf); - UNUSED(messageBufLen); - UNUSED(pUnpackedBuf); - UNUSED(unpackedBufLen); - UNUSED(config); - return false; -} -int nfapi_p7_message_header_unpack(void *pMessageBuf, - uint32_t messageBufLen, - void *pUnpackedBuf, - uint32_t unpackedBufLen, - nfapi_p7_codec_config_t *config) -{ - UNUSED(pMessageBuf); - UNUSED(messageBufLen); - UNUSED(pUnpackedBuf); - UNUSED(unpackedBufLen); - UNUSED(config); - return 0; -} - -void nr_mac_rrc_sync_ind(const module_id_t module_id, const frame_t frame, const bool in_sync) -{ - UNUSED(module_id); - UNUSED(frame); - UNUSED(in_sync); -} - -void nr_mac_rrc_msg3_ind(const module_id_t mod_id, int rnti, int gnb_id) -{ - UNUSED(mod_id); - UNUSED(gnb_id); - UNUSED(rnti); -} - -void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success) -{ - UNUSED(mod_id); - UNUSED(success); -} - -void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id) -{ - UNUSED(mod_id); -} - -void rrc_data_ind(const protocol_ctxt_t *const ctxt_pP, - const rb_id_t Srb_id, - const sdu_size_t sdu_sizeP, - const uint8_t *const buffer_pP) -{ - UNUSED(ctxt_pP); - UNUSED(Srb_id); - UNUSED(sdu_sizeP); - UNUSED(buffer_pP); -} - -typedef uint32_t channel_t; -int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, - const int CC_id, - const uint8_t gNB_index, - const int hfn, - const frame_t frame, - const int slot, - const rnti_t rnti, - const uint32_t cellid, - const long arfcn, - const channel_t channel, - const uint8_t *pduP, - const sdu_size_t pdu_len) -{ - UNUSED(module_id); - UNUSED(CC_id); - UNUSED(gNB_index); - UNUSED(hfn); - UNUSED(frame); - UNUSED(slot); - UNUSED(rnti); - UNUSED(arfcn); - UNUSED(channel); - UNUSED(pduP); - UNUSED(pdu_len); - UNUSED(cellid); - return 0; -} - -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) -{ - UNUSED(module_id); - UNUSED(Nid_cell); - UNUSED(gNB_index); - UNUSED(csi_meas); - UNUSED(is_neighboring_cell); - UNUSED(rsrp_dBm); -} diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index 6e29abd9a5..b47b35b470 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -547,12 +547,10 @@ int main(int argc, char **argv){ phy_init_nr_gNB(gNB); nr_phy_init_RU(ru); - prach_item_t *prach_data = calloc(1,sizeof(prach_item_t)); - gNB->prach_list.list[0] = prach_data; - nfapi_nr_prach_pdu_t *prach_pdu = &prach_data->pdu; - prach_pdu->num_cs = get_NCS(NCS_config, format0, restrictedSetConfig); - prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value = 1+(64/(N_ZC/prach_pdu->num_cs)); - prach_pdu->prach_format = prach_format; + nfapi_nr_prach_pdu_t prach_pdu = {0}; + prach_pdu.num_cs = get_NCS(NCS_config, format0, restrictedSetConfig); + prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value = 1+(64/(N_ZC/prach_pdu.num_cs)); + prach_pdu.prach_format = prach_format; // Configure UE UE = malloc(sizeof(PHY_VARS_NR_UE)); @@ -749,14 +747,14 @@ int main(int argc, char **argv){ } nfapi_nr_prach_config_t *cfg = &gNB->gNB_config.prach_config; - nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu->num_ra]; - prach_pdu->num_prach_ocas=1; + nfapi_nr_num_prach_fd_occasions_t *occ = &cfg->num_prach_fd_occasions_list[prach_pdu.num_ra]; + prach_pdu.num_prach_ocas=1; prach_item_t *in = malloc(sizeof(prach_item_t) + sizeof(c16_t) * gNB->gNB_config.carrier_config.num_rx_ant.value * NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX * NR_PRACH_SEQ_LEN_L); *in = (prach_item_t){.frame = frame, .slot = slot, - .pdu = *prach_pdu, + .pdu = prach_pdu, .rootSequenceIndex = occ->prach_root_sequence_index.value, .numrootSequenceIndex = occ->num_root_sequences.value, .msg1_frequencystart = occ->k1.value, @@ -772,7 +770,7 @@ int main(int argc, char **argv){ if (n_frames == 1) LOG_I(PHY, "ncs %d,num_seq %d\n", - prach_pdu->num_cs, + prach_pdu.num_cs, prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value); rx_prach_out_t out = rx_nr_prach(in, prachOccasion); @@ -823,7 +821,6 @@ int main(int argc, char **argv){ nr_phy_free_RU(ru); free(RC.ru[0]); free(RC.ru); - free(prach_data); phy_free_nr_gNB(gNB); // allocated in set_tdd_config_nr() int nb_slots_to_set = (1<ofdm_symbol_size], 12); // set UL mask for pucch allocation - uint32_t rb_mask_ul[14][9] = {0}; + uint32_t rb_mask_ul[14][MAX_BWP_SIZE] = {0}; if (format == 1) { for (int s = 0; s < frame_parms->symbols_per_slot; s++) { if (s >= startingSymbolIndex && s < (startingSymbolIndex + nrofSymbols / 2)) for (int rb = 0; rb < N_RB; rb++) { - int rb2 = rb + startingPRB; - rb_mask_ul[s][rb2 >> 5] |= (1 << (rb2 & 31)); + rb_mask_ul[s][rb + startingPRB] = 1; } else if (s >= (startingSymbolIndex + nrofSymbols / 2) && s < startingSymbolIndex + nrofSymbols) for (int rb = 0; rb < N_RB; rb++) { - int rb2 = rb + startingPRB_intraSlotHopping; - rb_mask_ul[s][rb2 >> 5] |= (1 << (rb2 & 31)); + rb_mask_ul[s][rb + startingPRB_intraSlotHopping] = 1; } } } else { for (int s = 0; s < frame_parms->symbols_per_slot; s++) { if (s >= startingSymbolIndex && s < (startingSymbolIndex + nrofSymbols)) for (int rb = 0; rb < N_RB; rb++) { - int rb2 = rb + startingPRB; - rb_mask_ul[s][rb2 >> 5] |= (1 << (rb2 & 31)); + rb_mask_ul[s][rb + startingPRB] = 1; } } } diff --git a/openair1/SIMULATION/NR_PHY/srssim.c b/openair1/SIMULATION/NR_PHY/srssim.c index afb4da5a80..0ab34dac47 100644 --- a/openair1/SIMULATION/NR_PHY/srssim.c +++ b/openair1/SIMULATION/NR_PHY/srssim.c @@ -435,11 +435,7 @@ int main(int argc, char *argv[]) .beamforming.num_prgs = m_SRS[srs_pdu.config_index], .beamforming.prg_size = 1}; - gNB->srs->srs_pdu = srs_pdu; - gNB->srs->active = true; - gNB->srs->beam_nb = 0; - gNB->srs->frame = frame; - gNB->srs->slot = slot; + NR_gNB_SRS_job_t srs_job = {.frame = frame, .slot = slot, .srs_pdu = srs_pdu}; // Configure SRS parameters at UE fapi_nr_ul_config_srs_pdu srs_config_pdu = {.rnti = srs_pdu.rnti, @@ -467,11 +463,6 @@ int main(int argc, char *argv[]) .beamforming.num_prgs = srs_pdu.beamforming.num_prgs, .beamforming.prg_size = srs_pdu.beamforming.prg_size}; - nr_phy_data_tx_t phy_data = {0}; - phy_data.srs_vars.active = true; - phy_data.srs_vars.srs_config_pdu = srs_config_pdu; - UE->nr_srs_info = malloc16_clear(sizeof(nr_srs_info_t)); - //----------- UE TX SRS procedures --------------------- UE_nr_rxtx_proc_t proc; @@ -492,7 +483,7 @@ int main(int argc, char *argv[]) for (i = 0; i < n_tx; i++) txd[i] = txdata[i] + slot_offset; - ue_srs_procedures_nr(UE, &proc, (c16_t **)txF, &phy_data, was_symbol_used); + ue_srs_procedures_nr(UE, &proc, (c16_t **)txF, &srs_config_pdu, was_symbol_used); //------------ TX rotation and OFDM Modulation -------------------------- nr_tx_rotation_and_ofdm_mod(slot, fp, n_tx, txF, txd, link_type_ul, was_symbol_used, false); @@ -564,16 +555,15 @@ int main(int argc, char *argv[]) //----------- UE RX SRS procedures --------------------- start_meas(&gNB->rx_srs_stats); - NR_gNB_SRS_t *srs = &gNB->srs[0]; - uint8_t N_symb_SRS = 1 << srs->srs_pdu.num_symbols; - uint8_t N_ap = 1 << srs->srs_pdu.num_ant_ports; - int16_t snr_per_rb[srs->srs_pdu.bwp_size]; + uint8_t N_symb_SRS = 1 << srs_pdu.num_symbols; + uint8_t N_ap = 1 << srs_pdu.num_ant_ports; + int16_t snr_per_rb[srs_pdu.bwp_size]; uint16_t timing_advance_offset; int16_t timing_advance_offset_nsec[n_rx]; int srs_est; c16_t srs_estimated_channel_freq[n_rx][N_ap][ofdm_symbol_size * N_symb_SRS] __attribute__((aligned(32))); - c16_t srs_estimated_channel_time[n_rx][N_ap][NR_SRS_IDFT_OVERSAMP_FACTOR * ofdm_symbol_size] __attribute__((aligned(32))); + int8_t snr; nr_srs_rx_procedures(gNB, frame, slot, @@ -581,16 +571,15 @@ int main(int argc, char *argv[]) N_ap, N_symb_SRS, ofdm_symbol_size, - srs, - gNB->nr_srs_info[0], + &srs_job, &srs_est, + &snr, srs_estimated_channel_freq, - srs_estimated_channel_time, snr_per_rb, &timing_advance_offset, timing_advance_offset_nsec); - sum_srs_snr += pow(10, (double)gNB->srs->snr / 10.0); + sum_srs_snr += pow(10, (double)snr / 10.0); int16_t delay_ns = delay * 1e9 / (fp->samples_per_frame * 100); for (int ant_idx = 0; ant_idx < n_rx; ant_idx++) { @@ -666,7 +655,6 @@ int main(int argc, char *argv[]) phy_free_nr_gNB(gNB); free_channel_desc_scm(UE2gNB); - free_and_zero(UE->nr_srs_info); free(gNB->RU_list[0]); free(UE); diff --git a/openair1/SIMULATION/NR_PHY/ulschsim.c b/openair1/SIMULATION/NR_PHY/ulschsim.c index f07ad92ca9..c5b8723908 100644 --- a/openair1/SIMULATION/NR_PHY/ulschsim.c +++ b/openair1/SIMULATION/NR_PHY/ulschsim.c @@ -414,12 +414,12 @@ int main(int argc, char **argv) unsigned int TBS = 8424; unsigned int available_bits; uint8_t nb_re_dmrs = 6; - uint8_t length_dmrs = 1; + uint8_t length_dmrs = 2; uint8_t N_PRB_oh; uint16_t N_RE_prime,code_rate; unsigned char mod_order; uint8_t rvidx = 0; - uint8_t UE_id = 0; + int UE_id = 0; NR_gNB_ULSCH_t *ulsch_gNB = &gNB->ulsch[UE_id]; NR_UL_gNB_HARQ_t *harq_process_gNB = ulsch_gNB->harq_process; @@ -429,9 +429,6 @@ int main(int argc, char **argv) nr_phy_data_tx_t phy_data = {0}; NR_UE_ULSCH_t *ulsch_ue = &phy_data.ulsch; - if ((Nl==4)||(Nl==3)) - nb_re_dmrs = nb_re_dmrs*2; - mod_order = nr_get_Qm_ul(Imcs, mcs_table); code_rate = nr_get_code_rate_ul(Imcs, mcs_table); available_bits = nr_get_G(nb_rb, nb_symb_sch, nb_re_dmrs, length_dmrs, 0, mod_order, Nl); @@ -445,10 +442,15 @@ int main(int argc, char **argv) rel15_ul->qam_mod_order = mod_order; rel15_ul->mcs_index = Imcs; rel15_ul->pusch_data.rv_index = rvidx; + rel15_ul->ul_dmrs_symb_pos = nb_re_dmrs; + rel15_ul->dmrs_config_type = pusch_dmrs_type1; + rel15_ul->num_dmrs_cdm_grps_no_data = 1; rel15_ul->nrOfLayers = Nl; rel15_ul->target_code_rate = code_rate; rel15_ul->pusch_data.tb_size = TBS>>3; rel15_ul->maintenance_parms_v3.ldpcBaseGraph = get_BG(TBS, code_rate); + int bits = count_bits64_with_mask(rel15_ul->ul_dmrs_symb_pos, rel15_ul->start_symbol_index, rel15_ul->nr_of_symbols); + AssertFatal(length_dmrs == bits, "length_dmrs %d bits %d\n", length_dmrs, bits); /////////////////////////////////////////////////// double modulated_input[16 * 68 * 384]; // [hna] 16 segments, 68*Zc @@ -558,9 +560,9 @@ int main(int argc, char **argv) printf("\n"); exit(-1); #endif - nr_ulsch_decoding(gNB, frame_parms, frame, subframe, &G, &UE_id, 1); + nr_ulsch_decoding(gNB, frame_parms, frame, subframe, &UE_id, 1); if (harq_process_gNB->processedSegments == harq_process_gNB->C) { - bool crc_valid = check_crc(harq_process_gNB->b, lenWithCrc(1, (harq_process_gNB->TBS) << 3), crcType(1, (harq_process_gNB->TBS) << 3)); + bool crc_valid = check_crc(harq_process_gNB->b, lenWithCrc(1, TBS << 3), crcType(1, TBS << 3)); if (!crc_valid) { n_false_positive++; } diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 0d432bfdd0..7e74f26f56 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -1208,6 +1208,7 @@ int main(int argc, char *argv[]) uint8_t round = 0; crc_status = 1; errors_decoding = 0; + NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[UE_id]; while (round < max_rounds && crc_status && !stop) { @@ -1307,7 +1308,7 @@ int main(int argc, char *argv[]) srs_pdu->resource_type = NR_SRS_Resource__resourceType_PR_periodic; srs_pdu->t_srs = 1; srs_pdu->srs_parameters_v4.srs_bandwidth_size = m_SRS[srs_pdu->config_index]; - srs_pdu->srs_parameters_v4.usage = 1 << NR_SRS_ResourceSet__usage_codebook; + srs_pdu->srs_parameters_v4.usage = 1 << NFAPI_NR_SRS_BEAMMANAGEMENT; // to get SNR srs_pdu->srs_parameters_v4.report_type[0] = 1; srs_pdu->srs_parameters_v4.iq_representation = 1; srs_pdu->srs_parameters_v4.prg_size = 1; @@ -1594,7 +1595,6 @@ int main(int argc, char *argv[]) } } - NR_gNB_PUSCH *pusch_vars = &gNB->pusch_vars[UE_id]; if (n_trials == 1 && round == 0) { __attribute__((unused)) int off = ((nb_rb & 1) == 1) ? 4 : 0; @@ -1742,13 +1742,20 @@ int main(int argc, char *argv[]) if (!crc_status) effRate += ((double)TBS) / (double)round; - sum_pusch_delay += ulsch_gNB->delay.est_delay; - min_pusch_delay = min(ulsch_gNB->delay.est_delay, min_pusch_delay); - max_pusch_delay = max(ulsch_gNB->delay.est_delay, max_pusch_delay); + sum_pusch_delay += pusch_vars->delay.est_delay; + min_pusch_delay = min(pusch_vars->delay.est_delay, min_pusch_delay); + max_pusch_delay = max(pusch_vars->delay.est_delay, max_pusch_delay); delay_pusch_est_count++; if (do_SRS == 1) { - sum_srs_snr += gNB->srs->snr; + DevAssert(UL_INFO.srs_ind.number_of_pdus == 1); // there must be SRS indication + const nfapi_nr_srs_indication_pdu_t *srs_ind = &UL_INFO.srs_ind.pdu_list[0]; + DevAssert(srs_ind->srs_usage == NFAPI_NR_SRS_BEAMMANAGEMENT); + nfapi_nr_srs_beamforming_report_t bf_rep; + unpack_nr_srs_beamforming_report((void *)srs_ind->report_tlv.value, srs_ind->report_tlv.length, &bf_rep, sizeof(bf_rep)); + DevAssert(bf_rep.wide_band_snr != 0xff); + int8_t snr = (bf_rep.wide_band_snr >> 1) - 64; + sum_srs_snr += snr; srs_snr_count++; } } // trial loop diff --git a/openair1/SIMULATION/TOOLS/channel_sim.c b/openair1/SIMULATION/TOOLS/channel_sim.c index 80f933db69..0e6e7404d0 100644 --- a/openair1/SIMULATION/TOOLS/channel_sim.c +++ b/openair1/SIMULATION/TOOLS/channel_sim.c @@ -256,9 +256,9 @@ void do_DL_sig(sim_t *sim, LOG_D(OCM,"[SIM][DL] UE %d : rx_pwr (ADC out) %f dB/RE (%d) for subframe %d, writing to %p, length %d\n",UE_id, 10*log10((double)rx_pwr2),rx_pwr2,subframe,rxdata,lengthN_RB_DL) ,subframe); #else - UNUSED_VARIABLE(rx_pwr2); - UNUSED_VARIABLE(tx_pwr); - UNUSED_VARIABLE(rx_pwr); + UNUSED(rx_pwr2); + UNUSED(tx_pwr); + UNUSED(rx_pwr); #endif } // RU_output_mask @@ -434,8 +434,8 @@ void do_UL_sig(sim_t *sim, uint16_t subframe, uint8_t abstraction_flag, LTE_DL_F rx_pwr2 = signal_energy(rxdata[0]+sf_offset_tdd,frame_parms->samples_per_tti)*(double)frame_parms->ofdm_symbol_size/(12.0*frame_parms->N_RB_DL); LOG_D(OCM,"[SIM][UL] RU %d rx_pwr (ADC out) %f dB (%d) for subframe %d (offset %d) = %p\n",ru_id,10*log10((double)rx_pwr2),rx_pwr2,subframe,sf_offset,rxdata[0]+sf_offset_tdd); #else - UNUSED_VARIABLE(tx_pwr); - UNUSED_VARIABLE(rx_pwr); - UNUSED_VARIABLE(rx_pwr2); + UNUSED(tx_pwr); + UNUSED(rx_pwr); + UNUSED(rx_pwr2); #endif } diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 37c4a7ee83..2df2c783bf 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -161,8 +161,7 @@ typedef struct f1ap_du_register_req_s { typedef struct f1ap_sib_msg_s { /// RRC container with system information owned by gNB-CU - uint8_t *SI_container; - int SI_container_length; + byte_array_t SI_container; /// SIB block type, e.g. 2 for sibType2 int SI_type; } f1ap_sib_msg_t; diff --git a/openair2/COMMON/mac_messages_def.h b/openair2/COMMON/mac_messages_def.h index cca53d38e6..bed2ad4243 100644 --- a/openair2/COMMON/mac_messages_def.h +++ b/openair2/COMMON/mac_messages_def.h @@ -31,6 +31,7 @@ MESSAGE_DEF(RRC_MAC_PCCH_DATA_REQ, MESSAGE_PRIORITY_MED_PLUS, RrcMacPcchDat MESSAGE_DEF(NR_RRC_MAC_RA_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacRaInd, nr_rrc_mac_ra_ind) MESSAGE_DEF(NR_RRC_MAC_MSG3_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacMsg3Ind, nr_rrc_mac_msg3_ind) MESSAGE_DEF(NR_RRC_MAC_INAC_IND, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacInacInd, nr_rrc_mac_inac_ind) +MESSAGE_DEF(NR_RRC_MAC_VERIFY, MESSAGE_PRIORITY_MED_PLUS, NRRrcMacVerify, nr_rrc_mac_verify) /* RRC configures DRX context (MAC timers) of a UE */ MESSAGE_DEF(RRC_MAC_DRX_CONFIG_REQ, MESSAGE_PRIORITY_MED, rrc_mac_drx_config_req_t, rrc_mac_drx_config_req) diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h index c447379640..dc6770948f 100644 --- a/openair2/COMMON/mac_messages_types.h +++ b/openair2/COMMON/mac_messages_types.h @@ -41,6 +41,7 @@ #define NR_RRC_MAC_RA_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_ra_ind #define NR_RRC_MAC_MSG3_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_msg3_ind #define NR_RRC_MAC_INAC_IND(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_inac_ind +#define NR_RRC_MAC_VERIFY(mSGpTR) (mSGpTR)->ittiMsg.nr_rrc_mac_verify #define RRC_MAC_DRX_CONFIG_REQ(mSGpTR) (mSGpTR)->ittiMsg.rrc_mac_drx_config_req @@ -67,6 +68,10 @@ typedef struct NRRrcMacMsg3Ind_s { bool prepare_payload; } NRRrcMacMsg3Ind; +typedef struct NRRrcMacVerify_s { + bool L2_RRC_verification_failed; // not to leave the struct empty +} NRRrcMacVerify; + typedef struct NRRrcMacInacInd_s { bool inactivity_timer_expired; // not to leave the struct empty } NRRrcMacInacInd; diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index bb2015b33e..815a9f1b82 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -627,10 +627,10 @@ static void encode_cells_to_activate(const served_cells_to_activate_t *cell, F1A F1AP_GNB_CUSystemInformation_t *gNB_CUSystemInformation = &cells_to_be_activated_itemExtIEs->extensionValue.choice.GNB_CUSystemInformation; const f1ap_sib_msg_t *SI_msg = &cell->SI_msg[n]; - if (SI_msg->SI_container != NULL) { + if (SI_msg->SI_container.buf != NULL) { asn1cSequenceAdd(gNB_CUSystemInformation->sibtypetobeupdatedlist.list, F1AP_SibtypetobeupdatedListItem_t, sib_item); sib_item->sIBtype = SI_msg->SI_type; - OCTET_STRING_fromBuf(&sib_item->sIBmessage, (const char *)SI_msg->SI_container, SI_msg->SI_container_length); + OCTET_STRING_fromBuf(&sib_item->sIBmessage, (const char *)SI_msg->SI_container.buf, SI_msg->SI_container.len); } } } @@ -670,7 +670,7 @@ static bool decode_cells_to_activate(served_cells_to_activate_t *out, const F1AP F1AP_SibtypetobeupdatedListItem_t *sib_item = gNB_CUSystemInformation->sibtypetobeupdatedlist.list.array[s]; /* SI container */ f1ap_sib_msg_t *SI_msg = &out->SI_msg[s]; - SI_msg->SI_container = cp_octet_string(&sib_item->sIBmessage, &SI_msg->SI_container_length); + SI_msg->SI_container.buf = cp_octet_string(&sib_item->sIBmessage, (int *)&SI_msg->SI_container.len); /* SIB type */ SI_msg->SI_type = sib_item->sIBtype; } @@ -1163,8 +1163,8 @@ bool eq_f1ap_setup_response(const f1ap_setup_resp_t *a, const f1ap_setup_resp_t for (int j = 0; j < b->cells_to_activate[i].num_SI; j++) { const f1ap_sib_msg_t *a_SI_msg = &a->cells_to_activate[i].SI_msg[j]; const f1ap_sib_msg_t *b_SI_msg = &b->cells_to_activate[i].SI_msg[j]; - _EQ_CHECK_INT(*a_SI_msg->SI_container, *b_SI_msg->SI_container); - _EQ_CHECK_INT(a_SI_msg->SI_container_length, b_SI_msg->SI_container_length); + if (!eq_byte_array(&a_SI_msg->SI_container, &b_SI_msg->SI_container)) + return false; _EQ_CHECK_INT(a_SI_msg->SI_type, b_SI_msg->SI_type); } } @@ -1201,9 +1201,7 @@ f1ap_setup_resp_t cp_f1ap_setup_response(const f1ap_setup_resp_t *msg) for (int j = 0; j < cp_cell->num_SI; j++) { f1ap_sib_msg_t *cp_SI_msg = &cp_cell->SI_msg[j]; const f1ap_sib_msg_t *b_SI_msg = &msg_cell->SI_msg[j]; - cp_SI_msg->SI_container_length = b_SI_msg->SI_container_length; - cp_SI_msg->SI_container = malloc_or_fail(cp_SI_msg->SI_container_length); - memcpy(cp_SI_msg->SI_container, b_SI_msg->SI_container, b_SI_msg->SI_container_length); + cp_SI_msg->SI_container = copy_byte_array(b_SI_msg->SI_container); cp_SI_msg->SI_type = b_SI_msg->SI_type; } } @@ -1221,8 +1219,7 @@ void free_f1ap_setup_response(const f1ap_setup_resp_t *msg) free(msg->gNB_CU_name); for (int i = 0; i < msg->num_cells_to_activate; i++) for (int j = 0; j < msg->cells_to_activate[i].num_SI; j++) - if (msg->cells_to_activate[i].SI_msg[j].SI_container_length > 0) - free(msg->cells_to_activate[i].SI_msg[j].SI_container); + free_byte_array(msg->cells_to_activate[i].SI_msg[j].SI_container); free(msg->cells_to_activate); } @@ -1798,7 +1795,7 @@ void free_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t { for (int i = 0; i < msg->num_cells_to_activate; i++) for (int j = 0; j < msg->cells_to_activate[i].num_SI; j++) - free(msg->cells_to_activate[i].SI_msg[j].SI_container); + free_byte_array(msg->cells_to_activate[i].SI_msg[j].SI_container); free(msg->cells_to_activate); } @@ -1819,8 +1816,8 @@ bool eq_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *a for (int s = 0; s < a->cells_to_activate[i].num_SI; s++) { f1ap_sib_msg_t *a_sib_msg = &a->cells_to_activate[i].SI_msg[s]; f1ap_sib_msg_t *b_sib_msg = &b->cells_to_activate[i].SI_msg[s]; - _EQ_CHECK_INT(*a_sib_msg->SI_container, *b_sib_msg->SI_container); - _EQ_CHECK_INT(a_sib_msg->SI_container_length, b_sib_msg->SI_container_length); + if (!eq_byte_array(&a_sib_msg->SI_container, &b_sib_msg->SI_container)) + return false; _EQ_CHECK_INT(a_sib_msg->SI_type, b_sib_msg->SI_type); } } @@ -1842,9 +1839,7 @@ f1ap_gnb_cu_configuration_update_t cp_f1ap_cu_configuration_update(const f1ap_gn for (int s = 0; s < cp.cells_to_activate[i].num_SI; s++) { cp.cells_to_activate[i].SI_msg[s] = msg->cells_to_activate[i].SI_msg[s]; f1ap_sib_msg_t *SI_msg = &cp.cells_to_activate[i].SI_msg[s]; - SI_msg->SI_container = calloc_or_fail(SI_msg->SI_container_length, sizeof(*SI_msg->SI_container)); - for (int j = 0; j < SI_msg->SI_container_length; j++) - SI_msg->SI_container[j] = msg->cells_to_activate[i].SI_msg[s].SI_container[j]; + SI_msg->SI_container = copy_byte_array(msg->cells_to_activate[i].SI_msg[s].SI_container); } } return cp; @@ -2153,8 +2148,8 @@ bool eq_f1ap_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration return false; _EQ_CHECK_INT(a->cells_to_activate[i].num_SI, b->cells_to_activate[i].num_SI); for (int s = 0; s < a->cells_to_activate[i].num_SI; s++) { - _EQ_CHECK_INT(*a->cells_to_activate[i].SI_msg[s].SI_container, *b->cells_to_activate[i].SI_msg[s].SI_container); - _EQ_CHECK_INT(a->cells_to_activate[i].SI_msg[s].SI_container_length, b->cells_to_activate[i].SI_msg[s].SI_container_length); + if (!eq_byte_array(&a->cells_to_activate[i].SI_msg[s].SI_container, &b->cells_to_activate[i].SI_msg[s].SI_container)) + return false; _EQ_CHECK_INT(a->cells_to_activate[i].SI_msg[s].SI_type, b->cells_to_activate[i].SI_msg[s].SI_type); } } @@ -2180,9 +2175,7 @@ f1ap_gnb_du_configuration_update_acknowledge_t cp_f1ap_du_configuration_update_a f1ap_sib_msg_t *cp_sib = &cp.cells_to_activate[i].SI_msg[s]; const f1ap_sib_msg_t *msg_sib = &msg->cells_to_activate[i].SI_msg[s]; cp_sib->SI_type = msg_sib->SI_type; - cp_sib->SI_container_length = msg_sib->SI_container_length; - cp_sib->SI_container = calloc_or_fail(cp_sib->SI_container_length, sizeof(*cp_sib->SI_container)); - memcpy(cp_sib->SI_container, msg_sib->SI_container, cp_sib->SI_container_length); + cp_sib->SI_container = copy_byte_array(msg_sib->SI_container); } } return cp; @@ -2196,9 +2189,7 @@ void free_f1ap_du_configuration_update_acknowledge(const f1ap_gnb_du_configurati // SI_container for (int i = 0; i < msg->num_cells_to_activate; i++) { for (int j = 0; j < msg->cells_to_activate[i].num_SI; j++) { - if (msg->cells_to_activate[i].SI_msg[j].SI_container) { - free(msg->cells_to_activate[i].SI_msg[j].SI_container); - } + free_byte_array(msg->cells_to_activate[i].SI_msg[j].SI_container); } } free(msg->cells_to_activate); diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 8f315ff8ae..1140e3c39b 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -313,9 +313,9 @@ static void test_f1ap_setup_response(void) int SI_container_length = strlen(s) + 1; orig.cells_to_activate[0].num_SI = 1; f1ap_sib_msg_t *SI_msg = &orig.cells_to_activate[0].SI_msg[0]; - SI_msg->SI_container = malloc_or_fail(SI_container_length); - memcpy(SI_msg->SI_container, (uint8_t *)s, SI_container_length); - SI_msg->SI_container_length = SI_container_length; + SI_msg->SI_container.buf = malloc_or_fail(SI_container_length); + memcpy(SI_msg->SI_container.buf, s, SI_container_length); + SI_msg->SI_container.len = SI_container_length; SI_msg->SI_type = 7; } F1AP_F1AP_PDU_t *f1enc = encode_f1ap_setup_response(&orig); @@ -609,10 +609,10 @@ static void test_f1ap_du_configuration_update_acknowledge(void) orig.cells_to_activate[0].plmn.mnc_digit_length = 2; orig.cells_to_activate[0].num_SI = 1; orig.cells_to_activate[0].SI_msg[0].SI_type = 7; - orig.cells_to_activate[0].SI_msg[0].SI_container_length = 10; - orig.cells_to_activate[0].SI_msg[0].SI_container = malloc(sizeof(uint8_t) * 10); - for (int i = 0; i < orig.cells_to_activate[0].SI_msg[0].SI_container_length; i++) { - orig.cells_to_activate[0].SI_msg[0].SI_container[i] = i; + orig.cells_to_activate[0].SI_msg[0].SI_container.len = 10; + orig.cells_to_activate[0].SI_msg[0].SI_container.buf = malloc(sizeof(uint8_t) * 10); + for (int i = 0; i < (int)orig.cells_to_activate[0].SI_msg[0].SI_container.len; i++) { + orig.cells_to_activate[0].SI_msg[0].SI_container.buf[i] = i; } // ASN.1 enc/dec F1AP_F1AP_PDU_t *f1enc = encode_f1ap_du_configuration_update_acknowledge(&orig); @@ -655,8 +655,8 @@ static void test_f1ap_cu_configuration_update(void) orig.cells_to_activate[0].plmn.mnc_digit_length = 2; orig.cells_to_activate[0].num_SI = 1; orig.cells_to_activate[0].SI_msg[0].SI_type = 7; - orig.cells_to_activate[0].SI_msg[0].SI_container_length = 10; - orig.cells_to_activate[0].SI_msg[0].SI_container = malloc(sizeof(uint8_t) * 10); + orig.cells_to_activate[0].SI_msg[0].SI_container.len = 10; + orig.cells_to_activate[0].SI_msg[0].SI_container.buf = malloc(sizeof(uint8_t) * 10); F1AP_F1AP_PDU_t *f1enc = encode_f1ap_cu_configuration_update(&orig); F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); f1ap_msg_free(f1enc); diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index a73a77b0ee..856078e6f7 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1083,7 +1083,7 @@ f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCC nr_SIBs_t *si = (nr_SIBs_t *)seq_arr_at(du_SIBs, i); // other SIB in gNB-DU System Information not implemented yet // only DU SIB not included in this message is SIB19 - AssertFatal(si->SIB_type == 19, "Cannot handle SIB%d in gNB-DU System Information\n", si->SIB_type); + AssertFatal(si->SIB_type == NR_SIB_19, "Cannot handle SIB%d in gNB-DU System Information\n", (int)si->SIB_type); } } return sys_info; @@ -1243,7 +1243,7 @@ static seq_arr_t *fill_du_sibs(paramdef_t *GNBparamarray) int sib_value = GNBparamarray[GNB_DU_SIBS_IDX].iptr[i]; // SIB10, SIB12, SIB13, SIB14, SIB15, SIB17, SIB18, SIB19 and SIB20 are generated by the DU // all the rest in the DU - AssertFatal((sib_value > 9 && sib_value < 21) && sib_value != 11 && sib_value != 16, + AssertFatal((sib_value > NR_SIB_9 && sib_value < NR_SIB_21) && sib_value != NR_SIB_11 && sib_value != NR_SIB_16, "SIB%d is not a DU SIB, to be configured in DU section\n", sib_value); nr_SIBs_t *du_sib = calloc_or_fail(1, sizeof(nr_SIBs_t)); @@ -2012,94 +2012,209 @@ static nr_neighbour_cell_t *get_neighbour_by_pci(seq_arr_t *neighbour_cells, int return NULL; } -static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) +/** @brief Parse gNB-level inter-frequency list (frequency_list) into a shared array. + * This parses gNBs.[gnb_idx].frequency_list once and validates per-frequency SIB4 + * parameters. The resulting list can then be reused for all serving cells. + * @param[out] inter_freqs Sequence array of nr_inter_freq_cfg_t to populate + * @param[in] gnb_idx gNB index */ +static bool eq_inter_freq_arfcn_scs(const void *vval, const void *vit) { - char gnbpath[MAX_OPTNAME_SIZE + 8]; - snprintf(gnbpath, sizeof(gnbpath), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx); + const nr_inter_freq_cfg_t *key = (const nr_inter_freq_cfg_t *)vval; + const nr_inter_freq_cfg_t *cur = (const nr_inter_freq_cfg_t *)vit; + return key->arfcn == cur->arfcn && key->scs == cur->scs; +} - GET_PARAMS_LIST(neighbour_list_param_list, - neighbour_list_params, - GNB_NEIGHBOUR_LIST_PARAM_LIST, - GNB_CONFIG_STRING_NEIGHBOUR_LIST, - gnbpath); - - if (neighbour_list_param_list.numelt < 1) - return; - - rrc->neighbour_cell_configuration = malloc(sizeof(seq_arr_t)); - seq_arr_init(rrc->neighbour_cell_configuration, sizeof(neighbour_cell_configuration_t)); - - for (int elm = 0; elm < neighbour_list_param_list.numelt; ++elm) { - neighbour_cell_configuration_t cell = {0}; - cell.nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr; - - char neighbourpath[MAX_OPTNAME_SIZE + 8]; - snprintf(neighbourpath, sizeof(neighbourpath), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm); - GET_PARAMS_LIST(NeighbourCellParamList, - NeighbourCellParams, - GNBNEIGHBOURCELLPARAMS_DESC, - GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, - neighbourpath); - 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 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, - sizeof(neighbour_plmn_path), - "%s.%s.[%i].%s", - neighbourpath, - GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, - l, - GNB_CONFIG_STRING_NEIGHBOUR_PLMN); - GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path); - - 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; - if (get_neighbour_by_pci(cell.neighbour_cells, n.physicalCellId) != NULL) { - LOG_E(GNB_APP, - "Cell %ld: duplicate PCI %d in neighbour list (nrcell_id %ld)\n", - cell.nr_cell_id, - n.physicalCellId, - n.nrcell_id); - AssertFatal(false, "PCI must be unique within a cell's neighbour list\n"); - } - 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)); +/** @brief Insert an inter-frequency config if (ARFCN,SCS) is unique in the list. + * Fails fast if a duplicate is found. + * @param[in,out] inter_freqs Existing inter-frequency list + * @param[in] f Candidate entry to insert (by value) + * @param[in] gnb_idx gNB index for logging + */ +static void add_inter_freq(seq_arr_t *inter_freqs, const nr_inter_freq_cfg_t *f, uint8_t gnb_idx) +{ + const nr_inter_freq_cfg_t key = {.arfcn = f->arfcn, .scs = f->scs}; + elm_arr_t dup = find_if(inter_freqs, (void *)&key, eq_inter_freq_arfcn_scs); + if (dup.found) { + AssertFatal(false, "gNB %d: duplicate inter-freq carrier ARFCN %d, SCS %d in frequency_list\n", gnb_idx, f->arfcn, f->scs); } + + seq_arr_push_back(inter_freqs, (void *)f, sizeof(*f)); +} + +static void parse_inter_freq_list(seq_arr_t *inter_freqs, const uint8_t gnb_idx) +{ + seq_arr_init(inter_freqs, sizeof(nr_inter_freq_cfg_t)); + + char freq_path[MAX_OPTNAME_SIZE + 8]; + snprintf(freq_path, sizeof(freq_path), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx); + GET_PARAMS_LIST(freq_list, freq_params, GNBFREQUENCYPARAMS_DESC, GNB_CONFIG_STRING_FREQUENCY_LIST, freq_path); + + for (int i = 0; i < freq_list.numelt; ++i) { + const paramdef_t *freq_item = freq_list.paramarray[i]; + nr_inter_freq_cfg_t f = {0}; + f.arfcn = *gpd(freq_item, sizeofArray(freq_params), GNB_CONFIG_STRING_FREQUENCY_ABS_FREQ_SSB)->i64ptr; + f.scs = *gpd(freq_item, sizeofArray(freq_params), GNB_CONFIG_STRING_FREQUENCY_SCS)->uptr; + + char cfg_path[MAX_OPTNAME_SIZE + 16]; + snprintf(cfg_path, + sizeof(cfg_path), + "%s.[%i].%s.[%i]", + GNB_CONFIG_STRING_GNB_LIST, + gnb_idx, + GNB_CONFIG_STRING_FREQUENCY_LIST, + i); + GET_PARAMS(freq_cfg, GNBFREQUENCYCONFIGPARAMS_DESC, cfg_path); + + nr_neighbour_cell_sib4_freq_t *p = &f.freq_cfg; + + p->cellReselectionPriority = *freq_cfg[GNB_CONFIG_FREQUENCY_CELL_RESEL_PRIO_IDX].iptr; + p->threshX_HighP = *freq_cfg[GNB_CONFIG_FREQUENCY_THRESH_X_HIGH_P_IDX].iptr; + p->threshX_LowP = *freq_cfg[GNB_CONFIG_FREQUENCY_THRESH_X_LOW_P_IDX].iptr; + p->threshX_HighQ = *freq_cfg[GNB_CONFIG_FREQUENCY_THRESH_X_HIGH_Q_IDX].iptr; + p->threshX_LowQ = *freq_cfg[GNB_CONFIG_FREQUENCY_THRESH_X_LOW_Q_IDX].iptr; + p->q_OffsetFreq = *freq_cfg[GNB_CONFIG_FREQUENCY_Q_OFFSET_FREQ_IDX].iptr; + f.q_RxLevMin = *freq_cfg[GNB_CONFIG_FREQUENCY_Q_RXLEVMIN_IDX].iptr; + f.t_ReselectionNR = *freq_cfg[GNB_CONFIG_FREQUENCY_T_RESEL_NR_IDX].uptr; + + /* Add inter-frequency configuration to the list. */ + add_inter_freq(inter_freqs, &f, gnb_idx); + + LOG_I(GNB_APP, + "gNB %d: SIB4 inter-freq ARFCN %d, SCS %d, prio=%d, ThreshX_HighP=%d, ThreshX_LowP=%d, ThreshX_HighQ=%d, " + "ThreshX_LowQ=%d, q_OffsetFreq=%d\n", + gnb_idx, + f.arfcn, + f.scs, + f.freq_cfg.cellReselectionPriority, + f.freq_cfg.threshX_HighP, + f.freq_cfg.threshX_LowP, + f.freq_cfg.threshX_HighQ, + f.freq_cfg.threshX_LowQ, + f.freq_cfg.q_OffsetFreq); + } +} + +static void set_sib3_offsets(nr_neighbour_cell_t *n, const paramdef_t *cell_params, int n_cell_params) +{ + nr_neighbour_cell_neighbor_offset_t *sib3_off = &n->sib3.offset; + + /* SIB3 per-neighbour offsets */ + sib3_off->q_OffsetCell = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_OFFSET_CELL)->iptr; + sib3_off->q_RxLevMinOffsetCell = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_RXLEVMIN_OFFSET_CELL)->iptr; + sib3_off->q_QualMinOffsetCell = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_QUALMIN_OFFSET_CELL)->iptr; +} + +static void set_sib4_offsets(nr_neighbour_cell_t *n, const paramdef_t *cell_params, int n_cell_params) +{ + nr_neighbour_cell_neighbor_offset_t *sib4_off = &n->sib4.offset; + + /* SIB4 per-neighbour offsets */ + sib4_off->q_OffsetCell = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_OFFSET_CELL)->iptr; + sib4_off->q_RxLevMinOffsetCell = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_RXLEVMIN_OFFSET_CELL)->iptr; + sib4_off->q_QualMinOffsetCell = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_QUALMIN_OFFSET_CELL)->iptr; +} + +/** @brief Parse and add neighbour cells for a given cell configuration + * @param[in,out] cell Neighbour cell configuration to populate + * @param[in] list Parameter list describing neighbour cells + * @param[in] n_path Base path for neighbour configuration in the config tree + * @param[in] n_cell_params Number of neighbour-cell parameters */ +static void parse_neighbour_cells_list(neighbour_cell_configuration_t *cell, + const paramlist_def_t *list, + const char *n_path, + int n_cell_params) +{ + seq_arr_init(&cell->neighbour_cells, sizeof(nr_neighbour_cell_t)); + + /* Parse each neighbour cell in the list */ + for (int l = 0; l < list->numelt; ++l) { + const paramdef_t *cell_params = list->paramarray[l]; + nr_neighbour_cell_t n = { + .gNB_ID = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_GNB_ID)->uptr, + .nrcell_id = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NRCELLID)->u64ptr, + .physicalCellId = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID)->uptr, + .subcarrierSpacing = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS)->uptr, + .band = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_BAND)->uptr, + .absoluteFrequencySSB = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB)->i64ptr, + .tac = *gpd(cell_params, n_cell_params, GNB_CONFIG_STRING_NEIGHBOUR_TRACKING_ARE_CODE)->uptr}; + + set_sib3_offsets(&n, cell_params, n_cell_params); + set_sib4_offsets(&n, cell_params, n_cell_params); + /* SIB4 per-frequency reselection parameters (q_OffsetFreq, thresholds, priority) + * are populated in parse_inter_freq_list() per-frequency, not per neighbour here. */ + + char p[CONFIG_MAXOPTLENGTH]; // plmn path + snprintf(p, sizeof(p), "%s.%s.[%i].%s", n_path, GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, l, GNB_CONFIG_STRING_NEIGHBOUR_PLMN); + GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, p); + n.plmn = extract_plmn_from_params(NeighbourPlmn, sizeofArray(NeighbourPlmn)); + + LOG_I(GNB_APP, + "Neighbour[%d]: cellId %ld, PLMN %03u.%0*u, gNB %d, PCI %d, SCS %d, SSB ARFCN %u, TAC %u\n", + l, + n.nrcell_id, + n.plmn.mcc, + n.plmn.mnc_digit_length, + n.plmn.mnc, + n.gNB_ID, + n.physicalCellId, + n.subcarrierSpacing, + n.absoluteFrequencySSB, + n.tac); + + /* Check for duplicate PCI in the neighbour list */ + if (get_neighbour_by_pci(&cell->neighbour_cells, n.physicalCellId) != NULL) { + LOG_E(GNB_APP, "Cell %ld: duplicate PCI %d in neighbour list (NCI=%ld)\n", cell->nr_cell_id, n.physicalCellId, n.nrcell_id); + AssertFatal(false, "PCI must be unique within a cell's neighbour list\n"); + } + + seq_arr_push_back(&cell->neighbour_cells, &n, sizeof(n)); + } +} + +/** @brief Sort neighbour cell configuration by cell ID + * @param[in] rrc Pointer to RRC instance */ +static void sort_neighbour_configuration(gNB_RRC_INST *rrc) +{ void *base = seq_arr_front(rrc->neighbour_cell_configuration); size_t nmemb = seq_arr_size(rrc->neighbour_cell_configuration); size_t element_size = sizeof(neighbour_cell_configuration_t); - qsort(base, nmemb, element_size, sort_neighbour_cell_config_by_cell_id); } +/** @brief Fill neighbour cell configuration from config file + * @param[in] gnb_idx gNB index + * @param[in,out] rrc Pointer to RRC instance */ +static void fill_neighbour_cell_configuration(const uint8_t gnb_idx, gNB_RRC_INST *rrc) +{ + char path[MAX_OPTNAME_SIZE + 8]; + snprintf(path, sizeof(path), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx); + GET_PARAMS_LIST(nlist, nparams, GNB_NEIGHBOUR_LIST_PARAM_LIST, GNB_CONFIG_STRING_NEIGHBOUR_LIST, path); + + LOG_I(GNB_APP, "gNB %d: neighbour_list has %d serving cell(s)\n", gnb_idx, nlist.numelt); + if (nlist.numelt < 1) + return; + + /* Parse gNB-level inter-frequency configuration once and reuse it for all cells. */ + parse_inter_freq_list(&rrc->inter_freqs, gnb_idx); + + rrc->neighbour_cell_configuration = malloc_or_fail(sizeof(seq_arr_t)); + seq_arr_init(rrc->neighbour_cell_configuration, sizeof(neighbour_cell_configuration_t)); + + for (int elm = 0; elm < nlist.numelt; ++elm) { + neighbour_cell_configuration_t cell = {0}; + cell.nr_cell_id = *gpd(nlist.paramarray[elm], sizeofArray(nparams), GNB_CONFIG_STRING_NRCELLID)->u64ptr; + snprintf(path, sizeof(path), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm); + GET_PARAMS_LIST(ncell_list, ncell_params, GNBNEIGHBOURCELLPARAMS_DESC, GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, path); + LOG_I(GNB_APP, "Cell %ld has %d neighbours configured\n", cell.nr_cell_id, ncell_list.numelt); + if (ncell_list.numelt < 1) + continue; + parse_neighbour_cells_list(&cell, &ncell_list, path, sizeofArray(ncell_params)); + seq_arr_push_back(rrc->neighbour_cell_configuration, &cell, sizeof(cell)); + } + + sort_neighbour_configuration(rrc); +} + static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) { char measurement_path[MAX_OPTNAME_SIZE + 8]; @@ -2166,6 +2281,64 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) } } +/** @brief Parse and populate SIB2 configuration from config file + * @param[in] gnb_idx gNB index + * @return populated SIB2 configuration */ +static sib2_config_t fill_sib2_configuration(uint8_t gnb_idx) +{ + sib2_config_t sib2 = {0}; + + char sib2_path[MAX_OPTNAME_SIZE * 2 + 8]; + snprintf(sib2_path, sizeof(sib2_path), "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_SIB2_CONFIG); + + GET_PARAMS(SIB2Params, GNBSIB2PARAMS_DESC, sib2_path); + const int n_sib2_params = sizeofArray(SIB2Params); + + cell_reselection_info_common_t *common = &sib2.cell_reselection_info_common; + common->q_Hyst = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_Q_HYST)->iptr; + /* speedStateReselectionPars */ + common->speedStateReselectionPars = calloc_or_fail(1, sizeof(*common->speedStateReselectionPars)); + sib2_speed_state_reselection_pars_t *speed = common->speedStateReselectionPars; + + /* Cell reselection serving frequency information */ + cell_reselection_serving_freq_info_t *serv = &sib2.cell_reselection_serving_freq_info; + serv->cellReselectionPriority = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_CELLRESEL_PRIORITY)->iptr; + serv->threshServingLowP = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_P)->iptr; + serv->threshServingLowQ = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_Q)->iptr; + serv->s_NonIntraSearchP = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_P)->iptr; + serv->s_NonIntraSearchQ = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_Q)->iptr; + + /* Intra-frequency cell reselection parameters */ + intra_freq_cell_reselection_info_t *intra = &sib2.intra_freq_cell_reselection_info; + intra->q_RxLevMin = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_Q_RXLEVMIN)->iptr; + intra->q_QualMin = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_Q_QUALMIN)->iptr; + intra->s_IntraSearchP = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_P)->iptr; + intra->s_IntraSearchQ = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_Q)->iptr; + intra->t_ReselectionNR = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_T_RESEL_NR)->iptr; + + /* deriveSSB_IndexFromCell (0/1) */ + int derive_ssb = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_DERIVE_SSB_IDX)->iptr; + sib2.deriveSSB_IndexFromCell = (derive_ssb != 0); + + /* Speed-state pars: optional parameters are omitted from the config file (default applied), not set to -1. */ + speed->t_Evaluation = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_T_EVAL)->iptr; + speed->t_HystNormal = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_T_HYST_NORMAL)->iptr; + speed->n_CellChangeMedium = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_MED)->iptr; + speed->n_CellChangeHigh = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_HIGH)->iptr; + speed->sf_Medium = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_SF_MEDIUM)->iptr; + speed->sf_High = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_SF_HIGH)->iptr; + + LOG_I(GNB_APP, + "gNB %d SIB2 config: q_Hyst=%d dB, cellReselPrio=%d, q_RxLevMin=%d dBm, t_ReselectionNR=%d s\n", + gnb_idx, + common->q_Hyst, + serv->cellReselectionPriority, + intra->q_RxLevMin, + intra->t_ReselectionNR); + + return sib2; +} + /** * @brief Allocates and initializes RRC instances * Currently assuming 1 instance @@ -2265,6 +2438,9 @@ gNB_RRC_INST *RCconfig_NRRRC() }// }//End for (k=0; k sib2_config = fill_sib2_configuration(i); }//End if (num_gnbs>0) if (!NODE_IS_DU(rrc->node_type)) diff --git a/openair2/GNB_APP/gnb_config_common.c b/openair2/GNB_APP/gnb_config_common.c index 395af98750..aca2457d08 100644 --- a/openair2/GNB_APP/gnb_config_common.c +++ b/openair2/GNB_APP/gnb_config_common.c @@ -31,19 +31,28 @@ uint16_t set_snssai_config(nssai_t *nssai, const int max_num_ssi, uint8_t k, uin return num_ssi; } +/** @brief Extract PLMN from parameter array + * @param[in] params Parameter array containing PLMN fields + * @return plmn_id_t structure filled from parameters */ +plmn_id_t extract_plmn_from_params(const paramdef_t *params, int n_params) +{ + plmn_id_t plmn = {.mcc = *gpd(params, n_params, GNB_CONFIG_STRING_MOBILE_COUNTRY_CODE)->uptr, + .mnc = *gpd(params, n_params, GNB_CONFIG_STRING_MOBILE_NETWORK_CODE)->uptr, + .mnc_digit_length = *gpd(params, n_params, GNB_CONFIG_STRING_MNC_DIGIT_LENGTH)->uptr}; + AssertFatal((plmn.mnc_digit_length == 2) || (plmn.mnc_digit_length == 3), "BAD MNC DIGIT LENGTH %d", plmn.mnc_digit_length); + return plmn; +} + uint8_t set_plmn_config(plmn_id_t *p, uint8_t idx) { char gnbpath[MAX_OPTNAME_SIZE * 2 + 8]; snprintf(gnbpath, sizeof(gnbpath), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, idx); GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, gnbpath, PLMNPARAMS_CHECK); uint8_t num_plmn = PLMNParamList.numelt; + const int n_plmn_params = sizeofArray(PLMNParams); AssertFatal(num_plmn >= 1 && num_plmn <= 6, "The number of PLMN IDs must be in [1,6], but is %d\n", num_plmn); for (int l = 0; l < num_plmn; ++l) { - plmn_id_t *plmn = &p[l]; - plmn->mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - plmn->mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; - plmn->mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; - AssertFatal((plmn->mnc_digit_length == 2) || (plmn->mnc_digit_length == 3), "BAD MNC DIGIT LENGTH %d", plmn->mnc_digit_length); + p[l] = extract_plmn_from_params(PLMNParamList.paramarray[l], n_plmn_params); } return num_plmn; } diff --git a/openair2/GNB_APP/gnb_config_common.h b/openair2/GNB_APP/gnb_config_common.h index ae2ae4e799..bfa875c13d 100644 --- a/openair2/GNB_APP/gnb_config_common.h +++ b/openair2/GNB_APP/gnb_config_common.h @@ -4,6 +4,8 @@ #include #include "common/5g_platform_types.h" +#include "common/config/config_paramdesc.h" uint16_t set_snssai_config(nssai_t *nssai, const int max_num_ssi, uint8_t k, uint8_t l); uint8_t set_plmn_config(plmn_id_t *p, uint8_t idx); +plmn_id_t extract_plmn_from_params(const paramdef_t *params, int n_params); diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 8265303969..35a1c096d1 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -10,6 +10,7 @@ #define __GNB_APP_GNB_PARAMDEF__H__ #include "common/config/config_paramdesc.h" +#include "common/config/config_userapi.h" #include "common/ngran_types.h" #include "RRC_nr_paramsvalues.h" @@ -289,7 +290,6 @@ typedef enum { #define GNB_NEIGHBOUR_LIST_PARAM_LIST { \ /* optname helpstr paramflags XXXptr def val type numelt */ \ {GNB_CONFIG_STRING_NRCELLID, "cell nrCell Id which has neighbours", PARAMFLAG_MANDATORY, .u64ptr=NULL, .defint64val=0, TYPE_UINT64, 0}, \ - {GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID, "neighbour cell physical id", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ } // clang-format on #define GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST "neighbour_cell_configuration" @@ -300,27 +300,111 @@ typedef enum { #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" +/* SIB3 fields (intra-frequency) - per-neighbor */ +#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_OFFSET_CELL "q_OffsetCell" +#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_RXLEVMIN_OFFSET_CELL "q_RxLevMinOffsetCell" +#define GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_QUALMIN_OFFSET_CELL "q_QualMinOffsetCell" +/* SIB4 per-frequency fields are configured in frequency_list.frequency_config */ -#define GNB_CONFIG_N_CELL_GNB_ID_IDX 0 -#define GNB_CONFIG_N_CELL_NR_CELLID_IDX 1 -#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_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 */ \ - {GNB_CONFIG_STRING_GNB_ID, "neighbour cell's gNB ID", PARAMFLAG_MANDATORY, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \ - {GNB_CONFIG_STRING_NRCELLID, "neighbour cell nrCell Id", PARAMFLAG_MANDATORY, .u64ptr=NULL, .defint64val=0, TYPE_UINT64, 0}, \ - {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}, \ +#define GNBNEIGHBOURCELLPARAMS_DESC { /* optname helpstr paramflags XXXptr def val type numelt */ \ + {GNB_CONFIG_STRING_GNB_ID, \ + "neighbour cell's gNB ID", PARAMFLAG_MANDATORY, .uptr=NULL, .defintval=0, TYPE_UINT, 0, \ + .chkPptr=NULL}, \ + {GNB_CONFIG_STRING_NRCELLID, \ + "neighbour cell nrCell Id", PARAMFLAG_MANDATORY, .u64ptr=NULL, .defint64val=0, TYPE_UINT64, 0, \ + .chkPptr=NULL}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID, \ + "neighbour cell physical id", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_uintrange, {0, 1007}}}}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB, \ + "neighbour cell absolute frequency SSB (0..3279165)", PARAMFLAG_MANDATORY, .i64ptr=NULL, .defint64val=0, TYPE_INT64, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 3279165}}}}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS, \ + "neighbour cell scs (15/30/60/120 kHz)", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0, \ + .chkPptr = &(checkedparam_t){.s1 = {config_check_intval, {0, 1, 2, 3}, 4}}}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_CELL_BAND, \ + "neighbour cell band (1..1024)", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=78, TYPE_UINT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_uintrange, {1, 1024}}}}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_TRACKING_ARE_CODE, \ + "neighbour cell tracking area (0..16777215)", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_uintrange, {0, 16777215}}}}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_OFFSET_CELL, \ + "Q-OffsetCell for SIB3/SIB4 (Q-OffsetRange, default 0)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s1 = {config_check_intval, \ + {-24, -22, -20, -18, -16, -14, -12, -10, -8, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24}, 31}}}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_RXLEVMIN_OFFSET_CELL, \ + "Q-RxLevMinOffsetCell for SIB3/SIB4 (1..8 or -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s1 = {config_check_intval, {-1, 1, 2, 3, 4, 5, 6, 7, 8}, 9}}}, \ + {GNB_CONFIG_STRING_NEIGHBOUR_CELL_Q_QUALMIN_OFFSET_CELL, \ + "Q-QualMinOffsetCell for SIB3/SIB4 (1..8 or -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s1 = {config_check_intval, {-1, 1, 2, 3, 4, 5, 6, 7, 8}, 9}}}, \ } // clang-format on +/* Per-frequency neighbour configuration (frequency_list) */ +#define GNB_CONFIG_STRING_FREQUENCY_LIST "frequency_list" +#define GNB_CONFIG_STRING_FREQUENCY_ABS_FREQ_SSB "absoluteFrequencySSB" +#define GNB_CONFIG_STRING_FREQUENCY_SCS "subcarrierSpacing" +#define GNB_CONFIG_STRING_FREQUENCY_BAND "band" +#define GNB_CONFIG_STRING_FREQUENCY_CONFIG "frequency_config" + +#define GNB_CONFIG_STRING_FREQUENCY_CELL_RESEL_PRIO "cellReselectionPriority" +#define GNB_CONFIG_STRING_FREQUENCY_THRESH_X_HIGH_P "threshX_HighP" +#define GNB_CONFIG_STRING_FREQUENCY_THRESH_X_LOW_P "threshX_LowP" +#define GNB_CONFIG_STRING_FREQUENCY_THRESH_X_HIGH_Q "threshX_HighQ" +#define GNB_CONFIG_STRING_FREQUENCY_THRESH_X_LOW_Q "threshX_LowQ" +#define GNB_CONFIG_STRING_FREQUENCY_Q_OFFSET_FREQ "q_OffsetFreq" +#define GNB_CONFIG_STRING_FREQUENCY_Q_RXLEVMIN "q_RxLevMin" +#define GNB_CONFIG_STRING_FREQUENCY_T_RESEL_NR "t_ReselectionNR" + +// clang-format off +#define GNBFREQUENCYPARAMS_DESC { \ +/* optname helpstr paramflags XXXptr def val type numelt */ \ + {GNB_CONFIG_STRING_FREQUENCY_ABS_FREQ_SSB, "inter-frequency abs freq ssb", PARAMFLAG_MANDATORY, .i64ptr=NULL, .defint64val=0, TYPE_INT64, 0}, \ + {GNB_CONFIG_STRING_FREQUENCY_SCS, "inter-frequency scs", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \ + {GNB_CONFIG_STRING_FREQUENCY_BAND, "inter-frequency band", PARAMFLAG_MANDATORY, .uptr=NULL, .defuintval=78, TYPE_UINT, 0}, \ +} + +#define GNBFREQUENCYCONFIGPARAMS_DESC { \ + {GNB_CONFIG_STRING_FREQUENCY_CELL_RESEL_PRIO, \ + "SIB4 cellReselectionPriority (0..7, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 7}}}}, \ + {GNB_CONFIG_STRING_FREQUENCY_THRESH_X_HIGH_P, \ + "SIB4 threshX-HighP (0..31)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 31}}}}, \ + {GNB_CONFIG_STRING_FREQUENCY_THRESH_X_LOW_P, \ + "SIB4 threshX-LowP (0..31)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 31}}}}, \ + {GNB_CONFIG_STRING_FREQUENCY_THRESH_X_HIGH_Q, \ + "SIB4 threshX-HighQ (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \ + {GNB_CONFIG_STRING_FREQUENCY_THRESH_X_LOW_Q, \ + "SIB4 threshX-LowQ (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \ + {GNB_CONFIG_STRING_FREQUENCY_Q_OFFSET_FREQ, \ + "SIB4 q-OffsetFreq (Q-OffsetRange values, default 0)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s1 = {config_check_intval, {-24, -22, -20, -18, -16, -14, -12, -10, \ + -8, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24}, 31}}}, \ + {GNB_CONFIG_STRING_FREQUENCY_Q_RXLEVMIN, \ + "SIB4 per-carrier Q-RxLevMin (-70..-22, default -22)", 0, .iptr=NULL, .defintval=-22, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-70, -22}}}}, \ + {GNB_CONFIG_STRING_FREQUENCY_T_RESEL_NR, \ + "SIB4 per-carrier t-ReselectionNR (0..7, default 0)", 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_uintrange, {0, 7}}}}, \ +} +// clang-format on + +/* Indexes into GNBFREQUENCYCONFIGPARAMS_DESC */ +#define GNB_CONFIG_FREQUENCY_CELL_RESEL_PRIO_IDX 0 +#define GNB_CONFIG_FREQUENCY_THRESH_X_HIGH_P_IDX 1 +#define GNB_CONFIG_FREQUENCY_THRESH_X_LOW_P_IDX 2 +#define GNB_CONFIG_FREQUENCY_THRESH_X_HIGH_Q_IDX 3 +#define GNB_CONFIG_FREQUENCY_THRESH_X_LOW_Q_IDX 4 +#define GNB_CONFIG_FREQUENCY_Q_OFFSET_FREQ_IDX 5 +#define GNB_CONFIG_FREQUENCY_Q_RXLEVMIN_IDX 6 +#define GNB_CONFIG_FREQUENCY_T_RESEL_NR_IDX 7 + /* New Measurement Configurations*/ #define GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION "nr_measurement_configuration" @@ -369,6 +453,95 @@ typedef enum { #define MEASUREMENT_EVENTS_INCLUDE_BEAM_MEAS_IDX 1 #define MEASUREMENT_EVENTS_MAX_RS_INDEX_TO_REPORT 2 +/*-------------------------------------------------------------------------------------------------------------------------------------*/ +/* SIB2 cell reselection configuration parameters */ +/*-------------------------------------------------------------------------------------------------------------------------------------*/ + +#define GNB_CONFIG_STRING_SIB2_CONFIG "sib2_config" + +/* clang-format off */ + +/* SIB2 top-level parameters (per cell) */ +#define GNB_CONFIG_STRING_SIB2_Q_HYST "q_Hyst" +#define GNB_CONFIG_STRING_SIB2_CELLRESEL_PRIORITY "cellReselectionPriority" +#define GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_P "threshServingLowP" +#define GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_Q "threshServingLowQ" +#define GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_P "s_NonIntraSearchP" +#define GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_Q "s_NonIntraSearchQ" +#define GNB_CONFIG_STRING_SIB2_Q_RXLEVMIN "q_RxLevMin" +#define GNB_CONFIG_STRING_SIB2_Q_QUALMIN "q_QualMin" +#define GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_P "s_IntraSearchP" +#define GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_Q "s_IntraSearchQ" +#define GNB_CONFIG_STRING_SIB2_T_RESEL_NR "t_ReselectionNR" +#define GNB_CONFIG_STRING_SIB2_DERIVE_SSB_IDX "deriveSSB_IndexFromCell" + +/* SIB2 speedStateReselectionPars parameters */ +#define GNB_CONFIG_STRING_SIB2_SPEED_T_EVAL "speed_t_Evaluation" +#define GNB_CONFIG_STRING_SIB2_SPEED_T_HYST_NORMAL "speed_t_HystNormal" +#define GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_MED "speed_n_CellChangeMedium" +#define GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_HIGH "speed_n_CellChangeHigh" +#define GNB_CONFIG_STRING_SIB2_SPEED_SF_MEDIUM "speed_sf_Medium" +#define GNB_CONFIG_STRING_SIB2_SPEED_SF_HIGH "speed_sf_High" + +#define GNBSIB2PARAMS_DESC { /* optname helpstr paramflags XXXptr def val type numelt */ \ + {GNB_CONFIG_STRING_SIB2_Q_HYST, \ + "SIB2 q-Hyst (0,1,2,3,4,5,6,8,10..24 dB)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s1 = {config_check_intval, {0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24}, 16}}}, \ + {GNB_CONFIG_STRING_SIB2_CELLRESEL_PRIORITY, \ + "SIB2 cellReselectionPriority (0..7)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 7}}}}, \ + {GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_P, \ + "SIB2 threshServingLowP (0..31)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 31}}}}, \ + {GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_Q, \ + "SIB2 threshServingLowQ (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \ + {GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_P, \ + "SIB2 s-NonIntraSearchP (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \ + {GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_Q, \ + "SIB2 s-NonIntraSearchQ (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \ + {GNB_CONFIG_STRING_SIB2_Q_RXLEVMIN, \ + "SIB2 q-RxLevMin (-70..-22)", 0, .iptr=NULL, .defintval=-56, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-70, -22}}}}, \ + {GNB_CONFIG_STRING_SIB2_Q_QUALMIN, \ + "SIB2 q-QualMin (-43..-12 or -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s1 = {config_check_intval, \ + {-1, -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}, 33}}}, \ + {GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_P, \ + "SIB2 s-IntraSearchP (0..31)", 0, .iptr=NULL, .defintval=22, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 31}}}}, \ + {GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_Q, \ + "SIB2 s-IntraSearchQ (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \ + {GNB_CONFIG_STRING_SIB2_T_RESEL_NR, \ + "SIB2 t-ReselectionNR (0..7)", 0, .iptr=NULL, .defintval=1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 7}}}}, \ + {GNB_CONFIG_STRING_SIB2_DERIVE_SSB_IDX, \ + "SIB2 deriveSSB-IndexFromCell (0/1)", PARAMFLAG_BOOL, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \ + {GNB_CONFIG_STRING_SIB2_SPEED_T_EVAL, \ + "SIB2 speed t-Evaluation (0=s30,1=s60,2=s120,3=s180,4=s240)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 4}}}}, \ + {GNB_CONFIG_STRING_SIB2_SPEED_T_HYST_NORMAL, \ + "SIB2 speed t-HystNormal (0=s30,1=s60,2=s120,3=s180,4=s240)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 4}}}}, \ + {GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_MED, \ + "SIB2 speed n-CellChangeMedium (1..16)", 0, .iptr=NULL, .defintval=1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {1, 16}}}}, \ + {GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_HIGH, \ + "SIB2 speed n-CellChangeHigh (1..16)", 0, .iptr=NULL, .defintval=2, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {1, 16}}}}, \ + {GNB_CONFIG_STRING_SIB2_SPEED_SF_MEDIUM, \ + "SIB2 speed sf-Medium (0=dB-6,1=dB-4,2=dB-2,3=dB0)", 0, .iptr=NULL, .defintval=1, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 3}}}}, \ + {GNB_CONFIG_STRING_SIB2_SPEED_SF_HIGH, \ + "SIB2 speed sf-High (0=dB-6,1=dB-4,2=dB-2,3=dB0)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \ + .chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 3}}}}, \ +} +/* clang-format on */ + /* PLMN ID configuration */ #define GNB_CONFIG_STRING_PLMN_LIST "plmn_list" diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 6ecba2e923..d56b921b48 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -15,6 +15,8 @@ #include "common/utils/nr/nr_common.h" #include "executables/softmodem-common.h" #include "SCHED_NR/phy_frame_config_nr.h" +#include "RRC/NR_UE/verify_RRC.h" +#include "RRC/NR_UE/L2_interface_ue.h" #include "oai_asn1.h" #define ASIGN_P_VAL(dst, src) \ @@ -2552,7 +2554,9 @@ static void modify_csi_measconfig(NR_CSI_MeasConfig_t *source, NR_CSI_MeasConfig } } -static void configure_csiconfig(NR_UE_ServingCell_Info_t *sc_info, struct NR_SetupRelease_CSI_MeasConfig *csi_MeasConfig_sr) +static void configure_csiconfig(NR_UE_ServingCell_Info_t *sc_info, + struct NR_SetupRelease_CSI_MeasConfig *csi_MeasConfig_sr, + module_id_t ue_id) { switch (csi_MeasConfig_sr->present) { case NR_SetupRelease_CSI_MeasConfig_PR_NOTHING: @@ -2574,6 +2578,8 @@ static void configure_csiconfig(NR_UE_ServingCell_Info_t *sc_info, struct NR_Set } else { // modification modify_csi_measconfig(csi_MeasConfig_sr->choice.setup, sc_info->csi_MeasConfig); } + if (!check_csi_report_consistency(sc_info->csi_MeasConfig)) + nr_mac_rrc_verification_failed(ue_id); break; } default: @@ -2585,7 +2591,7 @@ static void configure_servingcell_info(NR_UE_MAC_INST_t *mac, NR_ServingCellConf { NR_UE_ServingCell_Info_t *sc_info = &mac->sc_info; if (scd->csi_MeasConfig) { - configure_csiconfig(sc_info, scd->csi_MeasConfig); + configure_csiconfig(sc_info, scd->csi_MeasConfig, mac->ue_id); compute_csi_bitlen(sc_info->csi_MeasConfig, mac->csi_report_template); } diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp index ae79c87aee..0fb34a9a37 100644 --- a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp +++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp @@ -42,7 +42,9 @@ void nr_mac_rlc_data_ind(const module_id_t module_idP, int num_data) { } - +void nr_mac_rrc_verification_failed(const module_id_t mod_id) +{ +} bool nr_rlc_activate_srb0(int ue_id, void *data, void (*send_initial_ul_rrc_message)(int ue_id, const uint8_t *sdu, sdu_size_t sdu_len, void *data)) @@ -77,6 +79,10 @@ int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, { return 0; } +bool check_csi_report_consistency(const NR_CSI_MeasConfig_t *meas) +{ + return true; +} void nr_mac_rrc_meas_ind_ue(module_id_t module_id, uint32_t gNB_index, uint16_t Nid_cell, diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 202590f9fc..1d217b7c72 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -988,27 +988,56 @@ bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_ NR_SystemInformation_IEs_t *sysInfov17 = calloc(1, sizeof(*sysInfov17)); // for othersibs for (int i = 0; i < num_cu_sib; i++) { config_sibs[i] = cu_sib[i].SI_type; + const byte_array_t *container = &cu_sib[i].SI_container; + if (!container->buf || container->len == 0) { + LOG_W(NR_MAC, "SIB%d container is invalid (ptr=%p len=%zu), skipping\n", config_sibs[i], container->buf, container->len); + continue; + } switch (config_sibs[i]) { - case 2: { + case NR_SIB_2: { struct NR_SystemInformation_IEs__sib_TypeAndInfo__Member *type = calloc(1, sizeof(*type)); type->present = NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib2; // SIB2 coming from CU need to decode it NR_SIB2_t *sib2 = NULL; - asn_dec_rval_t dec_rval = uper_decode(NULL, - &asn_DEF_NR_SIB2, - (void **)&sib2, - cu_sib[i].SI_container, - cu_sib[i].SI_container_length, - 0, - 0); + asn_dec_rval_t dec_rval = uper_decode(NULL, &asn_DEF_NR_SIB2, (void **)&sib2, container->buf, container->len, 0, 0); if (dec_rval.code != RC_OK) { LOG_E(NR_MAC, "cannot decode SIB%d from CU\n", config_sibs[i]); - ASN_STRUCT_FREE(asn_DEF_NR_SIB2, cu_sib[i].SI_container); + ASN_STRUCT_FREE(asn_DEF_NR_SIB2, sib2); } type->choice.sib2 = sib2; add_sib_to_systeminformation(sysInfo, type); break; } + case NR_SIB_3: { + struct NR_SystemInformation_IEs__sib_TypeAndInfo__Member *type = calloc_or_fail(1, sizeof(*type)); + type->present = NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib3; + NR_SIB3_t *sib3 = NULL; + asn_dec_rval_t dec_rval = uper_decode(NULL, &asn_DEF_NR_SIB3, (void **)&sib3, container->buf, container->len, 0, 0); + if (dec_rval.code != RC_OK) { + LOG_E(NR_MAC, "cannot decode SIB%d from CU\n", config_sibs[i]); + ASN_STRUCT_FREE(asn_DEF_NR_SIB3, sib3); + free(type); + break; + } + type->choice.sib3 = sib3; + add_sib_to_systeminformation(sysInfo, type); + break; + } + case NR_SIB_4: { + struct NR_SystemInformation_IEs__sib_TypeAndInfo__Member *type = calloc_or_fail(1, sizeof(*type)); + type->present = NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib4; + NR_SIB4_t *sib4 = NULL; + asn_dec_rval_t dec_rval = uper_decode(NULL, &asn_DEF_NR_SIB4, (void **)&sib4, container->buf, container->len, 0, 0); + if (dec_rval.code != RC_OK) { + LOG_E(NR_MAC, "cannot decode SIB%d from CU\n", config_sibs[i]); + ASN_STRUCT_FREE(asn_DEF_NR_SIB4, sib4); + free(type); + break; + } + type->choice.sib4 = sib4; + add_sib_to_systeminformation(sysInfo, type); + break; + } default : AssertFatal(false, "Invalid or not supported SIB%d\n", config_sibs[i]); } @@ -1019,7 +1048,7 @@ bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_ int sib_idx = i + num_cu_sib; config_sibs[sib_idx] = si->SIB_type; switch (config_sibs[sib_idx]) { - case 19: { + case NR_SIB_19: { 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); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 6b2c9e23ac..3341455e45 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -7,7 +7,6 @@ */ #include "common/platform_types.h" -#include "uper_decoder.h" /* MAC */ #include "nr_mac_gNB.h" @@ -24,8 +23,6 @@ #include -static void nr_fill_rar(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}; static int16_t ssb_index_from_prach(module_id_t module_idP, @@ -1027,6 +1024,126 @@ static bool get_feasible_msg3_tda(const NR_ServingCellConfigCommon_t *scc, return false; } +///////////////////////////////////// +// Random Access Response PDU // +// TS 38.213 ch 8.2 // +// TS 38.321 ch 6.2.3 // +///////////////////////////////////// +//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise +//| E | T | R A P I D |// +//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// +//| R | T A |// +//| T A | UL grant |// +//| UL grant |// +//| UL grant |// +//| UL grant |// +//| T C - R N T I |// +//| T C - R N T I |// +///////////////////////////////////// +// UL grant (27 bits) // +///////////////////////////////////// +//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise +//|-------------------|FHF|F_alloc|// +//| Freq allocation |// +//| F_alloc |Time allocation|// +//| MCS | TPC |CSI|// +///////////////////////////////////// +// WIP +// todo: +// - handle MAC RAR BI subheader +// - sending only 1 RAR subPDU +// - UL Grant: hardcoded CSI, TPC, time alloc +// - padding +static void nr_fill_rar(NR_UE_info_t *UE, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu) +{ + NR_RA_t *ra = UE->ra; + LOG_D(NR_MAC, + "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u TA command %d \n", + ra->Msg2_frame, + ra->Msg2_slot, + ra->preamble_index, + ra->timing_offset); + NR_RA_HEADER_BI *rarbi = (NR_RA_HEADER_BI *) dlsch_buffer; + NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) (dlsch_buffer + 1); + NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 2); + unsigned char csi_req = 0; + + /// E/T/R/R/BI subheader /// + // E = 1, MAC PDU includes another MAC sub-PDU (RAPID) + // T = 0, Back-off indicator subheader + // R = 2, Reserved + // BI = 0, 5ms + rarbi->E = 1; + rarbi->T = 0; + rarbi->R = 0; + rarbi->BI = 0; + + /// E/T/RAPID subheader /// + // E = 0, one only RAR, first and last + // T = 1, RAPID + rarh->E = 0; + rarh->T = 1; + rarh->RAPID = ra->preamble_index; + + /// RAR MAC payload /// + rar->R = 0; + + // TA command + rar->TA1 = (uint8_t) (ra->timing_offset >> 5); // 7 MSBs of timing advance + rar->TA2 = (uint8_t) (ra->timing_offset & 0x1f); // 5 LSBs of timing advance + + // TC-RNTI + rar->TCRNTI_1 = (uint8_t) (UE->rnti >> 8); // 8 MSBs of rnti + rar->TCRNTI_2 = (uint8_t) (UE->rnti & 0xff); // 8 LSBs of rnti + + // UL grant + + if (pusch_pdu->frequency_hopping) + AssertFatal(1==0,"PUSCH with frequency hopping currently not supported"); + + int bwp_size = pusch_pdu->bwp_size; + int prb_alloc = PRBalloc_to_locationandbandwidth0(ra->msg3_nb_rb, ra->msg3_first_rb, bwp_size); + int valid_bits = 14; + int f_alloc = prb_alloc & ((1 << valid_bits) - 1); + + uint32_t ul_grant = csi_req | (ra->msg3_TPC << 1) | (pusch_pdu->mcs_index << 4) | (ra->Msg3_tda_id << 8) | (f_alloc << 12) | (pusch_pdu->frequency_hopping << 26); + + rar->UL_GRANT_1 = (uint8_t) (ul_grant >> 24) & 0x07; + rar->UL_GRANT_2 = (uint8_t) (ul_grant >> 16) & 0xff; + rar->UL_GRANT_3 = (uint8_t) (ul_grant >> 8) & 0xff; + rar->UL_GRANT_4 = (uint8_t) ul_grant & 0xff; + +#ifdef DEBUG_RAR + LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E); + LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T); + LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID); + LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R); + LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1); + LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2); + LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1); + LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2); + LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3); + LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4); + LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1); + LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2); +#endif + LOG_D(NR_MAC, + "In %s: Transmitted RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d csi_req %d t_crnti " + "%x \n", + __FUNCTION__, + rar->UL_GRANT_3 & 0x0f, + (rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12), + rar->TA2 + (rar->TA1 << 5), + rar->UL_GRANT_4 >> 4, + rar->UL_GRANT_1 >> 2, + ra->msg3_TPC, + csi_req, + rar->TCRNTI_2 + (rar->TCRNTI_1 << 8)); + + // resetting msg3 TPC to 0dB for possible retransmissions + ra->msg3_TPC = 1; +} + static bool nr_get_Msg3alloc(gNB_MAC_INST *mac, int CC_id, int current_slot, frame_t current_frame, NR_UE_info_t *UE) { NR_RA_t *ra = UE->ra; @@ -1964,126 +2081,6 @@ bool nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, N return false; } -///////////////////////////////////// -// Random Access Response PDU // -// TS 38.213 ch 8.2 // -// TS 38.321 ch 6.2.3 // -///////////////////////////////////// -//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise -//| E | T | R A P I D |// -//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// -//| R | T A |// -//| T A | UL grant |// -//| UL grant |// -//| UL grant |// -//| UL grant |// -//| T C - R N T I |// -//| T C - R N T I |// -///////////////////////////////////// -// UL grant (27 bits) // -///////////////////////////////////// -//| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |// bit-wise -//|-------------------|FHF|F_alloc|// -//| Freq allocation |// -//| F_alloc |Time allocation|// -//| MCS | TPC |CSI|// -///////////////////////////////////// -// WIP -// todo: -// - handle MAC RAR BI subheader -// - sending only 1 RAR subPDU -// - UL Grant: hardcoded CSI, TPC, time alloc -// - padding -static void nr_fill_rar(NR_UE_info_t *UE, uint8_t *dlsch_buffer, nfapi_nr_pusch_pdu_t *pusch_pdu) -{ - NR_RA_t *ra = UE->ra; - LOG_D(NR_MAC, - "[gNB] Generate RAR MAC PDU frame %d slot %d preamble index %u TA command %d \n", - ra->Msg2_frame, - ra->Msg2_slot, - ra->preamble_index, - ra->timing_offset); - NR_RA_HEADER_BI *rarbi = (NR_RA_HEADER_BI *) dlsch_buffer; - NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) (dlsch_buffer + 1); - NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 2); - unsigned char csi_req = 0; - - /// E/T/R/R/BI subheader /// - // E = 1, MAC PDU includes another MAC sub-PDU (RAPID) - // T = 0, Back-off indicator subheader - // R = 2, Reserved - // BI = 0, 5ms - rarbi->E = 1; - rarbi->T = 0; - rarbi->R = 0; - rarbi->BI = 0; - - /// E/T/RAPID subheader /// - // E = 0, one only RAR, first and last - // T = 1, RAPID - rarh->E = 0; - rarh->T = 1; - rarh->RAPID = ra->preamble_index; - - /// RAR MAC payload /// - rar->R = 0; - - // TA command - rar->TA1 = (uint8_t) (ra->timing_offset >> 5); // 7 MSBs of timing advance - rar->TA2 = (uint8_t) (ra->timing_offset & 0x1f); // 5 LSBs of timing advance - - // TC-RNTI - rar->TCRNTI_1 = (uint8_t) (UE->rnti >> 8); // 8 MSBs of rnti - rar->TCRNTI_2 = (uint8_t) (UE->rnti & 0xff); // 8 LSBs of rnti - - // UL grant - - if (pusch_pdu->frequency_hopping) - AssertFatal(1==0,"PUSCH with frequency hopping currently not supported"); - - int bwp_size = pusch_pdu->bwp_size; - int prb_alloc = PRBalloc_to_locationandbandwidth0(ra->msg3_nb_rb, ra->msg3_first_rb, bwp_size); - int valid_bits = 14; - int f_alloc = prb_alloc & ((1 << valid_bits) - 1); - - uint32_t ul_grant = csi_req | (ra->msg3_TPC << 1) | (pusch_pdu->mcs_index << 4) | (ra->Msg3_tda_id << 8) | (f_alloc << 12) | (pusch_pdu->frequency_hopping << 26); - - rar->UL_GRANT_1 = (uint8_t) (ul_grant >> 24) & 0x07; - rar->UL_GRANT_2 = (uint8_t) (ul_grant >> 16) & 0xff; - rar->UL_GRANT_3 = (uint8_t) (ul_grant >> 8) & 0xff; - rar->UL_GRANT_4 = (uint8_t) ul_grant & 0xff; - -#ifdef DEBUG_RAR - LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E); - LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T); - LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID); - LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R); - LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1); - LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2); - LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1); - LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2); - LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3); - LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4); - LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1); - LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2); -#endif - LOG_D(NR_MAC, - "In %s: Transmitted RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d csi_req %d t_crnti " - "%x \n", - __FUNCTION__, - rar->UL_GRANT_3 & 0x0f, - (rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12), - rar->TA2 + (rar->TA1 << 5), - rar->UL_GRANT_4 >> 4, - rar->UL_GRANT_1 >> 2, - ra->msg3_TPC, - csi_req, - rar->TCRNTI_2 + (rar->TCRNTI_1 << 8)); - - // resetting msg3 TPC to 0dB for possible retransmissions - ra->msg3_TPC = 1; -} - /** @brief remove the UE with RNTI rnti from list of UEs doing RA. * * The corresponding function to add is add_new_UE_RA(). */ diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 81e1ab1819..6e2e4970a0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -16,16 +16,12 @@ #include "UTIL/OPT/opt.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h" -#include "F1AP_CauseRadioNetwork.h" - #include "intertask_interface.h" #include "openair2/F1AP/f1ap_ids.h" #include "F1AP_CauseRadioNetwork.h" #include "T.h" - #include "uper_encoder.h" -#include "uper_decoder.h" #include "SIMULATION/TOOLS/sim.h" // for taus @@ -96,11 +92,6 @@ static const uint16_t cqi_table3[16][2] = {{0, 0}, {6, 6660}, {6, 7720}}; -static void determine_aggregation_level_search_order(int agg_level_search_order[NUM_PDCCH_AGG_LEVELS], - float pdcch_cl_adjust); - -static int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots, int slots_per_frame); - int get_ssbidx_from_beam(gNB_MAC_INST *mac, int beam_idx) { for (int i = 0; i < MAX_NUM_OF_SSB; i++) @@ -570,6 +561,21 @@ int find_pdcch_candidate(const gNB_MAC_INST *mac, return -1; } +/// @brief Orders PDCCH aggregation levels so that we first check desired aggregation level according to +/// pdcch_cl_adjust +/// @param agg_level_search_order in/out 5-element array of aggregation levels from 0 to 4 +/// @param pdcch_cl_adjust value from 0 to 1 indication channel impariments (0 - good channel, 1 - bad channel) +static void determine_aggregation_level_search_order(int agg_level_search_order[NUM_PDCCH_AGG_LEVELS], float pdcch_cl_adjust) +{ + int desired_agg_level_index = round(4 * pdcch_cl_adjust); + int agg_level_search_index = 0; + for (int i = desired_agg_level_index; i < NUM_PDCCH_AGG_LEVELS; i++) { + agg_level_search_order[agg_level_search_index++] = i; + } + for (int i = desired_agg_level_index - 1; i >= 0; i--) { + agg_level_search_order[agg_level_search_index++] = i; + } +} int get_cce_index(const gNB_MAC_INST *nrmac, const int CC_id, @@ -3448,6 +3454,25 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt } } +static void nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots, int slots_per_frame) +{ + DevAssert(mac != NULL); + DevAssert(UE != NULL); + NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); + + nr_timer_setup(&UE->UE_sched_ctrl.transm_interrupt, slots, 1); + nr_timer_start(&UE->UE_sched_ctrl.transm_interrupt); + + // it might happen that timing advance command should be sent during the UE inactivity time. + // To prevent this, delay next TA command just after the UE inactivity time. + const int inactive_frames = slots / slots_per_frame + 1; + if ((UE->UE_sched_ctrl.ta_frame - mac->frame + MAX_FRAME_NUMBER) % MAX_FRAME_NUMBER < inactive_frames) + UE->UE_sched_ctrl.ta_frame = (mac->frame + inactive_frames) % MAX_FRAME_NUMBER; + + LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots)\n", UE->rnti, slots); +} + + void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot) { NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock); @@ -3517,25 +3542,6 @@ int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs) return (delay_ms << scs) + sl_ahead; } -static int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots, int slots_per_frame) -{ - DevAssert(mac != NULL); - DevAssert(UE != NULL); - NR_SCHED_ENSURE_LOCKED(&mac->sched_lock); - - nr_timer_setup(&UE->UE_sched_ctrl.transm_interrupt, slots, 1); - nr_timer_start(&UE->UE_sched_ctrl.transm_interrupt); - - // it might happen that timing advance command should be sent during the UE inactivity time. - // To prevent this, delay next TA command just after the UE inactivity time. - const int inactive_frames = slots / slots_per_frame + 1; - if ((UE->UE_sched_ctrl.ta_frame - mac->frame + MAX_FRAME_NUMBER) % MAX_FRAME_NUMBER < inactive_frames) - UE->UE_sched_ctrl.ta_frame = (mac->frame + inactive_frames) % MAX_FRAME_NUMBER; - - 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); @@ -4120,22 +4126,6 @@ bool nr_mac_get_new_rnti(NR_UEs_t *UEs, rnti_t *rnti) return loop < 100; // nothing found: loop count 100 } -/// @brief Orders PDCCH aggregation levels so that we first check desired aggregation level according to -/// pdcch_cl_adjust -/// @param agg_level_search_order in/out 5-element array of aggregation levels from 0 to 4 -/// @param pdcch_cl_adjust value from 0 to 1 indication channel impariments (0 - good channel, 1 - bad channel) -static void determine_aggregation_level_search_order(int agg_level_search_order[NUM_PDCCH_AGG_LEVELS], float pdcch_cl_adjust) -{ - int desired_agg_level_index = round(4 * pdcch_cl_adjust); - int agg_level_search_index = 0; - for (int i = desired_agg_level_index; i < NUM_PDCCH_AGG_LEVELS; i++) { - agg_level_search_order[agg_level_search_index++] = i; - } - for (int i = desired_agg_level_index - 1; i >= 0; i--) { - agg_level_search_order[agg_level_search_index++] = i; - } -} - /// @brief Update PDCCH closed loop adjust for UE depending on detection of feedback. /// @param sched_ctrl UE scheduling control info /// @param feedback_not_detected Whether feedback (PUSCH or HARQ) was detected @@ -4200,6 +4190,21 @@ void nr_mac_pc_snr(nr_power_control_t *pc, int snrx10, int rssi) pc->tpc_in_flight = PC_AVG_CNST * pc->tpc_in_flight; // + (1 - PC_AVG_CNST) * 0.0f } +/** + * @brief Enter new SNR and RSSI value for the latest UL transmission as new + * fixed averages. Reset "TPC in flight" to zero. + * + * @param pc the power control loop + * @param snrx10 the current SNR measurement multiplied by 10 + * @param rssi the current RSSI measurement + */ +void nr_mac_pc_reset_snr(nr_power_control_t *pc, int snrx10, int rssi) +{ + pc->avg_snr = 0.1f * snrx10; + pc->avg_rssi = rssi; + pc->tpc_in_flight = 0.0f; +} + /** * @brief Set a new target SNR for this power control loop, which can be * updated on a continuous basis, and will be reflected immediately upon diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index a6f66d738a..d0ab235276 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -910,6 +910,9 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con NR_SCHED_UNLOCK(&nrmac->sched_lock); return; } + // Msg4 Ack: reset average with first measurement + if (uci_01->ul_cqi != 0xff) + nr_mac_pc_reset_snr(&UE->UE_sched_ctrl.pucch_pc, uci_01->ul_cqi * 5 - 640, uci_01->rssi); } if (harq_confidence == 1) { UE->mac_stats.pucch0_DTX++; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index be869d9de9..f1fbbe2dfc 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -762,11 +762,9 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, } if (ul_cqi != 0xff) { - NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - // Msg3: reset average. If this fails (e.g., ul_cqi == 0xff) + // Msg3: reset average with first measurement. If this fails (e.g., ul_cqi == 0xff) // everything starts from predetermined value - sched_ctrl->pusch_pc.avg_snr = 0.1 * (ul_cqi * 5 - 640); - sched_ctrl->pusch_pc.avg_rssi = rssi; + nr_mac_pc_reset_snr(&UE->UE_sched_ctrl.pusch_pc, ul_cqi * 5 - 640, rssi); } if (!sdu) { // NACK @@ -2528,34 +2526,6 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE 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 void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch) { int frame = pp_pusch->frame; @@ -2579,8 +2549,8 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp // FAPI cannot handle more than MAX_DCI_CORESET DCIs max_dci = min(max_dci, MAX_DCI_CORESET); - fsn_t current = {frame, slot}; - fsn_t min_next = fs_add_delta(fs, min_rxtx, current); + fsn_t current = {frame, slot, *scc->ssbSubcarrierSpacing}; + fsn_t min_next = fsn_add_delta(current, min_rxtx); /* 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 @@ -2589,16 +2559,16 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp 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); + *next = fsn_get_max(*next, min_next); while (!is_ul_slot(next->s, fs)) - *next = fs_add_delta(fs, 1, *next); + *next = fsn_add_delta(*next, 1); 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; + int k2 = fsn_get_diff(*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 @@ -2631,7 +2601,7 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp break; max_dci -= sched; - *next = fs_add_delta(fs, 1, *next); + *next = fsn_add_delta(*next, 1); } } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index fb2f12e6d2..5aeace199c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -500,6 +500,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE float nr_mac_get_snr(const nr_power_control_t *pc); void nr_mac_pc_snr(nr_power_control_t *pc, int snrx10, int rssi); +void nr_mac_pc_reset_snr(nr_power_control_t *pc, int snrx10, int rssi); void nr_mac_set_target_snrx10(nr_power_control_t *pc, int target_snrx10); void nr_mac_set_rssi_threshold(nr_power_control_t *pc, int rssi_threshold); void nr_mac_signal_dtx(nr_power_control_t *pc); diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index ca12c48c48..1f619308c2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -293,6 +293,7 @@ void mac_top_init_gNB(ngran_node_t node_type, RC.nrmac[i]->cset0_bwp_start = 0; RC.nrmac[i]->cset0_bwp_size = 0; + RC.nrmac[i]->ul_next = (fsn_t) {.mu = *scc->ssbSubcarrierSpacing}; RC.nrmac[i]->print_ue_stats = true; pthread_mutex_init(&RC.nrmac[i]->sched_lock, NULL); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index f7ea466a94..391bfeabe8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -16,6 +16,7 @@ #include #include #include +#include "fsn.h" #include "common/utils/ds/seq_arr.h" #include "common/utils/nr/nr_common.h" #include "common/utils/ds/byte_array.h" @@ -878,14 +879,6 @@ typedef struct { NR_ControlResourceSet_t coreset; } NR_sched_ctrl_sib1_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; - typedef struct NR_du_stats { /// cell-wide wide-band CQI distribution, see 28.552 5.1.1.11.1; /// 0-15 CQI, 1-8 RI, 1-3 CQI table diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 8d5d00c975..d818229054 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -223,39 +223,67 @@ NR_UE_NR_Capability_t *decode_nr_ue_capability(int rnti, const NR_UE_CapabilityR return NULL; } -//------------------------------------------------------------------------------ - -int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc) +byte_array_t do_SIB2_NR(const NR_SIB2_t *sib2) { - NR_SIB2_t *sib2 = calloc(1, sizeof(*sib2)); - sib2->cellReselectionInfoCommon.q_Hyst = NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB0; - struct NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars *speed = calloc(1, sizeof(*speed)); - NR_MobilityStateParameters_t mobilityStateParameters = {0}; - mobilityStateParameters.t_Evaluation = NR_MobilityStateParameters__t_Evaluation_s30; - mobilityStateParameters.t_HystNormal = NR_MobilityStateParameters__t_HystNormal_s30; - mobilityStateParameters.n_CellChangeMedium = 1; - mobilityStateParameters.n_CellChangeHigh = 2; - speed->mobilityStateParameters = mobilityStateParameters; - struct NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars__q_HystSF qhyst = {0}; - qhyst.sf_Medium = NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars__q_HystSF__sf_Medium_dB_4; - qhyst.sf_High = NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars__q_HystSF__sf_High_dB_6; - speed->q_HystSF = qhyst; - sib2->cellReselectionInfoCommon.speedStateReselectionPars = speed; - sib2->cellReselectionServingFreqInfo.cellReselectionPriority = 0; // INTEGER (0..7) - sib2->cellReselectionServingFreqInfo.threshServingLowP = 0; - NR_ReselectionThresholdQ_t *threshServingLowQ = calloc(1, sizeof(*threshServingLowQ)); - *threshServingLowQ = 0; - sib2->cellReselectionServingFreqInfo.threshServingLowQ = threshServingLowQ; - sib2->intraFreqCellReselectionInfo.q_RxLevMin = -56; // INTEGER (-70..-22) - sib2->intraFreqCellReselectionInfo.s_IntraSearchP = 22; // INTEGER (0..31) - sib2->intraFreqCellReselectionInfo.t_ReselectionNR = 1; // INTEGER (0..7) - sib2->intraFreqCellReselectionInfo.deriveSSB_IndexFromCell = true; - sib2->intraFreqCellReselectionInfo.smtc = ssbmtc; + byte_array_t msg = {.buf = NULL, .len = 0}; + char errbuf[256] = {0}; + size_t errlen = sizeof(errbuf); + int ret = asn_check_constraints(&asn_DEF_NR_SIB2, sib2, errbuf, &errlen); + if (ret != 0) { + LOG_E(NR_RRC, "SIB2 constraint check failed: %s\n", errbuf); + return msg; + } - ssize_t size = uper_encode_to_new_buffer(&asn_DEF_NR_SIB2, NULL, (void *)sib2, (void **)msg_SIB2); - AssertFatal (size > 0, "ASN1 message encoding failed (encoded %lu bytes)!\n", size); - ASN_STRUCT_FREE(asn_DEF_NR_SIB2, sib2); - return size; + int val = uper_encode_to_new_buffer(&asn_DEF_NR_SIB2, NULL, (void *)sib2, (void **)&msg.buf); + if (val <= 0) { + LOG_E(NR_RRC, "Failed to encode SIB2\n"); + return msg; + } + + msg.len = val; + return msg; +} + +byte_array_t do_SIB3_NR(const NR_SIB3_t *sib3) +{ + byte_array_t msg = {.buf = NULL, .len = 0}; + char errbuf[256] = {0}; + size_t errlen = sizeof(errbuf); + int ret = asn_check_constraints(&asn_DEF_NR_SIB3, sib3, errbuf, &errlen); + if (ret != 0) { + LOG_E(NR_RRC, "SIB3 constraint check failed: %s\n", errbuf); + return msg; + } + + int val = uper_encode_to_new_buffer(&asn_DEF_NR_SIB3, NULL, (void *)sib3, (void **)&msg.buf); + if (val <= 0) { + LOG_E(NR_RRC, "Failed to encode SIB3\n"); + return msg; + } + + msg.len = val; + return msg; +} + +byte_array_t do_SIB4_NR(NR_SIB4_t *sib4) +{ + byte_array_t msg = {.buf = NULL, .len = 0}; + char errbuf[256] = {0}; + size_t errlen = sizeof(errbuf); + int ret = asn_check_constraints(&asn_DEF_NR_SIB4, sib4, errbuf, &errlen); + if (ret != 0) { + LOG_E(NR_RRC, "SIB4 constraint check failed: %s\n", errbuf); + return msg; + } + + int val = uper_encode_to_new_buffer(&asn_DEF_NR_SIB4, NULL, (void *)sib4, (void **)&msg.buf); + if (val <= 0) { + LOG_E(NR_RRC, "Failed to encode SIB4\n"); + return msg; + } + + msg.len = val; + return msg; } int do_RRCReject(uint8_t *const buffer) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 7aeb2b4ed0..384096ee16 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -33,6 +33,9 @@ #include "NR_MeasurementTimingConfiguration.h" #include "NR_UE-NR-Capability.h" #include "NR_UE-CapabilityRAT-ContainerList.h" +#include "NR_SIB2.h" +#include "NR_SIB3.h" +#include "NR_SIB4.h" #include "ds/seq_arr.h" #include "ds/byte_array.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" @@ -65,7 +68,9 @@ typedef struct { */ int xer_sprint_NR(char *string, size_t string_size, struct asn_TYPE_descriptor_s *td, void *sptr); -int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc); +byte_array_t do_SIB2_NR(const NR_SIB2_t *sib2); +byte_array_t do_SIB3_NR(const NR_SIB3_t *sib3); +byte_array_t do_SIB4_NR(NR_SIB4_t *sib4); int do_RRCReject(uint8_t *const buffer); diff --git a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp index 4867d7f8ab..c14e9bdba0 100644 --- a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp +++ b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp @@ -14,12 +14,61 @@ extern "C" { #include "NR_DRB-ToAddMod.h" #include "NR_DRB-ToAddModList.h" #include "NR_SRB-ToAddModList.h" +#include "NR_InterFreqCarrierFreqInfo.h" #include "ds/byte_array.h" +#include "NR_SIB2.h" +#include "NR_SIB3.h" +#include "NR_SIB4.h" +#include "NR_IntraFreqNeighCellInfo.h" +#include "NR_IntraFreqNeighCellList.h" +#include "NR_InterFreqCarrierFreqInfo.h" +#include "NR_InterFreqNeighCellInfo.h" +#include "NR_InterFreqNeighCellList.h" +#include "asn_application.h" RAN_CONTEXT_t RC; #ifdef __cplusplus } #endif +static NR_SIB2_t *encode_and_decode_sib2(const NR_SIB2_t *sib2, byte_array_t *ba_out) +{ + *ba_out = do_SIB2_NR(sib2); + EXPECT_GT(ba_out->len, 0); + EXPECT_NE(ba_out->buf, nullptr); + + NR_SIB2_t *decoded = nullptr; + asn_dec_rval_t dec = uper_decode(nullptr, &asn_DEF_NR_SIB2, (void **)&decoded, ba_out->buf, ba_out->len, 0, 0); + EXPECT_EQ(dec.code, RC_OK); + EXPECT_NE(decoded, nullptr); + return decoded; +} + +static NR_SIB3_t *encode_and_decode_sib3(const NR_SIB3_t *sib3, byte_array_t *ba_out) +{ + *ba_out = do_SIB3_NR(sib3); + EXPECT_GT(ba_out->len, 0); + EXPECT_NE(ba_out->buf, nullptr); + + NR_SIB3_t *decoded = nullptr; + asn_dec_rval_t dec = uper_decode(nullptr, &asn_DEF_NR_SIB3, (void **)&decoded, ba_out->buf, ba_out->len, 0, 0); + EXPECT_EQ(dec.code, RC_OK); + EXPECT_NE(decoded, nullptr); + return decoded; +} + +static NR_SIB4_t *encode_and_decode_sib4(NR_SIB4_t *sib4, byte_array_t *ba_out) +{ + *ba_out = do_SIB4_NR(sib4); + EXPECT_GT(ba_out->len, 0); + EXPECT_NE(ba_out->buf, nullptr); + + NR_SIB4_t *decoded = nullptr; + asn_dec_rval_t dec = uper_decode(nullptr, &asn_DEF_NR_SIB4, (void **)&decoded, ba_out->buf, ba_out->len, 0, 0); + EXPECT_EQ(dec.code, RC_OK); + EXPECT_NE(decoded, nullptr); + return decoded; +} + TEST(nr_asn1, rrc_reject) { unsigned char buf[1000]; @@ -138,6 +187,167 @@ TEST(nr_asn1, rrc_reconfiguration) free_RRCReconfiguration_params(params); } +TEST(nr_asn1, sib2_basic_encode_decode) +{ + NR_SIB2_t *sib2 = (NR_SIB2_t *)calloc_or_fail(1, sizeof(*sib2)); + sib2->cellReselectionInfoCommon.q_Hyst = NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB0; + sib2->cellReselectionServingFreqInfo.cellReselectionPriority = 3; + sib2->cellReselectionServingFreqInfo.threshServingLowP = 10; + sib2->intraFreqCellReselectionInfo.q_RxLevMin = -56; + sib2->intraFreqCellReselectionInfo.s_IntraSearchP = 22; + sib2->intraFreqCellReselectionInfo.t_ReselectionNR = 1; + sib2->intraFreqCellReselectionInfo.deriveSSB_IndexFromCell = true; + + byte_array_t ba = {}; + NR_SIB2_t *decoded = encode_and_decode_sib2(sib2, &ba); + + EXPECT_EQ(decoded->cellReselectionServingFreqInfo.cellReselectionPriority, + sib2->cellReselectionServingFreqInfo.cellReselectionPriority); + EXPECT_EQ(decoded->cellReselectionServingFreqInfo.threshServingLowP, sib2->cellReselectionServingFreqInfo.threshServingLowP); + + ASN_STRUCT_FREE(asn_DEF_NR_SIB2, sib2); + ASN_STRUCT_FREE(asn_DEF_NR_SIB2, decoded); + free_byte_array(ba); +} + +TEST(nr_asn1, sib3_basic_encode_decode) +{ + NR_SIB3_t *sib3 = (NR_SIB3_t *)calloc_or_fail(1, sizeof(*sib3)); + sib3->intraFreqNeighCellList = (struct NR_IntraFreqNeighCellList *)calloc_or_fail(1, sizeof(*sib3->intraFreqNeighCellList)); + + NR_IntraFreqNeighCellInfo_t *cell = (NR_IntraFreqNeighCellInfo_t *)calloc_or_fail(1, sizeof(*cell)); + cell->physCellId = 100; + cell->q_OffsetCell = NR_Q_OffsetRange_dB0; + ASN_SEQUENCE_ADD(&sib3->intraFreqNeighCellList->list, cell); + + byte_array_t ba = {}; + NR_SIB3_t *decoded = encode_and_decode_sib3(sib3, &ba); + + ASSERT_NE(decoded->intraFreqNeighCellList, nullptr); + EXPECT_EQ(decoded->intraFreqNeighCellList->list.count, 1); + EXPECT_EQ(decoded->intraFreqNeighCellList->list.array[0]->physCellId, cell->physCellId); + + ASN_STRUCT_FREE(asn_DEF_NR_SIB3, sib3); + ASN_STRUCT_FREE(asn_DEF_NR_SIB3, decoded); + free_byte_array(ba); +} + +TEST(nr_asn1, sib4_basic_encode_decode) +{ + NR_SIB4_t *sib4 = (NR_SIB4_t *)calloc_or_fail(1, sizeof(*sib4)); + + NR_InterFreqCarrierFreqInfo_t *carrier = (NR_InterFreqCarrierFreqInfo_t *)calloc_or_fail(1, sizeof(*carrier)); + carrier->dl_CarrierFreq = 2000; + carrier->ssbSubcarrierSpacing = NR_SubcarrierSpacing_kHz15; + carrier->deriveSSB_IndexFromCell = true; + carrier->q_RxLevMin = -56; + carrier->t_ReselectionNR = 1; + carrier->threshX_HighP = 5; + carrier->threshX_LowP = 3; + carrier->interFreqNeighCellList = (struct NR_InterFreqNeighCellList *)calloc_or_fail(1, sizeof(*carrier->interFreqNeighCellList)); + + NR_InterFreqNeighCellInfo_t *ncell = (NR_InterFreqNeighCellInfo_t *)calloc_or_fail(1, sizeof(*ncell)); + ncell->physCellId = 200; + ncell->q_OffsetCell = NR_Q_OffsetRange_dB0; + ASN_SEQUENCE_ADD(&carrier->interFreqNeighCellList->list, ncell); + ASN_SEQUENCE_ADD(&sib4->interFreqCarrierFreqList.list, carrier); + + byte_array_t ba = {}; + NR_SIB4_t *decoded = encode_and_decode_sib4(sib4, &ba); + + ASSERT_GT(decoded->interFreqCarrierFreqList.list.count, 0); + EXPECT_EQ(decoded->interFreqCarrierFreqList.list.array[0]->dl_CarrierFreq, carrier->dl_CarrierFreq); + + ASN_STRUCT_FREE(asn_DEF_NR_SIB4, sib4); + ASN_STRUCT_FREE(asn_DEF_NR_SIB4, decoded); + free_byte_array(ba); +} + +TEST(nr_asn1, inter_freq_carrier_freq_info_ranges) +{ + NR_SIB4_t *sib4 = (NR_SIB4_t *)calloc_or_fail(1, sizeof(*sib4)); + ASN_SEQUENCE_ADD(&sib4->interFreqCarrierFreqList.list, + (NR_InterFreqCarrierFreqInfo_t *)calloc_or_fail(1, sizeof(NR_InterFreqCarrierFreqInfo_t))); + + NR_InterFreqCarrierFreqInfo_t *carrier = sib4->interFreqCarrierFreqList.list.array[0]; + carrier->dl_CarrierFreq = 640000; + carrier->ssbSubcarrierSpacing = NR_SubcarrierSpacing_kHz30; + carrier->deriveSSB_IndexFromCell = 1; + carrier->threshX_HighP = 0; + carrier->threshX_LowP = 0; + + NR_Q_OffsetRange_t *qoff = (NR_Q_OffsetRange_t *)calloc_or_fail(1, sizeof(*qoff)); + *qoff = 15; // arbitrary valid Q-OffsetRange enum + carrier->q_OffsetFreq = qoff; + + // Optional threshX_Q struct + carrier->threshX_Q = (decltype(carrier->threshX_Q))calloc_or_fail(1, sizeof(*carrier->threshX_Q)); + carrier->threshX_Q->threshX_HighQ = 0; + carrier->threshX_Q->threshX_LowQ = 0; + + auto try_encode = [](NR_SIB4_t *s, bool expect_success) { + byte_array_t ba = do_SIB4_NR(s); + int len = (int)ba.len; + if (expect_success) { + EXPECT_GT(len, 0); + EXPECT_NE(ba.buf, nullptr); + } else { + EXPECT_LE(len, 0); + } + free_byte_array(ba); + }; + + // Valid lower bounds for all constrained scalars + carrier->q_RxLevMin = -70; + carrier->t_ReselectionNR = 0; + carrier->threshX_HighP = 0; + carrier->threshX_LowP = 0; + carrier->threshX_Q->threshX_HighQ = 0; + carrier->threshX_Q->threshX_LowQ = 0; + *qoff = 15; + try_encode(sib4, true); + + // Invalid q_RxLevMin (below ASN.1 range) + carrier->q_RxLevMin = -80; + carrier->t_ReselectionNR = 0; + try_encode(sib4, false); + + // Invalid t_ReselectionNR (above ASN.1 range) + carrier->q_RxLevMin = -70; + carrier->t_ReselectionNR = 8; + try_encode(sib4, false); + + // Restore valid q_RxLevMin / t_ReselectionNR + carrier->q_RxLevMin = -70; + carrier->t_ReselectionNR = 0; + + // Invalid threshX_HighP (below 0) + carrier->threshX_HighP = -1; + try_encode(sib4, false); + carrier->threshX_HighP = 0; + + // Invalid threshX_LowP (below 0) + carrier->threshX_LowP = -1; + try_encode(sib4, false); + carrier->threshX_LowP = 0; + + // Invalid threshX_HighQ (below 0) + carrier->threshX_Q->threshX_HighQ = -1; + try_encode(sib4, false); + carrier->threshX_Q->threshX_HighQ = 0; + + // Invalid threshX_LowQ (below 0) + carrier->threshX_Q->threshX_LowQ = -1; + try_encode(sib4, false); + carrier->threshX_Q->threshX_LowQ = 0; + + // Invalid q_OffsetFreq (outside [-24,24] enum range) + *qoff = 99; + try_encode(sib4, false); + + ASN_STRUCT_FREE(asn_DEF_NR_SIB4, sib4); +} + int main(int argc, char **argv) { logInit(); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 606eb86327..5a4063c3f2 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -312,21 +312,107 @@ typedef struct { bool is_default_a3_configuration_exists; } nr_measurement_configuration_t; +/** @brief Per-neighbor cell-specific offsets (TS 38.331), shared by SIB3 and SIB4 + * Maps to ASN.1 IntraFreqNeighCellInfo and InterFreqNeighCellInfo + * (SIB3.IntraFreqNeighCellList, SIB4.InterFreqCarrierFreqInfo.neighCellList) */ typedef struct { + // q-OffsetCell: (Q-OffsetRange values -24,-22,-20,-18,-16,-14,-12,-10,-8,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,8,10,12,14,16,18,20,22,24 dB) + // per-neighbor cell ranking + int q_OffsetCell; + // q-RxLevMinOffsetCell: Q-OffsetCellSmall (1..8): Per-neighbor RSRP minimum offset + int q_RxLevMinOffsetCell; + // q-QualMinOffsetCell: Q-OffsetCellSmall (1..8): Per-neighbor RSRQ minimum offset + int q_QualMinOffsetCell; +} nr_neighbour_cell_neighbor_offset_t; + +/** @brief SIB3 (intra-frequency) neighbor list parameters (TS 38.331) + * Per-neighbor fields for SIB3.IntraFreqNeighCellList.IntraFreqNeighCellInfo. + * SIB3 carries intra-freq neighbor offsets for ranking. */ +typedef struct { + nr_neighbour_cell_neighbor_offset_t offset; +} nr_neighbour_cell_sib3_t; + +/** @brief SIB4 inter-frequency carrier parameters (TS 38.331) + * Per-frequency fields for SIB4.InterFreqCarrierFreqList.InterFreqCarrierFreqInfo. + * Stored once per ARFCN; all neighbors on that frequency share this config. */ +typedef struct { + // cellReselectionPriority (0..7): Absolute priority of this inter-freq carrier + int cellReselectionPriority; + // threshX-HighP (0..31): RSRP threshold for reselection to a higher-priority inter-freq + int threshX_HighP; + // threshX-LowP (0..31): RSRP threshold for reselection to a lower-priority inter-freq + int threshX_LowP; + // threshX-HighQ (0..31): RSRQ threshold for higher-priority inter-freq reselection + int threshX_HighQ; + // threshX-LowQ (0..31): RSRQ threshold for lower-priority inter-freq reselection + int threshX_LowQ; + // q-OffsetFreq (Q-OffsetRange values: -24,-22,-20,-18,-16,-14,-12,-10,-8,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,8,10,12,14,16,18,20,22,24 dB): + // Frequency-specific offset in inter-freq cell ranking formula + int q_OffsetFreq; +} nr_neighbour_cell_sib4_freq_t; + +/** @brief SIB4 (inter-frequency) parameters per neighbor (TS 38.331) + * Combines per-frequency carrier info (InterFreqCarrierFreqInfo) and per-neighbor + * offsets (InterFreqNeighCellInfo). */ +typedef struct { + // Per-frequency carrier (InterFreqCarrierFreqInfo) + nr_neighbour_cell_sib4_freq_t sib4_freq; + // Per-neighbor offsets (InterFreqNeighCellInfo) + nr_neighbour_cell_neighbor_offset_t offset; +} nr_neighbour_cell_sib4_t; + +/** @brief Per-frequency SIB4 configuration (TS 38.331), keyed by ARFCN + * One entry per inter-freq carrier (absoluteFrequencySSB + subcarrierSpacing). + * freq_cfg holds InterFreqCarrierFreqInfo parameters. Analogous to one “carrier” slice of SIB4 + * interFreqCarrierFreqList. */ +typedef struct { + // absoluteFrequencySSB (ARFCN) + int arfcn; + // ssbSubcarrierSpacing + int scs; + // q-RxLevMin (-70..-22 dBm) + int q_RxLevMin; + // t-ReselectionNR (0..7) + int t_ReselectionNR; + // Inter-frequency carrier parameters (InterFreqCarrierFreqInfo) + nr_neighbour_cell_sib4_freq_t freq_cfg; +} nr_inter_freq_cfg_t; + +/** @brief Neighbor cell configuration structure + * Single source of truth for neighbor cell information, used across multiple protocols/scopes: + * - Handover (NGAP/XnAP): for target gNB (ID, plmn, tac, nrcell_id, physicalCellId) + * - Measurement (MeasConfig): physicalCellId, absoluteFrequencySSB, band + * - DU validation: all fields validated against actual cell information + * - SIB3/SIB4 generation: physicalCellId, absoluteFrequencySSB, subcarrierSpacing, band + * References: + * - 3GPP TS 38.331 (RRC) for SIB3/SIB4 and MeasConfig + * - 3GPP TS 38.413 (NGAP) / TS 38.423 (XnAP) for target cell identification */ +typedef struct { + // gNB identifier (for target node in NGAP/XnAP handover) uint32_t gNB_ID; + // NR Cell Global Identifier (for NGAP/XnAP handover, DU validation) uint64_t nrcell_id; + // Physical Cell ID (PCI) (used in HandoverPreparationInformation and MeasObjectNR) int physicalCellId; + // SSB absolute frequency (ARFCN) (for MeasObjectNR, intra/inter-frequency determination) int absoluteFrequencySSB; + // SSB subcarrier spacing (for MeasObjectNR/SIB4) int subcarrierSpacing; + // Frequency band indicator (for MeasObjectNR/SIB4) int band; + // PLMN identity (for target node in NGAP/XnAP handover) plmn_id_t plmn; + // Tracking Area Code (for target node in NGAP/XnAP handover) uint32_t tac; - bool isIntraFrequencyNeighbour; + // SIB3 (intra-frequency neighbor cell-specific offsets) + nr_neighbour_cell_sib3_t sib3; + // SIB4 (inter-frequency neighbor cell-specific parameters) + nr_neighbour_cell_sib4_t sib4; } nr_neighbour_cell_t; typedef struct neighbour_cell_configuration_s { uint64_t nr_cell_id; - seq_arr_t *neighbour_cells; + seq_arr_t neighbour_cells; } neighbour_cell_configuration_t; typedef struct nr_mac_rrc_dl_if_s { @@ -418,6 +504,101 @@ typedef struct nr_rrc_cuup_container_t { sctp_assoc_t assoc_id; } nr_rrc_cuup_container_t; +/**Timers for SIB2 MobilityStateParameters (TS 38.331) + * Value set shared by T-Evaluation and T-HystNormal: (s30, s60, s120, s180, s240). */ +typedef enum sib2_mobility_state_timer_e { + SIB2_MOBILITY_STATE_TIMER_S30, + SIB2_MOBILITY_STATE_TIMER_S60, + SIB2_MOBILITY_STATE_TIMER_S120, + SIB2_MOBILITY_STATE_TIMER_S180, + SIB2_MOBILITY_STATE_TIMER_S240, +} sib2_mobility_state_timer_t; + +/** Q-HystSF scaling factors for Q_hyst (TS 38.331) + * Speed-dependent offsets (-6, -4, -2, 0 dB) applied to the base Q_hyst + * when the UE is in medium or high mobility state. */ +typedef enum sib2_q_hystsf_e { + SIB2_Q_HYSTSF_DB_6, + SIB2_Q_HYSTSF_DB_4, + SIB2_Q_HYSTSF_DB_2, + SIB2_Q_HYSTSF_DB0, +} sib2_q_hystsf_t; + +/** SIB2 speedStateReselectionPars configuration + * Mirrors TS 38.331 MobilityStateParameters and Q-hystSF. */ +typedef struct sib2_speed_state_reselection_pars_s { + /* t-Evaluation: duration for evaluating allowed reselections + * to enter mobility states (s30, s60, s120, s180, s240) */ + sib2_mobility_state_timer_t t_Evaluation; + /* t-HystNormal: additional time period to evaluate reselection criteria + * before returning to normal mobility (s30, s60, s120, s180, s240) */ + sib2_mobility_state_timer_t t_HystNormal; + /* n-CellChangeMedium: max number of cell reselections to enter medium mobility state (1..16) */ + int n_CellChangeMedium; + /* n-CellChangeHigh: max number of cell reselections to enter high mobility state (1..16) */ + int n_CellChangeHigh; + /* sf-Medium: speed-dependent scaling factor for Qhyst in medium state (-6, -4, -2, 0 dB) */ + sib2_q_hystsf_t sf_Medium; + /* sf-High: speed-dependent scaling factor for Qhyst in high state (-6, -4, -2, 0 dB) */ + sib2_q_hystsf_t sf_High; +} sib2_speed_state_reselection_pars_t; + +/** SIB2 cellReselectionServingFreqInfo (TS 38.331) */ +typedef struct { + /* s-NonIntraSearchP: Srxlev threshold to trigger NR inter-freq / inter-RAT measurements (0..31)*2 dB. + * Set to -1 to omit (optional ASN.1 field). */ + int s_NonIntraSearchP; + /* s-NonIntraSearchQ: Squal threshold to trigger NR inter-freq / inter-RAT measurements (0..31)*2 dB */ + int s_NonIntraSearchQ; + /* threshServingLowP: Srxlev threshold (dB) used by the UE on the serving cell + * when reselecting towards a lower-priority RAT/frequency (0..31)*2 dB */ + int threshServingLowP; + /* threshServingLowQ: Squal threshold (dB) used by the UE on the serving cell + * when reselecting towards a lower-priority RAT/frequency (0..31)*2 dB. + * Set to -1 to omit (optional ASN.1 field). */ + int threshServingLowQ; + /* cellReselectionPriority: absolute priority of serving NR frequency (0..7) */ + int cellReselectionPriority; +} cell_reselection_serving_freq_info_t; + +/** SIB2 cellReselectionInfoCommon (TS 38.331) */ +typedef struct { + /* q-Hyst: hysteresis added to serving-cell ranking R_s (0..24 dB) */ + int q_Hyst; + /* speedStateReselectionPars: MobilityStateParameters + q-HystSF */ + sib2_speed_state_reselection_pars_t *speedStateReselectionPars; +} cell_reselection_info_common_t; + +/** SIB2 intraFreqCellReselectionInfo (TS 38.331) */ +typedef struct { + /* q-RxLevMin: minimum required RX level in the cell (dBm) */ + int q_RxLevMin; + /* q-QualMin: minimum required quality level in the cell (dB); */ + int q_QualMin; + /* s-IntraSearchP: Srxlev threshold for intra-freq meas (0..31) */ + int s_IntraSearchP; + /* s-IntraSearchQ: Squal threshold for intra-freq meas (0..31) */ + int s_IntraSearchQ; + /* t-ReselectionNR: NR cell reselection timer (0..7) */ + int t_ReselectionNR; +} intra_freq_cell_reselection_info_t; + +/** SIB2 configuration for idle/inactive cell reselection + * (maps to SIB2 reselection parameters in TS 38.304/38.331, per cell). + * @note Squal = Cell selection quality value (dB) + * Srxlev = Cell selection RX level value (dB) */ +typedef struct sib2_config_s { + // cellReselectionInfoCommon + cell_reselection_info_common_t cell_reselection_info_common; + // cellReselectionServingFreqInfo + cell_reselection_serving_freq_info_t cell_reselection_serving_freq_info; + // intraFreqCellReselectionInfo + intra_freq_cell_reselection_info_t intra_freq_cell_reselection_info; + /* deriveSSB_IndexFromCell: SIB2 deriveSSB-IndexFromCell - whether UE may + * assume SFN/SSB alignment across cells on serving freq (per TS 38.304/38.133) */ + bool deriveSSB_IndexFromCell; +} sib2_config_t; + //---NR---(completely change)--------------------- typedef struct gNB_RRC_INST_s { @@ -432,6 +613,8 @@ typedef struct gNB_RRC_INST_s { // RRC configuration nr_rrc_config_t configuration; seq_arr_t *SIBs; + // SIB2 configuration for cell reselection parameters + sib2_config_t sib2_config; // gNB N3 GTPU instance instance_t e1_inst; @@ -443,6 +626,9 @@ typedef struct gNB_RRC_INST_s { nr_mac_rrc_dl_if_t mac_rrc; cucp_cuup_if_t cucp_cuup; + // Per-frequency SIB4 configurations, indexed by ARFCN + seq_arr_t inter_freqs; /* array of nr_inter_freq_cfg_t */ + // Per-cell neighbour configurations, indexed by cell_id seq_arr_t *neighbour_cell_configuration; nr_measurement_configuration_t measurementConfiguration; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 096dc98eea..4c47e6a23b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -263,10 +263,8 @@ static bool eq_pci(const void *vval, const void *vit) const nr_neighbour_cell_t *get_neighbour_cell_by_pci(const neighbour_cell_configuration_t *cell, int pci) { - seq_arr_t *head = cell->neighbour_cells; - DevAssert(head != NULL); - LOG_D(NR_RRC, "Number of neighbour cells: %ld\n", head->size); - elm_arr_t e = find_if(head, &pci, eq_pci); + DevAssert(cell); + elm_arr_t e = find_if((seq_arr_t *)&cell->neighbour_cells, &pci, eq_pci); if (e.found) { const nr_neighbour_cell_t *neighbour = (const nr_neighbour_cell_t *)e.it; LOG_D(NR_RRC, "Found matching neighbour cell with PCI %d and Cell ID %ld\n", neighbour->physicalCellId, neighbour->nrcell_id); @@ -772,23 +770,23 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell const NR_MeasTimingList_t *mtlist = cell->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; const NR_MeasTiming_t *mt = mtlist->list.array[0]; const neighbour_cell_configuration_t *neighbour_config = get_neighbour_cell_config(rrc, cell->info.cell_id); - seq_arr_t *neighbour_cells = NULL; - if (neighbour_config) - neighbour_cells = neighbour_config->neighbour_cells; + const seq_arr_t *neighbour_cells = neighbour_config ? &neighbour_config->neighbour_cells : NULL; int *neigh_a3_id = NULL; if (neighbour_cells && neighbour_cells->size) neigh_a3_id = calloc_or_fail(neighbour_cells->size, sizeof(int)); - if (neighbour_cells && rrc->measurementConfiguration.a3_event_list && rrc->measurementConfiguration.a3_event_list->size > 0) { + const nr_measurement_configuration_t *meas_cfg = &rrc->measurementConfiguration; + const seq_arr_t *a3_event_list = meas_cfg->a3_event_list; + if (neighbour_cells && a3_event_list && 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. */ 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); + int i = 0; + FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, neighbourCell, neighbour_cells) { 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) { @@ -814,12 +812,13 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell } NR_ReportConfigId_t reportConfigId = neigh_a3_id[i]; seq_arr_push_back(&rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t)); + i++; } } - if (rrc->measurementConfiguration.per_event) - rc_PER = prepare_periodic_event_report(rrc->measurementConfiguration.per_event); - if (rrc->measurementConfiguration.a2_event) - rc_A2 = prepare_a2_event_report(rrc->measurementConfiguration.a2_event); + if (meas_cfg->per_event) + rc_PER = prepare_periodic_event_report(meas_cfg->per_event); + if (meas_cfg->a2_event) + rc_A2 = prepare_a2_event_report(meas_cfg->a2_event); NR_MeasConfig_t *result = get_MeasConfig(mt, band, cell->info.pci, rc_PER, rc_A2, &rc_A3_seq, &neigh_seq, neigh_a3_id); diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index ec139e684d..6b60e5b6b9 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -23,6 +23,11 @@ #include "f1ap_messages_types.h" #include "ngap_messages_types.h" #include "nr_rrc_defs.h" +#include "NR_SIB2.h" +#include "NR_SIB3.h" +#include "NR_SIB4.h" +#include "NR_Q-OffsetRange.h" +#include "openair2/RRC/NR/MESSAGES/asn1_msg.h" #include "rrc_gNB_mobility.h" #include "openair2/F1AP/f1ap_common.h" #include "openair2/F1AP/f1ap_ids.h" @@ -33,6 +38,7 @@ #include "s1ap_messages_types.h" #include "tree.h" #include "uper_decoder.h" +#include "common/utils/oai_asn1.h" #include "utils.h" #include "xer_encoder.h" @@ -55,6 +61,375 @@ static NR_SSB_MTC_t *get_ssb_mtc(const NR_MeasurementTimingConfiguration_t *mtc) return ssb_mtc; } +/** @brief Map config q_Hyst (dB: 0,1,2,3,4,5,6,8,10..24) to ASN.1 q-Hyst enum index (0..15). + * ASN.1 NR_SIB2 cellReselectionInfoCommon.q-Hyst is encoded with 16 values. */ +static long get_q_hyst_asn1(int q_hyst_db) +{ + switch (q_hyst_db) { + case 0: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB0; + case 1: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB1; + case 2: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB2; + case 3: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB3; + case 4: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB4; + case 5: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB5; + case 6: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB6; + case 8: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB8; + case 10: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB10; + case 12: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB12; + case 14: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB14; + case 16: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB16; + case 18: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB18; + case 20: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB20; + case 22: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB22; + case 24: + return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB24; + default: + AssertFatal(false, "unexpected q-Hyst value %d (configuration should have been validated)\n", q_hyst_db); + } +} + +/** @brief Build NR_SIB2 from validated SIB2 configuration. + * @param cfg Validated SIB2 configuration from config file + * @param ssbmtc SSB-MTC instance to attach to intraFreqCellReselectionInfo.smtc. */ +static NR_SIB2_t *get_sib2_from_cfg(const sib2_config_t *cfg, NR_SSB_MTC_t *ssbmtc) +{ + NR_SIB2_t *sib2 = calloc_or_fail(1, sizeof(*sib2)); + typeof(sib2->cellReselectionInfoCommon) *common = &sib2->cellReselectionInfoCommon; + const cell_reselection_info_common_t *cfg_common = &cfg->cell_reselection_info_common; + + /* q-Hyst: ASN.1 enum (0..15) converted from config dB (0,1,2,3,4,5,6,8,10..24). */ + common->q_Hyst = get_q_hyst_asn1(cfg_common->q_Hyst); + + /* speedStateReselectionPars */ + if (cfg_common->speedStateReselectionPars != NULL) { + struct NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars *speed = calloc_or_fail(1, sizeof(*speed)); + NR_MobilityStateParameters_t mobilityStateParameters = {0}; + const sib2_speed_state_reselection_pars_t *pars = cfg_common->speedStateReselectionPars; + /* t-Evaluation / t-HystNormal: (0..7) */ + mobilityStateParameters.t_Evaluation = pars->t_Evaluation; + mobilityStateParameters.t_HystNormal = pars->t_HystNormal; + /* n-CellChangeMedium / n-CellChangeHigh: (1..16) */ + mobilityStateParameters.n_CellChangeMedium = pars->n_CellChangeMedium; + mobilityStateParameters.n_CellChangeHigh = pars->n_CellChangeHigh; + speed->mobilityStateParameters = mobilityStateParameters; + + /* q-HystSF: sf-Medium/sf-High (0..3) */ + struct NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars__q_HystSF qhyst = {0}; + qhyst.sf_Medium = pars->sf_Medium; + qhyst.sf_High = pars->sf_High; + speed->q_HystSF = qhyst; + + common->speedStateReselectionPars = speed; + } + + /* cellReselectionServingFreqInfo */ + typeof(sib2->cellReselectionServingFreqInfo) *serv = &sib2->cellReselectionServingFreqInfo; + const cell_reselection_serving_freq_info_t *cfg_serv = &cfg->cell_reselection_serving_freq_info; + /* cellReselectionPriority: CellReselectionPriority (0..7) */ + serv->cellReselectionPriority = cfg_serv->cellReselectionPriority; + /* threshServingLowP: ReselectionThreshold (0..31) */ + serv->threshServingLowP = cfg_serv->threshServingLowP; + /* threshServingLowQ: ReselectionThresholdQ (0..31) */ + if (cfg_serv->threshServingLowQ != -1) + asn1cCallocOne(serv->threshServingLowQ, cfg_serv->threshServingLowQ); + /* s-NonIntraSearchP/Q: ReselectionThreshold/ReselectionThresholdQ (0..31) */ + if (cfg_serv->s_NonIntraSearchP != -1) + asn1cCallocOne(serv->s_NonIntraSearchP, cfg_serv->s_NonIntraSearchP); + if (cfg_serv->s_NonIntraSearchQ != -1) + asn1cCallocOne(serv->s_NonIntraSearchQ, cfg_serv->s_NonIntraSearchQ); + + /* intraFreqCellReselectionInfo */ + typeof(sib2->intraFreqCellReselectionInfo) *intra = &sib2->intraFreqCellReselectionInfo; + const intra_freq_cell_reselection_info_t *cfg_intra = &cfg->intra_freq_cell_reselection_info; + /* q-RxLevMin: Q-RxLevMin (-70..-22) */ + intra->q_RxLevMin = cfg_intra->q_RxLevMin; + /* q-QualMin: Q-QualMin (-43..-12) */ + if (cfg_intra->q_QualMin != -1) + asn1cCallocOne(intra->q_QualMin, cfg_intra->q_QualMin); + /* s-IntraSearchP: ReselectionThreshold (0..31) */ + intra->s_IntraSearchP = cfg_intra->s_IntraSearchP; + /* s-IntraSearchQ: ReselectionThresholdQ (0..31) */ + if (cfg_intra->s_IntraSearchQ != -1) + asn1cCallocOne(intra->s_IntraSearchQ, cfg_intra->s_IntraSearchQ); + /* t-ReselectionNR: (0..7) */ + intra->t_ReselectionNR = cfg_intra->t_ReselectionNR; + /* deriveSSB-IndexFromCell (bool) */ + intra->deriveSSB_IndexFromCell = cfg->deriveSSB_IndexFromCell; + /* smtc */ + intra->smtc = ssbmtc; + + return sib2; +} + +/** @brief Map internal int enum to ASN.1 Q-OffsetRange value. */ +static long get_q_offset_asn1(int q_offset_db) +{ + switch (q_offset_db) { + case -24: + return NR_Q_OffsetRange_dB_24; + case -22: + return NR_Q_OffsetRange_dB_22; + case -20: + return NR_Q_OffsetRange_dB_20; + case -18: + return NR_Q_OffsetRange_dB_18; + case -16: + return NR_Q_OffsetRange_dB_16; + case -14: + return NR_Q_OffsetRange_dB_14; + case -12: + return NR_Q_OffsetRange_dB_12; + case -10: + return NR_Q_OffsetRange_dB_10; + case -8: + return NR_Q_OffsetRange_dB_8; + case -6: + return NR_Q_OffsetRange_dB_6; + case -5: + return NR_Q_OffsetRange_dB_5; + case -4: + return NR_Q_OffsetRange_dB_4; + case -3: + return NR_Q_OffsetRange_dB_3; + case -2: + return NR_Q_OffsetRange_dB_2; + case -1: + return NR_Q_OffsetRange_dB_1; + case 0: + return NR_Q_OffsetRange_dB0; + case 1: + return NR_Q_OffsetRange_dB1; + case 2: + return NR_Q_OffsetRange_dB2; + case 3: + return NR_Q_OffsetRange_dB3; + case 4: + return NR_Q_OffsetRange_dB4; + case 5: + return NR_Q_OffsetRange_dB5; + case 6: + return NR_Q_OffsetRange_dB6; + case 8: + return NR_Q_OffsetRange_dB8; + case 10: + return NR_Q_OffsetRange_dB10; + case 12: + return NR_Q_OffsetRange_dB12; + case 14: + return NR_Q_OffsetRange_dB14; + case 16: + return NR_Q_OffsetRange_dB16; + case 18: + return NR_Q_OffsetRange_dB18; + case 20: + return NR_Q_OffsetRange_dB20; + case 22: + return NR_Q_OffsetRange_dB22; + case 24: + return NR_Q_OffsetRange_dB24; + default: + AssertFatal(false, "Invalid q_offset_db value %d\n", q_offset_db); + } +} + +/** @brief Build a SIB3 (intra-frequency neighbour cell list) from the configured neighbour cells. + * Only neighbours whose SSB ARFCN matches @param serving_ssb_arfcn are included. + * @param neighbours list of configured neighbour cells + * @param serving_ssb_arfcn SSB ARFCN of the serving cell, used to filter intra-frequency neighbours + * @returns allocated NR_SIB3_t on success, NULL if no matching neighbours were found */ +static NR_SIB3_t *get_sib3_intra_freq_neighbors(const seq_arr_t *neighbours, uint32_t serving_ssb_arfcn) +{ + DevAssert(neighbours); + + NR_SIB3_t *sib3 = calloc_or_fail(1, sizeof(*sib3)); + sib3->intraFreqNeighCellList = calloc_or_fail(1, sizeof(*sib3->intraFreqNeighCellList)); + + int intra_count = 0; + FOR_EACH_SEQ_ARR (const nr_neighbour_cell_t *, neigh, neighbours) { + if (neigh->absoluteFrequencySSB != serving_ssb_arfcn) + continue; + + LOG_D(NR_RRC, + "SIB3: intra-frequency neighbour candidate: cell ID %lu, PCI %d (SSB ARFCN %d)\n", + neigh->nrcell_id, + neigh->physicalCellId, + neigh->absoluteFrequencySSB); + + NR_IntraFreqNeighCellInfo_t *cell = calloc_or_fail(1, sizeof(*cell)); + cell->physCellId = neigh->physicalCellId; + + const nr_neighbour_cell_neighbor_offset_t *off = &neigh->sib3.offset; + /* q-OffsetCell: NR_Q-OffsetRange (-24..24 dB), 0 dB default */ + cell->q_OffsetCell = get_q_offset_asn1(off->q_OffsetCell); + + /* q-RxLevMinOffsetCell / q-QualMinOffsetCell: (1..8) */ + if (off->q_RxLevMinOffsetCell != -1) + asn1cCallocOne(cell->q_RxLevMinOffsetCell, off->q_RxLevMinOffsetCell); + if (off->q_QualMinOffsetCell != -1) + asn1cCallocOne(cell->q_QualMinOffsetCell, off->q_QualMinOffsetCell); + + /* Add to SIB3 intra-frequency neighbour list */ + if (sib3->intraFreqNeighCellList->list.count >= NR_maxCellIntra) { + LOG_W(NR_RRC, "SIB3: too many intra-frequency neighbors (max %d), skipping cell %ld\n", NR_maxCellIntra, neigh->nrcell_id); + asn1cFreeStruc(asn_DEF_NR_IntraFreqNeighCellInfo, cell); + break; + } + asn1cSeqAdd(&sib3->intraFreqNeighCellList->list, cell); + ++intra_count; + } + + if (intra_count == 0) { + LOG_W(NR_RRC, + "SIB3: no intra-frequency neighbours found for serving SSB ARFCN %u " + "(configured neighbours %u), not building SIB3\n", + serving_ssb_arfcn, + (unsigned)seq_arr_size(neighbours)); + asn1cFreeStruc(asn_DEF_NR_SIB3, sib3); + return NULL; + } + + return sib3; +} + +/** @brief Build an NR_InterFreqCarrierFreqInfo structure from a nr_inter_freq_cfg_t configuration. + * @param cfg Configuration to build the carrier from + * @return Allocated NR_InterFreqCarrierFreqInfo_t on success, NULL if the configuration is invalid */ +static NR_InterFreqCarrierFreqInfo_t *build_inter_freq_carrier_from_cfg(const nr_inter_freq_cfg_t *cfg) +{ + DevAssert(cfg); + + const nr_neighbour_cell_sib4_freq_t *f = &cfg->freq_cfg; + + NR_InterFreqCarrierFreqInfo_t *carrier = calloc_or_fail(1, sizeof(*carrier)); + /* dl_CarrierFreq (ARFCN) */ + carrier->dl_CarrierFreq = cfg->arfcn; + /* ssbSubcarrierSpacing: (15/30/60/120 kHz) */ + carrier->ssbSubcarrierSpacing = cfg->scs; + carrier->deriveSSB_IndexFromCell = true; + /* Q-RxLevMin (-70..-22 dBm) */ + carrier->q_RxLevMin = cfg->q_RxLevMin; + /* T-Reselection (0..7) */ + carrier->t_ReselectionNR = cfg->t_ReselectionNR; + /* threshX_HighP/LowP: Reselection threshold (0..31) */ + carrier->threshX_HighP = f->threshX_HighP; + carrier->threshX_LowP = f->threshX_LowP; + /* threshX-Q: Optional RSRQ thresholds; emit only when both are provided. */ + if (f->threshX_HighQ != -1 && f->threshX_LowQ != -1) { + carrier->threshX_Q = calloc_or_fail(1, sizeof(*carrier->threshX_Q)); + carrier->threshX_Q->threshX_HighQ = f->threshX_HighQ; + carrier->threshX_Q->threshX_LowQ = f->threshX_LowQ; + } else if (f->threshX_HighQ != -1 || f->threshX_LowQ != -1) { + LOG_W(NR_RRC, + "SIB4: partial threshX-Q for ARFCN %d (HighQ=%d LowQ=%d), omitting threshX-Q\n", + cfg->arfcn, + f->threshX_HighQ, + f->threshX_LowQ); + } + /* CellReselectionPriority (0..7) */ + if (f->cellReselectionPriority != -1) + asn1cCallocOne(carrier->cellReselectionPriority, f->cellReselectionPriority); + /* q-OffsetFreq (-24..24 dB), 0 dB default */ + asn1cCallocOne(carrier->q_OffsetFreq, get_q_offset_asn1(f->q_OffsetFreq)); + /* InterFreqNeighCellList */ + carrier->interFreqNeighCellList = calloc_or_fail(1, sizeof(*carrier->interFreqNeighCellList)); + return carrier; +} + +/** + * @brief Build an NR_SIB4 structure populated with inter-frequency neighbour cell entries. + * + * Iterates over all configured inter-frequency carriers (excluding the serving cell ARFCN) + * and, for each carrier, adds the matching neighbour cells from @p neighbour_config. + * Carriers with no matching neighbours are discarded. If no valid carrier is found, + * the function returns NULL. + * + * @param neighbour_config Neighbour cell configuration (cells only). + * @param inter_freqs gNB-level inter-frequency configuration. + * @param serving_ssb_arfcn SSB ARFCN of the serving cell, used to skip the serving carrier. + * @return Allocated NR_SIB4_t on success, NULL if no inter-frequency neighbours are available. + */ +static NR_SIB4_t *get_sib4_inter_freq_neighbors(const neighbour_cell_configuration_t *neighbour_config, + const seq_arr_t *inter_freqs, + uint32_t serving_ssb_arfcn) +{ + DevAssert(neighbour_config); + + NR_SIB4_t *sib4 = calloc_or_fail(1, sizeof(*sib4)); + + const seq_arr_t *neigh = &neighbour_config->neighbour_cells; + + FOR_EACH_SEQ_ARR (nr_inter_freq_cfg_t *, cfg, inter_freqs) { + if (cfg->arfcn == serving_ssb_arfcn) + continue; + + NR_InterFreqCarrierFreqInfo_t *carrier = build_inter_freq_carrier_from_cfg(cfg); + if (!carrier) + continue; + + NR_InterFreqNeighCellList_t *neigh_list = carrier->interFreqNeighCellList; + + FOR_EACH_SEQ_ARR (nr_neighbour_cell_t *, nc, neigh) { + if (nc->absoluteFrequencySSB != cfg->arfcn || nc->subcarrierSpacing != cfg->scs) + continue; + + if (neigh_list->list.count >= NR_maxCellInter) { + LOG_W(NR_RRC, + "SIB4: too many inter-frequency neighbors for ARFCN %ld (max %d), skipping neighbour\n", + carrier->dl_CarrierFreq, + NR_maxCellInter); + continue; + } + + const nr_neighbour_cell_neighbor_offset_t *offset = &nc->sib4.offset; + LOG_I(NR_RRC, + "SIB4: added inter-frequency neighbour cell: cellId %ld (PCI %d), ARFCN %d, SCS %d\n", + nc->nrcell_id, + nc->physicalCellId, + cfg->arfcn, + cfg->scs); + asn1cSequenceAdd(neigh_list->list, NR_InterFreqNeighCellInfo_t, cell); + cell->physCellId = nc->physicalCellId; + + /* q_OffsetCell: 0 dB is default */ + cell->q_OffsetCell = get_q_offset_asn1(offset->q_OffsetCell); + + /* q_RxLevMinOffsetCell / q_QualMinOffsetCell: range 1..8 */ + if (offset->q_RxLevMinOffsetCell != -1) + asn1cCallocOne(cell->q_RxLevMinOffsetCell, offset->q_RxLevMinOffsetCell); + if (offset->q_QualMinOffsetCell != -1) + asn1cCallocOne(cell->q_QualMinOffsetCell, offset->q_QualMinOffsetCell); + } + + if (neigh_list->list.count > 0) { + asn1cSeqAdd(&sib4->interFreqCarrierFreqList.list, carrier); + } else { + ASN_STRUCT_FREE(asn_DEF_NR_InterFreqCarrierFreqInfo, carrier); + } + } + + if (sib4->interFreqCarrierFreqList.list.count == 0) { + ASN_STRUCT_FREE(asn_DEF_NR_SIB4, sib4); + return NULL; + } + + return sib4; +} + /** @brief Return the frequency of the SS block of the cell for which this message is included, * or of other SS blocks within the same carrier. MeasurementTimingConfiguration message is * used to convey assistance information for measurement timing between nodes (e.g F1 setup) */ @@ -152,7 +527,7 @@ static int nr_cell_id_match(const void *key, const void *element) return 1; } -static neighbour_cell_configuration_t *get_cell_neighbour_list(const gNB_RRC_INST *rrc, const nr_rrc_cell_container_t *cell) +static const neighbour_cell_configuration_t *get_cell_neighbour_list(const gNB_RRC_INST *rrc, const nr_rrc_cell_container_t *cell) { void *base = seq_arr_front(rrc->neighbour_cell_configuration); size_t nmemb = seq_arr_size(rrc->neighbour_cell_configuration); @@ -160,42 +535,7 @@ static neighbour_cell_configuration_t *get_cell_neighbour_list(const gNB_RRC_INS void *it = bsearch((void *)&cell->info.cell_id, base, nmemb, size, nr_cell_id_match); - return (neighbour_cell_configuration_t *)it; -} - -static void is_intra_frequency_neighbour(void *ssb_arfcn, void *neighbour_cell) -{ - uint32_t *ssb_arfcn_ptr = (uint32_t *)ssb_arfcn; - nr_neighbour_cell_t *neighbour_cell_ptr = (nr_neighbour_cell_t *)neighbour_cell; - - if (*ssb_arfcn_ptr == neighbour_cell_ptr->absoluteFrequencySSB) { - LOG_D(NR_RRC, "HO LOG: found intra frequency neighbour %lu!\n", neighbour_cell_ptr->nrcell_id); - neighbour_cell_ptr->isIntraFrequencyNeighbour = true; - } -} -/** - * @brief Labels neighbour cells if they are intra frequency to prepare meas config only for intra frequency ho - * @param[in] rrc Pointer to RRC instance - * @param[in] cell Pointer to cell container - */ -static void label_intra_frequency_neighbours(gNB_RRC_INST *rrc, const nr_rrc_cell_container_t *cell) -{ - if (!rrc->neighbour_cell_configuration) - return; - - neighbour_cell_configuration_t *neighbour_cell_config = get_cell_neighbour_list(rrc, cell); - if (!neighbour_cell_config) - return; - - uint32_t ssb_arfcn = get_ssb_arfcn(cell); - LOG_D(NR_RRC, - "Cell %lu (PCI %d, SSB ARFCN %u) has neighbour cell configuration, labeling intra-frequency neighbours\n", - cell->info.cell_id, - cell->info.pci, - ssb_arfcn); - - seq_arr_t *cell_neighbour_list = neighbour_cell_config->neighbour_cells; - for_each(cell_neighbour_list, (void *)&ssb_arfcn, is_intra_frequency_neighbour); + return (const neighbour_cell_configuration_t *)it; } static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_configuration, const f1ap_served_cell_info_t *cell) @@ -206,10 +546,8 @@ static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_config int ssb_arfcn = ssb_arfcn_mtc(mtc); ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); - for (int c = 0; c < neighbour_cell_configuration->size; c++) { - const neighbour_cell_configuration_t *neighbour_config = seq_arr_at(neighbour_cell_configuration, c); - for (int ni = 0; ni < neighbour_config->neighbour_cells->size; ni++) { - const nr_neighbour_cell_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); + FOR_EACH_SEQ_ARR(const neighbour_cell_configuration_t *, neighbour_config, neighbour_cell_configuration) { + FOR_EACH_SEQ_ARR(const nr_neighbour_cell_t *, nc, &neighbour_config->neighbour_cells) { if (nc->nrcell_id != cell->nr_cellid) continue; // current cell is in the nc config, check that config matches @@ -299,6 +637,17 @@ static void cp_f1_served_cell_info_to_cell(nr_rrc_cell_container_t *dst, const f } } +static void add_si_msg(served_cells_to_activate_t *cell, int sib_type, const byte_array_t *enc) +{ + AssertFatal(cell->num_SI < F1AP_MAX_NO_SIB_TYPES, + "Too many SI messages (%u), max supported is %u\n", + cell->num_SI, + F1AP_MAX_NO_SIB_TYPES); + cell->SI_msg[cell->num_SI].SI_container = copy_byte_array(*enc); + cell->SI_msg[cell->num_SI].SI_type = sib_type; + cell->num_SI++; +} + void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) { AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n"); @@ -427,16 +776,68 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) // Encode CU SIBs and configure setup response with sysinfo seq_arr_t *sibs = rrc->SIBs; if (sibs) { - for (int i = 0; i < sibs->size; i++) { - nr_SIBs_t *sib = (nr_SIBs_t *)seq_arr_at(sibs, i); + FOR_EACH_SEQ_ARR (nr_SIBs_t *, sib, sibs) { switch (sib->SIB_type) { - case 2: { + case NR_SIB_2: { NR_SSB_MTC_t *ssbmtc = get_ssb_mtc(new->mtc); - sib->SIB_size = do_SIB2_NR(&sib->SIB_buffer, ssbmtc); - cell.SI_msg[cell.num_SI].SI_container = sib->SIB_buffer; - cell.SI_msg[cell.num_SI].SI_container_length = sib->SIB_size; - cell.SI_msg[cell.num_SI].SI_type = sib->SIB_type; - cell.num_SI++; + NR_SIB2_t *sib2 = get_sib2_from_cfg(&rrc->sib2_config, ssbmtc); + byte_array_t enc = do_SIB2_NR(sib2); + ASN_STRUCT_FREE(asn_DEF_NR_SIB2, sib2); + if (!enc.buf || enc.len == 0) { + free_byte_array(enc); + LOG_E(NR_RRC, "SIB2 encoding failed\n"); + break; + } + add_si_msg(&cell, sib->SIB_type, &enc); + free_byte_array(enc); + LOG_I(NR_RRC, "DU %ld: added SIB2 to F1 Setup Response (cell %ld)\n", du->gNB_DU_id, new->info.cell_id); + } break; + case NR_SIB_3: { + if (!rrc->neighbour_cell_configuration) + break; + const neighbour_cell_configuration_t *neighbour_config = get_cell_neighbour_list(rrc, new); + if (!neighbour_config) + break; + const seq_arr_t *neigh_cells = &neighbour_config->neighbour_cells; + + NR_SIB3_t *sib3 = get_sib3_intra_freq_neighbors(neigh_cells, get_ssb_arfcn(new)); + if (!sib3) + break; + + byte_array_t enc = do_SIB3_NR(sib3); + ASN_STRUCT_FREE(asn_DEF_NR_SIB3, sib3); + if (!enc.buf || enc.len == 0) { + free_byte_array(enc); + LOG_E(NR_RRC, "SIB3 encoding failed\n"); + break; + } + add_si_msg(&cell, sib->SIB_type, &enc); + free_byte_array(enc); + LOG_I(NR_RRC, "DU %ld: added SIB3 to F1 Setup Response (cell %ld)\n", du->gNB_DU_id, new->info.cell_id); + } break; + case NR_SIB_4: { + if (!rrc->neighbour_cell_configuration) + break; + const neighbour_cell_configuration_t *neighbour_cfg = get_cell_neighbour_list(rrc, new); + if (!neighbour_cfg) + break; + + NR_SIB4_t *sib4 = get_sib4_inter_freq_neighbors(neighbour_cfg, &rrc->inter_freqs, get_ssb_arfcn(new)); + if (!sib4) { + LOG_W(NR_RRC, "SIB4: could not build from neighbours, skipping\n"); + break; + } + + byte_array_t enc = do_SIB4_NR(sib4); + ASN_STRUCT_FREE(asn_DEF_NR_SIB4, sib4); + if (!enc.buf || enc.len == 0) { + free_byte_array(enc); + LOG_E(NR_RRC, "SIB4 encoding failed\n"); + break; + } + add_si_msg(&cell, sib->SIB_type, &enc); + free_byte_array(enc); + LOG_I(NR_RRC, "DU %ld: added SIB4 to F1 Setup Response (cell %ld)\n", du->gNB_DU_id, new->info.cell_id); } break; default: AssertFatal(false, "SIB%d not handled yet\n", sib->SIB_type); @@ -444,9 +845,6 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) } } - if (new->mib != NULL &&new->sib1 != NULL) - label_intra_frequency_neighbours(rrc, new); - resp.cells_to_activate[i] = cell; } @@ -662,10 +1060,6 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update LOG_I(NR_RRC, "update system information of DU %ld\n", du->gNB_DU_id); } } - - if (cell && cell->mib != NULL && cell->sib1 != NULL && cell->assoc_id == du->assoc_id) { - label_intra_frequency_neighbours(rrc, cell); - } } if (conf_up->num_cells_to_delete > 0) { diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index e36e6ee684..fdbc2d66af 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -607,7 +607,6 @@ void nr_HO_N2_trigger_telnet(gNB_RRC_INST *rrc, uint32_t neighbour_pci, uint32_t 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->gNB_DU_id, .nrcell_id = pcell->info.cell_id, .physicalCellId = pcell->info.pci, diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c index b0b3b501cd..0133f81e03 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.c +++ b/openair2/RRC/NR_UE/L2_interface_ue.c @@ -155,6 +155,13 @@ void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id) } } +void nr_mac_rrc_verification_failed(const module_id_t mod_id) +{ + MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_VERIFY); + NR_RRC_MAC_VERIFY (message_p).L2_RRC_verification_failed = true; + itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(mod_id), message_p); +} + void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id) { MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_INAC_IND); diff --git a/openair2/RRC/NR_UE/L2_interface_ue.h b/openair2/RRC/NR_UE/L2_interface_ue.h index 09c7b7daae..5121f0859e 100644 --- a/openair2/RRC/NR_UE/L2_interface_ue.h +++ b/openair2/RRC/NR_UE/L2_interface_ue.h @@ -30,5 +30,6 @@ void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_ void nr_ue_rrc_timer_trigger(int instance, int hfn, int frame, int gnb_id); void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success); void process_msg_rcc_to_mac(nr_mac_rrc_message_t *msg, int instance_id); +void nr_mac_rrc_verification_failed(const module_id_t mod_id); #endif diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 37bca1d45a..5f0fefdcff 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -24,6 +24,7 @@ #include "rrc_defs.h" #include "rrc_proto.h" +#include "verify_RRC.h" #include "L2_interface_ue.h" #include "LAYER2/NR_MAC_UE/mac_proto.h" @@ -3115,6 +3116,11 @@ void *rrc_nrue(void *notUsed) } break; + case NR_RRC_MAC_VERIFY: + LOG_W(NR_RRC, "L2 verification of RRC consistency failed\n"); + handle_rlf_detection(rrc); + break; + case NR_RRC_MAC_INAC_IND: LOG_D(NR_RRC, "Received data inactivity indication from lower layers\n"); NR_Release_Cause_t release_cause = RRC_CONNECTION_FAILURE; diff --git a/openair2/RRC/NR_UE/rrc_proto.h b/openair2/RRC/NR_UE/rrc_proto.h index 5efd15306a..f4bf1b4e1e 100644 --- a/openair2/RRC/NR_UE/rrc_proto.h +++ b/openair2/RRC/NR_UE/rrc_proto.h @@ -72,7 +72,6 @@ void nr_rrc_ue_decode_NR_SBCCH_SL_BCH_Message(NR_UE_RRC_INST_t *rrc, const uint16_t rx_slss_id); void nr_rrc_set_mac_queue(instance_t instance, notifiedFIFO_t *mac_input_nf); -bool check_cellgroup_config(const NR_CellGroupConfig_t *cgConfig); /** @}*/ #endif diff --git a/openair2/RRC/NR_UE/verify_RRC.c b/openair2/RRC/NR_UE/verify_RRC.c index 9d5cd5d726..42d3204d27 100644 --- a/openair2/RRC/NR_UE/verify_RRC.c +++ b/openair2/RRC/NR_UE/verify_RRC.c @@ -188,7 +188,7 @@ static bool check_csi_resourceMapping_consistency(NR_CSI_RS_ResourceMapping_t re return true; } -static bool check_csi_report_consistency(const NR_CSI_MeasConfig_t *meas) +bool check_csi_report_consistency(const NR_CSI_MeasConfig_t *meas) { if (!meas || !meas->csi_ReportConfigToAddModList) return true; @@ -223,8 +223,6 @@ static bool check_csi_resource_consistency(const NR_CSI_MeasConfig_t *meas) static bool check_csi_MeasConfig(struct NR_SetupRelease_CSI_MeasConfig *csi_MeasConfig) { const NR_CSI_MeasConfig_t *meas = csi_MeasConfig->choice.setup; - if (!check_csi_report_consistency(meas)) - return false; if (!check_csi_resource_consistency(meas)) return false; return true; diff --git a/openair2/RRC/NR_UE/verify_RRC.h b/openair2/RRC/NR_UE/verify_RRC.h new file mode 100644 index 0000000000..e4de684402 --- /dev/null +++ b/openair2/RRC/NR_UE/verify_RRC.h @@ -0,0 +1,16 @@ +/* + * SPDX-License-Identifier: LicenseRef-CSSL-1.0 + */ + +/* + * \brief RRC functions prototypes for eNB and UE + */ + +#ifndef _VERIFY_RRC_H_ +#define _VERIFY_RRC_H_ + +#include "NR_MeasConfig.h" + +bool check_csi_report_consistency(const NR_CSI_MeasConfig_t *meas); +bool check_cellgroup_config(const NR_CellGroupConfig_t *cgConfig); +#endif diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 754a2e2f86..78bc0b3de4 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -68,9 +68,17 @@ void ngap_handle_ng_setup_message(ngap_gNB_amf_data_t *amf_desc_p, int sctp_shut } } } else { + if (amf_desc_p->t_reconnect != -1 && amf_desc_p->ngap_gNB_instance->ngap_amf_associated_nb > 0) { + timer_remove(amf_desc_p->t_reconnect); + amf_desc_p->t_reconnect = -1; + NGAP_INFO("reconnected to AMF\n"); + } + /* Check that at least one setup message is pending */ - DevCheck(amf_desc_p->ngap_gNB_instance->ngap_amf_pending_nb > 0, amf_desc_p->ngap_gNB_instance->instance, - amf_desc_p->ngap_gNB_instance->ngap_amf_pending_nb, 0); + DevCheck(amf_desc_p->ngap_gNB_instance->ngap_amf_pending_nb > 0, + amf_desc_p->ngap_gNB_instance->instance, + amf_desc_p->ngap_gNB_instance->ngap_amf_pending_nb, + 0); if (amf_desc_p->ngap_gNB_instance->ngap_amf_pending_nb > 0) { /* Decrease pending messages number */ diff --git a/openair3/NGAP/ngap_gNB_ue_context.c b/openair3/NGAP/ngap_gNB_ue_context.c index 7555685afb..57856a890f 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.c +++ b/openair3/NGAP/ngap_gNB_ue_context.c @@ -94,7 +94,7 @@ void ngap_release_ues_for_amf(ngap_gNB_amf_data_t *amf_desc_p) 0, TASK_NGAP, amf_desc_p->ngap_gNB_instance->instance, - TIMER_ONE_SHOT, + TIMER_PERIODIC, amf_desc_p, &tid); if (rc == 0) { diff --git a/radio/ETHERNET/if_defs.h b/radio/ETHERNET/if_defs.h index e357858137..9e5ec6818e 100644 --- a/radio/ETHERNET/if_defs.h +++ b/radio/ETHERNET/if_defs.h @@ -9,7 +9,7 @@ #include #ifndef LITE_COMPILATION -#include "PHY/LTE_TRANSPORT/if4_tools.h" +#include "PHY/if4_tools.h" #endif // ETH transport preference modes diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index ed330ed30e..3a670f5f7f 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -12,6 +12,7 @@ #include "xran_sync_api.h" #include "common/utils/LOG/log.h" +#include "common/utils/fsn.h" #include "openair1/PHY/defs_gNB.h" #include "openair1/PHY/NR_TRANSPORT/nr_transport_proto.h" #include "oaioran.h" @@ -205,19 +206,21 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) .prach_buf = NULL, }; - prach_item_t *prach_id = find_nr_prach(&ru->gNB_list[0]->prach_list, *frame, *slot, ru->nr_frame_parms->nb_antennas_rx, SEARCH_EXIST); - if (prach_id) { + prach_item_t p; + PHY_VARS_gNB *gNB = ru->gNB_list[0]; + fsn_t now = {.f = *frame, .s = *slot, .mu = gNB->frame_parms.numerology_index}; + if (get_next_nr_prach(&gNB->prach_ru_queue, &now, &p)) { struct xran_fh_config *fh_cfg = get_xran_fh_config(0); int slots_per_subframe = 1 << fh_cfg->frame_conf.nNumerology; uint32_t subframe = *slot / slots_per_subframe; // `slot` = slot in which PRACH is received // PRACH occasion in a frame if and only if SFN % x == y, TS 38.211 Table 6.3.3.2-2/3/4 nr_prach_info_t prach_info = get_prach_info(0); bool is_prach_frame = (*frame % prach_info.x == prach_info.y); - bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (prach_id->slot % slots_per_subframe)); // `prach_id->slot` = slot in which PRACH is scheduled + bool is_prach_slot = is_prach_frame && xran_is_prach_slot(0, subframe, (p.slot % slots_per_subframe)); // `p.slot` = slot in which PRACH is scheduled if (is_prach_slot) { - ru_info.prach_buf = prach_id->prach_buf; + ru_info.prach_buf = p.prach_buf; } else { - LOG_W(HW, "[%d.%d] Expected PRACH reception of scheduled slot %d\n", *frame, *slot, prach_id->slot); + LOG_W(HW, "[%d.%d] Expected PRACH reception of scheduled slot %d\n", *frame, *slot, p.slot); } } @@ -232,6 +235,15 @@ void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) printf("ORAN: %d.%d ORAN_fh_if4p5_south_in ERROR in RX function \n", f, sl); } + if (ru_info.prach_buf) { + // xran_fh_rx_read_slot() should have read PRACH, write back to queue + bool success = spsc_q_put(&gNB->prach_l1rx_queue, &p, sizeof(p)); + // assume prach_l1rx_queue never full: prach_ru_queue filled at + // constant pace, but prach_l1rx_queue emptied as fast as possible, + // see rx_func() + DevAssert(success); + } + int slots_per_frame = 10 << (ru->openair0_cfg.nr_scs_for_raster); proc->tti_rx = sl; proc->frame_rx = f; 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 b5b5708811..735c15ca1c 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 @@ -21,7 +21,7 @@ gNBs: # Physical parameters: do_CSIRS: 1 do_SRS: 1 - first_active_bwp: 1; + first_active_bwp: 1 bwp_list: - scs: 1 diff --git a/tools/cppcheck/README.md b/tools/cppcheck/README.md new file mode 100644 index 0000000000..414f35a68a --- /dev/null +++ b/tools/cppcheck/README.md @@ -0,0 +1,28 @@ + + +# Static code analysis + +How to run static code analysis tool(s). + +[[_TOC_]] + +## cppcheck Overview + +This can run a (dockerized) cppcheck static code analysis. The docker-compose +file represents the status as run as in the CI until it's removal (because it +was not enforced). It is now here so that people could use it to find bugs (and +use the tool more easily). + +## cppcheck Usage + +From the openairinterface5g root, simply run + + ./tools/cppcheck/run-cppcheck.sh + +This will run cppcheck with options listed in this file, assuming you have it +installed. Alternatively, you can run the CI version as of Ubuntu 20 with + + cd tools/cppcheck && docker compose up --no-log-prefix + +You can upgrade to a newer version by modifying the `FROM` line in the +docker-compose file. diff --git a/tools/cppcheck/docker-compose.yaml b/tools/cppcheck/docker-compose.yaml new file mode 100644 index 0000000000..8b8c5878d0 --- /dev/null +++ b/tools/cppcheck/docker-compose.yaml @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: MIT + +services: + cppcheck: + image: cppcheck + build: + dockerfile_inline: | + FROM ubuntu:focal + RUN DEBIAN_FRONTEND=noninteractive apt update && apt install -y cppcheck + volumes: + - ../../:/code/ + command: + bash -c "cd /code/ && ./tools/cppcheck/run-cppcheck.sh" + diff --git a/tools/cppcheck/run-cppcheck.sh b/tools/cppcheck/run-cppcheck.sh new file mode 100755 index 0000000000..5a5df0c752 --- /dev/null +++ b/tools/cppcheck/run-cppcheck.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# SPDX-License-Identifier: MIT + +cppcheck --enable=warning --force \ + --inline-suppr \ + --quiet \ + -i openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c \ + --suppressions-list=tools/cppcheck/suppressions.list \ + -I common/utils \ + -I openair3/NAS/COMMON/UTIL \ + -j`nproc` . diff --git a/ci-scripts/cppcheck_suppressions.list b/tools/cppcheck/suppressions.list similarity index 100% rename from ci-scripts/cppcheck_suppressions.list rename to tools/cppcheck/suppressions.list