mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 20:50:28 +00:00
Compare commits
170 Commits
simple-sta
...
multi_cc_s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a05d9af72 | ||
|
|
7451e4e08c | ||
|
|
088bdc9bcd | ||
|
|
bfb177c38e | ||
|
|
434cd8ca3d | ||
|
|
38167e50f8 | ||
|
|
d1129d1f90 | ||
|
|
6a6f200790 | ||
|
|
1c26f372aa | ||
|
|
0da440017e | ||
|
|
e0a2b4837c | ||
|
|
11dc86f59c | ||
|
|
2d34e6cb9a | ||
|
|
0054b496d4 | ||
|
|
6b06bda933 | ||
|
|
ff4284050d | ||
|
|
7487638d72 | ||
|
|
6b111384e5 | ||
|
|
bb11b8eafe | ||
|
|
c834a694ae | ||
|
|
2f23dd2444 | ||
|
|
46a4097f6a | ||
|
|
b242eb3093 | ||
|
|
d40f56ddd2 | ||
|
|
6cd797c64e | ||
|
|
5558f98154 | ||
|
|
3f5520d792 | ||
|
|
c70ed20ca7 | ||
|
|
80ad56af63 | ||
|
|
b75ddf0e85 | ||
|
|
430e336e15 | ||
|
|
3afda6aea1 | ||
|
|
7af713a1d1 | ||
|
|
9a2a313515 | ||
|
|
9fb78e1b34 | ||
|
|
82f57789a5 | ||
|
|
c5e1c4f34f | ||
|
|
b92936f7d7 | ||
|
|
84a1eb8b07 | ||
|
|
d06bd3d49f | ||
|
|
1bc8e64641 | ||
|
|
6b665a851e | ||
|
|
ba4239653e | ||
|
|
7b7afae05b | ||
|
|
74bc9bf0cc | ||
|
|
b0f63bf83c | ||
|
|
d4f039a326 | ||
|
|
0ecfd11d92 | ||
|
|
77bb143b04 | ||
|
|
e7c4d80a5d | ||
|
|
6b437c5187 | ||
|
|
66a3328b81 | ||
|
|
02f7ecf861 | ||
|
|
fb60743b26 | ||
|
|
6539889821 | ||
|
|
2c34d84d6f | ||
|
|
aa37846454 | ||
|
|
ef632db840 | ||
|
|
384886ce48 | ||
|
|
9ef4efe10a | ||
|
|
46c120651f | ||
|
|
9b0b9dc066 | ||
|
|
be74bfb437 | ||
|
|
5902635d2d | ||
|
|
4a36f46a38 | ||
|
|
7f6e5ff38e | ||
|
|
711c632001 | ||
|
|
f4c4e02d78 | ||
|
|
ca31590282 | ||
|
|
210b9089b9 | ||
|
|
a12050203b | ||
|
|
c3b2b4d30e | ||
|
|
a2230079d8 | ||
|
|
5b1f09faf1 | ||
|
|
57c4633fd6 | ||
|
|
644ba5cdcf | ||
|
|
1b7be0c35a | ||
|
|
6bb7e3cb68 | ||
|
|
29457abe71 | ||
|
|
0dd1243e6e | ||
|
|
27158b9244 | ||
|
|
389d7a0246 | ||
|
|
547f683ebe | ||
|
|
38dc378224 | ||
|
|
93df326273 | ||
|
|
e5c54b5971 | ||
|
|
ff97f0dea6 | ||
|
|
1c512f3dc5 | ||
|
|
32cb3401b4 | ||
|
|
6f2d90fee9 | ||
|
|
f6b6ce2da3 | ||
|
|
aa5bd641fd | ||
|
|
463a3ad1cf | ||
|
|
288e0e1412 | ||
|
|
c1d0e836b4 | ||
|
|
dc550ebaf6 | ||
|
|
03096dd495 | ||
|
|
22783bb3a7 | ||
|
|
879e374d32 | ||
|
|
39d3477d84 | ||
|
|
f5989abd0d | ||
|
|
a5696562da | ||
|
|
2bb1f36a2c | ||
|
|
81b2fe634f | ||
|
|
cb4c307221 | ||
|
|
4a47fbbef7 | ||
|
|
2213235fc1 | ||
|
|
138e0f9547 | ||
|
|
25f77993ca | ||
|
|
cbe69c7dfa | ||
|
|
337abd5716 | ||
|
|
c0a2dc9006 | ||
|
|
a2f8f2ead3 | ||
|
|
c99e5642b5 | ||
|
|
0161568d69 | ||
|
|
1aed7b5802 | ||
|
|
e8e3f60e73 | ||
|
|
85b4057bde | ||
|
|
b15d394212 | ||
|
|
0b752116ee | ||
|
|
3a935bc9f7 | ||
|
|
17a87cd858 | ||
|
|
7fc1d1835a | ||
|
|
3ff08f25ca | ||
|
|
a1b68b9f98 | ||
|
|
e0ef042fe6 | ||
|
|
34aad5d276 | ||
|
|
51e17fd7c8 | ||
|
|
449910dbc7 | ||
|
|
b81442de91 | ||
|
|
7e3406c3bd | ||
|
|
1be48251f0 | ||
|
|
05c2165535 | ||
|
|
8ecc693799 | ||
|
|
74fcab8779 | ||
|
|
45ae5f19e4 | ||
|
|
d694aa68eb | ||
|
|
99c0e6a149 | ||
|
|
a91741818b | ||
|
|
9fe14b784f | ||
|
|
d33466d632 | ||
|
|
90ec531554 | ||
|
|
82f9501424 | ||
|
|
d45a1e209b | ||
|
|
850f03d328 | ||
|
|
08085af943 | ||
|
|
4cda6ab959 | ||
|
|
a1ab732111 | ||
|
|
00c1976078 | ||
|
|
f414ae474c | ||
|
|
10516db5dd | ||
|
|
c866078b21 | ||
|
|
3e515d9c9c | ||
|
|
da7054092a | ||
|
|
4569ef199d | ||
|
|
6f9a716eb9 | ||
|
|
817d1a6cb5 | ||
|
|
c53b28f51d | ||
|
|
9afa94040d | ||
|
|
52d5705f47 | ||
|
|
e27f8c24cf | ||
|
|
7606a93f57 | ||
|
|
185690cb94 | ||
|
|
442b3045d6 | ||
|
|
196855364c | ||
|
|
afb3005a7c | ||
|
|
425ea41ba5 | ||
|
|
dc260bd4d9 | ||
|
|
ec327d26fc | ||
|
|
14cceed229 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@ cmake_targets/*/build/
|
||||
cmake_targets/ran_build/
|
||||
log/
|
||||
lte_build_oai/
|
||||
build*
|
||||
|
||||
# IDE files
|
||||
.vscode
|
||||
|
||||
120
CMakeLists.txt
120
CMakeLists.txt
@@ -83,25 +83,40 @@ option(PACKAGING_COMMON "Will produce a package containing common target, config
|
||||
option(PACKAGING_USRP "Will produce a package containing usrp target, configuration files and docs" OFF)
|
||||
option(PACKAGING_PHYSIM "Will produce a package containing physim target, configuration files and docs" OFF)
|
||||
|
||||
|
||||
# Check if asn1c is installed, and check if it supports all options we need
|
||||
# a user can provide ASN1C_EXEC to override an asn1c to use (e.g., parallel
|
||||
# installation)
|
||||
find_program(ASN1C_EXEC_PATH asn1c HINTS /opt/asn1c/bin)
|
||||
set(ASN1C_EXEC ${ASN1C_EXEC_PATH} CACHE FILEPATH "path to asn1c executable")
|
||||
if(NOT ASN1C_EXEC)
|
||||
message(FATAL_ERROR "No asn1c found!
|
||||
You might want to re-run ./build_oai -I
|
||||
Or provide a path to asn1c using
|
||||
./build_oai ... --cmake-opt -DASN1C_EXEC=/path/to/asn1c
|
||||
")
|
||||
option(AUTO_DOWNLOAD_ASN1C "Automatically download asn1c if not found" OFF)
|
||||
if (ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -gen-APER ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -no-gen-UPER ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -no-gen-JER ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -no-gen-BER ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -no-gen-OER ASN1C_EXEC)
|
||||
add_custom_target(asn1c DEPENDS ${ASN1C_EXEC})
|
||||
else ()
|
||||
if (NOT AUTO_DOWNLOAD_ASN1C)
|
||||
message(FATAL_ERROR "asn1c not found. Install it globally or activate AUTO_DOWNLOAD_ASN1C")
|
||||
endif()
|
||||
message(STATUS "Downloading and compile asn1c local in this build tree")
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
asn1c_gen
|
||||
GIT_REPOSITORY https://github.com/mouse07410/asn1c
|
||||
GIT_TAG 940dd5fa9f3917913fd487b13dfddfacd0ded06e
|
||||
GIT_REMOTE_UPDATE_STRATEGY CHECKOUT
|
||||
BUILD_BYPRODUCTS ${CMAKE_BINARY_DIR}/bin/asn1c
|
||||
BUILD_IN_SOURCE True
|
||||
CONFIGURE_COMMAND autoreconf -i
|
||||
BUILD_COMMAND ./configure --prefix ${CMAKE_BINARY_DIR}
|
||||
COMMAND make -j8 CFLAGS=-fno-strict-aliasing -Wmisleading-indentation
|
||||
STEP_TARGETS build
|
||||
)
|
||||
set(ASN1C_EXEC ${CMAKE_BINARY_DIR}/bin/asn1c)
|
||||
add_custom_target(asn1c DEPENDS asn1c_gen)
|
||||
endif()
|
||||
check_option(${ASN1C_EXEC} -gen-APER ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -no-gen-UPER ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -no-gen-JER ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -no-gen-BER ASN1C_EXEC)
|
||||
check_option(${ASN1C_EXEC} -no-gen-OER ASN1C_EXEC)
|
||||
|
||||
#########################################################
|
||||
# Base directories, compatible with legacy OAI building #
|
||||
#########################################################
|
||||
@@ -420,7 +435,6 @@ add_library(ngap
|
||||
${NGAP_DIR}/ngap_gNB_pdu_session_management.c
|
||||
${NGAP_DIR}/ngap_gNB_nnsf.c
|
||||
${NGAP_DIR}/ngap_gNB_overload.c
|
||||
${NGAP_DIR}/ngap_gNB_trace.c
|
||||
${NGAP_DIR}/ngap_gNB_ue_context.c
|
||||
${NGAP_DIR}/ngap_gNB_NRPPa_transport_procedures.c
|
||||
)
|
||||
@@ -709,14 +723,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 +767,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)
|
||||
@@ -866,7 +882,6 @@ set(PHY_SRC_COMMON
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/sqrt.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/get_sin_cos.c
|
||||
${OPENAIR1_DIR}/PHY/TOOLS/oai_arith_operations.c
|
||||
${OPENAIR1_DIR}/PHY/log_tools.c
|
||||
)
|
||||
|
||||
set(PHY_SRC
|
||||
@@ -877,6 +892,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 +912,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 +1087,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 +1099,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 +1763,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 +1778,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 +1817,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 +1833,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 +1862,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 +1907,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 +1931,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 +2009,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 +2026,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 +2045,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 +2061,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 +2074,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 +2085,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 +2154,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)
|
||||
|
||||
8
NOTICE
8
NOTICE
@@ -84,3 +84,11 @@ Nuand: https://github.com/Nuand/bladeRF/tree/master?tab=License-1-ov-file
|
||||
|
||||
Credits for https://github.com/pothosware/SoapySDR
|
||||
Pothosware: BSL 1.0 License
|
||||
|
||||
Credits for https://github.com/zeromq/libzmq
|
||||
ZeroMQ authors: Mozilla Public License Version 2.0
|
||||
|
||||
Credits for source code:
|
||||
- radio/zmq/zmq_imported.cpp
|
||||
- radio/zmq/zmq_imported.h
|
||||
Software Radio Systems Limited: BSD-3-Clause-Open-MPI
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -79,11 +79,11 @@ oc-cn5g:
|
||||
|
||||
oc-cn5g-20897:
|
||||
Host: cacofonix
|
||||
NetworkScript: echo "inet 172.21.6.105"
|
||||
NetworkScript: echo "inet 172.21.6.115"
|
||||
RunIperf3Server: False
|
||||
Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72"
|
||||
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72"
|
||||
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2025-jan oaicicd-core-for-fhi72 %%log_dir%%"
|
||||
Deploy: "! scripts/oc-cn5g-deploy.sh /opt/oai-cn5g-fed-develop-2026-apr oaicicd-core-for-fhi72"
|
||||
Undeploy: "! scripts/oc-cn5g-undeploy.sh /opt/oai-cn5g-fed-develop-2026-apr oaicicd-core-for-fhi72"
|
||||
LogCollect: "! scripts/oc-cn5g-logcollect.sh /opt/oai-cn5g-fed-develop-2026-apr oaicicd-core-for-fhi72 %%log_dir%%"
|
||||
|
||||
oc-cn5g-00103-ho:
|
||||
Host: groot
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -379,90 +379,6 @@ class HTMLManagement():
|
||||
self.htmlFile.write(' </tr>\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(' <tr bgcolor = "#F0F0F0" >\n')
|
||||
self.htmlFile.write(' <td colspan="6"><b> Results for cppcheck v ' + version + ' </b></td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> NB ERRORS</b></td>\n')
|
||||
if CCR.nbErrors[vId] == 0:
|
||||
myColor = 'lightgreen'
|
||||
elif CCR.nbErrors[vId] < 20:
|
||||
myColor = 'orange'
|
||||
else:
|
||||
myColor = 'lightcoral'
|
||||
self.htmlFile.write(' <td colspan="3" bgcolor = "' + myColor + '"><b>' + str(CCR.nbErrors[vId]) + '</b></td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> NB WARNINGS</b></td>\n')
|
||||
if CCR.nbWarnings[vId] == 0:
|
||||
myColor = 'lightgreen'
|
||||
elif CCR.nbWarnings[vId] < 20:
|
||||
myColor = 'orange'
|
||||
else:
|
||||
myColor = 'lightcoral'
|
||||
self.htmlFile.write(' <td colspan="3" bgcolor = "' + myColor + '"><b>' + str(CCR.nbWarnings[vId]) + '</b></td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr bgcolor = "#F0F0F0" >\n')
|
||||
self.htmlFile.write(' <td colspan="6"> ----------------- </td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Memory leak</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbMemLeaks[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Possible null pointer deference</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbNullPtrs[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Uninitialized variable</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbUninitVars[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Undefined behaviour shifting</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbTooManyBitsShift[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Signed integer overflow</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbIntegerOverflow[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr bgcolor = "#F0F0F0" >\n')
|
||||
self.htmlFile.write(' <td colspan="6"> </td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Printf formatting issues</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbInvalidPrintf[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Modulo result is predetermined</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbModuloAlways[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Opposite Condition -> dead code</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbOppoInnerCondition[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
self.htmlFile.write(' <tr>\n')
|
||||
self.htmlFile.write(' <td></td>\n')
|
||||
self.htmlFile.write(' <td colspan="2" bgcolor = "lightcyan" ><b> Wrong Scanf Nb Args</b></td>\n')
|
||||
self.htmlFile.write(' <td colspan="3">' + str(CCR.nbWrongScanfArg[vId]) + '</td>\n')
|
||||
self.htmlFile.write(' </tr>\n')
|
||||
vId += 1
|
||||
|
||||
def CreateHtmlTestRowPhySimTestResult(self, testSummary, testResult):
|
||||
if (self.htmlFooterCreated or (not self.htmlHeaderCreated)):
|
||||
return
|
||||
|
||||
@@ -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<version>[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')
|
||||
|
||||
@@ -215,6 +215,7 @@ L1s =
|
||||
(
|
||||
{
|
||||
num_cc = 1;
|
||||
prach_dtx_threshold = 200;
|
||||
tr_n_preference = "local_mac";
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -186,10 +186,10 @@ MACRLCs = (
|
||||
local_s_portd = 50011; // vnf p7 port [!]
|
||||
tr_s_preference = "aerial";
|
||||
tr_n_preference = "local_RRC";
|
||||
pucch_RSSI_Threshold = -270;
|
||||
pusch_RSSI_Threshold = -260;
|
||||
pusch_TargetSNRx10 = 260; # 150;
|
||||
pucch_TargetSNRx10 = 200; #200;
|
||||
pucch_RSSI_Threshold = -270;
|
||||
pusch_RSSI_Threshold = -260;
|
||||
pusch_TargetSNRx10 = 290;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
dl_max_mcs = 28;
|
||||
ul_max_mcs = 28;
|
||||
ul_min_mcs = 9;
|
||||
|
||||
@@ -161,7 +161,7 @@ gNBs =
|
||||
|
||||
|
||||
////////// AMF parameters:
|
||||
amf_ip_address = ({ ipv4 = "172.21.6.103"; });
|
||||
amf_ip_address = ({ ipv4 = "172.21.6.113"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
|
||||
@@ -197,7 +197,7 @@ RUs = (
|
||||
nb_tx = 2;
|
||||
nb_rx = 2;
|
||||
att_tx = 0;
|
||||
att_rx = 0;
|
||||
att_rx = 6;
|
||||
bands = [77];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 71;
|
||||
|
||||
@@ -18,7 +18,7 @@ gNBs =
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
use_deltaMCS = 1;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
@@ -180,7 +180,7 @@ MACRLCs = (
|
||||
{
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "local_RRC";
|
||||
pusch_TargetSNRx10 = 200;
|
||||
pusch_TargetSNRx10 = 100;
|
||||
pucch_TargetSNRx10 = 200;
|
||||
ul_prbblack_SNR_threshold = 10;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -13,11 +13,12 @@ RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install --yes \
|
||||
libgtest-dev \
|
||||
libyaml-cpp-dev
|
||||
libyaml-cpp-dev \
|
||||
libzmq3-dev
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
WORKDIR /oai-ran/build
|
||||
RUN cmake -GNinja -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug -DSANITIZE_ADDRESS=True .. && ninja tests
|
||||
RUN cmake -GNinja -DENABLE_TESTS=ON -DOAI_ZMQ=ON -DCMAKE_BUILD_TYPE=Debug -DSANITIZE_ADDRESS=True .. && ninja tests
|
||||
|
||||
@@ -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"
|
||||
|
||||
48
ci-scripts/scripts/vvdn-activate-carriers.sh
Executable file
48
ci-scripts/scripts/vvdn-activate-carriers.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
set -e
|
||||
|
||||
RU_IP="10.10.0.111"
|
||||
RU_HOST="root@10.10.0.111"
|
||||
|
||||
ssh_exec() {
|
||||
ssh $RU_HOST $@ </dev/null
|
||||
}
|
||||
|
||||
echo "→ Checking for PTP fluctuations in the last 60 minutes..."
|
||||
|
||||
logs=$(journalctl -u ptp4l.service --since "60 minutes ago")
|
||||
|
||||
check_ptp=$(echo "$logs" | awk '
|
||||
/rms/ {
|
||||
rms=$8
|
||||
if (rms > 100) {
|
||||
print "✗ PTP FLUCTUATION DETECTED → " $0
|
||||
exit 0
|
||||
}
|
||||
}
|
||||
')
|
||||
|
||||
if [ -n "$check_ptp" ]; then
|
||||
echo "$check_ptp"
|
||||
else
|
||||
echo "✓ No PTP fluctuations detected."
|
||||
fi
|
||||
|
||||
echo "→ Checking if VVDN LPRU is PTP synchronized (timeout 1 min)..."
|
||||
if ssh_exec 'timeout 1m sh -c "tail -F /var/log/synctimingptp2.log | grep -m 1 -F ,\ synchronized"'; then
|
||||
echo "✓ VVDN LPRU synchronized"
|
||||
else
|
||||
echo "✗ VVDN LPRU not synchronized"
|
||||
fi
|
||||
|
||||
echo "→ Checking TX/RX carrier configuration..."
|
||||
if ssh_exec 'sysrepocfg -X -d running -f xml | grep -q "<active>INACTIVE</active>"'; then
|
||||
echo "→ Some carriers are not active, activating via sysrepocfg..."
|
||||
ssh_exec 'sysrepocfg -X -d running -f xml | sed "s/<active>INACTIVE<\/active>/<active>ACTIVE<\/active>/g" | sysrepocfg -I -d running -f xml'
|
||||
echo "✓ All TX/RX carriers activated."
|
||||
else
|
||||
echo "✓ All TX/RX carriers already activated."
|
||||
fi
|
||||
exit 0
|
||||
14
ci-scripts/scripts/vvdn-inactivate-carriers.sh
Executable file
14
ci-scripts/scripts/vvdn-inactivate-carriers.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
set -e
|
||||
|
||||
RU_HOST="root@10.10.0.111"
|
||||
|
||||
ssh_exec() {
|
||||
ssh $RU_HOST $@ </dev/null
|
||||
}
|
||||
|
||||
echo "→ Inactivating TX/RX carriers on VVDN LPRU..."
|
||||
ssh_exec 'sysrepocfg -X -d running -f xml | sed "s/ACTIVE/INACTIVE/g" | sysrepocfg -I -d running -f xml'
|
||||
echo "✓ TX/RX carriers inactivated."
|
||||
@@ -23,7 +23,6 @@
|
||||
- Deploy_Object
|
||||
- Stop_Object
|
||||
- Undeploy_Object
|
||||
- Cppcheck_Analysis
|
||||
- Deploy_Run_OC_PhySim
|
||||
- Build_Deploy_PhySim
|
||||
- LicenceAndFormattingCheck
|
||||
|
||||
109
ci-scripts/xml_files/container_5g_zmq_2x2.xml
Normal file
109
ci-scripts/xml_files/container_5g_zmq_2x2.xml
Normal file
@@ -0,0 +1,109 @@
|
||||
<!-- SPDX-License-Identifier: LicenseRef-CSSL-1.0 -->
|
||||
|
||||
<testCaseList>
|
||||
<htmlTabRef>zmq-5gnr-tdd-2x2</htmlTabRef>
|
||||
<htmlTabName>Monolithic SA TDD 2x2 gNB with zmq radio</htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
|
||||
<testCase>
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<node>localhost</node>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Create_Workspace</class>
|
||||
<desc>Create new Workspace</desc>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G CoreNetwork</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_2x2/</yaml_path>
|
||||
<services>mysql oai-amf oai-smf oai-upf oai-ext-dn</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G gNB+UE RF sim SA</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_2x2</yaml_path>
|
||||
<services>oai-gnb oai-nr-ue</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Attach_UE</class>
|
||||
<desc>Attach OAI UE (Wait for IP)</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Ping</class>
|
||||
<desc>Ping ext-dn from NR-UE</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Ping</class>
|
||||
<desc>Ping NR-UE from ext-dn</desc>
|
||||
<id>rfsim5g_ext_dn</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ue</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Iperf</class>
|
||||
<desc>Iperf (DL/10Mbps/UDP)(20 sec)</desc>
|
||||
<iperf_args>-u -b 10M -t 20 -R</iperf_args>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>90</iperf_bitrate_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Iperf</class>
|
||||
<desc>Iperf (UL/3Mbps/UDP)(20 sec)</desc>
|
||||
<iperf_args>-u -b 3M -t 20</iperf_args>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>90</iperf_bitrate_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Undeploy_Object</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Undeploy all OAI 5G stack</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_2x2</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-gnb=RetxCheck=1,0,0,0 oai-gnb=EndsWithBye oai-nr-ue</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Clean_Test_Server_Images</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<node>localhost</node>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
109
ci-scripts/xml_files/container_5g_zmq_ocudu_1x1.xml
Normal file
109
ci-scripts/xml_files/container_5g_zmq_ocudu_1x1.xml
Normal file
@@ -0,0 +1,109 @@
|
||||
<!-- SPDX-License-Identifier: LicenseRef-CSSL-1.0 -->
|
||||
|
||||
<testCaseList>
|
||||
<htmlTabRef>ocudu-5gnr-tdd-1x1</htmlTabRef>
|
||||
<htmlTabName>OCUDU gnb split8 with OAI UE</htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
|
||||
<testCase>
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<node>localhost</node>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Create_Workspace</class>
|
||||
<desc>Create new Workspace</desc>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G CoreNetwork</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_1x1_ocudu</yaml_path>
|
||||
<services>mysql oai-amf oai-smf oai-upf oai-ext-dn</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OCUDU Split 8 gNB + OAI UE</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_1x1_ocudu</yaml_path>
|
||||
<services>ocudu-gnb oai-nr-ue</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Attach_UE</class>
|
||||
<desc>Attach OAI UE (Wait for IP)</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Ping</class>
|
||||
<desc>Ping ext-dn from NR-UE</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Ping</class>
|
||||
<desc>Ping NR-UE from ext-dn</desc>
|
||||
<id>rfsim5g_ext_dn</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ue</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Iperf</class>
|
||||
<desc>Iperf (DL/3Mbps/UDP)(20 sec)</desc>
|
||||
<iperf_args>-u -b 3M -t 20 -R</iperf_args>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>90</iperf_bitrate_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Iperf</class>
|
||||
<desc>Iperf (UL/3Mbps/UDP)(20 sec)</desc>
|
||||
<iperf_args>-u -b 3M -t 20</iperf_args>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>90</iperf_bitrate_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Undeploy_Object</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Undeploy all OAI 5G stack</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_1x1_ocudu</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-nr-ue</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Clean_Test_Server_Images</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<node>localhost</node>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
109
ci-scripts/xml_files/container_5g_zmq_ocudu_2x2.xml
Normal file
109
ci-scripts/xml_files/container_5g_zmq_ocudu_2x2.xml
Normal file
@@ -0,0 +1,109 @@
|
||||
<!-- SPDX-License-Identifier: LicenseRef-CSSL-1.0 -->
|
||||
|
||||
<testCaseList>
|
||||
<htmlTabRef>ocudu-5gnr-tdd-2x2</htmlTabRef>
|
||||
<htmlTabName>OCUDU gnb split8 with OAI UE</htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
|
||||
<testCase>
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
<node>localhost</node>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Create_Workspace</class>
|
||||
<desc>Create new Workspace</desc>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OAI 5G CoreNetwork</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_2x2_ocudu</yaml_path>
|
||||
<services>mysql oai-amf oai-smf oai-upf oai-ext-dn</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Deploy_Object</class>
|
||||
<desc>Deploy OCUDU Split 8 gNB + OAI UE</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_2x2_ocudu</yaml_path>
|
||||
<services>ocudu-gnb oai-nr-ue</services>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Attach_UE</class>
|
||||
<desc>Attach OAI UE (Wait for IP)</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Ping</class>
|
||||
<desc>Ping ext-dn from NR-UE</desc>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Ping</class>
|
||||
<desc>Ping NR-UE from ext-dn</desc>
|
||||
<id>rfsim5g_ext_dn</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ue</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<ping_args>-c 20 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Iperf</class>
|
||||
<desc>Iperf (DL/10Mbps/UDP)(20 sec)</desc>
|
||||
<iperf_args>-u -b 1M -t 20 -R</iperf_args>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>90</iperf_bitrate_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Iperf</class>
|
||||
<desc>Iperf (UL/3Mbps/UDP)(20 sec)</desc>
|
||||
<iperf_args>-u -b 1M -t 20</iperf_args>
|
||||
<id>rfsim5g_ue</id>
|
||||
<node>localhost</node>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>localhost</svr_node>
|
||||
<iperf_packetloss_threshold>5</iperf_packetloss_threshold>
|
||||
<iperf_bitrate_threshold>90</iperf_bitrate_threshold>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Undeploy_Object</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Undeploy all OAI 5G stack</desc>
|
||||
<node>localhost</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_zmq_radio_2x2_ocudu</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-nr-ue</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Clean_Test_Server_Images</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Clean Test Images on Test Server</desc>
|
||||
<node>localhost</node>
|
||||
<images>oai-gnb-asan oai-nr-ue-asan</images>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
@@ -122,7 +122,7 @@
|
||||
<node>gracehopper1-oai</node>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_gnb_aerial</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-gnb-aerial=RetxCheck=20,100,100,100 oai-gnb-aerial=EndsWithBye</services>
|
||||
<services>oai-gnb-aerial=EndsWithBye</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
<node>gracehopper1-oai</node>
|
||||
<yaml_path>ci-scripts/yaml_files/sa_gnb_aerial_ul</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-gnb-aerial=RetxCheck=20,100,100,100 oai-gnb-aerial=EndsWithBye</services>
|
||||
<services>oai-gnb-aerial=EndsWithBye</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
<script>yaml_files/sa_fhi_7.2_vvdn_gnb/setup_config.sh</script>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Custom_Script</class>
|
||||
<desc>Activate carriers on VVDN RU</desc>
|
||||
<node>cacofonix</node>
|
||||
<script>scripts/vvdn-activate-carriers.sh</script>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Pull_Local_Registry</class>
|
||||
<desc>Pull Images from Local Registry</desc>
|
||||
@@ -134,9 +141,9 @@
|
||||
<testCase>
|
||||
<class>Custom_Script</class>
|
||||
<always_exec>true</always_exec>
|
||||
<desc>Set CPU to idle state, set kernel parameters to default values</desc>
|
||||
<desc>Inactivate carriers on VVDN RU</desc>
|
||||
<node>cacofonix</node>
|
||||
<script>yaml_files/sa_fhi_7.2_vvdn_gnb/setup_cleanup.sh</script>
|
||||
<script>scripts/vvdn-inactivate-carriers.sh</script>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<node>matix</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_sa_n310_2x2_100MHz</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-gnb=RetxCheck=dl=10,100,100,100;ul=25,100,100,100 oai-gnb=EndsWithBye</services>
|
||||
<services>oai-gnb=EndsWithBye</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<node>matix</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_sa_n310_2x2_60MHz</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-gnb=RetxCheck=dl=15,100,100,100;ul=20,100,100,100 oai-gnb=EndsWithBye</services>
|
||||
<services>oai-gnb=EndsWithBye</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<node>matix</node>
|
||||
<yaml_path>ci-scripts/yaml_files/5g_sa_n310_4x4_60MHz</yaml_path>
|
||||
<analysis>
|
||||
<services>oai-vnf=RetxCheck=10,100,100,100 oai-vnf=EndsWithBye oai-pnf=EndsWithBye</services>
|
||||
<services>oai-vnf=EndsWithBye oai-pnf=EndsWithBye</services>
|
||||
</analysis>
|
||||
</testCase>
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<!-- SPDX-License-Identifier: LicenseRef-CSSL-1.0 -->
|
||||
|
||||
<testCaseList>
|
||||
<htmlTabRef>build-tab</htmlTabRef>
|
||||
<htmlTabName>CPPCHECK Analysis</htmlTabName>
|
||||
<htmlTabIcon>wrench</htmlTabIcon>
|
||||
|
||||
<testCase>
|
||||
<class>Create_Workspace</class>
|
||||
<desc>Create new Workspace</desc>
|
||||
<node>carabe</node>
|
||||
</testCase>
|
||||
|
||||
<testCase>
|
||||
<class>Cppcheck_Analysis</class>
|
||||
<desc>Static Code Analysis with cppcheck</desc>
|
||||
<node>carabe</node>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;"\
|
||||
|
||||
@@ -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;"\
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;"\
|
||||
|
||||
@@ -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;"\
|
||||
|
||||
@@ -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;"\
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;"\
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;"\
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;"\
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
162
ci-scripts/yaml_files/5g_zmq_radio_1x1_ocudu/docker-compose.yaml
Normal file
162
ci-scripts/yaml_files/5g_zmq_radio_1x1_ocudu/docker-compose.yaml
Normal file
@@ -0,0 +1,162 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
services:
|
||||
mysql:
|
||||
container_name: "rfsim5g-mysql"
|
||||
image: mysql:8.0
|
||||
init: true
|
||||
volumes:
|
||||
- ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql
|
||||
- ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
- MYSQL_DATABASE=oai_db
|
||||
- MYSQL_USER=test
|
||||
- MYSQL_PASSWORD=test
|
||||
- MYSQL_ROOT_PASSWORD=linux
|
||||
healthcheck:
|
||||
test: /bin/bash -c "/tmp/mysql-healthcheck.sh"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.131
|
||||
oai-amf:
|
||||
container_name: "rfsim5g-oai-amf"
|
||||
image: oaisoftwarealliance/oai-amf:v2.1.10
|
||||
environment:
|
||||
- TZ=Europe/paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-amf/etc/config.yaml
|
||||
depends_on:
|
||||
- mysql
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.132
|
||||
oai-smf:
|
||||
container_name: "rfsim5g-oai-smf"
|
||||
image: oaisoftwarealliance/oai-smf:v2.1.10
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-smf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-amf
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.133
|
||||
oai-upf:
|
||||
container_name: "rfsim5g-oai-upf"
|
||||
image: oaisoftwarealliance/oai-upf:v2.1.10
|
||||
init: true
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-upf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-smf
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
cap_drop:
|
||||
- ALL
|
||||
privileged: true
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.134
|
||||
interface_name: eth0
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.134
|
||||
interface_name: eth1
|
||||
oai-ext-dn:
|
||||
privileged: true
|
||||
container_name: rfsim5g-oai-ext-dn
|
||||
image: oaisoftwarealliance/trf-gen-cn5g:focal
|
||||
init: true
|
||||
entrypoint: /bin/bash -c \
|
||||
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
|
||||
"ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity"
|
||||
depends_on:
|
||||
- oai-upf
|
||||
networks:
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.135
|
||||
healthcheck:
|
||||
test: /bin/bash -c "ping -c 2 192.168.72.134"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
ocudu-gnb:
|
||||
image: ghcr.io/bpodrygajlo/ocudu/ocudu-avx2:7cecca5
|
||||
container_name: ocudu-gnb
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- SYS_NICE
|
||||
depends_on:
|
||||
- oai-ext-dn
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.140
|
||||
volumes:
|
||||
- ./ocudu.yml:/ocudu.yml
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep gnb_split_8"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
command: ./usr/local/bin/gnb_split_8 -c /ocudu.yml
|
||||
|
||||
oai-nr-ue:
|
||||
image: ${REGISTRY-oaisoftwarealliance/}${NRUE_IMG:-oai-nr-ue}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-nr-ue
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- NET_ADMIN # for interface bringup
|
||||
- NET_RAW # for ping
|
||||
- SYS_NICE
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: -r 51 --numerology 1 --band 78 -C 3489420000 --ssb 0 -E --uicc0.imsi 208990100001100 --uecap_file /opt/oai-nr-ue/etc/uecap.xml --log_config.global_log_options level,nocolor,time --device.name oai_zmqdevif --zmq.[0].tx_channels tcp://0.0.0.0:4556 --zmq.[0].rx_channels tcp://192.168.71.140:4558
|
||||
depends_on:
|
||||
- ocudu-gnb
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.150
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports1.xml:/opt/oai-nr-ue/etc/uecap.xml
|
||||
- ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-uesoftmodem"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
networks:
|
||||
public_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-public-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.71.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-public"
|
||||
traffic_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-traffic-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.72.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-traffic"
|
||||
52
ci-scripts/yaml_files/5g_zmq_radio_1x1_ocudu/ocudu.yml
Normal file
52
ci-scripts/yaml_files/5g_zmq_radio_1x1_ocudu/ocudu.yml
Normal file
@@ -0,0 +1,52 @@
|
||||
# SPDX-FileCopyrightText: Copyright (C) 2021-2026 Software Radio Systems Limited
|
||||
# SPDX-License-Identifier: BSD-3-Clause-Open-MPI
|
||||
# Refer to https://gitlab.com/ocudu/ocudu/-/raw/dev/LICENSE?ref_type=heads
|
||||
|
||||
cu_cp:
|
||||
amf:
|
||||
addrs: 192.168.71.132
|
||||
port: 38412
|
||||
bind_addrs: 192.168.71.140
|
||||
supported_tracking_areas:
|
||||
- tac: 1
|
||||
plmn_list:
|
||||
- plmn: "20899"
|
||||
tai_slice_support_list:
|
||||
- sst: 1
|
||||
|
||||
ru_sdr:
|
||||
device_driver: zmq
|
||||
device_args: tx_port=tcp://0.0.0.0:4558,rx_port=tcp://192.168.71.150:4556
|
||||
srate: 23.04
|
||||
tx_gain: 25
|
||||
rx_gain: 25
|
||||
|
||||
cell_cfg:
|
||||
dl_arfcn: 632628
|
||||
band: 78
|
||||
channel_bandwidth_MHz: 20
|
||||
common_scs: 30
|
||||
plmn: "20899"
|
||||
tac: 1
|
||||
pci: 1
|
||||
tdd_ul_dl_cfg:
|
||||
dl_ul_tx_period: 5
|
||||
nof_dl_slots: 3
|
||||
nof_dl_symbols: 10
|
||||
nof_ul_slots: 1
|
||||
nof_ul_symbols: 2
|
||||
csi:
|
||||
csi_rs_enabled: false
|
||||
pucch:
|
||||
formats: f0_and_f2
|
||||
nof_cell_csi_res: 0
|
||||
|
||||
log:
|
||||
filename: gnb.log
|
||||
all_level: debug
|
||||
|
||||
pcap:
|
||||
mac_enable: false
|
||||
mac_filename: /tmp/gnb_mac.pcap
|
||||
ngap_enable: false
|
||||
ngap_filename: /tmp/gnb_ngap.pcap
|
||||
164
ci-scripts/yaml_files/5g_zmq_radio_2x2/docker-compose.yaml
Normal file
164
ci-scripts/yaml_files/5g_zmq_radio_2x2/docker-compose.yaml
Normal file
@@ -0,0 +1,164 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
services:
|
||||
mysql:
|
||||
container_name: "rfsim5g-mysql"
|
||||
image: mysql:8.0
|
||||
init: true
|
||||
volumes:
|
||||
- ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql
|
||||
- ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
- MYSQL_DATABASE=oai_db
|
||||
- MYSQL_USER=test
|
||||
- MYSQL_PASSWORD=test
|
||||
- MYSQL_ROOT_PASSWORD=linux
|
||||
healthcheck:
|
||||
test: /bin/bash -c "/tmp/mysql-healthcheck.sh"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.131
|
||||
oai-amf:
|
||||
container_name: "rfsim5g-oai-amf"
|
||||
image: oaisoftwarealliance/oai-amf:v2.1.10
|
||||
environment:
|
||||
- TZ=Europe/paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-amf/etc/config.yaml
|
||||
depends_on:
|
||||
- mysql
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.132
|
||||
oai-smf:
|
||||
container_name: "rfsim5g-oai-smf"
|
||||
image: oaisoftwarealliance/oai-smf:v2.1.10
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-smf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-amf
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.133
|
||||
oai-upf:
|
||||
container_name: "rfsim5g-oai-upf"
|
||||
image: oaisoftwarealliance/oai-upf:v2.1.10
|
||||
init: true
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-upf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-smf
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
cap_drop:
|
||||
- ALL
|
||||
privileged: true
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.134
|
||||
interface_name: eth0
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.134
|
||||
interface_name: eth1
|
||||
oai-ext-dn:
|
||||
privileged: true
|
||||
container_name: rfsim5g-oai-ext-dn
|
||||
image: oaisoftwarealliance/trf-gen-cn5g:focal
|
||||
init: true
|
||||
entrypoint: /bin/bash -c \
|
||||
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
|
||||
"ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity"
|
||||
depends_on:
|
||||
- oai-upf
|
||||
networks:
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.135
|
||||
healthcheck:
|
||||
test: /bin/bash -c "ping -c 2 192.168.72.134"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
oai-gnb:
|
||||
image: ${REGISTRY-oaisoftwarealliance/}${GNB_IMG:-oai-gnb}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-gnb
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- SYS_NICE
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: --log_config.global_log_options level,nocolor,time --device.name oai_zmqdevif --zmq.[0].tx_channels tcp://0.0.0.0:4558,tcp://0.0.0.0:4559 --zmq.[0].rx_channels tcp://oai-nr-ue:4556,tcp://oai-nr-ue:4557
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
depends_on:
|
||||
- oai-ext-dn
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.140
|
||||
volumes:
|
||||
- ../../conf_files/gnb.sa.band78.273prb.rfsim.2x2.conf:/opt/oai-gnb/etc/gnb.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-softmodem"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
oai-nr-ue:
|
||||
image: ${REGISTRY-oaisoftwarealliance/}${NRUE_IMG:-oai-nr-ue}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-nr-ue
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- NET_ADMIN # for interface bringup
|
||||
- NET_RAW # for ping
|
||||
- SYS_NICE
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: -r 273 --numerology 1 --band 78 -C 3450720000 --ssb 1518 --ue-nb-ant-tx 2 --uicc0.imsi 208990100001100 --ue-nb-ant-rx 2 --uecap_file /opt/oai-nr-ue/etc/uecap.xml --log_config.global_log_options level,nocolor,time --device.name oai_zmqdevif --zmq.[0].tx_channels tcp://0.0.0.0:4556,tcp://0.0.0.0:4557 --zmq.[0].rx_channels tcp://oai-gnb:4558,tcp://oai-gnb:4559
|
||||
depends_on:
|
||||
- oai-gnb
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.150
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports2.xml:/opt/oai-nr-ue/etc/uecap.xml
|
||||
- ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-uesoftmodem"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
networks:
|
||||
public_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-public-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.71.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-public"
|
||||
traffic_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-traffic-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.72.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-traffic"
|
||||
162
ci-scripts/yaml_files/5g_zmq_radio_2x2_ocudu/docker-compose.yaml
Normal file
162
ci-scripts/yaml_files/5g_zmq_radio_2x2_ocudu/docker-compose.yaml
Normal file
@@ -0,0 +1,162 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
services:
|
||||
mysql:
|
||||
container_name: "rfsim5g-mysql"
|
||||
image: mysql:8.0
|
||||
init: true
|
||||
volumes:
|
||||
- ../5g_rfsimulator/oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql
|
||||
- ../5g_rfsimulator/mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
- MYSQL_DATABASE=oai_db
|
||||
- MYSQL_USER=test
|
||||
- MYSQL_PASSWORD=test
|
||||
- MYSQL_ROOT_PASSWORD=linux
|
||||
healthcheck:
|
||||
test: /bin/bash -c "/tmp/mysql-healthcheck.sh"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.131
|
||||
oai-amf:
|
||||
container_name: "rfsim5g-oai-amf"
|
||||
image: oaisoftwarealliance/oai-amf:v2.1.10
|
||||
environment:
|
||||
- TZ=Europe/paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-amf/etc/config.yaml
|
||||
depends_on:
|
||||
- mysql
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.132
|
||||
oai-smf:
|
||||
container_name: "rfsim5g-oai-smf"
|
||||
image: oaisoftwarealliance/oai-smf:v2.1.10
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-smf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-amf
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.133
|
||||
oai-upf:
|
||||
container_name: "rfsim5g-oai-upf"
|
||||
image: oaisoftwarealliance/oai-upf:v2.1.10
|
||||
init: true
|
||||
environment:
|
||||
- TZ=Europe/Paris
|
||||
volumes:
|
||||
- ../5g_rfsimulator/mini_nonrf_config.yaml:/openair-upf/etc/config.yaml
|
||||
depends_on:
|
||||
- oai-smf
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- SYS_ADMIN
|
||||
cap_drop:
|
||||
- ALL
|
||||
privileged: true
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.134
|
||||
interface_name: eth0
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.134
|
||||
interface_name: eth1
|
||||
oai-ext-dn:
|
||||
privileged: true
|
||||
container_name: rfsim5g-oai-ext-dn
|
||||
image: oaisoftwarealliance/trf-gen-cn5g:focal
|
||||
init: true
|
||||
entrypoint: /bin/bash -c \
|
||||
"iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\
|
||||
"ip route add 12.1.1.0/24 via 192.168.72.134 dev eth0; sleep infinity"
|
||||
depends_on:
|
||||
- oai-upf
|
||||
networks:
|
||||
traffic_net:
|
||||
ipv4_address: 192.168.72.135
|
||||
healthcheck:
|
||||
test: /bin/bash -c "ping -c 2 192.168.72.134"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
ocudu-gnb:
|
||||
image: ghcr.io/bpodrygajlo/ocudu/ocudu-avx2:7cecca5
|
||||
container_name: ocudu-gnb
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- SYS_NICE
|
||||
depends_on:
|
||||
- oai-ext-dn
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.140
|
||||
volumes:
|
||||
- ./ocudu.yml:/ocudu.yml
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep gnb_split_8"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
command: ./usr/local/bin/gnb_split_8 -c /ocudu.yml
|
||||
|
||||
oai-nr-ue:
|
||||
image: ${REGISTRY-oaisoftwarealliance/}${NRUE_IMG:-oai-nr-ue}:${TAG:-develop}
|
||||
container_name: rfsim5g-oai-nr-ue
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- NET_ADMIN # for interface bringup
|
||||
- NET_RAW # for ping
|
||||
- SYS_NICE
|
||||
environment:
|
||||
USE_ADDITIONAL_OPTIONS: -r 106 --numerology 1 --band 78 -C 3489420000 --ssb 42 --ue-nb-ant-tx 2 --uicc0.imsi 208990100001100 --ue-nb-ant-rx 2 --uecap_file /opt/oai-nr-ue/etc/uecap.xml --log_config.global_log_options level,nocolor,time --device.name oai_zmqdevif --zmq.[0].tx_channels tcp://0.0.0.0:4556,tcp://0.0.0.0:4557 --zmq.[0].rx_channels tcp://192.168.71.140:4558,tcp://192.168.71.140:4559
|
||||
depends_on:
|
||||
- ocudu-gnb
|
||||
networks:
|
||||
public_net:
|
||||
ipv4_address: 192.168.71.150
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports2.xml:/opt/oai-nr-ue/etc/uecap.xml
|
||||
- ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf
|
||||
healthcheck:
|
||||
test: /bin/bash -c "pgrep nr-uesoftmodem"
|
||||
start_period: 10s
|
||||
start_interval: 500ms
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
networks:
|
||||
public_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-public-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.71.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-public"
|
||||
traffic_net:
|
||||
driver: bridge
|
||||
name: rfsim5g-oai-traffic-net
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.72.128/26
|
||||
driver_opts:
|
||||
com.docker.network.bridge.name: "rfsim5g-traffic"
|
||||
54
ci-scripts/yaml_files/5g_zmq_radio_2x2_ocudu/ocudu.yml
Normal file
54
ci-scripts/yaml_files/5g_zmq_radio_2x2_ocudu/ocudu.yml
Normal file
@@ -0,0 +1,54 @@
|
||||
# SPDX-FileCopyrightText: Copyright (C) 2021-2026 Software Radio Systems Limited
|
||||
# SPDX-License-Identifier: BSD-3-Clause-Open-MPI
|
||||
# Refer to https://gitlab.com/ocudu/ocudu/-/raw/dev/LICENSE?ref_type=heads
|
||||
|
||||
cu_cp:
|
||||
amf:
|
||||
addrs: 192.168.71.132
|
||||
port: 38412
|
||||
bind_addrs: 192.168.71.140
|
||||
supported_tracking_areas:
|
||||
- tac: 1
|
||||
plmn_list:
|
||||
- plmn: "20899"
|
||||
tai_slice_support_list:
|
||||
- sst: 1
|
||||
|
||||
ru_sdr:
|
||||
device_driver: zmq
|
||||
device_args: tx_port=tcp://0.0.0.0:4558,tx_port=tcp://0.0.0.0:4559,rx_port=tcp://192.168.71.150:4556,rx_port=tcp://192.168.71.150:4557
|
||||
srate: 61.44
|
||||
tx_gain: 25
|
||||
rx_gain: 25
|
||||
|
||||
cell_cfg:
|
||||
dl_arfcn: 632628
|
||||
band: 78
|
||||
channel_bandwidth_MHz: 40
|
||||
common_scs: 30
|
||||
plmn: "20899"
|
||||
tac: 1
|
||||
pci: 1
|
||||
nof_antennas_ul: 2
|
||||
nof_antennas_dl: 2
|
||||
tdd_ul_dl_cfg:
|
||||
dl_ul_tx_period: 5
|
||||
nof_dl_slots: 3
|
||||
nof_dl_symbols: 10
|
||||
nof_ul_slots: 1
|
||||
nof_ul_symbols: 2
|
||||
csi:
|
||||
csi_rs_enabled: false
|
||||
pucch:
|
||||
formats: f0_and_f2
|
||||
nof_cell_csi_res: 0
|
||||
|
||||
log:
|
||||
filename: gnb.log
|
||||
all_level: debug
|
||||
|
||||
pcap:
|
||||
mac_enable: false
|
||||
mac_filename: /tmp/gnb_mac.pcap
|
||||
ngap_enable: false
|
||||
ngap_filename: /tmp/gnb_ngap.pcap
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
set -e
|
||||
sudo cpupower idle-set -E > /dev/null
|
||||
sudo sysctl kernel.sched_rt_runtime_us=950000
|
||||
sudo sysctl kernel.timer_migration=1
|
||||
exit 0
|
||||
@@ -17,7 +17,7 @@ services:
|
||||
devices:
|
||||
- /dev/bus/usb/:/dev/bus/usb/
|
||||
volumes:
|
||||
- ../../conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma.conf:/opt/oai-gnb/etc/gnb.conf
|
||||
- ../../conf_files/gnb.sa.band78.106prb.usrpb200.sc-fdma-deltaMCS.conf:/opt/oai-gnb/etc/gnb.conf
|
||||
# for performance reasons, we use host mode: in bridge mode, we have
|
||||
# unacceptable DL TCP performance. However, the whole point of
|
||||
# containerization is to not be in host mode, so update this to macvlan
|
||||
|
||||
@@ -68,7 +68,7 @@ Options:
|
||||
--UE-conf-nvram [configuration file]
|
||||
Specify conf_nvram_path (default \"$conf_nvram_path\")
|
||||
-w | --hardware
|
||||
USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default)
|
||||
USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, ZMQ, None (Default)
|
||||
Adds this RF board support (in external packages installation and in compilation)
|
||||
-t | --transport
|
||||
Selects the transport protocol type, options: None, Ethernet, oran_fhlib_5g, oran_fhlib_5g_mplane, WLS
|
||||
@@ -223,7 +223,7 @@ function main() {
|
||||
shift 2;;
|
||||
-w | --hardware)
|
||||
case "$2" in
|
||||
"USRP" | "BLADERF" | "LMSSDR" | "IRIS")
|
||||
"USRP" | "BLADERF" | "LMSSDR" | "IRIS" | "ZMQ")
|
||||
HWs+=" OAI_"$2
|
||||
TARGET_LIST="$TARGET_LIST oai_${2,,}devif" # ,, makes lowercase
|
||||
CMAKE_CMD="$CMAKE_CMD -DOAI_$2=ON"
|
||||
|
||||
@@ -84,7 +84,7 @@ function(run_asn1c ASN1C_GRAMMAR ASN1C_PREFIX)
|
||||
set(LOGFILE "${CMAKE_CURRENT_BINARY_DIR}/${GRAMMAR_FILE}.log")
|
||||
add_custom_command(OUTPUT ${ASN1C_OUTPUT}
|
||||
COMMAND ASN1C_PREFIX=${ASN1C_PREFIX} ${ASN1C_EXEC} ${ASN1C_OPTIONS} -D ${CMAKE_CURRENT_BINARY_DIR} ${ASN1C_GRAMMAR} > ${LOGFILE} 2>&1 || ( cat ${LOGFILE} && false )
|
||||
DEPENDS ${ASN1C_GRAMMAR}
|
||||
DEPENDS ${ASN1C_GRAMMAR} asn1c
|
||||
COMMENT "Generating ${ASN1C_COMMENT} from ${GRAMMAR_FILE}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
# -------
|
||||
#
|
||||
# Finds the xran library. Note that the library number is as follows:
|
||||
# - oran_bronze_release_v1.1 -> 2.1.1 (B = second letter)
|
||||
# - oran_e_maintenance_release_v1.0 -> 5.1.0
|
||||
# the version is currently hardcoded to 5.1.0
|
||||
# - oran_e_maintenance_release_v1.5 -> 5.1.6
|
||||
# - oran_f_release_v1.3 -> 6.1.4
|
||||
# - oran_k_release_v1.1 -> 11.1.1
|
||||
#
|
||||
# Required options
|
||||
# ^^^^^^^^^^^^^^^^
|
||||
@@ -46,13 +46,7 @@
|
||||
# ``xran_LIBRARY``
|
||||
# The path to the xran library.
|
||||
|
||||
option(xran_LOCATION "directory of XRAN library" "")
|
||||
if (NOT xran_LOCATION)
|
||||
message(FATAL_ERROR "xran_LOCATION required")
|
||||
endif()
|
||||
if (NOT EXISTS ${xran_LOCATION})
|
||||
message(FATAL_ERROR "no such directory: ${xran_LOCATION}")
|
||||
endif()
|
||||
set(CACHE{xran_LOCATION} TYPE PATH HELP "directory of XRAN library" VALUE "")
|
||||
|
||||
find_path(xran_INCLUDE_DIR
|
||||
NAMES
|
||||
@@ -73,27 +67,26 @@ find_library(xran_LIBRARY
|
||||
PATH_SUFFIXES build api
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
if (NOT xran_LIBRARY)
|
||||
message(FATAL_ERROR "could not detect xran build artifacts at ${xran_LOCATION}/build")
|
||||
endif()
|
||||
|
||||
set(xran_VERSION_FILE "${xran_LOCATION}/../app/src/common.h")
|
||||
if(NOT EXISTS ${xran_VERSION_FILE})
|
||||
message(FATAL_ERROR "could not find xran version file at ${xran_VERSION_FILE}")
|
||||
if(EXISTS ${xran_VERSION_FILE})
|
||||
file(STRINGS ${xran_VERSION_FILE} xran_VERSION_LINE REGEX "^#define[ \t]+VERSIONX[ \t]+\"[a-z_.0-9]+\"$")
|
||||
else()
|
||||
set(xran_VERSION_LINE "UNKNOWN")
|
||||
endif()
|
||||
|
||||
file(STRINGS ${xran_VERSION_FILE} xran_VERSION_LINE REGEX "^#define[ \t]+VERSIONX[ \t]+\"[a-z_.0-9]+\"$")
|
||||
string(REGEX REPLACE "^#define[ \t]+VERSIONX[ \t]+\"([a-z_.0-9]+)\"$" "\\1" xran_VERSION_STRING "${xran_VERSION_LINE}")
|
||||
if (xran_VERSION_STRING MATCHES "^oran_e_maintenance_release_v")
|
||||
string(REGEX REPLACE "oran_e_maintenance_release_v([0-9]+).([0-9]+)" "5.\\1.\\2" xran_VERSION ${xran_VERSION_STRING})
|
||||
elseif(xran_VERSION_STRING MATCHES "^oran_f_release_v")
|
||||
string(REGEX REPLACE "oran_f_release_v([0-9]+).([0-9]+)" "6.\\1.\\2" xran_VERSION ${xran_VERSION_STRING})
|
||||
elseif(xran_VERSION_STRING MATCHES "^oran_k_release_v")
|
||||
string(REGEX REPLACE "oran_k_release_v([0-9]+).([0-9]+)" "11.\\1.\\2" xran_VERSION ${xran_VERSION_STRING})
|
||||
elseif(xran_VERSION_STRING MATCHES "^oran_bronze_release_v")
|
||||
string(REGEX REPLACE "oran_bronze_release_v([0-9]+).([0-9]+)" "2.\\1.\\2" xran_VERSION ${xran_VERSION_STRING})
|
||||
else()
|
||||
message(FATAL_ERROR "unrecognized xran version string: ${xran_VERSION_STRING}")
|
||||
set(xran_VERSION "UNKNOWN")
|
||||
endif()
|
||||
message(STATUS "Found xran release ${xran_VERSION_STRING} (v${xran_VERSION})")
|
||||
unset(xran_VERSION_LINE)
|
||||
unset(xran_VERSION_STRING)
|
||||
unset(xran_VERSION_FILE)
|
||||
|
||||
@@ -282,12 +282,9 @@ configmodule_interface_t *load_configmodule(int argc,
|
||||
cfgmode = strdup(CONFIG_LIBCONFIGFILE);
|
||||
}
|
||||
}
|
||||
static configmodule_interface_t *cfgptr = NULL;
|
||||
if (cfgptr)
|
||||
fprintf(stderr, "ERROR: Call load_configmodule more than one time\n");
|
||||
|
||||
// The macros are not thread safe print_params and similar
|
||||
cfgptr = calloc(sizeof(configmodule_interface_t), 1);
|
||||
configmodule_interface_t *cfgptr = calloc(sizeof(configmodule_interface_t), 1);
|
||||
if (!cfgptr) {
|
||||
fprintf(stderr, "ERROR: cannot allocate a memory for configuration\n");
|
||||
return NULL;
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
#ifndef INCLUDE_CONFIG_LOADCONFIGMODULE_H
|
||||
#define INCLUDE_CONFIG_LOADCONFIGMODULE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -117,5 +120,8 @@ void write_parsedcfg(configmodule_interface_t *cfg);
|
||||
extern void free_configmodule(void);
|
||||
#define CONFIG_PRINTF_ERROR(f, x... ) if (isLogInitDone ()) { LOG_E(ENB_APP,f,x);} else {printf(f,x);}; if ( !CONFIG_ISFLAGSET(CONFIG_NOABORTONCHKF) ) exit_fun("exit because configuration failed\n");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* INCLUDE_CONFIG_LOADCONFIGMODULE_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;
|
||||
@@ -181,6 +181,11 @@ typedef struct paramdef {
|
||||
{ \
|
||||
OPTNAME(name), HELPSTR(help), PARAMFLAG(flags), .u64ptr = ptr, .defuintval = defval, PARAMTYPE(TYPE_UINT64), .numelt = 0 \
|
||||
}
|
||||
#define STRINGLISTPARAM(name, help, flags, ptr, defval) \
|
||||
{ \
|
||||
OPTNAME(name), HELPSTR(help), PARAMFLAG(flags), .strptr = ptr, .defstrlistval = defval, PARAMTYPE(TYPE_STRINGLIST), \
|
||||
.numelt = 0 \
|
||||
}
|
||||
|
||||
typedef struct paramlist_def {
|
||||
char listname[MAX_OPTNAME_SIZE];
|
||||
|
||||
@@ -183,14 +183,35 @@ int config_check_intval(configmodule_interface_t *cfg, paramdef_t *param)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for ( int i=0; i<param->chkPptr->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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 bits.c fsn.c)
|
||||
target_include_directories(utils PUBLIC .)
|
||||
target_link_libraries(utils PRIVATE ${T_LIB})
|
||||
add_subdirectory(barrier)
|
||||
|
||||
@@ -55,7 +55,7 @@ add_dependencies(T_headers T_IDs.h generate_T)
|
||||
target_include_directories(T_headers INTERFACE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
if(T_TRACER)
|
||||
add_library(T STATIC T.c local_tracer.c T_IDs.h T_messages.txt.h)
|
||||
add_library(T STATIC T.c local_tracer.c T_messages_creator.c T_IDs.h T_messages.txt.h)
|
||||
target_link_libraries(T PUBLIC rt)
|
||||
target_link_libraries(T PRIVATE CONFIG_LIB T_headers)
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -115,7 +115,7 @@ extern int T_stdout;
|
||||
|
||||
/* type used to send arbitrary buffer data */
|
||||
typedef struct {
|
||||
void *addr;
|
||||
const void *addr;
|
||||
int length;
|
||||
} T_buffer;
|
||||
|
||||
|
||||
@@ -118,23 +118,23 @@ ID = GNB_PHY_PUCCH_PUSCH_IQ
|
||||
ID = GNB_PHY_UL_FD_PUSCH_IQ
|
||||
DESC = gNodeB UL PUSCH IQ Data in the frequency domain
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
FORMAT = int,frame : int,slot : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
ID = GNB_PHY_UL_FD_DMRS
|
||||
DESC = gNodeB UL DMRS Signal in the frequency domain
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
FORMAT = int,frame : int,slot : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
ID = GNB_PHY_UL_FD_CHAN_EST_DMRS_POS
|
||||
DESC = gNodeB channel estimation in the frequency domain based on DMRS and at DMRS pilots location without any further interploation.
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
FORMAT = int,frame : int,slot : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
ID = GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL
|
||||
DESC = gNodeB channel estimation in the frequency domain based on DMRS and interploation.
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,dataI
|
||||
FORMAT = int,frame : int,slot : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,dataI
|
||||
ID = GNB_PHY_UL_PAYLOAD_RX_BITS
|
||||
DESC = gNodeB slot payload after decoder
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
FORMAT = int,frame : int,slot : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
ID = GNB_PHY_UL_FREQ_CHANNEL_ESTIMATE
|
||||
DESC = gNodeB channel estimation in the frequency domain
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:GNB
|
||||
@@ -1474,11 +1474,11 @@ ID = UE_PHY_MEAS
|
||||
ID = UE_PHY_UL_PAYLOAD_TX_BITS
|
||||
DESC = UE UL Tx bits in one slot before decoder and scrambler
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:UE
|
||||
FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_tx : int,number_of_bits : buffer,data
|
||||
FORMAT = int,frame : int,slot : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_tx : int,number_of_bits : buffer,data
|
||||
ID = UE_PHY_UL_SCRAMBLED_TX_BITS
|
||||
DESC = UE UL Tx bits in one slot after scrambler
|
||||
GROUP = ALL:PHY:GRAPHIC:HEAVY:UE
|
||||
FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_tx : int,number_of_bits : buffer,data
|
||||
FORMAT = int,frame : int,slot : int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot : int,Nid_cell : int,rnti : int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols : int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers : int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port : int,dmrs_nscid : int,nb_antennas_tx : int,number_of_bits : buffer,data
|
||||
|
||||
#for debug/test - not used
|
||||
ID = first
|
||||
|
||||
220
common/utils/T/T_messages_creator.c
Normal file
220
common/utils/T/T_messages_creator.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Helper functions for creating T-Tracer UL PHY trace messages, it is used by data recording application
|
||||
*/
|
||||
|
||||
/*
|
||||
* Each function logs one UL PHY trace message via the T() macro.
|
||||
* All messages share the same field format (Data Collection Trace Messages Structure):
|
||||
* int,frame : int,slot :
|
||||
* int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
* int,Nid_cell : int,rnti :
|
||||
* int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
* int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
* int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port :
|
||||
* int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
*/
|
||||
|
||||
#include "T.h"
|
||||
#include "T_messages_creator.h"
|
||||
|
||||
#if T_TRACER
|
||||
|
||||
// Internal helper: emit the common UL metadata + buffer via T()
|
||||
// Note: The T() macro internally checks T_ACTIVE(trace_id) before sending,
|
||||
// so callers do not need an additional T_ACTIVE() guard.
|
||||
static inline void log_ul_common(int trace_id,
|
||||
int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
int number_of_bits,
|
||||
const void *data,
|
||||
int data_len)
|
||||
{
|
||||
T(trace_id,
|
||||
T_INT((int)frame),
|
||||
T_INT((int)slot),
|
||||
T_INT((int)frame_parms->frame_type),
|
||||
T_INT((int)frame_parms->freq_range),
|
||||
T_INT((int)rel15_ul->subcarrier_spacing),
|
||||
T_INT((int)rel15_ul->cyclic_prefix),
|
||||
T_INT((int)frame_parms->symbols_per_slot),
|
||||
T_INT((int)frame_parms->Nid_cell),
|
||||
T_INT((int)rel15_ul->rnti),
|
||||
T_INT((int)rel15_ul->rb_size),
|
||||
T_INT((int)rel15_ul->rb_start),
|
||||
T_INT((int)rel15_ul->start_symbol_index),
|
||||
T_INT((int)rel15_ul->nr_of_symbols),
|
||||
T_INT((int)rel15_ul->qam_mod_order),
|
||||
T_INT((int)rel15_ul->mcs_index),
|
||||
T_INT((int)rel15_ul->mcs_table),
|
||||
T_INT((int)rel15_ul->nrOfLayers),
|
||||
T_INT((int)rel15_ul->transform_precoding),
|
||||
T_INT((int)rel15_ul->dmrs_config_type),
|
||||
T_INT((int)rel15_ul->ul_dmrs_symb_pos),
|
||||
T_INT((int)number_dmrs_symbols),
|
||||
T_INT((int)dmrs_port),
|
||||
T_INT((int)rel15_ul->scid),
|
||||
T_INT((int)frame_parms->nb_antennas_rx),
|
||||
T_INT((int)number_of_bits),
|
||||
T_BUFFER(data, data_len));
|
||||
}
|
||||
|
||||
void log_ul_fd_dmrs(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const c16_t *data,
|
||||
int data_len)
|
||||
{
|
||||
log_ul_common(T_GNB_PHY_UL_FD_DMRS,
|
||||
frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port, 0, data, data_len);
|
||||
}
|
||||
|
||||
void log_ul_fd_chan_est_dmrs_pos(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const c16_t *data,
|
||||
int data_len)
|
||||
{
|
||||
log_ul_common(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS,
|
||||
frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port, 0, data, data_len);
|
||||
}
|
||||
|
||||
void log_ul_fd_pusch_iq(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const c16_t *data,
|
||||
int data_len)
|
||||
{
|
||||
log_ul_common(T_GNB_PHY_UL_FD_PUSCH_IQ,
|
||||
frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port, 0, data, data_len);
|
||||
}
|
||||
|
||||
void log_ul_fd_chan_est_dmrs_interpl(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const c16_t *data,
|
||||
int data_len)
|
||||
{
|
||||
log_ul_common(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL,
|
||||
frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port, 0, data, data_len);
|
||||
}
|
||||
|
||||
void log_ul_payload_rx_bits(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const uint8_t *data,
|
||||
int tb_size)
|
||||
{
|
||||
log_ul_common(T_GNB_PHY_UL_PAYLOAD_RX_BITS,
|
||||
frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
tb_size << 3, data, tb_size);
|
||||
}
|
||||
|
||||
// UE-side: uses nfapi_nr_ue_pusch_pdu_t, derives subcarrier_spacing index
|
||||
// from frame_parms, and logs nb_antennas_tx instead of nb_antennas_rx.
|
||||
void log_ul_payload_tx_bits(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const uint8_t *data,
|
||||
int tb_size)
|
||||
{
|
||||
int subcarrier_spacing_index = frame_parms->subcarrier_spacing / 15000 - 1;
|
||||
T(T_UE_PHY_UL_PAYLOAD_TX_BITS,
|
||||
T_INT((int)frame),
|
||||
T_INT((int)slot),
|
||||
T_INT((int)frame_parms->frame_type),
|
||||
T_INT((int)frame_parms->freq_range),
|
||||
T_INT((int)subcarrier_spacing_index),
|
||||
T_INT((int)pusch_pdu->cyclic_prefix),
|
||||
T_INT((int)frame_parms->symbols_per_slot),
|
||||
T_INT((int)frame_parms->Nid_cell),
|
||||
T_INT((int)pusch_pdu->rnti),
|
||||
T_INT((int)pusch_pdu->rb_size),
|
||||
T_INT((int)pusch_pdu->rb_start),
|
||||
T_INT((int)pusch_pdu->start_symbol_index),
|
||||
T_INT((int)pusch_pdu->nr_of_symbols),
|
||||
T_INT((int)pusch_pdu->qam_mod_order),
|
||||
T_INT((int)pusch_pdu->mcs_index),
|
||||
T_INT((int)pusch_pdu->mcs_table),
|
||||
T_INT((int)pusch_pdu->nrOfLayers),
|
||||
T_INT((int)pusch_pdu->transform_precoding),
|
||||
T_INT((int)pusch_pdu->dmrs_config_type),
|
||||
T_INT((int)pusch_pdu->ul_dmrs_symb_pos),
|
||||
T_INT((int)number_dmrs_symbols),
|
||||
T_INT((int)dmrs_port),
|
||||
T_INT((int)pusch_pdu->scid),
|
||||
T_INT((int)frame_parms->nb_antennas_tx),
|
||||
T_INT((int)(tb_size << 3)),
|
||||
T_BUFFER(data, tb_size));
|
||||
}
|
||||
|
||||
void log_ul_scrambled_tx_bits(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const uint8_t *data,
|
||||
int number_of_bits)
|
||||
{
|
||||
int subcarrier_spacing_index = frame_parms->subcarrier_spacing / 15000 - 1;
|
||||
T(T_UE_PHY_UL_SCRAMBLED_TX_BITS,
|
||||
T_INT((int)frame),
|
||||
T_INT((int)slot),
|
||||
T_INT((int)frame_parms->frame_type),
|
||||
T_INT((int)frame_parms->freq_range),
|
||||
T_INT((int)subcarrier_spacing_index),
|
||||
T_INT((int)pusch_pdu->cyclic_prefix),
|
||||
T_INT((int)frame_parms->symbols_per_slot),
|
||||
T_INT((int)frame_parms->Nid_cell),
|
||||
T_INT((int)pusch_pdu->rnti),
|
||||
T_INT((int)pusch_pdu->rb_size),
|
||||
T_INT((int)pusch_pdu->rb_start),
|
||||
T_INT((int)pusch_pdu->start_symbol_index),
|
||||
T_INT((int)pusch_pdu->nr_of_symbols),
|
||||
T_INT((int)pusch_pdu->qam_mod_order),
|
||||
T_INT((int)pusch_pdu->mcs_index),
|
||||
T_INT((int)pusch_pdu->mcs_table),
|
||||
T_INT((int)pusch_pdu->nrOfLayers),
|
||||
T_INT((int)pusch_pdu->transform_precoding),
|
||||
T_INT((int)pusch_pdu->dmrs_config_type),
|
||||
T_INT((int)pusch_pdu->ul_dmrs_symb_pos),
|
||||
T_INT((int)number_dmrs_symbols),
|
||||
T_INT((int)dmrs_port),
|
||||
T_INT((int)pusch_pdu->scid),
|
||||
T_INT((int)frame_parms->nb_antennas_tx),
|
||||
T_INT((int)number_of_bits),
|
||||
T_BUFFER(data, number_of_bits / 8));
|
||||
}
|
||||
|
||||
#endif /* T_TRACER */
|
||||
195
common/utils/T/T_messages_creator.h
Normal file
195
common/utils/T/T_messages_creator.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Helper functions for creating T-Tracer UL PHY trace messages, it is used by data recording application
|
||||
*/
|
||||
|
||||
#ifndef T_MESSAGES_CREATOR_H
|
||||
#define T_MESSAGES_CREATOR_H
|
||||
|
||||
#if T_TRACER
|
||||
|
||||
#include <stdint.h>
|
||||
#include "common/platform_types.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "PHY/defs_nr_common.h"
|
||||
#include "nfapi_nr_interface_scf.h"
|
||||
#include "fapi_nr_ue_interface.h"
|
||||
|
||||
/**
|
||||
* @brief Log PUSCH UL DMRS using T-Tracer
|
||||
*
|
||||
* This function creates and sends a T_GNB_PHY_UL_FD_DMRS message containing
|
||||
* PUSCH DMRS symbols in frequency domain.
|
||||
*
|
||||
* @param frame Frame number
|
||||
* @param slot Slot number
|
||||
* @param frame_parms Pointer to frame parameters structure
|
||||
* @param rel15_ul Pointer to PUSCH PDU structure
|
||||
* @param number_dmrs_symbols Number of DMRS symbols
|
||||
* @param dmrs_port DMRS port number
|
||||
* @param data Pointer to DMRS data buffer (c16_t complex samples)
|
||||
* @param data_len Size of the data buffer in bytes
|
||||
*/
|
||||
void log_ul_fd_dmrs(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const c16_t *data,
|
||||
int data_len);
|
||||
|
||||
/**
|
||||
* @brief Log PUSCH UL channel estimates at DMRS positions using T-Tracer
|
||||
*
|
||||
* This function creates and sends a T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS message
|
||||
* containing channel estimates at DMRS positions in frequency domain.
|
||||
*
|
||||
* @param frame Frame number
|
||||
* @param slot Slot number
|
||||
* @param frame_parms Pointer to frame parameters structure
|
||||
* @param rel15_ul Pointer to PUSCH PDU structure
|
||||
* @param number_dmrs_symbols Number of DMRS symbols
|
||||
* @param dmrs_port DMRS port number
|
||||
* @param data Pointer to channel estimate data buffer (c16_t complex samples)
|
||||
* @param data_len Size of the data buffer in bytes
|
||||
*/
|
||||
void log_ul_fd_chan_est_dmrs_pos(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const c16_t *data,
|
||||
int data_len);
|
||||
|
||||
/**
|
||||
* @brief Log PUSCH UL IQ data using T-Tracer
|
||||
*
|
||||
* This function creates and sends a T_GNB_PHY_UL_FD_PUSCH_IQ message
|
||||
* containing PUSCH IQ samples in frequency domain.
|
||||
*
|
||||
* @param frame Frame number
|
||||
* @param slot Slot number
|
||||
* @param frame_parms Pointer to frame parameters structure
|
||||
* @param rel15_ul Pointer to PUSCH PDU structure
|
||||
* @param number_dmrs_symbols Number of DMRS symbols
|
||||
* @param dmrs_port DMRS port number
|
||||
* @param data Pointer to PUSCH IQ data buffer (c16_t complex samples)
|
||||
* @param data_len Size of the data buffer in bytes
|
||||
*/
|
||||
void log_ul_fd_pusch_iq(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const c16_t *data,
|
||||
int data_len);
|
||||
|
||||
/**
|
||||
* @brief Log PUSCH UL interpolated channel estimates using T-Tracer
|
||||
*
|
||||
* This function creates and sends a T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL message
|
||||
* containing interpolated channel estimates across all subcarriers in frequency domain.
|
||||
*
|
||||
* @param frame Frame number
|
||||
* @param slot Slot number
|
||||
* @param frame_parms Pointer to frame parameters structure
|
||||
* @param rel15_ul Pointer to PUSCH PDU structure
|
||||
* @param number_dmrs_symbols Number of DMRS symbols
|
||||
* @param dmrs_port DMRS port number
|
||||
* @param data Pointer to interpolated channel estimate data buffer (c16_t complex samples)
|
||||
* @param data_len Size of the data buffer in bytes
|
||||
*/
|
||||
void log_ul_fd_chan_est_dmrs_interpl(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const c16_t *data,
|
||||
int data_len);
|
||||
|
||||
/**
|
||||
* @brief Log PUSCH UL received payload bits using T-Tracer
|
||||
*
|
||||
* This function creates and sends a T_GNB_PHY_UL_PAYLOAD_RX_BITS message
|
||||
* containing the decoded transport block payload data.
|
||||
*
|
||||
* @param frame Frame number
|
||||
* @param slot Slot number
|
||||
* @param frame_parms Pointer to frame parameters structure
|
||||
* @param rel15_ul Pointer to PUSCH PDU structure
|
||||
* @param number_dmrs_symbols Number of DMRS symbols
|
||||
* @param dmrs_port DMRS port number
|
||||
* @param data Pointer to decoded transport block data (uint8_t bytes)
|
||||
* @param tb_size Transport block size in bytes
|
||||
*/
|
||||
void log_ul_payload_rx_bits(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_pusch_pdu_t *rel15_ul,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const uint8_t *data,
|
||||
int tb_size);
|
||||
|
||||
/**
|
||||
* @brief Log UE PUSCH UL transmitted payload bits using T-Tracer
|
||||
*
|
||||
* This function creates and sends a T_UE_PHY_UL_PAYLOAD_TX_BITS message
|
||||
* containing the transport block payload data before encoding.
|
||||
* Note: subcarrier_spacing is derived from frame_parms->subcarrier_spacing
|
||||
* and nb_antennas_tx is used (UE transmit side).
|
||||
*
|
||||
* @param frame Frame number
|
||||
* @param slot Slot number
|
||||
* @param frame_parms Pointer to frame parameters structure
|
||||
* @param pusch_pdu Pointer to UE PUSCH PDU structure
|
||||
* @param number_dmrs_symbols Number of DMRS symbols
|
||||
* @param dmrs_port DMRS port number
|
||||
* @param data Pointer to transport block payload data (uint8_t bytes)
|
||||
* @param tb_size Transport block size in bytes
|
||||
*/
|
||||
void log_ul_payload_tx_bits(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const uint8_t *data,
|
||||
int tb_size);
|
||||
|
||||
/**
|
||||
* @brief Log UE PUSCH UL scrambled transmit bits using T-Tracer
|
||||
*
|
||||
* This function creates and sends a T_UE_PHY_UL_SCRAMBLED_TX_BITS message
|
||||
* containing the scrambled codeword bits after scrambling.
|
||||
* Note: subcarrier_spacing is derived from frame_parms->subcarrier_spacing
|
||||
* and nb_antennas_tx is used (UE transmit side).
|
||||
*
|
||||
* @param frame Frame number
|
||||
* @param slot Slot number
|
||||
* @param frame_parms Pointer to frame parameters structure
|
||||
* @param pusch_pdu Pointer to UE PUSCH PDU structure
|
||||
* @param number_dmrs_symbols Number of DMRS symbols
|
||||
* @param dmrs_port DMRS port number
|
||||
* @param data Pointer to scrambled codeword data (uint8_t bytes)
|
||||
* @param number_of_bits Number of scrambled bits
|
||||
*/
|
||||
void log_ul_scrambled_tx_bits(int frame,
|
||||
int slot,
|
||||
const NR_DL_FRAME_PARMS *frame_parms,
|
||||
const nfapi_nr_ue_pusch_pdu_t *pusch_pdu,
|
||||
int number_dmrs_symbols,
|
||||
int dmrs_port,
|
||||
const uint8_t *data,
|
||||
int number_of_bits);
|
||||
|
||||
#endif /* T_TRACER */
|
||||
|
||||
#endif /* T_MESSAGES_CREATOR_H */
|
||||
@@ -18,10 +18,13 @@
|
||||
#ifndef _SHARED_MEMORY_CONFIG_H_
|
||||
#define _SHARED_MEMORY_CONFIG_H_
|
||||
|
||||
#define SHMSIZE ((122.88e6 / (100 * 20)) * 1000 * 8) // Assume capture in 1000, each I+Q represented by 8 byts
|
||||
// 122.88e6: 10ms at 100 MHz BW of 5G NR
|
||||
// 20: 20 slots in 10ms
|
||||
// subcarrier spacing: 30 KHz
|
||||
#define NUM_MESSAGES_PER_SLOT 5
|
||||
#define SHMSIZE ((122.88e6 / (100 * 20)) * 100 * NUM_MESSAGES_PER_SLOT * 8) // ~229 MiB
|
||||
// 122.88e6: sample rate at 100 MHz BW of 5G NR
|
||||
// 100 * 20: 2000 slots/s (20 slots/frame, 100 frames/s) at SCS 30 kHz
|
||||
// 100: number of slots to capture
|
||||
// NUM_MESSAGES_PER_SLOT: messages captured per slot
|
||||
// 8: bytes per complex I+Q sample
|
||||
|
||||
// for gNB T Tracer App
|
||||
#define GETKEYDIR1_gNB ("/tmp/gnb_app1")
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief T-Tracer gnb service to capture tracee Messages from gNB, it is used by data recording application
|
||||
* \brief T-Tracer gnb service to capture trace Messages from gNB, it is used by data recording application
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -34,6 +34,21 @@
|
||||
// the buffer in the stack from the previous record
|
||||
#define DISCARD_RECORD_DURATION_MS 10
|
||||
|
||||
// Sentinel values for field_descriptor: source is e.sending_time
|
||||
#define FIELD_SENDING_TIME_SEC -2
|
||||
#define FIELD_SENDING_TIME_NSEC -3
|
||||
|
||||
// State machine constants for shared memory protocol
|
||||
#define STATE_WAIT 0
|
||||
#define STATE_CONFIG 1
|
||||
#define STATE_RECORD 2
|
||||
#define STATE_STOP 3
|
||||
|
||||
// Visual separator for state machine transitions in console output
|
||||
#define STATE_SEPARATOR "========================================"
|
||||
#define PRINT_STATE_BANNER(state_name) \
|
||||
printf("\n%s\n [STATE: %s]\n%s\n", STATE_SEPARATOR, state_name, STATE_SEPARATOR)
|
||||
|
||||
// Combine bytes in - little-endian format
|
||||
int combine_bytes(const uint8_t *bytes, size_t num_bytes)
|
||||
{
|
||||
@@ -44,19 +59,11 @@ int combine_bytes(const uint8_t *bytes, size_t num_bytes)
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert an integer to an array of bytes - little-endian format
|
||||
void int_to_bytes(int num, uint8_t *bytes, size_t num_bytes)
|
||||
// Check if a message ID is present in a given list of message IDs
|
||||
bool is_message_in_list(int msg_id_list[], int n_msgs, int msg_id)
|
||||
{
|
||||
for (size_t i = 0; i < num_bytes; ++i) {
|
||||
bytes[i] = (num >> (i * 8)) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the message is in the list of bits messages
|
||||
bool is_bits_messages(int traces_bits_support_data_Collection_format_idx[], int n_bits_msgs, int msg_id)
|
||||
{
|
||||
for (int i = 0; i < n_bits_msgs; i++) {
|
||||
if (msg_id == traces_bits_support_data_Collection_format_idx[i]) {
|
||||
for (int i = 0; i < n_msgs; i++) {
|
||||
if (msg_id == msg_id_list[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -71,12 +78,6 @@ struct timespec get_current_time()
|
||||
return time;
|
||||
}
|
||||
|
||||
// Function to convert timespec to microseconds
|
||||
long long timespec_to_microseconds(struct timespec time)
|
||||
{
|
||||
return (time.tv_sec * 1000000LL) + (time.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
// Calculate the time difference in milliseconds
|
||||
double calculate_time_difference(struct timespec start, struct timespec end)
|
||||
{
|
||||
@@ -88,7 +89,7 @@ double calculate_time_difference(struct timespec start, struct timespec end)
|
||||
// Get Time Stamp in microseconds in YYYYMMDDHHMMSSmmmuuu format
|
||||
char *get_time_stamp_usec(char time_stamp_str[])
|
||||
{
|
||||
// initialization to measure time stamp --This part should be moved to inilization part
|
||||
// initialization to measure time stamp
|
||||
time_t my_time;
|
||||
struct tm *timeinfo;
|
||||
time(&my_time);
|
||||
@@ -104,31 +105,12 @@ char *get_time_stamp_usec(char time_stamp_str[])
|
||||
uint8_t hour = timeinfo->tm_hour;
|
||||
uint8_t min = timeinfo->tm_min;
|
||||
uint8_t sec = timeinfo->tm_sec;
|
||||
uint16_t usec = (tv.tv_usec);
|
||||
// printf ("Time stamp: %d_%d_%d_%d_%d_%d_%d \n",year,mon,mday,hour,min,sec,usec);
|
||||
// sprintf(time_stamp_str, "%d_%d_%d_%d_%d_%d_%d",year,mon,mday,hour,min,sec,usec);
|
||||
sprintf(time_stamp_str, "%04d%02d%02d%02d%02d%02d%06d", year, mon, mday, hour, min, sec, usec);
|
||||
uint32_t usec = (tv.tv_usec);
|
||||
sprintf(time_stamp_str, "%04d%02d%02d%02d%02d%02d%06u", year, mon, mday, hour, min, sec, usec);
|
||||
|
||||
return time_stamp_str;
|
||||
}
|
||||
|
||||
// Convert timestamp string to integer
|
||||
int convert_time_stamp_to_int(const char *timestamp)
|
||||
{
|
||||
return atoi(timestamp);
|
||||
}
|
||||
|
||||
// Split timestamp string and convert to integer
|
||||
int split_time_stamp_and_convert_to_int(char time_stamp_str[], int shift, int length)
|
||||
{
|
||||
char time_part[length + 1]; // Buffer to hold the date part YYYYMMDD or HHMMSSmmm
|
||||
// Copy the first 8 or 9 characters (YYYYMMDD) to HHMMSSmmm
|
||||
strncpy(time_part, time_stamp_str + shift, length);
|
||||
time_part[length] = '\0'; // Null-terminate the string
|
||||
// Convert timestamp string to integer
|
||||
return convert_time_stamp_to_int(time_part);
|
||||
}
|
||||
|
||||
void err_exit(char *buf)
|
||||
{
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
@@ -153,7 +135,7 @@ int create_shm(char **addrN, const char *shm_path, int projectId)
|
||||
shm_id = shmget(key, SHMSIZE, IPC_CREAT | IPC_EXCL | 0664);
|
||||
if (shm_id == -1) {
|
||||
if (errno == EEXIST) {
|
||||
printf("Error: shared memeory already exist\n");
|
||||
printf("Error: shared memory already exists\n");
|
||||
shm_id = shmget(key, 0, 0);
|
||||
printf("reference shm_id = %d\n", shm_id);
|
||||
} else {
|
||||
@@ -210,75 +192,28 @@ void usage(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// class to store the message and the action to enable capture selected data
|
||||
// 0: do not record message
|
||||
// 1: record message
|
||||
struct trace_struct {
|
||||
char on_off_name[100];
|
||||
int on_off_action;
|
||||
};
|
||||
|
||||
// struct for trace message based on Data Collection Trace Messages Structure
|
||||
// you need to define the vararibles of each message
|
||||
// you need to define the variables of each message
|
||||
typedef struct {
|
||||
/* Data Collection Trace Message Structure */
|
||||
int frame;
|
||||
int slot;
|
||||
int datetime_yyyymmdd;
|
||||
int datetime_hhmmssmmm;
|
||||
int frame_type, freq_range, subcarrier_spacing, cyclic_prefix, symbols_per_slot;
|
||||
int Nid_cell, rnti;
|
||||
int rb_size, rb_start, start_symbol_index, nr_of_symbols;
|
||||
int qam_mod_order, mcs_index, mcs_table, nrOfLayers, transform_precoding;
|
||||
int dmrs_config_type, ul_dmrs_symb_pos, number_dmrs_symbols;
|
||||
int dmrs_port, dmrs_nscid, nb_antennas_rx, number_of_bits;
|
||||
int data_size, data;
|
||||
} event_trace_msg_data;
|
||||
int data;
|
||||
} event_trace_msg_ul_data;
|
||||
|
||||
void setup_trace_msg_data(event_trace_msg_data *d, void *database)
|
||||
void setup_trace_msg_ul_data(event_trace_msg_ul_data *d, void *database)
|
||||
{
|
||||
database_event_format f;
|
||||
int i;
|
||||
|
||||
/* Data Collection Trace Message Structure */
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols :
|
||||
// int,dmrs_port : int,dmrs_nscid :
|
||||
// int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
|
||||
// Initialize the data structure
|
||||
d->frame = -1;
|
||||
d->slot = -1;
|
||||
d->datetime_yyyymmdd = -1;
|
||||
d->datetime_hhmmssmmm = -1;
|
||||
d->frame_type = -1;
|
||||
d->freq_range = -1;
|
||||
d->subcarrier_spacing = -1;
|
||||
d->cyclic_prefix = -1;
|
||||
d->symbols_per_slot = -1;
|
||||
d->Nid_cell = -1;
|
||||
d->rnti = -1;
|
||||
d->rb_size = -1;
|
||||
d->rb_start = -1;
|
||||
d->start_symbol_index = -1;
|
||||
d->nr_of_symbols = -1;
|
||||
d->qam_mod_order = -1;
|
||||
d->mcs_index = -1;
|
||||
d->mcs_table = -1;
|
||||
d->nrOfLayers = -1;
|
||||
d->transform_precoding = -1;
|
||||
d->dmrs_config_type = -1;
|
||||
d->ul_dmrs_symb_pos = -1;
|
||||
d->number_dmrs_symbols = -1;
|
||||
d->dmrs_port = -1;
|
||||
d->dmrs_nscid = -1;
|
||||
d->nb_antennas_rx = -1;
|
||||
d->number_of_bits = -1;
|
||||
d->data = -1;
|
||||
// Initialize all fields to -1 (marks unset indices)
|
||||
memset(d, -1, sizeof(*d));
|
||||
|
||||
/* this macro looks for a particular element and checks its type */
|
||||
#define G(var_name, var_type, var) \
|
||||
@@ -291,35 +226,14 @@ void setup_trace_msg_data(event_trace_msg_data *d, void *database)
|
||||
continue; \
|
||||
}
|
||||
|
||||
/* ------------------------------*/
|
||||
/* Create Macro for Data Collection Trace Message */
|
||||
/* ------------------------------*/
|
||||
// Data Collection Trace Message Structure
|
||||
// Example: GNB_PHY_UL_FD_PUSCH_IQ, GNB_PHY_UL_FD_DMRS_ID,
|
||||
// GNB_PHY_UL_FD_CHAN_EST_DMRS_POS, GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL
|
||||
// GNB_PHY_UL_PAYLOAD_RX_BITS
|
||||
// UE_PHY_UL_SCRAMBLED_TX_BITS
|
||||
// UE_PHY_UL_PAYLOAD_TX_BITS
|
||||
// Get a template of any message based on Data Collection Trace Messages Structure
|
||||
// Get a template of any UL message based on Data Collection Trace Messages Structure
|
||||
int Trace_MSG_ID = event_id_from_name(database, "GNB_PHY_UL_FD_PUSCH_IQ");
|
||||
f = get_format(database, Trace_MSG_ID);
|
||||
|
||||
/* get the elements of the trace
|
||||
* the value is an index in the event, see below */
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols :
|
||||
// int,dmrs_port : int,dmrs_nscid :
|
||||
// int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
|
||||
// Map each field name to its index in the event structure
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("frame", "int", d->frame)
|
||||
G("slot", "int", d->slot)
|
||||
G("datetime_yyyymmdd", "int", d->datetime_yyyymmdd)
|
||||
G("datetime_hhmmssmmm", "int", d->datetime_hhmmssmmm)
|
||||
G("frame_type", "int", d->frame_type)
|
||||
G("freq_range", "int", d->freq_range)
|
||||
G("subcarrier_spacing", "int", d->subcarrier_spacing)
|
||||
@@ -345,20 +259,106 @@ void setup_trace_msg_data(event_trace_msg_data *d, void *database)
|
||||
G("number_of_bits", "int", d->number_of_bits)
|
||||
G("data", "buffer", d->data)
|
||||
}
|
||||
// if (d->frame == -1 || d->slot == -1) goto error;
|
||||
#undef G
|
||||
return;
|
||||
}
|
||||
|
||||
// Function to check if a value is in the array
|
||||
int isValueInArray(int value, int arr[], int size)
|
||||
// -------------------------------------------------------------------
|
||||
// Table-driven metadata shared memory writer and debug printer
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Descriptor for one metadata field to write to shared memory
|
||||
typedef struct {
|
||||
int field_idx; // index into event e.e[] array
|
||||
size_t wire_size; // number of bytes to write to shm
|
||||
} field_descriptor;
|
||||
|
||||
// Number of UL metadata fields written to shared memory (excludes msg_id and buffer)
|
||||
#define N_UL_METADATA_FIELDS 27
|
||||
|
||||
// Build UL field descriptor array from a populated event_trace_msg_ul_data struct.
|
||||
// Must be called after setup_trace_msg_ul_data() so that field indices are populated.
|
||||
void build_ul_field_descriptors(field_descriptor *fields, const event_trace_msg_ul_data *d)
|
||||
{
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (arr[i] == value) {
|
||||
return 1; // Value found
|
||||
int i = 0;
|
||||
fields[i++] = (field_descriptor){ d->frame, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->slot, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ FIELD_SENDING_TIME_SEC, sizeof(uint32_t) };
|
||||
fields[i++] = (field_descriptor){ FIELD_SENDING_TIME_NSEC, sizeof(uint32_t) };
|
||||
fields[i++] = (field_descriptor){ d->frame_type, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->freq_range, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->subcarrier_spacing, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->cyclic_prefix, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->symbols_per_slot, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->Nid_cell, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->rnti, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->rb_size, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->rb_start, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->start_symbol_index, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->nr_of_symbols, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->qam_mod_order, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->mcs_index, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->mcs_table, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->nrOfLayers, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->transform_precoding, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->dmrs_config_type, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->ul_dmrs_symb_pos, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->number_dmrs_symbols, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->dmrs_port, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->dmrs_nscid, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->nb_antennas_rx, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->number_of_bits, sizeof(uint32_t) };
|
||||
}
|
||||
|
||||
// Print UL metadata fields for debug output
|
||||
void print_ul_metadata_debug(event e, const event_trace_msg_ul_data *d, void *database)
|
||||
{
|
||||
printf("\nUnix TS: %ld.%09ld", e.sending_time.tv_sec, e.sending_time.tv_nsec);
|
||||
printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type);
|
||||
printf("frame %d, slot %d, unix_ts %ld.%09ld\n",
|
||||
e.e[d->frame].i, e.e[d->slot].i,
|
||||
e.sending_time.tv_sec, e.sending_time.tv_nsec);
|
||||
printf("frame_type %d, freq_range %d, subcarrier_spacing %d, cyclic_prefix %d, symbols_per_slot %d\n",
|
||||
e.e[d->frame_type].i, e.e[d->freq_range].i,
|
||||
e.e[d->subcarrier_spacing].i, e.e[d->cyclic_prefix].i,
|
||||
e.e[d->symbols_per_slot].i);
|
||||
printf("Nid_cell %d, rnti %d, rb_size %d, rb_start %d, start_symbol_index %d, nr_of_symbols %d\n",
|
||||
e.e[d->Nid_cell].i, e.e[d->rnti].i,
|
||||
e.e[d->rb_size].i, e.e[d->rb_start].i,
|
||||
e.e[d->start_symbol_index].i, e.e[d->nr_of_symbols].i);
|
||||
printf("qam_mod_order %d, mcs_index %d, mcs_table %d, nrOfLayers %d, transform_precoding %d\n",
|
||||
e.e[d->qam_mod_order].i, e.e[d->mcs_index].i,
|
||||
e.e[d->mcs_table].i, e.e[d->nrOfLayers].i,
|
||||
e.e[d->transform_precoding].i);
|
||||
printf("dmrs_config_type %d, ul_dmrs_symb_pos %d, number_dmrs_symbols %d, dmrs_port %d, dmrs_nscid %d\n",
|
||||
e.e[d->dmrs_config_type].i, e.e[d->ul_dmrs_symb_pos].i,
|
||||
e.e[d->number_dmrs_symbols].i, e.e[d->dmrs_port].i,
|
||||
e.e[d->dmrs_nscid].i);
|
||||
printf("nb_antennas_rx %d, number_of_bits %d, data size %d\n",
|
||||
e.e[d->nb_antennas_rx].i, e.e[d->number_of_bits].i,
|
||||
e.e[d->data].bsize);
|
||||
}
|
||||
|
||||
// Write metadata fields to shared memory using field descriptor table.
|
||||
// Writes msg_id first, then loops through all fields.
|
||||
void write_metadata_to_shm(char *addr_wr, unsigned int *bufIdx_wr, event e,
|
||||
const field_descriptor *fields, int n_fields)
|
||||
{
|
||||
// Write message ID
|
||||
memcpy(&addr_wr[*bufIdx_wr], &e.type, sizeof(uint16_t));
|
||||
*bufIdx_wr += sizeof(uint16_t);
|
||||
// Write all metadata fields
|
||||
for (int i = 0; i < n_fields; i++) {
|
||||
if (fields[i].field_idx == FIELD_SENDING_TIME_SEC) {
|
||||
uint32_t ts_sec = (uint32_t)e.sending_time.tv_sec;
|
||||
memcpy(&addr_wr[*bufIdx_wr], &ts_sec, fields[i].wire_size);
|
||||
} else if (fields[i].field_idx == FIELD_SENDING_TIME_NSEC) {
|
||||
uint32_t ts_nsec = (uint32_t)e.sending_time.tv_nsec;
|
||||
memcpy(&addr_wr[*bufIdx_wr], &ts_nsec, fields[i].wire_size);
|
||||
} else {
|
||||
memcpy(&addr_wr[*bufIdx_wr], &e.e[fields[i].field_idx].i, fields[i].wire_size);
|
||||
}
|
||||
*bufIdx_wr += fields[i].wire_size;
|
||||
}
|
||||
return 0; // Value not found
|
||||
}
|
||||
|
||||
void reestablish_connection(int *socket, char *ip, int port, int number_of_events, int *is_on)
|
||||
@@ -386,40 +386,24 @@ int main(int n, char **v)
|
||||
// trace_msgs_support_data_Collection_format
|
||||
// it is used to parse the requested messages if it is based
|
||||
// on Data Collection Trace Messages Structure and supported tracer messages indices
|
||||
char *traces_iq_support_data_Collection_format[] = {"GNB_PHY_UL_FD_PUSCH_IQ",
|
||||
"GNB_PHY_UL_FD_DMRS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_POS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL"};
|
||||
char *traces_bits_support_data_Collection_format[] = {"GNB_PHY_UL_PAYLOAD_RX_BITS",
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS",
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS"};
|
||||
// extra number of records to simlify Sync between base station and UE synchronization records.
|
||||
char *traces_ul_support_data_Collection_format[] = {"GNB_PHY_UL_FD_PUSCH_IQ",
|
||||
"GNB_PHY_UL_FD_DMRS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_POS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL",
|
||||
"GNB_PHY_UL_PAYLOAD_RX_BITS",
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS",
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS"};
|
||||
// extra number of records to simplify sync between base station and UE synchronization records.
|
||||
// if you have network delay, you can increase the number of records to capture
|
||||
int max_sync_offset = 6; // 6 frames ~ 60 ms
|
||||
// all supported messages
|
||||
// Calculate the size of the combined array
|
||||
int n_iq_msgs = sizeof(traces_iq_support_data_Collection_format) / sizeof(traces_iq_support_data_Collection_format[0]);
|
||||
int n_bits_msgs = sizeof(traces_bits_support_data_Collection_format) / sizeof(traces_bits_support_data_Collection_format[0]);
|
||||
int n_msgs_based_data_Collection_format = n_iq_msgs + n_bits_msgs;
|
||||
|
||||
// Create the combined array
|
||||
char *traces_support_data_Collection_format[n_msgs_based_data_Collection_format];
|
||||
// Copy IQ messages to the combined array
|
||||
for (int i = 0; i < n_iq_msgs; i++) {
|
||||
traces_support_data_Collection_format[i] = traces_iq_support_data_Collection_format[i];
|
||||
}
|
||||
|
||||
// Copy Bits messages to the combined array
|
||||
for (int i = 0; i < n_bits_msgs; i++) {
|
||||
traces_support_data_Collection_format[i + n_iq_msgs] = traces_bits_support_data_Collection_format[i];
|
||||
}
|
||||
// Calculate the size of the message array
|
||||
int n_ul_msgs = sizeof(traces_ul_support_data_Collection_format) / sizeof(traces_ul_support_data_Collection_format[0]);
|
||||
|
||||
uint16_t msg_id = 0;
|
||||
uint16_t start_frame_number = 0;
|
||||
uint32_t number_records = 0; // number of records to capture, it is number of slots
|
||||
// array to store the requested tracer messages indices
|
||||
int req_tracer_msgs_indices[100] = {0};
|
||||
// define variables --> to do: add all of them to be class of pointers
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
char *ip = DEFAULT_REMOTE_IP;
|
||||
@@ -432,18 +416,19 @@ int main(int n, char **v)
|
||||
char trace_time_stamp_str[30];
|
||||
|
||||
// data structure for the trace messages based on Data Collection Trace Messages Structure
|
||||
event_trace_msg_data trace_msg_data;
|
||||
event_trace_msg_ul_data trace_msg_ul_data;
|
||||
|
||||
// initlization variables
|
||||
// initialization variables
|
||||
unsigned int bufIdx_wr = 0;
|
||||
unsigned int bufIdx_rd = 0;
|
||||
uint8_t num_req_tracer_msgs = 0;
|
||||
|
||||
// initilaze shared memory
|
||||
// initialize shared memory
|
||||
char *addr_wr, *addr_rd;
|
||||
printf("\n Data Collection Service: Initializing shared memory ...");
|
||||
printf("\n Directory 1: %s, Directory 2: %s", GETKEYDIR1_gNB, GETKEYDIR2_gNB);
|
||||
printf("\n Project ID: %d\n", PROJECTID_gNB);
|
||||
PRINT_STATE_BANNER("INIT");
|
||||
printf(" Data Collection Service: Initializing shared memory ...\n");
|
||||
printf(" Directory 1: %s, Directory 2: %s\n", GETKEYDIR1_gNB, GETKEYDIR2_gNB);
|
||||
printf(" Project ID: %d\n", PROJECTID_gNB);
|
||||
int shm_id_wr = create_shm(&addr_wr, GETKEYDIR1_gNB, PROJECTID_gNB);
|
||||
int shm_id_rd = create_shm(&addr_rd, GETKEYDIR2_gNB, PROJECTID_gNB);
|
||||
del_shm(addr_wr, shm_id_wr);
|
||||
@@ -500,20 +485,18 @@ int main(int n, char **v)
|
||||
addr_rd[0] = 0; // important to check if we have new requested messages
|
||||
|
||||
// read requested tracer msg indices from memory
|
||||
printf("\n Data Collection Service: Waiting for messages request ...\n");
|
||||
// 0: Wait
|
||||
// 1: config
|
||||
// 2: record
|
||||
// 3: stop
|
||||
PRINT_STATE_BANNER("WAIT");
|
||||
printf(" Data Collection Service: Waiting for config message ...\n");
|
||||
// Wait for Action Config
|
||||
while (1) {
|
||||
if ((uint8_t)(addr_rd[0]) == 0) {
|
||||
if ((uint8_t)(addr_rd[0]) == STATE_WAIT) {
|
||||
usleep(50); // sleep for 50 us: 0.5 ms slot duration
|
||||
}
|
||||
// config state
|
||||
else if ((uint8_t)(addr_rd[0]) == 1) {
|
||||
else if ((uint8_t)(addr_rd[0]) == STATE_CONFIG) {
|
||||
get_time_stamp_usec(trace_time_stamp_str);
|
||||
printf("\n Received config message. Time Stamp: %s", trace_time_stamp_str);
|
||||
PRINT_STATE_BANNER("CONFIG");
|
||||
printf(" Received config message. Time Stamp: %s\n", trace_time_stamp_str);
|
||||
|
||||
// get the IP address length in bytes
|
||||
bufIdx_rd = 1;
|
||||
@@ -530,11 +513,11 @@ int main(int n, char **v)
|
||||
|
||||
// get the array bytes of the port number : 2 bytes
|
||||
uint8_t port_number_bytes[2] = {addr_rd[bufIdx_rd], addr_rd[bufIdx_rd + 1]};
|
||||
bufIdx_rd += 2; // + 2 bytes = start frame number
|
||||
bufIdx_rd += 2; // + 2 bytes = port number
|
||||
|
||||
port = combine_bytes(port_number_bytes, 2);
|
||||
printf("\n Parameters: IP Address length: %d, IP Address: %s, Port Number: %d \n", ip_address_length, ip_address, port);
|
||||
addr_rd[0] = 0; // reset memory : to wait for record action
|
||||
printf(" Parameters: IP Address length: %d, IP Address: %s, Port Number: %d\n", ip_address_length, ip_address, port);
|
||||
addr_rd[0] = STATE_WAIT; // reset memory : to wait for record action
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -545,37 +528,39 @@ int main(int n, char **v)
|
||||
|
||||
/* connect to the nr-softmodem */
|
||||
socket = connect_to(ip, port);
|
||||
printf("\n Connected to nr-softmodem");
|
||||
printf(" Connected to nr-softmodem\n");
|
||||
|
||||
// Read Action record or stop
|
||||
printf("\n Data Collection Service: Waiting for record message ...\n");
|
||||
PRINT_STATE_BANNER("WAIT");
|
||||
printf(" Data Collection Service: Waiting for record/stop message ...\n");
|
||||
while (1) {
|
||||
// wait for Action record
|
||||
if ((uint8_t)(addr_rd[0]) == 0) {
|
||||
if ((uint8_t)(addr_rd[0]) == STATE_WAIT) {
|
||||
usleep(50); // sleep for 50 us: 0.5 ms slot duration
|
||||
}
|
||||
|
||||
// quit state
|
||||
else if ((uint8_t)(addr_rd[0]) == 3) {
|
||||
printf("\n Received 'stop' command. Exiting...");
|
||||
printf("\n ");
|
||||
else if ((uint8_t)(addr_rd[0]) == STATE_STOP) {
|
||||
PRINT_STATE_BANNER("STOP");
|
||||
printf(" Received 'stop' command. Exiting...\n");
|
||||
// Clean up and exit
|
||||
break;
|
||||
}
|
||||
// record state
|
||||
else if ((uint8_t)(addr_rd[0]) == 2) {
|
||||
else if ((uint8_t)(addr_rd[0]) == STATE_RECORD) {
|
||||
// clear remote buffer if there is
|
||||
clear_remote_config();
|
||||
get_time_stamp_usec(trace_time_stamp_str);
|
||||
printf("\n Received record message. Time Stamp: %s", trace_time_stamp_str);
|
||||
PRINT_STATE_BANNER("RECORD");
|
||||
printf(" Received record message. Time Stamp: %s\n", trace_time_stamp_str);
|
||||
|
||||
// read number of requested messages
|
||||
bufIdx_rd = 1;
|
||||
num_req_tracer_msgs = addr_rd[bufIdx_rd];
|
||||
bufIdx_rd += 1;
|
||||
printf("\n Number of requested tracer messages: %d,", num_req_tracer_msgs);
|
||||
printf(" Number of requested tracer messages: %d\n", num_req_tracer_msgs);
|
||||
// reset memory : action to wait for next record action
|
||||
addr_rd[0] = 0;
|
||||
addr_rd[0] = STATE_WAIT;
|
||||
|
||||
// read tracer msg IDs - every message ID has been stored in two bytes
|
||||
for (uint8_t msg_n = 0; msg_n < num_req_tracer_msgs; msg_n++) {
|
||||
@@ -607,40 +592,36 @@ int main(int n, char **v)
|
||||
printf("start_frame: %d\n", start_frame_number);
|
||||
|
||||
/* activate the trace in this array */
|
||||
printf("\n Activate Tracer messages in on_off array: ");
|
||||
printf(" Activating tracer messages:\n");
|
||||
for (i = 0; i < num_req_tracer_msgs; i++) {
|
||||
char *on_off_name = event_name_from_id(database, req_tracer_msgs_indices[i]);
|
||||
on_off(database, on_off_name, is_on, 1);
|
||||
printf("%d, %s, ", req_tracer_msgs_indices[i], on_off_name);
|
||||
// on_off(database, "GNB_PHY_DL_OUTPUT_SIGNAL", is_on, 1);
|
||||
printf(" %d: %s\n", req_tracer_msgs_indices[i], on_off_name);
|
||||
}
|
||||
|
||||
// get the event IDs for the bit messages
|
||||
int traces_bits_support_data_Collection_format_idx[n_bits_msgs];
|
||||
for (int i = 0; i < n_bits_msgs; i++) {
|
||||
traces_bits_support_data_Collection_format_idx[i] =
|
||||
event_id_from_name(database, traces_bits_support_data_Collection_format[i]);
|
||||
}
|
||||
|
||||
// all supported messages
|
||||
int traces_support_data_Collection_format_idx[n_msgs_based_data_Collection_format];
|
||||
for (int i = 0; i < n_msgs_based_data_Collection_format; i++) {
|
||||
traces_support_data_Collection_format_idx[i] = event_id_from_name(database, traces_support_data_Collection_format[i]);
|
||||
// Build UL message ID array for generic UL dispatch
|
||||
int ul_msg_ids[n_ul_msgs];
|
||||
for (int i = 0; i < n_ul_msgs; i++) {
|
||||
ul_msg_ids[i] = event_id_from_name(database, traces_ul_support_data_Collection_format[i]);
|
||||
}
|
||||
|
||||
// setup data for the trace messages
|
||||
setup_trace_msg_data(&trace_msg_data, database);
|
||||
printf("\n Setup Trace Data Done");
|
||||
setup_trace_msg_ul_data(&trace_msg_ul_data, database);
|
||||
printf(" Setup UL trace data done\n");
|
||||
|
||||
// Build field descriptor table for table-driven shared memory writes
|
||||
field_descriptor ul_fields[N_UL_METADATA_FIELDS];
|
||||
build_ul_field_descriptors(ul_fields, &trace_msg_ul_data);
|
||||
|
||||
// Get the start time
|
||||
struct timespec start_time = get_current_time();
|
||||
|
||||
/* activate the tracee in the nr-softmodem */
|
||||
/* activate the traces in the nr-softmodem */
|
||||
activate_traces(socket, number_of_events, is_on);
|
||||
printf("\n Activated Traces in nr-softmodem");
|
||||
printf(" Activated traces in nr-softmodem\n");
|
||||
|
||||
/* a buffer needed to receive events from the nr-softmodem */
|
||||
OBUF ebuf = {osize : 0, omaxsize : 0, obuf : NULL};
|
||||
OBUF ebuf = {.osize = 0, .omaxsize = 0, .obuf = NULL};
|
||||
|
||||
/* read events */
|
||||
int nrecord_idx = 0;
|
||||
@@ -655,8 +636,8 @@ int main(int n, char **v)
|
||||
int current_frame = 0, prev_frame = 0, current_slot = 0, prev_slot = 0;
|
||||
// offset to sync between base station and UE synchronization records or power measurements
|
||||
int sync_offset_index = 0; // increase the index only if the index of frame changes after getting all records
|
||||
// since we will use the frame differece to do extra records, we should be sure that the last slot is recorded completely
|
||||
printf("\n\n Data Collection Service: Start reading messages ...");
|
||||
// since we will use the frame difference to do extra records, we should be sure that the last slot is recorded completely
|
||||
printf("\n Data Collection Service: Start reading messages ...\n");
|
||||
struct pollfd event_poll_fd;
|
||||
event_poll_fd.fd = socket;
|
||||
event_poll_fd.events = POLLIN;
|
||||
@@ -676,27 +657,24 @@ int main(int n, char **v)
|
||||
reestablish_connection(&socket, ip, port, number_of_events, is_on);
|
||||
continue; // Skip further processing and retry
|
||||
}
|
||||
//-------------------------
|
||||
// GNB_PHY_UL_FD_PUSCH_IQ, GNB_PHY_UL_FD_DMRS_ID, GNB_PHY_UL_FD_CHAN_EST_DMRS_POS,
|
||||
// UE_PHY_UL_SCRAMBLED_TX_BITS, GNB_PHY_UL_PAYLOAD_RX_BITS, UE_PHY_UL_PAYLOAD_TX_BITS
|
||||
//-------------------------
|
||||
|
||||
// is it a requested message
|
||||
if (isValueInArray(e.type, req_tracer_msgs_indices, num_req_tracer_msgs)) {
|
||||
if (is_message_in_list(req_tracer_msgs_indices, num_req_tracer_msgs, e.type)) {
|
||||
// is it based on Data Collection Trace Messages Structure
|
||||
if (isValueInArray(e.type, traces_support_data_Collection_format_idx, n_msgs_based_data_Collection_format)) {
|
||||
if (is_message_in_list(ul_msg_ids, n_ul_msgs, e.type)) {
|
||||
// Start recording from the next slot to mitigate capturing partial data
|
||||
// check if the current frame and slot are different from the previous frame and slot
|
||||
// Then, increase the record index
|
||||
if (start_recording == false) {
|
||||
if (got_ref_frame_slot == false) {
|
||||
ref_frame = e.e[trace_msg_data.frame].i;
|
||||
ref_slot = e.e[trace_msg_data.slot].i;
|
||||
ref_frame = e.e[trace_msg_ul_data.frame].i;
|
||||
ref_slot = e.e[trace_msg_ul_data.slot].i;
|
||||
printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type);
|
||||
got_ref_frame_slot = true;
|
||||
}
|
||||
|
||||
current_frame = e.e[trace_msg_data.frame].i;
|
||||
current_slot = e.e[trace_msg_data.slot].i;
|
||||
current_frame = e.e[trace_msg_ul_data.frame].i;
|
||||
current_slot = e.e[trace_msg_ul_data.slot].i;
|
||||
frame_difference = (current_frame - ref_frame + MAX_FRAME_INDEX + 1) % (MAX_FRAME_INDEX + 1);
|
||||
slot_difference = (current_slot - ref_slot + MAX_SLOT_INDEX + 1) % (MAX_SLOT_INDEX + 1);
|
||||
printf("\n First frame.slot: %d.%d, current frame.slot: %d.%d, diff frame.slot: %d.%d",
|
||||
@@ -709,129 +687,30 @@ int main(int n, char **v)
|
||||
|
||||
if ((ref_frame != current_frame) || (ref_slot != current_slot)) {
|
||||
start_recording = true;
|
||||
printf("\n Start recording from frame: %d, slot: %d ", e.e[trace_msg_data.frame].i, e.e[trace_msg_data.slot].i);
|
||||
printf("\n Start recording from frame: %d, slot: %d ", e.e[trace_msg_ul_data.frame].i, e.e[trace_msg_ul_data.slot].i);
|
||||
}
|
||||
}
|
||||
// start recording from the next frame to mitigate capturing partial data
|
||||
if (start_recording == true) {
|
||||
/* this is how to access the elements of the Data Collection trace messages.
|
||||
* we use e.e[<element>] and then the correct suffix, here
|
||||
* it's .i for the integer and .b for the buffer and .bsize for the buffer size
|
||||
* see in event.h the structure event_arg
|
||||
*/
|
||||
unsigned char *buf = e.e[trace_msg_data.data].b;
|
||||
|
||||
printf("\n\nRecord number: %d", nrecord_idx);
|
||||
#ifdef DEBUG_BUFFER
|
||||
printf("\nBuffer index in bytes: %d", bufIdx_wr);
|
||||
#endif
|
||||
|
||||
// add general message header: message ID,
|
||||
// T-Tracer Message format
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols :
|
||||
// int,dmrs_port : int,dmrs_nscid :
|
||||
// int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.type, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.frame].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.slot].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.datetime_yyyymmdd].i, sizeof(uint32_t));
|
||||
// --- UL IQ/Bits handler ---
|
||||
// Write metadata + buffer to shared memory
|
||||
write_metadata_to_shm(addr_wr, &bufIdx_wr, e, ul_fields, N_UL_METADATA_FIELDS);
|
||||
// Write buffer: size (uint32_t) + raw data
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_ul_data.data].bsize, sizeof(uint32_t));
|
||||
bufIdx_wr += sizeof(uint32_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.datetime_hhmmssmmm].i, sizeof(uint32_t));
|
||||
bufIdx_wr += sizeof(uint32_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.frame_type].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.freq_range].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.subcarrier_spacing].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.cyclic_prefix].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.symbols_per_slot].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.Nid_cell].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rnti].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rb_size].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rb_start].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.start_symbol_index].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nr_of_symbols].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.qam_mod_order].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.mcs_index].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.mcs_table].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nrOfLayers].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.transform_precoding].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_config_type].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.ul_dmrs_symb_pos].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.number_dmrs_symbols].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_port].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_nscid].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nb_antennas_rx].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.number_of_bits].i, sizeof(uint32_t));
|
||||
bufIdx_wr += sizeof(uint32_t);
|
||||
|
||||
printf("\nTime Stamp: %d_%d", e.e[trace_msg_data.datetime_yyyymmdd].i, e.e[trace_msg_data.datetime_hhmmssmmm].i);
|
||||
|
||||
// add message body: length in bytes + recorded data
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.data].bsize, sizeof(uint32_t));
|
||||
bufIdx_wr += sizeof(uint32_t);
|
||||
|
||||
// read data from buffer and convert from unsigned char * array to int 16 using the right endianness
|
||||
// T-tracer: Little Endian
|
||||
// For BITS Messages, example: UE_PHY_UL_SCRAMBLED_TX_BITS: data in bytes
|
||||
|
||||
if (is_bits_messages(traces_bits_support_data_Collection_format_idx, n_bits_msgs, e.type)) {
|
||||
for (int byte_idx = 0; byte_idx < e.e[trace_msg_data.data].bsize; byte_idx += 1) {
|
||||
// printf("%d, ", buf[byte_idx]);
|
||||
memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx], sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int byte_idx = 0; byte_idx < e.e[trace_msg_data.data].bsize; byte_idx += 2) {
|
||||
// For a little-endian system:
|
||||
memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx], sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx + 1], sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (int byte_idx_i = 0; byte_idx_i < e.e[d.nr_ul_fd_dmrs_data].bsize; byte_idx_i+=4) {
|
||||
int16_t I = buf[byte_idx_i] | (buf[byte_idx_i+1] << 8);
|
||||
int16_t Q = buf[byte_idx_i+2] | (buf[byte_idx_i+3] << 8);
|
||||
printf ("idx %d, ", byte_idx_i);
|
||||
printf ("\n%d", I);
|
||||
printf ("\n%d", Q);
|
||||
}
|
||||
*/
|
||||
memcpy(&addr_wr[bufIdx_wr], e.e[trace_msg_ul_data.data].b, e.e[trace_msg_ul_data.data].bsize);
|
||||
bufIdx_wr += e.e[trace_msg_ul_data.data].bsize;
|
||||
#ifdef DEBUG_T_Tracer
|
||||
print_ul_metadata_debug(e, &trace_msg_ul_data, database);
|
||||
#endif
|
||||
// check if the current frame and slot are different from the previous frame and slot
|
||||
// Then, increase the record index
|
||||
current_frame = e.e[trace_msg_data.frame].i;
|
||||
current_slot = e.e[trace_msg_data.slot].i;
|
||||
current_frame = e.e[trace_msg_ul_data.frame].i;
|
||||
current_slot = e.e[trace_msg_ul_data.slot].i;
|
||||
|
||||
// increase sync offset index if the current frame is different from the previous frame
|
||||
if ((current_frame != prev_frame) && nrecord_idx >= number_records) {
|
||||
@@ -844,43 +723,7 @@ int main(int n, char **v)
|
||||
prev_frame = current_frame;
|
||||
prev_slot = current_slot;
|
||||
}
|
||||
#ifdef DEBUG_T_Tracer
|
||||
printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type);
|
||||
printf("frame %d, slot %d, datetime %d_%d\n",
|
||||
e.e[trace_msg_data.frame].i,
|
||||
e.e[trace_msg_data.slot].i,
|
||||
e.e[trace_msg_data.datetime_yyyymmdd].i,
|
||||
e.e[trace_msg_data.datetime_hhmmssmmm].i);
|
||||
printf("frame_type %d, freq_range %d, subcarrier_spacing %d, cyclic_prefix %d, symbols_per_slot %d\n",
|
||||
e.e[trace_msg_data.frame_type].i,
|
||||
e.e[trace_msg_data.freq_range].i,
|
||||
e.e[trace_msg_data.subcarrier_spacing].i,
|
||||
e.e[trace_msg_data.cyclic_prefix].i,
|
||||
e.e[trace_msg_data.symbols_per_slot].i);
|
||||
printf("Nid_cell %d, rnti %d, rb_size %d, rb_start %d, start_symbol_index %d, nr_of_symbols %d\n",
|
||||
e.e[trace_msg_data.Nid_cell].i,
|
||||
e.e[trace_msg_data.rnti].i,
|
||||
e.e[trace_msg_data.rb_size].i,
|
||||
e.e[trace_msg_data.rb_start].i,
|
||||
e.e[trace_msg_data.start_symbol_index].i,
|
||||
e.e[trace_msg_data.nr_of_symbols].i);
|
||||
printf("qam_mod_order %d, mcs_index %d, mcs_table %d, nrOfLayers %d, transform_precoding %d\n",
|
||||
e.e[trace_msg_data.qam_mod_order].i,
|
||||
e.e[trace_msg_data.mcs_index].i,
|
||||
e.e[trace_msg_data.mcs_table].i,
|
||||
e.e[trace_msg_data.nrOfLayers].i,
|
||||
e.e[trace_msg_data.transform_precoding].i);
|
||||
printf("dmrs_config_type %d, ul_dmrs_symb_pos %d, number_dmrs_symbols %d, dmrs_port %d, dmrs_nscid %d\n",
|
||||
e.e[trace_msg_data.dmrs_config_type].i,
|
||||
e.e[trace_msg_data.ul_dmrs_symb_pos].i,
|
||||
e.e[trace_msg_data.number_dmrs_symbols].i,
|
||||
e.e[trace_msg_data.dmrs_port].i,
|
||||
e.e[trace_msg_data.dmrs_nscid].i);
|
||||
printf("nb_antennas_rx %d, number_of_bits %d, data size %d\n",
|
||||
e.e[trace_msg_data.nb_antennas_rx].i,
|
||||
e.e[trace_msg_data.number_of_bits].i,
|
||||
e.e[trace_msg_data.data].bsize);
|
||||
#endif
|
||||
|
||||
} // End of start recording flag
|
||||
} // end of if statement for the supported messages based on Data Collection Trace Messages Structure
|
||||
else {
|
||||
@@ -891,29 +734,28 @@ int main(int n, char **v)
|
||||
} // end while loop of reading events
|
||||
else {
|
||||
// No data, just loop and check time
|
||||
usleep(100); // optional: avoid busy-waiting
|
||||
usleep(50); // optional: avoid busy-waiting
|
||||
}
|
||||
} // End of while loop to read events
|
||||
|
||||
// de-activate the tracee in the nr-softmodem
|
||||
printf("\n De-activated Tracer message:\n");
|
||||
// de-activate the traces in the nr-softmodem
|
||||
printf("\n De-activating tracer messages\n");
|
||||
for (i = 0; i < num_req_tracer_msgs; i++) {
|
||||
char *on_off_name = event_name_from_id(database, req_tracer_msgs_indices[i]);
|
||||
on_off(database, on_off_name, is_on, 0);
|
||||
// printf("\n %d, %s, ", req_tracer_msgs_indices[i], on_off_name);
|
||||
// on_off(database, "GNB_PHY_DL_OUTPUT_SIGNAL", is_on, 1);
|
||||
}
|
||||
// De-activate the tracee in the nr-softmodem
|
||||
activate_traces(socket, number_of_events, is_on);
|
||||
printf("\n De-activated Traces");
|
||||
printf(" De-activated traces\n");
|
||||
// Get the end time
|
||||
struct timespec end_time = get_current_time();
|
||||
// Calculate the time difference
|
||||
double time_diff = calculate_time_difference(start_time, end_time);
|
||||
printf("Total Time difference: %.2f ms\n", time_diff);
|
||||
printf("Time difference per record: %.2f ms\n", time_diff / (number_records + max_sync_offset));
|
||||
printf(" Total time: %.2f ms\n", time_diff);
|
||||
printf(" Time per record: %.2f ms\n", time_diff / (number_records + max_sync_offset));
|
||||
|
||||
//-----------------------------
|
||||
// discard stale or previous record data for the first DISCARD_RECORD_DURATION_MS
|
||||
//-----------------------------
|
||||
struct timespec record_start, record_now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &record_start);
|
||||
|
||||
@@ -934,12 +776,11 @@ int main(int n, char **v)
|
||||
}
|
||||
} else {
|
||||
// No data, just loop and check time
|
||||
usleep(100); // optional: avoid busy-waiting
|
||||
usleep(50); // optional: avoid busy-waiting
|
||||
}
|
||||
} // End of while loop to discard stale records
|
||||
}
|
||||
} // End a while loop to check for the "stop" command
|
||||
// de-activate the tracee in the nr-softmodem
|
||||
} // End of while loop for record/stop
|
||||
|
||||
free_database(database);
|
||||
free(is_on);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief T-Tracer UE service to capture tracee Messages from UE, it is used by data recording application
|
||||
* \brief T-Tracer UE service to capture trace Messages from UE, it is used by data recording application
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -32,7 +32,21 @@
|
||||
#define DEBUG_BUFFER
|
||||
// Duration to discard recording in milliseconds to mitigate stale or previous record data
|
||||
#define DISCARD_RECORD_DURATION_MS 10
|
||||
// #include <linux/time.h>
|
||||
|
||||
// Sentinel values for field_descriptor: source is e.sending_time
|
||||
#define FIELD_SENDING_TIME_SEC -2
|
||||
#define FIELD_SENDING_TIME_NSEC -3
|
||||
|
||||
// State machine constants for shared memory protocol
|
||||
#define STATE_WAIT 0
|
||||
#define STATE_CONFIG 1
|
||||
#define STATE_RECORD 2
|
||||
#define STATE_STOP 3
|
||||
|
||||
// Visual separator for state machine transitions in console output
|
||||
#define STATE_SEPARATOR "========================================"
|
||||
#define PRINT_STATE_BANNER(state_name) \
|
||||
printf("\n%s\n [STATE: %s]\n%s\n", STATE_SEPARATOR, state_name, STATE_SEPARATOR)
|
||||
|
||||
// Combine bytes in little-endian format
|
||||
int combine_bytes(const uint8_t *bytes, size_t num_bytes)
|
||||
@@ -44,19 +58,11 @@ int combine_bytes(const uint8_t *bytes, size_t num_bytes)
|
||||
return result;
|
||||
}
|
||||
|
||||
// Convert an integer to an array of bytes in little-endian format
|
||||
void int_to_bytes(int num, uint8_t *bytes, size_t num_bytes)
|
||||
// Check if a message ID is present in an array of message IDs (generic array lookup)
|
||||
bool is_message_in_list(int msg_id_list[], int list_size, int msg_id)
|
||||
{
|
||||
for (size_t i = 0; i < num_bytes; ++i) {
|
||||
bytes[i] = (num >> (i * 8)) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the message is in the list of bits messages
|
||||
bool is_bits_messages(int traces_bits_support_data_Collection_format_idx[], int n_bits_msgs, int msg_id)
|
||||
{
|
||||
for (int i = 0; i < n_bits_msgs; i++) {
|
||||
if (msg_id == traces_bits_support_data_Collection_format_idx[i]) {
|
||||
for (int i = 0; i < list_size; i++) {
|
||||
if (msg_id == msg_id_list[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -71,12 +77,6 @@ struct timespec get_current_time()
|
||||
return time;
|
||||
}
|
||||
|
||||
// Function to convert timespec to microseconds
|
||||
long long timespec_to_microseconds(struct timespec time)
|
||||
{
|
||||
return (time.tv_sec * 1000000LL) + (time.tv_nsec / 1000);
|
||||
}
|
||||
|
||||
// Calculate the time difference in milliseconds
|
||||
double calculate_time_difference(struct timespec start, struct timespec end)
|
||||
{
|
||||
@@ -88,7 +88,7 @@ double calculate_time_difference(struct timespec start, struct timespec end)
|
||||
// Get Time Stamp in microseconds in YYYYMMDDHHMMSSmmmuuu format
|
||||
char *get_time_stamp_usec(char time_stamp_str[])
|
||||
{
|
||||
// initialization to measure time stamp --This part should be moved to inilization part
|
||||
// initialization to measure time stamp
|
||||
time_t my_time;
|
||||
struct tm *timeinfo;
|
||||
time(&my_time);
|
||||
@@ -104,31 +104,12 @@ char *get_time_stamp_usec(char time_stamp_str[])
|
||||
uint8_t hour = timeinfo->tm_hour;
|
||||
uint8_t min = timeinfo->tm_min;
|
||||
uint8_t sec = timeinfo->tm_sec;
|
||||
uint16_t usec = (tv.tv_usec);
|
||||
// printf ("Time stamp: %d_%d_%d_%d_%d_%d_%d \n",year,mon,mday,hour,min,sec,usec);
|
||||
// sprintf(time_stamp_str, "%d_%d_%d_%d_%d_%d_%d",year,mon,mday,hour,min,sec,usec);
|
||||
sprintf(time_stamp_str, "%04d%02d%02d%02d%02d%02d%06d", year, mon, mday, hour, min, sec, usec);
|
||||
uint32_t usec = (tv.tv_usec);
|
||||
sprintf(time_stamp_str, "%04d%02d%02d%02d%02d%02d%06u", year, mon, mday, hour, min, sec, usec);
|
||||
|
||||
return time_stamp_str;
|
||||
}
|
||||
|
||||
// Convert timestamp string to integer
|
||||
int convert_time_stamp_to_int(const char *timestamp)
|
||||
{
|
||||
return atoi(timestamp);
|
||||
}
|
||||
|
||||
// Split timestamp string and convert to integer
|
||||
int split_time_stamp_and_convert_to_int(char time_stamp_str[], int shift, int length)
|
||||
{
|
||||
char time_part[length + 1]; // Buffer to hold the date part YYYYMMDD or HHMMSSmmm
|
||||
// Copy the first 8 or 9 characters (YYYYMMDD) to HHMMSSmmm
|
||||
strncpy(time_part, time_stamp_str + shift, length);
|
||||
time_part[length] = '\0'; // Null-terminate the string
|
||||
// Convert timestamp string to integer
|
||||
return convert_time_stamp_to_int(time_part);
|
||||
}
|
||||
|
||||
void err_exit(char *buf)
|
||||
{
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
@@ -153,7 +134,7 @@ int create_shm(char **addrN, const char *shm_path, int projectId)
|
||||
shm_id = shmget(key, SHMSIZE, IPC_CREAT | IPC_EXCL | 0664);
|
||||
if (shm_id == -1) {
|
||||
if (errno == EEXIST) {
|
||||
printf("Error: shared memeory already exist\n");
|
||||
printf("Error: shared memory already exists\n");
|
||||
shm_id = shmget(key, 0, 0);
|
||||
printf("reference shm_id = %d\n", shm_id);
|
||||
} else {
|
||||
@@ -210,75 +191,28 @@ void usage(void)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// class to store the message and the action to enable capture selected data
|
||||
// 0: do not record message
|
||||
// 1: record message
|
||||
struct trace_struct {
|
||||
char on_off_name[100];
|
||||
int on_off_action;
|
||||
};
|
||||
|
||||
// struct for trace message based on Data Collection Trace Messages Structure
|
||||
// you need to define the vararibles of each message
|
||||
// you need to define the variables of each message
|
||||
typedef struct {
|
||||
/* Data Collection Trace Message Structure */
|
||||
int frame;
|
||||
int slot;
|
||||
int datetime_yyyymmdd;
|
||||
int datetime_hhmmssmmm;
|
||||
int frame_type, freq_range, subcarrier_spacing, cyclic_prefix, symbols_per_slot;
|
||||
int Nid_cell, rnti;
|
||||
int rb_size, rb_start, start_symbol_index, nr_of_symbols;
|
||||
int qam_mod_order, mcs_index, mcs_table, nrOfLayers, transform_precoding;
|
||||
int dmrs_config_type, ul_dmrs_symb_pos, number_dmrs_symbols;
|
||||
int dmrs_port, dmrs_nscid, nb_antennas_tx, number_of_bits;
|
||||
int data_size, data;
|
||||
} event_trace_msg_data;
|
||||
int data;
|
||||
} event_trace_msg_ul_data;
|
||||
|
||||
void setup_trace_msg_data(event_trace_msg_data *d, void *database)
|
||||
void setup_trace_msg_ul_data(event_trace_msg_ul_data *d, void *database)
|
||||
{
|
||||
database_event_format f;
|
||||
int i;
|
||||
|
||||
/* Data Collection Trace Message Structure */
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols :
|
||||
// int,dmrs_port : int,dmrs_nscid :
|
||||
// int,nb_antennas_tx : int,number_of_bits : buffer,data
|
||||
|
||||
// Initialize the data structure
|
||||
d->frame = -1;
|
||||
d->slot = -1;
|
||||
d->datetime_yyyymmdd = -1;
|
||||
d->datetime_hhmmssmmm = -1;
|
||||
d->frame_type = -1;
|
||||
d->freq_range = -1;
|
||||
d->subcarrier_spacing = -1;
|
||||
d->cyclic_prefix = -1;
|
||||
d->symbols_per_slot = -1;
|
||||
d->Nid_cell = -1;
|
||||
d->rnti = -1;
|
||||
d->rb_size = -1;
|
||||
d->rb_start = -1;
|
||||
d->start_symbol_index = -1;
|
||||
d->nr_of_symbols = -1;
|
||||
d->qam_mod_order = -1;
|
||||
d->mcs_index = -1;
|
||||
d->mcs_table = -1;
|
||||
d->nrOfLayers = -1;
|
||||
d->transform_precoding = -1;
|
||||
d->dmrs_config_type = -1;
|
||||
d->ul_dmrs_symb_pos = -1;
|
||||
d->number_dmrs_symbols = -1;
|
||||
d->dmrs_port = -1;
|
||||
d->dmrs_nscid = -1;
|
||||
d->nb_antennas_tx = -1;
|
||||
d->number_of_bits = -1;
|
||||
d->data = -1;
|
||||
// Initialize all fields to -1 (marks unset indices)
|
||||
memset(d, -1, sizeof(*d));
|
||||
|
||||
/* this macro looks for a particular element and checks its type */
|
||||
#define G(var_name, var_type, var) \
|
||||
@@ -291,35 +225,14 @@ void setup_trace_msg_data(event_trace_msg_data *d, void *database)
|
||||
continue; \
|
||||
}
|
||||
|
||||
/* ------------------------------*/
|
||||
/* Create Macro for Data Collection Trace Message */
|
||||
/* ------------------------------*/
|
||||
// Data Collection Trace Message Structure
|
||||
// Example: GNB_PHY_UL_FD_PUSCH_IQ, GNB_PHY_UL_FD_DMRS_ID,
|
||||
// GNB_PHY_UL_FD_CHAN_EST_DMRS_POS, GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL
|
||||
// GNB_PHY_UL_PAYLOAD_RX_BITS
|
||||
// UE_PHY_UL_SCRAMBLED_TX_BITS
|
||||
// UE_PHY_UL_PAYLOAD_TX_BITS
|
||||
// Get a template of any message based on Data Collection Trace Messages Structure
|
||||
// Get a template of any UL message based on Data Collection Trace Messages Structure
|
||||
int Trace_MSG_ID = event_id_from_name(database, "GNB_PHY_UL_FD_PUSCH_IQ");
|
||||
f = get_format(database, Trace_MSG_ID);
|
||||
|
||||
/* get the elements of the trace
|
||||
* the value is an index in the event, see below */
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols :
|
||||
// int,dmrs_port : int,dmrs_nscid :
|
||||
// int,nb_antennas_tx : int,number_of_bits : buffer,data
|
||||
|
||||
// Map each field name to its index in the event structure
|
||||
for (i = 0; i < f.count; i++) {
|
||||
G("frame", "int", d->frame)
|
||||
G("slot", "int", d->slot)
|
||||
G("datetime_yyyymmdd", "int", d->datetime_yyyymmdd)
|
||||
G("datetime_hhmmssmmm", "int", d->datetime_hhmmssmmm)
|
||||
G("frame_type", "int", d->frame_type)
|
||||
G("freq_range", "int", d->freq_range)
|
||||
G("subcarrier_spacing", "int", d->subcarrier_spacing)
|
||||
@@ -347,20 +260,108 @@ void setup_trace_msg_data(event_trace_msg_data *d, void *database)
|
||||
G("number_of_bits", "int", d->number_of_bits)
|
||||
G("data", "buffer", d->data)
|
||||
}
|
||||
// if (d->frame == -1 || d->slot == -1) goto error;
|
||||
#undef G
|
||||
return;
|
||||
}
|
||||
|
||||
// Function to check if a value is in the array
|
||||
int isValueInArray(int value, int arr[], int size)
|
||||
// -------------------------------------------------------------------
|
||||
// Table-driven UL metadata shared memory writer and debug printer
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Number of UL metadata fields written to shared memory (excludes msg_id and buffer)
|
||||
#define N_UL_METADATA_FIELDS 27
|
||||
|
||||
// Descriptor for one metadata field to write to shared memory
|
||||
typedef struct {
|
||||
int field_idx; // index into event e.e[] array
|
||||
size_t wire_size; // number of bytes to write to shm
|
||||
} field_descriptor;
|
||||
|
||||
// Build UL field descriptor array from a populated event_trace_msg_ul_data struct.
|
||||
// Must be called after setup_trace_msg_ul_data() so that field indices are populated.
|
||||
// Note: nb_antennas_tx maps to database field "nb_antennas_rx" (see G macro workaround above)
|
||||
void build_ul_field_descriptors(field_descriptor *fields, const event_trace_msg_ul_data *d)
|
||||
{
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (arr[i] == value) {
|
||||
return 1; // Value found
|
||||
int i = 0;
|
||||
fields[i++] = (field_descriptor){ d->frame, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->slot, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ FIELD_SENDING_TIME_SEC, sizeof(uint32_t) };
|
||||
fields[i++] = (field_descriptor){ FIELD_SENDING_TIME_NSEC, sizeof(uint32_t) };
|
||||
fields[i++] = (field_descriptor){ d->frame_type, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->freq_range, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->subcarrier_spacing, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->cyclic_prefix, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->symbols_per_slot, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->Nid_cell, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->rnti, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->rb_size, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->rb_start, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->start_symbol_index, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->nr_of_symbols, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->qam_mod_order, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->mcs_index, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->mcs_table, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->nrOfLayers, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->transform_precoding, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->dmrs_config_type, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->ul_dmrs_symb_pos, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->number_dmrs_symbols, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->dmrs_port, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->dmrs_nscid, sizeof(uint16_t) };
|
||||
fields[i++] = (field_descriptor){ d->nb_antennas_tx, sizeof(uint8_t) };
|
||||
fields[i++] = (field_descriptor){ d->number_of_bits, sizeof(uint32_t) };
|
||||
}
|
||||
|
||||
// Print UL metadata fields for debug output
|
||||
// Note: nb_antennas_tx is the UE transmit antenna count (maps to database field "nb_antennas_rx")
|
||||
void print_ul_metadata_debug(event e, const event_trace_msg_ul_data *d, void *database)
|
||||
{
|
||||
printf("\nUnix TS: %ld.%09ld", e.sending_time.tv_sec, e.sending_time.tv_nsec);
|
||||
printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type);
|
||||
printf("frame %d, slot %d, unix_ts %ld.%09ld\n",
|
||||
e.e[d->frame].i, e.e[d->slot].i,
|
||||
e.sending_time.tv_sec, e.sending_time.tv_nsec);
|
||||
printf("frame_type %d, freq_range %d, subcarrier_spacing %d, cyclic_prefix %d, symbols_per_slot %d\n",
|
||||
e.e[d->frame_type].i, e.e[d->freq_range].i,
|
||||
e.e[d->subcarrier_spacing].i, e.e[d->cyclic_prefix].i,
|
||||
e.e[d->symbols_per_slot].i);
|
||||
printf("Nid_cell %d, rnti %d, rb_size %d, rb_start %d, start_symbol_index %d, nr_of_symbols %d\n",
|
||||
e.e[d->Nid_cell].i, e.e[d->rnti].i,
|
||||
e.e[d->rb_size].i, e.e[d->rb_start].i,
|
||||
e.e[d->start_symbol_index].i, e.e[d->nr_of_symbols].i);
|
||||
printf("qam_mod_order %d, mcs_index %d, mcs_table %d, nrOfLayers %d, transform_precoding %d\n",
|
||||
e.e[d->qam_mod_order].i, e.e[d->mcs_index].i,
|
||||
e.e[d->mcs_table].i, e.e[d->nrOfLayers].i,
|
||||
e.e[d->transform_precoding].i);
|
||||
printf("dmrs_config_type %d, ul_dmrs_symb_pos %d, number_dmrs_symbols %d, dmrs_port %d, dmrs_nscid %d\n",
|
||||
e.e[d->dmrs_config_type].i, e.e[d->ul_dmrs_symb_pos].i,
|
||||
e.e[d->number_dmrs_symbols].i, e.e[d->dmrs_port].i,
|
||||
e.e[d->dmrs_nscid].i);
|
||||
printf("nb_antennas_tx %d, number_of_bits %d, data size %d\n",
|
||||
e.e[d->nb_antennas_tx].i, e.e[d->number_of_bits].i,
|
||||
e.e[d->data].bsize);
|
||||
}
|
||||
|
||||
// Write metadata fields to shared memory using field descriptor table.
|
||||
// Writes msg_id first, then loops through all fields.
|
||||
void write_metadata_to_shm(char *addr_wr, unsigned int *bufIdx_wr, event e,
|
||||
const field_descriptor *fields, int n_fields)
|
||||
{
|
||||
// Write message ID
|
||||
memcpy(&addr_wr[*bufIdx_wr], &e.type, sizeof(uint16_t));
|
||||
*bufIdx_wr += sizeof(uint16_t);
|
||||
// Write all metadata fields
|
||||
for (int i = 0; i < n_fields; i++) {
|
||||
if (fields[i].field_idx == FIELD_SENDING_TIME_SEC) {
|
||||
uint32_t ts_sec = (uint32_t)e.sending_time.tv_sec;
|
||||
memcpy(&addr_wr[*bufIdx_wr], &ts_sec, fields[i].wire_size);
|
||||
} else if (fields[i].field_idx == FIELD_SENDING_TIME_NSEC) {
|
||||
uint32_t ts_nsec = (uint32_t)e.sending_time.tv_nsec;
|
||||
memcpy(&addr_wr[*bufIdx_wr], &ts_nsec, fields[i].wire_size);
|
||||
} else {
|
||||
memcpy(&addr_wr[*bufIdx_wr], &e.e[fields[i].field_idx].i, fields[i].wire_size);
|
||||
}
|
||||
*bufIdx_wr += fields[i].wire_size;
|
||||
}
|
||||
return 0; // Value not found
|
||||
}
|
||||
|
||||
void reestablish_connection(int *socket, char *ip, int port, int number_of_events, int *is_on)
|
||||
@@ -388,40 +389,24 @@ int main(int n, char **v)
|
||||
// trace_msgs_support_data_Collection_format
|
||||
// it is used to parse the requested messages if it is based
|
||||
// on Data Collection Trace Messages Structure and supported tracer messages indices
|
||||
char *traces_iq_support_data_Collection_format[] = {"GNB_PHY_UL_FD_PUSCH_IQ",
|
||||
"GNB_PHY_UL_FD_DMRS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_POS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL"};
|
||||
char *traces_bits_support_data_Collection_format[] = {"GNB_PHY_UL_PAYLOAD_RX_BITS",
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS",
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS"};
|
||||
// extra number of records to simlify Sync between base station and UE synchronization records.
|
||||
char *traces_ul_support_data_Collection_format[] = {"GNB_PHY_UL_FD_PUSCH_IQ",
|
||||
"GNB_PHY_UL_FD_DMRS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_POS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL",
|
||||
"GNB_PHY_UL_PAYLOAD_RX_BITS",
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS",
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS"};
|
||||
// extra number of records to simplify sync between base station and UE synchronization records.
|
||||
// if you have network delay, you can increase the number of records to capture
|
||||
int max_sync_offset = 6; // 6 frames ~ 60 ms
|
||||
// all supported messages
|
||||
// Calculate the size of the combined array
|
||||
int n_iq_msgs = sizeof(traces_iq_support_data_Collection_format) / sizeof(traces_iq_support_data_Collection_format[0]);
|
||||
int n_bits_msgs = sizeof(traces_bits_support_data_Collection_format) / sizeof(traces_bits_support_data_Collection_format[0]);
|
||||
int n_msgs_based_data_Collection_format = n_iq_msgs + n_bits_msgs;
|
||||
|
||||
// Create the combined array
|
||||
char *traces_support_data_Collection_format[n_msgs_based_data_Collection_format];
|
||||
// Copy IQ messages to the combined array
|
||||
for (int i = 0; i < n_iq_msgs; i++) {
|
||||
traces_support_data_Collection_format[i] = traces_iq_support_data_Collection_format[i];
|
||||
}
|
||||
|
||||
// Copy Bits messages to the combined array
|
||||
for (int i = 0; i < n_bits_msgs; i++) {
|
||||
traces_support_data_Collection_format[i + n_iq_msgs] = traces_bits_support_data_Collection_format[i];
|
||||
}
|
||||
// Calculate the size of the UL message array
|
||||
int n_ul_msgs = sizeof(traces_ul_support_data_Collection_format) / sizeof(traces_ul_support_data_Collection_format[0]);
|
||||
|
||||
uint16_t msg_id = 0;
|
||||
uint16_t start_frame_number = 0;
|
||||
uint32_t number_records = 0; // number of records to capture, it is number of slots
|
||||
// array to store the requested tracer messages indices
|
||||
int req_tracer_msgs_indices[100] = {0};
|
||||
// define variables --> to do: add all of them to be class of pointers
|
||||
char *database_filename = NULL;
|
||||
void *database;
|
||||
char *ip = DEFAULT_REMOTE_IP;
|
||||
@@ -434,18 +419,19 @@ int main(int n, char **v)
|
||||
char trace_time_stamp_str[30];
|
||||
|
||||
// data structure for the trace messages based on Data Collection Trace Messages Structure
|
||||
event_trace_msg_data trace_msg_data;
|
||||
event_trace_msg_ul_data trace_msg_ul_data;
|
||||
|
||||
// initlization variables
|
||||
// initialization variables
|
||||
unsigned int bufIdx_wr = 0;
|
||||
unsigned int bufIdx_rd = 0;
|
||||
uint8_t num_req_tracer_msgs = 0;
|
||||
|
||||
// initilaze shared memory
|
||||
// initialize shared memory
|
||||
char *addr_wr, *addr_rd;
|
||||
printf("\n Data Collection Service: Initializing shared memory ...");
|
||||
printf("\n Directory 1: %s, Directory 2: %s", GETKEYDIR1_UE, GETKEYDIR2_UE);
|
||||
printf("\n Project ID: %d\n", PROJECTID_UE);
|
||||
PRINT_STATE_BANNER("INIT");
|
||||
printf(" Data Collection Service: Initializing shared memory ...\n");
|
||||
printf(" Directory 1: %s, Directory 2: %s\n", GETKEYDIR1_UE, GETKEYDIR2_UE);
|
||||
printf(" Project ID: %d\n", PROJECTID_UE);
|
||||
int shm_id_wr = create_shm(&addr_wr, GETKEYDIR1_UE, PROJECTID_UE);
|
||||
int shm_id_rd = create_shm(&addr_rd, GETKEYDIR2_UE, PROJECTID_UE);
|
||||
del_shm(addr_wr, shm_id_wr);
|
||||
@@ -502,20 +488,18 @@ int main(int n, char **v)
|
||||
addr_rd[0] = 0; // important to check if we have new requested messages
|
||||
|
||||
// read requested tracer msg indices from memory
|
||||
printf("\n Data Collection Service: Waiting for messages request ...\n");
|
||||
// 0: Wait
|
||||
// 1: config
|
||||
// 2: record
|
||||
// 3: stop
|
||||
PRINT_STATE_BANNER("WAIT");
|
||||
printf(" Data Collection Service: Waiting for config message ...\n");
|
||||
// Wait for Action Config
|
||||
while (1) {
|
||||
if ((uint8_t)(addr_rd[0]) == 0) {
|
||||
if ((uint8_t)(addr_rd[0]) == STATE_WAIT) {
|
||||
usleep(50); // sleep for 50 us: 0.5 ms slot duration
|
||||
}
|
||||
// config state
|
||||
else if ((uint8_t)(addr_rd[0]) == 1) {
|
||||
else if ((uint8_t)(addr_rd[0]) == STATE_CONFIG) {
|
||||
get_time_stamp_usec(trace_time_stamp_str);
|
||||
printf("\n Received config message. Time Stamp: %s", trace_time_stamp_str);
|
||||
PRINT_STATE_BANNER("CONFIG");
|
||||
printf(" Received config message. Time Stamp: %s\n", trace_time_stamp_str);
|
||||
|
||||
// get the IP address length in bytes
|
||||
bufIdx_rd = 1;
|
||||
@@ -532,11 +516,11 @@ int main(int n, char **v)
|
||||
|
||||
// get the array bytes of the port number : 2 bytes
|
||||
uint8_t port_number_bytes[2] = {addr_rd[bufIdx_rd], addr_rd[bufIdx_rd + 1]};
|
||||
bufIdx_rd += 2; // + 2 bytes = start frame number
|
||||
bufIdx_rd += 2; // + 2 bytes = port number
|
||||
|
||||
port = combine_bytes(port_number_bytes, 2);
|
||||
printf("\n Parameters: IP Address length: %d, IP Address: %s, Port Number: %d \n", ip_address_length, ip_address, port);
|
||||
addr_rd[0] = 0; // reset memory : to wait for record action
|
||||
printf(" Parameters: IP Address length: %d, IP Address: %s, Port Number: %d\n", ip_address_length, ip_address, port);
|
||||
addr_rd[0] = STATE_WAIT; // reset memory : to wait for record action
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -547,37 +531,39 @@ int main(int n, char **v)
|
||||
|
||||
/* connect to the nr-softmodem */
|
||||
socket = connect_to(ip, port);
|
||||
printf("\n Connected to nr-UEsoftmodem");
|
||||
printf(" Connected to nr-uesoftmodem\n");
|
||||
|
||||
// Read Action record or stop
|
||||
printf("\n Data Collection Service: Waiting for record message ...\n");
|
||||
PRINT_STATE_BANNER("WAIT");
|
||||
printf(" Data Collection Service: Waiting for record/stop message ...\n");
|
||||
while (1) {
|
||||
// wait for Action record
|
||||
if ((uint8_t)(addr_rd[0]) == 0) {
|
||||
if ((uint8_t)(addr_rd[0]) == STATE_WAIT) {
|
||||
usleep(50); // sleep for 50 us: 0.5 ms slot duration
|
||||
}
|
||||
|
||||
// quit state
|
||||
else if ((uint8_t)(addr_rd[0]) == 3) {
|
||||
printf("\n Received 'stop' command. Exiting...");
|
||||
printf("\n ");
|
||||
else if ((uint8_t)(addr_rd[0]) == STATE_STOP) {
|
||||
PRINT_STATE_BANNER("STOP");
|
||||
printf(" Received 'stop' command. Exiting...\n");
|
||||
// Clean up and exit
|
||||
break;
|
||||
}
|
||||
// record state
|
||||
else if ((uint8_t)(addr_rd[0]) == 2) {
|
||||
else if ((uint8_t)(addr_rd[0]) == STATE_RECORD) {
|
||||
// clear remote buffer if there is
|
||||
clear_remote_config();
|
||||
get_time_stamp_usec(trace_time_stamp_str);
|
||||
printf("\n Received record message. Time Stamp: %s", trace_time_stamp_str);
|
||||
PRINT_STATE_BANNER("RECORD");
|
||||
printf(" Received record message. Time Stamp: %s\n", trace_time_stamp_str);
|
||||
|
||||
// read number of requested messages
|
||||
bufIdx_rd = 1;
|
||||
num_req_tracer_msgs = addr_rd[bufIdx_rd];
|
||||
bufIdx_rd += 1;
|
||||
printf("\n Number of requested tracer messages: %d,", num_req_tracer_msgs);
|
||||
printf(" Number of requested tracer messages: %d\n", num_req_tracer_msgs);
|
||||
// reset memory : action to wait for next record action
|
||||
addr_rd[0] = 0;
|
||||
addr_rd[0] = STATE_WAIT;
|
||||
|
||||
// read tracer msg IDs - every message ID has been stored in two bytes
|
||||
for (uint8_t msg_n = 0; msg_n < num_req_tracer_msgs; msg_n++) {
|
||||
@@ -609,40 +595,36 @@ int main(int n, char **v)
|
||||
printf("start_frame: %d\n", start_frame_number);
|
||||
|
||||
/* activate the trace in this array */
|
||||
printf("\n Activate Tracer messages in on_off array: \n");
|
||||
printf(" Activating tracer messages:\n");
|
||||
for (i = 0; i < num_req_tracer_msgs; i++) {
|
||||
char *on_off_name = event_name_from_id(database, req_tracer_msgs_indices[i]);
|
||||
on_off(database, on_off_name, is_on, 1);
|
||||
printf("%d, %s, ", req_tracer_msgs_indices[i], on_off_name);
|
||||
// on_off(database, "GNB_PHY_DL_OUTPUT_SIGNAL", is_on, 1);
|
||||
printf(" %d: %s\n", req_tracer_msgs_indices[i], on_off_name);
|
||||
}
|
||||
|
||||
// get the event IDs for the bit messages
|
||||
int traces_bits_support_data_Collection_format_idx[n_bits_msgs];
|
||||
for (int i = 0; i < n_bits_msgs; i++) {
|
||||
traces_bits_support_data_Collection_format_idx[i] =
|
||||
event_id_from_name(database, traces_bits_support_data_Collection_format[i]);
|
||||
}
|
||||
|
||||
// all supported messages
|
||||
int traces_support_data_Collection_format_idx[n_msgs_based_data_Collection_format];
|
||||
for (int i = 0; i < n_msgs_based_data_Collection_format; i++) {
|
||||
traces_support_data_Collection_format_idx[i] = event_id_from_name(database, traces_support_data_Collection_format[i]);
|
||||
// Build UL message ID array for generic UL dispatch
|
||||
int ul_msg_ids[n_ul_msgs];
|
||||
for (int i = 0; i < n_ul_msgs; i++) {
|
||||
ul_msg_ids[i] = event_id_from_name(database, traces_ul_support_data_Collection_format[i]);
|
||||
}
|
||||
|
||||
// setup data for the trace messages
|
||||
setup_trace_msg_data(&trace_msg_data, database);
|
||||
printf("\n Setup Trace Data Done");
|
||||
setup_trace_msg_ul_data(&trace_msg_ul_data, database);
|
||||
printf(" Setup UL trace data done\n");
|
||||
|
||||
// Build field descriptor table for table-driven shared memory writes
|
||||
field_descriptor ul_fields[N_UL_METADATA_FIELDS];
|
||||
build_ul_field_descriptors(ul_fields, &trace_msg_ul_data);
|
||||
|
||||
// Get the start time
|
||||
struct timespec start_time = get_current_time();
|
||||
|
||||
/* activate the tracee in the nr-softmodem */
|
||||
/* activate the traces in the nr-uesoftmodem */
|
||||
activate_traces(socket, number_of_events, is_on);
|
||||
printf("\n Activated Traces in nr-UEsoftmodem");
|
||||
printf(" Activated traces in nr-uesoftmodem\n");
|
||||
|
||||
/* a buffer needed to receive events from the nr-softmodem */
|
||||
OBUF ebuf = {osize : 0, omaxsize : 0, obuf : NULL};
|
||||
OBUF ebuf = {.osize = 0, .omaxsize = 0, .obuf = NULL};
|
||||
/* read events */
|
||||
int nrecord_idx = 0;
|
||||
bufIdx_wr = 0;
|
||||
@@ -656,8 +638,8 @@ int main(int n, char **v)
|
||||
int current_frame = 0, prev_frame = 0, current_slot = 0, prev_slot = 0;
|
||||
// offset to sync between base station and UE synchronization records or power measurements
|
||||
int sync_offset_index = 0; // increase the index only if the index of frame changes after getting all records
|
||||
// since we will use the frame differece to do extra records, we should be sure that the last slot is recorded completely
|
||||
printf("\n\n Data Collection Service: Start reading messages ...");
|
||||
// since we will use the frame difference to do extra records, we should be sure that the last slot is recorded completely
|
||||
printf("\n Data Collection Service: Start reading messages ...\n");
|
||||
struct pollfd event_poll_fd;
|
||||
event_poll_fd.fd = socket;
|
||||
event_poll_fd.events = POLLIN;
|
||||
@@ -677,27 +659,23 @@ int main(int n, char **v)
|
||||
continue; // Skip further processing and retry
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
// GNB_PHY_UL_FD_PUSCH_IQ, GNB_PHY_UL_FD_DMRS_ID, GNB_PHY_UL_FD_CHAN_EST_DMRS_POS,
|
||||
// UE_PHY_UL_SCRAMBLED_TX_BITS, GNB_PHY_UL_PAYLOAD_RX_BITS, UE_PHY_UL_PAYLOAD_TX_BITS
|
||||
//-------------------------
|
||||
// is it a requested message
|
||||
if (isValueInArray(e.type, req_tracer_msgs_indices, num_req_tracer_msgs)) {
|
||||
if (is_message_in_list(req_tracer_msgs_indices, num_req_tracer_msgs, e.type)) {
|
||||
// is it based on Data Collection Trace Messages Structure
|
||||
if (isValueInArray(e.type, traces_support_data_Collection_format_idx, n_msgs_based_data_Collection_format)) {
|
||||
if (is_message_in_list(ul_msg_ids, n_ul_msgs, e.type)) {
|
||||
// Start recording from the next slot to mitigate capturing partial data
|
||||
// check if the current frame and slot are different from the previous frame and slot
|
||||
// Then, increase the record index
|
||||
if (start_recording == false) {
|
||||
if (got_ref_frame_slot == false) {
|
||||
ref_frame = e.e[trace_msg_data.frame].i;
|
||||
ref_slot = e.e[trace_msg_data.slot].i;
|
||||
ref_frame = e.e[trace_msg_ul_data.frame].i;
|
||||
ref_slot = e.e[trace_msg_ul_data.slot].i;
|
||||
printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type);
|
||||
got_ref_frame_slot = true;
|
||||
}
|
||||
|
||||
current_frame = e.e[trace_msg_data.frame].i;
|
||||
current_slot = e.e[trace_msg_data.slot].i;
|
||||
current_frame = e.e[trace_msg_ul_data.frame].i;
|
||||
current_slot = e.e[trace_msg_ul_data.slot].i;
|
||||
frame_difference = (current_frame - ref_frame + MAX_FRAME_INDEX + 1) % (MAX_FRAME_INDEX + 1);
|
||||
slot_difference = (current_slot - ref_slot + MAX_SLOT_INDEX + 1) % (MAX_SLOT_INDEX + 1);
|
||||
printf("\n First frame.slot: %d.%d, current frame.slot: %d.%d, diff frame.slot: %d.%d",
|
||||
@@ -710,130 +688,30 @@ int main(int n, char **v)
|
||||
|
||||
if ((ref_frame != current_frame) || (ref_slot != current_slot)) {
|
||||
start_recording = true;
|
||||
printf("\n Start recording from frame: %d, slot: %d ", e.e[trace_msg_data.frame].i, e.e[trace_msg_data.slot].i);
|
||||
printf("\n Start recording from frame: %d, slot: %d ", e.e[trace_msg_ul_data.frame].i, e.e[trace_msg_ul_data.slot].i);
|
||||
}
|
||||
}
|
||||
// start recording from the next frame to mitigate capturing partial data
|
||||
if (start_recording == true) {
|
||||
/* this is how to access the elements of the Data Collection trace messages.
|
||||
* we use e.e[<element>] and then the correct suffix, here
|
||||
* it's .i for the integer and .b for the buffer and .bsize for the buffer size
|
||||
* see in event.h the structure event_arg
|
||||
*/
|
||||
unsigned char *buf = e.e[trace_msg_data.data].b;
|
||||
|
||||
printf("\n\nRecord number: %d", nrecord_idx);
|
||||
#ifdef DEBUG_BUFFER
|
||||
printf("\nBuffer index in bytes: %d", bufIdx_wr);
|
||||
#endif
|
||||
|
||||
// add general message header: message ID,
|
||||
// T-Tracer Message format
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols :
|
||||
// int,dmrs_port : int,dmrs_nscid :
|
||||
// int,nb_antennas_tx : int,number_of_bits : buffer,data
|
||||
// printf("\nTX : %d", e.e[trace_msg_data.nb_antennas_tx].i);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.type, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.frame].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.slot].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.datetime_yyyymmdd].i, sizeof(uint32_t));
|
||||
// --- UL IQ/Bits handler ---
|
||||
// Write metadata + buffer to shared memory
|
||||
write_metadata_to_shm(addr_wr, &bufIdx_wr, e, ul_fields, N_UL_METADATA_FIELDS);
|
||||
// Write buffer: size (uint32_t) + raw data
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_ul_data.data].bsize, sizeof(uint32_t));
|
||||
bufIdx_wr += sizeof(uint32_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.datetime_hhmmssmmm].i, sizeof(uint32_t));
|
||||
bufIdx_wr += sizeof(uint32_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.frame_type].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.freq_range].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.subcarrier_spacing].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.cyclic_prefix].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.symbols_per_slot].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.Nid_cell].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rnti].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rb_size].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.rb_start].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.start_symbol_index].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nr_of_symbols].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.qam_mod_order].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.mcs_index].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.mcs_table].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nrOfLayers].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.transform_precoding].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_config_type].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.ul_dmrs_symb_pos].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.number_dmrs_symbols].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_port].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.dmrs_nscid].i, sizeof(uint16_t));
|
||||
bufIdx_wr += sizeof(uint16_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.nb_antennas_tx].i, sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.number_of_bits].i, sizeof(uint32_t));
|
||||
bufIdx_wr += sizeof(uint32_t);
|
||||
|
||||
printf("\nTime Stamp: %d_%d", e.e[trace_msg_data.datetime_yyyymmdd].i, e.e[trace_msg_data.datetime_hhmmssmmm].i);
|
||||
|
||||
// add message body: length in bytes + recorded data
|
||||
memcpy(&addr_wr[bufIdx_wr], &e.e[trace_msg_data.data].bsize, sizeof(uint32_t));
|
||||
bufIdx_wr += sizeof(uint32_t);
|
||||
|
||||
// read data from buffer and convert from unsigned char * array to int 16 using the right endianness
|
||||
// T-tracer: Little Endian
|
||||
// For BITS Messages, example: UE_PHY_UL_SCRAMBLED_TX_BITS: data in bytes
|
||||
|
||||
if (is_bits_messages(traces_bits_support_data_Collection_format_idx, n_bits_msgs, e.type)) {
|
||||
for (int byte_idx = 0; byte_idx < e.e[trace_msg_data.data].bsize; byte_idx += 1) {
|
||||
// printf("%d, ", buf[byte_idx]);
|
||||
memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx], sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int byte_idx = 0; byte_idx < e.e[trace_msg_data.data].bsize; byte_idx += 2) {
|
||||
// For a little-endian system:
|
||||
memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx], sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
memcpy(&addr_wr[bufIdx_wr], &buf[byte_idx + 1], sizeof(uint8_t));
|
||||
bufIdx_wr += sizeof(uint8_t);
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (int byte_idx_i = 0; byte_idx_i < e.e[d.nr_ul_fd_dmrs_data].bsize; byte_idx_i+=4) {
|
||||
int16_t I = buf[byte_idx_i] | (buf[byte_idx_i+1] << 8);
|
||||
int16_t Q = buf[byte_idx_i+2] | (buf[byte_idx_i+3] << 8);
|
||||
printf ("idx %d, ", byte_idx_i);
|
||||
printf ("\n%d", I);
|
||||
printf ("\n%d", Q);
|
||||
}
|
||||
*/
|
||||
memcpy(&addr_wr[bufIdx_wr], e.e[trace_msg_ul_data.data].b, e.e[trace_msg_ul_data.data].bsize);
|
||||
bufIdx_wr += e.e[trace_msg_ul_data.data].bsize;
|
||||
#ifdef DEBUG_T_Tracer
|
||||
print_ul_metadata_debug(e, &trace_msg_ul_data, database);
|
||||
#endif
|
||||
// check if the current frame and slot are different from the previous frame and slot
|
||||
// Then, increase the record index
|
||||
current_frame = e.e[trace_msg_data.frame].i;
|
||||
current_slot = e.e[trace_msg_data.slot].i;
|
||||
current_frame = e.e[trace_msg_ul_data.frame].i;
|
||||
current_slot = e.e[trace_msg_ul_data.slot].i;
|
||||
|
||||
// increase sync offset index if the current frame is different from the previous frame
|
||||
if ((current_frame != prev_frame) && nrecord_idx >= number_records) {
|
||||
@@ -846,43 +724,6 @@ int main(int n, char **v)
|
||||
prev_frame = current_frame;
|
||||
prev_slot = current_slot;
|
||||
}
|
||||
#ifdef DEBUG_T_Tracer
|
||||
printf("\nMessage Info: msg_id %s (%d) \n", event_name_from_id(database, e.type), e.type);
|
||||
printf("frame %d, slot %d, datetime %d_%d\n",
|
||||
e.e[trace_msg_data.frame].i,
|
||||
e.e[trace_msg_data.slot].i,
|
||||
e.e[trace_msg_data.datetime_yyyymmdd].i,
|
||||
e.e[trace_msg_data.datetime_hhmmssmmm].i);
|
||||
printf("frame_type %d, freq_range %d, subcarrier_spacing %d, cyclic_prefix %d, symbols_per_slot %d\n",
|
||||
e.e[trace_msg_data.frame_type].i,
|
||||
e.e[trace_msg_data.freq_range].i,
|
||||
e.e[trace_msg_data.subcarrier_spacing].i,
|
||||
e.e[trace_msg_data.cyclic_prefix].i,
|
||||
e.e[trace_msg_data.symbols_per_slot].i);
|
||||
printf("Nid_cell %d, rnti %d, rb_size %d, rb_start %d, start_symbol_index %d, nr_of_symbols %d\n",
|
||||
e.e[trace_msg_data.Nid_cell].i,
|
||||
e.e[trace_msg_data.rnti].i,
|
||||
e.e[trace_msg_data.rb_size].i,
|
||||
e.e[trace_msg_data.rb_start].i,
|
||||
e.e[trace_msg_data.start_symbol_index].i,
|
||||
e.e[trace_msg_data.nr_of_symbols].i);
|
||||
printf("qam_mod_order %d, mcs_index %d, mcs_table %d, nrOfLayers %d, transform_precoding %d\n",
|
||||
e.e[trace_msg_data.qam_mod_order].i,
|
||||
e.e[trace_msg_data.mcs_index].i,
|
||||
e.e[trace_msg_data.mcs_table].i,
|
||||
e.e[trace_msg_data.nrOfLayers].i,
|
||||
e.e[trace_msg_data.transform_precoding].i);
|
||||
printf("dmrs_config_type %d, ul_dmrs_symb_pos %d, number_dmrs_symbols %d, dmrs_port %d, dmrs_nscid %d\n",
|
||||
e.e[trace_msg_data.dmrs_config_type].i,
|
||||
e.e[trace_msg_data.ul_dmrs_symb_pos].i,
|
||||
e.e[trace_msg_data.number_dmrs_symbols].i,
|
||||
e.e[trace_msg_data.dmrs_port].i,
|
||||
e.e[trace_msg_data.dmrs_nscid].i);
|
||||
printf("nb_antennas_tx %d, number_of_bits %d, data size %d\n",
|
||||
e.e[trace_msg_data.nb_antennas_tx].i,
|
||||
e.e[trace_msg_data.number_of_bits].i,
|
||||
e.e[trace_msg_data.data].bsize);
|
||||
#endif
|
||||
} // End of start recording flag
|
||||
} // end of if statement for the supported messages based on Data Collection Trace Messages Structure
|
||||
else {
|
||||
@@ -893,28 +734,25 @@ int main(int n, char **v)
|
||||
} // end while loop of reading events
|
||||
else {
|
||||
// No data, just loop and check time
|
||||
usleep(100); // optional: avoid busy-waiting
|
||||
usleep(50); // optional: avoid busy-waiting
|
||||
}
|
||||
} // End of while loop to read messages
|
||||
|
||||
// de-activate the tracee in the nr-softmodem
|
||||
printf("\n De-activated Tracer message:\n");
|
||||
// de-activate the traces in the nr-uesoftmodem
|
||||
printf("\n De-activating tracer messages\n");
|
||||
for (i = 0; i < num_req_tracer_msgs; i++) {
|
||||
char *on_off_name = event_name_from_id(database, req_tracer_msgs_indices[i]);
|
||||
on_off(database, on_off_name, is_on, 0);
|
||||
// printf("\n %d, %s, ", req_tracer_msgs_indices[i], on_off_name);
|
||||
// on_off(database, "GNB_PHY_DL_OUTPUT_SIGNAL", is_on, 1);
|
||||
}
|
||||
// De-activate the tracee in the nr-softmodem
|
||||
activate_traces(socket, number_of_events, is_on);
|
||||
printf("\n De-activated Traces");
|
||||
printf(" De-activated traces\n");
|
||||
|
||||
// Get the end time
|
||||
struct timespec end_time = get_current_time();
|
||||
// Calculate the time difference
|
||||
double time_diff = calculate_time_difference(start_time, end_time);
|
||||
printf("Total Time difference: %.2f ms\n", time_diff);
|
||||
printf("Time difference per record: %.2f ms\n", time_diff / (number_records + max_sync_offset));
|
||||
printf(" Total time: %.2f ms\n", time_diff);
|
||||
printf(" Time per record: %.2f ms\n", time_diff / (number_records + max_sync_offset));
|
||||
|
||||
// discard stale or previous record data for the first DISCARD_RECORD_DURATION_MS
|
||||
struct timespec record_start, record_now;
|
||||
@@ -941,10 +779,9 @@ int main(int n, char **v)
|
||||
}
|
||||
} // End of while loop to discard stale records
|
||||
}
|
||||
} // End a while loop to check for the "stop" command
|
||||
// de-activate the tracee in the nr-softmodem
|
||||
} // End of while loop for record/stop
|
||||
|
||||
// free_database(database); //Do on one app, for example on gNB App
|
||||
// free_database(database); // Done on gNB App only
|
||||
free(is_on);
|
||||
close(socket);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#include "reverse_bits.h"
|
||||
#include "bits.h"
|
||||
// we avoid assertions.h as it necessitates othe dependencies (e.g., exit_function)
|
||||
#include <assert.h>
|
||||
#include <simde/x86/gfni.h>
|
||||
76
common/utils/bits.h
Normal file
76
common/utils/bits.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#ifndef BITS_H_
|
||||
#define BITS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "assertions.h"
|
||||
|
||||
uint64_t reverse_bits(uint64_t in, int n_bits);
|
||||
void reverse_bits_u8(uint8_t const* in, size_t sz, uint8_t* out);
|
||||
|
||||
static inline int get_last_bit_index(const uint32_t *arr, int sz)
|
||||
{
|
||||
AssertFatal(sz > 0, "Invalid size %d to get the first bit of array\n", sz);
|
||||
for (int i = sz - 1; i >= 0; i--) {
|
||||
if (arr[i] != 0) {
|
||||
// 31 - clz gives the index of the highest bit (0-31)
|
||||
return (i * 32) + (31 - __builtin_clz(arr[i]));
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static uint32_t bit_mask(int from_bit, int num_bits)
|
||||
{
|
||||
int total = from_bit + num_bits;
|
||||
uint32_t right_mask = total < 32 ? (0xFFFFFFFF >> (32 - total)) : 0xFFFFFFFF;
|
||||
return (0xFFFFFFFF << from_bit) & right_mask;
|
||||
}
|
||||
|
||||
static inline int get_first_bit_index_mask(const uint32_t *arr, int sz, int from_bit, int num_bits)
|
||||
{
|
||||
// start i from first_bit
|
||||
int i = from_bit / 32;
|
||||
from_bit %= 32;
|
||||
for (; i < sz && num_bits > 0; i++) {
|
||||
uint32_t a = arr[i] & bit_mask(from_bit, num_bits);
|
||||
if (a != 0) {
|
||||
// Find the first set bit in this 32-bit word
|
||||
return (i * 32) + __builtin_ctz(a);
|
||||
}
|
||||
num_bits -= 32 - from_bit;
|
||||
from_bit = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int get_first_bit_index(const uint32_t *arr, int sz)
|
||||
{
|
||||
return get_first_bit_index_mask(arr, sz, 0, sz * 32);
|
||||
}
|
||||
|
||||
static inline int count_bits(const uint32_t *arr, int sz)
|
||||
{
|
||||
int ret = 0;
|
||||
// sz is the number of uint32_t elements
|
||||
for (int i = 0; i < sz; i++)
|
||||
ret += __builtin_popcount(arr[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __attribute__((always_inline)) inline int count_bits64(uint64_t v)
|
||||
{
|
||||
return __builtin_popcountll(v);
|
||||
}
|
||||
|
||||
static __attribute__((always_inline)) inline int count_bits64_with_mask(uint64_t v, int start, int num)
|
||||
{
|
||||
uint64_t mask = ((1LL << num) - 1) << start;
|
||||
return count_bits64(v & mask);
|
||||
}
|
||||
#endif /* BITS_H_ */
|
||||
@@ -42,43 +42,59 @@
|
||||
"t_tracer_message_definition_file": "../T/T_messages.txt",
|
||||
"parameter_map_file": "config/wireless_link_parameter_map.yaml",
|
||||
"start_frame_number": 5,
|
||||
"base_station": {
|
||||
"requested_tracer_messages": [
|
||||
"GNB_PHY_UL_FD_PUSCH_IQ",
|
||||
"GNB_PHY_UL_FD_DMRS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_POS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL",
|
||||
"GNB_PHY_UL_PAYLOAD_RX_BITS"
|
||||
],
|
||||
"meta_data":{
|
||||
"num_rx_antennas": 1,
|
||||
"tx_gain": 48.0,
|
||||
"rx_gain": 30.0,
|
||||
"hw_type": "USRP X410",
|
||||
"hw_subtype": "ZBX",
|
||||
"seid": "328AB35"
|
||||
}
|
||||
},
|
||||
"user_equipment": {
|
||||
"requested_tracer_messages": [
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS",
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS"
|
||||
],
|
||||
"meta_data":{
|
||||
"num_tx_antennas": 1,
|
||||
"tx_gain": 48.0,
|
||||
"rx_gain": 40.0,
|
||||
"hw_type": "USRP X410",
|
||||
"hw_subtype": "ZBX",
|
||||
"seid": "323F75F"
|
||||
}
|
||||
},
|
||||
"common_meta_data": {
|
||||
"sample_rate": 61440000.0,
|
||||
"bandwidth": 40000000.0,
|
||||
"clock_reference": "external"
|
||||
},
|
||||
"tracer_service_baseStation_address": "127.0.0.1:2021",
|
||||
"tracer_service_userEquipment_address": "127.0.0.1:2023"
|
||||
"nodes": [
|
||||
{
|
||||
"id": "gnb_0",
|
||||
"type": "gnb",
|
||||
"requested_tracer_messages": [
|
||||
"GNB_PHY_UL_FD_PUSCH_IQ",
|
||||
"GNB_PHY_UL_FD_DMRS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_POS",
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL",
|
||||
"GNB_PHY_UL_PAYLOAD_RX_BITS"],
|
||||
"tracer_service_address": "127.0.0.1:2021",
|
||||
"meta_data": {
|
||||
"num_tx_antennas": 1,
|
||||
"num_rx_antennas": 1,
|
||||
"tx_gain": 48.0,
|
||||
"rx_gain": 30.0,
|
||||
"hw_type": "USRP X410",
|
||||
"hw_subtype": "ZBX",
|
||||
"seid": "328AB35"
|
||||
},
|
||||
"shared_mem_config": {
|
||||
"read_path": "/tmp/gnb_app1",
|
||||
"write_path": "/tmp/gnb_app2",
|
||||
"project_id": 2335
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ue_0",
|
||||
"type": "ue",
|
||||
"requested_tracer_messages": [
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS",
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS"],
|
||||
"tracer_service_address": "127.0.0.1:2023",
|
||||
"meta_data": {
|
||||
"num_tx_antennas": 1,
|
||||
"num_rx_antennas": 1,
|
||||
"tx_gain": 48.0,
|
||||
"rx_gain": 30.0,
|
||||
"hw_type": "USRP X410",
|
||||
"hw_subtype": "ZBX",
|
||||
"seid": "323F75F"
|
||||
},
|
||||
"shared_mem_config": {
|
||||
"read_path": "/tmp/ue_app1",
|
||||
"write_path": "/tmp/ue_app2",
|
||||
"project_id": 2336
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,803 +0,0 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# brief main application of synchronized real-time data recording
|
||||
|
||||
import sysv_ipc as ipc
|
||||
import struct
|
||||
import time
|
||||
from datetime import datetime
|
||||
from termcolor import colored
|
||||
import numpy as np
|
||||
import json
|
||||
import concurrent.futures
|
||||
# from concurrent import futures
|
||||
import threading
|
||||
# import related functions
|
||||
from lib import sigmf_interface
|
||||
# import library functions
|
||||
from lib import sync_service
|
||||
from lib import data_recording_messages_def
|
||||
from lib import common_utils
|
||||
from lib import config_interface
|
||||
|
||||
DEBUG_WIRELESS_RECORDED_DATA = True
|
||||
DEBUG_BUFFER_READING = False
|
||||
|
||||
# globally applicable metadata
|
||||
global_info = {
|
||||
"author": "Abdo Gaber",
|
||||
"description": "Synchronized Real-Time Data Recording",
|
||||
"timestamp": 0,
|
||||
"collection_file_prefix": "data-collection", # collection file name prefix "deap-rx + str(...)"
|
||||
"collection_file": "", # Reserved to be created in the code: “data-collection_rec-0_TIME-STAMP”
|
||||
"datetime_offset": "", # datetime offset between current location and UTC/Zulu timezone
|
||||
# Example: "+01:00" for Berlin, Germany
|
||||
"save_config_data_recording_app_json": True,
|
||||
"waveform_generator": "5gnr_oai",
|
||||
"extensions": {},
|
||||
}
|
||||
|
||||
# Supported OAI Trace messages
|
||||
# UL receiver messages
|
||||
# gNB IQ Msgs: "GNB_PHY_UL_FD_PUSCH_IQ", "GNB_PHY_UL_FD_DMRS", "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS",
|
||||
# "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL"
|
||||
# gNB BITS Msgs: "GNB_PHY_UL_PAYLOAD_RX_BITS"
|
||||
# UE BITS Msgs: "UE_PHY_UL_SCRAMBLED_TX_BITS", "UE_PHY_UL_PAYLOAD_TX_BITS"
|
||||
|
||||
supported_oai_tracer_messages = {
|
||||
# gNB messages
|
||||
"GNB_PHY_UL_FD_PUSCH_IQ": {
|
||||
"file_name_prefix": "rx-fd-data",
|
||||
"scope": "gNB",
|
||||
"description": "Frequency-domain RX data",
|
||||
"serialization_scheme": ["subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"GNB_PHY_UL_FD_DMRS": {
|
||||
"file_name_prefix": "tx-pilots-fd-data",
|
||||
"scope": "gNB",
|
||||
"description": "Frequency-domain TX PUSCH DMRS data",
|
||||
"serialization_scheme": ["subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_POS": {
|
||||
"file_name_prefix": "raw-ce-fd-data",
|
||||
"scope": "gNB",
|
||||
"description": "Frequency-domain raw channel estimates (at DMRS positions)",
|
||||
"serialization_scheme": ["subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL": {
|
||||
"file_name_prefix": "raw-inter-ce-fd-data",
|
||||
"scope": "gNB",
|
||||
"description": "Interpolcated Frequency-domain raw channel estimates",
|
||||
"serialization_scheme": ["subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"GNB_PHY_UL_PAYLOAD_RX_BITS": {
|
||||
"file_name_prefix": "rx-payload-bits",
|
||||
"scope": "gNB",
|
||||
"description": "Received PUSCH payload bits",
|
||||
"serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
# UE messages
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS": {
|
||||
"file_name_prefix": "tx-scrambled-bits",
|
||||
"scope": "UE",
|
||||
"description": "Transmitted scrambled PUSCH bits",
|
||||
"serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS": {
|
||||
"file_name_prefix": "tx-payload-bits",
|
||||
"scope": "UE",
|
||||
"description": "Transmitted PUSCH payload bits",
|
||||
"serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
}
|
||||
# -------------------------------------------
|
||||
# System configuration: gNB
|
||||
project_id_gnb = 2335
|
||||
read_shm_path_gnb = "/tmp/gnb_app1"
|
||||
write_shm_path_gnb = "/tmp/gnb_app2"
|
||||
|
||||
# System configuration: UE
|
||||
project_id_ue = 2336
|
||||
read_shm_path_ue = "/tmp/ue_app1"
|
||||
write_shm_path_ue = "/tmp/ue_app2"
|
||||
|
||||
|
||||
# initialize shared memory
|
||||
def attach_shm(shm_path, project_id):
|
||||
key = ipc.ftok(shm_path, project_id)
|
||||
shm = ipc.SharedMemory(key, 0, 0)
|
||||
# I found if we do not attach ourselves
|
||||
# it will attach as ReadOnly.
|
||||
shm.attach(0, 0)
|
||||
return shm
|
||||
|
||||
|
||||
def detach_shm(shm):
|
||||
try:
|
||||
shm.detach()
|
||||
print("Shared memory detached successfully.")
|
||||
except ipc.ExistentialError:
|
||||
print("Shared memory segment does not exist.")
|
||||
|
||||
|
||||
def remove_shm(shm):
|
||||
try:
|
||||
shm.remove()
|
||||
print("Shared memory removed successfully.")
|
||||
except ipc.ExistentialError:
|
||||
print("Shared memory segment does not exist.")
|
||||
|
||||
|
||||
# check data if avalible in the shared memory
|
||||
def is_data_available_in_memory(shm, bufIdx, general_message_header_length, timeout=20):
|
||||
start_time = time.time()
|
||||
while True:
|
||||
buf = shm.read(bufIdx + general_message_header_length)
|
||||
n_bytes = sum(buf)
|
||||
print("Data Recording App: Waiting for Measurements!")
|
||||
if n_bytes > 0:
|
||||
print("There is data in memory, n_bytes: ", n_bytes)
|
||||
return True
|
||||
if (time.time() - start_time) > timeout:
|
||||
break
|
||||
time.sleep(1)
|
||||
return False
|
||||
|
||||
|
||||
# Read data from Shared memory based Data Conversion Service message structure
|
||||
def read_data_from_shm(shm, bufIdx, tracer_msgs_identities):
|
||||
# print buffer index
|
||||
if DEBUG_BUFFER_READING:
|
||||
print("Buffer Index: ", bufIdx)
|
||||
# get general message header list
|
||||
general_msg_header_list, general_message_header_length = data_recording_messages_def.get_general_msg_header_list()
|
||||
buf = shm.read(bufIdx + general_message_header_length)
|
||||
n_bytes = sum(buf)
|
||||
if n_bytes == 0:
|
||||
raise Exception('ERROR: No data available in memory')
|
||||
msg_id = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("msg_id")])[0]
|
||||
bufIdx += general_msg_header_list.get("msg_id")
|
||||
frame = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("frame")])[0]
|
||||
bufIdx += general_msg_header_list.get("frame")
|
||||
slot = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("slot")])[0]
|
||||
bufIdx += general_msg_header_list.get("slot")
|
||||
# get time stamp: yyyy mm dd hh mm ss msec
|
||||
nr_trace_time_stamp_yyymmdd = \
|
||||
struct.unpack('<i', buf[bufIdx:bufIdx+general_msg_header_list.get("datetime_yyyymmdd")])[0]
|
||||
bufIdx += general_msg_header_list.get("datetime_yyyymmdd")
|
||||
nr_trace_time_stamp_hhmmssmmm = \
|
||||
struct.unpack('<i', buf[bufIdx:bufIdx+general_msg_header_list.get("datetime_hhmmssmmm")])[0]
|
||||
bufIdx += general_msg_header_list.get("datetime_hhmmssmmm")
|
||||
time_stamp_milli_sec = str(nr_trace_time_stamp_yyymmdd)+"_"+str(nr_trace_time_stamp_hhmmssmmm)
|
||||
# get frame type
|
||||
frame_type = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("frame_type")])[0]
|
||||
bufIdx += general_msg_header_list.get("frame_type")
|
||||
# get frequency range
|
||||
freq_range = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("freq_range")])[0]
|
||||
bufIdx += general_msg_header_list.get("freq_range")
|
||||
# get subcarrier spacing
|
||||
subcarrier_spacing = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("subcarrier_spacing")])[0]
|
||||
bufIdx += general_msg_header_list.get("subcarrier_spacing")
|
||||
# get cyclic prefix
|
||||
cyclic_prefix = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("cyclic_prefix")])[0]
|
||||
bufIdx += general_msg_header_list.get("cyclic_prefix")
|
||||
# get symbols per slot
|
||||
symbols_per_slot = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("symbols_per_slot")])[0]
|
||||
bufIdx += general_msg_header_list.get("symbols_per_slot")
|
||||
# get Nid cell
|
||||
Nid_cell = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("Nid_cell")])[0]
|
||||
bufIdx += general_msg_header_list.get("Nid_cell")
|
||||
# get rnti
|
||||
rnti = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("rnti")])[0]
|
||||
bufIdx += general_msg_header_list.get("rnti")
|
||||
# get rb size
|
||||
rb_size = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("rb_size")])[0]
|
||||
bufIdx += general_msg_header_list.get("rb_size")
|
||||
# get rb start
|
||||
rb_start = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("rb_start")])[0]
|
||||
bufIdx += general_msg_header_list.get("rb_start")
|
||||
# get start symbol index
|
||||
start_symbol_index = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("start_symbol_index")])[0]
|
||||
bufIdx += general_msg_header_list.get("start_symbol_index")
|
||||
# get number of symbols
|
||||
nr_of_symbols = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("nr_of_symbols")])[0]
|
||||
bufIdx += general_msg_header_list.get("nr_of_symbols")
|
||||
# get qam modulation order
|
||||
qam_mod_order = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("qam_mod_order")])[0]
|
||||
bufIdx += general_msg_header_list.get("qam_mod_order")
|
||||
# get mcs index
|
||||
mcs_index = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("mcs_index")])[0]
|
||||
bufIdx += general_msg_header_list.get("mcs_index")
|
||||
# get mcs table
|
||||
mcs_table = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("mcs_table")])[0]
|
||||
bufIdx += general_msg_header_list.get("mcs_table")
|
||||
# get number of layers
|
||||
nrOfLayers = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("nrOfLayers")])[0]
|
||||
bufIdx += general_msg_header_list.get("nrOfLayers")
|
||||
# get transform precoding
|
||||
transform_precoding = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("transform_precoding")])[0]
|
||||
bufIdx += general_msg_header_list.get("transform_precoding")
|
||||
# get dmrs config type
|
||||
dmrs_config_type = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("dmrs_config_type")])[0]
|
||||
bufIdx += general_msg_header_list.get("dmrs_config_type")
|
||||
# get ul dmrs symb pos
|
||||
ul_dmrs_symb_pos = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("ul_dmrs_symb_pos")])[0]
|
||||
bufIdx += general_msg_header_list.get("ul_dmrs_symb_pos")
|
||||
# get number dmrs symbols
|
||||
number_dmrs_symbols = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("number_dmrs_symbols")])[0]
|
||||
bufIdx += general_msg_header_list.get("number_dmrs_symbols")
|
||||
# get dmrs port
|
||||
dmrs_port = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("dmrs_port")])[0]
|
||||
bufIdx += general_msg_header_list.get("dmrs_port")
|
||||
# get dmrs scid
|
||||
dmrs_scid = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("dmrs_scid")])[0]
|
||||
bufIdx += general_msg_header_list.get("dmrs_scid")
|
||||
# get nb antennas rx for gNB or nb antennas tx for UE
|
||||
nb_antennas = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("nb_antennas")])[0]
|
||||
bufIdx += general_msg_header_list.get("nb_antennas")
|
||||
# get number of bits
|
||||
number_of_bits = struct.unpack('<I', buf[bufIdx:bufIdx+general_msg_header_list.get("number_of_bits")])[0]
|
||||
bufIdx += general_msg_header_list.get("number_of_bits")
|
||||
# get length of bytes
|
||||
length_bytes = struct.unpack('<I', buf[bufIdx:bufIdx+general_msg_header_list.get("length_bytes")])[0]
|
||||
bufIdx += general_msg_header_list.get("length_bytes")
|
||||
|
||||
# print all captured data
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(" ")
|
||||
print(f"Time stamp: {time_stamp_milli_sec}")
|
||||
print(f"MSG ID: {msg_id:<5} MSG Name: {tracer_msgs_identities[msg_id]}")
|
||||
print(f"Frame: {frame:<5} Slot: {slot:<5}")
|
||||
print(f"Frame Type: {frame_type:<5} Frequency Range: {freq_range:<5}"
|
||||
f"Subcarrier Spacing: {subcarrier_spacing:<5} Cyclic Prefix: {cyclic_prefix:<5} "
|
||||
f"Symbols per Slot: {symbols_per_slot:<5}")
|
||||
print(f"Nid Cell: {Nid_cell:<5} RNTI: {rnti:<5}")
|
||||
print(f"RB Size: {rb_size:<5} RB Start: {rb_start:<5} Start Symbol Index: {start_symbol_index:<5} "
|
||||
f"Number of Symbols: {nr_of_symbols:<5}")
|
||||
print(f"QAM Modulation Order: {qam_mod_order:<5} MCS Index: {mcs_index:<5} "
|
||||
f"MCS Table: {mcs_table:<5}")
|
||||
print(f"Number of Layers: {nrOfLayers:<5} Transform Precoding: {transform_precoding:<5}")
|
||||
print(f"DMRS Config Type: {dmrs_config_type:<5} UL DMRS Symbol Position: {ul_dmrs_symb_pos:<5} "
|
||||
f"Number of DMRS Symbols: {number_dmrs_symbols:<5}")
|
||||
print(f"DMRS Port: {dmrs_port:<5} DMRS SCID: {dmrs_scid:<5} "
|
||||
f"Number of Antennas: {nb_antennas:<5}")
|
||||
print(f"Number of bits: {number_of_bits:<5} Length of bytes: {length_bytes:<5}")
|
||||
# raise exception if time stamp is zero, it means that the data is not recorded yet
|
||||
if nr_trace_time_stamp_yyymmdd == 0 and nr_trace_time_stamp_hhmmssmmm == 0:
|
||||
raise Exception("ERROR: Time stamp is zero, data is not recorded yet or something wrong, check logs!")
|
||||
# get recorded data
|
||||
buf = shm.read(bufIdx + length_bytes)
|
||||
# bit_msg_index = get_index_of_id(tracer_msgs_identities, "GNB_PHY_UL_PAYLOAD_RX_BITS")
|
||||
captured_data = {}
|
||||
# If message is bit message, store data in bytes
|
||||
# then the field number_of_bits should be not zero
|
||||
if "_BITS" in tracer_msgs_identities[msg_id]:
|
||||
# recorded_data = buf[bufIdx:bufIdx + length_bytes]
|
||||
recorded_data = struct.unpack("<" + int(length_bytes) * 'B', buf[bufIdx:bufIdx + length_bytes])
|
||||
bufIdx += length_bytes
|
||||
# convert data in bytes to bits
|
||||
bits_vector = []
|
||||
for byte in recorded_data:
|
||||
bits_vector.extend([int(bit) for bit in format(int(byte), '08b')])
|
||||
captured_data["sigmf_data_type"] = "ri8_le"
|
||||
# convert to uint8
|
||||
captured_data["recorded_data"] = np.asarray(bits_vector).astype(np.uint8)
|
||||
# recorded_data_formated = recorded_data.astype(np.complex64) # convert to complex64
|
||||
else:
|
||||
recorded_data = struct.unpack("<" + int(length_bytes/2) * 'h', buf[bufIdx:bufIdx + length_bytes])
|
||||
bufIdx += length_bytes
|
||||
# print("IQ data I/Q: ", recorded_data)
|
||||
# Convert real data to complext data
|
||||
# converting list to array
|
||||
recorded_data = np.asarray(recorded_data)
|
||||
# recorded_data_complex = recorded_data
|
||||
recorded_data_complex = common_utils.real_to_complex(recorded_data)
|
||||
captured_data["sigmf_data_type"] = "cf32_le"
|
||||
# convert to complex64
|
||||
captured_data["recorded_data"] = recorded_data_complex.astype(np.complex64)
|
||||
# print("Recorded Data: ", captured_data["recorded_data"])
|
||||
# store data in dictonary
|
||||
captured_data["message_id"] = msg_id
|
||||
captured_data["message_type"] = tracer_msgs_identities[msg_id]
|
||||
captured_data["frame"] = frame
|
||||
captured_data["slot"] = slot
|
||||
captured_data["time_stamp"] = time_stamp_milli_sec
|
||||
captured_data["frame_type"] = frame_type
|
||||
captured_data["freq_range"] = freq_range
|
||||
captured_data["subcarrier_spacing"] = subcarrier_spacing
|
||||
captured_data["cyclic_prefix"] = cyclic_prefix
|
||||
# captured_data["symbols_per_slot"] = symbols_per_slot ... not used
|
||||
captured_data["Nid_cell"] = Nid_cell
|
||||
captured_data["rnti"] = rnti
|
||||
captured_data["rb_size"] = rb_size
|
||||
captured_data["rb_start"] = rb_start
|
||||
captured_data["start_symbol_index"] = start_symbol_index
|
||||
captured_data["nr_of_symbols"] = nr_of_symbols
|
||||
captured_data["qam_mod_order"] = qam_mod_order
|
||||
captured_data["mcs_index"] = mcs_index
|
||||
captured_data["mcs_table"] = mcs_table
|
||||
captured_data["nrOfLayers"] = nrOfLayers
|
||||
captured_data["transform_precoding"] = transform_precoding
|
||||
captured_data["dmrs_config_type"] = dmrs_config_type
|
||||
captured_data["ul_dmrs_symb_pos"] = ul_dmrs_symb_pos
|
||||
captured_data["number_dmrs_symbols"] = number_dmrs_symbols
|
||||
captured_data["dmrs_port"] = dmrs_port
|
||||
captured_data["dmrs_scid"] = dmrs_scid
|
||||
captured_data["nb_antennas"] = nb_antennas
|
||||
captured_data["number_of_bits"] = number_of_bits
|
||||
return captured_data, bufIdx
|
||||
|
||||
|
||||
# Synchronize data between gNB and UE
|
||||
def sync_data_conversion_service(
|
||||
shm_reading_gnb, shm_reading_ue, sync_info, config_meta_data, gnb_args, ue_args):
|
||||
# Initialize variables
|
||||
record_idx = 0
|
||||
prev_frame = -1
|
||||
prev_slot = -1
|
||||
ue_bufIdx = 0
|
||||
gnb_bufIdx = 0
|
||||
|
||||
gnb_args.num_requested_tracer_msgs = len(
|
||||
config_meta_data["data_recording_config"]["base_station"][
|
||||
"requested_tracer_messages"])
|
||||
ue_args.num_requested_tracer_msgs = len(
|
||||
config_meta_data["data_recording_config"]["user_equipment"][
|
||||
"requested_tracer_messages"])
|
||||
tracer_msgs_identities = config_meta_data["data_recording_config"][
|
||||
"tracer_msgs_identities"]
|
||||
|
||||
global_info = config_meta_data["data_recording_config"]["global_info"]
|
||||
|
||||
# Get UE data based on the sync data
|
||||
bufIdx = 0
|
||||
timeout_sync = time.time() + 5 # 5 seconds if no sync data found, stop the process
|
||||
while True:
|
||||
# wait for the next record
|
||||
# To do: check if we need to add exta waiting times between different events in case of
|
||||
# data streaming via network such as on UE side or gNB side
|
||||
time.sleep(0.0035) # 2.3 ms = latency of T tracer to capture data from the RAN
|
||||
ue_bufIdx = bufIdx
|
||||
captured_data, bufIdx = read_data_from_shm(shm_reading_ue, bufIdx, tracer_msgs_identities)
|
||||
if (captured_data["frame"] == sync_info["frame"]
|
||||
and captured_data["slot"] == sync_info["slot"]):
|
||||
break
|
||||
if time.time() > timeout_sync:
|
||||
raise Exception(
|
||||
"ERROR: Data Recording NO Sync Found, check Tracer Services if they are connected!")
|
||||
|
||||
# Get gNB data based on the sync data
|
||||
bufIdx = 0
|
||||
while True:
|
||||
time.sleep(0.0035)
|
||||
gnb_bufIdx = bufIdx
|
||||
captured_data, bufIdx = read_data_from_shm(
|
||||
shm_reading_gnb, bufIdx, tracer_msgs_identities)
|
||||
if (captured_data["frame"] == sync_info["frame"]
|
||||
and captured_data["slot"] == sync_info["slot"]):
|
||||
break
|
||||
|
||||
# Read Synchronized data between gNB and UE
|
||||
while True: # read all records
|
||||
print("\nRecord number: ", record_idx)
|
||||
if DEBUG_BUFFER_READING:
|
||||
print(f"Buffer Index gNB: {gnb_bufIdx}, Buffer Index UE: {ue_bufIdx}")
|
||||
# wait for the next record
|
||||
# To do: check if we need to add exta waiting times between different events in case of
|
||||
# data streaming via network such as on UE side or gNB side
|
||||
time.sleep(0.0035) # 2.3 ms = latency of T tracer to capture data from the RAN
|
||||
|
||||
collected_metafiles = []
|
||||
# Read data from gNB T-tracer Application
|
||||
for idx in range(gnb_args.num_requested_tracer_msgs):
|
||||
time.sleep(0.0015)
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(f"\nRecord number: {record_idx}, Reading MSG data ", idx)
|
||||
captured_data, gnb_bufIdx = read_data_from_shm(
|
||||
shm_reading_gnb, gnb_bufIdx, tracer_msgs_identities)
|
||||
# drive the collection file time stamp from the first message per record
|
||||
if idx == 0:
|
||||
# Get time stamp
|
||||
time_stamp_ms, time_stamp_ms_file_name = (
|
||||
sigmf_interface.time_stamp_formating(
|
||||
captured_data["time_stamp"], global_info["datetime_offset"]))
|
||||
global_info["collection_file"] = (
|
||||
global_info["collection_file_prefix"]
|
||||
+ "-rec-"
|
||||
+ str(record_idx)
|
||||
+ "-"
|
||||
+ str(time_stamp_ms_file_name)
|
||||
)
|
||||
global_info["timestamp"] = time_stamp_ms
|
||||
|
||||
# Write data into files with the given format
|
||||
if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]:
|
||||
collected_metafiles.append(
|
||||
sigmf_interface.write_recorded_data_to_sigmf(
|
||||
captured_data, config_meta_data, global_info, record_idx))
|
||||
|
||||
# Read data from UE T-tracer Application
|
||||
for idx in range(ue_args.num_requested_tracer_msgs):
|
||||
time.sleep(0.0015)
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(f"\nRecord number: {record_idx}, Reading MSG data ", idx)
|
||||
captured_data, ue_bufIdx = read_data_from_shm(
|
||||
shm_reading_ue, ue_bufIdx, tracer_msgs_identities)
|
||||
|
||||
# Write data into files with the given format
|
||||
if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]:
|
||||
collected_metafiles.append(
|
||||
sigmf_interface.write_recorded_data_to_sigmf(
|
||||
captured_data, config_meta_data, global_info, record_idx))
|
||||
|
||||
# generate SigMF collection file
|
||||
if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]:
|
||||
data_storage_path = config_meta_data["data_recording_config"][
|
||||
"data_storage_path"]
|
||||
description = global_info["description"]
|
||||
sigmf_interface.save_sigmf_collection(
|
||||
collected_metafiles, global_info, description, data_storage_path)
|
||||
|
||||
frame = captured_data["frame"]
|
||||
slot = captured_data["slot"]
|
||||
|
||||
# Check for changes in frame or slot
|
||||
if frame != prev_frame or slot != prev_slot:
|
||||
record_idx += 1
|
||||
# We have reached the end of the data. Break the loop
|
||||
if record_idx >= config_meta_data["data_recording_config"]["num_records"]:
|
||||
break
|
||||
# Update previous frame and slot
|
||||
prev_frame = frame
|
||||
prev_slot = slot
|
||||
|
||||
|
||||
# data conversion service
|
||||
def data_conversion_service(shm_reading, config_meta_data, args, sync_info, do_sync):
|
||||
# Initialize variables
|
||||
record_idx = 0
|
||||
prev_frame = -1
|
||||
prev_slot = -1
|
||||
bufIdx = 0
|
||||
# Read data from T-tracer Application
|
||||
print("Data Conversion Service: Reading data from T-tracer Application")
|
||||
print("Requested Tracer Messages: ", args.num_requested_tracer_msgs)
|
||||
if args.num_requested_tracer_msgs > 0:
|
||||
num_requested_tracer_msgs = args.num_requested_tracer_msgs
|
||||
else:
|
||||
raise Exception("ERROR: No requested tracer messages found!")
|
||||
|
||||
tracer_msgs_identities = config_meta_data["data_recording_config"][
|
||||
"tracer_msgs_identities"]
|
||||
global_info = config_meta_data["data_recording_config"]["global_info"]
|
||||
|
||||
if do_sync:
|
||||
print(" Find Memory Index of NR MSGs based on Sync info")
|
||||
while True:
|
||||
time.sleep(0.0035)
|
||||
station_bufIdx = bufIdx
|
||||
captured_data, bufIdx = read_data_from_shm(
|
||||
shm_reading, bufIdx, tracer_msgs_identities)
|
||||
print("*Sync Status: NR Captured Data (Frame, slot): (", captured_data["frame"],
|
||||
", ", captured_data["slot"], "), Sync Info (Frame, slot): (", sync_info["frame"],
|
||||
", ", sync_info["slot"]," )")
|
||||
if (captured_data["frame"] == sync_info["frame"]
|
||||
and captured_data["slot"] == sync_info["slot"]):
|
||||
print("*sync Pass")
|
||||
break
|
||||
print("*sync Fail")
|
||||
bufIdx = station_bufIdx
|
||||
|
||||
# Read data from T-tracer Application
|
||||
while True: # read all records
|
||||
print("\nRecord number: ", record_idx)
|
||||
if DEBUG_BUFFER_READING:
|
||||
print(f"Buffer Index: {bufIdx}")
|
||||
# wait for the next record
|
||||
# To do: check if we need to add exta waiting times between different events in case of
|
||||
# data streaming via network such as on UE side or gNB side
|
||||
time.sleep(0.0035) # 2.3 ms = latency of T tracer to capture data from the RAN
|
||||
|
||||
collected_metafiles = []
|
||||
for idx in range(num_requested_tracer_msgs):
|
||||
time.sleep(0.0015)
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(f"\nRecord number: {record_idx}, Reading MSG data ", idx)
|
||||
captured_data, bufIdx = read_data_from_shm(
|
||||
shm_reading, bufIdx, tracer_msgs_identities)
|
||||
# derive the collection file time stamp from the first message per record
|
||||
if idx == 0:
|
||||
# Get time stamp
|
||||
time_stamp_ms, time_stamp_ms_file_name = (
|
||||
sigmf_interface.time_stamp_formating(
|
||||
captured_data["time_stamp"], global_info["datetime_offset"]))
|
||||
global_info["collection_file"] = (
|
||||
global_info["collection_file_prefix"]
|
||||
+ "-rec-"
|
||||
+ str(record_idx)
|
||||
+ "-"
|
||||
+ str(time_stamp_ms_file_name))
|
||||
global_info["timestamp"] = time_stamp_ms
|
||||
# Write data into files with the given format
|
||||
if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]:
|
||||
collected_metafiles.append(
|
||||
sigmf_interface.write_recorded_data_to_sigmf(
|
||||
captured_data, config_meta_data, global_info, record_idx))
|
||||
|
||||
frame = captured_data["frame"]
|
||||
slot = captured_data["slot"]
|
||||
|
||||
# generate SigMF collection file
|
||||
if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]:
|
||||
data_storage_path = config_meta_data["data_recording_config"][
|
||||
"data_storage_path"]
|
||||
description = global_info["description"]
|
||||
sigmf_interface.save_sigmf_collection(
|
||||
collected_metafiles, global_info, description, data_storage_path)
|
||||
|
||||
# Check for changes in frame or slot
|
||||
if frame != prev_frame or slot != prev_slot:
|
||||
record_idx += 1
|
||||
# We have reached the end of the data. Break the loop
|
||||
if record_idx >= config_meta_data["data_recording_config"]["num_records"]:
|
||||
break
|
||||
# Update previous frame and slot
|
||||
prev_frame = frame
|
||||
prev_slot = slot
|
||||
|
||||
|
||||
# Write Tracer Control Message
|
||||
def write_shm(shm, args):
|
||||
# Note: Big Endian >, Little Endian <
|
||||
# Note: unsigned char B, signed char b, short h, int I, long long q
|
||||
# Note: float f, double d, string s, char c, bool ?
|
||||
# 1: config
|
||||
# 2: record
|
||||
# 3: quit
|
||||
print("Write Shared Memory: ", args.action)
|
||||
if args.action == "config":
|
||||
# Determine the length of the IP address
|
||||
ip_length = len(args.bytes_IPaddress) + 1 # String terminator
|
||||
# Construct the format string dynamically
|
||||
format_string = f"{ip_length}s"
|
||||
shm.write(
|
||||
# Config action
|
||||
struct.pack("<B", 1) +
|
||||
struct.pack("<B", ip_length) +
|
||||
struct.pack(format_string, args.bytes_IPaddress) +
|
||||
struct.pack("<h", int(args.port))
|
||||
)
|
||||
print("T-Tracer Config IP: ", args.bytes_IPaddress, " port: ", args.port)
|
||||
elif args.action == "record":
|
||||
shm.write(
|
||||
# Record action
|
||||
struct.pack("<B", int(2)) +
|
||||
struct.pack("<B", args.num_requested_tracer_msgs) +
|
||||
struct.pack(
|
||||
"<{}h".format(len(args.req_tracer_msgs_indices)),
|
||||
*args.req_tracer_msgs_indices,) +
|
||||
struct.pack("<I", args.num_records) +
|
||||
struct.pack("<h", args.start_frame_number)
|
||||
)
|
||||
print("T-Tracer Record: N Messags: ", args.num_requested_tracer_msgs,
|
||||
", Msg IDs: ", args.req_tracer_msgs_indices,
|
||||
", Num records: ", args.num_records,
|
||||
", Start Frame: ", args.start_frame_number,
|
||||
)
|
||||
elif args.action == "quit":
|
||||
shm.write(struct.pack("<B", int(3))) # Quit action
|
||||
print("T-Tracer Quit")
|
||||
else:
|
||||
print("Unknown action for data recording system!")
|
||||
|
||||
|
||||
# write shared memory task
|
||||
def write_shm_task(barrier, shm_id, args):
|
||||
# Wait for threads to be ready
|
||||
barrier.wait()
|
||||
# send request to related T-Tracer Application
|
||||
write_shm(shm_id, args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# -------------------------------------------
|
||||
# ------------- Configuration --------------
|
||||
# ------------------------------------------
|
||||
# Data Recording Configuration
|
||||
data_recording_config_file = "config/config_data_recording.json"
|
||||
# -------------------------------------------
|
||||
# Configuration
|
||||
# -------------------------------------------
|
||||
# First: get the configuration mode either local or remote
|
||||
# Second: get data recording configuration
|
||||
# Read and parse the JSON file
|
||||
with open(data_recording_config_file, "r") as file:
|
||||
config_meta_data = json.load(file)
|
||||
|
||||
# get Configuration parameters
|
||||
config_meta_data, gnb_args, ue_args = config_interface.get_data_recording_config(config_meta_data)
|
||||
|
||||
# check if lists of requested tracer messages IDs are not empty
|
||||
if not gnb_args.requested_tracer_messages and \
|
||||
not ue_args.requested_tracer_messages:
|
||||
raise Exception("ERROR: No requested tracer messages are provided")
|
||||
|
||||
# check if gnb_requested_tracer_messages is not empty, attach to the shared memory
|
||||
if gnb_args.requested_tracer_messages:
|
||||
# attach to the shared memory
|
||||
shm_writing_gnb = attach_shm(write_shm_path_gnb, project_id_gnb)
|
||||
shm_reading_gnb = attach_shm(read_shm_path_gnb, project_id_gnb)
|
||||
|
||||
# check if ue_requested_tracer_messages is not empty, attach to the shared memory
|
||||
if ue_args.requested_tracer_messages:
|
||||
# attach to the shared memory
|
||||
shm_writing_ue = attach_shm(write_shm_path_ue, project_id_ue)
|
||||
shm_reading_ue = attach_shm(read_shm_path_ue, project_id_ue)
|
||||
|
||||
# get general message header list
|
||||
general_msg_header_list, general_message_header_length = \
|
||||
data_recording_messages_def.get_general_msg_header_list()
|
||||
|
||||
# Add supported OAI Tracer Messages
|
||||
config_meta_data["data_recording_config"]["supported_oai_tracer_messages"] = supported_oai_tracer_messages
|
||||
# Add global info
|
||||
config_meta_data["data_recording_config"]["global_info"] = global_info
|
||||
|
||||
# -------------------------------------------
|
||||
# Initialization
|
||||
# -------------------------------------------
|
||||
# -------------------------------------------
|
||||
# send Tracer Control Message request to T-Tracers Apps
|
||||
# -------------------------------------------
|
||||
# It consists of the following fields:
|
||||
# Config action
|
||||
# IP address length
|
||||
# IP address
|
||||
# Port Number
|
||||
# check if gnb_requested_tracer_messages is not empty, config T-Tracer gNB via shared memory
|
||||
if gnb_args.requested_tracer_messages:
|
||||
# Config T-Tracer via shared memory
|
||||
gnb_args.action = "config"
|
||||
write_shm(shm_writing_gnb, gnb_args)
|
||||
|
||||
# check if ue_requested_tracer_messages is not empty, config T-Tracer UE via shared memory
|
||||
if ue_args.requested_tracer_messages:
|
||||
# Config T-Tracer via shared memory
|
||||
ue_args.action = "config"
|
||||
write_shm(shm_writing_ue, ue_args)
|
||||
|
||||
time.sleep(0.5) # wait for the config to be applied
|
||||
|
||||
# -------------------------------------------
|
||||
# Execution
|
||||
# -------------------------------------------
|
||||
# send Tracer Control Message request to T-Tracers Apps
|
||||
# -------------------------------------------
|
||||
# It consists of the following fields:
|
||||
# Record action
|
||||
# Number of requested Tracer Messages
|
||||
# Requested Tracer Messages ID 1, …, ID N
|
||||
# Number of records to be recorded in slots
|
||||
# Start SFN: Frame Index to start data collection from it, useful for future
|
||||
# data sync between gNB and UE but not yet used
|
||||
print("Args:")
|
||||
if gnb_args.requested_tracer_messages:
|
||||
gnb_args.action = "record"
|
||||
print("gnb_args: ", gnb_args)
|
||||
if ue_args.requested_tracer_messages:
|
||||
ue_args.action = "record"
|
||||
print("ue_args: ", ue_args)
|
||||
|
||||
start_time = time.time()
|
||||
print("Send data logging request us:", datetime.now().strftime("%Y%m%d-%H%M%S%f"))
|
||||
|
||||
# if requested: gNB and UE Tracer Messages
|
||||
# gNB + UE Tracer Messages
|
||||
if gnb_args.requested_tracer_messages and ue_args.requested_tracer_messages:
|
||||
# Create a barrier to synchronize the threads
|
||||
barrier = threading.Barrier(2)
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
tracer_ue = executor.submit(write_shm_task, barrier, shm_writing_ue, ue_args)
|
||||
tracer_gnb = executor.submit(write_shm_task, barrier, shm_writing_gnb, gnb_args)
|
||||
# Wait for both functions to complete
|
||||
concurrent.futures.wait([tracer_ue, tracer_gnb])
|
||||
|
||||
# gNB Tracer Messages
|
||||
elif gnb_args.requested_tracer_messages:
|
||||
write_shm(shm_writing_gnb, gnb_args)
|
||||
|
||||
# UE Tracer Messages
|
||||
elif ue_args.requested_tracer_messages:
|
||||
write_shm(shm_writing_ue, ue_args)
|
||||
else:
|
||||
raise Exception("ERROR: No requested tracer messages IDs are provided")
|
||||
|
||||
# -------------------------------------------
|
||||
# Read data from gNB and UE T-tracer Application
|
||||
# -------------------------------------------
|
||||
# Check if data is available in memory
|
||||
# Initialize variables
|
||||
bufIdx = 0
|
||||
timeout = 10 # 10 seconds from now
|
||||
|
||||
# If gNB MSGs are requested
|
||||
if gnb_args.requested_tracer_messages:
|
||||
# Check if data is available in gNB memory
|
||||
is_gnb_data_in_memory = is_data_available_in_memory(
|
||||
shm_reading_gnb, bufIdx, general_message_header_length, timeout)
|
||||
# Report the status of gNB T-Tracer APP locally
|
||||
if not is_gnb_data_in_memory:
|
||||
print("Error: gNB: Check t-Tracer APP of gNB, check IPs and Ports")
|
||||
print("Error: gNB: If IPs and Ports are correct, re-run the hanging app.")
|
||||
print("It seems the socket was not closed properly")
|
||||
raise Exception("ERROR: Time out, check if gNB T-Tracer APP connected to stack")
|
||||
# If UE MSGs are requested
|
||||
if ue_args.requested_tracer_messages:
|
||||
# Check if data is available in UE memory
|
||||
is_ue_data_in_memory = is_data_available_in_memory(
|
||||
shm_reading_ue, bufIdx, general_message_header_length, timeout)
|
||||
# Report the status of UE T-Tracer APP locally
|
||||
if not is_ue_data_in_memory:
|
||||
print("Error: UE: Check t-Tracer APP of UE, check IPs and Ports")
|
||||
print("Error: UE: If IPs and Ports are correct, re-run the hanging app.")
|
||||
print("It seems the socket was not closed properly")
|
||||
raise Exception("ERROR: Time out, check if UE T-Tracer APP connected to stack")
|
||||
|
||||
# -------------------------------------------
|
||||
# Sync data between gNB and UE
|
||||
# -------------------------------------------
|
||||
# write JSON file
|
||||
common_utils.write_config_data_recording_app_json(config_meta_data)
|
||||
sync_info = {}
|
||||
if gnb_args.requested_tracer_messages and ue_args.requested_tracer_messages:
|
||||
# Sync data between gNB and UE
|
||||
sync_info = sync_service.sync_gnb_ue_captured_data(shm_reading_gnb, shm_reading_ue)
|
||||
print("\n***Sync data between gNB and UE: ", sync_info)
|
||||
# Read data from gNB and UE T-tracer Applications
|
||||
sync_data_conversion_service(
|
||||
shm_reading_gnb, shm_reading_ue, sync_info, config_meta_data, gnb_args, ue_args)
|
||||
elif gnb_args.requested_tracer_messages:
|
||||
# Read data from gNB T-tracer Application
|
||||
data_conversion_service(
|
||||
shm_reading_gnb, config_meta_data, gnb_args, sync_info, do_sync=False)
|
||||
elif ue_args.requested_tracer_messages:
|
||||
# Read data from UE T-tracer Application
|
||||
data_conversion_service(
|
||||
shm_reading_ue, config_meta_data, ue_args, sync_info, do_sync=False)
|
||||
else:
|
||||
raise Exception("ERROR: No requested tracer messages IDs are provided")
|
||||
|
||||
# measure Elapsed time
|
||||
time_elapsed = time.time() - start_time
|
||||
time_elapsed_ms = int(time_elapsed * 1000)
|
||||
print(
|
||||
"Elapsed time of getting Requested Messages and writing data and meta data files:",
|
||||
colored(time_elapsed_ms, "yellow"), "ms",)
|
||||
|
||||
# Stop T-Tracer Application function
|
||||
if gnb_args.requested_tracer_messages:
|
||||
gnb_args.action = "quit"
|
||||
write_shm(shm_writing_gnb, gnb_args)
|
||||
# Add Sleep time to ensure that the message sent to the UE T-tracer application is received
|
||||
# before the shared memory is detached
|
||||
time.sleep(0.5)
|
||||
# Clean shared memory
|
||||
detach_shm(shm_reading_gnb)
|
||||
detach_shm(shm_writing_gnb)
|
||||
remove_shm(shm_reading_gnb)
|
||||
remove_shm(shm_writing_gnb)
|
||||
if ue_args.requested_tracer_messages:
|
||||
ue_args.action = "quit"
|
||||
write_shm(shm_writing_ue, ue_args)
|
||||
# Add Sleep time to ensure that the message sent to the UE T-tracer application is received
|
||||
# before the shared memory is detached
|
||||
time.sleep(0.5)
|
||||
# Clean shared memory
|
||||
detach_shm(shm_reading_ue)
|
||||
detach_shm(shm_writing_ue)
|
||||
remove_shm(shm_reading_ue)
|
||||
remove_shm(shm_writing_ue)
|
||||
|
||||
print("End of the RF Data Recording API")
|
||||
pass
|
||||
523
common/utils/data_recording/data_recording_app_v1.1.py
Normal file
523
common/utils/data_recording/data_recording_app_v1.1.py
Normal file
@@ -0,0 +1,523 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# brief main application of synchronized real-time data recording
|
||||
|
||||
import atexit
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
import json
|
||||
import concurrent.futures
|
||||
from termcolor import colored
|
||||
import threading
|
||||
# import library functions
|
||||
from lib import sigmf_interface
|
||||
from lib import sync_service
|
||||
from lib import data_recording_messages_def
|
||||
from lib import common_utils
|
||||
from lib import config_interface
|
||||
from lib import shared_memory_interface as shm_interface
|
||||
|
||||
DEBUG_WIRELESS_RECORDED_DATA = True
|
||||
DEBUG_BUFFER_READING = False
|
||||
|
||||
# globally applicable metadata
|
||||
global_info = {
|
||||
"author": "Abdo Gaber",
|
||||
"description": "Synchronized Real-Time Data Recording",
|
||||
"timestamp": 0,
|
||||
"collection_file_prefix": "data-collection", # collection file name prefix
|
||||
"collection_file": "", # Reserved to be created in the code: “data-collection_rec-0_TIME-STAMP”
|
||||
"datetime_offset": "", # datetime offset between current location and UTC/Zulu timezone
|
||||
# Example: "+01:00" for Berlin, Germany
|
||||
"save_config_data_recording_app_json": True,
|
||||
"waveform_generator": "5gnr_oai",
|
||||
"extensions": {},
|
||||
}
|
||||
|
||||
# Supported OAI Trace messages
|
||||
# UL receiver messages
|
||||
# gNB IQ Msgs: "GNB_PHY_UL_FD_PUSCH_IQ", "GNB_PHY_UL_FD_DMRS", "GNB_PHY_UL_FD_CHAN_EST_DMRS_POS",
|
||||
# "GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL"
|
||||
# gNB BITS Msgs: "GNB_PHY_UL_PAYLOAD_RX_BITS"
|
||||
# UE BITS Msgs: "UE_PHY_UL_SCRAMBLED_TX_BITS", "UE_PHY_UL_PAYLOAD_TX_BITS"
|
||||
|
||||
supported_oai_tracer_messages = {
|
||||
# gNB messages
|
||||
"GNB_PHY_UL_FD_PUSCH_IQ": {
|
||||
"file_name_prefix": "rx-fd-data",
|
||||
"scope": "gNB",
|
||||
"description": "Frequency-domain RX data",
|
||||
"serialization_scheme": ["subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"GNB_PHY_UL_FD_DMRS": {
|
||||
"file_name_prefix": "tx-pilots-fd-data",
|
||||
"scope": "gNB",
|
||||
"description": "Frequency-domain TX PUSCH DMRS data",
|
||||
"serialization_scheme": ["subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_POS": {
|
||||
"file_name_prefix": "raw-ce-fd-data",
|
||||
"scope": "gNB",
|
||||
"description": "Frequency-domain raw channel estimates (at DMRS positions)",
|
||||
"serialization_scheme": ["subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL": {
|
||||
"file_name_prefix": "raw-inter-ce-fd-data",
|
||||
"scope": "gNB",
|
||||
"description": "Interpolcated Frequency-domain raw channel estimates",
|
||||
"serialization_scheme": ["subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"GNB_PHY_UL_PAYLOAD_RX_BITS": {
|
||||
"file_name_prefix": "rx-payload-bits",
|
||||
"scope": "gNB",
|
||||
"description": "Received PUSCH payload bits",
|
||||
"serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
# UE messages
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS": {
|
||||
"file_name_prefix": "tx-scrambled-bits",
|
||||
"scope": "UE",
|
||||
"description": "Transmitted scrambled PUSCH bits",
|
||||
"serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS": {
|
||||
"file_name_prefix": "tx-payload-bits",
|
||||
"scope": "UE",
|
||||
"description": "Transmitted PUSCH payload bits",
|
||||
"serialization_scheme": ["bits", "subcarriers", "ofdm_symbols"],
|
||||
},
|
||||
}
|
||||
|
||||
def read_and_store_tracer_messages(shm_reading, bufIdx, num_messages, config_meta_data,
|
||||
global_info, update_timestamp=False):
|
||||
"""
|
||||
Read tracer messages from shared memory while they belong to the same frame and slot.
|
||||
Continuously reads messages until a different frame/slot is encountered.
|
||||
|
||||
Args:
|
||||
shm_reading: Shared memory reading handle
|
||||
bufIdx: Current buffer index
|
||||
num_messages: Maximum number of messages to read (used as safeguard)
|
||||
config_meta_data: Configuration metadata
|
||||
global_info: Global information dict (for timestamp on first message)
|
||||
update_timestamp: If True, update global_info timestamp from first message
|
||||
|
||||
Returns:
|
||||
tuple: (updated_bufIdx, collected_metafiles, last_captured_data)
|
||||
"""
|
||||
tracer_msgs_identities = config_meta_data["data_recording_config"]["tracer_msgs_identities"]
|
||||
collected_metafiles = []
|
||||
captured_data = None
|
||||
|
||||
# Get sync header to check frame and slot
|
||||
sync_header_msg, sync_header_msg_length = data_recording_messages_def.get_sync_header_msg_list()
|
||||
|
||||
# Read first message to establish the reference frame and slot
|
||||
timeout = 10 # 10 seconds timeout
|
||||
is_data_in_memory = shm_interface.is_data_available_in_memory(
|
||||
shm_reading, bufIdx, sync_header_msg_length, timeout)
|
||||
|
||||
if not is_data_in_memory:
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print("Warning: No data available in shared memory")
|
||||
return bufIdx, collected_metafiles, global_info
|
||||
|
||||
# Get reference frame and slot from first message
|
||||
ref_frame, ref_slot = shm_interface.get_frame_slot_start(
|
||||
shm_reading, bufIdx, sync_header_msg, sync_header_msg_length)
|
||||
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(f"\nRecord number: {global_info['record_idx']}, Reference Frame: {ref_frame}, Slot: {ref_slot}")
|
||||
|
||||
idx = 0
|
||||
while idx < num_messages:
|
||||
time.sleep(0.0015)
|
||||
|
||||
# Check if data is available
|
||||
is_data_in_memory = shm_interface.is_data_available_in_memory(
|
||||
shm_reading, bufIdx, sync_header_msg_length, timeout)
|
||||
|
||||
if not is_data_in_memory:
|
||||
break
|
||||
|
||||
# Get frame and slot of current message before reading
|
||||
current_frame, current_slot = shm_interface.get_frame_slot_start(
|
||||
shm_reading, bufIdx, sync_header_msg, sync_header_msg_length)
|
||||
|
||||
# Check if we're still on the same frame and slot
|
||||
if current_frame != ref_frame or current_slot != ref_slot:
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(f"Frame/Slot changed: ({ref_frame}, {ref_slot}) -> ({current_frame}, {current_slot}). Stopping at message {idx}")
|
||||
# Keep buffer index pointing to this new frame/slot message (don't increment)
|
||||
break
|
||||
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(f"Reading MSG {idx}: Frame={current_frame}, Slot={current_slot}")
|
||||
|
||||
# Read the message
|
||||
captured_data, bufIdx = shm_interface.read_data_from_shm(
|
||||
shm_reading, bufIdx, tracer_msgs_identities)
|
||||
|
||||
# Update timestamp from the first message if requested
|
||||
if idx == 0 and update_timestamp:
|
||||
time_stamp, time_stamp_file_name = (
|
||||
sigmf_interface.time_stamp_formating(
|
||||
captured_data["unix_capture_ts_sec"],
|
||||
captured_data["unix_capture_ts_nsec"],
|
||||
global_info["datetime_offset"]))
|
||||
global_info["collection_file"] = (
|
||||
f"{global_info['collection_file_prefix']}-rec-{global_info['record_idx']}-{time_stamp_file_name}")
|
||||
global_info["timestamp"] = time_stamp
|
||||
global_info["frame"] = captured_data["frame"]
|
||||
global_info["slot"]= captured_data["slot"]
|
||||
|
||||
# Write data into files with the given format
|
||||
if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]:
|
||||
collected_metafiles.append(sigmf_interface.write_recorded_data_to_sigmf(
|
||||
captured_data, config_meta_data, global_info, global_info['record_idx']))
|
||||
|
||||
idx += 1
|
||||
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(f"Total messages read: {idx} for Frame {ref_frame}, Slot {ref_slot}")
|
||||
|
||||
return bufIdx, collected_metafiles, global_info
|
||||
|
||||
def find_sync_buffer_index(shm_reading, sync_info, tracer_msgs_identities, timeout_sec=None):
|
||||
"""
|
||||
Find buffer index that matches sync frame and slot.
|
||||
|
||||
Args:
|
||||
shm_reading: Shared memory reading handle
|
||||
sync_info: Dictionary with 'frame' and 'slot' keys
|
||||
tracer_msgs_identities: Tracer message identities
|
||||
timeout_sec: Timeout in seconds (None for no timeout)
|
||||
|
||||
Returns:
|
||||
bufIdx: Buffer index where sync match was found (points to the matching message)
|
||||
|
||||
Raises:
|
||||
Exception if timeout occurs before sync is found
|
||||
"""
|
||||
bufIdx = 0
|
||||
timeout_sync = time.time() + timeout_sec if timeout_sec else None
|
||||
|
||||
while True:
|
||||
time.sleep(0.0035) # 2.3 ms = latency of T tracer to capture data from the RAN
|
||||
saved_bufIdx = bufIdx # Save index BEFORE read
|
||||
captured_data, bufIdx = shm_interface.read_data_from_shm(
|
||||
shm_reading, bufIdx, tracer_msgs_identities)
|
||||
print(f" [NR Data Sync] NR Data (Frame:{captured_data['frame']}, Slot:{captured_data['slot']}) | "
|
||||
f"Target (Frame:{sync_info['frame']}, Slot:{sync_info['slot']})")
|
||||
|
||||
if (captured_data["frame"] == sync_info["frame"] and
|
||||
captured_data["slot"] == sync_info["slot"]):
|
||||
print(" [NR Data Sync] Sync pass")
|
||||
return saved_bufIdx # Return index pointing to the matching message
|
||||
|
||||
if timeout_sync and time.time() > timeout_sync:
|
||||
raise Exception(
|
||||
"ERROR: Data Recording NO Sync Found, check Tracer Services if they are connected!")
|
||||
|
||||
def send_5g_nr_msgs_request(barrier, shm_writing, shm_reading, args):
|
||||
# send Tracer Control Message request to T-Tracers Apps
|
||||
# -------------------------------------------
|
||||
# It consists of the following fields:
|
||||
# Record action
|
||||
# Number of requested Tracer Messages
|
||||
# Requested Tracer Messages ID 1, …, ID N
|
||||
# Number of records to be recorded in slots
|
||||
# Start SFN: Frame Index to start data collection from it, but not yet used
|
||||
shm_interface.write_shm_task(barrier,shm_writing, args)
|
||||
|
||||
def generic_data_conversion_service(node_shm, config_meta_data, tracer_nodes, sync_info=None):
|
||||
"""Generic data conversion service for N tracer nodes.
|
||||
|
||||
Args:
|
||||
node_shm: dict {node_id: {"reading": shm, "writing": shm}}
|
||||
config_meta_data: Config metadata dict
|
||||
tracer_nodes: dict {node_id: args} for nodes with tracer messages
|
||||
sync_info: Optional sync info dict with 'frame' and 'slot'. If provided,
|
||||
each node's buffer index is synced to this frame/slot.
|
||||
"""
|
||||
record_idx = 0
|
||||
prev_frame = -1
|
||||
prev_slot = -1
|
||||
|
||||
tracer_msgs_identities = config_meta_data["data_recording_config"]["tracer_msgs_identities"]
|
||||
global_info = config_meta_data["data_recording_config"]["global_info"]
|
||||
|
||||
# Find sync buffer indices for each node if sync_info provided
|
||||
node_buf_idx = {}
|
||||
for node_id in tracer_nodes:
|
||||
if sync_info:
|
||||
print(f" [NR Data Sync] Finding memory index for node {node_id}")
|
||||
node_buf_idx[node_id] = find_sync_buffer_index(
|
||||
node_shm[node_id]["reading"], sync_info, tracer_msgs_identities, timeout_sec=5)
|
||||
else:
|
||||
node_buf_idx[node_id] = 0
|
||||
|
||||
# Determine num_records from first tracer node
|
||||
num_records = next(iter(tracer_nodes.values())).num_records
|
||||
|
||||
print("\n--- Data Conversion: Reading data from T-tracer Applications ---")
|
||||
for node_id, args in tracer_nodes.items():
|
||||
print(f" [Data Conversion] {node_id}: Requested tracer messages: {args.num_requested_tracer_msgs}")
|
||||
|
||||
# Read data from all tracer nodes
|
||||
while True:
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print("\nRecord number: ", record_idx)
|
||||
if DEBUG_BUFFER_READING:
|
||||
for nid in tracer_nodes:
|
||||
print(f" Buffer Index {nid}: {node_buf_idx[nid]}")
|
||||
time.sleep(0.0035)
|
||||
|
||||
global_info["record_idx"] = record_idx
|
||||
all_metafiles = []
|
||||
|
||||
for i, (node_id, args) in enumerate(tracer_nodes.items()):
|
||||
buf_idx, metafiles, global_info = read_and_store_tracer_messages(
|
||||
node_shm[node_id]["reading"], node_buf_idx[node_id],
|
||||
args.num_requested_tracer_msgs, config_meta_data, global_info,
|
||||
update_timestamp=(i == 0))
|
||||
node_buf_idx[node_id] = buf_idx
|
||||
all_metafiles.extend(metafiles)
|
||||
|
||||
# Generate SigMF collection file
|
||||
if config_meta_data["data_recording_config"]["enable_saving_tracer_messages_sigmf"]:
|
||||
data_storage_path = config_meta_data["data_recording_config"]["data_storage_path"]
|
||||
description = global_info["description"]
|
||||
sigmf_interface.save_sigmf_collection(
|
||||
all_metafiles, global_info, description, data_storage_path)
|
||||
|
||||
frame = global_info["frame"]
|
||||
slot = global_info["slot"]
|
||||
|
||||
if frame != prev_frame or slot != prev_slot:
|
||||
record_idx += 1
|
||||
if record_idx >= num_records:
|
||||
break
|
||||
prev_frame = frame
|
||||
prev_slot = slot
|
||||
|
||||
# -------------------------------------------
|
||||
# Cleanup — ensures shared memory and resources are released even on Ctrl+C
|
||||
# -------------------------------------------
|
||||
# Module-level dict populated at runtime with resources that need cleanup.
|
||||
# Each key is optional; the cleanup function checks before acting.
|
||||
_cleanup_state = {"done": False}
|
||||
|
||||
|
||||
def cleanup_resources():
|
||||
"""Release T-tracer shared memory resources."""
|
||||
if _cleanup_state["done"]:
|
||||
return
|
||||
_cleanup_state["done"] = True
|
||||
print("\nCleaning up resources...")
|
||||
|
||||
tracer_nodes = _cleanup_state.get("tracer_nodes", {})
|
||||
node_shm = _cleanup_state.get("node_shm", {})
|
||||
for node_id in tracer_nodes:
|
||||
try:
|
||||
tracer_nodes[node_id].action = "quit"
|
||||
shm_interface.write_shm(node_shm[node_id]["writing"], tracer_nodes[node_id])
|
||||
time.sleep(0.5)
|
||||
shm_interface.detach_shm(node_shm[node_id]["reading"])
|
||||
shm_interface.detach_shm(node_shm[node_id]["writing"])
|
||||
shm_interface.remove_shm(node_shm[node_id]["reading"])
|
||||
shm_interface.remove_shm(node_shm[node_id]["writing"])
|
||||
except Exception as e:
|
||||
print(f"Warning: {node_id} shared memory cleanup error: {e}")
|
||||
|
||||
|
||||
def register_cleanup():
|
||||
"""Register cleanup_resources with atexit and signal handlers."""
|
||||
atexit.register(cleanup_resources)
|
||||
|
||||
def _signal_handler(signum, frame):
|
||||
print(f"\nSignal {signum} received, shutting down...")
|
||||
cleanup_resources()
|
||||
sys.exit(130)
|
||||
|
||||
signal.signal(signal.SIGINT, _signal_handler)
|
||||
signal.signal(signal.SIGTERM, _signal_handler)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# -------------------------------------------
|
||||
# Data Control Service
|
||||
## -------------------------------------------
|
||||
# ------------- Configuration --------------
|
||||
# ------------------------------------------
|
||||
# Data Recording Configuration
|
||||
data_recording_config_file = "config/config_data_recording.json"
|
||||
# -------------------------------------------
|
||||
# Configuration
|
||||
# -------------------------------------------
|
||||
# Read and parse the JSON file
|
||||
with open(data_recording_config_file, "r") as file:
|
||||
config_meta_data = json.load(file)
|
||||
# -------------------------------------------
|
||||
# Generic node-based configuration
|
||||
# -------------------------------------------
|
||||
config_meta_data, all_node_args = config_interface.get_data_recording_config(config_meta_data)
|
||||
_nodes_cfg = config_meta_data["data_recording_config"]["nodes"]
|
||||
|
||||
# Build tracer_nodes: only nodes with requested tracer messages
|
||||
tracer_nodes = {nid: args for nid, args in all_node_args.items()
|
||||
if args.requested_tracer_messages}
|
||||
|
||||
# Validate: at least one node must have tracer messages
|
||||
any_tracer = bool(tracer_nodes)
|
||||
if not any_tracer:
|
||||
raise Exception("ERROR: No requested tracer messages IDs are provided")
|
||||
|
||||
# -------------------------------------------
|
||||
# Attach shared memory for each tracer node
|
||||
# -------------------------------------------
|
||||
node_shm = {} # {node_id: {"reading": shm, "writing": shm}}
|
||||
for node_id, args in tracer_nodes.items():
|
||||
node_cfg = next(n for n in _nodes_cfg if n["id"] == node_id)
|
||||
shm_cfg = node_cfg.get("shared_mem_config", {})
|
||||
read_path = shm_cfg.get("read_path")
|
||||
write_path = shm_cfg.get("write_path")
|
||||
proj_id = shm_cfg.get("project_id")
|
||||
if not read_path or not write_path or proj_id is None:
|
||||
raise Exception(
|
||||
f"ERROR: Node '{node_id}' has tracer messages but missing 'shared_mem_config' "
|
||||
f"(read_path, write_path, project_id) in config.")
|
||||
shm_writing = shm_interface.attach_shm(write_path, proj_id)
|
||||
shm_reading = shm_interface.attach_shm(read_path, proj_id)
|
||||
node_shm[node_id] = {"reading": shm_reading, "writing": shm_writing}
|
||||
|
||||
# get general message header list
|
||||
general_msg_header_list, general_message_header_length = \
|
||||
data_recording_messages_def.get_general_msg_header_list()
|
||||
|
||||
# Add supported OAI Tracer Messages
|
||||
config_meta_data["data_recording_config"]["supported_oai_tracer_messages"] = supported_oai_tracer_messages
|
||||
# Add global info
|
||||
config_meta_data["data_recording_config"]["global_info"] = global_info
|
||||
|
||||
# -------------------------------------------
|
||||
# Initialization
|
||||
# -------------------------------------------
|
||||
# send Tracer Control Message request to T-Tracers Apps
|
||||
# It consists of the following fields:
|
||||
# Config action
|
||||
# IP address length
|
||||
# IP address
|
||||
# Port Number
|
||||
# Configure T-Tracers via shared memory for each tracer node
|
||||
for node_id, args in tracer_nodes.items():
|
||||
args.action = "config"
|
||||
shm_interface.write_shm(node_shm[node_id]["writing"], args)
|
||||
|
||||
time.sleep(0.5) # wait for the config to be applied
|
||||
|
||||
# -------------------------------------------
|
||||
# Execution
|
||||
# -------------------------------------------
|
||||
# send Tracer Control Message request to T-Tracers Apps
|
||||
# -------------------------------------------
|
||||
# It consists of the following fields:
|
||||
# Record action
|
||||
# Number of requested Tracer Messages
|
||||
# Requested Tracer Messages ID 1, …, ID N
|
||||
# Number of records to be recorded in slots
|
||||
# Start SFN: Frame Index to start data collection from it, useful for future
|
||||
# data sync between gNB and UE but not yet used
|
||||
# -------------------------------------------
|
||||
# -------- Data Collection Service ----------
|
||||
# -------------------------------------------
|
||||
print("Args:")
|
||||
for node_id, args in tracer_nodes.items():
|
||||
args.action = "record"
|
||||
print(f" {node_id} args: ", args)
|
||||
|
||||
# Pre-create thread pool if user would like to create a for loop for N iterations
|
||||
# Outside the loop to avoid initialization overhead.
|
||||
# max_workers and barrier_parties are kept identical: every thread that
|
||||
# enters the pool must also call barrier.wait(), so pool size == barrier size.
|
||||
total_thread_count = len(tracer_nodes)
|
||||
thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=total_thread_count)
|
||||
barrier = threading.Barrier(total_thread_count) if total_thread_count > 0 else None
|
||||
|
||||
# Populate cleanup state and register signal handlers
|
||||
_cleanup_state.update({
|
||||
"tracer_nodes": tracer_nodes,
|
||||
"node_shm": node_shm,
|
||||
})
|
||||
register_cleanup()
|
||||
|
||||
# Start data recording iterations
|
||||
start_time = time.time()
|
||||
print("Send data logging request us:", datetime.now().strftime("%Y%m%d-%H%M%S%f"))
|
||||
|
||||
# -------------------------------------------
|
||||
# Submit NR tracer threads for all tracer nodes
|
||||
# -------------------------------------------
|
||||
futures = []
|
||||
for node_id, args in tracer_nodes.items():
|
||||
shm = node_shm[node_id]
|
||||
tracer_thread = thread_pool.submit(
|
||||
send_5g_nr_msgs_request, barrier, shm["writing"], shm["reading"], args)
|
||||
futures.append(tracer_thread)
|
||||
|
||||
# Wait for all threads to complete
|
||||
concurrent.futures.wait(futures)
|
||||
|
||||
# -------------------------------------------
|
||||
# Check data availability for each tracer node
|
||||
# -------------------------------------------
|
||||
bufIdx = 0
|
||||
timeout = 10 # 10 seconds from now
|
||||
|
||||
for node_id in tracer_nodes:
|
||||
is_data_in_memory = shm_interface.is_data_available_in_memory(
|
||||
node_shm[node_id]["reading"], bufIdx, general_message_header_length, timeout)
|
||||
|
||||
if not is_data_in_memory:
|
||||
print(f"Error: {node_id}: Check T-Tracer APP, check IPs and Ports")
|
||||
print(f"Error: {node_id}: If IPs and Ports are correct, re-run the hanging app. "
|
||||
"It seems the socket was not closed properly")
|
||||
raise Exception(
|
||||
f"ERROR: Time out, check if {node_id} T-Tracer APP connected to stack")
|
||||
|
||||
# -------------------------------------------
|
||||
# Sync and convert data
|
||||
# -------------------------------------------
|
||||
common_utils.write_config_data_recording_app_json(config_meta_data)
|
||||
sync_info = {}
|
||||
|
||||
# Step 1: Sync NR tracer nodes (find latest common frame/slot across all NR sources)
|
||||
if len(tracer_nodes) > 1:
|
||||
node_shm_readings = {nid: node_shm[nid]["reading"] for nid in tracer_nodes}
|
||||
sync_info = sync_service.sync_multiple_nr_nodes(node_shm_readings)
|
||||
print(f"\n--- NR Node Sync: Sync point: frame={sync_info['frame']}, slot={sync_info['slot']} ---")
|
||||
|
||||
# Step 2: Read and store NR tracer data
|
||||
if tracer_nodes:
|
||||
do_sync = bool(sync_info)
|
||||
generic_data_conversion_service(
|
||||
node_shm, config_meta_data, tracer_nodes, sync_info if do_sync else None)
|
||||
|
||||
# measure Elapsed time
|
||||
time_elapsed = time.time() - start_time
|
||||
time_elapsed_ms = int(time_elapsed * 1000)
|
||||
print(
|
||||
"Elapsed time of getting Requested Messages and writing data and meta data files:",
|
||||
colored(time_elapsed_ms, "yellow"),
|
||||
"ms",)
|
||||
|
||||
# Shutdown thread pool after all iterations complete
|
||||
thread_pool.shutdown(wait=True)
|
||||
|
||||
# Run cleanup (also registered with atexit and signal handlers for abnormal exits)
|
||||
cleanup_resources()
|
||||
|
||||
print("End of the RF Data Recording API")
|
||||
@@ -1,12 +1,11 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# brief Data Recording common utilities
|
||||
# brief Common utilities of Data Recording App
|
||||
|
||||
import os
|
||||
import json
|
||||
|
||||
|
||||
def real_to_complex(real_vector):
|
||||
# Ensure the length of the real vector is even
|
||||
if len(real_vector) % 2 != 0:
|
||||
@@ -34,7 +33,7 @@ def write_config_data_recording_app_json(config_meta_data):
|
||||
# Specify the file name
|
||||
output_file = (
|
||||
config_meta_data["data_recording_config"]["data_storage_path"]
|
||||
+ "config_data_recording_app.json"
|
||||
+ "config_data_recording_app_extended.json"
|
||||
)
|
||||
# Ensure the directory exists
|
||||
os.makedirs(os.path.dirname(output_file), exist_ok=True)
|
||||
@@ -43,6 +42,6 @@ def write_config_data_recording_app_json(config_meta_data):
|
||||
with open(output_file, "w") as file:
|
||||
try:
|
||||
json.dump(config_meta_data, file, indent=4)
|
||||
print(f"JSON file created successfully at {output_file}")
|
||||
print(f" [Config] JSON file saved: {output_file}")
|
||||
except Exception as e:
|
||||
print(f"Failed to create JSON file: {e}")
|
||||
print(f" [Config] Failed to create JSON file: {e}")
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# brief Data Recording App Configuration Interface
|
||||
# brief Configuration Interface of Data Recording App
|
||||
|
||||
import yaml
|
||||
import json
|
||||
import argparse
|
||||
|
||||
|
||||
# Function to read the main configuration file in JSON format
|
||||
def read_main_config_file_json(main_config_file: str) -> dict:
|
||||
"""
|
||||
Reads main config file.
|
||||
"""
|
||||
|
||||
# read general parameter set from yaml config file
|
||||
with open(main_config_file, "r") as file:
|
||||
main_config = json.load(file)
|
||||
@@ -20,22 +19,11 @@ def read_main_config_file_json(main_config_file: str) -> dict:
|
||||
return main_config
|
||||
|
||||
|
||||
# Function to read the main configuration file in YAML format
|
||||
def read_main_config_file(main_config_file: str) -> dict:
|
||||
"""
|
||||
Reads main config file.
|
||||
"""
|
||||
# read general parameter set from yaml config file
|
||||
with open(main_config_file, "r") as file:
|
||||
main_config = yaml.load(file, Loader=yaml.Loader)
|
||||
|
||||
return main_config
|
||||
|
||||
|
||||
# Function to parse the OAI T_messages file and get the index of a given string
|
||||
def parse_message_file(file_path):
|
||||
with open(file_path, "r") as file:
|
||||
content = file.readlines()
|
||||
|
||||
# Extract lines that start with 'ID' and remove the 'ID = ' prefix
|
||||
tracer_msgs_identities = [
|
||||
line.strip().replace("ID = ", "")
|
||||
@@ -65,12 +53,18 @@ def get_requested_tracer_msgs_indices(requested_tracer_messages, tracer_msgs_ide
|
||||
return req_tracer_msgs_indices
|
||||
|
||||
|
||||
# Function to get the data recording configuration
|
||||
def get_data_recording_config(config_meta_data):
|
||||
parser = argparse.ArgumentParser(description="request messages IDs")
|
||||
ue_args = parser.parse_args()
|
||||
gnb_args = parser.parse_args()
|
||||
# Helper: return the first node in the nodes list whose type matches the given type string
|
||||
def get_node_by_type(nodes, node_type):
|
||||
for node in nodes:
|
||||
if node.get("type") == node_type:
|
||||
return node
|
||||
return None
|
||||
|
||||
|
||||
# Function to get the data recording configuration.
|
||||
# Returns (config_meta_data, node_args_dict) where node_args_dict is
|
||||
# { node_id: Namespace } with one entry per node defined in the config.
|
||||
def get_data_recording_config(config_meta_data):
|
||||
# get Tracer Messages IDs from the T-Tracer Messages file
|
||||
# MSG list order should be similar to the T-Tracer Messages txt file
|
||||
# Be sure that you are using the same T_messages file that is used in the OAI project
|
||||
@@ -81,44 +75,33 @@ def get_data_recording_config(config_meta_data):
|
||||
config_meta_data["data_recording_config"]["t_tracer_message_definition_file"])
|
||||
config_meta_data["data_recording_config"]["tracer_msgs_identities"] = tracer_msgs_identities
|
||||
|
||||
# get requested tracer messages indices for gNB
|
||||
gnb_args.requested_tracer_messages = \
|
||||
config_meta_data["data_recording_config"]["base_station"]["requested_tracer_messages"]
|
||||
# get requested tracer messages indices for UE
|
||||
ue_args.requested_tracer_messages = \
|
||||
config_meta_data["data_recording_config"]["user_equipment"]["requested_tracer_messages"]
|
||||
nodes = config_meta_data["data_recording_config"]["nodes"]
|
||||
|
||||
# check if gnb_requested_tracer_messages is not empty
|
||||
if gnb_args.requested_tracer_messages:
|
||||
config_meta_data["data_recording_config"]["base_station"][
|
||||
"req_tracer_msgs_indices"] = get_requested_tracer_msgs_indices(
|
||||
gnb_args.requested_tracer_messages, tracer_msgs_identities)
|
||||
# Build per-node args generically
|
||||
node_args_dict = {}
|
||||
for node in nodes:
|
||||
parser = argparse.ArgumentParser(description="request messages IDs")
|
||||
node_args = parser.parse_args()
|
||||
|
||||
# get gNB Trace Messages
|
||||
gnb_args.num_records = config_meta_data["data_recording_config"]["num_records"]
|
||||
gnb_args.start_frame_number = config_meta_data["data_recording_config"]["start_frame_number"]
|
||||
gnb_args.req_tracer_msgs_indices = \
|
||||
config_meta_data["data_recording_config"]["base_station"]["req_tracer_msgs_indices"]
|
||||
gnb_args.num_requested_tracer_msgs = len(gnb_args.req_tracer_msgs_indices)
|
||||
# Split the string into IP and port
|
||||
gnb_args.IPaddress, gnb_args.port = config_meta_data["data_recording_config"][
|
||||
"tracer_service_baseStation_address"].split(":")
|
||||
gnb_args.bytes_IPaddress = bytes(gnb_args.IPaddress, "utf-8")
|
||||
node_id = node.get("id")
|
||||
node_args.node_id = node_id
|
||||
node_args.type = node.get("type")
|
||||
node_args.requested_tracer_messages = node.get("requested_tracer_messages", [])
|
||||
|
||||
# check if ue_requested_tracer_messages is not empty
|
||||
if ue_args.requested_tracer_messages:
|
||||
config_meta_data["data_recording_config"]["user_equipment"][
|
||||
"req_tracer_msgs_indices"] = get_requested_tracer_msgs_indices(
|
||||
ue_args.requested_tracer_messages, tracer_msgs_identities)
|
||||
if node_args.requested_tracer_messages:
|
||||
node["req_tracer_msgs_indices"] = get_requested_tracer_msgs_indices(
|
||||
node_args.requested_tracer_messages, tracer_msgs_identities)
|
||||
|
||||
# get UE Trace Messages
|
||||
ue_args.num_records = config_meta_data["data_recording_config"]["num_records"]
|
||||
ue_args.start_frame_number = config_meta_data["data_recording_config"]["start_frame_number"]
|
||||
ue_args.req_tracer_msgs_indices = \
|
||||
config_meta_data["data_recording_config"]["user_equipment"]["req_tracer_msgs_indices"]
|
||||
ue_args.num_requested_tracer_msgs = len(ue_args.req_tracer_msgs_indices)
|
||||
ue_args.IPaddress, ue_args.port = config_meta_data["data_recording_config"][
|
||||
"tracer_service_userEquipment_address"].split(":")
|
||||
ue_args.bytes_IPaddress = bytes(ue_args.IPaddress, "utf-8")
|
||||
node_args.num_records = config_meta_data["data_recording_config"]["num_records"]
|
||||
node_args.start_frame_number = config_meta_data["data_recording_config"]["start_frame_number"]
|
||||
node_args.req_tracer_msgs_indices = node["req_tracer_msgs_indices"]
|
||||
node_args.num_requested_tracer_msgs = len(node_args.req_tracer_msgs_indices)
|
||||
# Split the string into IP and port
|
||||
tracer_addr = node.get("tracer_service_address", "")
|
||||
if tracer_addr:
|
||||
node_args.IPaddress, node_args.port = tracer_addr.split(":")
|
||||
node_args.bytes_IPaddress = bytes(node_args.IPaddress, "utf-8")
|
||||
|
||||
return config_meta_data, gnb_args, ue_args
|
||||
node_args_dict[node_id] = node_args
|
||||
|
||||
return config_meta_data, node_args_dict
|
||||
|
||||
@@ -3,6 +3,32 @@
|
||||
# ---------------------------------------------------------------------
|
||||
# brief defination of captured data recording messages
|
||||
|
||||
# Get Common Sync Header - number of bytes
|
||||
def get_sync_header_msg_list():
|
||||
"""
|
||||
shared memory layout written from the app:
|
||||
=================================
|
||||
msg_id (uint8) message type ID
|
||||
frame (uint16)
|
||||
slot (uint8)
|
||||
unix_capture_ts_sec (uint32) Unix epoch seconds
|
||||
unix_capture_ts_nsec (uint32) nanoseconds [0, 999999999]
|
||||
|
||||
"""
|
||||
# Get Common Sync Header - number of bytes
|
||||
sync_header_msg = {
|
||||
"msg_id": 2,
|
||||
"frame": 2,
|
||||
"slot": 1,
|
||||
"unix_capture_ts_sec": 4,
|
||||
"unix_capture_ts_nsec": 4,
|
||||
}
|
||||
# initial number of bytes to read to get data
|
||||
sync_header_msg_length = 0
|
||||
for key, value in sync_header_msg.items():
|
||||
sync_header_msg_length = sync_header_msg_length + value
|
||||
return sync_header_msg, sync_header_msg_length
|
||||
|
||||
# Data Collection Trace Messages - General message structure - number of bytes
|
||||
def get_general_msg_header_list():
|
||||
"""
|
||||
@@ -11,8 +37,8 @@ def get_general_msg_header_list():
|
||||
msg_id (uint8) message type ID
|
||||
frame (uint16)
|
||||
slot (uint8)
|
||||
datetime_yyyymmdd (uint32)
|
||||
datetime_hhmmssmmm (uint32)
|
||||
unix_capture_ts_sec (uint32) Unix epoch seconds
|
||||
unix_capture_ts_nsec (uint32) nanoseconds [0, 999999999]
|
||||
frame_type (uint8)
|
||||
freq_range (uint8)
|
||||
subcarrier_spacing (uint8)
|
||||
@@ -46,8 +72,8 @@ def get_general_msg_header_list():
|
||||
"msg_id": 2,
|
||||
"frame": 2,
|
||||
"slot": 1,
|
||||
"datetime_yyyymmdd": 4,
|
||||
"datetime_hhmmssmmm": 4,
|
||||
"unix_capture_ts_sec": 4,
|
||||
"unix_capture_ts_nsec": 4,
|
||||
"frame_type": 1,
|
||||
"freq_range": 1,
|
||||
"subcarrier_spacing": 1,
|
||||
|
||||
348
common/utils/data_recording/lib/shared_memory_interface.py
Normal file
348
common/utils/data_recording/lib/shared_memory_interface.py
Normal file
@@ -0,0 +1,348 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# brief Shared Memory Interface for Data Recording App
|
||||
|
||||
import sysv_ipc as ipc
|
||||
import time
|
||||
import struct
|
||||
from lib import data_recording_messages_def
|
||||
import numpy as np
|
||||
from lib import common_utils
|
||||
|
||||
DEBUG_WIRELESS_RECORDED_DATA = True
|
||||
DEBUG_BUFFER_READING = False
|
||||
|
||||
# initialize shared memory
|
||||
def attach_shm(shm_path, project_id):
|
||||
key = ipc.ftok(shm_path, project_id)
|
||||
shm = ipc.SharedMemory(key, 0, 0)
|
||||
shm.attach(0, 0)
|
||||
return shm
|
||||
|
||||
|
||||
def detach_shm(shm):
|
||||
try:
|
||||
shm.detach()
|
||||
print("Shared memory detached successfully.")
|
||||
except ipc.ExistentialError:
|
||||
print("Shared memory segment does not exist.")
|
||||
|
||||
def remove_shm(shm):
|
||||
try:
|
||||
shm.remove()
|
||||
print("Shared memory removed successfully.")
|
||||
except ipc.ExistentialError:
|
||||
print("Shared memory segment does not exist.")
|
||||
|
||||
|
||||
# Write Tracer Control Message
|
||||
def write_shm(shm, args):
|
||||
# Note: Big Endian >, Little Endian <
|
||||
# Note: unsigned char B, signed char b, short h, int I, long long q
|
||||
# Note: float f, double d, string s, char c, bool ?
|
||||
# 1: config
|
||||
# 2: record
|
||||
# 3: quit
|
||||
print(f" [Shared Memory] Write action: {args.action}")
|
||||
if args.action == "config":
|
||||
# Determine the length of the IP address
|
||||
ip_length = len(args.bytes_IPaddress) + 1 # String terminator
|
||||
# Construct the format string dynamically
|
||||
format_string = f"{ip_length}s"
|
||||
shm.write(
|
||||
# Config action
|
||||
struct.pack("<B", 1) +
|
||||
struct.pack("<B", ip_length) +
|
||||
struct.pack(format_string, args.bytes_IPaddress) +
|
||||
struct.pack("<h", int(args.port))
|
||||
)
|
||||
print(f" [T-Tracer] Config: IP={args.bytes_IPaddress}, port={args.port}")
|
||||
elif args.action == "record":
|
||||
shm.write(
|
||||
# Record action
|
||||
struct.pack("<B", int(2)) +
|
||||
struct.pack("<B", args.num_requested_tracer_msgs) +
|
||||
struct.pack("<{}h".format(len(args.req_tracer_msgs_indices)),
|
||||
*args.req_tracer_msgs_indices,) +
|
||||
struct.pack("<I", args.num_records) +
|
||||
struct.pack("<h", args.start_frame_number)
|
||||
)
|
||||
print(f" [T-Tracer] Record: num_msgs={args.num_requested_tracer_msgs}, "
|
||||
f"msg_ids={args.req_tracer_msgs_indices}, "
|
||||
f"num_records={args.num_records}, "
|
||||
f"start_frame={args.start_frame_number}")
|
||||
elif args.action == "quit":
|
||||
shm.write(struct.pack("<B", int(3))) # Quit action
|
||||
print(" [T-Tracer] Quit")
|
||||
else:
|
||||
print("Unknown action for data recording system!")
|
||||
|
||||
|
||||
# write shared memory task
|
||||
def write_shm_task(barrier, shm_id, args):
|
||||
# Wait for threads to be ready
|
||||
barrier.wait()
|
||||
# send request to related T-Tracer Application
|
||||
write_shm(shm_id, args)
|
||||
|
||||
# check data if avalible in the shared memory
|
||||
def is_data_available_in_memory(shm, bufIdx, general_message_header_length, timeout=10):
|
||||
start_time = time.time()
|
||||
while True:
|
||||
buf = shm.read(bufIdx + general_message_header_length)
|
||||
# Only check bytes in the range [bufIdx, bufIdx + header_length),
|
||||
# not the entire buffer from 0 — earlier records would make sum > 0
|
||||
n_bytes = sum(buf[bufIdx:bufIdx + general_message_header_length])
|
||||
if n_bytes > 0:
|
||||
if DEBUG_BUFFER_READING:
|
||||
print("Data in memory: ", n_bytes, " bytes")
|
||||
return True
|
||||
if (time.time() - start_time) > timeout:
|
||||
break
|
||||
print("Data Recording App: Waiting for Measurements!")
|
||||
time.sleep(1)
|
||||
return False
|
||||
|
||||
# Read data from gNB T-tracer Application
|
||||
def get_frame_slot_start(shm_reading, bufIdx, general_msg_header_list,
|
||||
general_message_header_length):
|
||||
buf = shm_reading.read(bufIdx + general_message_header_length)
|
||||
msg_id = struct.unpack("<H", buf[bufIdx: bufIdx + general_msg_header_list.get("msg_id")])[0]
|
||||
bufIdx += general_msg_header_list.get("msg_id")
|
||||
frame = struct.unpack("<H", buf[bufIdx: bufIdx + general_msg_header_list.get("frame")])[0]
|
||||
bufIdx += general_msg_header_list.get("frame")
|
||||
slot = struct.unpack("B", buf[bufIdx: bufIdx + general_msg_header_list.get("slot")])[0]
|
||||
return frame, slot
|
||||
|
||||
# get MSG header Info
|
||||
def get_msg_header(shm_reading, bufIdx, sync_header_msg, sync_header_length):
|
||||
"""Read the sync header from shared memory and return msg_id, frame, slot, and timestamp.
|
||||
|
||||
Args:
|
||||
shm_reading: Shared memory handle.
|
||||
bufIdx: Current buffer index.
|
||||
sync_header_msg: Dict with field names and byte sizes (from get_sync_header_msg_list).
|
||||
sync_header_length: Total byte length of the sync header.
|
||||
|
||||
Returns:
|
||||
tuple: (msg_id, frame, slot, unix_capture_ts_sec, unix_capture_ts_nsec)
|
||||
"""
|
||||
buf = shm_reading.read(bufIdx + sync_header_length)
|
||||
offset = bufIdx
|
||||
msg_id = struct.unpack('<H', buf[offset:offset + sync_header_msg["msg_id"]])[0]
|
||||
offset += sync_header_msg["msg_id"]
|
||||
frame = struct.unpack('<H', buf[offset:offset + sync_header_msg["frame"]])[0]
|
||||
offset += sync_header_msg["frame"]
|
||||
slot = struct.unpack('B', buf[offset:offset + sync_header_msg["slot"]])[0]
|
||||
offset += sync_header_msg["slot"]
|
||||
unix_capture_ts_sec = struct.unpack('<I', buf[offset:offset + sync_header_msg["unix_capture_ts_sec"]])[0]
|
||||
offset += sync_header_msg["unix_capture_ts_sec"]
|
||||
unix_capture_ts_nsec = struct.unpack('<I', buf[offset:offset + sync_header_msg["unix_capture_ts_nsec"]])[0]
|
||||
return msg_id, frame, slot, unix_capture_ts_sec, unix_capture_ts_nsec
|
||||
|
||||
|
||||
# Get MSG ID from Shared memory
|
||||
def get_msg_id_from_shm(shm_reading, bufIdx, msg_id_length):
|
||||
buf = shm_reading.read(bufIdx + msg_id_length)
|
||||
msg_id = struct.unpack("<H", buf[bufIdx: bufIdx + msg_id_length])[0]
|
||||
return msg_id
|
||||
|
||||
# Read data from Shared memory based Data Conversion Service message structure
|
||||
def read_msg_data_from_shm(shm, bufIdx, tracer_msgs_identities):
|
||||
# read sync header to move buffer index
|
||||
# get general message header list
|
||||
general_msg_header_list, general_message_header_length = \
|
||||
data_recording_messages_def.get_general_msg_header_list()
|
||||
buf = shm.read(bufIdx + general_message_header_length)
|
||||
n_bytes = sum(buf)
|
||||
if n_bytes == 0:
|
||||
raise Exception('ERROR: No data available in memory')
|
||||
msg_id = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("msg_id")])[0]
|
||||
bufIdx += general_msg_header_list.get("msg_id")
|
||||
frame = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("frame")])[0]
|
||||
bufIdx += general_msg_header_list.get("frame")
|
||||
slot = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("slot")])[0]
|
||||
bufIdx += general_msg_header_list.get("slot")
|
||||
# get Unix capture timestamp (sec, nsec) — Unix epoch 1970
|
||||
unix_capture_ts_sec = \
|
||||
struct.unpack('<I', buf[bufIdx:bufIdx+general_msg_header_list.get("unix_capture_ts_sec")])[0]
|
||||
bufIdx += general_msg_header_list.get("unix_capture_ts_sec")
|
||||
unix_capture_ts_nsec = \
|
||||
struct.unpack('<I', buf[bufIdx:bufIdx+general_msg_header_list.get("unix_capture_ts_nsec")])[0]
|
||||
bufIdx += general_msg_header_list.get("unix_capture_ts_nsec")
|
||||
# Derive timestamp in seconds and nanoseconds (already in Unix epoch)
|
||||
timestamp_seconds = unix_capture_ts_sec
|
||||
timestamp_nseconds = unix_capture_ts_nsec
|
||||
# get frame type
|
||||
frame_type = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("frame_type")])[0]
|
||||
bufIdx += general_msg_header_list.get("frame_type")
|
||||
# get frequency range
|
||||
freq_range = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("freq_range")])[0]
|
||||
bufIdx += general_msg_header_list.get("freq_range")
|
||||
# get subcarrier spacing
|
||||
subcarrier_spacing = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("subcarrier_spacing")])[0]
|
||||
bufIdx += general_msg_header_list.get("subcarrier_spacing")
|
||||
# get cyclic prefix
|
||||
cyclic_prefix = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("cyclic_prefix")])[0]
|
||||
bufIdx += general_msg_header_list.get("cyclic_prefix")
|
||||
# get symbols per slot
|
||||
symbols_per_slot = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("symbols_per_slot")])[0]
|
||||
bufIdx += general_msg_header_list.get("symbols_per_slot")
|
||||
# get Nid cell
|
||||
Nid_cell = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("Nid_cell")])[0]
|
||||
bufIdx += general_msg_header_list.get("Nid_cell")
|
||||
# get rnti
|
||||
rnti = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("rnti")])[0]
|
||||
bufIdx += general_msg_header_list.get("rnti")
|
||||
# get rb size
|
||||
rb_size = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("rb_size")])[0]
|
||||
bufIdx += general_msg_header_list.get("rb_size")
|
||||
# get rb start
|
||||
rb_start = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("rb_start")])[0]
|
||||
bufIdx += general_msg_header_list.get("rb_start")
|
||||
# get start symbol index
|
||||
start_symbol_index = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("start_symbol_index")])[0]
|
||||
bufIdx += general_msg_header_list.get("start_symbol_index")
|
||||
# get number of symbols
|
||||
nr_of_symbols = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("nr_of_symbols")])[0]
|
||||
bufIdx += general_msg_header_list.get("nr_of_symbols")
|
||||
# get qam modulation order
|
||||
qam_mod_order = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("qam_mod_order")])[0]
|
||||
bufIdx += general_msg_header_list.get("qam_mod_order")
|
||||
# get mcs index
|
||||
mcs_index = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("mcs_index")])[0]
|
||||
bufIdx += general_msg_header_list.get("mcs_index")
|
||||
# get mcs table
|
||||
mcs_table = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("mcs_table")])[0]
|
||||
bufIdx += general_msg_header_list.get("mcs_table")
|
||||
# get number of layers
|
||||
nrOfLayers = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("nrOfLayers")])[0]
|
||||
bufIdx += general_msg_header_list.get("nrOfLayers")
|
||||
# get transform precoding
|
||||
transform_precoding = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("transform_precoding")])[0]
|
||||
bufIdx += general_msg_header_list.get("transform_precoding")
|
||||
# get dmrs config type
|
||||
dmrs_config_type = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("dmrs_config_type")])[0]
|
||||
bufIdx += general_msg_header_list.get("dmrs_config_type")
|
||||
# get ul dmrs symb pos
|
||||
ul_dmrs_symb_pos = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("ul_dmrs_symb_pos")])[0]
|
||||
bufIdx += general_msg_header_list.get("ul_dmrs_symb_pos")
|
||||
# get number dmrs symbols
|
||||
number_dmrs_symbols = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("number_dmrs_symbols")])[0]
|
||||
bufIdx += general_msg_header_list.get("number_dmrs_symbols")
|
||||
# get dmrs port
|
||||
dmrs_port = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("dmrs_port")])[0]
|
||||
bufIdx += general_msg_header_list.get("dmrs_port")
|
||||
# get dmrs scid
|
||||
dmrs_scid = struct.unpack('<H', buf[bufIdx:bufIdx+general_msg_header_list.get("dmrs_scid")])[0]
|
||||
bufIdx += general_msg_header_list.get("dmrs_scid")
|
||||
# get nb antennas rx for gNB or nb antennas tx for UE
|
||||
nb_antennas = struct.unpack('B', buf[bufIdx:bufIdx+general_msg_header_list.get("nb_antennas")])[0]
|
||||
bufIdx += general_msg_header_list.get("nb_antennas")
|
||||
# get number of bits
|
||||
number_of_bits = struct.unpack('<I', buf[bufIdx:bufIdx+general_msg_header_list.get("number_of_bits")])[0]
|
||||
bufIdx += general_msg_header_list.get("number_of_bits")
|
||||
# get length of bytes
|
||||
length_bytes = struct.unpack('<I', buf[bufIdx:bufIdx+general_msg_header_list.get("length_bytes")])[0]
|
||||
bufIdx += general_msg_header_list.get("length_bytes")
|
||||
# print all captured data
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print("\n" + "="*80)
|
||||
print(f"UL CONFIG METADATA - {tracer_msgs_identities[msg_id]}")
|
||||
print(f"Unix TS: {unix_capture_ts_sec}.{unix_capture_ts_nsec:09d} | MSG ID: {msg_id}")
|
||||
print("-"*80)
|
||||
print(f"Frame: {frame:<5} Slot: {slot:<5} Nid Cell: {Nid_cell:<5} RNTI: {rnti:<5}")
|
||||
print(f"Frame Type: {frame_type} Freq Range: {freq_range} | SCS: {subcarrier_spacing} Hz Cyclic Prefix: {cyclic_prefix} Symbols/Slot: {symbols_per_slot}")
|
||||
print("-"*80)
|
||||
print(f"RB: Start={rb_start:<4} Size={rb_size:<4} | Symbol Allocation: Start={start_symbol_index:<3} Count={nr_of_symbols:<3}")
|
||||
print(f"MCS: Index={mcs_index:<3} Table={mcs_table} | QAM Order: {qam_mod_order} Layers: {nrOfLayers} Transform Precoding: {transform_precoding}")
|
||||
print("-"*80)
|
||||
print(f"DMRS: Config Type={dmrs_config_type} Symb Pos={ul_dmrs_symb_pos} ({number_dmrs_symbols} symbols)")
|
||||
print(f" Port={dmrs_port} SCID={dmrs_scid} | Antennas: {nb_antennas}")
|
||||
print("-"*80)
|
||||
print(f"Data: {number_of_bits} bits ({length_bytes} bytes)")
|
||||
print("="*80)
|
||||
# raise exception if time stamp is zero, it means that the data is not recorded yet
|
||||
if unix_capture_ts_sec == 0 and unix_capture_ts_nsec == 0:
|
||||
raise Exception("ERROR: Time stamp is zero, data is not recorded yet or something wrong, check logs!")
|
||||
# get recorded data
|
||||
buf = shm.read(bufIdx + length_bytes)
|
||||
captured_data = {}
|
||||
# If message is bit message, store data in bytes
|
||||
# then the field number_of_bits should be not zero
|
||||
if "_BITS" in tracer_msgs_identities[msg_id]:
|
||||
recorded_data = struct.unpack("<" + int(length_bytes) * 'B', buf[bufIdx:bufIdx + length_bytes])
|
||||
bufIdx += length_bytes
|
||||
# convert data in bytes to bits
|
||||
bits_vector = []
|
||||
for byte in recorded_data:
|
||||
bits_vector.extend([int(bit) for bit in format(int(byte), '08b')])
|
||||
captured_data["sigmf_data_type"] = "ri8_le"
|
||||
# convert to uint8
|
||||
captured_data["recorded_data"] = np.asarray(bits_vector).astype(np.uint8)
|
||||
else:
|
||||
recorded_data = struct.unpack("<" + int(length_bytes/2) * 'h', buf[bufIdx:bufIdx + length_bytes])
|
||||
bufIdx += length_bytes
|
||||
# Convert real data to complext data
|
||||
# converting list to array
|
||||
recorded_data = np.asarray(recorded_data)
|
||||
recorded_data_complex = common_utils.real_to_complex(recorded_data)
|
||||
captured_data["sigmf_data_type"] = "cf32_le"
|
||||
# convert to complex64
|
||||
captured_data["recorded_data"] = recorded_data_complex.astype(np.complex64)
|
||||
# store data in dictonary
|
||||
captured_data["message_id"] = msg_id
|
||||
captured_data["message_type"] = tracer_msgs_identities[msg_id]
|
||||
captured_data["frame"] = frame
|
||||
captured_data["slot"] = slot
|
||||
captured_data["unix_capture_ts_sec"] = unix_capture_ts_sec
|
||||
captured_data["unix_capture_ts_nsec"] = unix_capture_ts_nsec
|
||||
captured_data["timestamp_seconds"] = timestamp_seconds
|
||||
captured_data["timestamp_nseconds"] = timestamp_nseconds
|
||||
captured_data["frame_type"] = frame_type
|
||||
captured_data["freq_range"] = freq_range
|
||||
captured_data["subcarrier_spacing"] = subcarrier_spacing
|
||||
captured_data["cyclic_prefix"] = cyclic_prefix
|
||||
# captured_data["symbols_per_slot"] = symbols_per_slot ... not used
|
||||
captured_data["Nid_cell"] = Nid_cell
|
||||
captured_data["rnti"] = rnti
|
||||
captured_data["rb_size"] = rb_size
|
||||
captured_data["rb_start"] = rb_start
|
||||
captured_data["start_symbol_index"] = start_symbol_index
|
||||
captured_data["nr_of_symbols"] = nr_of_symbols
|
||||
captured_data["qam_mod_order"] = qam_mod_order
|
||||
captured_data["mcs_index"] = mcs_index
|
||||
captured_data["mcs_table"] = mcs_table
|
||||
captured_data["nrOfLayers"] = nrOfLayers
|
||||
captured_data["transform_precoding"] = transform_precoding
|
||||
captured_data["dmrs_config_type"] = dmrs_config_type
|
||||
captured_data["ul_dmrs_symb_pos"] = ul_dmrs_symb_pos
|
||||
captured_data["number_dmrs_symbols"] = number_dmrs_symbols
|
||||
captured_data["dmrs_port"] = dmrs_port
|
||||
captured_data["dmrs_scid"] = dmrs_scid
|
||||
captured_data["nb_antennas"] = nb_antennas
|
||||
captured_data["number_of_bits"] = number_of_bits
|
||||
return captured_data, bufIdx
|
||||
|
||||
# Read data from Shared memory based Data Conversion Service message structure
|
||||
def read_data_from_shm(shm, bufIdx, tracer_msgs_identities):
|
||||
# print buffer index
|
||||
if DEBUG_BUFFER_READING:
|
||||
print("Buffer Index: ", bufIdx)
|
||||
# Get MSG ID by reading Sync Header
|
||||
sync_header_msg_list, sync_header_message_length = \
|
||||
data_recording_messages_def.get_sync_header_msg_list()
|
||||
msg_id_length = sync_header_msg_list.get("msg_id")
|
||||
|
||||
msg_id = get_msg_id_from_shm(shm, bufIdx, msg_id_length)
|
||||
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(f" [T-Tracer] Reading MSG ID: {msg_id} - {tracer_msgs_identities[msg_id]}")
|
||||
# Get MSG data based on Data Conversion Service message structure
|
||||
# UL IQ/bits messages (default UL data format)
|
||||
|
||||
captured_data, bufIdx = read_msg_data_from_shm(shm, bufIdx, tracer_msgs_identities)
|
||||
|
||||
return captured_data, bufIdx
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
import os
|
||||
import sigmf
|
||||
from sigmf import SigMFFile
|
||||
# from sigmf.utils import get_data_type_str
|
||||
import numpy as np
|
||||
from datetime import datetime
|
||||
import yaml
|
||||
from datetime import datetime, timezone
|
||||
from sigmf import SigMFCollection
|
||||
from .wireless_parameters_mapper import map_waveform_metadata_to_wireless_dic, derive_remaining_5gnr_metadata, STANDARDS
|
||||
from .config_interface import get_node_by_type
|
||||
|
||||
DEBUG_WIRELESS_RECORDED_DATA = True
|
||||
|
||||
"""
|
||||
SERIALIZATION_SCHEMES = {
|
||||
@@ -24,21 +25,29 @@ SERIALIZATION_SCHEMES = {
|
||||
"tx-payload-bits": ["bits", "subcarriers", "ofdm_symbols"],
|
||||
}
|
||||
"""
|
||||
STANDARDS = {"5gnr_oai": "5gnr"}
|
||||
|
||||
|
||||
def time_stamp_formating(time_stamp, datetime_offset):
|
||||
# Parse the input string into a datetime object
|
||||
time_stamp_ms_obj = datetime.strptime(time_stamp, "%Y%m%d_%H%M%S%f")
|
||||
def time_stamp_formating(unix_capture_ts_sec, unix_capture_ts_nsec, datetime_offset):
|
||||
# Convert Unix epoch (sec, nsec) to a datetime object (UTC).
|
||||
# Python datetime only supports µs, so we format the nanosecond
|
||||
# fractional part manually to preserve the full 9-digit resolution.
|
||||
dt_obj = datetime.fromtimestamp(unix_capture_ts_sec, tz=timezone.utc)
|
||||
|
||||
# Format the datetime object into the desired output format with milliseconds
|
||||
time_stamp_ms_iso = (
|
||||
time_stamp_ms_obj.strftime("%Y_%m_%dT%H:%M:%S.%f")[:-3] + datetime_offset
|
||||
# Format with nanosecond fractional seconds (9 digits)
|
||||
time_stamp_ns_iso = (
|
||||
dt_obj.strftime("%Y_%m_%dT%H:%M:%S")
|
||||
+ f".{unix_capture_ts_nsec:09d}"
|
||||
+ datetime_offset
|
||||
)
|
||||
time_stamp_ms = time_stamp_ms_iso
|
||||
time_stamp_ms_file_name = time_stamp_ms_iso.replace(":", "_").replace(".", "_")
|
||||
time_stamp_ns_file_name = time_stamp_ns_iso.replace(":", "_").replace(".", "_")
|
||||
|
||||
return time_stamp_ms, time_stamp_ms_file_name
|
||||
return time_stamp_ns_iso, time_stamp_ns_file_name
|
||||
|
||||
|
||||
def _get_node_meta_data(config_meta_data, role):
|
||||
"""Return the meta_data dict for the first node whose type matches the given type string."""
|
||||
node = get_node_by_type(config_meta_data["data_recording_config"]["nodes"], role)
|
||||
return node["meta_data"] if node else {}
|
||||
|
||||
|
||||
def create_serialization_metadata(serialization_scheme, data_source: str,
|
||||
@@ -46,6 +55,10 @@ def create_serialization_metadata(serialization_scheme, data_source: str,
|
||||
"""Creates dict that specifies the serialization metadata."""
|
||||
|
||||
# retrieve parameter from LinkSimulator config
|
||||
# if serialization_scheme empty, return empty dict, It is a meta-data only message
|
||||
if not serialization_scheme:
|
||||
return {}
|
||||
|
||||
if data_source == "5gnr_oai":
|
||||
num_ofdm_symbol = link_sim_parameters["nr_of_symbols"]
|
||||
num_subcarriers = link_sim_parameters["rb_size"] * 12
|
||||
@@ -72,131 +85,73 @@ def create_serialization_metadata(serialization_scheme, data_source: str,
|
||||
|
||||
return serialization_dict
|
||||
|
||||
|
||||
def map_metadata_to_sigmf_format(scope, waveform_generator, parameter_map_file, captured_data):
|
||||
"""
|
||||
Maps metadata from Waveform creator to API and SigMF format.
|
||||
The used parameters and the mapping pairs are specified in a separate YAML file
|
||||
that must be provided as well.
|
||||
"""
|
||||
# read waveform parameter map from yaml file
|
||||
dir_path = os.path.dirname(__file__)
|
||||
src_path = os.path.split(dir_path)[0]
|
||||
|
||||
with open(os.path.join(src_path, parameter_map_file), "r") as file:
|
||||
parameter_map_dic = yaml.load(file, Loader=yaml.Loader)
|
||||
# preallocate target dict
|
||||
sigmf_metadata_dict = {}
|
||||
|
||||
# get standard and name of generator
|
||||
standard_key = parameter_map_dic["waveform_generator"][waveform_generator]
|
||||
generator = standard_key["generator"]
|
||||
|
||||
if scope == "tx":
|
||||
parameter_map_dic = parameter_map_dic["transmitter"][
|
||||
STANDARDS[waveform_generator]
|
||||
]
|
||||
elif scope == "channel":
|
||||
parameter_map_dic = parameter_map_dic["channel"]
|
||||
elif scope == "rx":
|
||||
parameter_map_dic = parameter_map_dic["receiver"]
|
||||
else:
|
||||
raise Exception(
|
||||
f"Invalid mapping scope '{scope}'! Only 'tx', 'channel' and 'rx' are valid!"
|
||||
)
|
||||
|
||||
# check if standard key is given
|
||||
if parameter_map_dic is None:
|
||||
raise Exception(
|
||||
"Invalid standard key: "
|
||||
"Name should be corrected or added to wireless_link_parameter_map.yaml, given: "
|
||||
f"{waveform_generator}"
|
||||
)
|
||||
|
||||
for parameter_pair in parameter_map_dic:
|
||||
# check if key for chosen simulator even exists
|
||||
if waveform_generator + "_parameter" in parameter_pair.keys():
|
||||
# only continue with mapping from file if direct equivalent exists
|
||||
if parameter_pair[waveform_generator + "_parameter"]["name"]:
|
||||
# It is not necessary to get all parameters from wireless_link_parameter_map.yaml
|
||||
# in captured_data since some parameters related to DL or UL only
|
||||
if (parameter_pair[waveform_generator + "_parameter"]["name"] in captured_data.keys()):
|
||||
# extract value from waveform config source
|
||||
value = captured_data[
|
||||
parameter_pair[waveform_generator + "_parameter"]["name"]]
|
||||
# additional mapping if parameter values should come from a discrete set of values
|
||||
if ("value_map" in parameter_pair[waveform_generator + "_parameter"].keys()):
|
||||
value = parameter_pair[waveform_generator + "_parameter"]["value_map"][value]
|
||||
# write to target dictionary for SigMF
|
||||
sigmf_metadata_dict[parameter_pair["sigmf_parameter_name"]] = value
|
||||
else:
|
||||
raise Exception(
|
||||
f"Incomplete specification in field '{waveform_generator}_parameter'!")
|
||||
# else: # fill_non_explicit_fields
|
||||
# waveform_config[parameter_pair["sigmf_parameter_name"]] = "none"
|
||||
if not sigmf_metadata_dict:
|
||||
raise Exception(
|
||||
"""ERROR: Check captured meta-data or provided config and meta data """)
|
||||
|
||||
# check for non-JSON-serializable data types
|
||||
def isfloat(NumberString):
|
||||
try:
|
||||
float(NumberString)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
for key, value in sigmf_metadata_dict.items():
|
||||
if isinstance(value, np.integer):
|
||||
sigmf_metadata_dict[key] = int(value)
|
||||
elif isinstance(value, (np.float16, np.float32, np.float64)):
|
||||
sigmf_metadata_dict[key] = np.format_float_positional(value, trim="-")
|
||||
elif isinstance(value, int):
|
||||
sigmf_metadata_dict[key] = int(value)
|
||||
elif isinstance(value, float):
|
||||
# store value in decimal and not in scientific notation
|
||||
sigmf_metadata_dict[key] = float(value)
|
||||
elif isinstance(value, str) and key != "standard":
|
||||
# convert string to lower case
|
||||
sigmf_metadata_dict[key] = value.lower()
|
||||
if isfloat(value):
|
||||
if value.isdigit():
|
||||
sigmf_metadata_dict[key] = int(float(value))
|
||||
elif value.replace(".", "", 1).isdigit() and value.count(".") < 2:
|
||||
sigmf_metadata_dict[key] = float(value)
|
||||
|
||||
return sigmf_metadata_dict, generator
|
||||
|
||||
|
||||
def create_system_components_metadata(waveform_generator, parameter_map_file, captured_data):
|
||||
# map OAI config data to Wireless Dictionary Parameter Map - SigMF metadata
|
||||
def create_system_components_metadata(captured_data, config_meta_data):
|
||||
"""Creates system components (TX, channel, RX) metadata that will reside in the annotations."""
|
||||
# map metadata of waveform generator to SigMF format
|
||||
signal_info, generator = map_metadata_to_sigmf_format(
|
||||
"tx", waveform_generator, parameter_map_file, captured_data
|
||||
)
|
||||
|
||||
# map OAI config data to Wireless Dictionary Parameter Map - SigMF metadata
|
||||
waveform_generator = config_meta_data["data_recording_config"]["global_info"][
|
||||
"waveform_generator"]
|
||||
parameter_map_file = config_meta_data["data_recording_config"]["parameter_map_file"]
|
||||
|
||||
# map metadata of waveform generator to Wireless Dictionary Parameter Map - SigMF metadata
|
||||
signal_metadata, generator = map_waveform_metadata_to_wireless_dic(
|
||||
"tx", waveform_generator, parameter_map_file, captured_data)
|
||||
|
||||
# derive remaining Signal metadata
|
||||
signal_metadata = derive_remaining_5gnr_metadata(captured_data, signal_metadata)
|
||||
|
||||
tx_metadata = {
|
||||
"signal:detail": {
|
||||
"standard": STANDARDS[waveform_generator],
|
||||
"generator": generator,
|
||||
STANDARDS[waveform_generator]: signal_info,
|
||||
STANDARDS[waveform_generator]: signal_metadata,
|
||||
}
|
||||
}
|
||||
|
||||
channel_metadata = {} # will be filled later
|
||||
rx_metadata = {} # will be filled later
|
||||
|
||||
return tx_metadata, channel_metadata, rx_metadata
|
||||
# get meta data from config file
|
||||
base_station_meta_data = _get_node_meta_data(config_meta_data, "gnb")
|
||||
user_equipment_meta_data = _get_node_meta_data(config_meta_data, "ue")
|
||||
|
||||
# Set number of antennas based on link direction and captured side
|
||||
# Find number of antennas from global info on other side of the link
|
||||
if "UL" in captured_data["message_type"]:
|
||||
# On UE side, It is TX antennas
|
||||
# On gNB side, It is RX antennas
|
||||
if "UE" in captured_data["message_type"]:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"num_tx_antennas"] = captured_data["nb_antennas"]
|
||||
rx_metadata.update({"num_rx_antennas": base_station_meta_data["num_rx_antennas"]})
|
||||
else:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"num_tx_antennas"] = user_equipment_meta_data["num_tx_antennas"]
|
||||
rx_metadata.update({"num_rx_antennas": captured_data["nb_antennas"]})
|
||||
|
||||
if "DL" in captured_data["message_type"]:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"link_direction"] = "downlink"
|
||||
# On UE side, It is RX antennas
|
||||
# On gNB side, It is TX antennasr
|
||||
if "UE" in captured_data["message_type"]:
|
||||
rx_metadata["signal:detail"][STANDARDS[waveform_generator]]["num_rx_antennas"] = \
|
||||
captured_data["nb_antennas"] ## TO DO check key name: no DL message from UE yet
|
||||
tx_metadata.update({"num_tx_antennas": base_station_meta_data["num_tx_antennas"]})
|
||||
else:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"num_tx_antennas"] = captured_data["nrOfLayers"]
|
||||
rx_metadata.update({"num_rx_antennas": user_equipment_meta_data["num_rx_antennas"]})
|
||||
return tx_metadata, channel_metadata, rx_metadata
|
||||
|
||||
def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, idx):
|
||||
"""
|
||||
Compiles and saves provided data and metadata into SigMF file format.
|
||||
"""
|
||||
# get meta data from config file
|
||||
base_station_meta_data = config_meta_data["data_recording_config"]["base_station"][
|
||||
"meta_data"]
|
||||
user_equipment_meta_data = config_meta_data["data_recording_config"][
|
||||
"user_equipment"]["meta_data"]
|
||||
base_station_meta_data = _get_node_meta_data(config_meta_data, "gnb")
|
||||
user_equipment_meta_data = _get_node_meta_data(config_meta_data, "ue")
|
||||
|
||||
# Check the receive target path is valid, else create folder
|
||||
data_storage_path = config_meta_data["data_recording_config"]["data_storage_path"]
|
||||
@@ -206,111 +161,34 @@ def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, i
|
||||
|
||||
# Write recorded data to file
|
||||
# Get time stamp
|
||||
time_stamp_ms, time_stamp_ms_file_name = time_stamp_formating(
|
||||
captured_data["time_stamp"], global_info["datetime_offset"])
|
||||
time_stamp, time_stamp_file_name = time_stamp_formating(
|
||||
captured_data["unix_capture_ts_sec"], captured_data["unix_capture_ts_nsec"],
|
||||
global_info["datetime_offset"])
|
||||
# Map OAI Message Name to SigMF Message Name
|
||||
file_name_prefix = config_meta_data["data_recording_config"][
|
||||
"supported_oai_tracer_messages"][captured_data["message_type"]]["file_name_prefix"]
|
||||
recorded_data_file_name = (
|
||||
file_name_prefix + "-rec-" + str(idx) + "-" + time_stamp_ms_file_name)
|
||||
file_name_prefix + "-rec-" + str(idx) + "-" + time_stamp_file_name)
|
||||
|
||||
dataset_filename = recorded_data_file_name + ".sigmf-data"
|
||||
dataset_file_path = os.path.join(data_storage_path, dataset_filename)
|
||||
print(dataset_file_path)
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(dataset_file_path)
|
||||
captured_data["recorded_data"].tofile(dataset_file_path)
|
||||
|
||||
# map OAI config data to SigMF metadata
|
||||
# ----------------------------------------------------
|
||||
# map OAI config data to Wireless Dictionary Parameter Map - SigMF metadata
|
||||
waveform_generator = config_meta_data["data_recording_config"]["global_info"][
|
||||
"waveform_generator"]
|
||||
parameter_map_file = config_meta_data["data_recording_config"]["parameter_map_file"]
|
||||
tx_metadata, channel_metadata, rx_metadata = create_system_components_metadata(
|
||||
waveform_generator, parameter_map_file, captured_data)
|
||||
|
||||
# Add other OAI metadata to SigMF metadata
|
||||
# ----------------------------------------------------
|
||||
# Set 1: Parameters needs to be derived from OAI message
|
||||
# ----------------------------------------------------
|
||||
# PUSCH DMRS: OFDM symbol start index within slot
|
||||
get_pusch_dmrs_start_ofdm_symbol = 0
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch_dmrs:ofdm_symbol_idx"] = []
|
||||
|
||||
for symbol in range(captured_data["start_symbol_index"],
|
||||
captured_data["start_symbol_index"] + captured_data["nr_of_symbols"]):
|
||||
|
||||
dmrs_symbol_flag = (captured_data["ul_dmrs_symb_pos"] >> symbol) & 0x01
|
||||
if dmrs_symbol_flag and not get_pusch_dmrs_start_ofdm_symbol:
|
||||
get_pusch_dmrs_start_ofdm_symbol = 1
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch_dmrs:start_ofdm_symbol"] = symbol
|
||||
if dmrs_symbol_flag:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch_dmrs:ofdm_symbol_idx"].append(symbol) # Append symbol to the list
|
||||
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch_dmrs:duration_num_ofdm_symbols"] = 1
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch_dmrs:num_add_positions"] = (captured_data["number_dmrs_symbols"] - 1)
|
||||
|
||||
# If the message is a BIT message, add number of bits to the signal info
|
||||
# "UE_PHY_UL_SCRAMBLED_TX_BITS", "GNB_PHY_UL_PAYLOAD_RX_BITS", "UE_PHY_UL_PAYLOAD_TX_BITS"
|
||||
if "_BITS" in captured_data["message_type"]:
|
||||
# if "BIT" in captured_data["message_type"]:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]]["num_bits"] = (
|
||||
captured_data["number_of_bits"])
|
||||
|
||||
# If the message is captured from UE, it is UPLink message,
|
||||
# so number of antennas is num of Tx antennas
|
||||
# number of antennas on Rx side should be read from global_info given by user
|
||||
if "UE" in captured_data["message_type"]:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"num_tx_antennas"
|
||||
] = captured_data["nb_antennas"]
|
||||
rx_metadata.update(
|
||||
{"num_rx_antennas": base_station_meta_data["num_rx_antennas"]}
|
||||
)
|
||||
# If the message is captured from gNB, it is UPLink message,
|
||||
# so number of antennas is num of Rx antennas
|
||||
# number of antennas on Tx side should be read from global_info given by user
|
||||
else:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"num_tx_antennas"] = user_equipment_meta_data["num_tx_antennas"]
|
||||
rx_metadata.update({"num_rx_antennas": captured_data["nb_antennas"]})
|
||||
|
||||
# Check if the message type contains "UL"
|
||||
if "UL" in captured_data["message_type"]:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"link_direction"] = "uplink"
|
||||
else:
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"link_direction"] = "downlink"
|
||||
# ----------------------------------------------------
|
||||
# Set 2: Parameters that is hardcoded
|
||||
# ----------------------------------------------------
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch:content"] = "compliant"
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch:mapping_type"] = "B"
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]]["num_slots"] = 1
|
||||
if config_meta_data["test_config"]["test_mode"] == "rf_simulation":
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch:payload_bit_pattern"] = "random"
|
||||
elif config_meta_data["test_config"]["test_mode"] == "rf_real_time":
|
||||
tx_metadata["signal:detail"][STANDARDS[waveform_generator]][
|
||||
"pusch:payload_bit_pattern"] = "zeros"
|
||||
else:
|
||||
raise Exception("ERROR: Test mode is not supported in SigMF formatting")
|
||||
tx_metadata, channel_metadata, rx_metadata = create_system_components_metadata(captured_data, config_meta_data)
|
||||
|
||||
# ----------------------------------------------------
|
||||
# Read mean parameters
|
||||
freq = config_meta_data["environment_emulation"]["target_link_config"][
|
||||
"wireless_channel"]["carrierFreqValueList_hz"][0]
|
||||
bandwidth = config_meta_data["data_recording_config"]["common_meta_data"][
|
||||
"bandwidth"]
|
||||
# used_signal_bandwidth = (
|
||||
# pow(10, 6) * config_meta_data["environment_emulation"]["target_link_config"]["ran_config"][
|
||||
# "uplink"]["ul_used_signal_BW_MHz"])
|
||||
sample_rate = config_meta_data["data_recording_config"]["common_meta_data"][
|
||||
"sample_rate"]
|
||||
sample_rate = config_meta_data["data_recording_config"]["common_meta_data"]["sample_rate"]
|
||||
|
||||
# get signal emitter info
|
||||
signal_emitter = {
|
||||
@@ -322,23 +200,14 @@ def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, i
|
||||
"sample_rate": sample_rate,
|
||||
"bandwidth": bandwidth,
|
||||
"gain_tx": user_equipment_meta_data["tx_gain"],
|
||||
"clock_reference": config_meta_data["data_recording_config"][
|
||||
"common_meta_data"
|
||||
]["clock_reference"],
|
||||
"clock_reference": config_meta_data["data_recording_config"]["common_meta_data"]["clock_reference"],
|
||||
}
|
||||
|
||||
# ----------------------------------------------------
|
||||
# get channel metadata
|
||||
# ----------------------------------------------------
|
||||
# get downlink channel info
|
||||
# ch_downlink_config = config_meta_data["environment_emulation"]["target_link_config"]["wireless_channel"]["downlink"]
|
||||
# ch_downlink ={"channel_model": ch_downlink_config["type"]}
|
||||
|
||||
# ch_downlink_model = {"channel_model": "AWGN"}
|
||||
# get uplink channel info
|
||||
ch_uplink_config = config_meta_data["environment_emulation"]["target_link_config"][
|
||||
"wireless_channel"
|
||||
]["uplink"]
|
||||
ch_uplink_config = config_meta_data["environment_emulation"]["target_link_config"]["wireless_channel"]["uplink"]
|
||||
# Real Time RF Emulation
|
||||
if config_meta_data["test_config"]["test_mode"] == "rf_real_time":
|
||||
channel_metadata.update({"emulation_mode": "ni rf real time"})
|
||||
@@ -346,7 +215,7 @@ def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, i
|
||||
channel_metadata.update(
|
||||
{
|
||||
"channel_model": ch_uplink_config["statistical"]["predef_channel_profile"],
|
||||
"snr_esn0_db": ch_uplink_config["statistical"]["snr_db"],
|
||||
"snr_esn0_db": ch_uplink_config["statistical"]["snr_db"],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -361,6 +230,7 @@ def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, i
|
||||
)
|
||||
else:
|
||||
raise Exception("ERROR: channel type is not supported in SigMF formatting")
|
||||
|
||||
# RF Simulation
|
||||
elif config_meta_data["test_config"]["test_mode"] == "rf_simulation":
|
||||
channel_metadata.update({"emulation_mode": "oai rf simulation"})
|
||||
@@ -397,16 +267,6 @@ def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, i
|
||||
],
|
||||
}
|
||||
)
|
||||
# ----------------------------------------------------
|
||||
# get test config
|
||||
# ----------------------------------------------------
|
||||
"""
|
||||
test_config = {
|
||||
"test_name": config_meta_data["test_config"]["test_name"],
|
||||
"test_mode": config_meta_data["test_config"]["test_mode"],
|
||||
"dut_type": config_meta_data["test_config"]["dut_type"],
|
||||
}
|
||||
"""
|
||||
# Create sigmf metadata
|
||||
# ----------------------
|
||||
# Add global parameters to SigMF metadata
|
||||
@@ -439,10 +299,9 @@ def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, i
|
||||
# Add capture parameters to SigMF metadata
|
||||
# ----------------------
|
||||
serialization_scheme = config_meta_data["data_recording_config"][
|
||||
"supported_oai_tracer_messages"
|
||||
][captured_data["message_type"]]["serialization_scheme"]
|
||||
"supported_oai_tracer_messages"][captured_data["message_type"]]["serialization_scheme"]
|
||||
capture_metadata = {
|
||||
sigmf.SigMFFile.DATETIME_KEY: time_stamp_ms,
|
||||
sigmf.SigMFFile.DATETIME_KEY: time_stamp,
|
||||
SigMFFile.FREQUENCY_KEY: freq,
|
||||
**create_serialization_metadata(
|
||||
serialization_scheme, waveform_generator, captured_data
|
||||
@@ -486,7 +345,8 @@ def write_recorded_data_to_sigmf(captured_data, config_meta_data, global_info, i
|
||||
dataset_meta_file_path = os.path.join(data_storage_path, dataset_meta_filename)
|
||||
meta.tofile(dataset_meta_file_path) # extension is optional
|
||||
|
||||
print(dataset_meta_file_path)
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print(dataset_meta_file_path)
|
||||
|
||||
return dataset_meta_file_path
|
||||
|
||||
@@ -513,8 +373,9 @@ def save_sigmf_collection(streams: list, global_info: dict, description: str, st
|
||||
|
||||
# save collection file
|
||||
collection.tofile(collection_filepath)
|
||||
print("")
|
||||
print(collection_filepath + ".sigmf-collection")
|
||||
if DEBUG_WIRELESS_RECORDED_DATA:
|
||||
print("")
|
||||
print(collection_filepath + ".sigmf-collection")
|
||||
|
||||
|
||||
def load_sigmf(filename: str, storage_path: str, scope: str):
|
||||
@@ -536,7 +397,7 @@ def load_sigmf(filename: str, storage_path: str, scope: str):
|
||||
annotation_length = annotations_metadata[0][sigmf.SigMFFile.LENGTH_INDEX_KEY]
|
||||
|
||||
# get capture metadata
|
||||
capture_metadata = signal.get_capture_info(annotation_start_idx)
|
||||
#capture_metadata = signal.get_capture_info(annotation_start_idx)
|
||||
|
||||
# from source code: sigmffile.py
|
||||
# "autoscale : bool, default True
|
||||
@@ -551,4 +412,4 @@ def load_sigmf(filename: str, storage_path: str, scope: str):
|
||||
data = signal.read_samples(
|
||||
annotation_start_idx, annotation_length, autoscale=False, raw_components=True)
|
||||
|
||||
return data, global_metadata, annotations_metadata
|
||||
return data, global_metadata, annotations_metadata
|
||||
@@ -1,12 +1,10 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# brief Sync service between captured Data from 5GNR gNB and UE
|
||||
# brief Sync service between captured Data from 5G NR gNB and UE
|
||||
|
||||
import struct
|
||||
from lib import data_recording_messages_def
|
||||
|
||||
DEBUG_POW_MEAS_SYNC = True
|
||||
from lib import shared_memory_interface
|
||||
|
||||
|
||||
# check if first frame ahead:
|
||||
@@ -29,34 +27,55 @@ def is_frame_ahead(frame1, frame2, max_frame=1023):
|
||||
|
||||
|
||||
# find the frame and slot start
|
||||
def find_frame_slot_start(dataset1_start, dataset2_start):
|
||||
def find_frame_slot_start(dataset1_start_info, dataset2_start_info, is_dataset2_pow_monitoring):
|
||||
"""
|
||||
Function to find the frame and slot start for data sync
|
||||
Args:
|
||||
dataset1_start_info: Dictionary containing the start information of dataset1
|
||||
dataset2_start_info: Dictionary containing the start information of dataset2
|
||||
is_dataset2_pow_monitoring: Boolean indicating if dataset2 is pow monitoring
|
||||
Returns:
|
||||
sync_info: Dictionary containing the sync information
|
||||
sync_info["frame"] = frame_start
|
||||
sync_info["slot"] = slot_start
|
||||
Note: if is_dataset2_pow_monitoring is true, then the slot start is taken from dataset1
|
||||
Since the pow monitoring is capturing all slots while the gNB and UE are capturing only data slots
|
||||
|
||||
"""
|
||||
sync_info = {}
|
||||
|
||||
if dataset1_start["frame"] == dataset2_start["frame"]:
|
||||
if dataset1_start_info["frame"] == dataset2_start_info["frame"] :
|
||||
frame_diff = 0
|
||||
frame_start = dataset1_start["frame"]
|
||||
slot_start = max(dataset1_start["slot"], dataset2_start["slot"])
|
||||
frame_start = dataset1_start_info["frame"]
|
||||
if is_dataset2_pow_monitoring:
|
||||
if dataset1_start_info["slot"] >= dataset2_start_info["slot"]:
|
||||
slot_start = dataset1_start_info["slot"]
|
||||
elif dataset1_start_info["slot"] < dataset2_start_info["slot"]:
|
||||
# Go to next frame and use data slot as reference
|
||||
frame_start = (frame_start + 1) % 1024
|
||||
# Use the slot from dataset1 as reference
|
||||
slot_start = dataset1_start_info["slot"]
|
||||
else:
|
||||
slot_start = max(dataset1_start_info["slot"], dataset2_start_info["slot"])
|
||||
|
||||
elif is_frame_ahead(dataset1_start["frame"], dataset2_start["frame"]):
|
||||
frame_start = dataset1_start["frame"]
|
||||
slot_start = dataset1_start["slot"]
|
||||
frame_diff = (dataset1_start["frame"]- dataset2_start["frame"] + 1024) % 1024
|
||||
elif is_frame_ahead(dataset2_start["frame"], dataset1_start["frame"]):
|
||||
frame_start = dataset2_start["frame"]
|
||||
slot_start = dataset2_start["slot"]
|
||||
frame_diff = (dataset2_start["frame"] - dataset1_start["frame"] + 1024) % 1024
|
||||
# check first if the delta time between the two datasets is larger than expected offset time.
|
||||
elif is_frame_ahead(dataset1_start_info["frame"], dataset2_start_info["frame"]):
|
||||
frame_start = dataset1_start_info["frame"]
|
||||
slot_start = dataset1_start_info["slot"]
|
||||
frame_diff = (dataset1_start_info["frame"]- dataset2_start_info["frame"] + 1024) % 1024
|
||||
elif is_frame_ahead(dataset2_start_info["frame"], dataset1_start_info["frame"]):
|
||||
frame_start = dataset2_start_info["frame"]
|
||||
if is_dataset2_pow_monitoring:
|
||||
if dataset1_start_info["slot"] >= dataset2_start_info["slot"]:
|
||||
slot_start = dataset1_start_info["slot"]
|
||||
elif dataset1_start_info["slot"] < dataset2_start_info["slot"]:
|
||||
# Go to next frame and use data slot as reference
|
||||
frame_start = (frame_start + 1) % 1024
|
||||
# Use the slot from dataset1 as reference
|
||||
slot_start = dataset1_start_info["slot"]
|
||||
else:
|
||||
slot_start = dataset2_start_info["slot"]
|
||||
frame_diff = (dataset2_start_info["frame"] - dataset1_start_info["frame"] + 1024) % 1024
|
||||
# check first if the delta time between the two datasets is larger than expected offset time.
|
||||
# So, the sync will not be applied
|
||||
# check during the calculation of the frame the ramp-around from 1023 to 0
|
||||
if abs(frame_diff) > 6:
|
||||
@@ -70,54 +89,34 @@ def find_frame_slot_start(dataset1_start, dataset2_start):
|
||||
sync_info["slot"] = slot_start
|
||||
return sync_info
|
||||
|
||||
# Sync data across N NR tracer nodes
|
||||
def sync_multiple_nr_nodes(node_shm_readings):
|
||||
"""Sync frame/slot across N NR tracer nodes.
|
||||
|
||||
# Read data from gNB T-tracer Application
|
||||
def get_frame_slot_start(shm_reading, bufIdx, general_msg_header_list,
|
||||
general_message_header_length):
|
||||
buf = shm_reading.read(bufIdx + general_message_header_length)
|
||||
msg_id = struct.unpack("<H", buf[bufIdx: bufIdx + general_msg_header_list.get("msg_id")])[0]
|
||||
bufIdx += general_msg_header_list.get("msg_id")
|
||||
frame = struct.unpack("<H", buf[bufIdx: bufIdx + general_msg_header_list.get("frame")])[0]
|
||||
bufIdx += general_msg_header_list.get("frame")
|
||||
slot = struct.unpack("B", buf[bufIdx: bufIdx + general_msg_header_list.get("slot")])[0]
|
||||
return frame, slot
|
||||
|
||||
|
||||
# Sync data between gNB and UE
|
||||
def sync_gnb_ue_captured_data(shm_reading_gnb, shm_reading_ue):
|
||||
"""
|
||||
Function to get the sync (frame, slot) data between gNB and UE
|
||||
Args:
|
||||
shm_reading_gnb: Shared memory for gNB
|
||||
shm_reading_ue: Shared memory for UE
|
||||
Returns:
|
||||
sync_info: Dictionary containing the sync information between gNB and UE
|
||||
sync_info["frame"] = frame_start
|
||||
sync_info["slot"] = slot_start
|
||||
"""
|
||||
# get general message header list
|
||||
general_msg_header_list, general_message_header_length = (
|
||||
data_recording_messages_def.get_general_msg_header_list())
|
||||
node_shm_readings: dict {node_id: shm_reading}
|
||||
|
||||
# Read data from gNB T-tracer Application
|
||||
bufIdx = 0
|
||||
frame_gnb, slot_gnb = get_frame_slot_start(
|
||||
shm_reading_gnb, bufIdx, general_msg_header_list, general_message_header_length)
|
||||
# Read data from UE T-tracer Application
|
||||
bufIdx = 0
|
||||
frame_ue, slot_ue = get_frame_slot_start(
|
||||
shm_reading_ue, bufIdx, general_msg_header_list, general_message_header_length)
|
||||
dataset1_start = {}
|
||||
dataset1_start["frame"] = frame_gnb
|
||||
dataset1_start["slot"] = slot_gnb
|
||||
dataset2_start = {}
|
||||
dataset2_start["frame"] = frame_ue
|
||||
dataset2_start["slot"] = slot_ue
|
||||
# Sync data between gNB and UE
|
||||
# We noticed that the maximum difference between the frame number of gNB and UE is 3 frames
|
||||
# Calculate the frame difference considering the wrap-around from 1023 to 0
|
||||
sync_info = find_frame_slot_start(dataset1_start, dataset2_start)
|
||||
print(" gNB Start info: ", dataset1_start)
|
||||
print(" UE Start info: ", dataset2_start)
|
||||
print(" gNB and UE Sync info: ", sync_info)
|
||||
Returns:
|
||||
sync_info: dict with 'frame' and 'slot' of the common sync point
|
||||
"""
|
||||
sync_header_msg, sync_header_msg_length = (
|
||||
data_recording_messages_def.get_sync_header_msg_list())
|
||||
|
||||
# Get frame/slot from each node
|
||||
node_start_infos = {}
|
||||
for node_id, shm_reading in node_shm_readings.items():
|
||||
frame, slot = shared_memory_interface.get_frame_slot_start(
|
||||
shm_reading, 0, sync_header_msg, sync_header_msg_length)
|
||||
node_start_infos[node_id] = {"frame": frame, "slot": slot}
|
||||
print(f" [NR Node Sync] {node_id} start: frame={frame}, slot={slot}")
|
||||
|
||||
# Find the latest common frame/slot by pairwise comparison
|
||||
node_ids = list(node_start_infos.keys())
|
||||
sync_info = node_start_infos[node_ids[0]]
|
||||
for i in range(1, len(node_ids)):
|
||||
sync_info = find_frame_slot_start(sync_info, node_start_infos[node_ids[i]],
|
||||
is_dataset2_pow_monitoring=False)
|
||||
|
||||
print(f" [NR Node Sync] Multi-node sync point: frame={sync_info['frame']}, slot={sync_info['slot']}")
|
||||
return sync_info
|
||||
|
||||
|
||||
189
common/utils/data_recording/lib/wireless_parameters_mapper.py
Normal file
189
common/utils/data_recording/lib/wireless_parameters_mapper.py
Normal file
@@ -0,0 +1,189 @@
|
||||
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
|
||||
# ---------------------------------------------------------------------
|
||||
# brief Wireless parameters mapper to map captured parameters from waveform generator to API and SigMF format based on a mapping specification in a YAML file.
|
||||
# It also includes functions to derive other parameters that are not directly captured but can be derived from the captured parameters.
|
||||
import os
|
||||
import numpy as np
|
||||
import yaml
|
||||
|
||||
STANDARDS = {"5gnr_oai": "5gnr"}
|
||||
|
||||
|
||||
def map_waveform_metadata_to_wireless_dic(scope, waveform_generator, parameter_map_file, captured_data):
|
||||
"""
|
||||
Maps metadata from Waveform creator to API and SigMF format.
|
||||
The used parameters and the mapping pairs are specified in a separate YAML file
|
||||
that must be provided as well.
|
||||
"""
|
||||
# read waveform parameter map from yaml file
|
||||
dir_path = os.path.dirname(__file__)
|
||||
src_path = os.path.split(dir_path)[0]
|
||||
|
||||
with open(os.path.join(src_path, parameter_map_file), "r") as file:
|
||||
parameter_map_dic = yaml.load(file, Loader=yaml.Loader)
|
||||
# preallocate target dict
|
||||
signal_metadata = {}
|
||||
|
||||
# get standard and name of generator
|
||||
standard_key = parameter_map_dic["waveform_generator"][waveform_generator]
|
||||
generator = standard_key["generator"]
|
||||
|
||||
if scope == "tx":
|
||||
parameter_map_dic = parameter_map_dic["transmitter"][
|
||||
STANDARDS[waveform_generator]
|
||||
]
|
||||
elif scope == "channel":
|
||||
parameter_map_dic = parameter_map_dic["channel"]
|
||||
elif scope == "rx":
|
||||
parameter_map_dic = parameter_map_dic["receiver"]
|
||||
else:
|
||||
raise Exception(
|
||||
f"Invalid mapping scope '{scope}'! Only 'tx', 'channel' and 'rx' are valid!"
|
||||
)
|
||||
|
||||
# check if standard key is given
|
||||
if parameter_map_dic is None:
|
||||
raise Exception(
|
||||
"Invalid standard key: "
|
||||
"Name should be corrected or added to wireless_link_parameter_map.yaml, given: "
|
||||
f"{waveform_generator}"
|
||||
)
|
||||
|
||||
for parameter_pair in parameter_map_dic:
|
||||
# check if key for chosen simulator even exists
|
||||
if waveform_generator + "_parameter" in parameter_pair.keys():
|
||||
# only continue with mapping from file if direct equivalent exists
|
||||
if parameter_pair[waveform_generator + "_parameter"]["name"]:
|
||||
# It is not necessary to get all parameters from wireless_link_parameter_map.yaml
|
||||
# in captured_data since some parameters related to DL or UL only
|
||||
if (parameter_pair[waveform_generator + "_parameter"]["name"] in captured_data.keys()):
|
||||
# extract value from waveform config source
|
||||
value = captured_data[
|
||||
parameter_pair[waveform_generator + "_parameter"]["name"]]
|
||||
# additional mapping if parameter values should come from a discrete set of values
|
||||
if ("value_map" in parameter_pair[waveform_generator + "_parameter"].keys()):
|
||||
value = parameter_pair[waveform_generator + "_parameter"]["value_map"][value]
|
||||
# write to target dictionary for SigMF
|
||||
signal_metadata[parameter_pair["sigmf_parameter_name"]] = value
|
||||
else:
|
||||
raise Exception(
|
||||
f"Incomplete specification in field '{waveform_generator}_parameter'!")
|
||||
if not signal_metadata:
|
||||
raise Exception(
|
||||
"""ERROR: Check captured meta-data or provided config and meta data """)
|
||||
|
||||
# check for non-JSON-serializable data types
|
||||
def isfloat(NumberString):
|
||||
try:
|
||||
float(NumberString)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
for key, value in signal_metadata.items():
|
||||
if isinstance(value, np.integer):
|
||||
signal_metadata[key] = int(value)
|
||||
elif isinstance(value, (np.float16, np.float32, np.float64)):
|
||||
signal_metadata[key] = np.format_float_positional(value, trim="-")
|
||||
elif isinstance(value, int):
|
||||
signal_metadata[key] = int(value)
|
||||
elif isinstance(value, float):
|
||||
# store value in decimal and not in scientific notation
|
||||
signal_metadata[key] = float(value)
|
||||
elif isinstance(value, str) and key != "standard":
|
||||
# convert string to lower case
|
||||
signal_metadata[key] = value.lower()
|
||||
if isfloat(value):
|
||||
if value.isdigit():
|
||||
signal_metadata[key] = int(float(value))
|
||||
elif value.replace(".", "", 1).isdigit() and value.count(".") < 2:
|
||||
signal_metadata[key] = float(value)
|
||||
|
||||
return signal_metadata, generator
|
||||
|
||||
|
||||
# Derive other Signal metadata from captured metadata
|
||||
def derive_remaining_5gnr_metadata(captured_data, signal_metadata):
|
||||
# Add other OAI metadata to Wireless Dictionary Parameter Map - SigMF metadata
|
||||
# ----------------------------------------------------
|
||||
# Set 1: Parameters needs to be derived from OAI message
|
||||
# ----------------------------------------------------
|
||||
# DMRS Info:
|
||||
# Check if the message type contains "UL"
|
||||
if "UL" in captured_data["message_type"]:
|
||||
# PUSCH DMRS: OFDM symbol start index within slot
|
||||
get_pusch_dmrs_start_ofdm_symbol = 0
|
||||
signal_metadata["pusch_dmrs:ofdm_symbol_idx"] = []
|
||||
|
||||
for symbol in range(captured_data["start_symbol_index"],
|
||||
captured_data["start_symbol_index"] + captured_data["nr_of_symbols"]):
|
||||
|
||||
dmrs_symbol_flag = (captured_data["ul_dmrs_symb_pos"] >> symbol) & 0x01
|
||||
if dmrs_symbol_flag and not get_pusch_dmrs_start_ofdm_symbol:
|
||||
get_pusch_dmrs_start_ofdm_symbol = 1
|
||||
signal_metadata["pusch_dmrs:start_ofdm_symbol"] = symbol
|
||||
if dmrs_symbol_flag:
|
||||
signal_metadata["pusch_dmrs:ofdm_symbol_idx"].append(symbol) # Append symbol to the list
|
||||
|
||||
signal_metadata["pusch_dmrs:duration_num_ofdm_symbols"] = 1
|
||||
signal_metadata["pusch_dmrs:num_add_positions"] = (captured_data["number_dmrs_symbols"] - 1)
|
||||
|
||||
if "DL" in captured_data["message_type"]:
|
||||
# PDSCH DMRS: OFDM symbol start index within slot
|
||||
get_pdsch_dmrs_start_ofdm_symbol = 0
|
||||
signal_metadata["pdsch_dmrs:ofdm_symbol_idx"] = []
|
||||
for symbol in range(captured_data["StartSymbolIndex"],
|
||||
captured_data["StartSymbolIndex"] + captured_data["NrOfSymbols"]):
|
||||
dmrs_symbol_flag = captured_data["dlDmrsSymbPos"] & (1 << symbol)
|
||||
if dmrs_symbol_flag:
|
||||
if dmrs_symbol_flag and not get_pdsch_dmrs_start_ofdm_symbol:
|
||||
get_pdsch_dmrs_start_ofdm_symbol = 1
|
||||
signal_metadata["pdsch_dmrs:start_ofdm_symbol"] = symbol
|
||||
if dmrs_symbol_flag:
|
||||
signal_metadata["pdsch_dmrs:ofdm_symbol_idx"].append(symbol) # Append symbol to the list
|
||||
|
||||
signal_metadata["pdsch_dmrs:duration_num_ofdm_symbols"] = 1
|
||||
signal_metadata["pdsch_dmrs:num_add_positions"] = (captured_data["numDmrsSymbols"] - 1)
|
||||
|
||||
# If the message is a BIT message, add number of bits to the signal info
|
||||
# "UE_PHY_UL_SCRAMBLED_TX_BITS", "GNB_PHY_UL_PAYLOAD_RX_BITS", "UE_PHY_UL_PAYLOAD_TX_BITS"
|
||||
if "_BITS" in captured_data["message_type"]:
|
||||
# if "BIT" in captured_data["message_type"]:
|
||||
signal_metadata["num_bits"] = (captured_data["number_of_bits"])
|
||||
|
||||
# Set Link direction and number of antennas based on link direction and captured side
|
||||
if "UL" in captured_data["message_type"]:
|
||||
signal_metadata["link_direction"] = "uplink"
|
||||
# On UE side, It is TX antennas
|
||||
# On gNB side, It is RX antennas
|
||||
if "UE" in captured_data["message_type"]:
|
||||
signal_metadata["num_tx_antennas"] = captured_data["nb_antennas"]
|
||||
else:
|
||||
signal_metadata["num_rx_antennas"] = captured_data["nb_antennas"]
|
||||
|
||||
if "DL" in captured_data["message_type"]:
|
||||
signal_metadata["link_direction"] = "downlink"
|
||||
# On UE side, It is RX antennas
|
||||
# On gNB side, It is TX antennas
|
||||
if "UE" in captured_data["message_type"]:
|
||||
signal_metadata["num_rx_antennas"] = captured_data["nb_antennas"] ## TO DO check key name: no DL message from UE yet
|
||||
else:
|
||||
signal_metadata["num_tx_antennas"] = captured_data["nrOfLayers"]
|
||||
# ----------------------------------------------------
|
||||
# Set 2: Parameters that is hardcoded
|
||||
# ----------------------------------------------------
|
||||
# Note: The mapping type is hardcoded. It is fixed in OAI to mapping type A for DL and B for UL.
|
||||
# Look to: openair2/RRC/NR/nr_rrc_config.c
|
||||
if "UL" in captured_data["message_type"]:
|
||||
signal_metadata["pusch:mapping_type"] = "B"
|
||||
signal_metadata["pusch:content"] = "compliant"
|
||||
signal_metadata["pusch:payload_bit_pattern"] = "random"
|
||||
if "DL" in captured_data["message_type"]:
|
||||
signal_metadata["pdsch:mapping_type"] = "A"
|
||||
signal_metadata["pdsch:content"] = "compliant"
|
||||
signal_metadata["pdsch:payload_bit_pattern"] = "random"
|
||||
|
||||
signal_metadata["num_slots"] = 1
|
||||
|
||||
return signal_metadata
|
||||
@@ -118,7 +118,7 @@ def calculate_stats(main_config_file: str):
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
main_config = "/home/user/workarea/oai_recorded_data/config_data_recording_app.json"
|
||||
main_config = "/home/user/workarea/oai_recorded_data/config_data_recording_app_extended.json"
|
||||
|
||||
# calculate BER stats
|
||||
calculate_stats(main_config)
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user