mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Compare commits
86 Commits
pre-commit
...
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 | ||
|
|
32cb3401b4 | ||
|
|
f6b6ce2da3 | ||
|
|
3a935bc9f7 |
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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -868,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
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -215,6 +215,7 @@ L1s =
|
||||
(
|
||||
{
|
||||
num_cc = 1;
|
||||
prach_dtx_threshold = 200;
|
||||
tr_n_preference = "local_mac";
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
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."
|
||||
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>
|
||||
|
||||
|
||||
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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 fsn.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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdatomic.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include <atomic>
|
||||
// use atomic_size_t to help interworking with C++
|
||||
using std::atomic_size_t;
|
||||
#else
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
|
||||
typedef struct spsc_q {
|
||||
|
||||
@@ -262,28 +262,7 @@ static inline int get_num_dmrs(uint16_t dmrs_mask )
|
||||
return(num_dmrs);
|
||||
}
|
||||
|
||||
static inline int count_bits(uint8_t *arr, int sz)
|
||||
{
|
||||
AssertFatal(sz % sizeof(int) == 0, "to implement if needed\n");
|
||||
int ret = 0;
|
||||
for (uint *ptr = (uint *)arr; (uint8_t *)ptr < arr + sz; ptr++)
|
||||
ret += __builtin_popcount(*ptr);
|
||||
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);
|
||||
}
|
||||
|
||||
void warn_higher_threequarter_fs(const int n_rb, const int mu);
|
||||
|
||||
uint64_t from_nrarfcn(int nr_bandP, uint8_t scs_index, uint32_t dl_nrarfcn);
|
||||
uint32_t to_nrarfcn(uint64_t dl_CarrierFreq);
|
||||
uint8_t set_ssb_case(int scs, int nr_band);
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#ifndef REVERSE_BITS_H_
|
||||
#define REVERSE_BITS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.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);
|
||||
|
||||
#endif /* REVERSE_BITS_H_ */
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <linux/types.h>
|
||||
// global var to enable openair performance profiler
|
||||
extern int cpu_meas_enabled;
|
||||
extern double cpu_freq_GHz __attribute__ ((aligned(32)));;
|
||||
extern double cpu_freq_GHz __attribute__ ((aligned(32)));
|
||||
// structure to store data to compute cpu measurment
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
|
||||
typedef long long oai_cputime_t;
|
||||
|
||||
@@ -72,9 +72,9 @@ Tested libxran releases:
|
||||
| Vendor |
|
||||
|-----------------------------------------|
|
||||
| `oran_f_release_v1.0` |
|
||||
| `oran_k_release_v1.0` |
|
||||
|
||||
|
||||
**Note**: The libxran driver of OAI identifies the above F release version as "6.1.0" (F is the sixth letter, then 1.0).
|
||||
**Note**: The libxran driver of OAI identifies the above F release version as "6.1.0" (F is the sixth letter, then 1.0), and the above K release as "11.1.0".
|
||||
|
||||
### Configure your server
|
||||
|
||||
@@ -274,7 +274,7 @@ timedatectl set-ntp false
|
||||
|
||||
### DPDK (Data Plane Development Kit)
|
||||
|
||||
Download DPDK version 20.11.9.
|
||||
Download DPDK version 20.11.9 (F release) or 24.11.4 (K release).
|
||||
|
||||
```bash
|
||||
# on debian
|
||||
@@ -282,7 +282,8 @@ sudo apt install wget xz-utils libnuma-dev
|
||||
# on Fedora/RHEL
|
||||
sudo dnf install wget xz numactl-devel
|
||||
cd
|
||||
wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz
|
||||
wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz # F release
|
||||
wget http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz # K release
|
||||
```
|
||||
|
||||
#### DPDK Compilation and Installation
|
||||
@@ -290,10 +291,11 @@ wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz
|
||||
```bash
|
||||
# Installing meson : it should pull ninja-build and compiler packages
|
||||
# on debian
|
||||
sudo apt install meson
|
||||
sudo apt install python3-pyelftools meson
|
||||
# on Fedora/RHEL
|
||||
sudo dnf install meson
|
||||
tar xvf dpdk-20.11.9.tar.xz && cd dpdk-stable-20.11.9
|
||||
sudo dnf install python3-pyelftools meson
|
||||
tar xvf dpdk-20.11.9.tar.xz && cd dpdk-stable-20.11.9 # F release
|
||||
tar xvf dpdk-24.11.4.tar.xz && cd dpdk-stable-24.11.4 # K release
|
||||
|
||||
meson build
|
||||
ninja -C build
|
||||
@@ -359,7 +361,8 @@ pkg-config --libs libdpdk --static
|
||||
Go back to the version folder you used to build and install
|
||||
|
||||
```
|
||||
cd ~/dpdk-stable-20.11.9
|
||||
cd ~/dpdk-stable-20.11.9 # F release
|
||||
cd ~/dpdk-stable-24.11.4 # K release
|
||||
sudo ninja deinstall -C build
|
||||
```
|
||||
|
||||
@@ -384,6 +387,13 @@ git checkout oran_f_release_v1.0
|
||||
git apply ~/openairinterface5g/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch
|
||||
```
|
||||
|
||||
#### K release
|
||||
```bash
|
||||
git clone https://github.com/openairinterface/o-du-phy.git ~/phy
|
||||
cd ~/phy
|
||||
git checkout <desired-tag> # shall match a variable `K_VERSION`
|
||||
```
|
||||
|
||||
Compile the fronthaul interface library by calling `make` and the option
|
||||
`XRAN_LIB_SO=1` to have it build a shared object. Note that we provide two
|
||||
environment variables `RTE_SDK` for the path to the source tree of DPDK, and
|
||||
@@ -398,6 +408,7 @@ This feature is intended to enable experiments and future improvements on Arm sy
|
||||
cd ~/phy/fhi_lib/lib
|
||||
make clean
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=~/dpdk-stable-20.11.9/ XRAN_DIR=~/phy/fhi_lib make XRAN_LIB_SO=1 # F release
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=~/dpdk-stable-24.11.4/ XRAN_DIR=~/phy/fhi_lib make XRAN_LIB_SO=1 # K release
|
||||
...
|
||||
[AR] build/libxran.so
|
||||
./build/libxran.so
|
||||
@@ -483,23 +494,13 @@ Note that you might also call cmake directly instead of using `build_oai`:
|
||||
```
|
||||
cd ~/openairinterface5g
|
||||
mkdir build && cd build
|
||||
# build RAN after manually building xran F or K release
|
||||
cmake .. -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib
|
||||
# build RAN and xran K release automatically
|
||||
cmake .. -GNinja -DOAI_FHI72=ON -Dxran_DOWNLOAD=ON
|
||||
ninja nr-softmodem oran_fhlib_5g params_libconfig
|
||||
```
|
||||
|
||||
Note that in tags 2025.w06 and prior, the FHI72 driver used polling to wait for
|
||||
the next slot. This is inefficient as it burns CPU time, and has been replaced
|
||||
with a more efficient mechanism. Nevertheless, if you experience problems that
|
||||
did not occur previously, it is possible to re-enable polling, either with
|
||||
`build_oai` like this
|
||||
|
||||
./build_oai --gNB --ninja -t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=$HOME/phy/fhi_lib/lib --cmake-opt -DOAI_FHI72_USE_POLLING=ON
|
||||
|
||||
or with `cmake` like so
|
||||
|
||||
cmake .. -GNinja -DOAI_FHI72=ON -Dxran_LOCATION=$HOME/phy/fhi_lib/lib -DOAI_FHI72_USE_POLLING=ON
|
||||
ninja oran_fhlib_5g
|
||||
|
||||
## Configuration
|
||||
|
||||
RU and DU configurations have a circular dependency: you have to configure DU MAC address in the RU configuration and the RU MAC address, VLAN and Timing advance parameters in the DU configuration.
|
||||
@@ -1636,6 +1637,8 @@ PKG_CONFIG_PATH=/opt/mplane-v2/lib/pkgconfig cmake .. -GNinja -DOAI_FHI72=ON -DO
|
||||
ninja nr-softmodem oran_fhlib_5g_mplane params_libconfig
|
||||
```
|
||||
|
||||
Note: instead of setting `xran_LOCATION`, feel free to use `xran_DOWNLOAD` option for automatic xran K release build.
|
||||
|
||||
### Start the gNB
|
||||
Run the `nr-softmodem` from the build directory:
|
||||
```bash
|
||||
|
||||
@@ -108,6 +108,7 @@ Some directories under `radio` contain READMEs:
|
||||
- [fhi_72](../radio/fhi_72/README.md)
|
||||
- [vrtsim](../radio/vrtsim/README.md)
|
||||
- [rf_emulator](../radio/emulator/README.md)
|
||||
- [zmq](../radio/zmq/README.md)
|
||||
|
||||
The other SDRs (AW2S, LimeSDR, ...) have no READMEs.
|
||||
|
||||
|
||||
@@ -50,10 +50,11 @@ python3 -m pip install -r common/utils/data_recording/requirements.txt
|
||||
The Data Recording application provides configuration file in [JSON](http://www.json.org/) format. It is stored in [common/utils/data_recording/config/config_data_recording.json](../common/utils/data_recording/config/config_data_recording.json) folder. The main parameters are:
|
||||
|
||||
- **data_storage_path**: Path to directory for data storage
|
||||
- **num_records**: Number of requested data records in slots
|
||||
- **num_records**: Number of requested data records in slots. The maximum number of num_records depends on the memory size. If the user would like to record large number of records, user needs to increase the memory size defined here (common/utils/T/tracer/shared_memory_config.h)
|
||||
- **t_tracer_message_definition_file**: T-Tracer message definition file
|
||||
- **parameter_map_file**: Parameter mapping dictionary (OAI parameters to standardized metadata). It is located here: [common/utils/data_recording/config/wireless_link_parameter_map.yaml](../common/utils/data_recording/config/wireless_link_parameter_map.yaml)
|
||||
- **start_frame_number**: It can be used to start the recording from a specific frame, but it is not yet supported.
|
||||
- **common_meta_data**: Common metadata parameters that are not read from the system yet, but shall be included into the SigMF metadata such as the sampling rate, the bandwidth, and the clock reference of USRP.
|
||||
- **base_station**:
|
||||
|
||||
- requested_tracer_messages: Requested base station data traces. The supported messages are:
|
||||
@@ -62,16 +63,18 @@ The Data Recording application provides configuration file in [JSON](http://www.
|
||||
- GNB_PHY_UL_FD_CHAN_EST_DMRS_POS
|
||||
- GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL
|
||||
- GNB_PHY_UL_PAYLOAD_RX_BITS
|
||||
- tracer_service_baseStation_address: The IP address and port number of base station server. If the Data Recording App and the Data Collection (T–Tracer) Service are running on the same server of base station, the IP address and port number are : `127.0.0.1:2021`
|
||||
- meta_data: Additional base station metadata (additional fixed base station parameters that cannot be read from the system yet, but shall be included into the SigMF metadata)
|
||||
- shared_mem_config: Shared Memory configuration such as in T-Tracer App of gNB
|
||||
|
||||
- **user_equipment**
|
||||
|
||||
- requested_tracer_messages: Requested user equipment data traces. The supported messages are:
|
||||
- UE_PHY_UL_SCRAMBLED_TX_BITS
|
||||
- UE_PHY_UL_PAYLOAD_TX_BITS
|
||||
- tracer_service_userEquipment_address**: The IP address and port number of UE server.
|
||||
- meta_data: Additional user equipment metadata (additional fixed UE parameters that are not read from the system yet, but shall be included into the SigMF metadata)
|
||||
- **common_meta_data**: Common metadata parameters that are not read from the system yet, but shall be included into the SigMF metadata such as the sampling rate, the bandwidth, and the clock reference of USRP.
|
||||
- **tracer_service_baseStation_address**: The IP address and port number of base station server. If the Data Recording App and the Data Collection (T–Tracer) Service are running on the same server of base station, the IP address and port number are : `127.0.0.1:2021`
|
||||
- **tracer_service_userEquipment_address**: The IP address and port number of UE server.
|
||||
- shared_mem_config: Shared Memory configuration such as in T-Tracer App of UE
|
||||
|
||||
**Notes**:
|
||||
- The data can be recorded from base station and UE or from base station only or UE only. To disable the recording from any station, make the list of `requested_tracer_messages` empty such as: `requested_tracer_messages:[]`
|
||||
@@ -79,54 +82,68 @@ The Data Recording application provides configuration file in [JSON](http://www.
|
||||
The figure below illustrates an example of a JSON Data Recording App configuration file.
|
||||
|
||||
```json
|
||||
{
|
||||
"data_recording_config": {
|
||||
"data_storage_path": "/home/user/workarea/oai_recorded_data/",
|
||||
"data_file_format": "SigMF",
|
||||
"enable_saving_tracer_messages_sigmf": true,
|
||||
"num_records": 5,
|
||||
"t_tracer_message_definition_file": "../T/T_messages.txt",
|
||||
"parameter_map_file": "config/wireless_link_parameter_map.yaml",
|
||||
"start_frame_number": 5,
|
||||
"base_station": {
|
||||
"data_storage_path": "/home/user/workarea/oai_recorded_data/",
|
||||
"data_file_format": "SigMF",
|
||||
"enable_saving_tracer_messages_sigmf": true,
|
||||
"num_records": 5,
|
||||
"t_tracer_message_definition_file": "../T/T_messages.txt",
|
||||
"parameter_map_file": "config/wireless_link_parameter_map.yaml",
|
||||
"start_frame_number": 5,
|
||||
"common_meta_data": {
|
||||
"sample_rate": 61440000.0,
|
||||
"bandwidth": 40000000.0,
|
||||
"clock_reference": "external"
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"id": "gnb_0",
|
||||
"type": "gnb",
|
||||
"requested_tracer_messages": [
|
||||
"GNB_PHY_UL_FD_PUSCH_IQ",
|
||||
"GNB_PHY_UL_FD_DMRS",
|
||||
"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":{
|
||||
"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
|
||||
}
|
||||
},
|
||||
"user_equipment": {
|
||||
{
|
||||
"id": "ue_0",
|
||||
"type": "ue",
|
||||
"requested_tracer_messages": [
|
||||
"UE_PHY_UL_SCRAMBLED_TX_BITS",
|
||||
"UE_PHY_UL_PAYLOAD_TX_BITS"
|
||||
],
|
||||
"meta_data":{
|
||||
"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": 40.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
|
||||
}
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -153,7 +170,7 @@ The following figure shows an example of Wireless Link Parameter Map Dictionary.
|
||||
|
||||
### Global Metadata
|
||||
There are some metadata parameters that the user may need to change only once. Those parameters have been hard coded in the Data Recording App header.
|
||||
[common/utils/data_recording/data_recording_app_v1.0.py](../common/utils/data_recording/data_recording_app_v1.0.py). Those are:
|
||||
[common/utils/data_recording/data_recording_app_v1.1.py](../common/utils/data_recording/data_recording_app_v1.1.py). Those are:
|
||||
|
||||
- The global metadata such as: author, description, sigmf collection file prefix, datetime_offset, enable saving config Data Recording App in json file with recorded data, and name of signal generator (i.e. 5gnr_oai). The name of signal generator is used for parameter mapping dictionary (OAI parameters to standardized metadata).
|
||||
- The mapping between supported OAI messages and file_name_prefix, scope, and description.
|
||||
@@ -237,11 +254,11 @@ For the test simplicity, user can run the system in PHY-test mode. We will show
|
||||
|
||||
Run NR gNB Softmodem with USRP:
|
||||
```
|
||||
sudo ./cmake_targets/ran_build/build/nr-softmodem -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.106PRB.1x1.usrpx410_3300MHz.conf --gNBs.[0].min_rxtxtime 6 --usrp-tx-thread-config 1 --phy-test -d --T_stdout 2 --T_nowait
|
||||
sudo ./cmake_targets/ran_build/build/nr-softmodem -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310 --gNBs.[0].min_rxtxtime 6 --usrp-tx-thread-config 1 --phy-test -d --T_stdout 2 --T_nowait
|
||||
```
|
||||
Run NR gNB Softmodem in RF Simulation:
|
||||
```
|
||||
sudo ./cmake_targets/ran_build/build/nr-softmodem -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.band78.sa.fr1.106PRB.1x1.usrpx410_3300MHz.conf --gNBs.[0].min_rxtxtime 6 --rfsim --rfsimulator.[0].serveraddr server --phy-test -d --T_stdout 2 --T_nowait
|
||||
sudo ./cmake_targets/ran_build/build/nr-softmodem -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb0.prs.band78.fr1.106PRB.usrpx310.conf --gNBs.[0].min_rxtxtime 6 --rfsim --phy-test --rfsimulator.[0].serveraddr server --T_stdout 2 --T_nowait
|
||||
```
|
||||
> **Note:** User needs to change the name of gNB config file to your gNB config file.
|
||||
|
||||
@@ -265,9 +282,9 @@ sudo ./cmake_targets/ran_build/build/nr-uesoftmodem --usrp-args "type=x4xx,addr=
|
||||
```
|
||||
|
||||
|
||||
Run OAI Soft UE in RF Simulation, assume the IP address of gNB server is `192.168.100.2`:
|
||||
Run OAI Soft UE in RF Simulation, assume both gNB and UE are running on the same server in Simulation mode`:
|
||||
```
|
||||
sudo ./cmake_targets/ran_build/build/nr-uesoftmodem --rfsim --rfsimulator.[0].serveraddr 192.168.100.2 --phy-test -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --reconfig-file /home/user/workarea/rrc_files/reconfig.raw --rbconfig-file /home/user/workarea/rrc_files/rbconfig.raw --T_stdout 2 --T_nowait --T_port 2023
|
||||
sudo ./cmake_targets/ran_build/build/nr-uesoftmodem --rfsim --phy-test -O ./targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf --reconfig-file /home/user/workarea/openairinterface5g/reconfig.raw --rbconfig-file /home/user/workarea/openairinterface5g/rbconfig.raw --T_stdout 2 --T_nowait --T_port 2023
|
||||
```
|
||||
|
||||
### Step3: Run Data Recording Application Services
|
||||
@@ -286,7 +303,7 @@ Run gNB Data Collection service on one terminal:
|
||||
```
|
||||
Run UE Data Collection service on another terminal:
|
||||
```
|
||||
./t_tracer_app_ue -d ../T_messages.txt
|
||||
./t_tracer_app_ue -d ../T_messages.txt -p 2023
|
||||
```
|
||||
|
||||
Second, run main Data Recording Application:
|
||||
@@ -294,7 +311,7 @@ Second, run main Data Recording Application:
|
||||
|
||||
Run the following python script:
|
||||
```
|
||||
python3 data_recording_app_v1.0.py
|
||||
python3 data_recording_app_v1.1.py
|
||||
```
|
||||
|
||||
The recorded data set will be stored in the configured path, assume `/home/user/workarea/oai_recorded_data/`.
|
||||
@@ -372,8 +389,8 @@ The following figure shows an example of SigMF metadata file, for example for th
|
||||
{
|
||||
"global": {
|
||||
"core:author": "Abdo Gaber",
|
||||
"core:collection": "data-collection-rec-0-2025_06_19T11_19_00_037",
|
||||
"core:dataset": "raw-ce-fd-data-rec-0-2025_06_19T11_19_00_037.sigmf-data",
|
||||
"core:collection": "data-collection-rec-1-2026_04_21T14_14_07_008277523",
|
||||
"core:dataset": "raw-ce-fd-data-rec-1-2026_04_21T14_14_07_008279596.sigmf-data",
|
||||
"core:datatype": "cf32_le",
|
||||
"core:description": "Frequency-domain raw channel estimates (at DMRS positions)",
|
||||
"core:hw": "USRP X410",
|
||||
@@ -381,12 +398,12 @@ The following figure shows an example of SigMF metadata file, for example for th
|
||||
"core:num_channels": 1,
|
||||
"core:recorder": "NI Data Recording Application for OAI",
|
||||
"core:sample_rate": 61440000.0,
|
||||
"core:sha512": "55ae5bc81b4812e68f6e1c195600f240fc3ca71113c732271ee42a5524da98636c3c7ac587c46fd87c6d1b9253ca6504a4b94eafba8f4065099096fc7721228c",
|
||||
"core:sha512": "fce1c6e85e986939e8cf5a3937d0d2f08d9f27ab52ea4065d6e347beb5acf7017a4f9d200c70345f1724ff52d886403e2fddedce62c5c1de4ef895a941547e3d",
|
||||
"core:version": "1.2.1"
|
||||
},
|
||||
"captures": [
|
||||
{
|
||||
"core:datetime": "2025_06_19T11:19:00.037",
|
||||
"core:datetime": "2026_04_21T14:14:07.008279596",
|
||||
"core:frequency": 3319680000.0,
|
||||
"core:sample_start": 0,
|
||||
"serialization:counts": [
|
||||
@@ -431,10 +448,11 @@ The following figure shows an example of SigMF metadata file, for example for th
|
||||
"5gnr": {
|
||||
"cell_id": 0,
|
||||
"cp_mode": "normal",
|
||||
"frame": 785,
|
||||
"frame": 916,
|
||||
"frame_structure": "tdd",
|
||||
"frequency_range": "fr1",
|
||||
"link_direction": "uplink",
|
||||
"num_rx_antennas": 1,
|
||||
"num_slots": 1,
|
||||
"num_tx_antennas": 1,
|
||||
"pusch:content": "compliant",
|
||||
@@ -445,7 +463,7 @@ The following figure shows an example of SigMF metadata file, for example for th
|
||||
"pusch:num_layer": 1,
|
||||
"pusch:num_ofdm_symbols": 13,
|
||||
"pusch:num_prb": 50,
|
||||
"pusch:payload_bit_pattern": "zeros",
|
||||
"pusch:payload_bit_pattern": "random",
|
||||
"pusch:start_ofdm_symbol": 0,
|
||||
"pusch:start_prb": 0,
|
||||
"pusch:transform_precoding": "disabled",
|
||||
|
||||
@@ -45,7 +45,9 @@ RUN rm -f /etc/rhsm-host && \
|
||||
gcc-toolset-13-gcc-c++ \
|
||||
# python3-pip and pyyaml are used for conf template generation
|
||||
python3-pip && \
|
||||
pip3 install --ignore-installed pyyaml && \
|
||||
pip3 install --ignore-installed \
|
||||
pyyaml \
|
||||
pyelftools && \
|
||||
echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \
|
||||
echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ RUN apt-get update && \
|
||||
wget \
|
||||
flatbuffers-compiler \
|
||||
libflatbuffers-dev \
|
||||
libnanomsg-dev && \
|
||||
libnanomsg-dev \
|
||||
libzmq3-dev && \
|
||||
# --break-system-packages allows externally managed environment in pip
|
||||
pip3 install --ignore-installed pyyaml --break-system-packages
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
FROM ran-base:latest AS ran-base
|
||||
|
||||
ARG xran_VERSION=11.1.1
|
||||
ARG E2AP_VERSION=E2AP_V3
|
||||
ARG KPM_VERSION=KPM_V3_00
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@@ -20,7 +21,8 @@ RUN apt-get update && \
|
||||
wget \
|
||||
xz-utils \
|
||||
pkg-config \
|
||||
libnuma-dev && \
|
||||
libnuma-dev \
|
||||
python3-pyelftools && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
@@ -28,20 +30,19 @@ WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
## Download and build DPDK
|
||||
RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
|
||||
tar -xvf dpdk-20.11.9.tar.xz && \
|
||||
cd dpdk-stable-20.11.9 && \
|
||||
meson setup -Dmachine=default build && \
|
||||
RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \
|
||||
tar -xf dpdk-24.11.4.tar.xz && \
|
||||
cd dpdk-stable-24.11.4 && \
|
||||
meson build && \
|
||||
ninja -C build && \
|
||||
ninja install -C build
|
||||
|
||||
## Build Fronthaul library
|
||||
RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \
|
||||
cd /opt/phy && \
|
||||
git checkout oran_f_release_v1.0 &&\
|
||||
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \
|
||||
git checkout $xran_VERSION &&\
|
||||
cd /opt/phy/fhi_lib/lib && \
|
||||
TARGET=armv8 WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
TARGET=armv8 WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
|
||||
## Build Arm RAN Acceleration Library
|
||||
RUN git clone https://git.gitlab.arm.com/networking/ral.git /opt/ral && \
|
||||
|
||||
@@ -14,10 +14,12 @@ RUN rm -Rf /oai-ran
|
||||
WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
ARG xran_VERSION=11.1.1
|
||||
|
||||
## Download and build DPDK
|
||||
RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
|
||||
tar -xvf dpdk-20.11.9.tar.xz && \
|
||||
cd dpdk-stable-20.11.9 && \
|
||||
RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \
|
||||
tar -xf dpdk-24.11.4.tar.xz && \
|
||||
cd dpdk-stable-24.11.4 && \
|
||||
meson build && \
|
||||
ninja -C build && \
|
||||
ninja install -C build
|
||||
@@ -25,10 +27,9 @@ RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
|
||||
## Build Fronthaul library
|
||||
RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \
|
||||
cd /opt/phy && \
|
||||
git checkout oran_f_release_v1.0 &&\
|
||||
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \
|
||||
git checkout $xran_VERSION &&\
|
||||
cd /opt/phy/fhi_lib/lib && \
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
|
||||
FROM ran-base AS ran-build-fhi72
|
||||
ARG E2AP_VERSION=E2AP_V3
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
FROM ran-base:latest AS ran-base
|
||||
|
||||
ARG xran_VERSION=11.1.1
|
||||
ARG E2AP_VERSION=E2AP_V3
|
||||
ARG KPM_VERSION=KPM_V3_00
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
@@ -20,7 +21,8 @@ RUN apt-get update && \
|
||||
wget \
|
||||
xz-utils \
|
||||
pkg-config \
|
||||
libnuma-dev && \
|
||||
libnuma-dev \
|
||||
python3-pyelftools && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN rm -Rf /oai-ran
|
||||
@@ -28,9 +30,9 @@ WORKDIR /oai-ran
|
||||
COPY . .
|
||||
|
||||
## Download and build DPDK
|
||||
RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
|
||||
tar -xvf dpdk-20.11.9.tar.xz && \
|
||||
cd dpdk-stable-20.11.9 && \
|
||||
RUN wget --no-verbose http://fast.dpdk.org/rel/dpdk-24.11.4.tar.xz && \
|
||||
tar -xf dpdk-24.11.4.tar.xz && \
|
||||
cd dpdk-stable-24.11.4 && \
|
||||
meson build && \
|
||||
ninja -C build && \
|
||||
ninja install -C build
|
||||
@@ -38,10 +40,9 @@ RUN wget http://fast.dpdk.org/rel/dpdk-20.11.9.tar.xz && \
|
||||
## Build Fronthaul library
|
||||
RUN git clone https://github.com/openairinterface/o-du-phy.git /opt/phy && \
|
||||
cd /opt/phy && \
|
||||
git checkout oran_f_release_v1.0 &&\
|
||||
git apply /oai-ran/cmake_targets/tools/oran_fhi_integration_patches/F/oaioran_F.patch && \
|
||||
git checkout $xran_VERSION &&\
|
||||
cd /opt/phy/fhi_lib/lib && \
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-20.11.9/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
WIRELESS_SDK_TOOLCHAIN=gcc RTE_SDK=/oai-ran/dpdk-stable-24.11.4/ XRAN_DIR=/opt/phy/fhi_lib make XRAN_LIB_SO=1
|
||||
|
||||
FROM ran-base AS ran-build-fhi72
|
||||
## Build and install OAI
|
||||
|
||||
@@ -32,6 +32,7 @@ RUN \
|
||||
-w USRP -t Ethernet -w BLADERF \
|
||||
--build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \
|
||||
--cmake-opt -DOAI_VRTSIM_TAPS_CLIENT=ON \
|
||||
-w ZMQ \
|
||||
--noavx512 \
|
||||
--build-tool-opt -k10 \
|
||||
--cmake-opt -DT_RECORD_DB=ON \
|
||||
|
||||
@@ -41,6 +41,7 @@ RUN rm -f /etc/rhsm-host && \
|
||||
python3-pip \
|
||||
net-tools \
|
||||
iputils \
|
||||
libatomic \
|
||||
yaml-cpp-devel && \
|
||||
pip3 install six && \
|
||||
pip3 install requests && \
|
||||
|
||||
@@ -18,6 +18,7 @@ ENV TZ=Europe/Paris
|
||||
RUN dnf update -y && \
|
||||
dnf install -y \
|
||||
procps-ng \
|
||||
libatomic \
|
||||
libXpm \
|
||||
libX11 \
|
||||
lksctp-tools \
|
||||
|
||||
@@ -41,6 +41,7 @@ RUN apt-get update && \
|
||||
python3 \
|
||||
python3-six \
|
||||
python3-requests \
|
||||
libatomic1 \
|
||||
libyaml-cpp-dev && \
|
||||
# if the --sanitize option was used to build, additional packages are required
|
||||
/bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \
|
||||
|
||||
@@ -47,7 +47,8 @@ RUN apt-get update && \
|
||||
python3-requests \
|
||||
libusb-1.0-0 \
|
||||
libyaml-cpp-dev \
|
||||
libnanomsg5 && \
|
||||
libnanomsg5 \
|
||||
libzmq5 && \
|
||||
# if the --sanitize option was used to build, additional packages are required
|
||||
/bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \
|
||||
libasan8 \
|
||||
@@ -78,6 +79,7 @@ COPY --from=gnb-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_rrc.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv_o1.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/liboai_zmqdevif.so \
|
||||
/usr/local/lib/
|
||||
|
||||
# Now we are copying from builder-image the UHD files.
|
||||
@@ -105,7 +107,8 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai
|
||||
/usr/local/lib/libldpc*.so \
|
||||
/usr/local/lib/libtelnetsrv.so \
|
||||
/usr/local/lib/libtelnetsrv_ci.so \
|
||||
/usr/local/lib/libuhd.so.4.8.0
|
||||
/usr/local/lib/libuhd.so.4.8.0 \
|
||||
/usr/local/lib/liboai_zmqdevif.so
|
||||
|
||||
WORKDIR /opt/oai-gnb
|
||||
#EXPOSE 2152/udp # S1U, GTP/UDP
|
||||
|
||||
@@ -50,7 +50,8 @@ RUN apt-get update && \
|
||||
iperf \
|
||||
libyaml-cpp-dev \
|
||||
libzstd1 \
|
||||
libnanomsg5 && \
|
||||
libnanomsg5 \
|
||||
libzmq5 && \
|
||||
# if the --sanitize option was used to build, additional packages are required
|
||||
/bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \
|
||||
libasan8 \
|
||||
@@ -83,6 +84,7 @@ COPY --from=nr-ue-build \
|
||||
/oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/libvrtsim.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/liboai_zmqdevif.so \
|
||||
# Wildcards so it doesn't fail if not present
|
||||
/oai-ran/cmake_targets/ran_build/build/_deps*/fmtlog-build*/libfmtlog-shared*.so \
|
||||
/oai-ran/cmake_targets/ran_build/build/_deps*/clickhouse-cpp-build*/clickhouse/libclickhouse*.so \
|
||||
@@ -114,7 +116,8 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai
|
||||
/usr/local/lib/libtelnetsrv.so \
|
||||
/usr/local/lib/libtelnetsrv_ciUE.so \
|
||||
/usr/local/lib/libtelnetsrv_5Gue.so \
|
||||
/usr/local/lib/libuhd.so.4.8.0
|
||||
/usr/local/lib/libuhd.so.4.8.0 \
|
||||
/usr/local/lib/liboai_zmqdevif.so
|
||||
|
||||
WORKDIR /opt/oai-nr-ue
|
||||
|
||||
|
||||
@@ -131,13 +131,18 @@ void exit_function(const char *file, const char *function, const int line, const
|
||||
printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s);
|
||||
}
|
||||
|
||||
oai_exit = 1;
|
||||
|
||||
if (RC.ru == NULL)
|
||||
exit(-1); // likely init not completed, prevent crash or hang, exit now...
|
||||
|
||||
for (ru_id=0; ru_id<RC.nb_RU; ru_id++) {
|
||||
if (RC.ru[ru_id] && RC.ru[ru_id]->rfdevice.trx_end_func) {
|
||||
if (RC.ru[ru_id] == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (RC.ru[ru_id]->ifdevice.trx_stop_func) {
|
||||
RC.ru[ru_id]->ifdevice.trx_stop_func(&RC.ru[ru_id]->ifdevice);
|
||||
RC.ru[ru_id]->ifdevice.trx_stop_func = NULL;
|
||||
}
|
||||
if (RC.ru[ru_id]->rfdevice.trx_end_func) {
|
||||
if (RC.ru[ru_id]->rfdevice.trx_get_stats_func) {
|
||||
RC.ru[ru_id]->rfdevice.trx_get_stats_func(&RC.ru[ru_id]->rfdevice);
|
||||
RC.ru[ru_id]->rfdevice.trx_get_stats_func = NULL;
|
||||
@@ -146,6 +151,10 @@ void exit_function(const char *file, const char *function, const int line, const
|
||||
RC.ru[ru_id]->rfdevice.trx_end_func = NULL;
|
||||
}
|
||||
|
||||
if (RC.ru[ru_id]->ifdevice.trx_stop_func) {
|
||||
RC.ru[ru_id]->ifdevice.trx_stop_func(&RC.ru[ru_id]->ifdevice);
|
||||
RC.ru[ru_id]->ifdevice.trx_stop_func = NULL;
|
||||
}
|
||||
if (RC.ru[ru_id] && RC.ru[ru_id]->ifdevice.trx_end_func) {
|
||||
if (RC.ru[ru_id]->ifdevice.trx_get_stats_func) {
|
||||
RC.ru[ru_id]->ifdevice.trx_get_stats_func(&RC.ru[ru_id]->ifdevice);
|
||||
@@ -156,6 +165,8 @@ void exit_function(const char *file, const char *function, const int line, const
|
||||
}
|
||||
}
|
||||
|
||||
oai_exit = 1;
|
||||
|
||||
if (assert) {
|
||||
abort();
|
||||
} else {
|
||||
@@ -358,9 +369,6 @@ int stop_L1(module_id_t gnb_id)
|
||||
if (RC.nb_nr_L1_inst > 0)
|
||||
stop_gNB(RC.nb_nr_L1_inst);
|
||||
|
||||
if (RC.nb_RU > 0)
|
||||
stop_RU(RC.nb_RU);
|
||||
|
||||
/* stop trx devices, multiple carrier currently not supported by RU */
|
||||
if (ru->rfdevice.trx_get_stats_func) {
|
||||
ru->rfdevice.trx_get_stats_func(&ru->rfdevice);
|
||||
@@ -378,6 +386,9 @@ int stop_L1(module_id_t gnb_id)
|
||||
LOG_I(GNB_APP, "turned off RU ifdevice\n");
|
||||
}
|
||||
|
||||
if (RC.nb_RU > 0)
|
||||
stop_RU(RC.nb_RU);
|
||||
|
||||
/* release memory used by the RU/gNB threads (incomplete), after all
|
||||
* threads have been stopped (they partially use the same memory) */
|
||||
for (int inst = 0; inst < RC.nb_RU; inst++) {
|
||||
@@ -406,7 +417,7 @@ int start_L1L2(module_id_t gnb_id)
|
||||
/* update config */
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
nr_mac_config_scc(mac, scc, &mac->radio_config);
|
||||
nr_mac_config_scc(mac, 0, scc, &mac->radio_config[0]);
|
||||
|
||||
NR_BCCH_BCH_Message_t *mib = mac->common_channels[0].mib;
|
||||
const NR_BCCH_DL_SCH_Message_t *sib1 = mac->common_channels[0].sib1;
|
||||
|
||||
@@ -352,6 +352,14 @@ void nrue_ru_start(void)
|
||||
}
|
||||
}
|
||||
|
||||
void nrue_ru_stop(void)
|
||||
{
|
||||
for (int ru_id = 0; ru_id < nrue_ru_count; ru_id++) {
|
||||
if (openair0_dev[ru_id].trx_stop_func)
|
||||
openair0_dev[ru_id].trx_stop_func(&openair0_dev[ru_id]);
|
||||
}
|
||||
}
|
||||
|
||||
void nrue_ru_end(void)
|
||||
{
|
||||
for (int ru_id = 0; ru_id < nrue_ru_count; ru_id++) {
|
||||
|
||||
@@ -22,6 +22,7 @@ void nrue_set_ru_params(configmodule_interface_t *cfg);
|
||||
void nrue_init_openair0(void);
|
||||
|
||||
void nrue_ru_start(void);
|
||||
void nrue_ru_stop(void);
|
||||
void nrue_ru_end(void);
|
||||
void nrue_ru_set_freq(PHY_VARS_NR_UE *UE, uint64_t ul_carrier, uint64_t dl_carrier, int freq_offset);
|
||||
int nrue_ru_adjust_rx_gain(PHY_VARS_NR_UE *UE, int gain_change);
|
||||
|
||||
@@ -112,6 +112,7 @@ void exit_function(const char *file, const char *function, const int line, const
|
||||
|
||||
oai_exit = 1;
|
||||
|
||||
nrue_ru_stop();
|
||||
nrue_ru_end();
|
||||
|
||||
if (assert) {
|
||||
@@ -457,6 +458,8 @@ int main(int argc, char **argv)
|
||||
LOG_W(NR_PHY, "Returned from ITTI signal handler\n");
|
||||
oai_exit = 1;
|
||||
|
||||
nrue_ru_stop();
|
||||
|
||||
if (PHY_vars_UE_g && PHY_vars_UE_g[0]) {
|
||||
for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
PHY_VARS_NR_UE *phy_vars = PHY_vars_UE_g[0][CC_id];
|
||||
|
||||
@@ -59,8 +59,8 @@ void nvIPC_send_stop_request()
|
||||
}
|
||||
|
||||
|
||||
static uint16_t old_sfn = 0;
|
||||
static uint16_t old_slot = 0;
|
||||
static uint16_t old_sfn[NFAPI_CC_MAX];
|
||||
static uint16_t old_slot[NFAPI_CC_MAX];
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Handle an RX message
|
||||
static int ipc_handle_rx_msg(nv_ipc_msg_t *msg)
|
||||
@@ -134,22 +134,28 @@ static int ipc_handle_rx_msg(nv_ipc_msg_t *msg)
|
||||
NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__);
|
||||
} else {
|
||||
NFAPI_TRACE(NFAPI_TRACE_DEBUG, "%s: Handling NR SLOT Indication\n", __FUNCTION__);
|
||||
// use transport-level cell_id (0-based) from the nvIPC header —
|
||||
// ind.header.phy_id is not reliably populated by cuBB in incoming messages;
|
||||
// normalize it here so downstream callbacks can rely on it
|
||||
uint8_t cc_id = msg->cell_id;
|
||||
AssertFatal(cc_id < NFAPI_CC_MAX, "cell_id %d exceeds NFAPI_CC_MAX %d\n", cc_id, NFAPI_CC_MAX);
|
||||
ind.header.phy_id = cc_id + 1; // 1-based, consistent with outgoing P7 path
|
||||
// check if the sfn/slot unpacked come wrong at any time, should be old + 1 (slot 0 -- 19, sfn 0 -- 1023)
|
||||
// add 1 to current sfn number
|
||||
uint16_t old_slot_plus = ((old_slot + 1) % 20);
|
||||
uint16_t old_sfn_plus = old_slot_plus == 0 ? ((old_sfn + 1) % 1024) : old_sfn;
|
||||
uint16_t old_slot_plus = ((old_slot[cc_id] + 1) % 20);
|
||||
uint16_t old_sfn_plus = old_slot_plus == 0 ? ((old_sfn[cc_id] + 1) % 1024) : old_sfn[cc_id];
|
||||
if (old_slot_plus != ind.slot || old_sfn_plus != ind.sfn) {
|
||||
LOG_E(NFAPI_VNF,
|
||||
"\n============================================================================\n"
|
||||
"sfn slot doesn't match unpacked one! L2->L1 %d.%d vs L1->L2 %d.%d \n"
|
||||
"sfn slot doesn't match unpacked one! CC %d L2->L1 %d.%d vs L1->L2 %d.%d \n"
|
||||
"============================================================================\n",
|
||||
old_sfn,
|
||||
old_slot,
|
||||
cc_id,
|
||||
old_sfn[cc_id],
|
||||
old_slot[cc_id],
|
||||
ind.sfn,
|
||||
ind.slot);
|
||||
}
|
||||
old_sfn = ind.sfn;
|
||||
old_slot = ind.slot;
|
||||
old_sfn[cc_id] = ind.sfn;
|
||||
old_slot[cc_id] = ind.slot;
|
||||
if (vnf_p7_config->_public.nr_slot_indication) {
|
||||
(vnf_p7_config->_public.nr_slot_indication)(&ind);
|
||||
}
|
||||
@@ -210,7 +216,7 @@ bool aerial_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_messa
|
||||
if (pnf) {
|
||||
// Create the message
|
||||
nv_ipc_msg_t send_msg = {.msg_id = msg->message_id,
|
||||
.cell_id = 0,
|
||||
.cell_id = (msg->phy_id > 0) ? msg->phy_id - 1 : 0,
|
||||
// By default, P5 uses only message pool.
|
||||
.data_pool = NV_IPC_MEMPOOL_CPU_MSG,
|
||||
.data_len = 0,
|
||||
@@ -410,11 +416,11 @@ int nvIPC_Init(nvipc_params_t nvipc_params_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req)
|
||||
int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req, uint8_t CC_id)
|
||||
{
|
||||
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
|
||||
|
||||
ul_tti_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
|
||||
ul_tti_req->header.phy_id = CC_id + 1;
|
||||
ul_tti_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST;
|
||||
|
||||
bool retval = p7_config->send_p7_msg(get_p7_vnf(), &ul_tti_req->header);
|
||||
@@ -431,10 +437,10 @@ int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req)
|
||||
int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req, uint8_t CC_id)
|
||||
{
|
||||
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
|
||||
ul_dci_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
|
||||
ul_dci_req->header.phy_id = CC_id + 1;
|
||||
ul_dci_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST;
|
||||
|
||||
bool retval = p7_config->send_p7_msg(get_p7_vnf(), &ul_dci_req->header);
|
||||
@@ -446,10 +452,10 @@ int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req)
|
||||
int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req, uint8_t CC_id)
|
||||
{
|
||||
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
|
||||
tx_data_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
|
||||
tx_data_req->header.phy_id = CC_id + 1;
|
||||
tx_data_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST;
|
||||
|
||||
bool retval = p7_config->send_p7_msg(get_p7_vnf(), &tx_data_req->header);
|
||||
@@ -462,11 +468,11 @@ int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req)
|
||||
int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req, uint8_t CC_id)
|
||||
{
|
||||
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
|
||||
dl_config_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST;
|
||||
dl_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
|
||||
dl_config_req->header.phy_id = CC_id + 1;
|
||||
|
||||
bool retval = p7_config->send_p7_msg(get_p7_vnf(), &dl_config_req->header);
|
||||
dl_config_req->dl_tti_request_body.nPDUs = 0;
|
||||
@@ -478,10 +484,11 @@ int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int oai_fapi_send_end_request(uint32_t frame, uint32_t slot)
|
||||
int oai_fapi_send_end_request(uint32_t frame, uint32_t slot, uint8_t CC_id)
|
||||
{
|
||||
nfapi_vnf_p7_config_t *p7_config = get_p7_vnf_config();
|
||||
nfapi_nr_slot_indication_scf_t nr_slot_resp = {.header.message_id = 0x8F, .sfn = frame, .slot = slot};
|
||||
nfapi_nr_slot_indication_scf_t nr_slot_resp = {
|
||||
.header.message_id = 0x8F, .header.phy_id = CC_id + 1, .sfn = frame, .slot = slot};
|
||||
|
||||
bool retval = p7_config->send_p7_msg(get_p7_vnf(), &nr_slot_resp.header);
|
||||
if (!retval) {
|
||||
|
||||
@@ -24,11 +24,11 @@ void release_msg(nv_ipc_msg_t* send_msg);
|
||||
bool send_nvipc_msg(nv_ipc_msg_t* send_msg);
|
||||
bool aerial_nr_send_p5_message(vnf_t *vnf, uint16_t p5_idx, nfapi_nr_p4_p5_message_header_t *msg, uint32_t msg_len);
|
||||
int nvIPC_Init(nvipc_params_t nvipc_params_s);
|
||||
int oai_fapi_send_end_request(uint32_t frame, uint32_t slot);
|
||||
int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req);
|
||||
int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req);
|
||||
int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req);
|
||||
int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req);
|
||||
int oai_fapi_send_end_request(uint32_t frame, uint32_t slot, uint8_t CC_id);
|
||||
int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req, uint8_t CC_id);
|
||||
int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req, uint8_t CC_id);
|
||||
int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req, uint8_t CC_id);
|
||||
int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req, uint8_t CC_id);
|
||||
void nvIPC_Stop();
|
||||
void nvIPC_send_stop_request();
|
||||
#endif // OPENAIRINTERFACE_FAPI_NVIPC_H
|
||||
|
||||
@@ -897,25 +897,27 @@ int phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind)
|
||||
ifi->NR_slot_indication(ind, &sched_response);
|
||||
|
||||
#ifdef ENABLE_AERIAL
|
||||
// phy_id is 1-based in cuBB; convert to 0-based CC index
|
||||
uint8_t CC_id = (ind->header.phy_id > 0) ? ind->header.phy_id - 1 : 0;
|
||||
bool send_slt_resp = false;
|
||||
if (sched_response.DL_req.dl_tti_request_body.nPDUs> 0) {
|
||||
oai_fapi_dl_tti_req(&sched_response.DL_req);
|
||||
oai_fapi_dl_tti_req(&sched_response.DL_req, CC_id);
|
||||
send_slt_resp = true;
|
||||
}
|
||||
if (sched_response.UL_tti_req.n_pdus > 0) {
|
||||
oai_fapi_ul_tti_req(&sched_response.UL_tti_req);
|
||||
oai_fapi_ul_tti_req(&sched_response.UL_tti_req, CC_id);
|
||||
send_slt_resp = true;
|
||||
}
|
||||
if (sched_response.TX_req.Number_of_PDUs > 0) {
|
||||
oai_fapi_tx_data_req(&sched_response.TX_req);
|
||||
oai_fapi_tx_data_req(&sched_response.TX_req, CC_id);
|
||||
send_slt_resp = true;
|
||||
}
|
||||
if (sched_response.UL_dci_req.numPdus > 0) {
|
||||
oai_fapi_ul_dci_req(&sched_response.UL_dci_req);
|
||||
oai_fapi_ul_dci_req(&sched_response.UL_dci_req, CC_id);
|
||||
send_slt_resp = true;
|
||||
}
|
||||
if (send_slt_resp) {
|
||||
oai_fapi_send_end_request(ind->sfn, ind->slot);
|
||||
oai_fapi_send_end_request(ind->sfn, ind->slot, CC_id);
|
||||
}
|
||||
#else
|
||||
if (sched_response.DL_req.dl_tti_request_body.nPDUs > 0)
|
||||
|
||||
@@ -11,19 +11,13 @@
|
||||
#include "nfapi_interface.h"
|
||||
#include "nfapi_nr_interface.h"
|
||||
|
||||
#define NFAPI_NR_MAX_NB_CCE_AGGREGATION_LEVELS 5
|
||||
#define NFAPI_NR_MAX_NB_TCI_STATES_PDCCH 64
|
||||
#define NFAPI_NR_MAX_NB_CORESETS 12
|
||||
#define NFAPI_NR_MAX_NB_SEARCH_SPACES 40
|
||||
|
||||
#define NFAPI_MAX_NUM_UL_UE_PER_GROUP 6
|
||||
#define NFAPI_MAX_NUM_UL_PDU 255
|
||||
#define NFAPI_MAX_NUM_UCI_INDICATION 8
|
||||
#define NFAPI_MAX_NUM_GROUPS 8
|
||||
#define NFAPI_MAX_NUM_CB 8
|
||||
#define NFAPI_MAX_NUM_PRGS 1
|
||||
#define NFAPI_MAX_NUM_BG_IF 6
|
||||
#define NFAPI_MAX_NUM_PERIODS 8
|
||||
|
||||
// Extension to the generic structures for single tlv values
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "../nrLDPC_coding_interface.h"
|
||||
#include "nrLDPC_coding_aal.h"
|
||||
#include "PHY/sse_intrin.h"
|
||||
#include "reverse_bits.h"
|
||||
#include "bits.h"
|
||||
#include <common/utils/LOG/log.h>
|
||||
#include "common/config/config_paramdesc.h"
|
||||
#include "common/config/config_userapi.h"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
#include "PHY/CODING/nrPolar_tools/nr_polar_defs.h"
|
||||
#include "reverse_bits.h"
|
||||
#include "bits.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -94,7 +94,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB)
|
||||
common_vars->analog_bf = cfg->analog_beamforming_ve.analog_bf_vendor_ext.value;
|
||||
LOG_I(PHY, "L1 configured with%s analog beamforming\n", common_vars->analog_bf ? "" : "out");
|
||||
if (common_vars->analog_bf) {
|
||||
// True only if nrmac->beam_info.beam_mode == FAPI_ANALOG_BEAM, thus analog_beamforming=2
|
||||
// True only if nrmac->beam_info[0].beam_mode == FAPI_ANALOG_BEAM, thus analog_beamforming=2
|
||||
common_vars->num_beams_period = cfg->analog_beamforming_ve.num_beams_period_vendor_ext.value;
|
||||
LOG_I(PHY, "Max number of concurrent beams: %d\n", common_vars->num_beams_period);
|
||||
} else
|
||||
|
||||
@@ -154,7 +154,7 @@ static void nr_pusch_antenna_processing(void *arg)
|
||||
}
|
||||
//------------------Write channel parameters to Memory for data recording ------------------//
|
||||
#if T_TRACER
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS)) {
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS) && nl == 0) {
|
||||
// Trace channel coefficients
|
||||
c16_t *pusch_ch_est_dmrs_pos_slot_mem = rdata->pusch_ch_est_dmrs_pos_slot_mem;
|
||||
int dmrs_symbol_start_idx = rdata->dmrs_symbol_start_idx;
|
||||
@@ -521,7 +521,7 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB,
|
||||
//------------------Write DMRS to Memory for Data Recording ------------------//
|
||||
int dmrs_symbol_start_idx = symbol * pusch_pdu->nrOfLayers * nb_rb_pusch * NR_NB_SC_PER_RB + nl * nb_rb_pusch * NR_NB_SC_PER_RB;
|
||||
#if T_TRACER
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS)) {
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS) && nl == 0) {
|
||||
// used by T-Tracer to trace DMRS slot grid
|
||||
int dmrs_delta = 0; // intialize it to zero currently, derive it later from above functions
|
||||
for (int i = 0; i < (6 * nb_rb_pusch); i++) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "PHY/NR_REFSIG/dmrs_nr.h"
|
||||
#include "log.h"
|
||||
#include "nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h"
|
||||
#include "bits.h"
|
||||
|
||||
uint8_t allowed_xlsch_re_in_dmrs_symbol(uint16_t k,
|
||||
uint16_t start_sc,
|
||||
|
||||
@@ -25,8 +25,13 @@ static void nr_pdsch_codeword_scrambling(uint8_t *in, uint32_t size, uint8_t q,
|
||||
nr_codeword_scrambling(in, size, q, Nid, n_RNTI, out);
|
||||
}
|
||||
|
||||
static uint32_t get_block_start_sc(int block_start, int bwp_start, int symbol_sz)
|
||||
{
|
||||
return (block_start + bwp_start) * NR_NB_SC_PER_RB;
|
||||
}
|
||||
|
||||
static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
|
||||
int start_sc,
|
||||
const freq_alloc_bitmap_t *freq_alloc,
|
||||
int symbol_sz,
|
||||
c16_t *txF,
|
||||
c16_t *tx_layer,
|
||||
@@ -34,21 +39,30 @@ static int do_ptrs_symbol(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
|
||||
c16_t *mod_ptrs)
|
||||
{
|
||||
int ptrs_idx = 0;
|
||||
int k = start_sc;
|
||||
c16_t *in = tx_layer;
|
||||
for (int i = 0; i < rel15->rbSize * NR_NB_SC_PER_RB; i++) {
|
||||
/* check for PTRS symbol and set flag for PTRS RE */
|
||||
bool is_ptrs_re =
|
||||
is_ptrs_subcarrier(k, rel15->rnti, rel15->PTRSFreqDensity, rel15->rbSize, rel15->PTRSReOffset, start_sc, symbol_sz);
|
||||
if (is_ptrs_re) {
|
||||
/* check if cuurent RE is PTRS RE*/
|
||||
uint16_t beta_ptrs = 1;
|
||||
txF[k] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * amp, 15);
|
||||
ptrs_idx++;
|
||||
int last_rb = freq_alloc->last_rb;
|
||||
int first_rb = freq_alloc->first_rb;
|
||||
uint32_t start_sc = get_block_start_sc(freq_alloc->first_rb, rel15->BWPStart, symbol_sz);
|
||||
int k = start_sc;
|
||||
for (int j = first_rb; j <= last_rb; j++) {
|
||||
if (check_rb_in_bitmap(freq_alloc, j)) {
|
||||
for (int i = 0; i < NR_NB_SC_PER_RB; i++) {
|
||||
/* check for PTRS symbol and set flag for PTRS RE */
|
||||
bool is_ptrs_re =
|
||||
is_ptrs_subcarrier(k, rel15->rnti, rel15->PTRSFreqDensity, freq_alloc->num_rbs, rel15->PTRSReOffset, start_sc, symbol_sz);
|
||||
if (is_ptrs_re) {
|
||||
/* check if cuurent RE is PTRS RE*/
|
||||
uint16_t beta_ptrs = 1;
|
||||
txF[k] = c16mulRealShift(mod_ptrs[ptrs_idx], beta_ptrs * amp, 15);
|
||||
ptrs_idx++;
|
||||
} else {
|
||||
txF[k] = c16mulRealShift(*in++, amp, 15);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
} else {
|
||||
txF[k] = c16mulRealShift(*in++, amp, 15);
|
||||
k += NR_NB_SC_PER_RB;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
return in - tx_layer;
|
||||
}
|
||||
@@ -210,15 +224,14 @@ static inline int interleave_signals(c16_t *output, c16_t *signal1, const int am
|
||||
static inline int dmrs_case00(c16_t *output,
|
||||
c16_t *txl,
|
||||
c16_t *mod_dmrs,
|
||||
const freq_alloc_bitmap_t *freq_alloc,
|
||||
const int16_t amp_dmrs,
|
||||
const int amp,
|
||||
int sz,
|
||||
int start_sc,
|
||||
int dmrs_port,
|
||||
const int dmrs_Type,
|
||||
int symbol_sz,
|
||||
int l_prime,
|
||||
uint8_t numDmrsCdmGrpsNoData)
|
||||
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15)
|
||||
{
|
||||
// DMRS params for this dmrs port
|
||||
int Wt[2], Wf[2];
|
||||
@@ -226,27 +239,37 @@ static inline int dmrs_case00(c16_t *output,
|
||||
get_Wf(Wf, dmrs_port, dmrs_Type);
|
||||
const int8_t delta = get_delta(dmrs_port, dmrs_Type);
|
||||
int dmrs_idx = 0;
|
||||
uint32_t start_sc = get_block_start_sc(freq_alloc->first_rb, rel15->BWPStart, symbol_sz);
|
||||
int k = start_sc;
|
||||
c16_t *in = txl;
|
||||
uint8_t k_prime = 0;
|
||||
uint16_t n = 0;
|
||||
for (int i = 0; i < sz; i++) {
|
||||
if (k == ((start_sc + get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type)) % (symbol_sz))) {
|
||||
output[k] = c16mulRealShift(mod_dmrs[dmrs_idx], Wt[l_prime] * Wf[k_prime] * amp_dmrs, 15);
|
||||
dmrs_idx++;
|
||||
k_prime = (k_prime + 1) & 1;
|
||||
n += (k_prime ? 0 : 1);
|
||||
int pos = freq_alloc->first_rb;
|
||||
int last_processed_rb = freq_alloc->first_rb;
|
||||
int block_start, block_end;
|
||||
while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) {
|
||||
// Mute skipped RBs
|
||||
int skipped_sc = (block_start - last_processed_rb) * NR_NB_SC_PER_RB;
|
||||
memset(output + k, 0, skipped_sc * sizeof(c16_t));
|
||||
k += skipped_sc;
|
||||
for (int j = block_start; j <= block_end; j++) {
|
||||
for (int i = 0; i < NR_NB_SC_PER_RB; i++) {
|
||||
if (k == ((start_sc + get_dmrs_freq_idx(n, k_prime, delta, dmrs_Type)) % (symbol_sz))) {
|
||||
output[k] = c16mulRealShift(mod_dmrs[dmrs_idx], Wt[l_prime] * Wf[k_prime] * amp_dmrs, 15);
|
||||
dmrs_idx++;
|
||||
k_prime = (k_prime + 1) & 1;
|
||||
n += (k_prime ? 0 : 1);
|
||||
} else if (allowed_xlsch_re_in_dmrs_symbol(k, start_sc, symbol_sz, rel15->numDmrsCdmGrpsNoData, dmrs_Type)) {
|
||||
/* Map PTRS Symbol */
|
||||
/* Map DATA Symbol */
|
||||
output[k] = c16mulRealShift(*in++, amp, 15);
|
||||
} else {
|
||||
output[k] = (c16_t){0};
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
/* Map PTRS Symbol */
|
||||
/* Map DATA Symbol */
|
||||
else if (allowed_xlsch_re_in_dmrs_symbol(k, start_sc, symbol_sz, numDmrsCdmGrpsNoData, dmrs_Type)) {
|
||||
output[k] = c16mulRealShift(*in++, amp, 15);
|
||||
}
|
||||
/* mute RE */
|
||||
else {
|
||||
output[k] = (c16_t){0};
|
||||
}
|
||||
k++;
|
||||
last_processed_rb = block_end + 1;
|
||||
} // RE loop
|
||||
return in - txl;
|
||||
}
|
||||
@@ -291,10 +314,10 @@ static inline void neg_dmrs(c16_t *in, c16_t *out, int sz)
|
||||
static inline void do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
|
||||
int slot,
|
||||
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
|
||||
const freq_alloc_bitmap_t *freq_alloc,
|
||||
int layer,
|
||||
c16_t *output,
|
||||
c16_t *txl_start,
|
||||
int start_sc,
|
||||
int symbol_sz,
|
||||
int l_symbol,
|
||||
uint16_t dlPtrsSymPos,
|
||||
@@ -306,7 +329,6 @@ static inline void do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *dmrs_start)
|
||||
{
|
||||
c16_t *txl = txl_start;
|
||||
const uint sz = rel15->rbSize * NR_NB_SC_PER_RB;
|
||||
|
||||
/* calculate if current symbol is PTRS symbols */
|
||||
int ptrs_symbol = 0;
|
||||
@@ -322,68 +344,83 @@ static inline void do_onelayer(NR_DL_FRAME_PARMS *frame_parms,
|
||||
const uint32_t *gold =
|
||||
nr_gold_pdsch(frame_parms->N_RB_DL, frame_parms->symbols_per_slot, rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol);
|
||||
nr_modulation(gold, n_ptrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_ptrs);
|
||||
txl += do_ptrs_symbol(rel15, start_sc, symbol_sz, output, txl, amp, mod_ptrs);
|
||||
txl += do_ptrs_symbol(rel15, freq_alloc, symbol_sz, output, txl, amp, mod_ptrs);
|
||||
|
||||
} else if (rel15->dlDmrsSymbPos & (1 << l_symbol)) {
|
||||
/* Map DMRS Symbol */
|
||||
int dmrs_port = get_dmrs_port(layer, rel15->dmrsPorts);
|
||||
if (l_prime == 0 && dmrs_Type == NFAPI_NR_DMRS_TYPE1) {
|
||||
if (rel15->numDmrsCdmGrpsNoData == 2) {
|
||||
switch (dmrs_port & 3) {
|
||||
case 0:
|
||||
txl += interleave_with_0_signal_first(output + start_sc, dmrs_start, amp_dmrs, sz);
|
||||
break;
|
||||
case 1: {
|
||||
c16_t dmrs[sz / 2];
|
||||
neg_dmrs(dmrs_start, dmrs, sz / 2);
|
||||
txl += interleave_with_0_signal_first(output + start_sc, dmrs, amp_dmrs, sz);
|
||||
} break;
|
||||
case 2:
|
||||
txl += interleave_with_0_start_with_0(output + start_sc, dmrs_start, amp_dmrs, sz);
|
||||
break;
|
||||
case 3: {
|
||||
c16_t dmrs[sz / 2];
|
||||
neg_dmrs(dmrs_start, dmrs, sz / 2);
|
||||
txl += interleave_with_0_start_with_0(output + start_sc, dmrs, amp_dmrs, sz);
|
||||
} break;
|
||||
}
|
||||
} else if (rel15->numDmrsCdmGrpsNoData == 1) {
|
||||
switch (dmrs_port & 3) {
|
||||
case 0:
|
||||
txl += interleave_signals(output + start_sc, txl, amp, dmrs_start, amp_dmrs, sz);
|
||||
break;
|
||||
case 1: {
|
||||
c16_t dmrs[sz / 2];
|
||||
neg_dmrs(dmrs_start, dmrs, sz / 2);
|
||||
txl += interleave_signals(output + start_sc, txl, amp, dmrs, amp_dmrs, sz);
|
||||
} break;
|
||||
case 2:
|
||||
txl += interleave_signals(output + start_sc, dmrs_start, amp_dmrs, txl, amp, sz);
|
||||
break;
|
||||
case 3: {
|
||||
c16_t dmrs[sz / 2];
|
||||
neg_dmrs(dmrs_start, dmrs, sz / 2);
|
||||
txl += interleave_signals(output + start_sc, dmrs, amp_dmrs, txl, amp, sz);
|
||||
} break;
|
||||
}
|
||||
} else
|
||||
AssertFatal(false, "rel15->numDmrsCdmGrpsNoData is %d\n", rel15->numDmrsCdmGrpsNoData);
|
||||
int pos = 0;
|
||||
int block_start, block_end;
|
||||
while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) {
|
||||
int start_rb = block_start;
|
||||
int nb_rb = block_end - block_start + 1;
|
||||
int start_sc = get_block_start_sc(start_rb, rel15->BWPStart, symbol_sz);
|
||||
const int sz = nb_rb * NR_NB_SC_PER_RB;
|
||||
if (rel15->numDmrsCdmGrpsNoData == 2) {
|
||||
switch (dmrs_port & 3) {
|
||||
case 0:
|
||||
txl += interleave_with_0_signal_first(output + start_sc, dmrs_start, amp_dmrs, sz);
|
||||
break;
|
||||
case 1: {
|
||||
c16_t dmrs[sz / 2];
|
||||
neg_dmrs(dmrs_start, dmrs, sz / 2);
|
||||
txl += interleave_with_0_signal_first(output + start_sc, dmrs, amp_dmrs, sz);
|
||||
} break;
|
||||
case 2:
|
||||
txl += interleave_with_0_start_with_0(output + start_sc, dmrs_start, amp_dmrs, sz);
|
||||
break;
|
||||
case 3: {
|
||||
c16_t dmrs[sz / 2];
|
||||
neg_dmrs(dmrs_start, dmrs, sz / 2);
|
||||
txl += interleave_with_0_start_with_0(output + start_sc, dmrs, amp_dmrs, sz);
|
||||
} break;
|
||||
}
|
||||
} else if (rel15->numDmrsCdmGrpsNoData == 1) {
|
||||
switch (dmrs_port & 3) {
|
||||
case 0:
|
||||
txl += interleave_signals(output + start_sc, txl, amp, dmrs_start, amp_dmrs, sz);
|
||||
break;
|
||||
case 1: {
|
||||
c16_t dmrs[sz / 2];
|
||||
neg_dmrs(dmrs_start, dmrs, sz / 2);
|
||||
txl += interleave_signals(output + start_sc, txl, amp, dmrs, amp_dmrs, sz);
|
||||
} break;
|
||||
case 2:
|
||||
txl += interleave_signals(output + start_sc, dmrs_start, amp_dmrs, txl, amp, sz);
|
||||
break;
|
||||
case 3: {
|
||||
c16_t dmrs[sz / 2];
|
||||
neg_dmrs(dmrs_start, dmrs, sz / 2);
|
||||
txl += interleave_signals(output + start_sc, dmrs, amp_dmrs, txl, amp, sz);
|
||||
} break;
|
||||
}
|
||||
} else
|
||||
AssertFatal(false, "rel15->numDmrsCdmGrpsNoData is %d\n", rel15->numDmrsCdmGrpsNoData);
|
||||
}
|
||||
} else {
|
||||
txl += dmrs_case00(output,
|
||||
txl,
|
||||
dmrs_start,
|
||||
freq_alloc,
|
||||
amp_dmrs,
|
||||
amp,
|
||||
sz,
|
||||
start_sc,
|
||||
dmrs_port,
|
||||
dmrs_Type,
|
||||
symbol_sz,
|
||||
l_prime,
|
||||
rel15->numDmrsCdmGrpsNoData);
|
||||
rel15);
|
||||
} // generic DMRS case
|
||||
} else { // no PTRS or DMRS in this symbol
|
||||
txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, sz);
|
||||
int pos = 0;
|
||||
int block_start, block_end;
|
||||
while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) {
|
||||
int start_rb = block_start;
|
||||
int nb_rb = block_end - block_start + 1;
|
||||
int start_sc = get_block_start_sc(start_rb, rel15->BWPStart, symbol_sz);
|
||||
const int sz = nb_rb * NR_NB_SC_PER_RB;
|
||||
txl += no_ptrs_dmrs_case(output + start_sc, txl, amp, sz);
|
||||
}
|
||||
} // no DMRS/PTRS in symbol
|
||||
return;
|
||||
}
|
||||
@@ -394,24 +431,25 @@ static inline void do_txdataF(c16_t **txdataF,
|
||||
PHY_VARS_gNB *gNB,
|
||||
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15,
|
||||
int ant,
|
||||
int start_sc,
|
||||
int rb_start,
|
||||
int rb_size,
|
||||
int txdataF_offset_per_symbol)
|
||||
{
|
||||
NR_DL_FRAME_PARMS *frame_parms = &gNB->frame_parms;
|
||||
int rb = 0;
|
||||
uint16_t subCarrier = start_sc;
|
||||
uint16_t subCarrier = get_block_start_sc(rb_start, rel15->BWPStart, symbol_sz);
|
||||
const nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming;
|
||||
while (rb < rel15->rbSize) {
|
||||
while (rb < rb_size) {
|
||||
// get pmi info
|
||||
const int pmi = (pb->prg_size > 0) ? (pb->prgs_list[(int)rb / pb->prg_size].pm_idx) : 0;
|
||||
const int pmi2 = (rb < (rel15->rbSize - 1) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 1) / pb->prg_size].pm_idx) : -1;
|
||||
const int pmi3 = (rb < (rel15->rbSize - 2) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 2) / pb->prg_size].pm_idx) : -1;
|
||||
const int pmi4 = (rb < (rel15->rbSize - 3) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 3) / pb->prg_size].pm_idx) : -1;
|
||||
const int pmi2 = (rb < (rb_size - 1) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 1) / pb->prg_size].pm_idx) : -1;
|
||||
const int pmi3 = (rb < (rb_size - 2) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 2) / pb->prg_size].pm_idx) : -1;
|
||||
const int pmi4 = (rb < (rb_size - 3) && pb->prg_size > 0) ? (pb->prgs_list[(int)(rb + 3) / pb->prg_size].pm_idx) : -1;
|
||||
|
||||
// If pmi of next RB and pmi of current RB are the same, we do 2 RB in a row
|
||||
// if pmi differs, or current rb is the end (rel15->rbSize - 1), than we do 1 RB in a row
|
||||
// if pmi differs, or current rb is the end (rb_size - 1), than we do 1 RB in a row
|
||||
int rb_step0 = pmi == pmi2 ? 2 : 1;
|
||||
const int rb_step = rb_step0==2 && pmi3==pmi && pmi4==pmi ? 4 : rb_step0;
|
||||
const int rb_step = rb_step0 == 2 && pmi3 == pmi && pmi4 == pmi ? 4 : rb_step0;
|
||||
const int re_cnt = NR_NB_SC_PER_RB * rb_step;
|
||||
if (pmi == 0) { // unitary Precoding
|
||||
if (ant < rel15->nrOfLayers)
|
||||
@@ -446,13 +484,14 @@ static inline void do_txdataF(c16_t **txdataF,
|
||||
} // else { // non-unitary Precoding
|
||||
|
||||
rb += rb_step;
|
||||
} // RB loop: while(rb < rel15->rbSize)
|
||||
} // RB loop: while(rb < rb_size)
|
||||
}
|
||||
|
||||
typedef struct pdschSymbolProc_s {
|
||||
PHY_VARS_gNB *gNB;
|
||||
NR_DL_FRAME_PARMS *frame_parms;
|
||||
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15;
|
||||
freq_alloc_bitmap_t *freq_alloc;
|
||||
unsigned int slot;
|
||||
unsigned int startSymbol;
|
||||
unsigned int numSymbols;
|
||||
@@ -478,14 +517,14 @@ static void nr_pdsch_symbol_processing(void *arg)
|
||||
c16_t *tx_layers[rel15->nrOfLayers];
|
||||
for (int l = 0; l < rel15->nrOfLayers; l++)
|
||||
tx_layers[l] = rdata->tx_layers[l];
|
||||
freq_alloc_bitmap_t *freq_alloc = rdata->freq_alloc;
|
||||
const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4);
|
||||
const int n_dmrs = (rel15->BWPStart + rel15->rbStart + rel15->rbSize) * nb_re_dmrs;
|
||||
const int n_dmrs = (rel15->BWPStart + freq_alloc->last_rb + 1) * nb_re_dmrs;
|
||||
// Loop Over OFDM symbols:
|
||||
c16_t mod_dmrs[(n_dmrs + 63) & ~63] __attribute__((aligned(64)));
|
||||
const int symbol_sz = frame_parms->ofdm_symbol_size;
|
||||
|
||||
c16_t **txdataF = gNB->common_vars.txdataF[rdata->beam_nb];
|
||||
uint16_t start_sc = (rel15->rbStart + rel15->BWPStart) * NR_NB_SC_PER_RB;
|
||||
|
||||
for (int l_symbol = rdata->startSymbol; l_symbol < rdata->startSymbol + rdata->numSymbols; l_symbol++) {
|
||||
start_meas(&rdata->dlsch_resource_mapping_stats);
|
||||
@@ -513,7 +552,7 @@ static void nr_pdsch_symbol_processing(void *arg)
|
||||
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_dmrs);
|
||||
|
||||
}
|
||||
uint32_t dmrs_idx = rel15->rbStart;
|
||||
uint32_t dmrs_idx = freq_alloc->first_rb;
|
||||
if (rel15->refPoint == 0)
|
||||
dmrs_idx += rel15->BWPStart;
|
||||
dmrs_idx *= rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4;
|
||||
@@ -522,10 +561,10 @@ static void nr_pdsch_symbol_processing(void *arg)
|
||||
do_onelayer(frame_parms,
|
||||
slot,
|
||||
rel15,
|
||||
freq_alloc,
|
||||
layer,
|
||||
txdataF_precoding[layer],
|
||||
tx_layers[layer] + rdata->re_beginning_of_symbol[l_symbol],
|
||||
start_sc,
|
||||
symbol_sz,
|
||||
l_symbol,
|
||||
rdata->dlPtrsSymPos,
|
||||
@@ -539,9 +578,22 @@ static void nr_pdsch_symbol_processing(void *arg)
|
||||
stop_meas(&rdata->dlsch_resource_mapping_stats);
|
||||
|
||||
start_meas(&rdata->dlsch_precoding_stats);
|
||||
const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz;
|
||||
for (int ant = 0; ant < frame_parms->nb_antennas_tx; ant++) {
|
||||
const size_t txdataF_offset_per_symbol = l_symbol * symbol_sz;
|
||||
do_txdataF(txdataF, symbol_sz, txdataF_precoding, gNB, rel15, ant, start_sc, txdataF_offset_per_symbol);
|
||||
int pos = 0;
|
||||
int block_start, block_end;
|
||||
while (find_next_rb_block(freq_alloc->bitmap, rel15->BWPSize, &pos, &block_start, &block_end)) {
|
||||
do_txdataF(txdataF,
|
||||
symbol_sz,
|
||||
txdataF_precoding,
|
||||
gNB,
|
||||
rel15,
|
||||
ant,
|
||||
block_start,
|
||||
block_end - block_start + 1,
|
||||
txdataF_offset_per_symbol);
|
||||
|
||||
}
|
||||
}
|
||||
stop_meas(&rdata->dlsch_precoding_stats);
|
||||
}
|
||||
@@ -555,20 +607,15 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
|
||||
|
||||
time_stats_t *dlsch_scrambling_stats = &gNB->dlsch_scrambling_stats;
|
||||
time_stats_t *dlsch_modulation_stats = &gNB->dlsch_modulation_stats;
|
||||
freq_alloc_bitmap_t *freq_alloc = &dlsch->freq_alloc;
|
||||
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15;
|
||||
const int layerSz = frame_parms->N_RB_DL * frame_parms->symbols_per_slot * NR_NB_SC_PER_RB;
|
||||
const int nb_re_dmrs = rel15->numDmrsCdmGrpsNoData * (rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1 ? 6 : 4);
|
||||
LOG_D(PHY,
|
||||
"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n",
|
||||
rel15->BWPStart,
|
||||
rel15->BWPSize,
|
||||
rel15->rbStart,
|
||||
rel15->rbSize);
|
||||
const int n_dmrs = rel15->rbSize * nb_re_dmrs;
|
||||
const int n_dmrs = freq_alloc->num_rbs * nb_re_dmrs;
|
||||
|
||||
const int xOverhead = 0;
|
||||
const int nb_re =
|
||||
(12 * rel15->NrOfSymbols - nb_re_dmrs * get_num_dmrs(rel15->dlDmrsSymbPos) - xOverhead) * rel15->rbSize * rel15->nrOfLayers;
|
||||
(12 * rel15->NrOfSymbols - nb_re_dmrs * get_num_dmrs(rel15->dlDmrsSymbPos) - xOverhead) * freq_alloc->num_rbs * rel15->nrOfLayers;
|
||||
const int Qm = rel15->qamModOrder[0];
|
||||
const int encoded_length = nb_re * Qm;
|
||||
|
||||
@@ -581,7 +628,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
|
||||
rel15->StartSymbolIndex,
|
||||
1 << rel15->PTRSTimeDensity,
|
||||
rel15->dlDmrsSymbPos);
|
||||
n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity;
|
||||
n_ptrs = (freq_alloc->num_rbs + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DLSCH
|
||||
@@ -692,6 +739,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
|
||||
|
||||
rdata->gNB = gNB;
|
||||
rdata->frame_parms = frame_parms;
|
||||
rdata->freq_alloc = freq_alloc;
|
||||
rdata->rel15 = rel15;
|
||||
rdata->slot = slot;
|
||||
rdata->startSymbol = l_symbol;
|
||||
@@ -706,7 +754,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
|
||||
rdata->beam_nb = beam_nb;
|
||||
for (int s = l_symbol; s < l_symbol + rdata->numSymbols; s++) {
|
||||
rdata->re_beginning_of_symbol[s] = re_beginning_of_symbol;
|
||||
re_beginning_of_symbol += rel15->rbSize * NR_NB_SC_PER_RB;
|
||||
re_beginning_of_symbol += freq_alloc->num_rbs * NR_NB_SC_PER_RB;
|
||||
if (n_ptrs > 0 && is_ptrs_symbol(s, dlPtrsSymPos)) {
|
||||
re_beginning_of_symbol -= n_ptrs;
|
||||
} else if (rel15->dlDmrsSymbPos & (1 << s)) {
|
||||
@@ -733,7 +781,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC
|
||||
/* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits)
|
||||
* should remain a multiple of 8 * 64 with enough offset to fit each dlsch
|
||||
*/
|
||||
uint32_t size_output_tb = rel15->rbSize * frame_parms->symbols_per_slot * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers;
|
||||
uint32_t size_output_tb = freq_alloc->num_rbs * frame_parms->symbols_per_slot * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers;
|
||||
return ((size_output_tb + 511) >> 9) << 6;
|
||||
}
|
||||
|
||||
@@ -754,12 +802,19 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
|
||||
NR_gNB_DLSCH_t *dlsch = &dlsch_array[i];
|
||||
const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *rel15 = &dlsch->pdsch_pdu->pdsch_pdu_rel15;
|
||||
|
||||
if (rel15->resourceAlloc == 0) {
|
||||
int alloc_size = (rel15->BWPSize / 8) + (rel15->BWPSize % 8 > 0);
|
||||
dlsch->freq_alloc = set_start_end_from_bitmap(rel15->BWPSize, alloc_size, rel15->rbBitmap);
|
||||
} else {
|
||||
dlsch->freq_alloc = set_bitmap_from_start_size(rel15->rbStart, rel15->rbSize);
|
||||
}
|
||||
LOG_D(PHY,
|
||||
"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbsize %d\n",
|
||||
"pdsch: BWPStart %d, BWPSize %d, rbStart %d, rbEnd %d rbsize %d\n",
|
||||
rel15->BWPStart,
|
||||
rel15->BWPSize,
|
||||
rel15->rbStart,
|
||||
rel15->rbSize);
|
||||
dlsch->freq_alloc.first_rb,
|
||||
dlsch->freq_alloc.last_rb,
|
||||
dlsch->freq_alloc.num_rbs);
|
||||
|
||||
const int Qm = rel15->qamModOrder[0];
|
||||
|
||||
@@ -773,7 +828,7 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
|
||||
rel15->StartSymbolIndex,
|
||||
1 << rel15->PTRSTimeDensity,
|
||||
rel15->dlDmrsSymbPos);
|
||||
n_ptrs = (rel15->rbSize + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity;
|
||||
n_ptrs = (dlsch->freq_alloc.num_rbs + rel15->PTRSFreqDensity - 1) / rel15->PTRSFreqDensity;
|
||||
ptrsSymbPerSlot = get_ptrs_symbols_in_slot(dlPtrsSymPos, rel15->StartSymbolIndex, rel15->NrOfSymbols);
|
||||
}
|
||||
dlsch->unav_res = ptrsSymbPerSlot * n_ptrs;
|
||||
@@ -784,7 +839,7 @@ void nr_generate_pdsch(PHY_VARS_gNB *gNB, int n_dlsch, NR_gNB_DLSCH_t *dlsch_arr
|
||||
/* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits)
|
||||
* => size_output is a sum of parts sizes rounded up to a multiple of 8 * 64
|
||||
*/
|
||||
size_t size_output_tb = rel15->rbSize * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers;
|
||||
size_t size_output_tb = dlsch->freq_alloc.num_rbs * NR_SYMBOLS_PER_SLOT * NR_NB_SC_PER_RB * Qm * rel15->nrOfLayers;
|
||||
size_output += ceil_mod(size_output_tb, 8 * 64);
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,8 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
}
|
||||
#endif
|
||||
|
||||
TB_parameters->nb_rb = rel15->rbSize;
|
||||
int rbsize = dlsch->freq_alloc.num_rbs;
|
||||
TB_parameters->nb_rb = rbsize;
|
||||
TB_parameters->Qm = rel15->qamModOrder[0];
|
||||
TB_parameters->mcs = rel15->mcsIndex[0];
|
||||
TB_parameters->nb_layers = rel15->nrOfLayers;
|
||||
@@ -217,7 +218,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
|
||||
int nb_re_dmrs =
|
||||
(rel15->dmrsConfigType == NFAPI_NR_DMRS_TYPE1) ? (6 * rel15->numDmrsCdmGrpsNoData) : (4 * rel15->numDmrsCdmGrpsNoData);
|
||||
TB_parameters->G = nr_get_G(rel15->rbSize,
|
||||
TB_parameters->G = nr_get_G(rbsize,
|
||||
rel15->NrOfSymbols,
|
||||
nb_re_dmrs,
|
||||
get_num_dmrs(rel15->dlDmrsSymbPos),
|
||||
@@ -226,7 +227,6 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
rel15->nrOfLayers);
|
||||
|
||||
TB_parameters->tbslbrm = rel15->maintenance_parms_v3.tbSizeLbrmBytes;
|
||||
|
||||
TB_parameters->output = &output[dlsch_offset >> 3];
|
||||
TB_parameters->segments = &segments[segments_offset];
|
||||
|
||||
@@ -245,7 +245,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
|
||||
/* output and its parts for each dlsch should be aligned on 64 bytes (or 8 * 64 bits)
|
||||
* => dlsch_offset should remain a multiple of 8 * 64 with enough offset to fit each dlsch
|
||||
*/
|
||||
const size_t dlsch_size = rel15->rbSize * gNB->frame_parms.symbols_per_slot * NR_NB_SC_PER_RB * rel15->qamModOrder[0] * rel15->nrOfLayers;
|
||||
const size_t dlsch_size = rbsize * gNB->frame_parms.symbols_per_slot * NR_NB_SC_PER_RB * rel15->qamModOrder[0] * rel15->nrOfLayers;
|
||||
dlsch_offset += ceil_mod(dlsch_size, 8 * 64);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
|
||||
#include "PHY/sse_intrin.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
#include "reverse_bits.h"
|
||||
#include "bits.h"
|
||||
#include "openair1/PHY/NR_REFSIG/nr_refsig.h"
|
||||
#include "openair1/PHY/NR_REFSIG/nr_mod_table.h"
|
||||
#include "openair1/PHY/TOOLS/tools_defs.h"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
void init_nr_prach(PHY_VARS_gNB *gNB)
|
||||
{
|
||||
int num_prach = 8;
|
||||
int num_prach = 16;
|
||||
gNB->prach_ru_queue = spsc_q_alloc(num_prach, sizeof(prach_item_t));
|
||||
gNB->prach_l1rx_queue = spsc_q_alloc(num_prach, sizeof(prach_item_t));
|
||||
}
|
||||
@@ -34,7 +34,8 @@ static bool drop_old_prach(const void *data, void *user)
|
||||
{
|
||||
const prach_item_t *p = data;
|
||||
const fsn_t *now = user;
|
||||
const fsn_t t = {p->frame, p->slot, now->mu};
|
||||
// account for long PRACH over more than 1 slot
|
||||
const fsn_t t = {p->frame, p->slot + p->num_slots - 1, now->mu};
|
||||
bool drop = fsn_in_the_past(t, *now);
|
||||
if (drop)
|
||||
LOG_E(NR_PHY, "%4d.%2d PRACH job is in the past (%4d.%2d)\n", now->f, now->s, t.f, t.s);
|
||||
@@ -45,7 +46,8 @@ static bool get_current_prach(const void *data, void *user)
|
||||
{
|
||||
const prach_item_t *p = data;
|
||||
const fsn_t *now = user;
|
||||
const fsn_t t = {p->frame, p->slot, now->mu};
|
||||
// account for long PRACH over more than 1 slot
|
||||
const fsn_t t = {p->frame, p->slot + p->num_slots - 1, now->mu};
|
||||
return fsn_equal(t, *now);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "PHY/NR_TRANSPORT/nr_dlsch.h"
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
#include "defs.h"
|
||||
#include "bits.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include <syscall.h>
|
||||
// #define DEBUG_ULSCH_DECODING
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
#include <openair1/PHY/TOOLS/phy_scope_interface.h>
|
||||
#include "PHY/sse_intrin.h"
|
||||
#include "T.h"
|
||||
#include "T_messages_creator.h"
|
||||
#include <sys/time.h>
|
||||
#include "PHY/log_tools.h"
|
||||
|
||||
|
||||
#if T_TRACER
|
||||
@@ -899,13 +899,16 @@ static void inner_rx(PHY_VARS_gNB *gNB,
|
||||
rel15_ul,
|
||||
frame_parms);
|
||||
#if T_TRACER
|
||||
int nb_re_pusch = NR_NB_SC_PER_RB * rel15_ul->rb_size;
|
||||
// Assume assume Tx and Rx = 1
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ)) {
|
||||
copy_c16_data_to_slot_memory(rxFext[aarx], rxFext_slot, nb_re_pusch, symbol);
|
||||
}
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL)) {
|
||||
copy_c16_data_to_slot_memory(chFext[aatx][aarx], chFext_slot, nb_re_pusch, symbol);
|
||||
// Data Recording application supports only 1 layer and 1 Tx antenna, so only record the first layer and first Tx antenna
|
||||
if (aatx == 0 && aarx == 0) {
|
||||
int nb_re_pusch = NR_NB_SC_PER_RB * rel15_ul->rb_size;
|
||||
// Assume assume Tx and Rx = 1
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ)) {
|
||||
copy_c16_data_to_slot_memory(rxFext[aarx], rxFext_slot, nb_re_pusch, symbol);
|
||||
}
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL)) {
|
||||
copy_c16_data_to_slot_memory(chFext[aatx][aarx], chFext_slot, nb_re_pusch, symbol);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1111,34 +1114,35 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
|
||||
// Memories to store data for data recording
|
||||
int buffer_length_slot = rel15_ul->rb_size * NR_NB_SC_PER_RB * 14; // 14 OFDM Symbols per slot
|
||||
int nb_rx_ant = frame_parms->nb_antennas_rx;
|
||||
int nb_layer = rel15_ul->nrOfLayers;
|
||||
// data recording application supports only a single layer.
|
||||
// nb_rx_ant (= frame_parms->nb_antennas_rx) is limited to 1 for data recording application.
|
||||
// int nb_layer (= rel15_ul->nrOfLayers) is limited to 1 for data recording application.
|
||||
|
||||
// Initialize memory for DMRS signals
|
||||
c16_t pusch_dmrs_slot_mem[nb_layer * buffer_length_slot] __attribute__((aligned(32)));
|
||||
c16_t pusch_dmrs_slot_mem[1 * buffer_length_slot] __attribute__((aligned(32)));
|
||||
// Initialize memory for channel estimates based on DMRS positions
|
||||
c16_t pusch_ch_est_dmrs_pos_slot_mem[buffer_length_slot * nb_layer * nb_rx_ant] __attribute__((aligned(32)));
|
||||
c16_t pusch_ch_est_dmrs_pos_slot_mem[buffer_length_slot * 1 * 1] __attribute__((aligned(32)));
|
||||
// memory to store slot grid with channel coefficients based on DMRS positions after interpolation
|
||||
c16_t pusch_ch_est_dmrs_interpl_slot_mem[buffer_length_slot * nb_layer * nb_rx_ant] __attribute__((aligned(32)));
|
||||
c16_t pusch_ch_est_dmrs_interpl_slot_mem[buffer_length_slot * 1 * 1] __attribute__((aligned(32)));
|
||||
// memory to store extracted data including PUSCH + DMRS
|
||||
c16_t rxFext_slot_mem[nb_rx_ant * buffer_length_slot] __attribute__((aligned(32)));
|
||||
c16_t rxFext_slot_mem[1 * buffer_length_slot] __attribute__((aligned(32)));
|
||||
|
||||
#if T_TRACER
|
||||
// Initialize memory for DMRS signals
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS))
|
||||
memset(pusch_dmrs_slot_mem, 0, sizeof(c16_t) * nb_layer * buffer_length_slot);
|
||||
memset(pusch_dmrs_slot_mem, 0, sizeof(c16_t) * 1 * buffer_length_slot);
|
||||
|
||||
// Initialize memory for channel estimates based on DMRS positions
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS))
|
||||
memset(pusch_ch_est_dmrs_pos_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_layer * nb_rx_ant);
|
||||
memset(pusch_ch_est_dmrs_pos_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * 1 * 1);
|
||||
|
||||
// memory to store slot grid with channel coefficients based on DMRS positions after interpolation
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL))
|
||||
memset(pusch_ch_est_dmrs_interpl_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_layer * nb_rx_ant);
|
||||
memset(pusch_ch_est_dmrs_interpl_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * 1 * 1);
|
||||
|
||||
// memory to store extracted data including PUSCH + DMRS
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ))
|
||||
memset(rxFext_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * nb_rx_ant);
|
||||
memset(rxFext_slot_mem, 0, sizeof(c16_t) * buffer_length_slot * 1 * 1);
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------
|
||||
@@ -1401,188 +1405,28 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB,
|
||||
} // symbol loop
|
||||
|
||||
#if T_TRACER
|
||||
// Get Time Stamp for T-tracer messages
|
||||
char trace_time_stamp_str[30];
|
||||
get_time_stamp_usec(trace_time_stamp_str);
|
||||
// trace_time_stamp_str = 8 bytes timestamp = YYYYMMDD
|
||||
// + 9 bytes timestamp = HHMMSSMMM
|
||||
// Not Ready for MIMO
|
||||
int dmrs_port = get_dmrs_port(0, rel15_ul->dmrs_ports);
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_DMRS)) {
|
||||
// Log GNB_PHY_UL_FD_DMRS using T-Tracer if activated
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port :
|
||||
// int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
T(T_GNB_PHY_UL_FD_DMRS,
|
||||
T_INT((int)frame),
|
||||
T_INT((int)slot),
|
||||
T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)),
|
||||
T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)),
|
||||
T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure
|
||||
T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2)
|
||||
T_INT((int)rel15_ul->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz)
|
||||
T_INT((int)rel15_ul->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended)
|
||||
T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot
|
||||
T_INT((int)frame_parms->Nid_cell),
|
||||
T_INT((int)rel15_ul->rnti),
|
||||
T_INT((int)rel15_ul->rb_size),
|
||||
T_INT((int)rel15_ul->rb_start),
|
||||
T_INT((int)rel15_ul->start_symbol_index), // start_ofdm_symbol
|
||||
T_INT((int)rel15_ul->nr_of_symbols), // num_ofdm_symbols
|
||||
T_INT((int)rel15_ul->qam_mod_order), // modulation
|
||||
T_INT((int)rel15_ul->mcs_index), // mcs
|
||||
T_INT((int)rel15_ul->mcs_table), // mcs_table_index
|
||||
T_INT((int)rel15_ul->nrOfLayers), // num_layer
|
||||
T_INT((int)rel15_ul->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1
|
||||
T_INT((int)rel15_ul->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1
|
||||
T_INT((int)rel15_ul->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions
|
||||
T_INT((int)number_dmrs_symbols),
|
||||
// dmrs_start_ofdm_symbol
|
||||
// dmrs_duration_num_ofdm_symbols
|
||||
// dmrs_num_add_positions
|
||||
T_INT((int)dmrs_port), // dmrs_antenna_port
|
||||
T_INT((int)rel15_ul->scid), // dmrs_nscid
|
||||
T_INT((int)frame_parms->nb_antennas_rx), // rx antenna
|
||||
T_INT(0), // number_of_bits
|
||||
T_BUFFER((c16_t *)(&(pusch_dmrs_slot_mem[0])), rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4));
|
||||
}
|
||||
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS)) {
|
||||
// Log GNB_PHY_UL_FD_CHAN_EST_DMRS_POS using T-Tracer if activated
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port :
|
||||
// int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
T(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_POS,
|
||||
T_INT((int)frame),
|
||||
T_INT((int)slot),
|
||||
T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)),
|
||||
T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)),
|
||||
T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure
|
||||
T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2)
|
||||
T_INT((int)rel15_ul->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz)
|
||||
T_INT((int)rel15_ul->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended)
|
||||
T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot
|
||||
T_INT((int)frame_parms->Nid_cell),
|
||||
T_INT((int)rel15_ul->rnti),
|
||||
T_INT((int)rel15_ul->rb_size),
|
||||
T_INT((int)rel15_ul->rb_start),
|
||||
T_INT((int)rel15_ul->start_symbol_index), // start_ofdm_symbol
|
||||
T_INT((int)rel15_ul->nr_of_symbols), // num_ofdm_symbols
|
||||
T_INT((int)rel15_ul->qam_mod_order), // modulation
|
||||
T_INT((int)rel15_ul->mcs_index), // mcs
|
||||
T_INT((int)rel15_ul->mcs_table), // mcs_table_index
|
||||
T_INT((int)rel15_ul->nrOfLayers), // num_layer
|
||||
T_INT((int)rel15_ul->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1
|
||||
T_INT((int)rel15_ul->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1
|
||||
T_INT((int)rel15_ul->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions
|
||||
T_INT((int)number_dmrs_symbols),
|
||||
// dmrs_start_ofdm_symbol
|
||||
// dmrs_duration_num_ofdm_symbols
|
||||
// dmrs_num_add_positions
|
||||
T_INT((int)dmrs_port), // dmrs_antenna_port
|
||||
T_INT((int)rel15_ul->scid), // dmrs_nscid
|
||||
T_INT((int)frame_parms->nb_antennas_rx), // rx antenna
|
||||
T_INT(0), // number_of_bits
|
||||
T_BUFFER((c16_t *)(&(pusch_ch_est_dmrs_pos_slot_mem[0])), rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4));
|
||||
}
|
||||
log_ul_fd_dmrs(frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
(const c16_t *)(&(pusch_dmrs_slot_mem[0])),
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4);
|
||||
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_PUSCH_IQ)) {
|
||||
// Log GNB_PHY_UL_FD_PUSCH_IQ using T-Tracer if activated
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port :
|
||||
// int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
log_ul_fd_chan_est_dmrs_pos(frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
(const c16_t *)(&(pusch_ch_est_dmrs_pos_slot_mem[0])),
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * 4);
|
||||
|
||||
T(T_GNB_PHY_UL_FD_PUSCH_IQ,
|
||||
T_INT((int)frame),
|
||||
T_INT((int)slot),
|
||||
T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)),
|
||||
T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)),
|
||||
T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure
|
||||
T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2)
|
||||
T_INT((int)rel15_ul->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz)
|
||||
T_INT((int)rel15_ul->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended)
|
||||
T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot
|
||||
T_INT((int)frame_parms->Nid_cell),
|
||||
T_INT((int)rel15_ul->rnti),
|
||||
T_INT((int)rel15_ul->rb_size),
|
||||
T_INT((int)rel15_ul->rb_start),
|
||||
T_INT((int)rel15_ul->start_symbol_index), // start_ofdm_symbol
|
||||
T_INT((int)rel15_ul->nr_of_symbols), // num_ofdm_symbols
|
||||
T_INT((int)rel15_ul->qam_mod_order), // modulation
|
||||
T_INT((int)rel15_ul->mcs_index), // mcs
|
||||
T_INT((int)rel15_ul->mcs_table), // mcs_table_index
|
||||
T_INT((int)rel15_ul->nrOfLayers), // num_layer
|
||||
T_INT((int)rel15_ul->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1
|
||||
T_INT((int)rel15_ul->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1
|
||||
T_INT((int)rel15_ul->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions
|
||||
T_INT((int)number_dmrs_symbols),
|
||||
// dmrs_start_ofdm_symbol
|
||||
// dmrs_duration_num_ofdm_symbols
|
||||
// dmrs_num_add_positions
|
||||
T_INT((int)dmrs_port), // dmrs_antenna_port
|
||||
T_INT((int)rel15_ul->scid), // dmrs_nscid
|
||||
T_INT((int)frame_parms->nb_antennas_rx), // rx antenna
|
||||
T_INT(0), // number_of_bits
|
||||
T_BUFFER((c16_t *)(&(rxFext_slot_mem[0])),
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * frame_parms->nb_antennas_rx * 4));
|
||||
}
|
||||
if (T_ACTIVE(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL)) {
|
||||
// Log pusch_ch_est_dmrs_interpl_slot_mem using T-Tracer if activated
|
||||
// FORMAT = int,frame : int,slot : int,datetime_yyyymmdd : int,datetime_hhmmssmmm :
|
||||
// int,frame_type : int,freq_range : int,subcarrier_spacing : int,cyclic_prefix : int,symbols_per_slot :
|
||||
// int,Nid_cell : int,rnti :
|
||||
// int,rb_size : int,rb_start : int,start_symbol_index : int,nr_of_symbols :
|
||||
// int,qam_mod_order : int,mcs_index : int,mcs_table : int,nrOfLayers :
|
||||
// int,transform_precoding : int,dmrs_config_type : int,ul_dmrs_symb_pos : int,number_dmrs_symbols : int,dmrs_port :
|
||||
// int,dmrs_nscid : int,nb_antennas_rx : int,number_of_bits : buffer,data
|
||||
log_ul_fd_pusch_iq(frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
(const c16_t *)(&(rxFext_slot_mem[0])),
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * frame_parms->nb_antennas_rx * 4);
|
||||
|
||||
T(T_GNB_PHY_UL_FD_CHAN_EST_DMRS_INTERPL,
|
||||
T_INT((int)frame),
|
||||
T_INT((int)slot),
|
||||
T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 0, 8)),
|
||||
T_INT((int)split_time_stamp_and_convert_to_int(trace_time_stamp_str, 8, 9)),
|
||||
T_INT((int)frame_parms->frame_type), // Frame type (0 FDD, 1 TDD) frame_structure
|
||||
T_INT((int)frame_parms->freq_range), // Frequency range (0 FR1, 1 FR2)
|
||||
T_INT((int)rel15_ul->subcarrier_spacing), // Subcarrier spacing (0 15kHz, 1 30kHz, 2 60kHz)
|
||||
T_INT((int)rel15_ul->cyclic_prefix), // Normal or extended prefix (0 normal, 1 extended)
|
||||
T_INT((int)frame_parms->symbols_per_slot), // Number of symbols per slot
|
||||
T_INT((int)frame_parms->Nid_cell),
|
||||
T_INT((int)rel15_ul->rnti),
|
||||
T_INT((int)rel15_ul->rb_size),
|
||||
T_INT((int)rel15_ul->rb_start),
|
||||
T_INT((int)rel15_ul->start_symbol_index), // start_ofdm_symbol
|
||||
T_INT((int)rel15_ul->nr_of_symbols), // num_ofdm_symbols
|
||||
T_INT((int)rel15_ul->qam_mod_order), // modulation
|
||||
T_INT((int)rel15_ul->mcs_index), // mcs
|
||||
T_INT((int)rel15_ul->mcs_table), // mcs_table_index
|
||||
T_INT((int)rel15_ul->nrOfLayers), // num_layer
|
||||
T_INT((int)rel15_ul->transform_precoding), // transformPrecoder_enabled = 0, transformPrecoder_disabled = 1
|
||||
T_INT((int)rel15_ul->dmrs_config_type), // dmrs_resource_map_config: pusch_dmrs_type1 = 0, pusch_dmrs_type2 = 1
|
||||
T_INT((int)rel15_ul->ul_dmrs_symb_pos), // used to derive the DMRS symbol positions
|
||||
T_INT((int)number_dmrs_symbols),
|
||||
// dmrs_start_ofdm_symbol
|
||||
// dmrs_duration_num_ofdm_symbols
|
||||
// dmrs_num_add_positions
|
||||
T_INT((int)dmrs_port), // dmrs_antenna_port
|
||||
T_INT((int)rel15_ul->scid), // dmrs_nscid
|
||||
T_INT((int)frame_parms->nb_antennas_rx), // rx antenna
|
||||
T_INT(0), // number_of_bits
|
||||
T_BUFFER(
|
||||
(c16_t *)pusch_ch_est_dmrs_interpl_slot_mem,
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols * frame_parms->nb_antennas_rx * rel15_ul->nrOfLayers * 4));
|
||||
}
|
||||
log_ul_fd_chan_est_dmrs_interpl(frame, slot, frame_parms, rel15_ul,
|
||||
number_dmrs_symbols, dmrs_port,
|
||||
(const c16_t *)pusch_ch_est_dmrs_interpl_slot_mem,
|
||||
rel15_ul->rb_size * NR_NB_SC_PER_RB * rel15_ul->nr_of_symbols
|
||||
* frame_parms->nb_antennas_rx * rel15_ul->nrOfLayers * 4);
|
||||
#endif
|
||||
|
||||
join_task_ans(&ans);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "nfapi/oai_integration/vendor_ext.h"
|
||||
#include "SCHED_NR/sched_nr.h"
|
||||
#include "reverse_bits.h"
|
||||
#include "bits.h"
|
||||
|
||||
#include "T.h"
|
||||
#include "nr_phy_common.h"
|
||||
|
||||
@@ -900,25 +900,30 @@ void nr_pdcch_channel_estimation(const PHY_VARS_NR_UE *ue,
|
||||
}
|
||||
}
|
||||
|
||||
void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *rxF,
|
||||
c16_t *pil,
|
||||
c16_t *dl_ch,
|
||||
unsigned short bwp_start_subcarrier,
|
||||
int rb_offset,
|
||||
int nb_rb_pdsch,
|
||||
const uint8_t bitmap[36],
|
||||
delay_t *delay,
|
||||
uint32_t *nvar)
|
||||
static void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *rxF,
|
||||
c16_t *pil,
|
||||
c16_t *dl_ch,
|
||||
unsigned short bwp_start_subcarrier,
|
||||
const freq_alloc_bitmap_t *freq_alloc,
|
||||
int nb_rb_pdsch,
|
||||
int bwpsize,
|
||||
delay_t *delay,
|
||||
uint32_t *nvar)
|
||||
{
|
||||
c16_t *dl_ch0 = dl_ch;
|
||||
int re_offset = bwp_start_subcarrier % frame_parms->ofdm_symbol_size;
|
||||
c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
memset(dl_ls_est, 0, sizeof(dl_ls_est));
|
||||
int idx = 0;
|
||||
for (int rb = rb_offset; rb < rb_offset + nb_rb_pdsch; rb++) {
|
||||
bool allocated_rb = (bitmap[rb / 8] >> (rb % 8)) & 0x01;
|
||||
if (allocated_rb) {
|
||||
int pos = freq_alloc->first_rb;
|
||||
int last_processed_rb = freq_alloc->first_rb;
|
||||
int block_start, block_end;
|
||||
while (find_next_rb_block(freq_alloc->bitmap, bwpsize, &pos, &block_start, &block_end)) {
|
||||
int skipped_rbs = block_start - last_processed_rb;
|
||||
pil += skipped_rbs * 6;
|
||||
re_offset = (re_offset + skipped_rbs * 12) % frame_parms->ofdm_symbol_size;
|
||||
for (int rb = block_start; rb <= block_end; rb++) {
|
||||
for (int pilot_cnt = 0; pilot_cnt < 6; pilot_cnt += 2) {
|
||||
c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
#ifdef DEBUG_PDSCH
|
||||
@@ -938,10 +943,8 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pil += 6;
|
||||
re_offset = (re_offset + 12) % frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
last_processed_rb = block_end + 1;
|
||||
}
|
||||
c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
nr_est_delay(frame_parms->ofdm_symbol_size, dl_ls_est, ch_estimates_time, delay);
|
||||
@@ -1071,9 +1074,9 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t *pil,
|
||||
c16_t *dl_ch,
|
||||
unsigned short bwp_start_subcarrier,
|
||||
int rb_offset,
|
||||
const freq_alloc_bitmap_t *freq_alloc,
|
||||
int nb_rb_pdsch,
|
||||
const uint8_t bitmap[36],
|
||||
int bwpsize,
|
||||
delay_t *delay,
|
||||
uint32_t *nvar)
|
||||
{
|
||||
@@ -1082,9 +1085,14 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
c16_t dl_ls_est[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
memset(dl_ls_est, 0, sizeof(dl_ls_est));
|
||||
int idx = 0;
|
||||
for (int rb = rb_offset; rb < rb_offset + nb_rb_pdsch; rb++) {
|
||||
bool allocated_rb = (bitmap[rb / 8] >> (rb % 8)) & 0x01;
|
||||
if (allocated_rb) {
|
||||
int pos = freq_alloc->first_rb;
|
||||
int last_processed_rb = freq_alloc->first_rb;
|
||||
int block_start, block_end;
|
||||
while (find_next_rb_block(freq_alloc->bitmap, bwpsize, &pos, &block_start, &block_end)) {
|
||||
int skipped_rbs = block_start - last_processed_rb;
|
||||
pil += skipped_rbs * 4;
|
||||
re_offset = (re_offset + skipped_rbs * 12) % frame_parms->ofdm_symbol_size;
|
||||
for (int rb = block_start; rb <= block_end; rb++) {
|
||||
for (int pilot_cnt = 0; pilot_cnt < 4; pilot_cnt += 2) {
|
||||
c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15);
|
||||
#ifdef DEBUG_PDSCH
|
||||
@@ -1104,10 +1112,8 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms,
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pil += 4;
|
||||
re_offset = (re_offset + 12) % frame_parms->ofdm_symbol_size;
|
||||
}
|
||||
last_processed_rb = block_end + 1;
|
||||
}
|
||||
|
||||
c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
@@ -1251,7 +1257,7 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
|
||||
const int ch_offset = fp->ofdm_symbol_size * symbol;
|
||||
const int symbol_offset = fp->ofdm_symbol_size * symbol;
|
||||
int bwp_start_subcarrier = fp->first_carrier_offset + (dlsch->BWPStart + freq_alloc->start[0]) * 12;
|
||||
int bwp_start_subcarrier = fp->first_carrier_offset + (dlsch->BWPStart + freq_alloc->first_rb) * 12;
|
||||
|
||||
#ifdef DEBUG_PDSCH
|
||||
printf(
|
||||
@@ -1268,8 +1274,8 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
|
||||
// generate pilot for gNB port number 1000+p
|
||||
int config_type = dlsch->dmrsConfigType;
|
||||
int rb_offset = freq_alloc->start[0] + (dlsch->refPoint ? 0 : dlsch->BWPStart);
|
||||
int nb_rb_pdsch = freq_alloc->end[freq_alloc->num_blocks - 1] - freq_alloc->start[0] + 1;
|
||||
int rb_offset = freq_alloc->first_rb + (dlsch->refPoint ? 0 : dlsch->BWPStart);
|
||||
int nb_rb_pdsch = freq_alloc->last_rb - freq_alloc->first_rb + 1;
|
||||
int8_t delta = get_delta(p, config_type);
|
||||
c16_t pilot[3280] __attribute__((aligned(16)));
|
||||
// Note: pilot returned by the following function is already the complex conjugate of the transmitted DMRS
|
||||
@@ -1297,9 +1303,9 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
&pilot[6 * rb_offset],
|
||||
dl_ch,
|
||||
bwp_start_subcarrier,
|
||||
freq_alloc->start[0],
|
||||
freq_alloc,
|
||||
nb_rb_pdsch,
|
||||
freq_alloc->bitmap,
|
||||
dlsch->BWPSize,
|
||||
&delay,
|
||||
nvar);
|
||||
|
||||
@@ -1309,9 +1315,9 @@ void nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue,
|
||||
&pilot[4 * rb_offset],
|
||||
dl_ch,
|
||||
bwp_start_subcarrier,
|
||||
freq_alloc->start[0],
|
||||
freq_alloc,
|
||||
nb_rb_pdsch,
|
||||
freq_alloc->bitmap,
|
||||
dlsch->BWPSize,
|
||||
&delay,
|
||||
nvar);
|
||||
|
||||
@@ -1372,6 +1378,7 @@ void nr_pdsch_ptrs_processing(int nbRx,
|
||||
NR_DL_UE_HARQ_t *dlsch1_harq,
|
||||
uint8_t nr_slot_rx,
|
||||
unsigned char symbol,
|
||||
int nb_rb,
|
||||
uint16_t rnti,
|
||||
NR_UE_DLSCH_t dlsch[2])
|
||||
{
|
||||
@@ -1388,7 +1395,6 @@ void nr_pdsch_ptrs_processing(int nbRx,
|
||||
uint16_t *ptrsSymbPos = NULL;
|
||||
uint8_t *ptrsSymbIdx = NULL;
|
||||
uint8_t *ptrsReOffset = NULL;
|
||||
uint16_t *nb_rb = NULL;
|
||||
int nscid = 0;
|
||||
|
||||
if(dlsch0_harq->status == NR_ACTIVE) {
|
||||
@@ -1399,7 +1405,6 @@ void nr_pdsch_ptrs_processing(int nbRx,
|
||||
K_ptrs = &dlsch[0].dlsch_config.PTRSFreqDensity;
|
||||
dmrsSymbPos = &dlsch[0].dlsch_config.dlDmrsSymbPos;
|
||||
ptrsReOffset = &dlsch[0].dlsch_config.PTRSReOffset;
|
||||
nb_rb = &dlsch[0].dlsch_config.number_rbs;
|
||||
ptrsSymbPos = &dlsch[0].ptrs_symbols;
|
||||
ptrsSymbIdx = &dlsch[0].ptrs_symbol_index;
|
||||
nscid = dlsch[0].dlsch_config.nscid;
|
||||
@@ -1412,7 +1417,6 @@ void nr_pdsch_ptrs_processing(int nbRx,
|
||||
K_ptrs = &dlsch[1].dlsch_config.PTRSFreqDensity;
|
||||
dmrsSymbPos = &dlsch[1].dlsch_config.dlDmrsSymbPos;
|
||||
ptrsReOffset = &dlsch[1].dlsch_config.PTRSReOffset;
|
||||
nb_rb = &dlsch[1].dlsch_config.number_rbs;
|
||||
ptrsSymbPos = &dlsch[1].ptrs_symbols;
|
||||
ptrsSymbIdx = &dlsch[1].ptrs_symbol_index;
|
||||
nscid = dlsch[1].dlsch_config.nscid;
|
||||
@@ -1456,7 +1460,7 @@ void nr_pdsch_ptrs_processing(int nbRx,
|
||||
nr_gold_pdsch(frame_parms->N_RB_DL, frame_parms->symbols_per_slot, frame_parms->Nid_cell, nscid, nr_slot_rx, symbol);
|
||||
nr_ptrs_cpe_estimation(*K_ptrs,
|
||||
*ptrsReOffset,
|
||||
*nb_rb,
|
||||
nb_rb,
|
||||
rnti,
|
||||
frame_parms->ofdm_symbol_size,
|
||||
rxdataF_comp[symbol][0][aarx],
|
||||
@@ -1492,11 +1496,7 @@ void nr_pdsch_ptrs_processing(int nbRx,
|
||||
#ifdef DEBUG_DL_PTRS
|
||||
printf("[PHY][DL][PTRS]: Rotate Symbol %2d with %d + j* %d\n", i, phase_per_symbol[i].r,phase_per_symbol[i].i);
|
||||
#endif
|
||||
rotate_cpx_vector(rxdataF_comp[i][0][aarx],
|
||||
&phase_per_symbol[i],
|
||||
rxdataF_comp[i][0][aarx],
|
||||
((*nb_rb) * NR_NB_SC_PER_RB),
|
||||
15);
|
||||
rotate_cpx_vector(rxdataF_comp[i][0][aarx], &phase_per_symbol[i], rxdataF_comp[i][0][aarx], nb_rb * NR_NB_SC_PER_RB, 15);
|
||||
}// if not DMRS Symbol
|
||||
}// symbol loop
|
||||
}// last symbol check
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#ifndef __NR_ESTIMATION_DEFS__H__
|
||||
#define __NR_ESTIMATION_DEFS__H__
|
||||
|
||||
|
||||
#include "PHY/nr_phy_common/inc/nr_phy_common.h"
|
||||
#include "PHY/defs_nr_UE.h"
|
||||
|
||||
/** @addtogroup _PHY_PARAMETER_ESTIMATION_BLOCKS_
|
||||
@@ -130,6 +130,7 @@ void nr_pdsch_ptrs_processing(int nbRx,
|
||||
NR_DL_UE_HARQ_t *dlsch1_harq,
|
||||
uint8_t nr_slot_rx,
|
||||
unsigned char symbol,
|
||||
int nb_rb,
|
||||
uint16_t rnti,
|
||||
NR_UE_DLSCH_t dlsch[2]);
|
||||
|
||||
|
||||
@@ -459,6 +459,7 @@ void nr_ue_meas_neighboring_cell(void *arg)
|
||||
do_neighboring_cell_measurements(&args->proc, args->ue, args->rxdata, args->rxdata_size);
|
||||
|
||||
args->ue->measurements.meas_request_pending = false;
|
||||
free(args->rxdata);
|
||||
free(args);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "PHY/NR_UE_ESTIMATION/filt16a_32.h"
|
||||
|
||||
// Additional memory allocation, because of applying the filter and the memory offset to ensure memory alignment
|
||||
#define FILTER_MARGIN 32
|
||||
|
||||
//#define NR_CSIRS_DEBUG
|
||||
//#define NR_CSIIM_DEBUG
|
||||
|
||||
@@ -259,9 +256,8 @@ static int nr_csi_rs_channel_estimation(
|
||||
const c16_t csi_rs_received_signal[][fp->samples_per_slot_wCP],
|
||||
const csi_mapping_parms_t *csi_mapping,
|
||||
const int CDM_group_size,
|
||||
uint8_t mem_offset,
|
||||
c16_t csi_rs_ls_estimated_channel[][csi_mapping->ports][fp->ofdm_symbol_size],
|
||||
c16_t csi_rs_estimated_channel_freq[][csi_mapping->ports][fp->ofdm_symbol_size + FILTER_MARGIN],
|
||||
c16_t csi_rs_estimated_channel_freq[][csi_mapping->ports][fp->ofdm_symbol_size],
|
||||
int16_t *log2_re,
|
||||
int16_t *log2_maxh,
|
||||
uint32_t *noise_power)
|
||||
@@ -274,12 +270,12 @@ static int nr_csi_rs_channel_estimation(
|
||||
|
||||
/// LS channel estimation
|
||||
|
||||
const uint16_t stop_rb = csirs_config_pdu->start_rb + csirs_config_pdu->nr_of_rbs;
|
||||
for(uint16_t port_tx = 0; port_tx < csi_mapping->ports; port_tx++) {
|
||||
memset(csi_rs_ls_estimated_channel[ant_rx][port_tx], 0, fp->ofdm_symbol_size * sizeof(c16_t));
|
||||
}
|
||||
|
||||
for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {
|
||||
|
||||
for (int rb = csirs_config_pdu->start_rb; rb < stop_rb; rb++) {
|
||||
// for freq density 0.5 checks if even or odd RB
|
||||
if(csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
|
||||
continue;
|
||||
@@ -307,8 +303,8 @@ static int nr_csi_rs_channel_estimation(
|
||||
c16MulConjShift(tx_csi_rs_signal[k_tx], rx_csi_rs_signal[k_rx], nr_csi_info->csi_rs_generated_signal_bits);
|
||||
// This is not just the LS estimation for each (k,l), but also the sum of the different contributions
|
||||
// for the sake of optimizing the memory used.
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit_rx].r += tmp.r;
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit_rx].i += tmp.i;
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit_tx].r += tmp.r;
|
||||
csi_rs_ls_estimated_channel[ant_rx][port_tx][kinit_tx].i += tmp.i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,11 +337,10 @@ static int nr_csi_rs_channel_estimation(
|
||||
/// Channel interpolation
|
||||
|
||||
for(uint16_t port_tx = 0; port_tx < csi_mapping->ports; port_tx++) {
|
||||
memset(csi_rs_estimated_channel_freq[ant_rx][port_tx], 0, (fp->ofdm_symbol_size + FILTER_MARGIN) * sizeof(c16_t));
|
||||
memset(csi_rs_estimated_channel_freq[ant_rx][port_tx], 0, (fp->ofdm_symbol_size) * sizeof(c16_t));
|
||||
}
|
||||
|
||||
for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {
|
||||
|
||||
for (int rb = csirs_config_pdu->start_rb; rb < stop_rb; rb++) {
|
||||
// for freq density 0.5 checks if even or odd RB
|
||||
if(csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
|
||||
continue;
|
||||
@@ -353,15 +348,13 @@ static int nr_csi_rs_channel_estimation(
|
||||
|
||||
count++;
|
||||
|
||||
uint16_t k = (fp->first_carrier_offset + rb * NR_NB_SC_PER_RB) % fp->ofdm_symbol_size;
|
||||
uint16_t k_offset = k + mem_offset;
|
||||
uint16_t k = rb * NR_NB_SC_PER_RB;
|
||||
for(uint16_t port_tx = 0; port_tx < csi_mapping->ports; port_tx++) {
|
||||
c16_t csi_rs_ls_estimated_channel16 = csi_rs_ls_estimated_channel[ant_rx][port_tx][k];
|
||||
c16_t *csi_rs_estimated_channel16 = &csi_rs_estimated_channel_freq[ant_rx][port_tx][k_offset];
|
||||
if( (k == 0) || (k == fp->first_carrier_offset) ) { // Start of OFDM symbol case or first occupied subcarrier case
|
||||
c16_t *csi_rs_estimated_channel16 = &csi_rs_estimated_channel_freq[ant_rx][port_tx][k];
|
||||
if (k == 0) { // Start of OFDM symbol case or first occupied subcarrier case
|
||||
multadd_real_vector_complex_scalar(filt24_start, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16, 24);
|
||||
} else if(((k + NR_NB_SC_PER_RB) >= fp->ofdm_symbol_size) ||
|
||||
(rb == (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs-1))) { // End of OFDM symbol case or Last occupied subcarrier case
|
||||
} else if (rb == (stop_rb - 1)) { // End of OFDM symbol case or Last occupied subcarrier case
|
||||
multadd_real_vector_complex_scalar(filt24_end, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16 - 12, 24);
|
||||
} else { // Middle case
|
||||
multadd_real_vector_complex_scalar(filt24_middle, csi_rs_ls_estimated_channel16, csi_rs_estimated_channel16 - 12, 24);
|
||||
@@ -373,15 +366,14 @@ static int nr_csi_rs_channel_estimation(
|
||||
AssertFatal(csirs_config_pdu->nr_of_rbs > 0, " nr_of_rbs needs to be greater than 0\n");
|
||||
uint16_t noise_real[fp->nb_antennas_rx][csi_mapping->ports][csirs_config_pdu->nr_of_rbs];
|
||||
uint16_t noise_imag[fp->nb_antennas_rx][csi_mapping->ports][csirs_config_pdu->nr_of_rbs];
|
||||
for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {
|
||||
for (int rb = csirs_config_pdu->start_rb; rb < stop_rb; rb++) {
|
||||
if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
|
||||
continue;
|
||||
}
|
||||
uint16_t k = (fp->first_carrier_offset + rb*NR_NB_SC_PER_RB) % fp->ofdm_symbol_size;
|
||||
uint16_t k_offset = k + mem_offset;
|
||||
uint16_t k = rb * NR_NB_SC_PER_RB;
|
||||
for(uint16_t port_tx = 0; port_tx < csi_mapping->ports; port_tx++) {
|
||||
c16_t *csi_rs_ls_estimated_channel16 = &csi_rs_ls_estimated_channel[ant_rx][port_tx][k];
|
||||
c16_t *csi_rs_estimated_channel16 = &csi_rs_estimated_channel_freq[ant_rx][port_tx][k_offset];
|
||||
c16_t *csi_rs_estimated_channel16 = &csi_rs_estimated_channel_freq[ant_rx][port_tx][k];
|
||||
noise_real[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel16->r-csi_rs_estimated_channel16->r);
|
||||
noise_imag[ant_rx][port_tx][rb-csirs_config_pdu->start_rb] = abs(csi_rs_ls_estimated_channel16->i-csi_rs_estimated_channel16->i);
|
||||
maxh = cmax3(maxh, abs(csi_rs_estimated_channel16->r), abs(csi_rs_estimated_channel16->i));
|
||||
@@ -393,19 +385,20 @@ static int nr_csi_rs_channel_estimation(
|
||||
|
||||
#ifdef NR_CSIRS_DEBUG
|
||||
for(int k = 0; k < fp->ofdm_symbol_size; k++) {
|
||||
int rb = k >= fp->first_carrier_offset ?
|
||||
(k - fp->first_carrier_offset)/NR_NB_SC_PER_RB :
|
||||
(k + fp->ofdm_symbol_size - fp->first_carrier_offset)/NR_NB_SC_PER_RB;
|
||||
int rb = k / NR_NB_SC_PER_RB;
|
||||
LOG_I(NR_PHY, "(k = %4d) |\t", k);
|
||||
for(uint16_t port_tx = 0; port_tx < csi_mapping->ports; port_tx++) {
|
||||
c16_t *csi_rs_ls_estimated_channel16 = &csi_rs_ls_estimated_channel[ant_rx][port_tx][0];
|
||||
c16_t *csi_rs_estimated_channel16 = &csi_rs_estimated_channel_freq[ant_rx][port_tx][mem_offset];
|
||||
c16_t *csi_rs_estimated_channel16 = &csi_rs_estimated_channel_freq[ant_rx][port_tx][0];
|
||||
printf("Channel port_tx %d --> ant_rx %d : ls (%4d,%4d), int (%4d,%4d), noise (%4d,%4d) | ",
|
||||
port_tx+3000, ant_rx,
|
||||
csi_rs_ls_estimated_channel16[k].r, csi_rs_ls_estimated_channel16[k].i,
|
||||
csi_rs_estimated_channel16[k].r, csi_rs_estimated_channel16[k].i,
|
||||
rb >= csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs ? 0 : noise_real[ant_rx][port_tx][rb-csirs_config_pdu->start_rb],
|
||||
rb >= csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs ? 0 : noise_imag[ant_rx][port_tx][rb-csirs_config_pdu->start_rb]);
|
||||
port_tx + 3000,
|
||||
ant_rx,
|
||||
csi_rs_ls_estimated_channel16[k].r,
|
||||
csi_rs_ls_estimated_channel16[k].i,
|
||||
csi_rs_estimated_channel16[k].r,
|
||||
csi_rs_estimated_channel16[k].i,
|
||||
rb >= stop_rb ? 0 : noise_real[ant_rx][port_tx][rb - csirs_config_pdu->start_rb],
|
||||
rb >= stop_rb ? 0 : noise_imag[ant_rx][port_tx][rb - csirs_config_pdu->start_rb]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
@@ -426,8 +419,7 @@ static int nr_csi_rs_channel_estimation(
|
||||
static int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue,
|
||||
const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
|
||||
const uint8_t N_ports,
|
||||
uint8_t mem_offset,
|
||||
c16_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size + FILTER_MARGIN],
|
||||
c16_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size],
|
||||
const int16_t log2_maxh,
|
||||
uint8_t *rank_indicator)
|
||||
{
|
||||
@@ -450,11 +442,11 @@ static int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue,
|
||||
*/
|
||||
|
||||
c16_t csi_rs_estimated_conjch_ch[frame_parms->nb_antennas_rx][N_ports][frame_parms->nb_antennas_rx][N_ports]
|
||||
[frame_parms->ofdm_symbol_size + FILTER_MARGIN] __attribute__((aligned(32)));
|
||||
int32_t csi_rs_estimated_A_MF[N_ports][N_ports][frame_parms->ofdm_symbol_size + FILTER_MARGIN] __attribute__((aligned(32)));
|
||||
int32_t csi_rs_estimated_A_MF_sq[N_ports][N_ports][frame_parms->ofdm_symbol_size + FILTER_MARGIN] __attribute__((aligned(32)));
|
||||
int32_t csi_rs_estimated_determ_fin[frame_parms->ofdm_symbol_size + FILTER_MARGIN] __attribute__((aligned(32)));
|
||||
int32_t csi_rs_estimated_numer_fin[frame_parms->ofdm_symbol_size + FILTER_MARGIN] __attribute__((aligned(32)));
|
||||
[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
int32_t csi_rs_estimated_A_MF[N_ports][N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
int32_t csi_rs_estimated_A_MF_sq[N_ports][N_ports][frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
int32_t csi_rs_estimated_determ_fin[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
int32_t csi_rs_estimated_numer_fin[frame_parms->ofdm_symbol_size] __attribute__((aligned(32)));
|
||||
const uint8_t sum_shift = 1; // log2(2x2) = 2, which is a shift of 1 bit
|
||||
|
||||
for (int rb = csirs_config_pdu->start_rb; rb < (csirs_config_pdu->start_rb+csirs_config_pdu->nr_of_rbs); rb++) {
|
||||
@@ -462,8 +454,7 @@ static int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue,
|
||||
if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
|
||||
continue;
|
||||
}
|
||||
uint16_t k = (frame_parms->first_carrier_offset + rb*NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;
|
||||
uint16_t k_offset = k + mem_offset;
|
||||
uint16_t k = rb * NR_NB_SC_PER_RB;
|
||||
|
||||
for (int ant_rx_conjch = 0; ant_rx_conjch < frame_parms->nb_antennas_rx; ant_rx_conjch++) {
|
||||
for(uint16_t port_tx_conjch = 0; port_tx_conjch < N_ports; port_tx_conjch++) {
|
||||
@@ -471,16 +462,17 @@ static int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue,
|
||||
for(uint16_t port_tx_ch = 0; port_tx_ch < N_ports; port_tx_ch++) {
|
||||
|
||||
// conjch x ch computation
|
||||
nr_conjch0_mult_ch1(&csi_rs_estimated_channel_freq[ant_rx_conjch][port_tx_conjch][k_offset],
|
||||
&csi_rs_estimated_channel_freq[ant_rx_ch][port_tx_ch][k_offset],
|
||||
&csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k_offset],
|
||||
nr_conjch0_mult_ch1(&csi_rs_estimated_channel_freq[ant_rx_conjch][port_tx_conjch][k],
|
||||
&csi_rs_estimated_channel_freq[ant_rx_ch][port_tx_ch][k],
|
||||
&csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k],
|
||||
1,
|
||||
log2_maxh);
|
||||
|
||||
// construct Hh x H elements
|
||||
if(ant_rx_conjch == ant_rx_ch) {
|
||||
nr_a_sum_b(
|
||||
(c16_t *)&csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k_offset], (c16_t *)&csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k_offset], 1);
|
||||
nr_a_sum_b((c16_t *)&csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k],
|
||||
(c16_t *)&csi_rs_estimated_conjch_ch[ant_rx_conjch][port_tx_conjch][ant_rx_ch][port_tx_ch][k],
|
||||
1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -488,44 +480,44 @@ static int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue,
|
||||
}
|
||||
|
||||
// compute the determinant of A_MF (denominator)
|
||||
nr_det_A_MF_2x2(&csi_rs_estimated_A_MF[0][0][k_offset],
|
||||
&csi_rs_estimated_A_MF[0][1][k_offset],
|
||||
&csi_rs_estimated_A_MF[1][0][k_offset],
|
||||
&csi_rs_estimated_A_MF[1][1][k_offset],
|
||||
&csi_rs_estimated_determ_fin[k_offset],
|
||||
nr_det_A_MF_2x2(&csi_rs_estimated_A_MF[0][0][k],
|
||||
&csi_rs_estimated_A_MF[0][1][k],
|
||||
&csi_rs_estimated_A_MF[1][0][k],
|
||||
&csi_rs_estimated_A_MF[1][1][k],
|
||||
&csi_rs_estimated_determ_fin[k],
|
||||
1);
|
||||
|
||||
// compute the square of A_MF (numerator)
|
||||
nr_squared_matrix_element(&csi_rs_estimated_A_MF[0][0][k_offset], &csi_rs_estimated_A_MF_sq[0][0][k_offset], 1);
|
||||
nr_squared_matrix_element(&csi_rs_estimated_A_MF[0][1][k_offset], &csi_rs_estimated_A_MF_sq[0][1][k_offset], 1);
|
||||
nr_squared_matrix_element(&csi_rs_estimated_A_MF[1][0][k_offset], &csi_rs_estimated_A_MF_sq[1][0][k_offset], 1);
|
||||
nr_squared_matrix_element(&csi_rs_estimated_A_MF[1][1][k_offset], &csi_rs_estimated_A_MF_sq[1][1][k_offset], 1);
|
||||
nr_numer_2x2(&csi_rs_estimated_A_MF_sq[0][0][k_offset],
|
||||
&csi_rs_estimated_A_MF_sq[0][1][k_offset],
|
||||
&csi_rs_estimated_A_MF_sq[1][0][k_offset],
|
||||
&csi_rs_estimated_A_MF_sq[1][1][k_offset],
|
||||
&csi_rs_estimated_numer_fin[k_offset],
|
||||
nr_squared_matrix_element(&csi_rs_estimated_A_MF[0][0][k], &csi_rs_estimated_A_MF_sq[0][0][k], 1);
|
||||
nr_squared_matrix_element(&csi_rs_estimated_A_MF[0][1][k], &csi_rs_estimated_A_MF_sq[0][1][k], 1);
|
||||
nr_squared_matrix_element(&csi_rs_estimated_A_MF[1][0][k], &csi_rs_estimated_A_MF_sq[1][0][k], 1);
|
||||
nr_squared_matrix_element(&csi_rs_estimated_A_MF[1][1][k], &csi_rs_estimated_A_MF_sq[1][1][k], 1);
|
||||
nr_numer_2x2(&csi_rs_estimated_A_MF_sq[0][0][k],
|
||||
&csi_rs_estimated_A_MF_sq[0][1][k],
|
||||
&csi_rs_estimated_A_MF_sq[1][0][k],
|
||||
&csi_rs_estimated_A_MF_sq[1][1][k],
|
||||
&csi_rs_estimated_numer_fin[k],
|
||||
1);
|
||||
|
||||
#ifdef NR_CSIRS_DEBUG
|
||||
for(uint16_t port_tx_conjch = 0; port_tx_conjch < N_ports; port_tx_conjch++) {
|
||||
for(uint16_t port_tx_ch = 0; port_tx_ch < N_ports; port_tx_ch++) {
|
||||
c16_t *csi_rs_estimated_A_MF_k = (c16_t *) &csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k_offset];
|
||||
c16_t *csi_rs_estimated_A_MF_k = (c16_t *)&csi_rs_estimated_A_MF[port_tx_conjch][port_tx_ch][k];
|
||||
LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF[%i][%i] = (%i, %i)\n",
|
||||
k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_k->r, csi_rs_estimated_A_MF_k->i);
|
||||
c16_t *csi_rs_estimated_A_MF_sq_k = (c16_t *) &csi_rs_estimated_A_MF_sq[port_tx_conjch][port_tx_ch][k_offset];
|
||||
c16_t *csi_rs_estimated_A_MF_sq_k = (c16_t *)&csi_rs_estimated_A_MF_sq[port_tx_conjch][port_tx_ch][k];
|
||||
LOG_I(NR_PHY, "(%i) csi_rs_estimated_A_MF_sq[%i][%i] = (%i, %i)\n",
|
||||
k, port_tx_conjch, port_tx_ch, csi_rs_estimated_A_MF_sq_k->r, csi_rs_estimated_A_MF_sq_k->i);
|
||||
}
|
||||
}
|
||||
LOG_I(NR_PHY, "(%i) csi_rs_estimated_determ_fin = %i\n", k, csi_rs_estimated_determ_fin[k_offset]);
|
||||
LOG_I(NR_PHY, "(%i) csi_rs_estimated_numer_fin = %i\n", k, csi_rs_estimated_numer_fin[k_offset]>>sum_shift);
|
||||
LOG_I(NR_PHY, "(%i) csi_rs_estimated_determ_fin = %i\n", k, csi_rs_estimated_determ_fin[k]);
|
||||
LOG_I(NR_PHY, "(%i) csi_rs_estimated_numer_fin = %i\n", k, csi_rs_estimated_numer_fin[k] >> sum_shift);
|
||||
#endif
|
||||
|
||||
// compute the conditional number
|
||||
for (int sc_idx=0; sc_idx < NR_NB_SC_PER_RB; sc_idx++) {
|
||||
int8_t csi_rs_estimated_denum_db = dB_fixed(csi_rs_estimated_determ_fin[k_offset + sc_idx]);
|
||||
int8_t csi_rs_estimated_numer_db = dB_fixed(csi_rs_estimated_numer_fin[k_offset + sc_idx]>>sum_shift);
|
||||
int8_t csi_rs_estimated_denum_db = dB_fixed(csi_rs_estimated_determ_fin[k + sc_idx]);
|
||||
int8_t csi_rs_estimated_numer_db = dB_fixed(csi_rs_estimated_numer_fin[k + sc_idx] >> sum_shift);
|
||||
int8_t cond_db = csi_rs_estimated_numer_db - csi_rs_estimated_denum_db;
|
||||
|
||||
#ifdef NR_CSIRS_DEBUG
|
||||
@@ -558,8 +550,7 @@ static int nr_csi_rs_ri_estimation(const PHY_VARS_NR_UE *ue,
|
||||
static int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue,
|
||||
const fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu,
|
||||
const uint8_t N_ports,
|
||||
uint8_t mem_offset,
|
||||
const c16_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size + FILTER_MARGIN],
|
||||
const c16_t csi_rs_estimated_channel_freq[][N_ports][ue->frame_parms.ofdm_symbol_size],
|
||||
const uint32_t interference_plus_noise_power,
|
||||
const uint8_t rank_indicator,
|
||||
const int16_t log2_re,
|
||||
@@ -586,10 +577,9 @@ static int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue,
|
||||
if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
|
||||
continue;
|
||||
}
|
||||
uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;
|
||||
uint16_t k_offset = k + mem_offset;
|
||||
uint16_t k = rb * NR_NB_SC_PER_RB;
|
||||
|
||||
const c16_t h = csi_rs_estimated_channel_freq[0][0][k_offset];
|
||||
const c16_t h = csi_rs_estimated_channel_freq[0][0][k];
|
||||
signal_power += (int64_t)h.r * h.r + (int64_t)h.i * h.i;
|
||||
count++;
|
||||
}
|
||||
@@ -614,11 +604,10 @@ static int nr_csi_rs_pmi_estimation(const PHY_VARS_NR_UE *ue,
|
||||
if (csirs_config_pdu->freq_density <= 1 && csirs_config_pdu->freq_density != (rb % 2)) {
|
||||
continue;
|
||||
}
|
||||
uint16_t k = (frame_parms->first_carrier_offset + rb * NR_NB_SC_PER_RB) % frame_parms->ofdm_symbol_size;
|
||||
uint16_t k_offset = k + mem_offset;
|
||||
uint16_t k = rb * NR_NB_SC_PER_RB;
|
||||
for (int ant_rx = 0; ant_rx < frame_parms->nb_antennas_rx; ant_rx++) {
|
||||
const c16_t p0 = csi_rs_estimated_channel_freq[ant_rx][0][k_offset];
|
||||
const c16_t p1 = csi_rs_estimated_channel_freq[ant_rx][1][k_offset];
|
||||
const c16_t p0 = csi_rs_estimated_channel_freq[ant_rx][0][k];
|
||||
const c16_t p1 = csi_rs_estimated_channel_freq[ant_rx][1][k];
|
||||
|
||||
// H_p0 + 1*H_p1 = (H_p0_re + H_p1_re) + 1j*(H_p0_im + H_p1_im)
|
||||
sum[0].r += (p0.r + p1.r);
|
||||
@@ -860,15 +849,12 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
|
||||
csi_info->csi_rs_generated_signal_bits = log2_approx(AMP);
|
||||
|
||||
/* OFDM symbol size \times sizeof(c16_t) is always multiple of 64. Since the
|
||||
estimates have first RB at start of buffer we don't need padding for 32 or 64
|
||||
byte alignment. */
|
||||
c16_t csi_rs_ls_estimated_channel[frame_parms->nb_antennas_rx][mapping_parms.ports][frame_parms->ofdm_symbol_size];
|
||||
c16_t csi_rs_estimated_channel_freq[frame_parms->nb_antennas_rx][mapping_parms.ports]
|
||||
[frame_parms->ofdm_symbol_size + FILTER_MARGIN];
|
||||
c16_t csi_rs_estimated_channel_freq[frame_parms->nb_antennas_rx][mapping_parms.ports][frame_parms->ofdm_symbol_size];
|
||||
|
||||
// (long)&csi_rs_estimated_channel_freq[0][0][frame_parms->first_carrier_offset] & 0x1F
|
||||
// gives us the remainder of the integer division by 32 of the memory address
|
||||
// By subtracting the previous value of 32, we know how much is left to have a multiple of 32.
|
||||
// Doing >> 2 <=> /sizeof(int32_t), we know what is the index offset of the array.
|
||||
uint8_t mem_offset = (((32 - ((long)&csi_rs_estimated_channel_freq[0][0][frame_parms->first_carrier_offset])) & 0x1F) >> 2);
|
||||
int CDM_group_size = get_cdm_group_size(csirs_config_pdu->cdm_type);
|
||||
c16_t csi_rs_received_signal[frame_parms->nb_antennas_rx][frame_parms->samples_per_slot_wCP];
|
||||
uint32_t rsrp = 0;
|
||||
@@ -902,7 +888,6 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
csi_rs_received_signal,
|
||||
&mapping_parms,
|
||||
CDM_group_size,
|
||||
mem_offset,
|
||||
csi_rs_ls_estimated_channel,
|
||||
csi_rs_estimated_channel_freq,
|
||||
&log2_re,
|
||||
@@ -915,7 +900,6 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
nr_csi_rs_ri_estimation(ue,
|
||||
csirs_config_pdu,
|
||||
mapping_parms.ports,
|
||||
mem_offset,
|
||||
csi_rs_estimated_channel_freq,
|
||||
log2_maxh,
|
||||
&rank_indicator);
|
||||
@@ -930,7 +914,6 @@ void nr_ue_csi_rs_procedures(PHY_VARS_NR_UE *ue,
|
||||
nr_csi_rs_pmi_estimation(ue,
|
||||
csirs_config_pdu,
|
||||
mapping_parms.ports,
|
||||
mem_offset,
|
||||
csi_rs_estimated_channel_freq,
|
||||
csi_info->csi_im_meas_computed ? csi_info->interference_plus_noise_power : noise_power,
|
||||
rank_indicator,
|
||||
|
||||
@@ -47,6 +47,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
|
||||
uint8_t **b,
|
||||
int *G,
|
||||
int nb_dlsch,
|
||||
int number_rbs,
|
||||
uint8_t *DLSCH_ids)
|
||||
{
|
||||
nrLDPC_TB_decoding_parameters_t TBs[nb_dlsch];
|
||||
@@ -95,7 +96,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
TB_parameters->G = G[DLSCH_id];
|
||||
TB_parameters->nb_rb = dlsch_config->number_rbs;
|
||||
TB_parameters->nb_rb = number_rbs;
|
||||
TB_parameters->Qm = dlsch_config->qamModOrder;
|
||||
TB_parameters->mcs = dlsch_config->mcs;
|
||||
TB_parameters->nb_layers = dlsch[DLSCH_id].Nl;
|
||||
@@ -256,7 +257,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
|
||||
kpiStructure.nb_total++;
|
||||
kpiStructure.blockSize = dlsch_config->TBS;
|
||||
kpiStructure.dl_mcs = dlsch_config->mcs;
|
||||
kpiStructure.nofRBs = dlsch_config->number_rbs;
|
||||
kpiStructure.nofRBs = number_rbs;
|
||||
|
||||
harq_process->decodeResult = harq_process->processedSegments == harq_process->C;
|
||||
|
||||
@@ -327,7 +328,7 @@ void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
|
||||
dlsch->dlsch_config.mcs,
|
||||
dlsch->Nl,
|
||||
dlsch_config->number_symbols,
|
||||
dlsch_config->number_rbs,
|
||||
number_rbs,
|
||||
dlsch_config->qamModOrder,
|
||||
Coderate);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "nr_transport_proto_ue.h"
|
||||
#include "PHY/sse_intrin.h"
|
||||
#include "T.h"
|
||||
#include "bits.h"
|
||||
#include "openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
||||
#include "PHY/NR_REFSIG/nr_refsig.h"
|
||||
#include "PHY/NR_REFSIG/dmrs_nr.h"
|
||||
@@ -276,21 +277,26 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz,
|
||||
int32_t dl_ch_estimates_ext[][rx_size_symbol],
|
||||
unsigned char symbol,
|
||||
uint8_t pilots,
|
||||
uint8_t config_type,
|
||||
int startBWP,
|
||||
const fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config,
|
||||
const freq_alloc_bitmap_t *freq_alloc,
|
||||
uint8_t n_dmrs_cdm_groups,
|
||||
uint8_t Nl,
|
||||
NR_DL_FRAME_PARMS *fp,
|
||||
uint16_t dlDmrsSymbPos,
|
||||
uint32_t csi_res_bitmap,
|
||||
int chest_time_type)
|
||||
{
|
||||
int config_type = dlsch_config->dmrsConfigType;
|
||||
int n_dmrs_cdm_groups = dlsch_config->n_dmrs_cdm_groups;
|
||||
if (config_type == NFAPI_NR_DMRS_TYPE1)
|
||||
AssertFatal(n_dmrs_cdm_groups == 1 || n_dmrs_cdm_groups == 2, "n_dmrs_cdm_groups %d is illegal\n", n_dmrs_cdm_groups);
|
||||
AssertFatal(n_dmrs_cdm_groups == 1
|
||||
|| n_dmrs_cdm_groups == 2,
|
||||
"n_dmrs_cdm_groups %d is illegal\n",
|
||||
n_dmrs_cdm_groups);
|
||||
else
|
||||
AssertFatal(n_dmrs_cdm_groups == 1 || n_dmrs_cdm_groups == 2 || n_dmrs_cdm_groups == 3,
|
||||
"n_dmrs_cdm_groups %d is illegal\n",n_dmrs_cdm_groups);
|
||||
AssertFatal(n_dmrs_cdm_groups == 1
|
||||
|| n_dmrs_cdm_groups == 2
|
||||
|| n_dmrs_cdm_groups == 3,
|
||||
"n_dmrs_cdm_groups %d is illegal\n",
|
||||
n_dmrs_cdm_groups);
|
||||
|
||||
uint32_t dmrs_rb_bitmap = 0;
|
||||
if (pilots) {
|
||||
@@ -312,13 +318,15 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz,
|
||||
uint32_t dmrs_csi_overlap_odd = csi_res_odd + dmrs_rb_bitmap;
|
||||
int8_t validDmrsEst;
|
||||
if (chest_time_type == 0)
|
||||
validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlDmrsSymbPos, symbol);
|
||||
validDmrsEst = get_valid_dmrs_idx_for_channel_est(dlsch_config->dlDmrsSymbPos, symbol);
|
||||
else
|
||||
validDmrsEst = get_next_dmrs_symbol_in_slot(dlDmrsSymbPos, 0, 14); // get first dmrs symbol index
|
||||
validDmrsEst = get_next_dmrs_symbol_in_slot(dlsch_config->dlDmrsSymbPos, 0, 14); // get first dmrs symbol index
|
||||
|
||||
for (int b = 0; b < freq_alloc->num_blocks; b++) {
|
||||
int start_rb = freq_alloc->start[b] + startBWP;
|
||||
int nb_rb = freq_alloc->end[b] - freq_alloc->start[b] + 1;
|
||||
int pos = 0;
|
||||
int block_start, block_end;
|
||||
while (find_next_rb_block(freq_alloc->bitmap, dlsch_config->BWPSize, &pos, &block_start, &block_end)) {
|
||||
int start_rb = block_start + dlsch_config->BWPStart;
|
||||
int nb_rb = block_end - block_start + 1;
|
||||
const int start_re = (fp->first_carrier_offset + start_rb * NR_NB_SC_PER_RB) % fp->ofdm_symbol_size;
|
||||
for (int aarx = 0; aarx < fp->nb_antennas_rx; aarx++) {
|
||||
c16_t *rxF_ext = rxdataF_ext[aarx];
|
||||
@@ -1076,13 +1084,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
dl_ch_estimates_ext,
|
||||
symbol,
|
||||
pilots,
|
||||
config_type,
|
||||
dlsch_config->BWPStart,
|
||||
dlsch_config,
|
||||
freq_alloc,
|
||||
dlsch_config->n_dmrs_cdm_groups,
|
||||
nl,
|
||||
fp,
|
||||
dlsch_config->dlDmrsSymbPos,
|
||||
csi_res_bitmap,
|
||||
ue->chest_time);
|
||||
stop_meas_nr_ue_phy(ue, DLSCH_EXTRACT_RBS_STATS);
|
||||
@@ -1112,13 +1117,13 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
uint32_t csi_re_count = 0;
|
||||
uint32_t csi_res_even = csi_res_bitmap & 0xfff;
|
||||
uint32_t csi_res_odd = (csi_res_bitmap >> 16) & 0xfff;
|
||||
int start = freq_alloc->start[0] + dlsch_config->BWPStart;
|
||||
int end = freq_alloc->end[freq_alloc->num_blocks - 1] + 1;
|
||||
uint32_t count_even = count_bits(&csi_res_even, 1);
|
||||
uint32_t count_odd = count_bits(&csi_res_odd, 1);
|
||||
int start = freq_alloc->first_rb + dlsch_config->BWPStart;
|
||||
int end = freq_alloc->last_rb + 1;
|
||||
for (int rb = start; rb < end; rb++) {
|
||||
if ((freq_alloc->bitmap[rb / 8] >> (rb % 8)) & 0x01) {
|
||||
uint32_t rb_csi_pattern = (rb % 2 == 0) ? csi_res_even : csi_res_odd;
|
||||
csi_re_count += __builtin_popcount(rb_csi_pattern);
|
||||
}
|
||||
if ((freq_alloc->bitmap[rb / 32] >> (rb % 32)) & 0x01)
|
||||
csi_re_count += (rb % 2 == 0) ? count_even : count_odd;
|
||||
}
|
||||
nb_re_pdsch = (nb_re_pdsch > csi_re_count) ? (nb_re_pdsch - csi_re_count) : 0;
|
||||
if (csi_re_count > 0) {
|
||||
@@ -1326,6 +1331,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue,
|
||||
dlsch1_harq,
|
||||
nr_slot_rx,
|
||||
symbol,
|
||||
freq_alloc->num_rbs,
|
||||
dlsch[0].rnti,
|
||||
dlsch);
|
||||
dl_valid_re[symbol] -= ptrs_re_per_slot[0][symbol];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user