From 94d59d515397bd3eb85bad20a7ad106234e9c353 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 12 Jul 2024 17:20:50 +0200 Subject: [PATCH 01/61] Fix link in documentation --- common/utils/LOG/DOC/rtusage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/utils/LOG/DOC/rtusage.md b/common/utils/LOG/DOC/rtusage.md index 04ff9647a8..b3de6cd71e 100644 --- a/common/utils/LOG/DOC/rtusage.md +++ b/common/utils/LOG/DOC/rtusage.md @@ -1,5 +1,5 @@ ## configuring the logging facility -The logging facility is fully configurable and it uses the [config module](../../../config/config.md) to get its parameters at init time. The [telnet server](../../telnetsrv/DOC/telnetsrv.md) includes a set of commands which can be used to dynamically modify the logging facility behavior +The logging facility is fully configurable and it uses the [config module](../../../../common/config/DOC/config.md) to get its parameters at init time. The [telnet server](../../telnetsrv/DOC/telnetsrv.md) includes a set of commands which can be used to dynamically modify the logging facility behavior All logging facility parameters are defined in the log_config section. Some parameters are global to the logging facility, they modify the way messages are printed to stdout. Conversely, some parameters are specific to a component and only modify the behavior for messages issued by a given component. A third type of parameters can be used to activate conditional debug code or dump messages or buffers. From 21de8666d3762b275f2e419d79578ec4212a6033 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 19 Aug 2024 17:06:03 +0200 Subject: [PATCH 02/61] Updated Wireshark documentation --- common/utils/T/DOC/T/wireshark.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/common/utils/T/DOC/T/wireshark.md b/common/utils/T/DOC/T/wireshark.md index 67587d139f..af11535bdc 100644 --- a/common/utils/T/DOC/T/wireshark.md +++ b/common/utils/T/DOC/T/wireshark.md @@ -103,7 +103,7 @@ of wireshark. Adapt as necessary. 2) Then, in the menu, choose `Edit->Preferences`. 3) In the preference window, unroll `Protocols` and configure the following: -**MAC** +**MAC-NR** Go to `MAC-NR`. Select: @@ -117,7 +117,7 @@ For `Source of LCID -> drb channel settings`: Type `AM, SN Len=18`, same thing for DL RLC Bearer Type. * Click OK. -**RLC** +**RLC-NR** Now, go to `RLC-NR`. Select: @@ -129,7 +129,7 @@ Now, go to `RLC-NR`. Select: You don't need to select `May see RLC headers only` and `Try to reassemble UM frames`. -**PDCP** +**PDCP-NR** Now, go to `PDCP-NR`. Select what you need in there. @@ -146,6 +146,12 @@ You are done with the preferences. You can click OK. 4) Then, in the menu `Analyze`, choose `Enabled Protocols...`. 5) In the new window search for `nr` and select `mac_nr_udp` to have `MAC-NR over UDP`. +**NAS-5GS** + +Under `NAS-5GS`, select: + +* `Try to detect and decode 5G-EA0 ciphered messages` + And that's it. Maybe other settings can be changed, but those steps should be enough for a start. From 031622b1a3f9606592e08872a228b7db46953430 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 25 Jul 2024 11:59:44 +0200 Subject: [PATCH 03/61] Review of CL options section in RUNMODEM * place all NR UE CL optional options in the same section, in a table * add a section for common CL options * add subsection for UE capabilities * removed redundant text --- doc/RUNMODEM.md | 68 +++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md index 928935f898..d0722ff8dd 100644 --- a/doc/RUNMODEM.md +++ b/doc/RUNMODEM.md @@ -102,47 +102,65 @@ Command line parameters for UE in `--sa` mode: - `--band` : NR band number (default value 78) - `--ssb` : SSB start subcarrier (default value 516) -**Optional parameters**: -- `-E`: use three-quarter sampling for split 8 sample rate. Required for - certain radios (e.g., 40MHz with B210). If used on the gNB, it is a good idea - to use for the UE as well (and vice versa). -- `--ue-scan-carrier` : scan for cells in current bandwidth. This option can be used if the SSB position of the gNB is unknown. If multiple cells are detected, the UE will try to connect to the first cell. By default, this option is disabled and the UE attempts to only decode SSB given by `--ssb`. +To simplify the configuration for the user testing OAI UE with OAI gNB, the latter prints the following LOG that guides the user to correctly set some of the UE command line parameters: -To simplify the configuration for the user testing OAI UE with OAI gNB, the latter prints the following LOG that guides the user to correctly set some of the UE command line parameters. - -``` +```shell [PHY] Command line parameters for OAI UE: -C 3319680000 -r 106 --numerology 1 --ssb 516 ``` You can run this, using USRPs, on two separate machines: -``` +```shell sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --sa sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --ssb 516 --sa ``` -With the RFsimulator (on the same machine): +With the **RFsimulator** (on the same machine), just add the option `--rfsim` to both gNB and NR UE command lines. -```bash -sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --rfsim --sa -sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --ssb 516 --rfsim --sa -``` +UE capabilities can be passed according to the [UE Capabilities](#UE-Capabilities) section. -Additionally, at UE side `--uecap_file` option can be used to pass the UE Capabilities input file (path location + filename), e.g. `--uecap_file ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports1.xml` +A detailed tutorial is provided at this page [NR_SA_Tutorial_OAI_nrUE.md](./NR_SA_Tutorial_OAI_nrUE.md). -## Some useful NR-UE parameters +## Optional NR-UE command line options -Some other useful paramters of the UE are +Here are some useful command line options for the NR UE: -- `--ue-fo-compensation`: enables the frequency offset compenstation at the UE. This is useful when running over the air and/or without an external clock/time source -- `--usrp-args`: this is the equivalend paramter of `sdr_addrs` field in the gNB config file and can be used to identify the USRP and set some basic paramters (like the clock source) -- `--clock-source`: sets the clock-source (internal or external). -- `--time-source`: sets the time-source (internal or external). +| Parameter | Description | +|--------------------------|---------------------------------------------------------------------------------------------------------------| +| `--ue-scan-carrier` | Scan for cells in current bandwidth. This option can be used if the SSB position of the gNB is unknown. If multiple cells are detected, the UE will try to connect to the first cell. By default, this option is disabled and the UE attempts to only decode SSB given by `--ssb`. | +| `--ue-fo-compensation` | Enables the frequency offset compensation at the UE. Useful when running over the air and/or without an external clock/time source. | +| `--usrp-args` | Equivalent to the `sdr_addrs` field in the gNB config file. Used to identify the USRP and set some basic parameters (like the clock source). | +| `--clock-source` | Sets the clock source (internal or external). | +| `--time-source` | Sets the time source (internal or external). | -You can see all options by typing -``` +You can view all available options by typing: + +```shell ./nr-uesoftmodem --help ``` +## Common gNB and NR UE command line options + +### Three-quarter sampling + +The command line option `-E` can be used to enable three-quarter sampling for split 8 sample rate. Required for certain radios (e.g., 40MHz with B210). If used on the gNB, it is a good idea to use for the UE as well (and vice versa). + +### UE Capabilities + +The `--uecap_file` option can be used to pass the UE Capabilities input file (path location + filename), e.g.`--uecap_file ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports1.xml` for 1 layer or e.g. `--uecap_file ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports2.xml` for 2 layers. + +This option is available for the following combinations of operation modes and gNB/nrUE softmodems: + +| Mode | Executable | Description | +|------------|----------------|-----------------------------------------------------| +| SA | nr-uesoftmodem | Send UE capabilities from the UE to the gNB via RRC | +| phy-test | nr-softmodem | Mimic the reception of UE capabilities by the gNB | +| do-ra | nr-softmodem | Mimic the reception of UE capabilities by the gNB | + +e.g. + +```shell +sudo ./nr-uesoftmodem --sa -r 106 --numerology 1 --band 78 -C 3319680000 --ue-nb-ant-tx 2 --ue-nb-ant-rx 2 --uecap_file /opt/oai-nr-ue/etc/uecap.xml +``` ## How to run a NTN configuration @@ -252,7 +270,7 @@ In summary: * `scp usera@machineA:/the/path/where/you/launched/nr-softmodem/r*config.raw userb@machineB:/the/path/where/you/will/launch/nr-uesoftmodem/` * Obviously this operation should be done before launching the `nr-uesoftmodem` executable. -In phy-test mode it is possible to mimic the reception of UE Capabilities at gNB by passing through the command line parameter `--uecap_file` the location and file name of the input UE Capability file, e.g. `--uecap_file ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports1.xml` (1 layer) or `--uecap_file ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports2.xml` (2 layers). +In phy-test mode it is possible to mimic the reception of UE Capabilities at gNB through the command line parameter `--uecap_file`. Refer to the [UE Capabilities](#UE-Capabilities) section for more details. ## noS1 setup with OAI UE @@ -288,7 +306,7 @@ The do-ra flag is used to ran the NR Random Access procedures in contention-free In order to run the RA, the `--do-ra` flag is needed for both the gNB and the UE. -In do-ra mode it is possible to mimic the reception of UE Capabilities at gNB by passing through the command line parameter `--uecap_file` the location and file name of the input UE Capability file, e.g. `--uecap_file ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/uecap_ports1.xml` +In do-ra mode it is possible to mimic the reception of UE Capabilities at gNB through the command line parameter `--uecap_file`. Refer to the [UE Capabilities](#UE-Capabilities) section for more details. To run using the RFsimulator: From 1793e7e56d94e08c6e0042fd50ae901a78fd3af7 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Tue, 27 Aug 2024 14:47:17 +0200 Subject: [PATCH 04/61] fix(docker): aligning all rockylinux-9 Dockerfiles with the RHEL9 ones Signed-off-by: Raphael Defosseux --- cmake_targets/tools/build_helper | 1 + docker/Dockerfile.base.rocky | 21 +++++- docker/Dockerfile.build.rocky | 10 ++- docker/Dockerfile.gNB.fhi72.rocky | 117 ++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 docker/Dockerfile.gNB.fhi72.rocky diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index ac336478df..0317baf6b4 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -137,6 +137,7 @@ check_supported_distribution() { "rocky9.1") return 0 ;; "rocky9.2") return 0 ;; "rocky9.3") return 0 ;; + "rocky9.4") return 0 ;; esac return 1 } diff --git a/docker/Dockerfile.base.rocky b/docker/Dockerfile.base.rocky index 0e9d630bac..44be527344 100644 --- a/docker/Dockerfile.base.rocky +++ b/docker/Dockerfile.base.rocky @@ -35,6 +35,7 @@ ENV UHD_VERSION=4.4.0.0 RUN dnf install 'dnf-command(config-manager)' -y && \ dnf install epel-release -y && crb enable && \ dnf update -y && \ + cat /etc/os-release && \ dnf install -y \ #gcc needed for build_oai gcc gcc-c++ \ @@ -42,9 +43,22 @@ RUN dnf install 'dnf-command(config-manager)' -y && \ file \ psmisc \ git \ + meson \ + wget \ + xz \ + pkg-config \ + pcre2-devel \ + m4 \ + python3-devel \ + numactl-libs \ + numactl-devel \ + gcc-toolset-12-gcc \ + gcc-toolset-12-gcc-c++ \ # python3-pip and pyyaml are used for conf template generation python3-pip && \ - pip3 install --ignore-installed pyyaml + pip3 install --ignore-installed pyyaml && \ + echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ + echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf # Add "Tini - A tiny but valid init for containers", https://github.com/krallin/tini # it will be copied into target containers, to print exit numbers and handle signals properly @@ -65,7 +79,8 @@ WORKDIR /oai-ran COPY oaienv . #run build_oai -I to get the builder image -RUN /bin/sh oaienv && \ +RUN /bin/sh oaienv && \ cd cmake_targets && \ mkdir -p log && \ - ./build_oai -I --install-optional-packages -w USRP + scl enable gcc-toolset-12 "\ + ./build_oai -I --install-optional-packages -w USRP" diff --git a/docker/Dockerfile.build.rocky b/docker/Dockerfile.build.rocky index 3fe164b10d..1126c42057 100644 --- a/docker/Dockerfile.build.rocky +++ b/docker/Dockerfile.build.rocky @@ -35,4 +35,12 @@ COPY . . RUN /bin/sh oaienv && \ cd cmake_targets && \ mkdir -p log && \ - ./build_oai --eNB --gNB --RU --UE --nrUE --ninja --build-lib "telnetsrv enbscope uescope nrscope" -w USRP -t Ethernet --noavx512 -c + CXXFLAGS="-Werror -fstack-protector-strong" CFLAGS="-Werror -fstack-protector-strong" ./build_oai -c --ninja \ + --eNB --gNB --RU --UE --nrUE \ + --build-lib "telnetsrv enbscope uescope nrscope" \ + -w USRP -t Ethernet \ + --noavx512 && \ + echo "---- ldd on executables ----" && \ + ldd ran_build/build/*softmodem* ran_build/build/nr-cuup ran_build/build/oairu && \ + echo "---- ldd on shared libraries ----" && \ + ldd ran_build/build/*.so diff --git a/docker/Dockerfile.gNB.fhi72.rocky b/docker/Dockerfile.gNB.fhi72.rocky new file mode 100644 index 0000000000..a98c0b1948 --- /dev/null +++ b/docker/Dockerfile.gNB.fhi72.rocky @@ -0,0 +1,117 @@ +#/* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# +# Dockerfile for the Open-Air-Interface 7.2 Fronthaul +# Valid for Rocky 9 +# +#--------------------------------------------------------------------- + +FROM ran-base:latest AS gnb-base + +FROM ran-build-fhi72:latest AS gnb-build + +#start from scratch for target executable +FROM docker.io/rockylinux:9 AS oai-gnb-fhi72 +ENV TZ=Europe/Paris + +RUN dnf update -y && \ + dnf install -y \ + procps-ng \ + libXpm \ + libX11 \ + lksctp-tools \ + xz \ + numactl-libs \ + numactl-devel \ + pkg-config \ + pciutils \ + tzdata \ + gdb \ + python3 \ + python3-pip \ + net-tools \ + iputils && \ + pip3 install six && \ + pip3 install requests && \ + echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ + echo "/usr/local/lib64" >> /etc/ld.so.conf.d/local-lib.conf + +WORKDIR /opt/oai-gnb/bin +COPY --from=gnb-build \ + /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ +COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh + +COPY --from=gnb-build \ + /oai-ran/cmake_targets/ran_build/build/librfsimulator.so \ + /oai-ran/cmake_targets/ran_build/build/liboran_fhlib_5g.so \ + /oai-ran/cmake_targets/ran_build/build/liboai_transpro.so \ + /oai-ran/cmake_targets/ran_build/build/libcoding.so \ + /oai-ran/cmake_targets/ran_build/build/libparams_libconfig.so \ + /oai-ran/cmake_targets/ran_build/build/libdfts.so \ + /oai-ran/cmake_targets/ran_build/build/libldpc*.so \ + /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ + /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ci.so \ + /usr/local/lib/ + +## Libxran library +COPY --from=gnb-build \ + /opt/phy/fhi_lib/lib/build/libxran.so \ + /opt/phy/fhi_lib/lib/build/ + +## Copy all DPDK libraries as liboran_fhlib_5g.so require most of them +COPY --from=gnb-build /usr/local/lib64/ /usr/local/lib64/ + +## Copy E2 SM models +COPY --from=gnb-build /usr/local/lib64/flexric /usr/local/lib64/flexric + +# Copying file for configuration module +COPY --from=gnb-base \ + /lib64/libconfig.so.11 \ + /lib64/libforms.so.2 \ + /lib64/libblas.so.3 \ + /lib64/libcblas.so.3 \ + /lib64/liblapack.so.3 \ + /lib64/liblapacke.so.3 \ + /lib64/libicudata.so.67 \ + /lib64/libicui18n.so.67 \ + /lib64/libicuuc.so.67 \ + /lib64/ + +RUN ldconfig && \ + echo "---- ldd on executable nr-softmodem ----" && \ + ldd /opt/oai-gnb/bin/nr-softmodem && \ + echo "---- ldd on shared libraries ----" && \ + ldd /usr/local/lib/librfsimulator.so \ + /usr/local/lib/liboran_fhlib_5g.so \ + /usr/local/lib/liboai_transpro.so \ + /usr/local/lib/libcoding.so \ + /usr/local/lib/libparams_libconfig.so \ + /usr/local/lib/libdfts.so \ + /usr/local/lib/libldpc*.so \ + /usr/local/lib/libtelnetsrv.so \ + /usr/local/lib/libtelnetsrv_ci.so \ + /opt/phy/fhi_lib/lib/build/libxran.so + +WORKDIR /opt/oai-gnb +COPY --from=gnb-base /tini /tini +ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-gnb/bin/entrypoint.sh"] +CMD ["/opt/oai-gnb/bin/nr-softmodem", "-O", "/opt/oai-gnb/etc/gnb.conf"] From 0ef6153bb9a67e2277e9ba417d9f5fbed9ac9019 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 16 Aug 2024 13:35:04 +0200 Subject: [PATCH 05/61] Fix memory leak of NAS buffer transfered to RRC with NAS_UPLINK_DATA_REQ * Data buffer for NAS Registration Complete and Authentication Response is malloced in the NAS thread and transfered with ITTI message to RRC, where needs to be freed Direct leak of 24 byte(s) in 1 object(s) allocated from: >0 0x7ffff74b4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145 >1 0x5555572b0607 in generateAuthenticationResp /repo/openairinterface5g/develop/openair3/NAS/NR_UE/nr_nas_msg_sim.c:608 >2 0x5555572b0607 in nas_nrue /repo/openairinterface5g/develop/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1402 >3 0x5555572baef6 in nas_nrue_task /repo/openairinterface5g/develop/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1198 >4 0x7ffff5e94ac2 in start_thread nptl/pthread_create.c:442 Direct leak of 10 byte(s) in 1 object(s) allocated from: >0 0x7ffff74b4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145 >1 0x55555729754e in generateRegistrationComplete /repo/openairinterface5g/develop/openair3/NAS/NR_UE/nr_nas_msg_sim.c:782 >2 0x555557299ad3 in handle_registration_accept /repo/openairinterface5g/develop/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1212 >3 0x5555572b06a0 in nas_nrue /repo/openairinterface5g/develop/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1411 >4 0x5555572baef6 in nas_nrue_task /repo/openairinterface5g/develop/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1198 >5 0x7ffff5e94ac2 in start_thread nptl/pthread_create.c:442 --- openair2/RRC/NR_UE/rrc_UE.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index eb5113ccee..327f4fcf7b 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1823,6 +1823,7 @@ void *rrc_nrue(void *notUsed) // error: the remote gNB is hardcoded here rb_id_t srb_id = rrc->Srb[2] == RB_ESTABLISHED ? 2 : 1; nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, length, buffer, deliver_pdu_srb_rlc, NULL); + free(req->nasMsg.data); free(buffer); break; } From 8e9f6385cc481529bb27803c6feb7eafdf46012a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 30 Aug 2024 14:57:45 +0200 Subject: [PATCH 06/61] Fix memory leak in generateAuthenticationResp > Direct leak of 16 byte(s) in 1 object(s) allocated from: >0 0x7ffff74b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 >1 0x55555818ef1c in generateAuthenticationResp /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:588 >2 0x5555581b0fca in nas_nrue /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1405 >3 0x5555581a3069 in nas_nrue_task /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1213 >4 0x7ffff5e94ac2 in start_thread nptl/pthread_create.c:442 --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 0baab7b65c..aedcf71cbc 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -614,6 +614,8 @@ static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialN initialNasMsg->data = (Byte_t *)malloc(size * sizeof(Byte_t)); initialNasMsg->length = mm_msg_encode(mm_msg, (uint8_t *)(initialNasMsg->data), size); + // Free res value after encode + free(res.value); } int nas_itti_kgnb_refresh_req(instance_t instance, const uint8_t kgnb[32]) From 0265607a9523972e51035a71be619a149c57456a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 30 Aug 2024 15:01:45 +0200 Subject: [PATCH 07/61] Fix memory leaks in NAS generatePduSessionEstablishRequest >Direct leak of 7 byte(s) in 1 object(s) allocated from: >0 0x7ffff74b4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145 >1 0x55555819ab3c in generatePduSessionEstablishRequest /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:938 >2 0x5555581a8a9f in nas_nrue /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1295 >3 0x5555581a3078 in nas_nrue_task /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1215 >4 0x7ffff5e94ac2 in start_thread nptl/pthread_create.c:442 > Direct leak of 4 byte(s) in 1 object(s) allocated from: >0 0x7ffff74b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 >1 0x55555819c025 in generatePduSessionEstablishRequest /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:993 >2 0x5555581a8a9f in nas_nrue /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1295 >3 0x5555581a3078 in nas_nrue_task /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1215 >4 0x7ffff5e94ac2 in start_thread nptl/pthread_create.c:442 > Direct leak of 1 byte(s) in 1 object(s) allocated from: >0 0x7ffff74b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 >1 0x55555819c8f7 in generatePduSessionEstablishRequest /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:987 >2 0x5555581a9b75 in nas_nrue /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1299 >3 0x5555581a414e in nas_nrue_task /home/guido/repo/openairinterface5g/fix-ue-memory-leaks/openair3/NAS/NR_UE/nr_nas_msg_sim.c:1219 >4 0x7ffff5e94ac2 in start_thread nptl/pthread_create.c:442 --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index aedcf71cbc..7c9f7642cc 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -1004,6 +1004,11 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * security_header_len + mm_msg_encode(mm_msg, (uint8_t *)(initialNasMsg->data + security_header_len), size - security_header_len); + // Free allocated memory after encode + free(req_buffer); + free(mm_msg->uplink_nas_transport.dnn.value); + free(mm_msg->uplink_nas_transport.snssai.value); + /* ciphering */ uint8_t buf[initialNasMsg->length - 7]; stream_cipher.context = nas->security_container->ciphering_context; From 47833b1aebe76817bd83712fc5ee95590e28c87a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 30 Aug 2024 15:04:08 +0200 Subject: [PATCH 08/61] Free NAS PDU buffer in NAS task, which has ownership --- openair3/NAS/NR_UE/nr_nas_msg_sim.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index 7c9f7642cc..c942e079cd 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -1330,6 +1330,8 @@ void *nas_nrue(void *args_p) capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length); } + // Free NAS buffer memory after use (coming from RRC) + free(pdu_buffer); break; } @@ -1454,6 +1456,8 @@ void *nas_nrue(void *args_p) LOG_W(NR_RRC, "unknown message type %d\n", msg_type); break; } + // Free NAS buffer memory after use (coming from RRC) + free(pdu_buffer); if (initialNasMsg.length > 0) send_nas_uplink_data_req(nas, &initialNasMsg); From ec40b34b1dacef04ff0767f80d79a07ff25fd1fa Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 16 Aug 2024 16:34:43 +0200 Subject: [PATCH 09/61] initial cleanup --- .../NR_TRANSPORT/nr_ulsch_llr_computation.c | 148 ++++++-------- .../nr_dlsch_llr_computation.c | 192 +----------------- .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 36 ---- 3 files changed, 64 insertions(+), 312 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c index 2529fdd38e..5ca3f3e203 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c @@ -31,9 +31,7 @@ */ #include "PHY/defs_gNB.h" -#include "PHY/defs_nr_common.h" #include "PHY/sse_intrin.h" -#include "PHY/impl_defs_top.h" #ifdef __aarch64__ #define USE_128BIT @@ -55,13 +53,10 @@ int16_t saturating_sub(int16_t a, int16_t b) //---------------------------------------------------------------------------------------------- // QPSK //---------------------------------------------------------------------------------------------- -void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol) +void nr_qpsk_llr(int32_t *rxdataF_comp, int16_t *llr, uint32_t nb_re, uint8_t symbol) { c16_t *rxF = (c16_t *)rxdataF_comp; - c16_t *llr32 = (c16_t *)ulsch_llr; + c16_t *llr32 = (c16_t *)llr; for (int i = 0; i < nb_re; i++) { llr32[i].r = rxF[i].r >> 3; llr32[i].i = rxF[i].i >> 3; @@ -72,11 +67,11 @@ void nr_ulsch_qpsk_llr(int32_t *rxdataF_comp, // 16-QAM //---------------------------------------------------------------------------------------------- -void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_re, uint8_t symbol) +void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint32_t nb_re, uint8_t symbol) { simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; - simde__m256i *ch_mag = (simde__m256i *)ul_ch_mag; - int64_t *llr_64 = (int64_t *)ulsch_llr; + simde__m256i *ch_mag = (simde__m256i *)ch_mag_in; + int64_t *llr_64 = (int64_t *)llr; #ifndef USE_128BIT simde__m256i xmm0, xmm1, xmm2; @@ -110,7 +105,7 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsc simde__m128i *rxF_128 = (simde__m128i *)rxF_256; simde__m128i *ch_mag_128 = (simde__m128i *)ch_mag; - simde__m128i *ulsch_llr_128 = (simde__m128i *)llr_64; + simde__m128i *llr_128 = (simde__m128i *)llr_64; // Each iteration does 4 RE (gives 16 16bit-llrs) for (int i = 0; i < (nb_re >> 2); i++) { @@ -119,9 +114,9 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsc // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 xmm0 = simde_mm_subs_epi16(*ch_mag_128, xmm0); - ulsch_llr_128[0] = simde_mm_unpacklo_epi32(*rxF_128, xmm0); // llr128[0] contains the llrs of the 1st,2nd,5th and 6th REs - ulsch_llr_128[1] = simde_mm_unpackhi_epi32(*rxF_128, xmm0); // llr128[1] contains the llrs of the 3rd, 4th, 7th and 8th REs - ulsch_llr_128 += 2; + llr_128[0] = simde_mm_unpacklo_epi32(*rxF_128, xmm0); // llr128[0] contains the llrs of the 1st,2nd,5th and 6th REs + llr_128[1] = simde_mm_unpackhi_epi32(*rxF_128, xmm0); // llr128[1] contains the llrs of the 3rd, 4th, 7th and 8th REs + llr_128 += 2; rxF_128++; ch_mag_128++; } @@ -130,17 +125,17 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsc nb_re &= 0x3; int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ul_ch_mag_i16 = (int16_t *)ch_mag_128; - int16_t *ulsch_llr_i16 = (int16_t *)ulsch_llr_128; + int16_t *ch_mag_i16 = (int16_t *)ch_mag_128; + int16_t *llr_i16 = (int16_t *)llr_128; for (uint i = 0U; i < nb_re; i++) { int16_t real = rxDataF_i16[2 * i]; int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ul_ch_mag_i16[2 * i]; - int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; - ulsch_llr_i16[4 * i] = real; - ulsch_llr_i16[4 * i + 1] = imag; - ulsch_llr_i16[4 * i + 2] = saturating_sub(mag_real, abs(real)); - ulsch_llr_i16[4 * i + 3] = saturating_sub(mag_imag, abs(imag)); + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; + llr_i16[4 * i] = real; + llr_i16[4 * i + 1] = imag; + llr_i16[4 * i + 2] = saturating_sub(mag_real, abs(real)); + llr_i16[4 * i + 3] = saturating_sub(mag_imag, abs(imag)); } } @@ -148,19 +143,14 @@ void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsc // 64-QAM //---------------------------------------------------------------------------------------------- -void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol) +void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int16_t *llr, uint32_t nb_re, uint8_t symbol) { simde__m256i *rxF = (simde__m256i *)rxdataF_comp; - simde__m256i *ch_maga = (simde__m256i *)ul_ch_mag; - simde__m256i *ch_magb = (simde__m256i *)ul_ch_magb; + simde__m256i *ch_maga = (simde__m256i *)ch_mag; + simde__m256i *ch_magb = (simde__m256i *)ch_mag2; - int32_t *llr_32 = (int32_t *)ulsch_llr; + int32_t *llr_32 = (int32_t *)llr; #ifndef USE_128BIT simde__m256i xmm0, xmm1, xmm2; @@ -244,40 +234,40 @@ void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, nb_re &= 0x3; int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ul_ch_mag_i16 = (int16_t *)ch_mag_128; - int16_t *ul_ch_magb_i16 = (int16_t *)ch_magb_128; + int16_t *ch_mag_i16 = (int16_t *)ch_mag_128; + int16_t *ch_magb_i16 = (int16_t *)ch_magb_128; int16_t *llr_i16 = (int16_t *)llr64; for (int i = 0; i < nb_re; i++) { int16_t real = rxDataF_i16[2 * i]; int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ul_ch_mag_i16[2 * i]; - int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; llr_i16[6 * i] = real; llr_i16[6 * i + 1] = imag; llr_i16[6 * i + 2] = saturating_sub(mag_real, abs(real)); llr_i16[6 * i + 3] = saturating_sub(mag_imag, abs(imag)); - int16_t mag_realb = ul_ch_magb_i16[2 * i]; - int16_t mag_imagb = ul_ch_magb_i16[2 * i + 1]; + int16_t mag_realb = ch_magb_i16[2 * i]; + int16_t mag_imagb = ch_magb_i16[2 * i + 1]; llr_i16[6 * i + 4] = saturating_sub(mag_realb, abs(llr_i16[6 * i + 2])); llr_i16[6 * i + 5] = saturating_sub(mag_imagb, abs(llr_i16[6 * i + 3])); } simde_mm_empty(); } -void nr_ulsch_256qam_llr(int32_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - int32_t *ul_ch_magc, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol) +void nr_256qam_llr(int32_t *rxdataF_comp, + int32_t *ch_mag, + int32_t *ch_mag2, + int32_t *ch_mag3, + int16_t *llr, + uint32_t nb_re, + uint8_t symbol) { simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; - simde__m256i *llr256 = (simde__m256i *)ulsch_llr; + simde__m256i *llr256 = (simde__m256i *)llr; - simde__m256i *ch_maga = (simde__m256i *)ul_ch_mag; - simde__m256i *ch_magb = (simde__m256i *)ul_ch_magb; - simde__m256i *ch_magc = (simde__m256i *)ul_ch_magc; + simde__m256i *ch_maga = (simde__m256i *)ch_mag; + simde__m256i *ch_magb = (simde__m256i *)ch_mag2; + simde__m256i *ch_magc = (simde__m256i *)ch_mag3; #ifndef USE_128BIT simde__m256i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; @@ -357,26 +347,26 @@ void nr_ulsch_256qam_llr(int32_t *rxdataF_comp, if (nb_re & 3) { for (int i = 0; i < (nb_re & 0x3); i++) { int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ul_ch_mag_i16 = (int16_t *)ch_maga_128; - int16_t *ul_ch_magb_i16 = (int16_t *)ch_magb_128; - int16_t *ul_ch_magc_i16 = (int16_t *)ch_magc_128; - int16_t *ulsch_llr_i16 = (int16_t *)llr_128; + int16_t *ch_mag_i16 = (int16_t *)ch_maga_128; + int16_t *ch_magb_i16 = (int16_t *)ch_magb_128; + int16_t *ch_magc_i16 = (int16_t *)ch_magc_128; + int16_t *llr_i16 = (int16_t *)llr_128; int16_t real = rxDataF_i16[2 * i + 0]; int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ul_ch_mag_i16[2 * i]; - int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; - ulsch_llr_i16[8 * i] = real; - ulsch_llr_i16[8 * i + 1] = imag; - ulsch_llr_i16[8 * i + 2] = saturating_sub(mag_real, abs(real)); - ulsch_llr_i16[8 * i + 3] = saturating_sub(mag_imag, abs(imag)); - int16_t magb_real = ul_ch_magb_i16[2 * i]; - int16_t magb_imag = ul_ch_magb_i16[2 * i + 1]; - ulsch_llr_i16[8 * i + 4] = saturating_sub(magb_real, abs(ulsch_llr_i16[8 * i + 2])); - ulsch_llr_i16[8 * i + 5] = saturating_sub(magb_imag, abs(ulsch_llr_i16[8 * i + 3])); - int16_t magc_real = ul_ch_magc_i16[2 * i]; - int16_t magc_imag = ul_ch_magc_i16[2 * i + 1]; - ulsch_llr_i16[8 * i + 6] = saturating_sub(magc_real, abs(ulsch_llr_i16[8 * i + 4])); - ulsch_llr_i16[8 * i + 7] = saturating_sub(magc_imag, abs(ulsch_llr_i16[8 * i + 5])); + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; + llr_i16[8 * i] = real; + llr_i16[8 * i + 1] = imag; + llr_i16[8 * i + 2] = saturating_sub(mag_real, abs(real)); + llr_i16[8 * i + 3] = saturating_sub(mag_imag, abs(imag)); + int16_t magb_real = ch_magb_i16[2 * i]; + int16_t magb_imag = ch_magb_i16[2 * i + 1]; + llr_i16[8 * i + 4] = saturating_sub(magb_real, abs(llr_i16[8 * i + 2])); + llr_i16[8 * i + 5] = saturating_sub(magb_imag, abs(llr_i16[8 * i + 3])); + int16_t magc_real = ch_magc_i16[2 * i]; + int16_t magc_imag = ch_magc_i16[2 * i + 1]; + llr_i16[8 * i + 6] = saturating_sub(magc_real, abs(llr_i16[8 * i + 4])); + llr_i16[8 * i + 7] = saturating_sub(magc_imag, abs(llr_i16[8 * i + 5])); } } simde_mm_empty(); @@ -393,34 +383,16 @@ void nr_ulsch_compute_llr(int32_t *rxdataF_comp, { switch(mod_order){ case 2: - nr_ulsch_qpsk_llr(rxdataF_comp, - ulsch_llr, - nb_re, - symbol); + nr_qpsk_llr(rxdataF_comp, ulsch_llr, nb_re, symbol); break; case 4: - nr_ulsch_16qam_llr(rxdataF_comp, - ul_ch_mag, - ulsch_llr, - nb_re, - symbol); + nr_16qam_llr(rxdataF_comp, ul_ch_mag, ulsch_llr, nb_re, symbol); break; case 6: - nr_ulsch_64qam_llr(rxdataF_comp, - ul_ch_mag, - ul_ch_magb, - ulsch_llr, - nb_re, - symbol); + nr_64qam_llr(rxdataF_comp, ul_ch_mag, ul_ch_magb, ulsch_llr, nb_re, symbol); break; case 8: - nr_ulsch_256qam_llr(rxdataF_comp, - ul_ch_mag, - ul_ch_magb, - ul_ch_magc, - ulsch_llr, - nb_re, - symbol); + nr_256qam_llr(rxdataF_comp, ul_ch_mag, ul_ch_magb, ul_ch_magc, ulsch_llr, nb_re, symbol); break; default: AssertFatal(1==0,"nr_ulsch_compute_llr: invalid Qm value, symbol = %d, Qm = %d\n",symbol, mod_order); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c index 82b3410bc1..3a67306905 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c @@ -36,6 +36,10 @@ #include "PHY/TOOLS/tools_defs.h" #include "PHY/sse_intrin.h" +#ifdef __aarch64__ +#define USE_128BIT +#endif + //#define DEBUG_LLR_SIC //============================================================================================== @@ -323,191 +327,3 @@ void nr_dlsch_256qam_llr(NR_DL_FRAME_PARMS *frame_parms, simde_m_empty(); } -//============================================================================================== -// DUAL-STREAM -//============================================================================================== - -//---------------------------------------------------------------------------------------------- -// QPSK -//---------------------------------------------------------------------------------------------- - -simde__m128i y0r_over2 __attribute__ ((aligned(16))); -simde__m128i y0i_over2 __attribute__ ((aligned(16))); -simde__m128i y1r_over2 __attribute__ ((aligned(16))); -simde__m128i y1i_over2 __attribute__ ((aligned(16))); - -simde__m128i A __attribute__ ((aligned(16))); -simde__m128i B __attribute__ ((aligned(16))); -simde__m128i C __attribute__ ((aligned(16))); -simde__m128i D __attribute__ ((aligned(16))); -simde__m128i E __attribute__ ((aligned(16))); -simde__m128i F __attribute__ ((aligned(16))); -simde__m128i G __attribute__ ((aligned(16))); -simde__m128i H __attribute__ ((aligned(16))); - - - -void nr_qpsk_qpsk(short *stream0_in, - short *stream1_in, - short *stream0_out, - short *rho01, - int length - ) -{ - - /* - This function computes the LLRs of stream 0 (s_0) in presence of the interfering stream 1 (s_1) assuming that both symbols are QPSK. It can be used for both MU-MIMO interference-aware receiver or for SU-MIMO receivers. - - Parameters: - stream0_in = Matched filter output y0' = (h0*g0)*y0 - stream1_in = Matched filter output y1' = (h0*g1)*y0 - stream0_out = LLRs - rho01 = Correlation between the two effective channels \rho_{10} = (h1*g1)*(h0*g0) - length = number of resource elements - */ - - simde__m128i *rho01_128i = (simde__m128i *)rho01; - simde__m128i *stream0_128i_in = (simde__m128i *)stream0_in; - simde__m128i *stream1_128i_in = (simde__m128i *)stream1_in; - simde__m128i *stream0_128i_out = (simde__m128i *)stream0_out; - simde__m128i ONE_OVER_SQRT_8 =simde_mm_set1_epi16(23170); //round(2^16/sqrt(8)) - - int i; - - - for (i=0; i>2; i+=2) { - // in each iteration, we take 8 complex samples - simde__m128i xmm0 = rho01_128i[i]; // 4 symbols - simde__m128i xmm1 = rho01_128i[i+1]; - - // put (rho_r + rho_i)/2sqrt2 in rho_rpi - // put (rho_r - rho_i)/2sqrt2 in rho_rmi - - xmm0 =simde_mm_shufflelo_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm0 =simde_mm_shufflehi_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm0 =simde_mm_shuffle_epi32(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shufflelo_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shufflehi_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shuffle_epi32(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - //xmm0 = [Re(0,1) Re(2,3) Im(0,1) Im(2,3)] - //xmm1 = [Re(4,5) Re(6,7) Im(4,5) Im(6,7)] - simde__m128i xmm2 = simde_mm_unpacklo_epi64(xmm0, xmm1); // Re(rho) - simde__m128i xmm3 = simde_mm_unpackhi_epi64(xmm0, xmm1); // Im(rho) - simde__m128i rho_rpi = simde_mm_adds_epi16(xmm2, xmm3); // rho = Re(rho) + Im(rho) - simde__m128i rho_rmi = simde_mm_subs_epi16(xmm2, xmm3); // rho* = Re(rho) - Im(rho) - - // divide by sqrt(8), no shift needed ONE_OVER_SQRT_8 = Q1.16 - rho_rpi =simde_mm_mulhi_epi16(rho_rpi,ONE_OVER_SQRT_8); - rho_rmi =simde_mm_mulhi_epi16(rho_rmi,ONE_OVER_SQRT_8); - // Compute LLR for first bit of stream 0 - - // Compute real and imaginary parts of MF output for stream 0 - xmm0 = stream0_128i_in[i]; - xmm1 = stream0_128i_in[i+1]; - - xmm0 =simde_mm_shufflelo_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm0 =simde_mm_shufflehi_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm0 =simde_mm_shuffle_epi32(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shufflelo_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shufflehi_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shuffle_epi32(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - //xmm0 = [Re(0,1) Re(2,3) Im(0,1) Im(2,3)] - //xmm1 = [Re(4,5) Re(6,7) Im(4,5) Im(6,7)] - simde__m128i y0r = simde_mm_unpacklo_epi64(xmm0, xmm1); // = [y0r(1),y0r(2),y0r(3),y0r(4)] - simde__m128i y0i = simde_mm_unpackhi_epi64(xmm0, xmm1); - - simde__m128i y0r_over2 = simde_mm_srai_epi16(y0r, 1); // divide by 2 - simde__m128i y0i_over2 = simde_mm_srai_epi16(y0i, 1); // divide by 2 - // Compute real and imaginary parts of MF output for stream 1 - xmm0 = stream1_128i_in[i]; - xmm1 = stream1_128i_in[i+1]; - - xmm0 =simde_mm_shufflelo_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm0 =simde_mm_shufflehi_epi16(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm0 =simde_mm_shuffle_epi32(xmm0,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shufflelo_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shufflehi_epi16(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - xmm1 =simde_mm_shuffle_epi32(xmm1,0xd8); // SIMDE_MM_SHUFFLE(0,2,1,3)); - //xmm0 = [Re(0,1) Re(2,3) Im(0,1) Im(2,3)] - //xmm1 = [Re(4,5) Re(6,7) Im(4,5) Im(6,7)] - simde__m128i y1r = simde_mm_unpacklo_epi64(xmm0, xmm1); //[y1r(1),y1r(2),y1r(3),y1r(4)] - simde__m128i y1i = simde_mm_unpackhi_epi64(xmm0, xmm1); //[y1i(1),y1i(2),y1i(3),y1i(4)] - - simde__m128i y1r_over2 = simde_mm_srai_epi16(y1r, 1); // divide by 2 - simde__m128i y1i_over2 = simde_mm_srai_epi16(y1i, 1); // divide by 2 - - // Compute the terms for the LLR of first bit - - xmm0 =simde_mm_setzero_si128(); // ZERO - - // 1 term for numerator of LLR - xmm3 =simde_mm_subs_epi16(y1r_over2,rho_rpi); - A =simde_mm_abs_epi16(xmm3); // A = |y1r/2 - rho/sqrt(8)| - xmm2 =simde_mm_adds_epi16(A,y0i_over2); // = |y1r/2 - rho/sqrt(8)| + y0i/2 - xmm3 =simde_mm_subs_epi16(y1i_over2,rho_rmi); - B =simde_mm_abs_epi16(xmm3); // B = |y1i/2 - rho*/sqrt(8)| - simde__m128i logmax_num_re0 =simde_mm_adds_epi16(B,xmm2); // = |y1r/2 - rho/sqrt(8)|+|y1i/2 - rho*/sqrt(8)| + y0i/2 - - // 2 term for numerator of LLR - xmm3 =simde_mm_subs_epi16(y1r_over2,rho_rmi); - C =simde_mm_abs_epi16(xmm3); // C = |y1r/2 - rho*/4| - xmm2 =simde_mm_subs_epi16(C,y0i_over2); // = |y1r/2 - rho*/4| - y0i/2 - xmm3 =simde_mm_adds_epi16(y1i_over2,rho_rpi); - D =simde_mm_abs_epi16(xmm3); // D = |y1i/2 + rho/4| - xmm2 =simde_mm_adds_epi16(xmm2,D); // |y1r/2 - rho*/4| + |y1i/2 + rho/4| - y0i/2 - logmax_num_re0 =simde_mm_max_epi16(logmax_num_re0,xmm2); // max, numerator done - - // 1 term for denominator of LLR - xmm3 =simde_mm_adds_epi16(y1r_over2,rho_rmi); - E =simde_mm_abs_epi16(xmm3); // E = |y1r/2 + rho*/4| - xmm2 =simde_mm_adds_epi16(E,y0i_over2); // = |y1r/2 + rho*/4| + y0i/2 - xmm3 =simde_mm_subs_epi16(y1i_over2,rho_rpi); - F =simde_mm_abs_epi16(xmm3); // F = |y1i/2 - rho/4| - simde__m128i logmax_den_re0 =simde_mm_adds_epi16(F,xmm2); // = |y1r/2 + rho*/4| + |y1i/2 - rho/4| + y0i/2 - - // 2 term for denominator of LLR - xmm3 =simde_mm_adds_epi16(y1r_over2,rho_rpi); - G =simde_mm_abs_epi16(xmm3); // G = |y1r/2 + rho/4| - xmm2 =simde_mm_subs_epi16(G,y0i_over2); // = |y1r/2 + rho/4| - y0i/2 - xmm3 =simde_mm_adds_epi16(y1i_over2,rho_rmi); - H =simde_mm_abs_epi16(xmm3); // H = |y1i/2 + rho*/4| - xmm2 =simde_mm_adds_epi16(xmm2,H); // = |y1r/2 + rho/4| + |y1i/2 + rho*/4| - y0i/2 - logmax_den_re0 =simde_mm_max_epi16(logmax_den_re0,xmm2); // max, denominator done - - // Compute the terms for the LLR of first bit - - // 1 term for nominator of LLR - xmm2 = simde_mm_adds_epi16(A,y0r_over2); - simde__m128i logmax_num_im0 = simde_mm_adds_epi16(B, xmm2); // = |y1r/2 - rho/4| + |y1i/2 - rho*/4| + y0r/2 - - // 2 term for nominator of LLR - xmm2 =simde_mm_subs_epi16(E,y0r_over2); - xmm2 =simde_mm_adds_epi16(xmm2,F); // = |y1r/2 + rho*/4| + |y1i/2 - rho/4| - y0r/2 - - logmax_num_im0 =simde_mm_max_epi16(logmax_num_im0,xmm2); // max, nominator done - - // 1 term for denominator of LLR - xmm2 =simde_mm_adds_epi16(C,y0r_over2); - simde__m128i logmax_den_im0 =simde_mm_adds_epi16(D,xmm2); // = |y1r/2 - rho*/4| + |y1i/2 + rho/4| - y0r/2 - - xmm2 =simde_mm_subs_epi16(G,y0r_over2); - xmm2 =simde_mm_adds_epi16(xmm2,H); // = |y1r/2 + rho/4| + |y1i/2 + rho*/4| - y0r/2 - - logmax_den_im0 =simde_mm_max_epi16(logmax_den_im0,xmm2); // max, denominator done - - // LLR of first bit [L1(1), L1(2), L1(3), L1(4)] - y0r =simde_mm_adds_epi16(y0r,logmax_num_re0); - y0r =simde_mm_subs_epi16(y0r,logmax_den_re0); - - // LLR of second bit [L2(1), L2(2), L2(3), L2(4)] - y0i =simde_mm_adds_epi16(y0i,logmax_num_im0); - y0i =simde_mm_subs_epi16(y0i,logmax_den_im0); - - simde_mm_storeu_si128(&stream0_128i_out[i],simde_mm_unpacklo_epi16(y0r,y0i)); // = [L1(1), L2(1), L1(2), L2(2)] - - if (i<((length>>1) - 1)) // false if only 2 REs remain - simde_mm_storeu_si128(&stream0_128i_out[i+1],simde_mm_unpackhi_epi16(y0r,y0i)); - - } - -} diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h index 9b7fbb1023..44151bfbaf 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h @@ -52,42 +52,6 @@ */ void nr_ue_dlsch_init(NR_UE_DLSCH_t *dlsch_list, int num_dlsch, uint8_t max_ldpc_iterations); -/** \brief This function computes the LLRs for ML (max-logsum approximation) dual-stream QPSK/QPSK reception. - @param stream0_in Input from channel compensated (MR combined) stream 0 - @param stream1_in Input from channel compensated (MR combined) stream 1 - @param stream0_out Output from LLR unit for stream0 - @param rho01 Cross-correlation between channels (MR combined) - @param length in complex channel outputs*/ -void nr_qpsk_qpsk(int16_t *stream0_in, - int16_t *stream1_in, - int16_t *stream0_out, - int16_t *rho01, - int32_t length); - -/** \brief This function perform LLR computation for dual-stream (QPSK/QPSK) transmission. - @param frame_parms Frame descriptor structure - @param rxdataF_comp Compensated channel output - @param rxdataF_comp_i Compensated channel output for interference - @param rho_i Correlation between channel of signal and inteference - @param dlsch_llr llr output - @param symbol OFDM symbol index in sub-frame - @param len - @param first_symbol_flag flag to indicate this is the first symbol of the dlsch - @param nb_rb number of RBs for this allocation - @param pbch_pss_sss_adj Number of channel bits taken by PBCH/PSS/SSS - @param llr128p pointer to pointer to symbol in dlsch_llr*/ -int32_t nr_dlsch_qpsk_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, - int32_t **rxdataF_comp, - int32_t **rxdataF_comp_i, - int32_t **rho_i, - int16_t *dlsch_llr, - uint8_t symbol, - uint32_t len, - uint8_t first_symbol_flag, - uint16_t nb_rb, - uint16_t pbch_pss_sss_adj, - int16_t **llr128p); - /** \brief This function generates log-likelihood ratios (decoder input) for single-stream QPSK received waveforms @param frame_parms Frame descriptor structure @param rxdataF_comp Compensated channel output From aeb562756afa3f95b1648b55edbeb72e835e8fad Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 16 Aug 2024 16:51:00 +0200 Subject: [PATCH 10/61] moving LLR functions to phy_common --- .../NR_TRANSPORT/nr_ulsch_llr_computation.c | 336 +---------------- .../PHY/nr_phy_common/inc/nr_phy_common.h | 10 + .../PHY/nr_phy_common/src/nr_phy_common.c | 339 ++++++++++++++++++ 3 files changed, 350 insertions(+), 335 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c index 5ca3f3e203..450408e794 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c @@ -32,346 +32,12 @@ #include "PHY/defs_gNB.h" #include "PHY/sse_intrin.h" +#include "nr_phy_common.h" #ifdef __aarch64__ #define USE_128BIT #endif -int16_t saturating_sub(int16_t a, int16_t b) -{ - int32_t result = (int32_t)a - (int32_t)b; - - if (result < INT16_MIN) { - return INT16_MIN; - } else if (result > INT16_MAX) { - return INT16_MAX; - } else { - return (int16_t)result; - } -} - -//---------------------------------------------------------------------------------------------- -// QPSK -//---------------------------------------------------------------------------------------------- -void nr_qpsk_llr(int32_t *rxdataF_comp, int16_t *llr, uint32_t nb_re, uint8_t symbol) -{ - c16_t *rxF = (c16_t *)rxdataF_comp; - c16_t *llr32 = (c16_t *)llr; - for (int i = 0; i < nb_re; i++) { - llr32[i].r = rxF[i].r >> 3; - llr32[i].i = rxF[i].i >> 3; - } -} - -//---------------------------------------------------------------------------------------------- -// 16-QAM -//---------------------------------------------------------------------------------------------- - -void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint32_t nb_re, uint8_t symbol) -{ - simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; - simde__m256i *ch_mag = (simde__m256i *)ch_mag_in; - int64_t *llr_64 = (int64_t *)llr; - -#ifndef USE_128BIT - simde__m256i xmm0, xmm1, xmm2; - - for (int i = 0; i < (nb_re >> 3); i++) { - // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm256_abs_epi16(*rxF_256); - // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - xmm0 = simde_mm256_subs_epi16(*ch_mag, xmm0); - - xmm1 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); - xmm2 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); - - // xmm1 |1st 2ed 3rd 4th 9th 10th 13rd 14th| - // xmm2 |5th 6th 7th 8th 11st 12ed 15th 16th| - - *llr_64++ = simde_mm256_extract_epi64(xmm1, 0); - *llr_64++ = simde_mm256_extract_epi64(xmm1, 1); - *llr_64++ = simde_mm256_extract_epi64(xmm2, 0); - *llr_64++ = simde_mm256_extract_epi64(xmm2, 1); - *llr_64++ = simde_mm256_extract_epi64(xmm1, 2); - *llr_64++ = simde_mm256_extract_epi64(xmm1, 3); - *llr_64++ = simde_mm256_extract_epi64(xmm2, 2); - *llr_64++ = simde_mm256_extract_epi64(xmm2, 3); - rxF_256++; - ch_mag++; - } - - nb_re &= 0x7; -#endif - - simde__m128i *rxF_128 = (simde__m128i *)rxF_256; - simde__m128i *ch_mag_128 = (simde__m128i *)ch_mag; - simde__m128i *llr_128 = (simde__m128i *)llr_64; - - // Each iteration does 4 RE (gives 16 16bit-llrs) - for (int i = 0; i < (nb_re >> 2); i++) { - // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - simde__m128i xmm0 = simde_mm_abs_epi16(*rxF_128); - // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - xmm0 = simde_mm_subs_epi16(*ch_mag_128, xmm0); - - llr_128[0] = simde_mm_unpacklo_epi32(*rxF_128, xmm0); // llr128[0] contains the llrs of the 1st,2nd,5th and 6th REs - llr_128[1] = simde_mm_unpackhi_epi32(*rxF_128, xmm0); // llr128[1] contains the llrs of the 3rd, 4th, 7th and 8th REs - llr_128 += 2; - rxF_128++; - ch_mag_128++; - } - - simde_mm_empty(); - - nb_re &= 0x3; - int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ch_mag_i16 = (int16_t *)ch_mag_128; - int16_t *llr_i16 = (int16_t *)llr_128; - for (uint i = 0U; i < nb_re; i++) { - int16_t real = rxDataF_i16[2 * i]; - int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ch_mag_i16[2 * i]; - int16_t mag_imag = ch_mag_i16[2 * i + 1]; - llr_i16[4 * i] = real; - llr_i16[4 * i + 1] = imag; - llr_i16[4 * i + 2] = saturating_sub(mag_real, abs(real)); - llr_i16[4 * i + 3] = saturating_sub(mag_imag, abs(imag)); - } -} - -//---------------------------------------------------------------------------------------------- -// 64-QAM -//---------------------------------------------------------------------------------------------- - -void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int16_t *llr, uint32_t nb_re, uint8_t symbol) -{ - simde__m256i *rxF = (simde__m256i *)rxdataF_comp; - - simde__m256i *ch_maga = (simde__m256i *)ch_mag; - simde__m256i *ch_magb = (simde__m256i *)ch_mag2; - - int32_t *llr_32 = (int32_t *)llr; - -#ifndef USE_128BIT - simde__m256i xmm0, xmm1, xmm2; - for (int i = 0; i < (nb_re >> 3); i++) { - xmm0 = *rxF; - // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm1 = simde_mm256_abs_epi16(xmm0); - // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - xmm1 = simde_mm256_subs_epi16(*ch_maga, xmm1); - xmm2 = simde_mm256_abs_epi16(xmm1); - xmm2 = simde_mm256_subs_epi16(*ch_magb, xmm2); - // xmm0 |1st 4th 7th 10th 13th 16th 19th 22ed| - // xmm1 |2ed 5th 8th 11th 14th 17th 20th 23rd| - // xmm2 |3rd 6th 9th 12th 15th 18th 21st 24th| - - *llr_32++ = simde_mm256_extract_epi32(xmm0, 0); - *llr_32++ = simde_mm256_extract_epi32(xmm1, 0); - *llr_32++ = simde_mm256_extract_epi32(xmm2, 0); - - *llr_32++ = simde_mm256_extract_epi32(xmm0, 1); - *llr_32++ = simde_mm256_extract_epi32(xmm1, 1); - *llr_32++ = simde_mm256_extract_epi32(xmm2, 1); - - *llr_32++ = simde_mm256_extract_epi32(xmm0, 2); - *llr_32++ = simde_mm256_extract_epi32(xmm1, 2); - *llr_32++ = simde_mm256_extract_epi32(xmm2, 2); - - *llr_32++ = simde_mm256_extract_epi32(xmm0, 3); - *llr_32++ = simde_mm256_extract_epi32(xmm1, 3); - *llr_32++ = simde_mm256_extract_epi32(xmm2, 3); - - *llr_32++ = simde_mm256_extract_epi32(xmm0, 4); - *llr_32++ = simde_mm256_extract_epi32(xmm1, 4); - *llr_32++ = simde_mm256_extract_epi32(xmm2, 4); - - *llr_32++ = simde_mm256_extract_epi32(xmm0, 5); - *llr_32++ = simde_mm256_extract_epi32(xmm1, 5); - *llr_32++ = simde_mm256_extract_epi32(xmm2, 5); - - *llr_32++ = simde_mm256_extract_epi32(xmm0, 6); - *llr_32++ = simde_mm256_extract_epi32(xmm1, 6); - *llr_32++ = simde_mm256_extract_epi32(xmm2, 6); - - *llr_32++ = simde_mm256_extract_epi32(xmm0, 7); - *llr_32++ = simde_mm256_extract_epi32(xmm1, 7); - *llr_32++ = simde_mm256_extract_epi32(xmm2, 7); - rxF++; - ch_maga++; - ch_magb++; - } - - nb_re &= 0x7; -#endif - - simde__m128i *rxF_128 = (simde__m128i *)rxF; - simde__m128i *ch_mag_128 = (simde__m128i *)ch_maga; - simde__m128i *ch_magb_128 = (simde__m128i *)ch_magb; - - simde__m64 *llr64 = (simde__m64 *)llr_32; - - // Each iteration does 4 RE (gives 24 16bit-llrs) - for (int i = 0; i < (nb_re >> 2); i++) { - simde__m128i xmm0, xmm1, xmm2; - xmm0 = *rxF_128; - xmm1 = simde_mm_abs_epi16(xmm0); - xmm1 = simde_mm_subs_epi16(*ch_mag_128, xmm1); - xmm2 = simde_mm_abs_epi16(xmm1); - xmm2 = simde_mm_subs_epi16(*ch_magb_128, xmm2); - - *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm1, 0), simde_mm_extract_epi32(xmm0, 0)); - *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm0, 1), simde_mm_extract_epi32(xmm2, 0)); - *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm2, 1), simde_mm_extract_epi32(xmm1, 1)); - *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm1, 2), simde_mm_extract_epi32(xmm0, 2)); - *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm0, 3), simde_mm_extract_epi32(xmm2, 2)); - *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm2, 3), simde_mm_extract_epi32(xmm1, 3)); - rxF_128++; - ch_mag_128++; - ch_magb_128++; - } - - nb_re &= 0x3; - - int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ch_mag_i16 = (int16_t *)ch_mag_128; - int16_t *ch_magb_i16 = (int16_t *)ch_magb_128; - int16_t *llr_i16 = (int16_t *)llr64; - for (int i = 0; i < nb_re; i++) { - int16_t real = rxDataF_i16[2 * i]; - int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ch_mag_i16[2 * i]; - int16_t mag_imag = ch_mag_i16[2 * i + 1]; - llr_i16[6 * i] = real; - llr_i16[6 * i + 1] = imag; - llr_i16[6 * i + 2] = saturating_sub(mag_real, abs(real)); - llr_i16[6 * i + 3] = saturating_sub(mag_imag, abs(imag)); - int16_t mag_realb = ch_magb_i16[2 * i]; - int16_t mag_imagb = ch_magb_i16[2 * i + 1]; - llr_i16[6 * i + 4] = saturating_sub(mag_realb, abs(llr_i16[6 * i + 2])); - llr_i16[6 * i + 5] = saturating_sub(mag_imagb, abs(llr_i16[6 * i + 3])); - } - simde_mm_empty(); -} - -void nr_256qam_llr(int32_t *rxdataF_comp, - int32_t *ch_mag, - int32_t *ch_mag2, - int32_t *ch_mag3, - int16_t *llr, - uint32_t nb_re, - uint8_t symbol) -{ - simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; - simde__m256i *llr256 = (simde__m256i *)llr; - - simde__m256i *ch_maga = (simde__m256i *)ch_mag; - simde__m256i *ch_magb = (simde__m256i *)ch_mag2; - simde__m256i *ch_magc = (simde__m256i *)ch_mag3; -#ifndef USE_128BIT - simde__m256i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; - - for (int i = 0; i < (nb_re >> 3); i++) { - // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm256_abs_epi16(*rxF_256); - // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - xmm0 = simde_mm256_subs_epi16(*ch_maga, xmm0); - // xmmtmpD2 contains 16 LLRs - xmm1 = simde_mm256_abs_epi16(xmm0); - xmm1 = simde_mm256_subs_epi16(*ch_magb, xmm1); // contains 16 LLRs - xmm2 = simde_mm256_abs_epi16(xmm1); - xmm2 = simde_mm256_subs_epi16(*ch_magc, xmm2); // contains 16 LLRs - // rxF[i] A0 A1 A2 A3 A4 A5 A6 A7 bits 7,6 - // xmm0 B0 B1 B2 B3 B4 B5 B6 B7 bits 5,4 - // xmm1 C0 C1 C2 C3 C4 C5 C6 C7 bits 3,2 - // xmm2 D0 D1 D2 D3 D4 D5 D6 D7 bits 1,0 - xmm3 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); // A0 B0 A1 B1 A4 B4 A5 B5 - xmm4 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); // A2 B2 A3 B3 A6 B6 A7 B7 - xmm5 = simde_mm256_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 C4 D4 C5 D5 - xmm6 = simde_mm256_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 C6 D6 C7 D7 - - xmm0 = simde_mm256_unpacklo_epi64(xmm3, xmm5); // A0 B0 C0 D0 A4 B4 C4 D4 - xmm1 = simde_mm256_unpackhi_epi64(xmm3, xmm5); // A1 B1 C1 D1 A5 B5 C5 D5 - xmm2 = simde_mm256_unpacklo_epi64(xmm4, xmm6); // A2 B2 C2 D2 A6 B6 C6 D6 - xmm3 = simde_mm256_unpackhi_epi64(xmm4, xmm6); // A3 B3 C3 D3 A7 B7 C7 D7 - *llr256++ = simde_mm256_permute2x128_si256(xmm0, xmm1, 0x20); // A0 B0 C0 D0 A1 B1 C1 D1 - *llr256++ = simde_mm256_permute2x128_si256(xmm2, xmm3, 0x20); // A2 B2 C2 D2 A3 B3 C3 D3 - *llr256++ = simde_mm256_permute2x128_si256(xmm0, xmm1, 0x31); // A4 B4 C4 D4 A5 B5 C5 D5 - *llr256++ = simde_mm256_permute2x128_si256(xmm2, xmm3, 0x31); // A6 B6 C6 D6 A7 B7 C7 D7 - ch_magc++; - ch_magb++; - ch_maga++; - rxF_256++; - } - - nb_re &= 0x7; -#endif - - simde__m128i *rxF_128 = (simde__m128i *)rxF_256; - simde__m128i *llr_128 = (simde__m128i *)llr256; - - simde__m128i *ch_maga_128 = (simde__m128i *)ch_maga; - simde__m128i *ch_magb_128 = (simde__m128i *)ch_magb; - simde__m128i *ch_magc_128 = (simde__m128i *)ch_magc; - - for (int i = 0; i < (nb_re >> 2); i++) { - simde__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; - // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| - xmm0 = simde_mm_abs_epi16(*rxF_128); - // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 - xmm0 = simde_mm_subs_epi16(*ch_maga_128, xmm0); - xmm1 = simde_mm_abs_epi16(xmm0); - xmm1 = simde_mm_subs_epi16(*ch_magb_128, xmm1); // contains 8 LLRs - xmm2 = simde_mm_abs_epi16(xmm1); - xmm2 = simde_mm_subs_epi16(*ch_magc_128, xmm2); // contains 8 LLRs - // rxF[i] A0 A1 A2 A3 - // xmm0 B0 B1 B2 B3 - // xmm1 C0 C1 C2 C3 - // xmm2 D0 D1 D2 D3 - xmm3 = simde_mm_unpacklo_epi32(*rxF_128, xmm0); // A0 B0 A1 B1 - xmm4 = simde_mm_unpackhi_epi32(*rxF_128, xmm0); // A2 B2 A3 B3 - xmm5 = simde_mm_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 - xmm6 = simde_mm_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 - - *llr_128++ = simde_mm_unpacklo_epi64(xmm3, xmm5); // A0 B0 C0 D0 - *llr_128++ = simde_mm_unpackhi_epi64(xmm3, xmm5); // A1 B1 C1 D1 - *llr_128++ = simde_mm_unpacklo_epi64(xmm4, xmm6); // A2 B2 C2 D2 - *llr_128++ = simde_mm_unpackhi_epi64(xmm4, xmm6); // A3 B3 C3 D3 - - rxF_128++; - ch_maga_128++; - ch_magb_128++; - ch_magc_128++; - } - - if (nb_re & 3) { - for (int i = 0; i < (nb_re & 0x3); i++) { - int16_t *rxDataF_i16 = (int16_t *)rxF_128; - int16_t *ch_mag_i16 = (int16_t *)ch_maga_128; - int16_t *ch_magb_i16 = (int16_t *)ch_magb_128; - int16_t *ch_magc_i16 = (int16_t *)ch_magc_128; - int16_t *llr_i16 = (int16_t *)llr_128; - int16_t real = rxDataF_i16[2 * i + 0]; - int16_t imag = rxDataF_i16[2 * i + 1]; - int16_t mag_real = ch_mag_i16[2 * i]; - int16_t mag_imag = ch_mag_i16[2 * i + 1]; - llr_i16[8 * i] = real; - llr_i16[8 * i + 1] = imag; - llr_i16[8 * i + 2] = saturating_sub(mag_real, abs(real)); - llr_i16[8 * i + 3] = saturating_sub(mag_imag, abs(imag)); - int16_t magb_real = ch_magb_i16[2 * i]; - int16_t magb_imag = ch_magb_i16[2 * i + 1]; - llr_i16[8 * i + 4] = saturating_sub(magb_real, abs(llr_i16[8 * i + 2])); - llr_i16[8 * i + 5] = saturating_sub(magb_imag, abs(llr_i16[8 * i + 3])); - int16_t magc_real = ch_magc_i16[2 * i]; - int16_t magc_imag = ch_magc_i16[2 * i + 1]; - llr_i16[8 * i + 6] = saturating_sub(magc_real, abs(llr_i16[8 * i + 4])); - llr_i16[8 * i + 7] = saturating_sub(magc_imag, abs(llr_i16[8 * i + 5])); - } - } - simde_mm_empty(); -} - void nr_ulsch_compute_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int32_t *ul_ch_magb, diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h index 8e8f7399f0..216c186894 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -24,6 +24,16 @@ #include "PHY/impl_defs_top.h" #include "PHY/TOOLS/tools_defs.h" +void nr_qpsk_llr(int32_t *rxdataF_comp, int16_t *llr, uint32_t nb_re, uint8_t symbol); +void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint32_t nb_re, uint8_t symbol); +void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int16_t *llr, uint32_t nb_re, uint8_t symbol); +void nr_256qam_llr(int32_t *rxdataF_comp, + int32_t *ch_mag, + int32_t *ch_mag2, + int32_t *ch_mag3, + int16_t *llr, + uint32_t nb_re, + uint8_t symbol); void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal); void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay); unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb); diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common.c b/openair1/PHY/nr_phy_common/src/nr_phy_common.c index b67a94d8f6..42315a1436 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c @@ -21,6 +21,345 @@ #include "nr_phy_common.h" +#ifdef __aarch64__ +#define USE_128BIT +#endif + +int16_t saturating_sub(int16_t a, int16_t b) +{ + int32_t result = (int32_t)a - (int32_t)b; + + if (result < INT16_MIN) { + return INT16_MIN; + } else if (result > INT16_MAX) { + return INT16_MAX; + } else { + return (int16_t)result; + } +} + +//---------------------------------------------------------------------------------------------- +// QPSK +//---------------------------------------------------------------------------------------------- +void nr_qpsk_llr(int32_t *rxdataF_comp, int16_t *llr, uint32_t nb_re, uint8_t symbol) +{ + c16_t *rxF = (c16_t *)rxdataF_comp; + c16_t *llr32 = (c16_t *)llr; + for (int i = 0; i < nb_re; i++) { + llr32[i].r = rxF[i].r >> 3; + llr32[i].i = rxF[i].i >> 3; + } +} + +//---------------------------------------------------------------------------------------------- +// 16-QAM +//---------------------------------------------------------------------------------------------- + +void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint32_t nb_re, uint8_t symbol) +{ + simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; + simde__m256i *ch_mag = (simde__m256i *)ch_mag_in; + int64_t *llr_64 = (int64_t *)llr; + +#ifndef USE_128BIT + simde__m256i xmm0, xmm1, xmm2; + + for (int i = 0; i < (nb_re >> 3); i++) { + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + xmm0 = simde_mm256_abs_epi16(*rxF_256); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm0 = simde_mm256_subs_epi16(*ch_mag, xmm0); + + xmm1 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); + xmm2 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); + + // xmm1 |1st 2ed 3rd 4th 9th 10th 13rd 14th| + // xmm2 |5th 6th 7th 8th 11st 12ed 15th 16th| + + *llr_64++ = simde_mm256_extract_epi64(xmm1, 0); + *llr_64++ = simde_mm256_extract_epi64(xmm1, 1); + *llr_64++ = simde_mm256_extract_epi64(xmm2, 0); + *llr_64++ = simde_mm256_extract_epi64(xmm2, 1); + *llr_64++ = simde_mm256_extract_epi64(xmm1, 2); + *llr_64++ = simde_mm256_extract_epi64(xmm1, 3); + *llr_64++ = simde_mm256_extract_epi64(xmm2, 2); + *llr_64++ = simde_mm256_extract_epi64(xmm2, 3); + rxF_256++; + ch_mag++; + } + + nb_re &= 0x7; +#endif + + simde__m128i *rxF_128 = (simde__m128i *)rxF_256; + simde__m128i *ch_mag_128 = (simde__m128i *)ch_mag; + simde__m128i *llr_128 = (simde__m128i *)llr_64; + + // Each iteration does 4 RE (gives 16 16bit-llrs) + for (int i = 0; i < (nb_re >> 2); i++) { + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + simde__m128i xmm0 = simde_mm_abs_epi16(*rxF_128); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm0 = simde_mm_subs_epi16(*ch_mag_128, xmm0); + + llr_128[0] = simde_mm_unpacklo_epi32(*rxF_128, xmm0); // llr128[0] contains the llrs of the 1st,2nd,5th and 6th REs + llr_128[1] = simde_mm_unpackhi_epi32(*rxF_128, xmm0); // llr128[1] contains the llrs of the 3rd, 4th, 7th and 8th REs + llr_128 += 2; + rxF_128++; + ch_mag_128++; + } + + simde_mm_empty(); + + nb_re &= 0x3; + int16_t *rxDataF_i16 = (int16_t *)rxF_128; + int16_t *ch_mag_i16 = (int16_t *)ch_mag_128; + int16_t *llr_i16 = (int16_t *)llr_128; + for (uint i = 0U; i < nb_re; i++) { + int16_t real = rxDataF_i16[2 * i]; + int16_t imag = rxDataF_i16[2 * i + 1]; + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; + llr_i16[4 * i] = real; + llr_i16[4 * i + 1] = imag; + llr_i16[4 * i + 2] = saturating_sub(mag_real, abs(real)); + llr_i16[4 * i + 3] = saturating_sub(mag_imag, abs(imag)); + } +} + +//---------------------------------------------------------------------------------------------- +// 64-QAM +//---------------------------------------------------------------------------------------------- + +void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int16_t *llr, uint32_t nb_re, uint8_t symbol) +{ + simde__m256i *rxF = (simde__m256i *)rxdataF_comp; + + simde__m256i *ch_maga = (simde__m256i *)ch_mag; + simde__m256i *ch_magb = (simde__m256i *)ch_mag2; + + int32_t *llr_32 = (int32_t *)llr; + +#ifndef USE_128BIT + simde__m256i xmm0, xmm1, xmm2; + for (int i = 0; i < (nb_re >> 3); i++) { + xmm0 = *rxF; + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + xmm1 = simde_mm256_abs_epi16(xmm0); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm1 = simde_mm256_subs_epi16(*ch_maga, xmm1); + xmm2 = simde_mm256_abs_epi16(xmm1); + xmm2 = simde_mm256_subs_epi16(*ch_magb, xmm2); + // xmm0 |1st 4th 7th 10th 13th 16th 19th 22ed| + // xmm1 |2ed 5th 8th 11th 14th 17th 20th 23rd| + // xmm2 |3rd 6th 9th 12th 15th 18th 21st 24th| + + *llr_32++ = simde_mm256_extract_epi32(xmm0, 0); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 0); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 0); + + *llr_32++ = simde_mm256_extract_epi32(xmm0, 1); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 1); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 1); + + *llr_32++ = simde_mm256_extract_epi32(xmm0, 2); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 2); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 2); + + *llr_32++ = simde_mm256_extract_epi32(xmm0, 3); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 3); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 3); + + *llr_32++ = simde_mm256_extract_epi32(xmm0, 4); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 4); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 4); + + *llr_32++ = simde_mm256_extract_epi32(xmm0, 5); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 5); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 5); + + *llr_32++ = simde_mm256_extract_epi32(xmm0, 6); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 6); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 6); + + *llr_32++ = simde_mm256_extract_epi32(xmm0, 7); + *llr_32++ = simde_mm256_extract_epi32(xmm1, 7); + *llr_32++ = simde_mm256_extract_epi32(xmm2, 7); + rxF++; + ch_maga++; + ch_magb++; + } + + nb_re &= 0x7; +#endif + + simde__m128i *rxF_128 = (simde__m128i *)rxF; + simde__m128i *ch_mag_128 = (simde__m128i *)ch_maga; + simde__m128i *ch_magb_128 = (simde__m128i *)ch_magb; + + simde__m64 *llr64 = (simde__m64 *)llr_32; + + // Each iteration does 4 RE (gives 24 16bit-llrs) + for (int i = 0; i < (nb_re >> 2); i++) { + simde__m128i xmm0, xmm1, xmm2; + xmm0 = *rxF_128; + xmm1 = simde_mm_abs_epi16(xmm0); + xmm1 = simde_mm_subs_epi16(*ch_mag_128, xmm1); + xmm2 = simde_mm_abs_epi16(xmm1); + xmm2 = simde_mm_subs_epi16(*ch_magb_128, xmm2); + + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm1, 0), simde_mm_extract_epi32(xmm0, 0)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm0, 1), simde_mm_extract_epi32(xmm2, 0)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm2, 1), simde_mm_extract_epi32(xmm1, 1)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm1, 2), simde_mm_extract_epi32(xmm0, 2)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm0, 3), simde_mm_extract_epi32(xmm2, 2)); + *llr64++ = simde_mm_set_pi32(simde_mm_extract_epi32(xmm2, 3), simde_mm_extract_epi32(xmm1, 3)); + rxF_128++; + ch_mag_128++; + ch_magb_128++; + } + + nb_re &= 0x3; + + int16_t *rxDataF_i16 = (int16_t *)rxF_128; + int16_t *ch_mag_i16 = (int16_t *)ch_mag_128; + int16_t *ch_magb_i16 = (int16_t *)ch_magb_128; + int16_t *llr_i16 = (int16_t *)llr64; + for (int i = 0; i < nb_re; i++) { + int16_t real = rxDataF_i16[2 * i]; + int16_t imag = rxDataF_i16[2 * i + 1]; + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; + llr_i16[6 * i] = real; + llr_i16[6 * i + 1] = imag; + llr_i16[6 * i + 2] = saturating_sub(mag_real, abs(real)); + llr_i16[6 * i + 3] = saturating_sub(mag_imag, abs(imag)); + int16_t mag_realb = ch_magb_i16[2 * i]; + int16_t mag_imagb = ch_magb_i16[2 * i + 1]; + llr_i16[6 * i + 4] = saturating_sub(mag_realb, abs(llr_i16[6 * i + 2])); + llr_i16[6 * i + 5] = saturating_sub(mag_imagb, abs(llr_i16[6 * i + 3])); + } + simde_mm_empty(); +} + +void nr_256qam_llr(int32_t *rxdataF_comp, + int32_t *ch_mag, + int32_t *ch_mag2, + int32_t *ch_mag3, + int16_t *llr, + uint32_t nb_re, + uint8_t symbol) +{ + simde__m256i *rxF_256 = (simde__m256i *)rxdataF_comp; + simde__m256i *llr256 = (simde__m256i *)llr; + + simde__m256i *ch_maga = (simde__m256i *)ch_mag; + simde__m256i *ch_magb = (simde__m256i *)ch_mag2; + simde__m256i *ch_magc = (simde__m256i *)ch_mag3; +#ifndef USE_128BIT + simde__m256i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; + + for (int i = 0; i < (nb_re >> 3); i++) { + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + xmm0 = simde_mm256_abs_epi16(*rxF_256); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm0 = simde_mm256_subs_epi16(*ch_maga, xmm0); + // xmmtmpD2 contains 16 LLRs + xmm1 = simde_mm256_abs_epi16(xmm0); + xmm1 = simde_mm256_subs_epi16(*ch_magb, xmm1); // contains 16 LLRs + xmm2 = simde_mm256_abs_epi16(xmm1); + xmm2 = simde_mm256_subs_epi16(*ch_magc, xmm2); // contains 16 LLRs + // rxF[i] A0 A1 A2 A3 A4 A5 A6 A7 bits 7,6 + // xmm0 B0 B1 B2 B3 B4 B5 B6 B7 bits 5,4 + // xmm1 C0 C1 C2 C3 C4 C5 C6 C7 bits 3,2 + // xmm2 D0 D1 D2 D3 D4 D5 D6 D7 bits 1,0 + xmm3 = simde_mm256_unpacklo_epi32(*rxF_256, xmm0); // A0 B0 A1 B1 A4 B4 A5 B5 + xmm4 = simde_mm256_unpackhi_epi32(*rxF_256, xmm0); // A2 B2 A3 B3 A6 B6 A7 B7 + xmm5 = simde_mm256_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 C4 D4 C5 D5 + xmm6 = simde_mm256_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 C6 D6 C7 D7 + + xmm0 = simde_mm256_unpacklo_epi64(xmm3, xmm5); // A0 B0 C0 D0 A4 B4 C4 D4 + xmm1 = simde_mm256_unpackhi_epi64(xmm3, xmm5); // A1 B1 C1 D1 A5 B5 C5 D5 + xmm2 = simde_mm256_unpacklo_epi64(xmm4, xmm6); // A2 B2 C2 D2 A6 B6 C6 D6 + xmm3 = simde_mm256_unpackhi_epi64(xmm4, xmm6); // A3 B3 C3 D3 A7 B7 C7 D7 + *llr256++ = simde_mm256_permute2x128_si256(xmm0, xmm1, 0x20); // A0 B0 C0 D0 A1 B1 C1 D1 + *llr256++ = simde_mm256_permute2x128_si256(xmm2, xmm3, 0x20); // A2 B2 C2 D2 A3 B3 C3 D3 + *llr256++ = simde_mm256_permute2x128_si256(xmm0, xmm1, 0x31); // A4 B4 C4 D4 A5 B5 C5 D5 + *llr256++ = simde_mm256_permute2x128_si256(xmm2, xmm3, 0x31); // A6 B6 C6 D6 A7 B7 C7 D7 + ch_magc++; + ch_magb++; + ch_maga++; + rxF_256++; + } + + nb_re &= 0x7; +#endif + + simde__m128i *rxF_128 = (simde__m128i *)rxF_256; + simde__m128i *llr_128 = (simde__m128i *)llr256; + + simde__m128i *ch_maga_128 = (simde__m128i *)ch_maga; + simde__m128i *ch_magb_128 = (simde__m128i *)ch_magb; + simde__m128i *ch_magc_128 = (simde__m128i *)ch_magc; + + for (int i = 0; i < (nb_re >> 2); i++) { + simde__m128i xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6; + // registers of even index in xmm0-> |y_R|, registers of odd index in xmm0-> |y_I| + xmm0 = simde_mm_abs_epi16(*rxF_128); + // registers of even index in xmm0-> |y_R|-|h|^2, registers of odd index in xmm0-> |y_I|-|h|^2 + xmm0 = simde_mm_subs_epi16(*ch_maga_128, xmm0); + xmm1 = simde_mm_abs_epi16(xmm0); + xmm1 = simde_mm_subs_epi16(*ch_magb_128, xmm1); // contains 8 LLRs + xmm2 = simde_mm_abs_epi16(xmm1); + xmm2 = simde_mm_subs_epi16(*ch_magc_128, xmm2); // contains 8 LLRs + // rxF[i] A0 A1 A2 A3 + // xmm0 B0 B1 B2 B3 + // xmm1 C0 C1 C2 C3 + // xmm2 D0 D1 D2 D3 + xmm3 = simde_mm_unpacklo_epi32(*rxF_128, xmm0); // A0 B0 A1 B1 + xmm4 = simde_mm_unpackhi_epi32(*rxF_128, xmm0); // A2 B2 A3 B3 + xmm5 = simde_mm_unpacklo_epi32(xmm1, xmm2); // C0 D0 C1 D1 + xmm6 = simde_mm_unpackhi_epi32(xmm1, xmm2); // C2 D2 C3 D3 + + *llr_128++ = simde_mm_unpacklo_epi64(xmm3, xmm5); // A0 B0 C0 D0 + *llr_128++ = simde_mm_unpackhi_epi64(xmm3, xmm5); // A1 B1 C1 D1 + *llr_128++ = simde_mm_unpacklo_epi64(xmm4, xmm6); // A2 B2 C2 D2 + *llr_128++ = simde_mm_unpackhi_epi64(xmm4, xmm6); // A3 B3 C3 D3 + + rxF_128++; + ch_maga_128++; + ch_magb_128++; + ch_magc_128++; + } + + if (nb_re & 3) { + for (int i = 0; i < (nb_re & 0x3); i++) { + int16_t *rxDataF_i16 = (int16_t *)rxF_128; + int16_t *ch_mag_i16 = (int16_t *)ch_maga_128; + int16_t *ch_magb_i16 = (int16_t *)ch_magb_128; + int16_t *ch_magc_i16 = (int16_t *)ch_magc_128; + int16_t *llr_i16 = (int16_t *)llr_128; + int16_t real = rxDataF_i16[2 * i + 0]; + int16_t imag = rxDataF_i16[2 * i + 1]; + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; + llr_i16[8 * i] = real; + llr_i16[8 * i + 1] = imag; + llr_i16[8 * i + 2] = saturating_sub(mag_real, abs(real)); + llr_i16[8 * i + 3] = saturating_sub(mag_imag, abs(imag)); + int16_t magb_real = ch_magb_i16[2 * i]; + int16_t magb_imag = ch_magb_i16[2 * i + 1]; + llr_i16[8 * i + 4] = saturating_sub(magb_real, abs(llr_i16[8 * i + 2])); + llr_i16[8 * i + 5] = saturating_sub(magb_imag, abs(llr_i16[8 * i + 3])); + int16_t magc_real = ch_magc_i16[2 * i]; + int16_t magc_imag = ch_magc_i16[2 * i + 1]; + llr_i16[8 * i + 6] = saturating_sub(magc_real, abs(llr_i16[8 * i + 4])); + llr_i16[8 * i + 7] = saturating_sub(magc_imag, abs(llr_i16[8 * i + 5])); + } + } + simde_mm_empty(); +} + void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal) { const idft_size_idx_t idft_size = get_idft(ofdm_symbol_size); From 98a8e5dca3a9c88a392a3d5ae0b0a9635f4ca9cd Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 16 Aug 2024 17:37:18 +0200 Subject: [PATCH 11/61] use common LLR functions at UE for DLSCH --- CMakeLists.txt | 1 - doc/Doxyfile | 1 - .../NR_TRANSPORT/nr_ulsch_llr_computation.c | 12 +- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 31 +- .../nr_dlsch_llr_computation.c | 329 ------------------ .../NR_UE_TRANSPORT/nr_transport_proto_ue.h | 74 ---- .../PHY/nr_phy_common/inc/nr_phy_common.h | 14 +- .../PHY/nr_phy_common/src/nr_phy_common.c | 14 +- 8 files changed, 29 insertions(+), 447 deletions(-) delete mode 100644 openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c diff --git a/CMakeLists.txt b/CMakeLists.txt index faa3d9dc35..95232c3915 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1066,7 +1066,6 @@ set(PHY_SRC_UE ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c - ${OPENAIR1_DIR}/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_tbs_tools.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_prach_common.c ${OPENAIR1_DIR}/PHY/NR_TRANSPORT/nr_sch_dmrs.c diff --git a/doc/Doxyfile b/doc/Doxyfile index 5f377964cf..0d53026705 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -2256,7 +2256,6 @@ INPUT = \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_UE_TRANSPORT/pucch_nr.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_UE_TRANSPORT/sss_nr.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_UE_TRANSPORT/dci_nr.c \ -@CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_UE_TRANSPORT/nr_prach.c \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h \ @CMAKE_CURRENT_SOURCE_DIR@/../openair1/PHY/NR_UE_TRANSPORT/nr_ue_rf_helpers.c \ diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c index 450408e794..6c5c37385b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_llr_computation.c @@ -47,21 +47,21 @@ void nr_ulsch_compute_llr(int32_t *rxdataF_comp, uint8_t symbol, uint8_t mod_order) { - switch(mod_order){ + switch(mod_order) { case 2: - nr_qpsk_llr(rxdataF_comp, ulsch_llr, nb_re, symbol); + nr_qpsk_llr(rxdataF_comp, ulsch_llr, nb_re); break; case 4: - nr_16qam_llr(rxdataF_comp, ul_ch_mag, ulsch_llr, nb_re, symbol); + nr_16qam_llr(rxdataF_comp, ul_ch_mag, ulsch_llr, nb_re); break; case 6: - nr_64qam_llr(rxdataF_comp, ul_ch_mag, ul_ch_magb, ulsch_llr, nb_re, symbol); + nr_64qam_llr(rxdataF_comp, ul_ch_mag, ul_ch_magb, ulsch_llr, nb_re); break; case 8: - nr_256qam_llr(rxdataF_comp, ul_ch_mag, ul_ch_magb, ul_ch_magc, ulsch_llr, nb_re, symbol); + nr_256qam_llr(rxdataF_comp, ul_ch_mag, ul_ch_magb, ul_ch_magc, ulsch_llr, nb_re); break; default: - AssertFatal(1==0,"nr_ulsch_compute_llr: invalid Qm value, symbol = %d, Qm = %d\n",symbol, mod_order); + AssertFatal(false, "nr_ulsch_compute_llr: invalid Qm value, symbol = %d, Qm = %d\n",symbol, mod_order); break; } } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 6537e4b840..3482d2a80a 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -28,6 +28,7 @@ * \note * \warning */ +#include "nr_phy_common.h" #include "PHY/defs_nr_UE.h" #include "PHY/phy_extern.h" #include "nr_transport_proto_ue.h" @@ -1898,33 +1899,31 @@ static int nr_dlsch_llr(uint32_t rx_size_symbol, NR_UE_DLSCH_t dlsch[2], uint32_t llr_offset[14]) { - uint32_t llr_offset_symbol; - - if (first_symbol_flag==1) - llr_offset[symbol-1] = 0; - llr_offset_symbol = llr_offset[symbol-1]; + if (first_symbol_flag == 1) + llr_offset[symbol - 1] = 0; + uint32_t llr_offset_symbol = llr_offset[symbol - 1]; - llr_offset[symbol] = len*dlsch[0].dlsch_config.qamModOrder + llr_offset_symbol; + llr_offset[symbol] = len * dlsch[0].dlsch_config.qamModOrder + llr_offset_symbol; switch (dlsch[0].dlsch_config.qamModOrder) { case 2 : - for(int l=0; l < dlsch[0].Nl; l++) - nr_dlsch_qpsk_llr(frame_parms, rxdataF_comp[l][0], layer_llr[l] + llr_offset_symbol, symbol, len, first_symbol_flag, nb_rb); + for(int l = 0; l < dlsch[0].Nl; l++) + nr_qpsk_llr(&rxdataF_comp[l][0][symbol * nb_rb * 12], layer_llr[l] + llr_offset_symbol, len); break; case 4 : - for(int l=0; l < dlsch[0].Nl; l++) - nr_dlsch_16qam_llr(frame_parms, rxdataF_comp[l][0], layer_llr[l] + llr_offset_symbol, dl_ch_mag, symbol, len, first_symbol_flag, nb_rb); + for(int l = 0; l < dlsch[0].Nl; l++) + nr_16qam_llr(&rxdataF_comp[l][0][symbol * nb_rb * 12], dl_ch_mag, layer_llr[l] + llr_offset_symbol, len); break; case 6 : for(int l=0; l < dlsch[0].Nl; l++) - nr_dlsch_64qam_llr(frame_parms, rxdataF_comp[l][0], layer_llr[l] + llr_offset_symbol, dl_ch_mag, dl_ch_magb, symbol, len, first_symbol_flag, nb_rb); + nr_64qam_llr(&rxdataF_comp[l][0][symbol * nb_rb * 12], dl_ch_mag, dl_ch_magb, layer_llr[l] + llr_offset_symbol, len); break; case 8: for(int l=0; l < dlsch[0].Nl; l++) - nr_dlsch_256qam_llr(frame_parms, rxdataF_comp[l][0], layer_llr[l] + llr_offset_symbol, dl_ch_mag, dl_ch_magb, dl_ch_magr, symbol, len, first_symbol_flag, nb_rb); + nr_256qam_llr(&rxdataF_comp[l][0][symbol * nb_rb * 12], dl_ch_mag, dl_ch_magb, dl_ch_magr, layer_llr[l] + llr_offset_symbol, len); break; default: @@ -1937,19 +1936,19 @@ static int nr_dlsch_llr(uint32_t rx_size_symbol, if (dlsch1_harq) { switch (dlsch[1].dlsch_config.qamModOrder) { case 2 : - nr_dlsch_qpsk_llr(frame_parms, rxdataF_comp[0][0], layer_llr[0] + llr_offset_symbol, symbol, len, first_symbol_flag, nb_rb); + nr_qpsk_llr(&rxdataF_comp[0][0][symbol * nb_rb * 12], layer_llr[0] + llr_offset_symbol, len); break; case 4: - nr_dlsch_16qam_llr(frame_parms, rxdataF_comp[0][0], layer_llr[0] + llr_offset_symbol, dl_ch_mag, symbol, len, first_symbol_flag, nb_rb); + nr_16qam_llr(&rxdataF_comp[0][0][symbol * nb_rb * 12], dl_ch_mag, layer_llr[0] + llr_offset_symbol, len); break; case 6 : - nr_dlsch_64qam_llr(frame_parms, rxdataF_comp[0][0], layer_llr[0] + llr_offset_symbol, dl_ch_mag, dl_ch_magb, symbol, len, first_symbol_flag, nb_rb); + nr_64qam_llr(&rxdataF_comp[0][0][symbol * nb_rb * 12], dl_ch_mag, dl_ch_magb, layer_llr[0] + llr_offset_symbol, len); break; case 8 : - nr_dlsch_256qam_llr(frame_parms, rxdataF_comp[0][0], layer_llr[0] + llr_offset_symbol, dl_ch_mag, dl_ch_magb, dl_ch_magr, symbol, len, first_symbol_flag, nb_rb); + nr_256qam_llr(&rxdataF_comp[0][0][symbol * nb_rb * 12], dl_ch_mag, dl_ch_magb, dl_ch_magr, layer_llr[0] + llr_offset_symbol, len); break; default: diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c deleted file mode 100644 index 3a67306905..0000000000 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file PHY/NR_UE_TRANSPORT/nr_dlsch_llr_computation.c - * \brief Top-level routines for LLR computation of the PDSCH physical channel - * \author H. WANG - * \date 2018 - * \version 0.1 - * \company Eurecom - * \email: - * \note - * \warning - */ - -#include "PHY/defs_nr_UE.h" -#include "PHY/phy_extern_nr_ue.h" -#include "nr_transport_proto_ue.h" -#include "PHY/TOOLS/tools_defs.h" -#include "PHY/sse_intrin.h" - -#ifdef __aarch64__ -#define USE_128BIT -#endif - -//#define DEBUG_LLR_SIC - -//============================================================================================== -// SINGLE-STREAM -//============================================================================================== - -//---------------------------------------------------------------------------------------------- -// QPSK -//---------------------------------------------------------------------------------------------- - -int nr_dlsch_qpsk_llr(NR_DL_FRAME_PARMS *frame_parms, - int32_t *rxdataF_comp, - int16_t *dlsch_llr, - uint8_t symbol, - uint32_t len, - uint8_t first_symbol_flag, - uint16_t nb_rb) -{ - - c16_t *rxF = (c16_t *)&rxdataF_comp[((int32_t)symbol*nb_rb*12)]; - c16_t *llr32 = (c16_t *)dlsch_llr; - int i; - - if (!llr32) { - LOG_E(PHY,"nr_dlsch_qpsk_llr: llr is null, symbol %d, llr32=%p\n",symbol, llr32); - return(-1); - } - - /* - LOG_I(PHY,"dlsch_qpsk_llr: [symb %d / Length %d]: @LLR Buff %x, @LLR Buff(symb) %x \n", - symbol, - len, - dlsch_llr, - llr32); - */ - for (i=0; ir = rxF->r >> 3; - llr32->i = rxF->i >> 3; - LOG_D(PHY,"dlsch_qpsk_llr %d : (%d,%d)\n", i, llr32->r, llr32->i); - rxF++; - llr32++; - } - return(0); -} - - -//---------------------------------------------------------------------------------------------- -// 16-QAM -//---------------------------------------------------------------------------------------------- - -void nr_dlsch_16qam_llr(NR_DL_FRAME_PARMS *frame_parms, - int32_t *rxdataF_comp, - int16_t *dlsch_llr, - int32_t *dl_ch_mag, - uint8_t symbol, - uint32_t len, - uint8_t first_symbol_flag, - uint16_t nb_rb) -{ - - simde__m128i *rxF = (simde__m128i*)&rxdataF_comp[(symbol*nb_rb*12)]; - simde__m128i *ch_mag; - simde__m128i llr128[2]; - uint32_t *llr32; - - - int i; - unsigned char len_mod4=0; - - - llr32 = (uint32_t*)dlsch_llr; - ch_mag = (simde__m128i *)dl_ch_mag; - - - // printf("len=%d\n", len); - len_mod4 = len&3; - // printf("len_mod4=%d\n", len_mod4); - len>>=2; // length in quad words (4 REs) - // printf("len>>=2=%d\n", len); - len+=(len_mod4==0 ? 0 : 1); - // printf("len+=%d\n", len); - for (i=0; i>2; // length in quad words (4 REs) - len2+=((len_mod4==0)?0:1); - - for (i=0; i>2; // length in quad words (4 REs) - len2+=((len_mod4==0)?0:1); - - for (i=0; i Date: Tue, 20 Aug 2024 17:24:56 +0200 Subject: [PATCH 12/61] adapt LLR unit test to a generic UL/DL scenario --- openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp | 265 +++++++++---------- openair1/PHY/nr_phy_common/CMakeLists.txt | 2 +- 2 files changed, 124 insertions(+), 143 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp b/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp index 5778bd6c39..bd0c95d2ae 100644 --- a/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp +++ b/openair1/PHY/NR_TRANSPORT/tests/test_llr.cpp @@ -25,20 +25,9 @@ #include #include extern "C" { -void nr_ulsch_16qam_llr(int32_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_re, uint8_t symbol); -void nr_ulsch_64qam_llr(int32_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol); -void nr_ulsch_256qam_llr(int32_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - int32_t *ul_ch_magc, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol); +void nr_16qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag_in, int16_t *llr, uint32_t nb_re); +void nr_64qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int16_t *llr, uint32_t nb_re); +void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int32_t *ch_mag3, int16_t *llr, uint32_t nb_re); struct configmodule_interface_s; struct configmodule_interface_s *uniqCfg = NULL; @@ -72,74 +61,72 @@ int16_t saturating_sub(int16_t a, int16_t b) } } -void nr_ulsch_16qam_llr_ref(c16_t *rxdataF_comp, int32_t *ul_ch_mag, int16_t *ulsch_llr, uint32_t nb_re, uint8_t symbol) +void nr_16qam_llr_ref(c16_t *rxdataF_comp, int32_t *ch_mag, int16_t *llr, uint32_t nb_re) { - int16_t *ul_ch_mag_i16 = (int16_t *)ul_ch_mag; + int16_t *ch_mag_i16 = (int16_t *)ch_mag; for (auto i = 0U; i < nb_re; i++) { int16_t real = rxdataF_comp[i].r; int16_t imag = rxdataF_comp[i].i; - int16_t mag_real = ul_ch_mag_i16[2 * i]; - int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; - ulsch_llr[4 * i] = real; - ulsch_llr[4 * i + 1] = imag; - ulsch_llr[4 * i + 2] = saturating_sub(mag_real, std::abs(real)); - ulsch_llr[4 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; + llr[4 * i] = real; + llr[4 * i + 1] = imag; + llr[4 * i + 2] = saturating_sub(mag_real, std::abs(real)); + llr[4 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); } } -void nr_ulsch_64qam_llr_ref(c16_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol) +void nr_64qam_llr_ref(c16_t *rxdataF_comp, + int32_t *ch_mag, + int32_t *ch_magb, + int16_t *llr, + uint32_t nb_re) { - int16_t *ul_ch_mag_i16 = (int16_t *)ul_ch_mag; - int16_t *ul_ch_magb_i16 = (int16_t *)ul_ch_magb; + int16_t *ch_mag_i16 = (int16_t *)ch_mag; + int16_t *ch_magb_i16 = (int16_t *)ch_magb; for (auto i = 0U; i < nb_re; i++) { int16_t real = rxdataF_comp[i].r; int16_t imag = rxdataF_comp[i].i; - int16_t mag_real = ul_ch_mag_i16[2 * i]; - int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; - ulsch_llr[6 * i] = real; - ulsch_llr[6 * i + 1] = imag; - ulsch_llr[6 * i + 2] = saturating_sub(mag_real, std::abs(real)); - ulsch_llr[6 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); - int16_t mag_realb = ul_ch_magb_i16[2 * i]; - int16_t mag_imagb = ul_ch_magb_i16[2 * i + 1]; - ulsch_llr[6 * i + 4] = saturating_sub(mag_realb, std::abs(ulsch_llr[6 * i + 2])); - ulsch_llr[6 * i + 5] = saturating_sub(mag_imagb, std::abs(ulsch_llr[6 * i + 3])); + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; + llr[6 * i] = real; + llr[6 * i + 1] = imag; + llr[6 * i + 2] = saturating_sub(mag_real, std::abs(real)); + llr[6 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + int16_t mag_realb = ch_magb_i16[2 * i]; + int16_t mag_imagb = ch_magb_i16[2 * i + 1]; + llr[6 * i + 4] = saturating_sub(mag_realb, std::abs(llr[6 * i + 2])); + llr[6 * i + 5] = saturating_sub(mag_imagb, std::abs(llr[6 * i + 3])); } } -void nr_ulsch_256qam_llr_ref(c16_t *rxdataF_comp, - int32_t *ul_ch_mag, - int32_t *ul_ch_magb, - int32_t *ul_ch_magc, - int16_t *ulsch_llr, - uint32_t nb_re, - uint8_t symbol) +void nr_256qam_llr_ref(c16_t *rxdataF_comp, + int32_t *ch_mag, + int32_t *ch_magb, + int32_t *ch_magc, + int16_t *llr, + uint32_t nb_re) { - int16_t *ul_ch_mag_i16 = (int16_t *)ul_ch_mag; - int16_t *ul_ch_magb_i16 = (int16_t *)ul_ch_magb; - int16_t *ul_ch_magc_i16 = (int16_t *)ul_ch_magc; + int16_t *ch_mag_i16 = (int16_t *)ch_mag; + int16_t *ch_magb_i16 = (int16_t *)ch_magb; + int16_t *ch_magc_i16 = (int16_t *)ch_magc; for (auto i = 0U; i < nb_re; i++) { int16_t real = rxdataF_comp[i].r; int16_t imag = rxdataF_comp[i].i; - int16_t mag_real = ul_ch_mag_i16[2 * i]; - int16_t mag_imag = ul_ch_mag_i16[2 * i + 1]; - ulsch_llr[8 * i] = real; - ulsch_llr[8 * i + 1] = imag; - ulsch_llr[8 * i + 2] = saturating_sub(mag_real, std::abs(real)); - ulsch_llr[8 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); - int16_t magb_real = ul_ch_magb_i16[2 * i]; - int16_t magb_imag = ul_ch_magb_i16[2 * i + 1]; - ulsch_llr[8 * i + 4] = saturating_sub(magb_real, std::abs(ulsch_llr[8 * i + 2])); - ulsch_llr[8 * i + 5] = saturating_sub(magb_imag, std::abs(ulsch_llr[8 * i + 3])); - int16_t magc_real = ul_ch_magc_i16[2 * i]; - int16_t magc_imag = ul_ch_magc_i16[2 * i + 1]; - ulsch_llr[8 * i + 6] = saturating_sub(magc_real, std::abs(ulsch_llr[8 * i + 4])); - ulsch_llr[8 * i + 7] = saturating_sub(magc_imag, std::abs(ulsch_llr[8 * i + 5])); + int16_t mag_real = ch_mag_i16[2 * i]; + int16_t mag_imag = ch_mag_i16[2 * i + 1]; + llr[8 * i] = real; + llr[8 * i + 1] = imag; + llr[8 * i + 2] = saturating_sub(mag_real, std::abs(real)); + llr[8 * i + 3] = saturating_sub(mag_imag, std::abs(imag)); + int16_t magb_real = ch_magb_i16[2 * i]; + int16_t magb_imag = ch_magb_i16[2 * i + 1]; + llr[8 * i + 4] = saturating_sub(magb_real, std::abs(llr[8 * i + 2])); + llr[8 * i + 5] = saturating_sub(magb_imag, std::abs(llr[8 * i + 3])); + int16_t magc_real = ch_magc_i16[2 * i]; + int16_t magc_imag = ch_magc_i16[2 * i + 1]; + llr[8 * i + 6] = saturating_sub(magc_real, std::abs(llr[8 * i + 4])); + llr[8 * i + 7] = saturating_sub(magc_imag, std::abs(llr[8 * i + 5])); } } @@ -149,21 +136,21 @@ void test_function_16_qam(AlignedVector512 nb_res) uint32_t nb_re = nb_res[i]; auto rf_data = generate_random_c16(nb_re); auto magnitude_data = generate_random_uint16(nb_re * 2); - AlignedVector512 ulsch_llr_ref; - ulsch_llr_ref.resize(nb_re); - std::fill(ulsch_llr_ref.begin(), ulsch_llr_ref.end(), 0); - nr_ulsch_16qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int16_t *)ulsch_llr_ref.data(), nb_re, 0); + AlignedVector512 llr_ref; + llr_ref.resize(nb_re); + std::fill(llr_ref.begin(), llr_ref.end(), 0); + nr_16qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int16_t *)llr_ref.data(), nb_re); - AlignedVector512 ulsch_llr; - ulsch_llr.resize(nb_re); - std::fill(ulsch_llr.begin(), ulsch_llr.end(), 0); - nr_ulsch_16qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int16_t *)ulsch_llr.data(), nb_re, 0); + AlignedVector512 llr; + llr.resize(nb_re); + std::fill(llr.begin(), llr.end(), 0); + nr_16qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int16_t *)llr.data(), nb_re); int num_errors = 0; for (auto i = 0U; i < nb_re; i++) { - EXPECT_EQ(ulsch_llr_ref[i], ulsch_llr[i]) - << "Mismatch 16qam REF " << std::hex << ulsch_llr_ref[i] << " != DUT " << ulsch_llr[i] << " at " << std::dec << i; - if (ulsch_llr_ref[i] != ulsch_llr[i]) { + EXPECT_EQ(llr_ref[i], llr[i]) + << "Mismatch 16qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i; + if (llr_ref[i] != llr[i]) { num_errors++; } } @@ -178,31 +165,29 @@ void test_function_64_qam(AlignedVector512 nb_res) auto rf_data = generate_random_c16(nb_re); auto magnitude_data = generate_random_uint16(nb_re * 2); auto magnitude_b_data = generate_random_uint16(nb_re * 2); - AlignedVector512 ulsch_llr_ref; - ulsch_llr_ref.resize(nb_re * 3); - std::fill(ulsch_llr_ref.begin(), ulsch_llr_ref.end(), 0); - nr_ulsch_64qam_llr_ref((c16_t *)rf_data.data(), + AlignedVector512 llr_ref; + llr_ref.resize(nb_re * 3); + std::fill(llr_ref.begin(), llr_ref.end(), 0); + nr_64qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int32_t *)magnitude_b_data.data(), - (int16_t *)ulsch_llr_ref.data(), - nb_re, - 0); + (int16_t *)llr_ref.data(), + nb_re); - AlignedVector512 ulsch_llr; - ulsch_llr.resize(nb_re * 3); - std::fill(ulsch_llr.begin(), ulsch_llr.end(), 0); - nr_ulsch_64qam_llr((int32_t *)rf_data.data(), + AlignedVector512 llr; + llr.resize(nb_re * 3); + std::fill(llr.begin(), llr.end(), 0); + nr_64qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int32_t *)magnitude_b_data.data(), - (int16_t *)ulsch_llr.data(), - nb_re, - 0); + (int16_t *)llr.data(), + nb_re); int num_errors = 0; for (auto i = 0U; i < nb_re * 3; i++) { - EXPECT_EQ(ulsch_llr_ref[i], ulsch_llr[i]) - << "Mismatch 64qam REF " << std::hex << ulsch_llr_ref[i] << " != DUT " << ulsch_llr[i] << " at " << std::dec << i; - if (ulsch_llr_ref[i] != ulsch_llr[i]) { + EXPECT_EQ(llr_ref[i], llr[i]) + << "Mismatch 64qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i; + if (llr_ref[i] != llr[i]) { num_errors++; } } @@ -218,33 +203,31 @@ void test_function_256_qam(AlignedVector512 nb_res) auto magnitude_data = generate_random_uint16(nb_re * 2); auto magnitude_b_data = generate_random_uint16(nb_re * 2); auto magnitude_c_data = generate_random_uint16(nb_re * 2); - AlignedVector512 ulsch_llr_ref; - ulsch_llr_ref.resize(nb_re * 4); - std::fill(ulsch_llr_ref.begin(), ulsch_llr_ref.end(), 0); - nr_ulsch_256qam_llr_ref((c16_t *)rf_data.data(), + AlignedVector512 llr_ref; + llr_ref.resize(nb_re * 4); + std::fill(llr_ref.begin(), llr_ref.end(), 0); + nr_256qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int32_t *)magnitude_b_data.data(), (int32_t *)magnitude_c_data.data(), - (int16_t *)ulsch_llr_ref.data(), - nb_re, - 0); + (int16_t *)llr_ref.data(), + nb_re); - AlignedVector512 ulsch_llr; - ulsch_llr.resize(nb_re * 4); - std::fill(ulsch_llr.begin(), ulsch_llr.end(), 0); - nr_ulsch_256qam_llr((int32_t *)rf_data.data(), + AlignedVector512 llr; + llr.resize(nb_re * 4); + std::fill(llr.begin(), llr.end(), 0); + nr_256qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int32_t *)magnitude_b_data.data(), (int32_t *)magnitude_c_data.data(), - (int16_t *)ulsch_llr.data(), - nb_re, - 0); + (int16_t *)llr.data(), + nb_re); int num_errors = 0; for (auto i = 0U; i < nb_re * 4; i++) { - EXPECT_EQ(ulsch_llr_ref[i], ulsch_llr[i]) - << "Mismatch 256qam REF " << std::hex << ulsch_llr_ref[i] << " != DUT " << ulsch_llr[i] << " at " << std::dec << i; - if (ulsch_llr_ref[i] != ulsch_llr[i]) { + EXPECT_EQ(llr_ref[i], llr[i]) + << "Mismatch 256qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i; + if (llr_ref[i] != llr[i]) { num_errors++; } } @@ -370,59 +353,57 @@ TEST(test_llr, check_2_res_256_qam) AlignedVector512 magnitude_data = {1, 1, 1, 1}; AlignedVector512 magnitude_b_data = {2, 2, 2, 2}; AlignedVector512 magnitude_c_data = {3, 3, 3, 3}; - AlignedVector512 ulsch_llr_ref; - ulsch_llr_ref.resize(2 * 8); - std::fill(ulsch_llr_ref.begin(), ulsch_llr_ref.end(), 0); - nr_ulsch_256qam_llr_ref((c16_t *)rf_data.data(), + AlignedVector512 llr_ref; + llr_ref.resize(2 * 8); + std::fill(llr_ref.begin(), llr_ref.end(), 0); + nr_256qam_llr_ref((c16_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int32_t *)magnitude_b_data.data(), (int32_t *)magnitude_c_data.data(), - (int16_t *)ulsch_llr_ref.data(), - 2, - 0); + (int16_t *)llr_ref.data(), + 2); - AlignedVector512 ulsch_llr; - ulsch_llr.resize(2 * 8); - std::fill(ulsch_llr.begin(), ulsch_llr.end(), 0); - nr_ulsch_256qam_llr((int32_t *)rf_data.data(), + AlignedVector512 llr; + llr.resize(2 * 8); + std::fill(llr.begin(), llr.end(), 0); + nr_256qam_llr((int32_t *)rf_data.data(), (int32_t *)magnitude_data.data(), (int32_t *)magnitude_b_data.data(), (int32_t *)magnitude_c_data.data(), - (int16_t *)ulsch_llr.data(), - 2, - 0); + (int16_t *)llr.data(), + 2); printf("\nDUT:\n"); for (auto i = 0U; i < 2; i++) { printf("%d %d %d %d %d %d %d %d\n", - ulsch_llr[i * 8], - ulsch_llr[i * 8 + 1], - ulsch_llr[i * 8 + 2], - ulsch_llr[i * 8 + 3], - ulsch_llr[i * 8 + 4], - ulsch_llr[i * 8 + 5], - ulsch_llr[i * 8 + 6], - ulsch_llr[i * 8 + 7]); + llr[i * 8], + llr[i * 8 + 1], + llr[i * 8 + 2], + llr[i * 8 + 3], + llr[i * 8 + 4], + llr[i * 8 + 5], + llr[i * 8 + 6], + llr[i * 8 + 7]); } printf("\nREF:\n"); for (auto i = 0U; i < 2; i++) { printf("%d %d %d %d %d %d %d %d\n", - ulsch_llr_ref[i * 8], - ulsch_llr_ref[i * 8 + 1], - ulsch_llr_ref[i * 8 + 2], - ulsch_llr_ref[i * 8 + 3], - ulsch_llr_ref[i * 8 + 4], - ulsch_llr_ref[i * 8 + 5], - ulsch_llr_ref[i * 8 + 6], - ulsch_llr_ref[i * 8 + 7]); + llr_ref[i * 8], + llr_ref[i * 8 + 1], + llr_ref[i * 8 + 2], + llr_ref[i * 8 + 3], + llr_ref[i * 8 + 4], + llr_ref[i * 8 + 5], + llr_ref[i * 8 + 6], + llr_ref[i * 8 + 7]); } int num_errors = 0; for (auto i = 0U; i < 2 * 8; i++) { - EXPECT_EQ(ulsch_llr_ref[i], ulsch_llr[i]) - << "Mismatch 256qam REF " << std::hex << ulsch_llr_ref[i] << " != DUT " << ulsch_llr[i] << " at " << std::dec << i; - if (ulsch_llr_ref[i] != ulsch_llr[i]) { + EXPECT_EQ(llr_ref[i], llr[i]) + << "Mismatch 256qam REF " << std::hex << llr_ref[i] << " != DUT " << llr[i] << " at " << std::dec << i; + if (llr_ref[i] != llr[i]) { num_errors++; } } diff --git a/openair1/PHY/nr_phy_common/CMakeLists.txt b/openair1/PHY/nr_phy_common/CMakeLists.txt index ebbc3fcbc7..ee5fb820a8 100644 --- a/openair1/PHY/nr_phy_common/CMakeLists.txt +++ b/openair1/PHY/nr_phy_common/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(nr_phy_common src/nr_phy_common.c) -target_link_libraries(nr_phy_common PRIVATE UTIL) +target_link_libraries(nr_phy_common PRIVATE UTIL PHY_COMMON) target_include_directories(nr_phy_common PUBLIC inc/) add_library(nr_ue_phy_meas src/nr_ue_phy_meas.c) From 299137016903fd4cb0323476baae2e2836b4fd34 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sun, 25 Aug 2024 09:34:15 +0200 Subject: [PATCH 13/61] 32byte aligned DLSCH RX symbol size --- .../nr_dl_channel_estimation.c | 12 +-- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 98 +++++++++---------- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 2 +- 3 files changed, 51 insertions(+), 61 deletions(-) diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index d10f5b5b42..53c302e789 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -1633,7 +1633,7 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, nr_slot_rx, symbol, frame_parms->ofdm_symbol_size, - (int16_t *)(rxdataF_comp[0][aarx] + symbol * nb_re_pdsch), + (int16_t *)(rxdataF_comp[0][aarx] + symbol * rx_size_symbol), gold, (int16_t *)&phase_per_symbol[symbol], &ptrs_re_symbol[symbol]); @@ -1654,21 +1654,21 @@ void nr_pdsch_ptrs_processing(PHY_VARS_NR_UE *ue, } #ifdef DEBUG_DL_PTRS LOG_M("ptrsEst.m","est",ptrs_phase_per_slot[aarx],frame_parms->symbols_per_slot,1,1 ); - LOG_M("rxdataF_bf_ptrs_comp.m", "bf_ptrs_cmp", rxdataF_comp[0][aarx] + (*startSymbIndex) * NR_NB_SC_PER_RB * (*nb_rb), (*nb_rb) * NR_NB_SC_PER_RB * (*nbSymb), 1, 1); + LOG_M("rxdataF_bf_ptrs_comp.m", "bf_ptrs_cmp", rxdataF_comp[0][aarx] + (*startSymbIndex) * rx_size_symbol, rx_size_symbol * (*nbSymb), 1, 1); #endif /*------------------------------------------------------------------------------------------------------- */ /* 3) Compensated DMRS based estimated signal with PTRS estimation */ /*--------------------------------------------------------------------------------------------------------*/ - for(uint8_t i = *startSymbIndex; i< symbInSlot ;i++) { + for(uint8_t i = *startSymbIndex; i < symbInSlot; i++) { /* DMRS Symbol has 0 phase so no need to rotate the respective symbol */ /* Skip rotation if the slot processing is wrong */ - if((!is_dmrs_symbol(i,*dmrsSymbPos)) && (ret == 0)) { + if((!is_dmrs_symbol(i, *dmrsSymbPos)) && (ret == 0)) { #ifdef DEBUG_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((c16_t *)&rxdataF_comp[0][aarx][(i * (*nb_rb) * NR_NB_SC_PER_RB)], + rotate_cpx_vector((c16_t *)&rxdataF_comp[0][aarx][i * rx_size_symbol], &phase_per_symbol[i], - (c16_t *)&rxdataF_comp[0][aarx][(i * (*nb_rb) * NR_NB_SC_PER_RB)], + (c16_t *)&rxdataF_comp[0][aarx][i * rx_size_symbol], ((*nb_rb) * NR_NB_SC_PER_RB), 15); }// if not DMRS Symbol diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 3482d2a80a..05e8986ba5 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -116,7 +116,6 @@ static int nr_dlsch_llr(uint32_t rx_size_symbol, unsigned char harq_pid, unsigned char first_symbol_flag, unsigned char symbol, - unsigned short nb_rb, int32_t codeword_TB0, int32_t codeword_TB1, uint32_t len, @@ -221,17 +220,16 @@ void nr_dlsch_scale_channel(uint32_t rx_size_symbol, uint8_t pilots, uint32_t len, unsigned short nb_rb); -void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, - short n_tx, - short n_rx, - int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], - int ***rho, - int32_t dl_ch_mag[][n_rx][rx_size_symbol], - int32_t dl_ch_magb[][n_rx][rx_size_symbol], - int32_t dl_ch_magr[][n_rx][rx_size_symbol], - unsigned char symbol, - unsigned short nb_rb, - int length); +static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, + short n_tx, + short n_rx, + int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], + int ***rho, + int32_t dl_ch_mag[][n_rx][rx_size_symbol], + int32_t dl_ch_magb[][n_rx][rx_size_symbol], + int32_t dl_ch_magr[][n_rx][rx_size_symbol], + unsigned char symbol, + int length); static bool overlap_csi_symbol(fapi_nr_dl_config_csirs_pdu_rel15_t *csi_pdu, int symbol) { @@ -596,7 +594,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, dl_ch_magb, dl_ch_magr, symbol, - nb_rb_pdsch, nb_re_pdsch); if (nl >= 2) // Apply MMSE for 2, 3, and 4 Tx layers nr_dlsch_mmse(rx_size_symbol, @@ -691,7 +688,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, harq_pid, first_symbol_flag, i, - nb_rb_pdsch, codeword_TB0, codeword_TB1, dl_valid_re[i - 1], @@ -877,15 +873,13 @@ static void nr_dlsch_channel_compensation(uint32_t rx_size_symbol, QAM_amp128r = simde_mm_set1_epi16(QAM256_n3); } - // printf("comp: rxdataF_comp %p, symbol %d\n",rxdataF_comp[0],symbol); - for (int aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++) { dl_ch128 = (simde__m128i *)dl_ch_estimates_ext[(l * frame_parms->nb_antennas_rx) + aarx]; dl_ch_mag128 = (simde__m128i *)dl_ch_mag[l][aarx]; dl_ch_mag128b = (simde__m128i *)dl_ch_magb[l][aarx]; dl_ch_mag128r = (simde__m128i *)dl_ch_magr[l][aarx]; rxdataF128 = (simde__m128i *)rxdataF_ext[aarx]; - rxdataF_comp128 = (simde__m128i *)(rxdataF_comp[l][aarx] + symbol * nb_rb * 12); + rxdataF_comp128 = (simde__m128i *)(rxdataF_comp[l][aarx] + symbol * rx_size_symbol); for (int rb = 0; rb < nb_rb_0; rb++) { if (mod_order > 2) { @@ -1260,37 +1254,34 @@ static void nr_dlsch_extract_rbs(uint32_t rxdataF_sz, } } -void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, - short n_tx, - short n_rx, - int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], - int ***rho, - int32_t dl_ch_mag[][n_rx][rx_size_symbol], - int32_t dl_ch_magb[][n_rx][rx_size_symbol], - int32_t dl_ch_magr[][n_rx][rx_size_symbol], - unsigned char symbol, - unsigned short nb_rb, - int length) { - unsigned char aatx, aarx; - int i; +static void nr_dlsch_detection_mrc(uint32_t rx_size_symbol, + short n_tx, + short n_rx, + int32_t rxdataF_comp[][n_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], + int ***rho, + int32_t dl_ch_mag[][n_rx][rx_size_symbol], + int32_t dl_ch_magb[][n_rx][rx_size_symbol], + int32_t dl_ch_magr[][n_rx][rx_size_symbol], + unsigned char symbol, + int length) +{ simde__m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b,*dl_ch_mag128_0r,*dl_ch_mag128_1r; - uint32_t nb_rb_0 = length/12 + ((length%12)?1:0); - if (n_rx>1) { - for (aatx=0; aatx 1) { + for (int aatx = 0; aatx < n_tx; aatx++) { + rxdataF_comp128_0 = (simde__m128i *)(rxdataF_comp[aatx][0] + symbol * rx_size_symbol); dl_ch_mag128_0 = (simde__m128i *)dl_ch_mag[aatx][0]; dl_ch_mag128_0b = (simde__m128i *)dl_ch_magb[aatx][0]; dl_ch_mag128_0r = (simde__m128i *)dl_ch_magr[aatx][0]; - for (aarx=1; aarxframe_parms.nb_antennas_rx][NR_SYMBOLS_PER_SLOT]; memset(ptrs_re_per_slot, 0, sizeof(ptrs_re_per_slot)); - const uint32_t rx_size_symbol = dlsch[0].dlsch_config.number_rbs * NR_NB_SC_PER_RB; + const uint32_t rx_size_symbol = (dlsch[0].dlsch_config.number_rbs * NR_NB_SC_PER_RB + 15) & ~15; __attribute__((aligned(32))) int32_t rxdataF_comp[dlsch[0].Nl][ue->frame_parms.nb_antennas_rx][rx_size_symbol * NR_SYMBOLS_PER_SLOT]; memset(rxdataF_comp, 0, sizeof(rxdataF_comp)); From db098651b0662f78b08e05ef78aeda6a36b1f9c4 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sun, 25 Aug 2024 11:24:36 +0200 Subject: [PATCH 14/61] improvements in nr_dlsch_llr function --- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 108 +++++++----------- 1 file changed, 39 insertions(+), 69 deletions(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 05e8986ba5..6e17495925 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -102,26 +102,20 @@ static void nr_dlsch_layer_demapping(int16_t *llr_cw[2], int16_t llr_layers[][sz]); /* compute LLR */ -static int nr_dlsch_llr(uint32_t rx_size_symbol, - int nbRx, - uint sz, - int16_t layer_llr[][sz], - NR_DL_FRAME_PARMS *frame_parms, - int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], - int32_t dl_ch_mag[rx_size_symbol], - int32_t dl_ch_magb[rx_size_symbol], - int32_t dl_ch_magr[rx_size_symbol], - NR_DL_UE_HARQ_t *dlsch0_harq, - NR_DL_UE_HARQ_t *dlsch1_harq, - unsigned char harq_pid, - unsigned char first_symbol_flag, - unsigned char symbol, - int32_t codeword_TB0, - int32_t codeword_TB1, - uint32_t len, - uint8_t nr_slot_rx, - NR_UE_DLSCH_t dlsch[2], - uint32_t llr_offset[NR_SYMBOLS_PER_SLOT]); +static void nr_dlsch_llr(uint32_t rx_size_symbol, + int nbRx, + uint sz, + int16_t layer_llr[][sz], + int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], + int32_t dl_ch_mag[rx_size_symbol], + int32_t dl_ch_magb[rx_size_symbol], + int32_t dl_ch_magr[rx_size_symbol], + NR_DL_UE_HARQ_t *dlsch0_harq, + NR_DL_UE_HARQ_t *dlsch1_harq, + unsigned char symbol, + uint32_t len, + NR_UE_DLSCH_t dlsch[2], + uint32_t llr_offset_symbol); /** \fn nr_dlsch_extract_rbs \brief This function extracts the received resource blocks, both channel estimates and data symbols, for the current @@ -626,7 +620,7 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, /* Store the valid DL RE's */ - dl_valid_re[symbol-1] = nb_re_pdsch; + dl_valid_re[symbol] = nb_re_pdsch; int startSymbIdx = 0; int nbSymb = 0; int pduBitmap = 0; @@ -654,10 +648,10 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, (nb_rb_pdsch * 12), dlsch[0].rnti, dlsch); - dl_valid_re[symbol - 1] -= ptrs_re_per_slot[0][symbol]; + dl_valid_re[symbol] -= ptrs_re_per_slot[0][symbol]; } /* at last symbol in a slot calculate LLR's for whole slot */ - if(symbol == (startSymbIdx + nbSymb -1)) { + if(symbol == (startSymbIdx + nbSymb - 1)) { const uint32_t rx_llr_layer_size = (G + dlsch[0].Nl - 1) / dlsch[0].Nl; if (dlsch[0].Nl == 0 || rx_llr_layer_size == 0 || rx_llr_layer_size > 10 * 1000 * 1000) { @@ -666,41 +660,32 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, } int16_t layer_llr[dlsch[0].Nl][rx_llr_layer_size]; - for(int i = startSymbIdx; i < startSymbIdx+nbSymb; i++) { - /* re evaluating the first symbol flag as LLR's are done in symbol loop */ - if(i == startSymbIdx && i < 3) - first_symbol_flag = 1; - else - first_symbol_flag = 0; + for(int i = startSymbIdx; i < startSymbIdx + nbSymb; i++) { /* Calculate LLR's for each symbol */ start_meas_nr_ue_phy(ue, DLSCH_LLR_STATS); nr_dlsch_llr(rx_size_symbol, nbRx, rx_llr_layer_size, layer_llr, - frame_parms, rxdataF_comp, dl_ch_mag[0][0], dl_ch_magb[0][0], dl_ch_magr[0][0], dlsch0_harq, dlsch1_harq, - harq_pid, - first_symbol_flag, i, - codeword_TB0, - codeword_TB1, - dl_valid_re[i - 1], - nr_slot_rx, + dl_valid_re[i], dlsch, - llr_offset); + llr_offset[i]); + if (i < startSymbIdx + nbSymb - 1) // up to the penultimate symbol + llr_offset[i + 1] = dl_valid_re[i] * dlsch_config->qamModOrder + llr_offset[i]; stop_meas_nr_ue_phy(ue, DLSCH_LLR_STATS); } start_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING); nr_dlsch_layer_demapping(llr, dlsch[0].Nl, - dlsch[0].dlsch_config.qamModOrder, + dlsch_config->qamModOrder, G, codeword_TB0, codeword_TB1, @@ -1868,33 +1853,21 @@ static void nr_dlsch_layer_demapping(int16_t *llr_cw[2], } } -static int nr_dlsch_llr(uint32_t rx_size_symbol, - int nbRx, - uint sz, - int16_t layer_llr[][sz], - NR_DL_FRAME_PARMS *frame_parms, - int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], - int32_t dl_ch_mag[rx_size_symbol], - int32_t dl_ch_magb[rx_size_symbol], - int32_t dl_ch_magr[rx_size_symbol], - NR_DL_UE_HARQ_t *dlsch0_harq, - NR_DL_UE_HARQ_t *dlsch1_harq, - unsigned char harq_pid, - unsigned char first_symbol_flag, - unsigned char symbol, - int32_t codeword_TB0, - int32_t codeword_TB1, - uint32_t len, - uint8_t nr_slot_rx, - NR_UE_DLSCH_t dlsch[2], - uint32_t llr_offset[14]) +static void nr_dlsch_llr(uint32_t rx_size_symbol, + int nbRx, + uint sz, + int16_t layer_llr[][sz], + int32_t rxdataF_comp[][nbRx][rx_size_symbol * NR_SYMBOLS_PER_SLOT], + int32_t dl_ch_mag[rx_size_symbol], + int32_t dl_ch_magb[rx_size_symbol], + int32_t dl_ch_magr[rx_size_symbol], + NR_DL_UE_HARQ_t *dlsch0_harq, + NR_DL_UE_HARQ_t *dlsch1_harq, + unsigned char symbol, + uint32_t len, + NR_UE_DLSCH_t dlsch[2], + uint32_t llr_offset_symbol) { - if (first_symbol_flag == 1) - llr_offset[symbol - 1] = 0; - uint32_t llr_offset_symbol = llr_offset[symbol - 1]; - - llr_offset[symbol] = len * dlsch[0].dlsch_config.qamModOrder + llr_offset_symbol; - switch (dlsch[0].dlsch_config.qamModOrder) { case 2 : for(int l = 0; l < dlsch[0].Nl; l++) @@ -1917,8 +1890,7 @@ static int nr_dlsch_llr(uint32_t rx_size_symbol, break; default: - LOG_W(PHY,"rx_dlsch.c : Unknown mod_order!!!!\n"); - return(-1); + AssertFatal(false, "Unknown mod_order!!!!\n"); break; } @@ -1942,11 +1914,9 @@ static int nr_dlsch_llr(uint32_t rx_size_symbol, break; default: - LOG_W(PHY,"rx_dlsch.c : Unknown mod_order!!!!\n"); - return(-1); + AssertFatal(false, "Unknown mod_order!!!!\n"); break; } } - return 0; } //============================================================================================== From 01ec929ddb7564fe672f391854cdc2d84218d546 Mon Sep 17 00:00:00 2001 From: arora Date: Mon, 2 Sep 2024 18:17:04 +0200 Subject: [PATCH 15/61] Removing rhsm certificates, not needed. --- ci-scripts/cls_containerize.py | 3 --- openshift/README.md | 2 -- openshift/oai-gnb-fhi72-bc.yaml | 7 ------- openshift/ran-base-bc.yaml | 7 ------- 4 files changed, 19 deletions(-) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 94d7526813..ca7ca2608f 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -335,9 +335,6 @@ class Containerize(): # if asterix, copy the entitlement and subscription manager configurations if self.host == 'Red Hat': - cmd.run('mkdir -p ./etc-pki-entitlement ./rhsm-conf ./rhsm-ca') - cmd.run('cp /etc/rhsm/rhsm.conf ./rhsm-conf/') - cmd.run('cp /etc/rhsm/ca/redhat-uep.pem ./rhsm-ca/') cmd.run('cp /etc/pki/entitlement/*.pem ./etc-pki-entitlement/') baseImage = 'ran-base' diff --git a/openshift/README.md b/openshift/README.md index 5560621e68..e5a2b00bdd 100644 --- a/openshift/README.md +++ b/openshift/README.md @@ -53,8 +53,6 @@ In case you have difficulties in following it then you can copy the certificates from an RHEL9 host ```bash -oc create configmap rhsm-conf --from-file /etc/rhsm/rhsm.conf -oc create configmap rhsm-ca --from-file /etc/rhsm/ca/redhat-uep.pem oc create secret generic etc-pki-entitlement --from-file /etc/pki/entitlement/{NUMBER_ON_YOUR_COMPUTER}.pem --from-file /etc/pki/entitlement/{NUMBER_ON_YOUR_COMPUTER}-key.pem ``` diff --git a/openshift/oai-gnb-fhi72-bc.yaml b/openshift/oai-gnb-fhi72-bc.yaml index 2d8861e2d6..0e453ae379 100644 --- a/openshift/oai-gnb-fhi72-bc.yaml +++ b/openshift/oai-gnb-fhi72-bc.yaml @@ -32,13 +32,6 @@ spec: - secret: name: etc-pki-entitlement destinationDir: etc-pki-entitlement - configMaps: - - configMap: - name: rhsm-conf - destinationDir: rhsm-conf - - configMap: - name: rhsm-ca - destinationDir: rhsm-ca strategy: dockerStrategy: dockerfilePath: "docker/Dockerfile.gNB.fhi72.rhel9" diff --git a/openshift/ran-base-bc.yaml b/openshift/ran-base-bc.yaml index 788e980fef..5707e64abb 100644 --- a/openshift/ran-base-bc.yaml +++ b/openshift/ran-base-bc.yaml @@ -34,13 +34,6 @@ spec: - secret: name: etc-pki-entitlement destinationDir: etc-pki-entitlement - configMaps: - - configMap: - name: rhsm-conf - destinationDir: rhsm-conf - - configMap: - name: rhsm-ca - destinationDir: rhsm-ca strategy: dockerStrategy: dockerfilePath: "docker/Dockerfile.base.rhel9" From 9102e10747ba224de7c9cb739ddd75abe0163a81 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 1 Aug 2024 14:13:17 +0200 Subject: [PATCH 16/61] Updated F1-design.md * restructured the documentation * add details from specs * add tables and Mermaid diagrams whenever possible --- doc/F1-design.md | 174 ++++++++++++++++++++++++++++++++------------- doc/FEATURE_SET.md | 18 +++-- 2 files changed, 136 insertions(+), 56 deletions(-) diff --git a/doc/F1-design.md b/doc/F1-design.md index 22781650f1..4690639d5b 100644 --- a/doc/F1-design.md +++ b/doc/F1-design.md @@ -18,38 +18,58 @@ The F1 interface is the functional split of 3GPP between the CU (centralized unit: PDCP, RRC, SDAP) and the DU (distributed unit: RLC, MAC, PHY). It is -standardized in TS 38.470 - 38.473 for 5G NR. No equivalent for 4G exists. +standardized in TS 38.470 - 38.473 for 5G NR. -We assume that each DU handles only one cell. Multiple DUs connected to one CU -are supported. Mobility over F1 is not yet supported. +F1 specs: +* 3GPP TS 38.470 F1 general aspects and principles +* 3GPP TS 38.471 F1 layer 1 -# Control plane status (F1-C) +F1-C: +* 3GPP TS 38.472 F1 signalling transport +* 3GPP TS 38.473 F1 Application Protocol (F1AP) -## Implementation Status +F1-U: +* 3GPP TS 38.474 F1 Data Transport -Note that OAI uses F1 "internally". That means, that even **if you run a -monolithic gNB, the internal information exchange uses F1**. You can therefore -expect that everything working in a monolithic deployment should also work in -F1. The current implementation is based on R16.3. +No equivalent for 4G exists. -Note that NSA does NOT follow this logic yet, and does not work with F1. +## Control plane (F1-C) -The following messages are currently implemented: +The interface F1-C is designed for the exchange of signalling messages between the +Radio Network Layer (RNL) and the Transport Network Layer (TNL). It +consists of F1 Application Protocol messages (F1-AP) exchanged over SCTP. -- F1 Setup Request and F1 Setup Response/Failure -- Initial UL RRC, UL/DL RRC Message Transfer -- F1 UE Context management messages for the "good case" - * Setup Request/Response - * Modification Request/Response - * Release Request/Command/Complete +## Data plane (F1-U) -All other messages are not implemented or not working reliably: +F1-U uses GTP-U for information exchange. -- F1 CU/DU configuration updade -- Paging messages -- Warning Message transmissions +# OAI Implementation Status -## High-level F1-C code structure +The implementation of F1AP messages is seamlessly integrated into OAI, supporting both Monolithic SA +and CU/DU functional split modes. The F1 code is therefore always compiled with nr-softmodem. +This architecture ensures that even *when operating a monolithic gNB, internal information exchange +always utilizes F1AP messages*. +The major difference lies in the CU/DU split scenario, where ASN.1-encoded F1AP messages (F1-C) are +exchanges over SCTP, via a socket interface. + +This is the current status: + +- gNB-CU/gNB-DU split +- Supported deployments: + * SA + * Single cell per DU + * Multiple DUs connected to one CU (both CP and UP) +- Not supported: + * Mobility + * NSA + +## F1-C + +### F1AP messages + +Refer to [FEATURE_SET.md](FEATURE_SET.md#gNB-F1AP) to learn about the current F1AP implementation status. + +### High-level F1-C code structure The F1 interface is used internally between CU (mostly RRC) and DU (mostly MAC) to exchange information. In DL, the CU sends messages as defined by the @@ -69,38 +89,94 @@ dedicated handler). In F1, the DU task receives the ITTI message, encodes using ASN.1, and sends it over a network socket. The CU task decodes, and sends the same ITTI message to the RRC task as done directly in the monolithic case. +Summary of callbacks and handlers: + +| Entity | Callback definition | Callback F1 Implementation | Callback Monolithic SA Implementation | Handler | +|--------|---------------------|----------------------------|---------------------------------------|----------------------| +| CU/RRC | `mac_rrc_dl.h` | `mac_rrc_dl_f1ap.c` | `mac_rrc_dl_direct.c` |No handler (use ITTI) | +| DU/MAC | `mac_rrc_ul.h` | `mac_rrc_ul_f1ap.c` | `mac_rrc_ul_direct.c` |`mac_rrc_dl_handler.c`| + +A sequence diagram for downlink F1AP messages over the OAI CU/DU functional split: + +```mermaid +sequenceDiagram + box rgba(17,158,189,255) CU/RRC + participant TASK_RRC_GNB + participant TASK_CU_F1 + end + Note over TASK_RRC_GNB: MAC/RRC callback + TASK_RRC_GNB->>+TASK_CU_F1: F1AP message (ITTI) + Note over TASK_CU_F1: F1 message encoding + Note over TASK_CU_F1: ASN.1 encoding + box Grey DU/MAC + participant TASK_DU_F1 + participant MAC + end + Note over TASK_DU_F1: F1AP DL message handler + TASK_CU_F1->>+TASK_DU_F1: SCTP (ITTI) + Note over TASK_DU_F1: F1 message decoding + Note over TASK_DU_F1: ASN.1 decoding + TASK_DU_F1->>+MAC: F1AP message (function call) + Note over MAC: MAC DL message handler ``` - +-------------+ - | | - | CU/RRC | - | | - +-------------+ - | ^ - Callback def: mac_rrc_dl.h | | No handler needed: - F1 impl: mac_rrc_dl_f1ap.c | | RRC has ITTI -Monolithic: mac_rrc_dl_direct.c | | - | | - DL | | UL - | | - | | Callback def: mac_rrc_ul.h - Message handler: | | F1 impl: mac_rrc_ul_f1ap.c - mac_rrc_dl_handler.c | | Monolithic: mac_rrc_ul_direct.c - v | - +-------------+ - | | - | DU/MAC | - | | - +-------------+ +and for the uplink F1AP messages: + +```mermaid +sequenceDiagram + box rgba(17,158,189,255) CU/RRC + participant TASK_RRC_GNB + participant TASK_CU_F1 + end + box Grey DU/MAC + participant TASK_DU_F1 + participant TASK_MAC_GNB + end + Note over TASK_MAC_GNB: MAC/RRC callback + TASK_MAC_GNB->>+TASK_DU_F1: F1AP message (ITTI) + Note over TASK_DU_F1: F1 message encoding + Note over TASK_DU_F1: ASN.1 encoding + Note over TASK_CU_F1: F1AP UL message handler + TASK_DU_F1->>+TASK_CU_F1: SCTP (ITTI) + Note over TASK_CU_F1: F1 message decoding + Note over TASK_CU_F1: ASN.1 decoding + TASK_CU_F1->>+TASK_RRC_GNB: F1AP message (ITTI) ``` -# Data plane status (F1-U) +Alternative sequence handling (e.g. Monolithic), for downlink: -F1-U uses GTP-U for information exchange. The GTP protocol uses some extensions -for NR-U protocol to report buffer status, but this is not properly tested and -might malfunction. One limitation is that the current implementation -acknowledges each packet individually. +```mermaid +sequenceDiagram + box rgba(17,158,189,255) RRC + participant TASK_RRC_GNB + end + Note over TASK_RRC_GNB: mac_rrc_dl_direct.c callback + box Grey MAC + participant TASK_MAC_GNB + end + TASK_RRC_GNB->>+TASK_MAC_GNB: raw F1AP message + Note over TASK_MAC_GNB: mac_rrc_dl_handler.c +``` +and for the uplink: -Multiple DUs at one CU are supported in the data plane (as in the control plane). +```mermaid +sequenceDiagram + box rgba(17,158,189,255) RRC + participant TASK_RRC_GNB + end + box Grey MAC + participant TASK_MAC_GNB + end + Note over TASK_MAC_GNB: mac_rrc_ul_direct.c callback + TASK_MAC_GNB->>+TASK_RRC_GNB: raw F1AP message (ITTI) +``` + +## F1-U + +Current status: + +* Buffer status report over GTP-U +* Each packet is acknowledged individually +* Support of multiple DUs per CU # How to run diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md index 17d3f3b801..5469687ade 100644 --- a/doc/FEATURE_SET.md +++ b/doc/FEATURE_SET.md @@ -197,13 +197,17 @@ These modes of operation are supported: ## gNB F1AP - Integration of F1AP messages and procedures for the control plane exchanges between the CU and DU entities according to 38.473 Rel. 16 - - F1 Setup request/response/failure - - F1 DL/UL RRC message transfer - - F1 Initial UL RRC message transfer - - F1 UE Context setup request/response - - F1 UE Context modification request/response - - F1 UE Context modification required - - F1 UE Context release req/cmd/complete + - F1 Interface Management: + * F1 Setup request/response/failure + - F1 RRC Message Transfer: + * F1 Initial UL RRC Message Transfer + * F1 DL RRC Message Transfer + * F1 UL RRC Message Transfer + - F1 UE Context Management: + * F1 UE Context setup request/response + * F1 UE Context modification request/response + * F1 UE Context modification required + * F1 UE Context release req/cmd/complete - F1 gNB CU configuration update - F1 Reset (handled at DU only, full reset only) - Interface with RRC From 5764422342c42b94485032d03b30ff88e6367d98 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 16 Aug 2024 16:44:59 +0200 Subject: [PATCH 17/61] Section about connecting to an NG-Core in NR_SA_Tutorial_OAI_nrUE.md --- doc/NR_SA_Tutorial_OAI_nrUE.md | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/doc/NR_SA_Tutorial_OAI_nrUE.md b/doc/NR_SA_Tutorial_OAI_nrUE.md index 8c1b0afaf1..043820d11b 100644 --- a/doc/NR_SA_Tutorial_OAI_nrUE.md +++ b/doc/NR_SA_Tutorial_OAI_nrUE.md @@ -159,6 +159,41 @@ cd ~/openairinterface5g/cmake_targets/ran_build/build sudo ./nr-uesoftmodem -r 32 --numerology 3 --band 257 -C 27533280000 --sa --uicc0.imsi 001010000000001 --ssb 72 --rfsim ``` +### Connection to an NG-Core + +A configuration file can be fed to the nrUE command line in order to connect to the local NGC. + +The nrUE configuration file (e.g. [ue.conf](../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf)) is structured in a key-value format and contains the relevant UICC parameters that are necessary to authenticate the UE to the local 5GC. E.g.: + +```shell +uicc0 = { + imsi = "001010000000001"; + key = "fec86ba6eb707ed08905757b1bb44b8f"; + opc = "C42449363BBAD02B66D16BC975D77CC1"; + dnn = "oai"; + nssai_sst = 1; +} +``` + +| **Parameter** | **Description** | **Default Value** | +|---------------|-----------------|-------------------| +| **IMSI** | Unique identifier for the UE within the mobile network. Used by the network to identify the UE during authentication. It ensures that the UE is correctly identified by the network. | 001010000000001 | +| **key** | Cryptographic key shared between the UE and the network, used for encryption during the authentication process. | `fec86ba6eb707ed08905757b1bb44b8f` | +| **OPC** | Operator key for the Milenage Authentication and Key Agreement algorithm used for encryption during the authentication process. | Ensures secure communication between the UE and the network by matching the encryption keys. | `C42449363BBAD02B66D16BC975D77CC1` | +| **DNN** | Specifies the name of the data network the UE wishes to connect to, similar to an APN in 4G networks. | `oai` | +| **NSSAI** | Allows the UE to select the appropriate network slice, which provides different QoS. | `1` | + +The UE configuration must match the one of the network's AMF. The nrUE can connect by default to OAI CN5G with no need to provide the configuration file. + +When running the `nr-uesoftmodem`, one can specify the nrUE configuration file using the `-O` option. E.g.: + +```bash +sudo ./nr-uesoftmodem --rfsim --rfsimulator.serveraddr 127.0.0.1 --sa -r 106 --numerology 1 --band 78 -C 3619200000 -O ~/nrue.uicc.conf +``` +The CL option `--uicc0.imsi` can override the IMSI value in the configuration file if necessary (e.g. when running multiple UEs): `--uicc0.imsi 001010000000001`. + +More details available at [ci-scripts/yaml_files/5g_rfsimulator/README.md](../ci-scripts/yaml_files/5g_rfsimulator/README.md). + ## 5.2 End-to-end connectivity test - Ping test from the UE host to the CN5G ```bash From dbe5c5ee61047a56a10496e2f74a4dc501a779ef Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 16 Aug 2024 17:01:52 +0200 Subject: [PATCH 18/61] Minor additions to UnitTests.md --- doc/UnitTests.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/UnitTests.md b/doc/UnitTests.md index d1bbbed0ae..b9dc1194ff 100644 --- a/doc/UnitTests.md +++ b/doc/UnitTests.md @@ -25,7 +25,8 @@ ninja tests ``` Then, you can run `ctest` to run all tests: -``` + +```bash $ ctest Test project /home/richie/w/ctest/build Start 1: nr_rlc_tests @@ -36,6 +37,8 @@ Test project /home/richie/w/ctest/build Total Test time (real) = 0.06 sec ``` +The user can see all available tests by typing `ctest -N` and then run a specific with `ctest -R `, e.g. `ctest -R nr_rlc_tests`. + A couple of interesting variables are `--verbose`, `--output-on-failure`. # How to add a new test @@ -59,7 +62,8 @@ process is In the simplest case, in an existing `CMakeLists.txt`, you might add the following: -``` + +```bash if(ENABLE_TESTS) add_executable(my_test mytest.c) add_dependencies(tests my_test) From 419a14a8138210b325ba6f771210ffb2ebc2951e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 24 Jul 2024 14:32:23 +0200 Subject: [PATCH 19/61] Demote log message of ITTI thread creation --- common/utils/ocp_itti/intertask_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp index 9d22e06d7d..b59de2e0fc 100644 --- a/common/utils/ocp_itti/intertask_interface.cpp +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -320,7 +320,7 @@ typedef struct timer_elm_s { (char *)itti_get_task_name(task_id), -1, OAI_PRIORITY_RT); - LOG_I(ITTI,"Created Posix thread %s\n", itti_get_task_name(task_id) ); + LOG_D(ITTI,"Created Posix thread %s\n", itti_get_task_name(task_id) ); return 0; } From bdc6df8c42a133b93d2d3dea1faf9e3b8e9fe5c1 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 15 Jul 2024 06:36:42 +0200 Subject: [PATCH 20/61] NR UE & gNB imscope. A new phy scope based on ImGui and ImPlot. This scope uses a different concurrency model than previous scopes. The PHY thread writing the data first checks if the data is ready to be written. If its not, nothing is copied. The GUI thread reads data if available and marks it ready to write. This makes sure that the PHY threads are not busy copying data that would never be displayed. Some of the scopes also have a freeze functionality that further limit the amount of data that needs to be copied from PHY threads. If a scope is "frozen" it still allows the user to explore the data using plots zoom/pan functions but doesn't cause PHY threads to perform extra writes on the displayed data. A compile option was added to enable/disable the scope. Use cmake -DENABLE_IMSCOPE=ON to enable the scope. Update CXX standard to 17; it is required by some libraries (e.g., dear imgui). The oldest gcc version in use by a distribution supported is Ubuntu 20, which has gcc 9.4 with c++17 support. --- CMakeLists.txt | 35 +- cmake_targets/CPM.cmake | 24 + common/utils/nr/nr_common.h | 3 + doc/BUILD.md | 2 + doc/README.md | 2 +- executables/nr-softmodem.c | 16 +- executables/nr-uesoftmodem.c | 8 +- openair1/PHY/INIT/nr_init.c | 2 +- .../PHY/NR_TRANSPORT/nr_ulsch_demodulation.c | 27 +- openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c | 5 +- openair1/PHY/TOOLS/CMakeLists.txt | 4 + openair1/PHY/TOOLS/imscope/CMakeLists.txt | 34 + openair1/PHY/TOOLS/imscope/imscope.cpp | 841 ++++++++++++++++++ .../PHY/TOOLS/imscope/imscope_screenshot.png | Bin 0 -> 23323 bytes openair1/PHY/TOOLS/phy_scope_interface.c | 2 +- openair1/PHY/TOOLS/phy_scope_interface.h | 53 +- openair1/PHY/TOOLS/readme.md | 38 + 17 files changed, 1056 insertions(+), 40 deletions(-) create mode 100644 cmake_targets/CPM.cmake create mode 100644 openair1/PHY/TOOLS/imscope/CMakeLists.txt create mode 100644 openair1/PHY/TOOLS/imscope/imscope.cpp create mode 100644 openair1/PHY/TOOLS/imscope/imscope_screenshot.png diff --git a/CMakeLists.txt b/CMakeLists.txt index faa3d9dc35..b30565bcf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ cmake_minimum_required (VERSION 3.16) project (OpenAirInterface LANGUAGES C CXX) +set(CMAKE_CXX_STANDARD 17) ######################################################### # Base directories, compatible with legacy OAI building # @@ -30,6 +31,10 @@ project (OpenAirInterface LANGUAGES C CXX) set (OPENAIR_DIR ${CMAKE_SOURCE_DIR}) include("cmake_targets/macros.cmake") +if(NOT DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_SOURCE_CACHE ~/.cache/cpm/) +endif() +include("cmake_targets/CPM.cmake") ############################## ### CCache: reduce compilation time @@ -288,6 +293,8 @@ set_property(CACHE KPM_VERSION PROPERTY STRINGS "KPM_V2_03" "KPM_V3_00") message(STATUS "Selected KPM Version: ${KPM_VERSION}") +add_boolean_option(ENABLE_IMSCOPE OFF "Enable phy scope based on imgui" ON) + ################################################## # ASN.1 grammar C code generation & dependencies # ################################################## @@ -2340,30 +2347,24 @@ if(ENABLE_TESTS) find_package(GTest) if (NOT GTest_FOUND) message(STATUS "GTest package not found, will download googletest automatically. To prevent that install google test on your system (libgtest-dev)") - include(FetchContent) - FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG 58d77fa8070e8cec2dc1ed015d66b454c8d78850 # 1.12.1 + CPMAddPackage( + NAME googletest + GITHUB_REPOSITORY google/googletest + GIT_TAG release-1.12.1 + VERSION 1.12.1 + OPTIONS "INSTALL_GTEST OFF" "gtest_force_shared_crt" "BUILD_GMOCK OFF" ) - set(BUILD_GMOCK OFF) - set(INSTALL_GTEST OFF) - FetchContent_MakeAvailable(googletest) - add_library(GTest::gtest ALIAS gtest) - add_library(GTest::gtest_main ALIAS gtest_main) endif() find_package(benchmark) if (NOT benchmark_FOUND) message(STATUS "benchmark package not found, will download benchmark automatically. To prevent that install google benchmark on your system (libbenchmark-dev)") - include(FetchContent) - set(BENCHMARK_ENABLE_TESTING OFF) - FetchContent_Declare( - benchmark - GIT_REPOSITORY https://github.com/google/benchmark.git - GIT_TAG v1.9.0 + CPMAddPackage( + NAME benchmark + GITHUB_REPOSITORY google/benchmark + VERSION 1.9.0 + OPTIONS "BENCHMARK_ENABLE_TESTING OFF" ) - FetchContent_MakeAvailable(benchmark) endif() endif() diff --git a/cmake_targets/CPM.cmake b/cmake_targets/CPM.cmake new file mode 100644 index 0000000000..20013e1870 --- /dev/null +++ b/cmake_targets/CPM.cmake @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: MIT +# +# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors + +set(CPM_DOWNLOAD_VERSION 0.40.1) +set(CPM_HASH_SUM "117cbf2711572f113bab262933eb5187b08cfc06dce0714a1ee94f2183ddc3ec") + +if(CPM_SOURCE_CACHE) + set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +elseif(DEFINED ENV{CPM_SOURCE_CACHE}) + set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +else() + set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") +endif() + +# Expand relative path. This is important if the provided path contains a tilde (~) +get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) + +file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake + ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} +) + +include(${CPM_DOWNLOAD_LOCATION}) diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index fcefa29461..cafeebb632 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -254,6 +254,9 @@ int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_ #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) +// Align up to a multiple of 16 +#define ALIGN_UP_16(a) ((a + 15) & ~15) + #ifdef __cplusplus #ifdef min #undef min diff --git a/doc/BUILD.md b/doc/BUILD.md index 3e06e79d01..dc5b1361f2 100644 --- a/doc/BUILD.md +++ b/doc/BUILD.md @@ -42,6 +42,8 @@ Running the [build_oai](../cmake_targets/build_oai) script also generates some The build system for OAI uses [cmake](https://cmake.org/) which is a tool to generate makefiles. The `build_oai` script is a wrapper using `cmake` and `make`/`ninja` to ease the oai build and use. It logs the `cmake` and `ninja`/`make` commands it executes. The file describing how to build the executables from source files is the [CMakeLists.txt](../CMakeLists.txt), it is used as input by cmake to generate the makefiles. +cmake is further extended by using [CPM](https://github.com/cpm-cmake/CPM.cmake). CPM is a cmake script that handles external code dependencies. It is setup to cache downloaded code in `~/.cache/cpm`. While most external dependencies should be handled by system package managers, CPM has the advantage of using any code that is available in a public git repository. + The oai softmodem supports many use cases, and new ones are regularly added. Most of them are accessible using the configuration file or the command line options and continuous effort is done to avoid introducing build options as it makes tests and usage more complicated than run-time options. The following functionalities, originally requiring a specific build are now accessible by configuration or command line options: - s1, noS1 diff --git a/doc/README.md b/doc/README.md index 636c30d26b..4b05242e59 100644 --- a/doc/README.md +++ b/doc/README.md @@ -106,7 +106,7 @@ The other SDRs (AW2S, LimeSDR, ...) have no READMEs. ## Special-purpose libraries -- OAI has a scope based on Xforms, described in [this README](../openair1/PHY/TOOLS/readme.md) +- OAI has two scopes: one based on Xforms and one based on imgui, described in [this README](../openair1/PHY/TOOLS/readme.md) - OAI comes with an integrated [telnet server](../common/utils/telnetsrv/DOC/telnethelp.md) to monitor and control - OAI comes with an integrated [web server](../common/utils/websrv/DOC/websrv.md) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 6f49537b3a..803c7bbdcd 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -734,14 +734,18 @@ int main( int argc, char **argv ) { printf("ALL RUs ready - init gNBs\n"); for (int idx=0;idxif_inst->sl_ahead = sl_ahead; - if(IS_SOFTMODEM_DOSCOPE) { + if (IS_SOFTMODEM_DOSCOPE) { sleep(1); scopeParms_t p; - p.argc=&argc; - p.argv=argv; - p.gNB=RC.gNB[0]; - p.ru=RC.ru[0]; - load_softscope("nr",&p); + p.argc = &argc; + p.argv = argv; + p.gNB = RC.gNB[0]; + p.ru = RC.ru[0]; +#ifndef ENABLE_IMSCOPE + load_softscope("nr", &p); +#else + load_softscope("im", &p); +#endif } if (NFAPI_MODE != NFAPI_MODE_PNF && NFAPI_MODE != NFAPI_MODE_VNF && NFAPI_MODE != NFAPI_MODE_AERIAL) { diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 5049e269d2..3550a0a9ff 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -521,8 +521,12 @@ int main(int argc, char **argv) init_openair0(); lock_memory_to_ram(); - if(IS_SOFTMODEM_DOSCOPE) { - load_softscope("nr",PHY_vars_UE_g[0][0]); + if (IS_SOFTMODEM_DOSCOPE) { +#ifndef ENABLE_IMSCOPE + load_softscope("nr", PHY_vars_UE_g[0][0]); +#else + load_softscope("im", PHY_vars_UE_g[0][0]); +#endif } for (int inst = 0; inst < NB_UE_INST; inst++) { diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index d47eec2278..68333c821c 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -199,7 +199,7 @@ int phy_init_nr_gNB(PHY_VARS_gNB *gNB) int n_buf = Prx*max_ul_mimo_layers; int nb_re_pusch = N_RB_UL * NR_NB_SC_PER_RB; - int nb_re_pusch2 = (nb_re_pusch + 15) & ~15; + int nb_re_pusch2 = ALIGN_UP_16(nb_re_pusch); gNB->pusch_vars = (NR_gNB_PUSCH *)malloc16_clear(gNB->max_nb_pusch * sizeof(NR_gNB_PUSCH)); for (int ULSCH_id = 0; ULSCH_id < gNB->max_nb_pusch; ULSCH_id++) { diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c index 75ee35385f..4640ff0746 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch_demodulation.c @@ -1263,7 +1263,7 @@ static void inner_rx(PHY_VARS_gNB *gNB, int nb_layer = rel15_ul->nrOfLayers; int nb_rx_ant = frame_parms->nb_antennas_rx; int dmrs_symbol_flag = (rel15_ul->ul_dmrs_symb_pos >> symbol) & 0x01; - int buffer_length = (rel15_ul->rb_size * NR_NB_SC_PER_RB + 15) & ~15; + int buffer_length = ALIGN_UP_16(rel15_ul->rb_size * NR_NB_SC_PER_RB); c16_t rxFext[nb_rx_ant][buffer_length] __attribute__((aligned(32))); c16_t chFext[nb_layer][nb_rx_ant][buffer_length] __attribute__((aligned(32))); @@ -1631,7 +1631,7 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, // extract the data in the OFDM frame, to the start of the array int soffset = (slot % RU_RX_SLOT_DEPTH) * frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size; - nb_re_pusch = (nb_re_pusch + 15) & ~15; + nb_re_pusch = ALIGN_UP_16(nb_re_pusch); int dmrs_symbol; if (gNB->chest_time == 0) dmrs_symbol = get_valid_dmrs_idx_for_channel_est(rel15_ul->ul_dmrs_symb_pos, meas_symbol); @@ -1699,8 +1699,8 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, start_meas(&gNB->rx_pusch_symbol_processing_stats); int numSymbols = gNB->num_pusch_symbols_per_thread; + int total_res = 0; for(uint8_t symbol = rel15_ul->start_symbol_index; symbol < end_symbol; symbol += numSymbols) { - int total_res = 0; for (int s = 0; s < numSymbols; s++) { pusch_vars->ul_valid_re_per_slot[symbol+s] = get_nb_re_pusch(frame_parms,rel15_ul,symbol+s); pusch_vars->llr_offset[symbol+s] = ((symbol+s) == rel15_ul->start_symbol_index) ? @@ -1744,5 +1744,26 @@ int nr_rx_pusch_tp(PHY_VARS_gNB *gNB, } stop_meas(&gNB->rx_pusch_symbol_processing_stats); + + // Copy the data to the scope. This cannot be performed in one call to gNBscopeCopy because the data is not contiguous in the + // buffer due to reference symbol extraction and padding. The gNBscopeCopy call is broken up into steps: trylock, copy, unlock. + metadata mt = {.slot = slot, .frame = frame}; + if (gNBTryLockScopeData(gNB, gNBPuschRxIq, sizeof(c16_t), 1, total_res, &mt)) { + int buffer_length = ALIGN_UP_16(rel15_ul->rb_size * NR_NB_SC_PER_RB); + size_t offset = 0; + for (uint8_t symbol = rel15_ul->start_symbol_index; symbol < (rel15_ul->start_symbol_index + rel15_ul->nr_of_symbols); + symbol++) { + gNBscopeCopyUnsafe(gNB, + gNBPuschRxIq, + &pusch_vars->rxdataF_comp[0][symbol * buffer_length], + sizeof(c16_t) * pusch_vars->ul_valid_re_per_slot[symbol], + offset, + symbol - rel15_ul->start_symbol_index); + offset += sizeof(c16_t) * pusch_vars->ul_valid_re_per_slot[symbol]; + } + gNBunlockScopeData(gNB, gNBPuschRxIq) + } + uint32_t total_llrs = total_res * rel15_ul->qam_mod_order * rel15_ul->nrOfLayers; + gNBscopeCopyWithMetadata(gNB, gNBPuschLlr, pusch_vars->llr, sizeof(c16_t), 1, total_llrs, 0, &mt); return 0; } diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c index d09978728a..82819551e4 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_pbch.c @@ -442,8 +442,9 @@ int nr_rx_pbch(PHY_VARS_NR_UE *ue, // legacy code use int16, but it is complex16 if (ue) { - UEscopeCopy(ue, pbchRxdataF_comp, pbch_unClipped, sizeof(struct complex16), frame_parms->nb_antennas_rx, pbch_e_rx_idx / 2, 0); - UEscopeCopy(ue, pbchLlr, pbch_e_rx, sizeof(int16_t), frame_parms->nb_antennas_rx, pbch_e_rx_idx, 0); + metadata meta = {.slot = proc->nr_slot_rx, .frame = proc->frame_rx}; + UEscopeCopyWithMetadata(ue, pbchRxdataF_comp, pbch_unClipped, sizeof(struct complex16), frame_parms->nb_antennas_rx, pbch_e_rx_idx / 2, 0, &meta); + UEscopeCopyWithMetadata(ue, pbchLlr, pbch_e_rx, sizeof(int16_t), frame_parms->nb_antennas_rx, pbch_e_rx_idx, 0, &meta); } #ifdef DEBUG_PBCH for (int cnt = 0; cnt < 864 ; cnt++) diff --git a/openair1/PHY/TOOLS/CMakeLists.txt b/openair1/PHY/TOOLS/CMakeLists.txt index 93ef4f5cc7..ada3d8c863 100644 --- a/openair1/PHY/TOOLS/CMakeLists.txt +++ b/openair1/PHY/TOOLS/CMakeLists.txt @@ -63,3 +63,7 @@ endif() if (ENABLE_TESTS) add_subdirectory(tests) endif() + +if (ENABLE_IMSCOPE) + add_subdirectory(imscope) +endif() diff --git a/openair1/PHY/TOOLS/imscope/CMakeLists.txt b/openair1/PHY/TOOLS/imscope/CMakeLists.txt new file mode 100644 index 0000000000..60b2dc69ce --- /dev/null +++ b/openair1/PHY/TOOLS/imscope/CMakeLists.txt @@ -0,0 +1,34 @@ + +CPMAddPackage("gh:ocornut/imgui#v1.90.9") +add_library(imgui + ${imgui_SOURCE_DIR}/imgui_draw.cpp + ${imgui_SOURCE_DIR}/imgui.cpp + ${imgui_SOURCE_DIR}/imgui_widgets.cpp + ${imgui_SOURCE_DIR}/imgui_tables.cpp + ${imgui_SOURCE_DIR}/imgui_demo.cpp +) +target_include_directories(imgui PUBLIC ${imgui_SOURCE_DIR}) + +add_library(imgui_opengl_renderer ${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp) +target_include_directories(imgui_opengl_renderer PUBLIC ${imgui_SOURCE_DIR}/backends/) +target_link_libraries(imgui_opengl_renderer PUBLIC imgui) + +add_library(imgui_glfw_backend ${imgui_SOURCE_DIR}/backends/imgui_impl_glfw.cpp) +target_include_directories(imgui_glfw_backend PUBLIC ${imgui_SOURCE_DIR}/backends/) +target_link_libraries(imgui_glfw_backend PUBLIC imgui) + +find_package(OpenGL REQUIRED) +find_package(glfw3 3.3 REQUIRED) + +CPMAddPackage("gh:epezent/implot#v0.16") +add_library(implot + ${implot_SOURCE_DIR}/implot.cpp + ${implot_SOURCE_DIR}/implot_demo.cpp + ${implot_SOURCE_DIR}/implot_items.cpp +) +target_link_libraries(implot PUBLIC imgui) +target_include_directories(implot PUBLIC ${implot_SOURCE_DIR}) + +add_library(imscope MODULE imscope.cpp ../phy_scope_interface.c) +target_link_libraries(imscope PUBLIC imgui_glfw_backend glfw imgui_opengl_renderer OpenGL::OpenGL implot UTIL) +set_target_properties(imscope PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp new file mode 100644 index 0000000000..591e611be9 --- /dev/null +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -0,0 +1,841 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "imgui.h" +#include "imgui_impl_glfw.h" +#include "imgui_impl_opengl3.h" +#include +#define GL_SILENCE_DEPRECATION +#if defined(IMGUI_IMPL_OPENGL_ES2) +#include +#endif +#include // Will drag system OpenGL headers + +#include "implot.h" +#include "openair1/PHY/defs_nr_UE.h" +extern "C" { +#include "openair1/PHY/TOOLS/phy_scope_interface.h" +uint64_t get_softmodem_optmask(void); +} +#include +#include +#include +#include +#include +#include +#include + +#define MAX_OFFSETS 14 +#define NR_MAX_RB 273 +#define N_SC_PER_RB NR_NB_SC_PER_RB + +static std::vector rb_boundaries; + +void copyDataThreadSafe(void *scopeData, + enum scopeDataType type, + void *dataIn, + int elementSz, + int colSz, + int lineSz, + int offset, + metadata *meta); +bool tryLockScopeData(enum scopeDataType type, int elementSz, int colSz, int lineSz, metadata *meta); +void copyDataUnsafeWithOffset(enum scopeDataType type, void *dataIn, size_t size, size_t offset, int copy_index); +void unlockScopeData(enum scopeDataType type); + +static void glfw_error_callback(int error, const char *description) +{ + fprintf(stderr, "GLFW Error %d: %s\n", error, description); +} + +typedef struct ImScopeData { + std::mutex write_mutex; + scopeGraphData_t *scope_graph_data; + bool is_data_ready; + metadata meta; + uint64_t time_taken_in_ns; + uint64_t time_taken_in_ns_per_offset[MAX_OFFSETS]; +} ImScopeData; + +typedef struct MovingAverageTimer { + uint64_t sum = 0; + float average = 0; + float last_update_time = 0; + void UpdateAverage(float time) + { + if (time > last_update_time + 1) { + float new_average = sum / (float)((time - last_update_time) / 1000); + average = 0.95 * average + 0.05 * new_average; + sum = 0; + } + } + void Add(uint64_t ns) + { + sum += ns; + } +} MovingAverageTimer; + +MovingAverageTimer iq_procedure_timer; + +static ImScopeData scope_array[EXTRA_SCOPE_TYPES]; + +typedef struct IQData { + std::vector real; + std::vector imag; + int16_t max_iq; + std::vector power; + float max_power; + float timestamp; + int nonzero_count; + int len; + metadata meta; + + bool TryCollect(ImScopeData *imscope_data, float time, float epsilon) + { + if (imscope_data->is_data_ready) { + iq_procedure_timer.Add(imscope_data->time_taken_in_ns); + timestamp = time; + scopeGraphData_t *iq_header = imscope_data->scope_graph_data; + len = iq_header->lineSz; + real.reserve(len); + imag.reserve(len); + power.reserve(len); + c16_t *source = (c16_t *)(iq_header + 1); + max_iq = 0; + nonzero_count = 0; + for (auto i = 0; i < len; i++) { + real[i] = source[i].r; + imag[i] = source[i].i; + max_iq = std::max(max_iq, (int16_t)std::abs(source[i].r)); + max_iq = std::max(max_iq, (int16_t)std::abs(source[i].i)); + nonzero_count = std::abs(source[i].r) > epsilon || std::abs(source[i].i) > epsilon ? nonzero_count + 1 : nonzero_count; + power[i] = std::sqrt(std::pow(source[i].r, 2) + std::pow(source[i].i, 2)); + } + meta = imscope_data->meta; + imscope_data->is_data_ready = false; + return true; + } + return false; + } +} IQData; + +class LLRPlot { + int len = 0; + float timestamp = 0; + std::vector llr; + bool frozen = false; + bool next = false; + metadata meta; + + public: + void Draw(float time, enum scopeDataType type, const char *label) + { + ImGui::BeginGroup(); + if (ImGui::Button(frozen ? "Unfreeze" : "Freeze")) { + frozen = !frozen; + next = false; + } + if (frozen) { + ImGui::SameLine(); + ImGui::BeginDisabled(next); + if (ImGui::Button("Load next histogram")) { + next = true; + } + ImGui::EndDisabled(); + } + + ImScopeData &scope_data = scope_array[type]; + if (ImPlot::BeginPlot(label)) { + if (!frozen || next) { + if (scope_data.is_data_ready) { + iq_procedure_timer.Add(scope_data.time_taken_in_ns); + timestamp = time; + const int16_t *tmp = (int16_t *)(scope_data.scope_graph_data + 1); + len = scope_data.scope_graph_data->lineSz; + llr.reserve(len); + for (auto i = 0; i < len; i++) { + llr[i] = tmp[i]; + } + meta = scope_data.meta; + scope_data.is_data_ready = false; + if (frozen) { + next = false; + } + } + } + + ImPlot::PlotLine(label, llr.data(), len); + ImPlot::EndPlot(); + } + std::stringstream ss; + if (meta.slot != -1) { + ss << " slot: " << meta.slot; + } + if (meta.frame != -1) { + ss << " frame: " << meta.frame; + } + if (!ss.str().empty()) { + ImGui::Text("Data for %s", ss.str().c_str()); + } + ImGui::Text("Data is %.2f seconds old", time - timestamp); + ImGui::EndGroup(); + } +}; + +class IQHist { + private: + bool frozen = false; + bool next = false; + float range = 100; + int num_bins = 33; + std::string label; + float min_nonzero_percentage = 0.9; + float epsilon = 0.0; + bool auto_adjust_range = true; + int plot_type = 0; + + public: + IQHist(const char *label_) + { + label = label_; + }; + bool ShouldReadData(void) + { + return !frozen || next; + } + float GetEpsilon(void) + { + return epsilon; + } + void Draw(IQData *iq_data, float time, bool new_data) + { + if (new_data && frozen && next) { + // Evaluate if new data matches filter settings + if (((float)iq_data->nonzero_count / (float)iq_data->len) > min_nonzero_percentage) { + next = false; + } + } + ImGui::BeginGroup(); + ImGui::Checkbox("auto adjust range", &auto_adjust_range); + if (auto_adjust_range) { + if (range < iq_data->max_iq * 1.1) { + range = iq_data->max_iq * 1.1; + } + } + ImGui::BeginDisabled(auto_adjust_range); + ImGui::SameLine(); + ImGui::DragFloat("Range", &range, 1, 0.1, std::numeric_limits::max()); + ImGui::EndDisabled(); + + ImGui::DragInt("Number of bins", &num_bins, 1, 33, 101); + if (ImGui::Button(frozen ? "Unfreeze" : "Freeze")) { + frozen = !frozen; + next = false; + } + + if (frozen) { + ImGui::SameLine(); + ImGui::BeginDisabled(next); + if (ImGui::Button("Load next histogram")) { + next = true; + } + ImGui::EndDisabled(); + ImGui::Text("Filter parameters"); + ImGui::DragFloat("%% nonzero elements", &min_nonzero_percentage, 1, 0.0, 100); + ImGui::DragFloat("epsilon", &epsilon, 1, 0.0, 3000); + } + const char *items[] = {"Histogram", "Scatter", "RMS"}; + ImGui::Combo("Select plot type", &plot_type, items, sizeof(items) / sizeof(items[0])); + if (plot_type == 0) { + if (ImPlot::BeginPlot(label.c_str(), {(float)ImGui::GetWindowWidth() * 0.3f, (float)ImGui::GetWindowWidth() * 0.3f})) { + ImPlot::PlotHistogram2D(label.c_str(), + iq_data->real.data(), + iq_data->imag.data(), + iq_data->len, + num_bins, + num_bins, + ImPlotRect(-range, range, -range, range)); + ImPlot::EndPlot(); + } + } else if (plot_type == 1) { + if (ImPlot::BeginPlot(label.c_str(), {(float)ImGui::GetWindowWidth() * 0.3f, (float)ImGui::GetWindowWidth() * 0.3f})) { + // Limit the amount of data plotted with scatterplot (issue with vertices/draw call) + ImPlot::PlotScatter(label.c_str(), iq_data->real.data(), iq_data->imag.data(), std::min(16000, iq_data->len)); + ImPlot::EndPlot(); + } + } else if (plot_type == 2) { + if (ImPlot::BeginPlot(label.c_str())) { + ImPlot::PlotLine(label.c_str(), iq_data->power.data(), iq_data->len); + ImPlot::EndPlot(); + } + } + ImGui::Text("Maximum value = %d, nonzero elements/total %d/%d", iq_data->max_iq, iq_data->nonzero_count, iq_data->len); + ImGui::Text("Data is %.2f seconds old", time - iq_data->timestamp); + std::stringstream ss; + if (iq_data->meta.slot != -1) { + ss << " slot: " << iq_data->meta.slot; + } + if (iq_data->meta.frame != -1) { + ss << " frame: " << iq_data->meta.frame; + } + if (!ss.str().empty()) { + ImGui::Text("Data for %s", ss.str().c_str()); + } + ImGui::EndGroup(); + } +}; + +class IQSlotHeatmap { + private: + bool frozen = false; + bool next = false; + float timestamp = 0; + std::vector power; + ImScopeData *scope_data; + std::string label; + int len = 0; + float max = 0; + float stop_at_min = 1000; + + public: + IQSlotHeatmap(ImScopeData *scope_data_, const char *label_) + { + scope_data = scope_data_; + label = label_; + }; + // Read in the data from the sink and transform it for the use by the scope + void ReadData(float time, int ofdm_symbol_size, int num_symbols, int first_carrier_offset, int num_rb) + { + auto num_sc = num_rb * NR_NB_SC_PER_RB; + if (!frozen || next) { + if (scope_data->is_data_ready) { + iq_procedure_timer.Add(scope_data->time_taken_in_ns); + uint16_t first_sc = first_carrier_offset; + uint16_t last_sc = first_sc + num_rb * NR_NB_SC_PER_RB; + bool wrapped = false; + uint16_t wrapped_first_sc = 0; + uint16_t wrapped_last_sc = 0; + if (last_sc >= ofdm_symbol_size) { + last_sc = ofdm_symbol_size - 1; + wrapped = true; + auto num_sc_left = num_sc - (last_sc - first_sc + 1); + wrapped_last_sc = wrapped_first_sc + num_sc_left - 1; + } + timestamp = time; + scopeGraphData_t *iq_header = scope_data->scope_graph_data; + len = iq_header->lineSz; + c16_t *source = (c16_t *)(iq_header + 1); + + power.reserve(num_sc * num_symbols); + for (auto symbol = 0; symbol < num_symbols; symbol++) { + int subcarrier = 0; + for (auto sc = first_sc; sc <= last_sc; sc++) { + auto source_index = sc + symbol * ofdm_symbol_size; + power[subcarrier * num_symbols + symbol] = std::pow(source[source_index].r, 2) + std::pow(source[source_index].i, 2); + subcarrier++; + } + if (wrapped) { + for (auto sc = wrapped_first_sc; sc <= wrapped_last_sc; sc++) { + auto source_index = sc + symbol * ofdm_symbol_size; + power[subcarrier * num_symbols + symbol] = std::pow(source[source_index].r, 2) + std::pow(source[source_index].i, 2); + subcarrier++; + } + } + } + max = *std::max_element(power.begin(), power.end()); + if (frozen && max > stop_at_min) { + next = false; + } + scope_data->is_data_ready = false; + } + } + } + void Draw(float time, int ofdm_symbol_size, int num_symbols, int first_carrier_offset, int num_rb) + { + ReadData(time, ofdm_symbol_size, num_symbols, first_carrier_offset, num_rb); + ImGui::BeginGroup(); + if (ImGui::Button(frozen ? "Unfreeze" : "Freeze")) { + frozen = !frozen; + next = false; + } + if (frozen) { + ImGui::SameLine(); + ImGui::BeginDisabled(next); + if (ImGui::Button("Load next data")) { + next = true; + } + ImGui::EndDisabled(); + ImGui::Text("Filter parameters:"); + ImGui::InputFloat("Max Power minimum", &stop_at_min, 10, 100); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Data with maximum power below that value will be discarded."); + } + } + static std::vector symbol_boundaries = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; + if (ImPlot::BeginPlot(label.c_str(), {(float)ImGui::GetWindowWidth() * 0.9f, 0})) { + auto num_sc = num_rb * NR_NB_SC_PER_RB; + ImPlot::SetupAxes("symbols", "subcarriers"); + ImPlot::SetupAxisLimits(ImAxis_X1, num_symbols, 0); + ImPlot::SetupAxisLimits(ImAxis_Y1, num_sc, 0); + ImPlot::PlotHeatmap(label.c_str(), + power.data(), + num_sc, + num_symbols, + 0, + max, + nullptr, + {0, 0}, + {(double)num_symbols, (double)num_sc}); + ImPlot::PlotInfLines("Symbol boundary", symbol_boundaries.data(), symbol_boundaries.size()); + ImPlot::PlotInfLines("RB boundary", rb_boundaries.data(), num_rb, ImPlotInfLinesFlags_Horizontal); + ImPlot::EndPlot(); + } + ImGui::SameLine(); + ImPlot::ColormapScale("##HeatScale", 0, max); + ImGui::Text("Data is %.2f seconds old", time - timestamp); + ImGui::EndGroup(); + } +}; + +// utility structure for realtime plot +struct ScrollingBuffer { + int MaxSize; + int Offset; + ImVector Data; + ScrollingBuffer(int max_size = 2000) + { + MaxSize = max_size; + Offset = 0; + Data.reserve(MaxSize); + } + void AddPoint(float x, float y) + { + if (Data.size() < MaxSize) + Data.push_back(ImVec2(x, y)); + else { + Data[Offset] = ImVec2(x, y); + Offset = (Offset + 1) % MaxSize; + } + } + void Erase() + { + if (Data.size() > 0) { + Data.shrink(0); + Offset = 0; + } + } +}; + +void ShowUeScope(PHY_VARS_NR_UE *ue, float t) +{ + if (ImPlot::BeginPlot("##Scrolling", ImVec2(-1, 150))) { + static float history = 10.0f; + ImGui::SliderFloat("History", &history, 1, 30, "%.1f s"); + static ScrollingBuffer rbs_buffer; + static ScrollingBuffer bler; + static ScrollingBuffer mcs; + rbs_buffer.AddPoint(t, getKPIUE()->nofRBs); + bler.AddPoint(t, (float)getKPIUE()->nb_nack / (float)getKPIUE()->nb_total); + mcs.AddPoint(t, (float)getKPIUE()->dl_mcs); + ImPlot::SetupAxes("time", "noOfRbs"); + ImPlot::SetupAxisLimits(ImAxis_X1, t - history, t, ImGuiCond_Always); + ImPlot::SetupAxisLimits(ImAxis_Y1, 0, NR_MAX_RB); + ImPlot::SetupAxis(ImAxis_Y2, "bler [%]", ImPlotAxisFlags_AuxDefault); + ImPlot::SetupAxis(ImAxis_Y3, "MCS", ImPlotAxisFlags_AuxDefault); + ImPlot::SetAxes(ImAxis_X1, ImAxis_Y1); + ImPlot::PlotLine("noOfRbs", &rbs_buffer.Data[0].x, &rbs_buffer.Data[0].y, rbs_buffer.Data.size(), 0, 0, 2 * sizeof(float)); + ImPlot::SetAxes(ImAxis_X1, ImAxis_Y2); + ImPlot::PlotLine("bler", &bler.Data[0].x, &bler.Data[0].y, bler.Data.size(), 0, 0, 2 * sizeof(float)); + ImPlot::SetAxes(ImAxis_X1, ImAxis_Y3); + ImPlot::PlotLine("mcs", &mcs.Data[0].x, &mcs.Data[0].y, mcs.Data.size(), 0, 0, 2 * sizeof(float)); + ImPlot::EndPlot(); + } + if (ImGui::TreeNode("PDSCH IQ")) { + static auto iq_data = new IQData(); + static auto pdsch_iq_hist = new IQHist("PDSCH IQ"); + bool new_data = false; + if (pdsch_iq_hist->ShouldReadData()) { + new_data = iq_data->TryCollect(&scope_array[pdschRxdataF_comp], t, pdsch_iq_hist->GetEpsilon()); + } + pdsch_iq_hist->Draw(iq_data, t, new_data); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Broadcast channel")) { + ImGui::Text("RSRP %d", ue->measurements.ssb_rsrp_dBm[ue->frame_parms.ssb_index]); + if (ImGui::TreeNode("IQ")) { + static auto iq_data = new IQData(); + static auto broadcast_iq_hist = new IQHist("Broadcast IQ"); + bool new_data = false; + if (broadcast_iq_hist->ShouldReadData()) { + new_data = iq_data->TryCollect(&scope_array[ue->sl_mode ? psbchRxdataF_comp : pbchRxdataF_comp], + t, + broadcast_iq_hist->GetEpsilon()); + } + broadcast_iq_hist->Draw(iq_data, t, new_data); + ImGui::TreePop(); + } + if (ImGui::TreeNode("CHest")) { + static auto chest_iq_data = new IQData(); + static auto broadcast_iq_chest = new IQHist("Broadcast Chest"); + bool new_data = false; + if (broadcast_iq_chest->ShouldReadData()) { + new_data = chest_iq_data->TryCollect(&scope_array[ue->sl_mode ? psbchDlChEstimateTime : pbchDlChEstimateTime], + t, + broadcast_iq_chest->GetEpsilon()); + } + broadcast_iq_chest->Draw(chest_iq_data, t, new_data); + ImGui::TreePop(); + } + + if (ImGui::TreeNode("LLR")) { + static auto llr_plot = new LLRPlot(); + llr_plot->Draw(t, ue->sl_mode ? psbchLlr : pbchLlr, "Broadcast LLR"); + ImGui::TreePop(); + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("RX IQ")) { + static auto common_rx_iq_heatmap = new IQSlotHeatmap(&scope_array[commonRxdataF], "common RX IQ"); + common_rx_iq_heatmap->Draw(t, + ue->frame_parms.ofdm_symbol_size, + ue->frame_parms.symbols_per_slot, + ue->frame_parms.first_carrier_offset, + ue->frame_parms.N_RB_DL); + ImGui::TreePop(); + } +} + +void ShowGnbScope(PHY_VARS_gNB *gNB, float t) +{ + if (ImGui::TreeNode("RX IQ")) { + static auto gnb_heatmap = new IQSlotHeatmap(&scope_array[gNBRxdataF], "common RX IQ"); + + gnb_heatmap->Draw(t, + gNB->frame_parms.ofdm_symbol_size, + gNB->frame_parms.symbols_per_slot, + gNB->frame_parms.first_carrier_offset, + gNB->frame_parms.N_RB_UL); + ImGui::TreePop(); + } + if (ImGui::TreeNode("PUSCH SLOT IQ")) { + static auto pusch_iq = new IQData(); + static auto pusch_iq_display = new IQHist("PUSCH compensated IQ"); + bool new_data = false; + if (pusch_iq_display->ShouldReadData()) { + new_data = pusch_iq->TryCollect(&scope_array[gNBPuschRxIq], t, pusch_iq_display->GetEpsilon()); + } + pusch_iq_display->Draw(pusch_iq, t, new_data); + ImGui::TreePop(); + } + if (ImGui::TreeNode("PUSCH LLRs")) { + static auto pusch_llr_plot = new LLRPlot(); + pusch_llr_plot->Draw(t, gNBPuschLlr, "PUSCH LLR"); + ImGui::TreePop(); + } +} + +void *imscope_thread(void *data_void_ptr) +{ + glfwSetErrorCallback(glfw_error_callback); + if (!glfwInit()) + return nullptr; + + // Decide GL+GLSL versions +#if defined(IMGUI_IMPL_OPENGL_ES2) + // GL ES 2.0 + GLSL 100 + const char *glsl_version = "#version 100"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); +#elif defined(__APPLE__) + // GL 3.2 + GLSL 150 + const char *glsl_version = "#version 150"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac +#else + // GL 3.0 + GLSL 130 + const char *glsl_version = "#version 130"; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + // glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only + // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only +#endif + + // Create window with graphics context + GLFWwindow *window = glfwCreateWindow(1280, 720, "imscope", nullptr, nullptr); + if (window == nullptr) + return nullptr; + glfwMakeContextCurrent(window); + glfwSwapInterval(1); // For frame capping + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImPlot::CreateContext(); + ImGuiIO &io = ImGui::GetIO(); + (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + // ImGui::StyleColorsLight(); + + // Setup Platform/Renderer backends + ImGui_ImplGlfw_InitForOpenGL(window, true); +#ifdef __EMSCRIPTEN__ + ImGui_ImplGlfw_InstallEmscriptenCallbacks(window, "#canvas"); +#endif + ImGui_ImplOpenGL3_Init(glsl_version); + + // Our state + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + for (auto i = 0U; i < NR_MAX_RB; i++) { + rb_boundaries.push_back(i * NR_NB_SC_PER_RB); + } + + static double last_frame_time = glfwGetTime(); + static int target_fps = 24; + + const int SOFTMODEM_5GUE_BIT = 1 << 23; + bool is_ue = (get_softmodem_optmask() & SOFTMODEM_5GUE_BIT) > 0; + while (!glfwWindowShouldClose(window)) { + // Poll and handle events (inputs, window resize, etc.) + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. + // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy + // of the mouse data. + // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your + // copy of the keyboard data. Generally you may always pass all inputs to dear imgui, and hide them from your application based + // on those two flags. + glfwPollEvents(); + + // Start the Dear ImGui frame + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + int display_w, display_h; + glfwGetFramebufferSize(window, &display_w, &display_h); + + static float t = 0; + + t += ImGui::GetIO().DeltaTime; + ImGui::SetNextWindowPos({0, 0}); + ImGui::SetNextWindowSize({(float)display_w, (float)display_h}); + ImGui::Begin("NR KPI", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove); + if (ImGui::TreeNode("Global settings")) { + ImGui::ShowFontSelector("Font"); + ImGui::ShowStyleSelector("ImGui Style"); + ImPlot::ShowStyleSelector("ImPlot Style"); + ImPlot::ShowColormapSelector("ImPlot Colormap"); + ImGui::SliderInt("FPS target", &target_fps, 12, 60); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Reduces scope flickering in unfrozen mode. Can reduce impact on perfromance of the modem"); + } + ImGui::TreePop(); + } + iq_procedure_timer.UpdateAverage(t); + ImGui::Text("Total time used by IQ capture procedures per milisecond: %.2f [us]/[ms]", iq_procedure_timer.average / 1000); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Total time used in PHY threads for copying out IQ data for the scope, in uS, averaged over 1 ms"); + } + + if (is_ue) { + PHY_VARS_NR_UE *ue = (PHY_VARS_NR_UE *)data_void_ptr; + ShowUeScope(ue, t); + } else { + scopeParms_t *scope_params = (scopeParms_t *)data_void_ptr; + PHY_VARS_gNB *gNB = scope_params->gNB; + ShowGnbScope(gNB, t); + } + ImGui::End(); + + // For reference + ImPlot::ShowDemoWindow(); + ImGui::ShowDemoWindow(); + + // Rendering + ImGui::Render(); + glViewport(0, 0, display_w, display_h); + glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w); + glClear(GL_COLOR_BUFFER_BIT); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + double target_frame_time = 1.0 / target_fps; + double delta = glfwGetTime() - last_frame_time; + if (delta < target_frame_time) { + std::this_thread::sleep_for(std::chrono::duration(target_frame_time - delta)); + } + + glfwSwapBuffers(window); + last_frame_time = glfwGetTime(); + } + + // Cleanup + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + + glfwDestroyWindow(window); + glfwTerminate(); + + return nullptr; +} + +extern "C" void imscope_autoinit(void *dataptr) +{ + // Copied here due to issues with headers + const int SOFTMODEM_GNB_BIT = 1 << 21; + const int SOFTMODEM_5GUE_BIT = 1 << 23; + AssertFatal((get_softmodem_optmask() & SOFTMODEM_5GUE_BIT) || (get_softmodem_optmask() & SOFTMODEM_GNB_BIT), + "Scope cannot find NRUE or GNB context"); + + for (auto i = 0U; i < EXTRA_SCOPE_TYPES; i++) { + scope_array[i].is_data_ready = false; + scope_array[i].scope_graph_data = nullptr; + scope_array[i].meta = {-1, -1}; + } + + if (SOFTMODEM_GNB_BIT & get_softmodem_optmask()) { + scopeParms_t *scope_params = (scopeParms_t *)dataptr; + scopeData_t *scope = (scopeData_t *)calloc(1, sizeof(scopeData_t)); + scope->copyData = copyDataThreadSafe; + scope->tryLockScopeData = tryLockScopeData; + scope->copyDataUnsafeWithOffset = copyDataUnsafeWithOffset; + scope->unlockScopeData = unlockScopeData; + scope_params->gNB->scopeData = scope; + } else { + PHY_VARS_NR_UE *ue = (PHY_VARS_NR_UE *)dataptr; + scopeData_t *scope = (scopeData_t *)calloc(1, sizeof(scopeData_t)); + scope->copyData = copyDataThreadSafe; + ue->scopeData = scope; + } + pthread_t thread; + threadCreate(&thread, imscope_thread, dataptr, (char *)"imscope", -1, sched_get_priority_min(SCHED_RR)); +} + +void copyDataThreadSafe(void *scopeData, + enum scopeDataType type, + void *dataIn, + int elementSz, + int colSz, + int lineSz, + int offset, + metadata *meta) +{ + ImScopeData &scope_data = scope_array[type]; + + if (scope_data.is_data_ready) { + // data is ready, wasn't consumed yet by scope + return; + } + + if (scope_data.write_mutex.try_lock()) { + auto start = std::chrono::high_resolution_clock::now(); + scopeGraphData_t *data = scope_data.scope_graph_data; + int oldDataSz = data ? data->dataSize : 0; + int newSz = elementSz * colSz * lineSz; + if (data == NULL || oldDataSz < newSz) { + free(data); + scopeGraphData_t *ptr = (scopeGraphData_t *)malloc(sizeof(scopeGraphData_t) + newSz); + if (!ptr) { + LOG_E(PHY, "can't realloc\n"); + return; + } else { + data = ptr; + } + } + + data->elementSz = elementSz; + data->colSz = colSz; + data->lineSz = lineSz; + data->dataSize = newSz; + memcpy(((void *)(data + 1)), dataIn, newSz); + scope_data.scope_graph_data = data; + scope_data.meta = *meta; + scope_data.time_taken_in_ns = + std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count(); + scope_data.is_data_ready = true; + scope_data.write_mutex.unlock(); + } +} + +bool tryLockScopeData(enum scopeDataType type, int elementSz, int colSz, int lineSz, metadata *meta) +{ + ImScopeData &scope_data = scope_array[type]; + + if (scope_data.is_data_ready) { + // data is ready, wasn't consumed yet by scope + return false; + } + + if (scope_data.write_mutex.try_lock()) { + auto start = std::chrono::high_resolution_clock::now(); + scopeGraphData_t *data = scope_data.scope_graph_data; + int oldDataSz = data ? data->dataSize : 0; + int newSz = elementSz * colSz * lineSz; + if (data == NULL || oldDataSz < newSz) { + free(data); + scopeGraphData_t *ptr = (scopeGraphData_t *)malloc(sizeof(scopeGraphData_t) + newSz); + if (!ptr) { + LOG_E(PHY, "can't realloc\n"); + return false; + } else { + data = ptr; + } + } + + data->elementSz = elementSz; + data->colSz = colSz; + data->lineSz = lineSz; + data->dataSize = newSz; + scope_data.scope_graph_data = data; + scope_data.meta = *meta; + scope_data.time_taken_in_ns = + std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count(); + memset(scope_data.time_taken_in_ns_per_offset, 0, sizeof(scope_data.time_taken_in_ns_per_offset)); + return true; + } + return false; +} + +void copyDataUnsafeWithOffset(enum scopeDataType type, void *dataIn, size_t size, size_t offset, int copy_index) +{ + ImScopeData &scope_data = scope_array[type]; + auto start = std::chrono::high_resolution_clock::now(); + scopeGraphData_t *data = scope_data.scope_graph_data; + uint8_t *outptr = (uint8_t *)(data + 1); + memcpy(&outptr[offset], dataIn, size); + scope_data.time_taken_in_ns_per_offset[copy_index] = + std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count(); +} + +void unlockScopeData(enum scopeDataType type) +{ + ImScopeData &scope_data = scope_array[type]; + for (auto i = 0; i < MAX_OFFSETS; i++) { + scope_data.time_taken_in_ns += scope_data.time_taken_in_ns_per_offset[i]; + } + scope_data.is_data_ready = true; + scope_data.write_mutex.unlock(); +} diff --git a/openair1/PHY/TOOLS/imscope/imscope_screenshot.png b/openair1/PHY/TOOLS/imscope/imscope_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..e33b294827675459b587c7233d0c6433d006a5c0 GIT binary patch literal 23323 zcmbrmcU)6j+BUqc94lg@3D{ApG*P+*6sd|3iUb8I5+Kqcp?Q=hO;LJRkrE&RhMHob zNbdv)Md^eR1BB3dSI{#v&&-_nd*0udKh(YVDtoPU-Pc{W!MfTv_U-1`4MEU8^_$o4 zK+tvu1Z`dXV<)(C=+T!0;IHk@SJm(S0e)V8JPZQY+%BqyE_z5S7xxEFmXNgr(%w?k z*}}=v(!tpV=|bB^QUZ;HS&gnaSw3)igmgH5_mRCNbl1l9xa8&IS6r=+OJ0zaJ}x0G zcj2O(wB+$?s(N>Y{c;~b&~Zrp`jxvLiBo;viAk>Bf~&N+IE5Em{@fF%{_JDw?0rO! z?dcB(UsrV$P|b^XxTOpCloNY;sGT#p{pGE>rigMhZ;tWc*PbbI>A9t>El%iLq%GYA^O^(e4Fm) zCBwCdq3k0eW?X~b^n4oW#QL~0{&FE}=LFTs~<%|eR_Ly?QY zo>FWT(Fw?4c>ynJH=XN=sH*3Sl}w_nScv@4SF-n+mlGf3*lR7@1-?zq(#6Te(lxA+*|UI>MS=r?Oc+ zqgn?)+u%4Y6QeruB3eu7V9LfP!NJdS1BVa;YuStR3o8~wH}6^v zw^3$@ZqP9EP%N$rT)(f8xba!1N?y!{Fkg*a(_Q^+b^|~2l*CCZNri7aJD9H}TP^CY z#1)||!yOV0KY+>eGP%ddwv@m&8ZoLUvx2mc4M|TeufdISk)tseX#-pWYu{r|t&da> zGW$K$H0_pNc{Fj3Rif9Y2=r{u{oSr(fkS0j;%TMD8uyAFju(iob7O;8{@x=i>`J_W z83BXs>6{81aIX&TU?Jh+$wu~SS6`g853{MCPtZ%aeW^@Uv*NA$dQ6FZodtby-P%G( zJ1hpz7^t8T98b>Re?)i9F0OZNO#O)Ek&}tWdR)UhR<4)O647%6Y|2$ z&_fz2z5@D0>v+$NnI0}*r>~~;@fm9i+wpco)aUGyS#n-5Of)>!lbtYJX1Ed_b9U-h z7}m6653O2@9$ApW#~{&!CogkF^sbhcOn)}bpZs1ZaYV3kqE0MGAL(tfI*4h!xd`6| zL4H-c{jc^-k8GGMIZh0G`lQkk5!k;{6h$YSt;3HgdR-uHB+)7=@-66Vf+^u+$vxZ= z3O`k*M3p#nj(Ldfgu7YZ^ZcRw{Bsc3v3_oLg`ZF3uG;QE3wl^d?qsKh*VD}PTpN;TUPDYV&jz1o8$onp89_t~U;^*fL z5m3E;Y*~AC#H^Pa-RNbCU*|Na`qO&jL{aZr*5aDL+PVI<(U=Ndg+mc`i&uMb)~5~N z3v+a;Uf|$(p`HYN(J)l8@YI4pe5fT7WrBC>zJGmhQ~isWlemCf#?BNk7u zaada1bLr+C?D#sAKlB7ym63L0rcEs+MiO0!*JZ zDf)_X5A!NtO{fTOkaq&`H=thGaeu0>SH64B?9Jw`Ef z##~D9n5=ym->ZzO=T9vpE_T{>$PYEjlQ;vL@F(FH*OSV|XiJn09D|nxB1j$Ytv0>euA4!RB`6AgxL}IF2KH^<1*N%enpD?jlv% z%BRA?<4g0sx^@D*A+7T68{un?<8eFazExG`3dzAM#i5lR354R`ocvx+Tq2qG(z^ z-*eJ^@LR1fe+-s8e5lDsaE7oFLeI({$)7C<8DuESA8t}AJ3q6&>Ki&1j+giOQ6H4) z)g(Q)t|)n=4tDRLc)7=wip7XQB6cIfaHYC>P!my0MRj=P@bJUEF6As$4W)Wkn%~Z3 zWBt?fR6CG%$S;wb>b8Y-W4<^mD=RiJF%p^(LUf^Q&p8;X7SR zGWc0dvd$k3aU5?>i{6$K6!i8+L{-|gz&D0=zWa?yVR2c>34)=3sAHLO(VHXJ}QQJ_S3|g(eSBw?HnRKE)wJ&Cui@ivv0-d|2Nw6?SM`dAe6NuRk_7;87Sg z^JuSXJNs&Dj>Y}^$HmIV-;~g+cv+_}Rz6h_+l56^{-MK`}D;lmfCcx2L>GVyq1vsL9}V*qk>`Z1DvE0d&dUe zrVzc|9FAVrcB}K8gNOld$pr<5-Ld3k0deE?HhRRstoRU>oWvJ$>-;c%8~vx5_j!lz zMHR1&PjoK0+ZFsMCpOHibZY97`kh^na}N*~w0XTk`|bEN_n|OZwd)nl&CQyru-!{M zVdnu@#sdcXJ?4plL+HRg63E5&OP)V;mAbtM*VxjWVtx!Jh=Xz=})dfpK`OJx|Sl>G*PKH;xlU4)iKPW`b8y3e$*;5Yg z37-j}e|fz3h~OZNw8%z(DW4pa#r51jWVCWIg8zB>h8=p!VK)6*o4 ztlw0SqUj87n0m)^2SFDCkAzevb4iK2-rb2N!_m_@BPEQg`P99TpMy|ng)(8LX^`Zz zFi?>m!gg}^+~AncoHN~@RC2;+&6@N2gJoTX)$bM(M>yJaro$DhpWlw%Xmf11p>!0X zyi~dv;z~LyJgTZG&~?mgJtd;D<;$Q4qg;u@Y<1AAf)lxX)oVCKG{S@GTWRmE%&q4y zWzJYp;*<56*h8;zCrE0aKNd_|Yueyv*Gx2Q8WC7-qA!WBdV0;LkfcYCR1eAfdZHD) zq|KMJ8XPHoIu-P^xgl7mkCGBIPB}t(EeuxmX7F=Y5gj?CGQFa>4SFG&#t*5mpW90k zX*5ydx*dASY0>5|8~m`i=R_n|&_t}qjIQR5itn?q%38~795)1>EBn%rm4WLn*X-6> z^3Pqbm}d%v(fCBGKAp#g`z{BJ7~g2$@bG9;0k5td}ga zZ&<84Im#tBweNhRTiSZ+hcEf)XhTSv`Srsqw@~AE7Yh6mcV=q$r>B%{&G2g zbXp)(21W}tQC@vgGEy#YK^a&(=d%=9XtC5h+O^(WJcwY<1gESowZwA10({T6r%_23 zE{D`pSnYjE56fK{JQ71Zx3G>y56V}E+%|O4#!uDHZhTJ+&&mo4%IYH7nF?X3)l_;4n@R&r*ghn9y1vb!q$m%Xm?O^|E!NG4jYgVh>ByaoGR^FLV zS})^k3G)?+&%#$p{CyRB^+S=M82kk1P{&se3C0)I_smMOjX<-o+z__G=C;5=L&tN` zrf!~ir`r{u)MF~e2@83KD`ABE>81@W{M>szbC2&gkHyCdU{{)bgPHhRU*oNx?p*}B z^4hg)5;8I!i{Fn{X%vQ^{$bwZx_9s1ij{sQF*~h~+JPC8!Fp-;@y8WE#?0{_E;TB+ zUf5s#W--ov{mN=NLM&{q$?(9d8{ySoT2h|Nkd{~IG^~$Ny*TOS1E0kF`Sw^jm(%8p zmGna7GMS#{jz6jWJm_2^59fN7Kvkg6$k~sY z4{!9*=C%$?z24n3%`=TThWUUTP}*4A0bL+#^$GYcH*OqG2oJ3~;ya%~Z=7o=+Xh8) z3kXC2onItV^~HY=W&h|hVZRgzC_vE7hBvAq2m7ApJp?9>w%o*NSLsZa!UMLCE$~MY zy=H6j?|=R?y2-TU@qjH!9T+6oe zqqclkH_aeP85x-)uU@@!TwSD}JDL*l28_6O|Nbhx=bYr8mgUm@0D|B*9Et{N8_d}F z$L2d7xBg|+ypZ}e%s1}8+5zbYKPRj4AAtfhZu?jlDtiKy=$r{!T;?zb zy;R&+D$j7v*>NGxx?b)(n{ux}%F3*)9>E6p0jnQ1*1=nNcy-r2Yr=6hDQ5dheZxQ| z>Qe^USFz<&hgEaBstW4}0DKQo`|>B!O5CT)1*h=fPsgzhRLPKP$Ejx4Z1?kcg*G1c zEh8(aQDaFzJ>_jh(ORg8a+K6YuPkfnex-xYbZI}Pbt**N`#F*5IaOd;Fe|@OQoaqp zNpH^W7%3eY)8Fa-rvhjUjXr-;yDtU4!QfK%lBN^pg*wWM;jJq(mY$ojBWT>U@G4;& zTlJ8XtnaD)$Bxl%Zb|xM;a2sot*ql4XY-FCOs9ZwyayJp=&-yu>vj(!|ImQ#ZG&ky69!hkY{rQG9`|$NgHTE*m16v_o^6JtY z%LxeA;t$EnT1b9v!fnIHlVXFwyG4=PY(>?Z?8oHP8`+@cR{*1a0Xui@&VT&*&r3=! z3gKGX!24(mt`=fX*XD<}cf6oBFJ6DcBh*y0>^gs^3G(Yd4irS{qo+@wI<|hluc@t7 znQu`IOmif@RyVhQs@Qnt)>zC!F|UU{Jj1EiHqAKKyF&?CTxEso9G7XAV~4&)q1PpfNTR7S|2}Mcp?l2GgQh-V`!DNR; zb(TEp*TcdEsDuFRCh6@^EBS6_v290o{7R8MrL*1t)&t{;;3qxb##;|9Smw5oF`V@> zyQjCKAQkK_#Cv!;>IsbCjr&5%VSKTZW$y=o%gWM4{`lhWNXg~3vM0@EV-m`4T6$RS z}wC6&cj5BcUC}RXz3{(dBNKozQ)UM?&osyr;8W*M}2%#O3M}{Q>)U&4Fs# z*OYtoyA1DmM|>Z-k@!x?nyDY~nvoatuG6^g*zr*>PBniL(S|CS7hrGcI`B#|^2 zHpkG7WXfEa!&j!yO|Us#?TqGGVmab&ZUaq|(W z+JZaCB4c^mh5+FK@+6h86Y{fd-3tihW|Im=(96yq@dTccaxnp?h81MT;s%IkSyJV! zr6I*QdD4Nv=!_P>!+lalN+YM`GH$_=!>|MW>H1r_$!VR|7!;M@#$Ll}KQ7>Z=G5EH zyYuJk?6&w>X$t5tgNqHzo5OW3mb} z$!tZ{dEPqisc)uM7mx&brM0*wD>ntGo9dAX<3Fi7@AKlW@VuP$$dN+0M)4F^Il)Tc z)lA(R{w*hg>F7WvW(>`@X$KE@u8hb;EVak1zn@S+(vtfMi^4+1wCb4e( z!_j~`;7lQmU_`@W)Pl&nqMjr{?5V|!_F2lEWHM0KsTo{b9hjgnf; z-tiRIX#dW@kgVxvUBs_K8_&`ef8+L{^A-f-KiENuab4?B(ka8fL{%G5V7mue_kN4# z#ux+{PU2$7=YfJr)tl*>&-Iv`gjJ;ri^q1mHFdpp9DC1Z!jFMJhSBCwD?-c+t;cN5 zD`f|%9SQmd!o#(%P@f-Qdjqj1)P`p{?%}}o_R}_TZ|f6$hMIJ^bx}iHybh@W_+zP= zfu=IvS_x=Mkhg)%#JDB9y|01;(L&?iT(rjEsC-eyHHrYuO&z*mkxJPypKZ$w&^Y)d z{YbB?9HhB|nhu50;NBoclEV@UnNy|QGo5iFa zuP{RW>*X|lm4)zQ$+1fw4e>HE5rwPKM$ha3+y`zIGK^0&ZyOgaHS(d{j7(1oTWHW< z29RIFcKB(hvNfA5J1vOLb5CTqF_*1jHtUWCVQ^{$;)W zhouy!Ny{3W0Nqr?=jKhI+1g(!_&+SDzYL;R6Hg_<6tfSzBRMP6u}Y*Lj!cCQif+^B zvTaAs6uLLfaB-XVOiP*r{Bv+9-rl1^+7wIt{r@5+=_=U6cB&uw9nL7qss|bPDsj`w~E~94AKMY53 z&m19w4oidUJ^<*}FCO@?K6AHfpxl~SPnvD2W5NRb(wl_87TKm`aD3B;lL|(yY_l?Y zJRs>NuyK&zZg;z713ZHvJk%P+S#MWvJ=Id;-1aof^sT}>%z~r*P!Z4Ts1&`)l?~zBiG5fVDNzgQ10e7wSNGh1jf|IQN@LV)(JL!7j);n zVl4ZM8!W2=YJdFwdzxXfkHxV|9_Q#>BkW&oEY*xHKfu-x_kFzf!PX+09PcKItJ;?8 z$s*>;oSgzn2z`TV!1ViQ|9QMLE6nx2owu#UNE90!`bhisBRDRCoMWUncj=dTe%yL< z(~nEk*=#A>wCYvN|5Wgs`LKGF1uUntZE>g}9fvw653pxNiwQgY@REOHG1tr|qge3& z)l`H_Q5KiKKQvdzUIenK`2Pbk{bB&Jpdc2^a6CO7?AR@-37h7>co&W~acS+N-k^KG zk7t905+j}T=zO!VKa8V+&2VJwt~~Og%S4VvJRb{e*yMK>XTA493cmm#$>LY~Q-K*w z*}u>&Y&YI`A5l#$rg3%BYEggpG%B4RN)}`VKQmb;l}$k!`nn4Z(fSI}qh?EEMxlMw zb*sBOUw2gH93w?drr$oLLMmi!Ug{UV1mY2-_gXFRB6dhoX1LMPGrjZoZOP|$Sd7%c zUWr+XW+{+*Jk+iBUM$-%jb~OOMr9zDp$BE!_G!7N9H8cwpHDJEHQaI%C+55k3?E6c zt^^RP+FZQ8!pAjw$x^teV}prUFbisc9r16;G`ANpEn}(O355L+u9OwnRoOS$i43KG zy@BYrK#GkoyxK}<}CdHa8_aQT6yoONp71co%gwJ$^?TLh5@?A ze#sM8rMdjN_q5E`de#3c${45E@sLg9%ddx|1h7Vh??)XsK@8lsO{q{hEAn>7w{Vt= z=BN3`EL32@;xb@GYrdCaRHgJrkNgBz_H@}jkf-JQ-;UpJhwh(rq{s+pGLHJy)aU}r z!PbJ0%Os`85NZyJ+l+Moty6fmjm?rZT}{Cm@#h+5-acQ4W<2ksr+Sz!Y(m)%n*=5y zS@sbjBYjHTb?fl$>T3i(i{g}@OP7VQ<1V{EU;Sy&IMJu)JY611!jDR%EVmAPJUkxt zXKv8w*W6j>>?9UPbxJgZCrIDdn3ap{+@)e+8kYs*AD-qaH~j#%d_J_Pe->mg;-i4? zr(rd{@|m4kX^mX6)ffW97<~OWJ4D$v)T-;b=0M)2!Y)Em1a^qvcJzqUlF(P8@k;$V zKuGIH0LGH_rzAdp|}ten+^#bCad1V5kP^ z?aNv^{wR(@>pq!sFvxMONr$qPXS(u~n3sRm0wDXeChA)e2CdwW*HR6*$U!U2Ezasq z{wRi3SDZK42$$NwNRo^niDW^U-n>vPk6J4|I*h~g*eUz@Tx_1+N)?TgL4Y~N-~UfF zF4K{GU--hdabjM5JBINor1hGVaUTq+3BdIZXz9Z&&~Ia7Kg0j_u%GLol0(#%d$^T} zGe(^zllYI-h#R<{`MvkxjeF-afRou`Zt#>n1t)|_)A|0H3&_mDf6>_?E}j>5z7V{z zU#H#+Z`BYVU+wDs3%SiazvB*?X3tR3{eZA_L(+>?l&K-VU^^PAnezXlm}R{>vp044 zIQL8wn~LD3i~@uA)r6*Es!W~lQb19)$DlAxD~%P3NR9dH`Cn0szYJnlLZ`IIVrn5S zqRGfpwQq5^c%%~!=T(Ofc0dWy+*NMtH>gNN7I9@FDw9NRkspn5N zD9J#)U1$Kt@29`#>-LAx>qFEnFH9Qh@xnX2|5Su#^P*I+UeRWjj|~wk!1Ie+%dO|h zk+CXV*>V#|s)||WMUAFNV4z%y)WyI*bxtjX6~P);F*14|dK?=gdfDh?fcChB{)9dDXl)(ypX?t5`#vzODw z8)~!q;SPS^wF0sfs1pWn{V+*TP8^%%>D=^=54T^iy$E~azzH@ODAB4-%|$JEb~Kgw z2O~95fgZ(lE8h-5v8pfFn$eru6J+XYT;BIDzM>Qy+hncL(|==p{d<_|{bX8yzhb!s zpq{u;ig>)Y=-PaIO#t)eoGl}}r6~u`xP)XBVdfbcbFQ-TRwL^Uod9FQ1G*DWQNB=U zsF?kwX3#%DF0ZFceSOi!g>V|DYq~_vFgDXzDes$mN4t{wz7w4VhALgo{3AJ1m>}teK8gFbu{H~YA zyW)j>qhF_(EES$*S4Pk3o&t8Y__Z+hrF<)EJN+4?wVG-qD!btrMxiLqB0e{*UmzyR zx8fq2@UBpV$~Zl({HJhrCg(cvQwZJ+lo72Lg(b{8=5`0D4;;c#?Z!}#rZBz9s%G&^ za{8F`{>x$gST;N1Q#JU3@RM-%}k|rjTd+O>aHWsxu8lAsANpGf91|7^!PK47mwn z?V39E(Y&jT+p5*J4l8WTDA6kYwzY61p7@T8oG*(E(7`oo%voP4^sX6Hyshyz*_u&! z?$KiWu-x>$w;gjPOQyhHtv3~IXx9)5Q|6IBF)hd2aJ*K-te}%B@)1Xm zhcLx<7&$j&GnWgJKSu?8^f~H6Wu&j+>VytxoYHhqGoVf4$>3mJV54d9qlH%sA}a-M zGSq0jG;^+7k|(SH>(ohn92Jztz{>Da5yTYs`mgPYgF@s*z{s0M%uV z{?l?T30FAxwDhaMOBJjJ`r-pZ_XolqU~)J6K0`U*?2oyy^`med+eud{UOR%dD`(UC zk3}+-7iRDH!l_edP^|K}TsrW4!0#VUPksF?(jpv^pU3}ZH+;&@R)+f2a4r9pLatQwIfEFAr;)|L9)7L zR+xtEZYJA}BQDO%@Gi&i^KMYXcoSA@2ZC}fA|4vvcE5*rQZ*yyp{i0e#nFFR)K#0F z7UX1G-8C&GkOCqY^-XWxe?`2VY`{&y?M_iC8Q%N^)lBlU5bT=QSBs+l#k~D@59T8W zh;b1yB1Wz4^oCm5|ha%ThhgC%=`15`%r z?DxDVBe#+2xFlAmrH?4anK-kzymd%%cqT=?*Aki$4=mNDC#ox-_WLQ>M{s>em}=a>AE6=9}6Z*k8;E7z%0r#Ludu*L4Q z{zFxnZiLpZ5Ki$tR3H2?H7f%I!-(&&-CX?qGZVB7{H#wy0P(-!B3FFkd2^{-c~P>5 zu3EI7Dvh+Uo~;v}bywu*TSF0pzG6m|yNm+q-pEv0>zF@hUYpH=Y3^FCoj3>!=2}^A zIT}*Q3TNw8yJ=v_F|g%$BAxE&-4OI&Cu>k6&Eup`<#B!~glDF`x?|*HV(dV%om*Cv z07M3jb4Fq7`DK*(0Wz@5=7*w^0iyKm_W0 zI?s(y;>Iq{$G2Z47)#A8fA*%K?Y~-xEf0^zMer)(isrvRH%PJDM2c3_1Gwx=7EHJ# zLE{Ph`mHoL?tKGJt;oD4@{FLuOV$gelB28@N0@DxUUHtBLwRS@t41N$HCC7dPyi9d zY}Sxh&~VZy^4b40n}cfk&g(2(xXuod1T$_$Oo)L-&7#htmnJQPuMun`Bu1;VcQ}RJ zrl1f0 zM}b^!zuh;7F*AFAR0rJfdVx%D)Yx70+q>lkk$})6*(_fx|M52J7nVPO{pTyy#?-k{ z8sK8^(l@ztaiWZjfudJ?W#tXz5mm2B#$P3v$Pwc%LI<8Da*!bFv_Jg{3ZH(YKx$O_<3_y)ph_T0Hsu=A-xUR+oa+ zN?4vwUNMoV-Q$lpL%hd5_aMcC-z>;^udGY zN6ZKwI)uB)K9oJ;r?Iuy@WxUrn|v_z`~b3 z6P#AltWZ0_PE31-T1igmc`8}U7~C_hkNZ;InxpucWx8I7nQz^8hgb1OQ34LfM`cjU z2I2a|ilTYX;J}CAIYh|o^d4;`s) zbS@Z=0fPpTj;snTGLTAal^Od|+b}z({@S;H4d5GwI&cW}bg6qb?(FiMDGLY%iAV zo-R5fY+xzplcpPFo*z3Q!|Hz0md&-p;M#(dhpKDVGgJq0u>pU=c-OjdA32+CV}^LQ zD$ANaSjmE9Jr?-z&^)O&_)gO9(ON8}j+r>=ZffR}fcqC+gjm=Dm&r&**~0QDv`s@I z?8lEEhQRJ9t{a!{|92DPm(;wpGMn^&)UeZDee2~Da3;emlRT3!_ghv>>f7r!o3+U* zDdl0gTmFZQ@=vjY^+ffwAz%GYjvK#psd1Ez7P3B%i$hH-JxX`l=SFb-(Pu2RAFM)! zc~{9St$R%Lv?4af)pf~Up1t)OdWZ$J**8x9Rx*Udj(I10_4K1u{guH5i?84TH2MZ! z>)8|ch|FF%fAY?5#&SA0>vkW@{s3wv+s!!z9F@&-mxy3ELoc9XPKOm6hGK5ALGRK!2^-6z%^{C?w~mLU4R^ADB zezNJ%9}g6=u9lHE0mjFCbn-q1Pv2XeH!QwvE_yzK5F} zyfznLZtIl&%eVvwGps89JjLf4a#fQm_%|ni8;jL}b-Oto%aezB-rYrS9wGtf=&oFeBgbZe1*Q1AYr_sfy2$Mlg}n)v^GVQ20|eb~lhJf4d3O zL`6w19UphZ{{^@$wq|CxPqoW~^9dF>ZM>Aa=Y-k%yj`ZC42y#^v2eFLh!lLfGPng3 zw|5W>X5IF~PlBbLH0og;g387%i#IUkoCDJnzrruKgua%X{&8<)ZTp-p$Pj@hkc!~^ z*S&;;AOpjeYe;|2O5#H=(CStchF&V?gUzUpN|PaBITF+l1pk7d?Gw}T2lq%jP#hq% z0H#c4tlu+hk~ za+lQ1EPp-j>r+X&@xc&rs@pDab(X&{9L)TuxA0F%WC_#*RDXual$R4bO>PI@PG$TS~l$!Eg9qT_^I7nLbualzpjY7Q%5mbJ1(Y z829jafS6*&$lNVj%GC!87f&{pf1khPj%N_9vIK|g zU#PlKbu0xuXkU?W^_)S_{mowc7nmhiJ~vBF_l~0QP9w-W#*+BOFT1!=hZOBH!{#bB9*wEQ40!!@a_dw~KgKG*k}W@8^wI5_6u z80;hTPmc;bd0mYKGUcG4CG1MKLrjain_9(IZ>=O?XINhsX(zW&ATEMi>M;|Do?oE9 zW9I9$RPa8WG_tYL)P1yl3sAWd2uf%EjWS*Jjc=}*WX;`cKa@O%Sft$^8EAysil5&M zt+Qg+V4IT)XLm=~vG6!54Nf4sPFMU3?-6jRq9p15OWFNr(t3Cy8Rhu_#OMMLl!VIx zhdL&WCU&NwddiHwUE4Z_sSItiS8ZfFX^K3l*tjhd>w`QqG^X;~p(GU-{9qbfTs?MN z_$ndvwXa2y^IpMhvJ~mVD@+HuHks-;_a6iFzpYuk`~vu*09{{cxps?$sC~+8-y%nf zxi4H3=MA$OpRkrh#q3jTP$Lkjo=y$(jZM!x<1R<;^JXcHzq){_(~u8qGzokEm@jD2 zG)qv77C_7kBrNw3Q5&@UQGFCIG;Ta>8O_L-7l-F;x(@>*(4n6cvg98R$TZ^pp6 z;-a6mB%{1LCWo_G{b86GA7W8P91}xq6-tA1-tDJ+mKB@NP#d5SX|FiOE#Jlk9*}Vs z5p2Z(8FC-@T*k)~{$L)x0Q&<>wjssl{FF9r2i9;K>kjrd1NPfvU+u3A7%=H>2EBxh zghaTxMb)nFO~GYTaPwidI!3c~c<-=fDtvp*FYlhQ+*8{G*B;(Hjc;I|GT=a0ml_l1 z&=|!AqTpJ;ZCJ{-?q*nRm~v_E4~c(?BL6CSO5N7Fm$CCs*5;Q8<6Qq%$o5y>82U{G~n;im-hj|hC(H=0RvC)==2#@b!u!N0x;!8@Omm$_4V7J>i@A4qA*x6@LsytBwHHUySUj6QVA!Qw&TKzrSfxTptqRZ~5Y1JC_ z=jYR(;Ukx=mbWx#x3*Gj3ulC4Mhp_@Fncq?G{}}?;Dt`3DRF+#JJn3KPrI^3V{&oQ z#mR0~%w2TIMvZ_TjS94j8k64LVY}l=LxAg_@{rsW&@$Bai80PkyskOd%Pr+GyB~_$ z@B!nlO)&C$)PAygTk0W&wWEGPP)e9h}YYEjLb=QVxs&d>=SNZM)mXGMKAqBAGUGx3)n z@Iq=ck@)ajO#yf(RvKP~Dw5$ZaA5S90MZvcGqB$HGjv_m?rS*$F*l>Ut}YfOdl^<~fb*6! z&uucm(EV#lmCpLGPLbD3kYJJ8$ll@Fu@LoVi4_wTo^btq4(7;sy60xL^JaGXNHNUJ z+qIW8OOH&Q(*(ma7 zjtjhXZgY__GOjv=TL>~-0D&bDCx&?YFnQ5HtaB47qi z6nfX?_!(;IA9mX+Em<<{=S8a77Q4m=RFWDLt-zc0pXJDRGGG3e+mwx<-8jTr=7 zVI5ZK!#p5p<>F?rns4KGHs?}d2gQRXpg6e~9F!3Si>FfGi{0V(V4xwE%7%;(e^Xm% zZ;C(sGs^0Tet`E#;n&C+j9Y_rmEB0M2qJ5*CZZ!&b&b{C<%S+G`73%Rm3^*e7B4JE z$a=q2J7IGEdN#um*MykHxWRKJBEyZeFjov)jSITSAo&G;D2=wX{>CJEi|L-pp=|;l zzN{j_sov7UiIBSqM+|xlgk5Y;hoSK@@?Ww2c3(caEaTkGHCa6iT3j+YIr9It08n31 zD@&GF93x>8hl@!Ufuo37Am&RK&H^x8~<0Z>MNTjevX~YaA;Ch+|x@ z$Sv;gnN{Uce3uqq`!ffWLrG~^w(%6+USm|{o~gMUM%5I0vXLZp-=@%iFTdaLNswsrQ3a-Ep^F z?Z2#WQ1ktp_0P_Y6ob-Lr5|%Zvb3hL?(nw~Z65#<;>q=cpv<&r=k6UE&Rd{yUcS-{ zxaB1S{$Bk(OSdStNn{(da-nNqZMUS{X9xMM$2J!N-W;etD_CxN%T$nE{CQB&wV^|% zdD}rev(uTqcHGU-VD}VIZhq@hzUz1{9-ikGpk~xIdrfd8dTUA0=(Q47hTq-B%bb{h7o0XQ7qV_qcR6XzAhw-5~!xN5Ka+L!hEoGF%`AbEZ9BrV@ELHz1u=C#Tzh#;GAONEZo{Xg z#exFg>Ttdgi&uJCp++F5yK*VGb`BF3W94T+LowiHQm#O`5yQnuqN2t2GUqS~;+URV zP@s7@ODe=VUTOA?>qo1pLvo= z0D^H5H-Jj-HM3`BE1+Q`@>PQW9?mNJVux7VS}i8efw~Gno6iF46Zj)^t_7>vaco)9 zsv9U?&VTSVIPI@WX8SM`?!l-p%B&XSoTh|~en2U3rZek$ku=?h3^lb(V*6>9wwg6< ze88r>NF$b~aNor;xvmORj~@s6qQ2QR>}<319}g(DG7I7zI$Jfh$D&9k!BpL=uqHC+ z$n{{WFG8;moW8GVtakVSCZQ23a$7vroSxKaJWl*1-&^Y3SUQ%xGS)lR-y|6KnC98& z*+_%mv|1cxCI&{??qei-FLZYmS|h>t|J{YMtSh-X7Nz^0ZYQoxClinXp6G>{-15V$ zH@93$_NP`45Il%R(~WTrR1jY$=vF+r`o{$9H7th>8)C z0(;n3Zr!~?aai%vih?Y|Tr$bW z##OK5e>Rgk4EI4V-i&_8VR$%ubgmL@a{36_^+pUIs5$5IH%hsC#C`UF-fsaYqbL2r zUn8Q+iacv6V?hcw6V%GfT6W%%HWPF`Y>Fv7 z;O8LyB_9tsu}alh&2Dv3rPWQ!I_mMQlPB`CtQP-gbk;g=v)cJ>P{`m3o6pCFgB((4}Uc!Sdz_ zEHjo|Mz>tJshZ@dUp|`Mn5DrER_Wd)BTOxstX%W6ZN!xOIV8%>78-VKL|tN5O>(q& zr&gQDnU=}tsQr+FE}#_Nvim)7qu8eicyK1=DURQ3O+s-Xcc8<<2|+Vk32!c7Oq)C8 z`p3EIyuBr=kDYW4gF=f(f9BH5TK194o~Sv;+-os>nZ0?|!;iM3 zi~AOqYEPK8xaL}vEu=bQ^143I@Aav=m`_LZ#Z{B-mO{GbTg0nE*f(xWsL+OAZX<}; zp9}k{#z9yNH+yAf)!58=KFnOecdczDvi>3}lg;$GhZRhpk;> z?#L(EvXJ`L{^3_Lo-%a})A*oRW-%3RDxw0Z>7Y-z!-><@-#L9y~FMj*3r+>R? z!M~j(bKvMekj0Gu7$;Tifj?)mnc?zzw2ye>mYb?h%RqV|nMDbK6tM16}$tBNW6~JN_?*EfAH%nT9(EK);{)5;6DNbI=XB|?g{NEgw z`b->(7Tas;zDtolJ4M`NOz8M+IpE*|dY1T2jsKSk5=NTYiA955MZ8L|Yaj>#!jZnG zIH;B7W2 z1a_*x*c8p`Ki^~MPL)BXws@FXsKd^#8kPGS3N0n{GL-V$Eix#vT@y>Ch_anD+0n2mQg7V z>30NGlGIMN*X^D%j?mvVzx@fzJqsr+-n!>jlTxAFzbacgwz}dwK)#(y{)50%8(_wJ z(ZSf!zL=%w#(tP|$N~Kk(F8RkH=XYJZrK^H2ozuZS zm4gBXZn{u$Qp)m&IJ)~#Vfg_$;iQ~={E({iMY)YxYE670!?1nSn7mi-Y zVZ^)rFoYlI;`xc&>F()zBq>4Gx^pRdC-@-CcxJ6dX9$T+37tG!EXs#|xS+e*6v0ok zNgi#)=NvyT{!FM<3~wuI9o3voc6HO!=$I^9YJ|#UB-7yK4yAa+&b}ps`9zYW3{X82 zWorpc@jVQO4J(`&q0=EBuT9W?P0+riAAY7qg%qZl3G4XaLc~q}1dUsnb7qR117*x= zI#XZ+v)D;c4o}&jmgbGtQTOsb%-~t_N>L$opBsvpjUERmnQvw7LX93Ng2J4}x_Arn z-CrB;X?xOnd4Ri_-J&mx?C>hIGZnkU?e58Id3PV1|8qdI{BR|olMVyL%HZ!etqh~` zzKiY?`rWB%<7I9@$5>-0r`|{7Cwrzv?lI)I{R_17fhkm`F@CeJ4h6n}`dnr+RF1w# zt}9$YT_j&ncO43P({KSojr>!Y{Ek)!b5D*GuSFJ110M7HXsEVluW%Y%0Mu-Qq+a^r z@R5%AR%=M@)$iy`EKnZW{FimzS)O_6s`4J_>ED@H|I{8T`xH_@jP1MV|B_<Y?NCE)@RYVbpRg0-*Nsy&%DRG_5~S5L;)D0AU(d9iMu9X_l6;PBH4zd7$+ZvvwyZ`WbJVKtx>fTZ6yLTSH5}n$Ame-M4;q4-6c9}y z^mQ99YyY5@ZC>(-!}lDL@Uk;sC8mjzJeOlYsmrcZZK;c!`|-xQdgn_l^w$TzY3Xop zaDtTYD&nR@#sI`ajTYy^9zUTu8ks+&tIMFqBZ=MXYT|BdoY*dm(A>Dx~-h@8c z4}x))HA7e)_$I8o?vVdWWR=EA6q?>^4Vyladh~qUx0lj6l&ANcbF+Os$HnDI$zClF z8>_fH;=g=gXr=CEU#QYxc-lY8H6$yiy*J($MMds=ZJDFc3O^33+n{OZi3;>|JY=oN zBeAwV3%Kfi7`YjgA?$6w(--ju_({n@vP~s%nwq}G#;zsBb^%_sBxO4tP{&vtB#NgK zfM0WNb#Ar=MIVPU>Ira(umq+v3 z?4uR}_^Q2Ey4gS3$-=)?W^#UMD{r)ABk%_uv-ETsjyIrO*m4!eOe=sNsWkAbKy6-B zWT#FLh?v@k)RU(!=D%Clf+qF_f>E+bR07XL*6KFAs!9K6?r~(6H&*<6sZqxETrjfz z!BA-tJgQ69J=4vC*4oayo1tPNf=cK2b(>g?nSNn&G^;}L9^R+ZqDYq4ORS(@jX>bD zZcj)FLAC2?_eY7FUS!mDJAwWK~p5Oe~W_cKFK_e#(hS^&t~<&7Sz%q!4AD zgnGAOIUe>Gj0&0pyp;Pi4i;WBFL$#oNvtx$K+l)~#U^Cpex?ZeM~GCkgRgxNunJee zX)<7%7RY_|WYPwx zV(yox*ZS{q5o{T)2p~6TN0LEp@PT4-%U(A+5)8n!4C^T;271YlTClKmKY#^A_mdkx zJZr{ccb1hj7lY;sn{HqA7Lm}f7BA7oXkUR}e}dv{4@Fx|h(8IwtO2!ji)hZwdH@ix zfYk>MVvR;qNUrP+rF)qCR2Y(=!b*0+7FIej-R=D^=)Hutgzh|V%|4PWpTPMuD$dCt zTpIm)MqE)h0Qy%apQFy(7q0qCIEgS;xFa~Twhkg=ToFYI?7|Dpjh?RnmyveaGr6{G zM}PK5kRNOX_YrGF-RIQ$5)`Lp5W^>HaG;SVlkh1-=|KjX(&*P?ZeIj(^^x;>09I-$ z%4GponSYJ2l?TX+i@#G zeP5|%V^}8B@7}Mul_w++PegQc6G8N>K7R*WWz^}QvyrCioJ=XsraySFlMJF|SSfPU zEyJ5T2Pos_Jajv@Zfp=A!7PYM9pUO30+M2XV@vz{Tn{fVamx(IkQVs(INNZrV5n%l z4{c7$=q!s-#l9CePt1*TH>s$AmBm=)@V?#H7h1%!JY28v&T&i(gGRQ}4i&SmUHk3r zB_-i)+RW*VmKV2blP5Zkn8W5U`TY-mq0w&ey(4V2L%MEyura9C;Li9FkP?F@6biHR zz-s4)*w|QBh@>ZYqT{L$27@^l0FK*Z>z$D0MiG;*z`psnbt96hP{~*7=Q$(1>`-uq z!lqr4GG4~!&c3@P@EFQK7g}M8CVRGDcxyW&RO2!;DCh#wqjX{Ernw8P;p1)C(XQX` zcc!~%QF8pM4Xwv-IU2?s3KOcDn3<_^r`v|M32@+*EPsCHM2B*Ox{{JoLhm`Sc#sSH z(S5BUy~!h2cX1{QX18pb-0u}OQVw>OjrYv02FqQ86JuEsg;GJsWG`(KZK{DG9C@+n zhF(hWJ?Sh1WIB}g*Rvu%%mILAMqkO2n_bl=>8FJB+#TGx(N@PfX@}N8Bf512-#JV? zwx=w?9lZfy6&^MeDu@M(&*nNhFq7dgDJkfwX<@V`<{Gj+*vB&?Uhox23~LL(KHWc# zl?dFeiGy)q48PG18-BiiTq~NJrqMo@Ni4_nQEJ3i?2GFx-gprJZac2$;2zFo=p-CI zu=S63^pMSZxEWmBUT94oy-h0v$t1V&v9%6r<(a60JF`WCqVP~JT%|ddk0O@$*E6We zf(hbq+YlKElIlI942}W$*aZ@Bjb}_$WPCs!u6pE}eg`ce4P=b;rO9$r-l2ThWtv&m T#a)SzQ91`4ocCnfpSbiV0%~xm literal 0 HcmV?d00001 diff --git a/openair1/PHY/TOOLS/phy_scope_interface.c b/openair1/PHY/TOOLS/phy_scope_interface.c index 14f361362d..5b857312ba 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.c +++ b/openair1/PHY/TOOLS/phy_scope_interface.c @@ -58,7 +58,7 @@ int end_forms(void) { return -1; } -void copyData(void *scopeData, enum scopeDataType type, void *dataIn, int elementSz, int colSz, int lineSz, int offset) +void copyData(void *scopeData, enum scopeDataType type, void *dataIn, int elementSz, int colSz, int lineSz, int offset, metadata *meta) { scopeData_t *tmp = (scopeData_t *)scopeData; diff --git a/openair1/PHY/TOOLS/phy_scope_interface.h b/openair1/PHY/TOOLS/phy_scope_interface.h index 7c5e33b379..2d44e0cf45 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.h +++ b/openair1/PHY/TOOLS/phy_scope_interface.h @@ -70,7 +70,10 @@ enum scopeDataType { psbchDlChEstimateTime, psbchLlr, psbchRxdataF_comp, - MAX_SCOPE_TYPES + MAX_SCOPE_TYPES, + gNBPuschRxIq = MAX_SCOPE_TYPES, + gNBPuschLlr, + EXTRA_SCOPE_TYPES }; enum PlotTypeGnbIf { @@ -87,34 +90,70 @@ typedef struct { int lineSz; } scopeGraphData_t; +typedef struct { + int slot; + int frame; +} metadata; + typedef struct scopeData_s { int *argc; char **argv; RU_t *ru; PHY_VARS_gNB *gNB; scopeGraphData_t *liveData[MAX_SCOPE_TYPES]; - void (*copyData)(void *, enum scopeDataType, void *data, int elementSz, int colSz, int lineSz, int offset); + void (*copyData)(void *, enum scopeDataType, void *data, int elementSz, int colSz, int lineSz, int offset, metadata *meta); pthread_mutex_t copyDataMutex; scopeGraphData_t *copyDataBufs[MAX_SCOPE_TYPES][COPIES_MEM]; int copyDataBufsIdx[MAX_SCOPE_TYPES]; void (*scopeUpdater)(enum PlotTypeGnbIf plotType, int numElements); + bool (*tryLockScopeData)(enum scopeDataType type, int elementSz, int colSz, int lineSz, metadata *meta); + void (*copyDataUnsafeWithOffset)(enum scopeDataType type, void *dataIn, size_t size, size_t offset, int copy_index); + void (*unlockScopeData)(enum scopeDataType type); } scopeData_t; int load_softscope(char *exectype, void *initarg); int end_forms(void) ; int copyDataMutexInit(scopeData_t *); -void copyData(void *, enum scopeDataType type, void *dataIn, int elementSz, int colSz, int lineSz, int offset); +void copyData(void *, enum scopeDataType type, void *dataIn, int elementSz, int colSz, int lineSz, int offset, metadata *meta); +#define UEscopeCopyWithMetadata(ue, type, ...) \ + if (ue->scopeData) { \ + ((scopeData_t *)ue->scopeData)->copyData((scopeData_t *)ue->scopeData, type, ##__VA_ARGS__); \ + } #define UEscopeCopy(ue, type, ...) \ - if (ue->scopeData) \ - ((scopeData_t *)ue->scopeData)->copyData((scopeData_t *)ue->scopeData, type, ##__VA_ARGS__); + if (ue->scopeData) { \ + metadata mt = {.slot = -1, .frame = -1}; \ + ((scopeData_t *)ue->scopeData)->copyData((scopeData_t *)ue->scopeData, type, ##__VA_ARGS__, &mt); \ + } +#define gNBscopeCopyWithMetadata(gnb, type, ...) \ + if (gnb->scopeData) { \ + ((scopeData_t *)gnb->scopeData)->copyData((scopeData_t *)gNB->scopeData, type, ##__VA_ARGS__); \ + } #define gNBscopeCopy(gnb, type, ...) \ - if (gnb->scopeData) \ - ((scopeData_t *)gnb->scopeData)->copyData((scopeData_t *)gNB->scopeData, type, ##__VA_ARGS__); + if (gnb->scopeData) { \ + metadata mt = {.slot = -1, .frame = -1}; \ + ((scopeData_t *)gnb->scopeData)->copyData((scopeData_t *)gNB->scopeData, type, ##__VA_ARGS__, &mt); \ + } #define GnbScopeUpdate(gnb, type, numElt) \ if (gnb->scopeData) \ ((scopeData_t *)gnb->scopeData)->scopeUpdater(type, numElt); +#define gNBTryLockScopeData(gnb, type, ...) \ + gnb->scopeData && ((scopeData_t *)gnb->scopeData)->tryLockScopeData \ + && ((scopeData_t *)gnb->scopeData)->tryLockScopeData(type, ##__VA_ARGS__) + +#define gNBscopeCopyUnsafe(gnb, type, ...) \ + scopeData_t *scope_data = (scopeData_t *)gnb->scopeData; \ + if (scope_data && scope_data->copyDataUnsafeWithOffset) { \ + scope_data->copyDataUnsafeWithOffset(type, ##__VA_ARGS__); \ + } + +#define gNBunlockScopeData(gnb, type) \ + scopeData_t *scope_data = (scopeData_t *)gnb->scopeData; \ + if (scope_data && scope_data->unlockScopeData) { \ + scope_data->unlockScopeData(type); \ + } + extended_kpi_ue* getKPIUE(); #endif diff --git a/openair1/PHY/TOOLS/readme.md b/openair1/PHY/TOOLS/readme.md index 9a0e2947f9..566ff62b7b 100644 --- a/openair1/PHY/TOOLS/readme.md +++ b/openair1/PHY/TOOLS/readme.md @@ -31,3 +31,41 @@ or ``` phy_scope_gNB(0, phy_vars_gnb, phy_vars_ru, UE_id) ``` + +# ImScope + +ImScope is a scope based on imgui & implot. This scope uses a different concurrency model than xforms scope, with thread +safety being priority. The goal is to never show incorrect data on the screen and be able to use the scope with real radios. +If correctness cannot be achieved e.g. due to performance issues when using thread safe implementation user should be warned +clearly on the screen. + +![image](./imscope/imscope_screenshot.png) + +## Prerequisites + +ImScope uses imgui, implot, glfw3 and opengl. imgui and implot should be downloaded automatically when configuring the project +with `-DENABLE_IMSCOPE=ON`, using [CPM](https://github.com/cpm-cmake/CPM.cmake). CPM is used because imgui and implot do not have +an official binary release. glfw3 and opengl should be installed with your system, on ubuntu these are contained in packages +libglfw3-dev and libopengl-dev respectivly. + +## Building + +Add `-DENABLE_IMSCOPE=ON` to your `cmake` command. Build target `imscope` + +## Running + +Run with `-d` flag + +## Usage notes + + - It's experimental and might contain bugs + - It uses tree nodes to hide/show scopes (layout is subject to change). If a scope is not visible or is frozen it costs nearly + nothing in the PHY threads. If its unfrozen every time the data is displayed the PHY thread would have to perform the copy. By + default this can happen up to 24 times per second. User is informed on the estimated impact on PHY threads at the top of the + window. You can use FPS target to limit the impact on PHY threads and maintain scope functionality while minimizing the effect + on realtime operation. + +## Reporting bugs and feature requests + +Report bugs and feature requests on [gitlab](https://gitlab.eurecom.fr/oai/openairinterface5g/-/issues). There is two demo windows +enabled in the scope that showcase imgui/implot, if you find something of interest it can be implemented in the scope. From 6dcd3ae8c45e741dc57b80b2c84b7c9164bcedb2 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 3 Sep 2024 16:20:08 +0200 Subject: [PATCH 21/61] Use --imscope flag to enable/disable imscope --- executables/nr-softmodem.c | 13 +++++++------ executables/nr-uesoftmodem.c | 5 ++--- executables/softmodem-common.c | 5 +++++ executables/softmodem-common.h | 5 +++++ openair1/PHY/TOOLS/readme.md | 2 +- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 803c7bbdcd..c28b741406 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -734,18 +734,19 @@ int main( int argc, char **argv ) { printf("ALL RUs ready - init gNBs\n"); for (int idx=0;idxif_inst->sl_ahead = sl_ahead; - if (IS_SOFTMODEM_DOSCOPE) { + if (IS_SOFTMODEM_DOSCOPE || IS_SOFTMODEM_IMSCOPE_ENABLED) { sleep(1); scopeParms_t p; p.argc = &argc; p.argv = argv; p.gNB = RC.gNB[0]; p.ru = RC.ru[0]; -#ifndef ENABLE_IMSCOPE - load_softscope("nr", &p); -#else - load_softscope("im", &p); -#endif + if (IS_SOFTMODEM_DOSCOPE) { + load_softscope("nr", &p); + } + if (IS_SOFTMODEM_IMSCOPE_ENABLED) { + load_softscope("im", &p); + } } if (NFAPI_MODE != NFAPI_MODE_PNF && NFAPI_MODE != NFAPI_MODE_VNF && NFAPI_MODE != NFAPI_MODE_AERIAL) { diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 3550a0a9ff..99ce9040d4 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -522,11 +522,10 @@ int main(int argc, char **argv) lock_memory_to_ram(); if (IS_SOFTMODEM_DOSCOPE) { -#ifndef ENABLE_IMSCOPE load_softscope("nr", PHY_vars_UE_g[0][0]); -#else + } + if (IS_SOFTMODEM_IMSCOPE_ENABLED) { load_softscope("im", PHY_vars_UE_g[0][0]); -#endif } for (int inst = 0; inst < NB_UE_INST; inst++) { diff --git a/executables/softmodem-common.c b/executables/softmodem-common.c index be2a79eb64..d566767902 100644 --- a/executables/softmodem-common.c +++ b/executables/softmodem-common.c @@ -99,6 +99,7 @@ void get_common_options(configmodule_interface_t *cfg, uint32_t execmask) uint32_t start_websrv = 0; uint32_t noS1 = 0, nonbiot = 0; uint32_t rfsim = 0, do_forms = 0; + uint32_t enable_imscope = 0; int nfapi_index = 0; char *logmem_filename = NULL; check_execmask(execmask); @@ -158,6 +159,10 @@ void get_common_options(configmodule_interface_t *cfg, uint32_t execmask) set_softmodem_optmask(SOFTMODEM_DOSCOPE_BIT); } + if (enable_imscope) { + set_softmodem_optmask(SOFTMODEM_IMSCOPE_BIT); + } + if (start_websrv) { load_module_shlib("websrv", NULL, 0, NULL); } diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 110a5c60a7..a336a77d50 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -76,6 +76,7 @@ extern "C" #define CONFIG_HLP_256QAM "Use the 256 QAM mcs table for PDSCH\n" #define CONFIG_HLP_CHESTFREQ "Set channel estimation type in frequency domain. 0-Linear interpolation (default). 1-PRB based averaging of channel estimates in frequency. \n" #define CONFIG_HLP_CHESTTIME "Set channel estimation type in time domain. 0-Symbols take estimates of the last preceding DMRS symbol (default). 1-Symbol based averaging of channel estimates in time. \n" +#define CONFIG_HLP_IMSCOPE "Enable phy scope based on imgui and implot" #define CONFIG_HLP_NONSTOP "Go back to frame sync mode after 100 consecutive PBCH failures\n" //#define CONFIG_HLP_NUMUES "Set the number of UEs for the emulation" @@ -188,6 +189,7 @@ extern int usrp_tx_thread; {"sync-ref", CONFIG_HLP_SYNC_REF, 0, .uptr=&SYNC_REF, .defintval=0, TYPE_UINT, 0}, \ {"A" , CONFIG_HLP_TADV, 0, .iptr=&softmodem_params.command_line_sample_advance,.defintval=0, TYPE_INT, 0}, \ {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \ + {"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \ } // clang-format on @@ -235,6 +237,7 @@ extern int usrp_tx_thread; { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } // clang-format on @@ -288,6 +291,7 @@ extern int usrp_tx_thread; #define SOFTMODEM_4GUE_BIT (1<<22) #define SOFTMODEM_5GUE_BIT (1<<23) #define SOFTMODEM_NOSTATS_BIT (1<<24) +#define SOFTMODEM_IMSCOPE_BIT (1<<25) #define SOFTMODEM_FUNC_BITS (SOFTMODEM_ENB_BIT | SOFTMODEM_GNB_BIT | SOFTMODEM_5GUE_BIT | SOFTMODEM_4GUE_BIT) #define MAPPING_SOFTMODEM_FUNCTIONS {{"enb",SOFTMODEM_ENB_BIT},{"gnb",SOFTMODEM_GNB_BIT},{"4Gue",SOFTMODEM_4GUE_BIT},{"5Gue",SOFTMODEM_5GUE_BIT}} @@ -307,6 +311,7 @@ extern int usrp_tx_thread; #define IS_SOFTMODEM_4GUE_BIT ( get_softmodem_optmask() & SOFTMODEM_4GUE_BIT) #define IS_SOFTMODEM_5GUE_BIT ( get_softmodem_optmask() & SOFTMODEM_5GUE_BIT) #define IS_SOFTMODEM_NOSTATS_BIT ( get_softmodem_optmask() & SOFTMODEM_NOSTATS_BIT) +#define IS_SOFTMODEM_IMSCOPE_ENABLED ( get_softmodem_optmask() & SOFTMODEM_IMSCOPE_BIT) typedef struct { uint64_t optmask; diff --git a/openair1/PHY/TOOLS/readme.md b/openair1/PHY/TOOLS/readme.md index 566ff62b7b..9d1f4d465b 100644 --- a/openair1/PHY/TOOLS/readme.md +++ b/openair1/PHY/TOOLS/readme.md @@ -54,7 +54,7 @@ Add `-DENABLE_IMSCOPE=ON` to your `cmake` command. Build target `imscope` ## Running -Run with `-d` flag +Run with `--imscope` flag ## Usage notes From d8bba3124feba29e754f4f49e0888b8ab61ac3ad Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 3 Sep 2024 16:21:51 +0200 Subject: [PATCH 22/61] Add imscope to optional libraries in ./build_oai --- cmake_targets/build_oai | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index cd7e326be8..1d04174aea 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -46,7 +46,7 @@ BUILD_DOXYGEN=0 DISABLE_HARDWARE_DEPENDENCY="False" CMAKE_BUILD_TYPE="RelWithDebInfo" CMAKE_CMD="$CMAKE" -OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 websrv oai_iqplayer" +OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope ldpc_cuda ldpc_t2 websrv oai_iqplayer imscope" TARGET_LIST="" function print_help() { From 70dd524e2b0ffcea1f516cb04ef64cc903bd5289 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Sep 2024 15:26:09 +0200 Subject: [PATCH 23/61] Define softmodem bits in a separate header for either C and C++ --- executables/softmodem-bits.h | 61 ++++++++++++++++++++++++++ executables/softmodem-common.h | 17 +------ openair1/PHY/TOOLS/imscope/imscope.cpp | 5 +-- 3 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 executables/softmodem-bits.h diff --git a/executables/softmodem-bits.h b/executables/softmodem-bits.h new file mode 100644 index 0000000000..6d527148cd --- /dev/null +++ b/executables/softmodem-bits.h @@ -0,0 +1,61 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef SOFTMODEM_BITS_H +#define SOFTMODEM_BITS_H + +// clang-format off +#define BIT_0 (1 << 0) +#define BIT_1 (1 << 1) +#define BIT_2 (1 << 2) +#define BIT_10 (1 << 10) +#define BIT_12 (1 << 12) +#define BIT_13 (1 << 13) +#define BIT_15 (1 << 15) +#define BIT_16 (1 << 16) +#define BIT_17 (1 << 17) +#define BIT_18 (1 << 18) +#define BIT_20 (1 << 20) +#define BIT_21 (1 << 21) +#define BIT_22 (1 << 22) +#define BIT_23 (1 << 23) +#define BIT_24 (1 << 24) +#define BIT_25 (1 << 25) + +#define SOFTMODEM_NOS1_BIT BIT_0 +#define SOFTMODEM_NOKRNMOD_BIT BIT_1 +#define SOFTMODEM_NONBIOT_BIT BIT_2 +#define SOFTMODEM_RFSIM_BIT BIT_10 +#define SOFTMODEM_SIML1_BIT BIT_12 +#define SOFTMODEM_DLSIM_BIT BIT_13 +#define SOFTMODEM_DOSCOPE_BIT BIT_15 +#define SOFTMODEM_RECPLAY_BIT BIT_16 +#define SOFTMODEM_TELNETCLT_BIT BIT_17 +#define SOFTMODEM_RECRECORD_BIT BIT_18 +#define SOFTMODEM_ENB_BIT BIT_20 +#define SOFTMODEM_GNB_BIT BIT_21 +#define SOFTMODEM_4GUE_BIT BIT_22 +#define SOFTMODEM_5GUE_BIT BIT_23 +#define SOFTMODEM_NOSTATS_BIT BIT_24 +#define SOFTMODEM_IMSCOPE_BIT BIT_25 +// clang-format on + +#endif // SOFTMODEM_BITS_H diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index a336a77d50..141afa1a37 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -32,6 +32,7 @@ #ifndef SOFTMODEM_COMMON_H #define SOFTMODEM_COMMON_H #include "openair1/PHY/defs_common.h" +#include "softmodem-bits.h" #ifdef __cplusplus extern "C" { @@ -277,22 +278,6 @@ extern int usrp_tx_thread; /***************************************************************************************************************************************/ -#define SOFTMODEM_NOS1_BIT (1<<0) -#define SOFTMODEM_NONBIOT_BIT (1<<2) -#define SOFTMODEM_RFSIM_BIT (1<<10) -#define SOFTMODEM_SIML1_BIT (1<<12) -#define SOFTMODEM_DLSIM_BIT (1<<13) -#define SOFTMODEM_DOSCOPE_BIT (1<<15) -#define SOFTMODEM_RECPLAY_BIT (1<<16) -#define SOFTMODEM_TELNETCLT_BIT (1<<17) -#define SOFTMODEM_RECRECORD_BIT (1<<18) -#define SOFTMODEM_ENB_BIT (1<<20) -#define SOFTMODEM_GNB_BIT (1<<21) -#define SOFTMODEM_4GUE_BIT (1<<22) -#define SOFTMODEM_5GUE_BIT (1<<23) -#define SOFTMODEM_NOSTATS_BIT (1<<24) -#define SOFTMODEM_IMSCOPE_BIT (1<<25) - #define SOFTMODEM_FUNC_BITS (SOFTMODEM_ENB_BIT | SOFTMODEM_GNB_BIT | SOFTMODEM_5GUE_BIT | SOFTMODEM_4GUE_BIT) #define MAPPING_SOFTMODEM_FUNCTIONS {{"enb",SOFTMODEM_ENB_BIT},{"gnb",SOFTMODEM_GNB_BIT},{"4Gue",SOFTMODEM_4GUE_BIT},{"5Gue",SOFTMODEM_5GUE_BIT}} diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp index 591e611be9..687226940f 100644 --- a/openair1/PHY/TOOLS/imscope/imscope.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -42,6 +42,7 @@ uint64_t get_softmodem_optmask(void); #include #include #include +#include "executables/softmodem-bits.h" #define MAX_OFFSETS 14 #define NR_MAX_RB 273 @@ -617,7 +618,6 @@ void *imscope_thread(void *data_void_ptr) static double last_frame_time = glfwGetTime(); static int target_fps = 24; - const int SOFTMODEM_5GUE_BIT = 1 << 23; bool is_ue = (get_softmodem_optmask() & SOFTMODEM_5GUE_BIT) > 0; while (!glfwWindowShouldClose(window)) { // Poll and handle events (inputs, window resize, etc.) @@ -704,9 +704,6 @@ void *imscope_thread(void *data_void_ptr) extern "C" void imscope_autoinit(void *dataptr) { - // Copied here due to issues with headers - const int SOFTMODEM_GNB_BIT = 1 << 21; - const int SOFTMODEM_5GUE_BIT = 1 << 23; AssertFatal((get_softmodem_optmask() & SOFTMODEM_5GUE_BIT) || (get_softmodem_optmask() & SOFTMODEM_GNB_BIT), "Scope cannot find NRUE or GNB context"); From 8eb9e3d90257d663c14a672e6d1fb4fc059db3f8 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Wed, 4 Sep 2024 17:51:28 +0200 Subject: [PATCH 24/61] Fix pdschRxdataF_comp phy scope data source pdschRxdataF_comp data source was handled incorrectly. Each symbol entire slot data was copied. This caused pdschRxdataF_comp to mostly contain zeros. The call to UEscopeCopy was moved from symbol loop into last symbol processing. In case imscope is used padding and unused REs are not copied to the sink. Added checks inside scope functions to ensure correct functionality. --- .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 19 ++++++++++++++++++- openair1/PHY/TOOLS/imscope/imscope.cpp | 9 +++++++++ openair1/PHY/TOOLS/phy_scope_interface.h | 19 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 6537e4b840..cb2359c675 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -736,6 +736,24 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, } */ #endif + if (UEScopeHasTryLock(ue)) { + metadata mt = {.frame = proc->frame_rx, .slot = proc->nr_slot_rx }; + int total_valid_res = 0; + for (int i = startSymbIdx; i < startSymbIdx + nbSymb; i++) { + total_valid_res = dl_valid_re[i - 1]; + } + if (UETryLockScopeData(ue, pdschRxdataF_comp, sizeof(c16_t), 1, total_valid_res, &mt)) { + size_t offset = 0; + for (int i = startSymbIdx; i < startSymbIdx + nbSymb; i++) { + size_t data_size = sizeof(c16_t) * dl_valid_re[i - i]; + UEscopeCopyUnsafe(ue, pdschRxdataF_comp, &rxdataF_comp[0][0][rx_size_symbol * i], data_size, offset, i - startSymbIdx); + offset += data_size; + } + UEunlockScopeData(ue, pdschRxdataF_comp) + } + } else { + UEscopeCopy(ue, pdschRxdataF_comp, rxdataF_comp[0], sizeof(c16_t), nbRx, rx_size_symbol * NR_SYMBOLS_PER_SLOT, 0); + } } if (meas_enabled) { @@ -759,7 +777,6 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, T_INT(frame_parms->symbols_per_slot), T_BUFFER(&rxdataF_comp[gNB_id][0], 2 * /* ulsch[UE_id]->harq_processes[harq_pid]->nb_rb */ frame_parms->N_RB_UL * 12 * 2)); #endif - UEscopeCopy(ue, pdschRxdataF_comp, rxdataF_comp[0], sizeof(c16_t), nbRx, rx_size_symbol * NR_SYMBOLS_PER_SLOT, 0); if (ue->phy_sim_pdsch_rxdataF_comp) for (int a = 0; a < nbRx; a++) { diff --git a/openair1/PHY/TOOLS/imscope/imscope.cpp b/openair1/PHY/TOOLS/imscope/imscope.cpp index 687226940f..8205c85b9e 100644 --- a/openair1/PHY/TOOLS/imscope/imscope.cpp +++ b/openair1/PHY/TOOLS/imscope/imscope.cpp @@ -74,6 +74,7 @@ typedef struct ImScopeData { metadata meta; uint64_t time_taken_in_ns; uint64_t time_taken_in_ns_per_offset[MAX_OFFSETS]; + size_t data_copied_per_offset[MAX_OFFSETS]; } ImScopeData; typedef struct MovingAverageTimer { @@ -811,6 +812,7 @@ bool tryLockScopeData(enum scopeDataType type, int elementSz, int colSz, int lin scope_data.time_taken_in_ns = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count(); memset(scope_data.time_taken_in_ns_per_offset, 0, sizeof(scope_data.time_taken_in_ns_per_offset)); + memset(scope_data.data_copied_per_offset, 0, sizeof(scope_data.data_copied_per_offset)); return true; } return false; @@ -818,6 +820,7 @@ bool tryLockScopeData(enum scopeDataType type, int elementSz, int colSz, int lin void copyDataUnsafeWithOffset(enum scopeDataType type, void *dataIn, size_t size, size_t offset, int copy_index) { + AssertFatal(copy_index < MAX_OFFSETS, "Unexpected number of copies per sink. copy_index = %d\n", copy_index); ImScopeData &scope_data = scope_array[type]; auto start = std::chrono::high_resolution_clock::now(); scopeGraphData_t *data = scope_data.scope_graph_data; @@ -825,13 +828,19 @@ void copyDataUnsafeWithOffset(enum scopeDataType type, void *dataIn, size_t size memcpy(&outptr[offset], dataIn, size); scope_data.time_taken_in_ns_per_offset[copy_index] = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count(); + scope_data.data_copied_per_offset[copy_index] = size; } void unlockScopeData(enum scopeDataType type) { ImScopeData &scope_data = scope_array[type]; + size_t total_size = 0; for (auto i = 0; i < MAX_OFFSETS; i++) { scope_data.time_taken_in_ns += scope_data.time_taken_in_ns_per_offset[i]; + total_size += scope_data.data_copied_per_offset[i]; + } + if (total_size != (uint64_t)scope_data.scope_graph_data->dataSize) { + LOG_E(PHY, "Scope is missing data - not all data that was expected was copied - possibly missed copyDataUnsafeWithOffset call\n"); } scope_data.is_data_ready = true; scope_data.write_mutex.unlock(); diff --git a/openair1/PHY/TOOLS/phy_scope_interface.h b/openair1/PHY/TOOLS/phy_scope_interface.h index 2d44e0cf45..2f8378e7b7 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.h +++ b/openair1/PHY/TOOLS/phy_scope_interface.h @@ -154,6 +154,25 @@ void copyData(void *, enum scopeDataType type, void *dataIn, int elementSz, int scope_data->unlockScopeData(type); \ } +#define UEScopeHasTryLock(ue) \ + (ue->scopeData && ((scopeData_t *)ue->scopeData)->tryLockScopeData) + +#define UETryLockScopeData(ue, type, ...) \ + ue->scopeData && ((scopeData_t *)ue->scopeData)->tryLockScopeData \ + && ((scopeData_t *)ue->scopeData)->tryLockScopeData(type, ##__VA_ARGS__) + +#define UEscopeCopyUnsafe(ue, type, ...) \ + scopeData_t *scope_data = (scopeData_t *)ue->scopeData; \ + if (scope_data && scope_data->copyDataUnsafeWithOffset) { \ + scope_data->copyDataUnsafeWithOffset(type, ##__VA_ARGS__); \ + } + +#define UEunlockScopeData(ue, type) \ + scopeData_t *scope_data = (scopeData_t *)ue->scopeData; \ + if (scope_data && scope_data->unlockScopeData) { \ + scope_data->unlockScopeData(type); \ + } + extended_kpi_ue* getKPIUE(); #endif From e1879c07bc472a9e664b24686811089ad25719fc Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Thu, 5 Sep 2024 15:21:07 +0200 Subject: [PATCH 25/61] Fix segfault when attempting to use unsupported scope types in nrscope Do not attempt to copy scope types >= MAX_SCOPE_TYPES in nrscope as it does not support them at this point. --- openair1/PHY/TOOLS/phy_scope_interface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair1/PHY/TOOLS/phy_scope_interface.c b/openair1/PHY/TOOLS/phy_scope_interface.c index 5b857312ba..70d3889b64 100644 --- a/openair1/PHY/TOOLS/phy_scope_interface.c +++ b/openair1/PHY/TOOLS/phy_scope_interface.c @@ -60,6 +60,9 @@ int end_forms(void) { void copyData(void *scopeData, enum scopeDataType type, void *dataIn, int elementSz, int colSz, int lineSz, int offset, metadata *meta) { + if (type >= MAX_SCOPE_TYPES) { + return; + } scopeData_t *tmp = (scopeData_t *)scopeData; if (tmp) { From 0b684732eef24ce48cecc4dd8d02e69c5257cbdc Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Fri, 5 Jul 2024 18:10:40 +0200 Subject: [PATCH 26/61] YAML as a drop-in replacement for libconfig This commit introduces a substitute module library for setting up softmodems using YAML instead of libconfig. The softmodems should work the same with both types of files. Extra care was put to make sure the behavior of both modules is the same. Example yaml config files were added for the UE and gNB --- ci-scripts/conf_files/nrue.uicc.yaml | 28 ++ cmake_targets/tools/build_helper | 8 +- common/CMakeLists.txt | 1 + common/config/config_load_configmodule.c | 8 +- common/config/yaml/CMakeLists.txt | 26 ++ common/config/yaml/config_yaml.cpp | 327 +++++++++++++++ common/config/yaml/tests/CMakeLists.txt | 11 + common/config/yaml/tests/test1.yaml | 4 + common/config/yaml/tests/test_int_array.yaml | 6 + common/config/yaml/tests/test_list.yaml | 13 + .../yaml/tests/test_list_of_mappings.yml | 14 + common/config/yaml/tests/test_recursion.yaml | 8 + common/config/yaml/tests/test_string.yaml | 6 + common/config/yaml/tests/test_yaml_config.cpp | 373 ++++++++++++++++++ .../gnb.sa.band78.fr1.106PRB.usrpb210.yaml | 221 +++++++++++ 15 files changed, 1049 insertions(+), 5 deletions(-) create mode 100644 ci-scripts/conf_files/nrue.uicc.yaml create mode 100644 common/config/yaml/CMakeLists.txt create mode 100644 common/config/yaml/config_yaml.cpp create mode 100644 common/config/yaml/tests/CMakeLists.txt create mode 100644 common/config/yaml/tests/test1.yaml create mode 100644 common/config/yaml/tests/test_int_array.yaml create mode 100644 common/config/yaml/tests/test_list.yaml create mode 100644 common/config/yaml/tests/test_list_of_mappings.yml create mode 100644 common/config/yaml/tests/test_recursion.yaml create mode 100644 common/config/yaml/tests/test_string.yaml create mode 100644 common/config/yaml/tests/test_yaml_config.cpp create mode 100644 targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.yaml diff --git a/ci-scripts/conf_files/nrue.uicc.yaml b/ci-scripts/conf_files/nrue.uicc.yaml new file mode 100644 index 0000000000..518315c7ff --- /dev/null +++ b/ci-scripts/conf_files/nrue.uicc.yaml @@ -0,0 +1,28 @@ +uicc0: + imsi: 208990100001100 + key: fec86ba6eb707ed08905757b1bb44b8f + opc: C42449363BBAD02B66D16BC975D77CC1 + dnn: oai + nssai_sst: 1 + +#/* configuration for channel modelisation */ +#/* To be included in main config file when */ +#/* channel modelisation is used (rfsimulator with chanmod options enabled) */ +channelmod: + max_chan: 10; + modellist: modellist_rfsimu_1 + modellist_rfsimu_1: + - model_name: rfsimu_channel_enB0 + type: AWGN + ploss_dB: 20 + noise_power_dB: -4 + forgetfact: 0 + offset: 0 + ds_tdl: 0 + - model_name: rfsimu_channel_ue0 + type: AWGN + ploss_dB: 20 + nose_power_dB: -2 + forgetfact: 0 + offset: 0 + ds_tdl: 0 diff --git a/cmake_targets/tools/build_helper b/cmake_targets/tools/build_helper index 30cb1f0b00..23558bfe56 100755 --- a/cmake_targets/tools/build_helper +++ b/cmake_targets/tools/build_helper @@ -589,8 +589,9 @@ check_install_oai_software() { libtool \ patch \ openssl \ - zlib1g-dev \ - xxd + zlib1g-dev \ + xxd \ + libyaml-cpp-dev elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then if [[ "$OS_DISTRO" == "rhel" ]] || [[ "$OS_DISTRO" == "centos" ]] || [[ "$OS_DISTRO" == "rocky" ]]; then @@ -625,7 +626,8 @@ check_install_oai_software() { blas \ blas-devel \ vim-common \ - zlib-devel + zlib-devel \ + yaml-cpp-devel fi install_asn1c_from_source $1 diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 6c2d123397..14c4ac582a 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(utils) +add_subdirectory(config/yaml) configure_file(oai_version.h.in oai_version.h @ONLY) diff --git a/common/config/config_load_configmodule.c b/common/config/config_load_configmodule.c index 411e737976..71cab2a33a 100644 --- a/common/config/config_load_configmodule.c +++ b/common/config/config_load_configmodule.c @@ -293,8 +293,12 @@ configmodule_interface_t *load_configmodule(int argc, } else if ( i == 1 ) { /* -O argument doesn't contain ":" separator, assume -O option, default cfgmode to libconfig with one parameter, the path to the configuration file cfgmode must not be NULL */ - modeparams=cfgmode; - cfgmode=strdup(CONFIG_LIBCONFIGFILE); + modeparams = cfgmode; + if (strstr(modeparams, ".yaml") != NULL || strstr(modeparams, ".yml") != NULL) { + cfgmode = strdup("yaml"); + } else { + cfgmode = strdup(CONFIG_LIBCONFIGFILE); + } } static configmodule_interface_t *cfgptr; if (cfgptr) diff --git a/common/config/yaml/CMakeLists.txt b/common/config/yaml/CMakeLists.txt new file mode 100644 index 0000000000..67d90a0099 --- /dev/null +++ b/common/config/yaml/CMakeLists.txt @@ -0,0 +1,26 @@ +find_package(yaml-cpp REQUIRED) + +# include(FetchContent) + +# FetchContent_Declare( +# yaml-cpp +# GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git +# GIT_TAG 0.8.0 +# ) +# FetchContent_GetProperties(yaml-cpp) + +# if(NOT yaml-cpp_POPULATED) +# message(STATUS "Fetching yaml-cpp...") +# FetchContent_Populate(yaml-cpp) +# add_subdirectory(${yaml-cpp_SOURCE_DIR} ${yaml-cpp_BINARY_DIR}) +# endif() + +add_library(params_yaml_static config_yaml.cpp) +target_link_libraries(params_yaml_static PUBLIC UTIL yaml-cpp) +if (ENABLE_TESTS) + add_subdirectory(tests) +endif() + +add_library(params_yaml MODULE config_yaml.cpp) +target_link_libraries(params_yaml PUBLIC UTIL yaml-cpp) +set_target_properties(params_yaml PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/common/config/yaml/config_yaml.cpp b/common/config/yaml/config_yaml.cpp new file mode 100644 index 0000000000..c2af51e2db --- /dev/null +++ b/common/config/yaml/config_yaml.cpp @@ -0,0 +1,327 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "yaml-cpp/yaml.h" +extern "C" { +#include "common/config/config_load_configmodule.h" +#include "common/config/config_userapi.h" +void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree); +void config_check_valptr(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int elt_sz, int nb_elt); +} +#include +#include +#include +#include +#include + +namespace config_yaml { +class YamlConfig { + public: + YAML::Node config; + YamlConfig(std::string filename) + { + config = YAML::LoadFile(filename); + } +}; + +void SetDefault(configmodule_interface_t *cfg, paramdef_t *param) +{ + switch (param->type) { + case TYPE_INT: + *param->iptr = param->defintval; + break; + case TYPE_UINT: + *param->uptr = param->defuintval; + break; + case TYPE_STRING: + if (param->defstrval != nullptr) { + if (param->numelt == 0) { + config_check_valptr(cfg, param, 1, strlen(param->defstrval) + 1); + } + sprintf(*param->strptr, "%s", param->defstrval); + } + break; + case TYPE_INT8: + *param->i8ptr = param->defintval; + break; + case TYPE_UINT8: + *param->i8ptr = param->defuintval; + break; + case TYPE_INT16: + *param->i16ptr = param->defintval; + break; + case TYPE_UINT16: + *param->u16ptr = param->defuintval; + break; + case TYPE_INT64: + *param->i64ptr = param->defint64val; + break; + case TYPE_UINT64: + *param->u64ptr = param->defint64val; + break; + case TYPE_DOUBLE: + *param->dblptr = param->defdblval; + break; + case TYPE_MASK: + *param->uptr = param->defuintval; + break; + case TYPE_STRINGLIST: + if (param->defstrlistval != nullptr) { + param->strlistptr = param->defstrlistval; + } + break; + case TYPE_INTARRAY: + if (param->defintarrayval) { + param->iptr = param->defintarrayval; + } + break; + case TYPE_UINTARRAY: + if (param->defintarrayval) { + param->uptr = (uint32_t *)param->defintarrayval; + } + break; + default: + AssertFatal(false, "Unhandled type %d", param->type); + } + param->paramflags |= PARAMFLAG_PARAMSETDEF; +} + +void SetNonDefault(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *param) +{ + auto optname = std::string(param->optname); + switch (param->type) { + case TYPE_INT: + *param->iptr = node[optname].as(); + break; + case TYPE_UINT: + *param->uptr = node[optname].as(); + break; + case TYPE_STRING: { + std::string setting = node[optname].as(); + config_check_valptr(cfg, param, 1, setting.length() + 1); + sprintf(*param->strptr, "%s", setting.c_str()); + break; + } + case TYPE_UINT8: + *param->i8ptr = node[optname].as(); + break; + case TYPE_INT16: + *param->i16ptr = node[optname].as(); + break; + case TYPE_UINT16: + *param->u16ptr = node[optname].as(); + break; + case TYPE_INT64: + *param->i64ptr = node[optname].as(); + break; + case TYPE_UINT64: + *param->u64ptr = node[optname].as(); + break; + case TYPE_DOUBLE: + *param->dblptr = node[optname].as(); + break; + case TYPE_MASK: + *param->uptr = node[optname].as(); + break; + case TYPE_STRINGLIST: { + if (node[optname].IsSequence()) { + config_check_valptr(cfg, param, sizeof(char *), node[optname].size()); + int i = 0; + for (const auto &elem : node[optname]) { + sprintf(param->strlistptr[i], "%s", elem.as().c_str()); + i++; + } + param->numelt = i; + } else { + param->numelt = 0; + } + break; + } + case TYPE_INTARRAY: { + if (node[optname].IsSequence() && node[optname].size() > 0) { + param->numelt = node[optname].size(); + param->iptr = + (int32_t *)config_allocate_new(cfg, param->numelt * sizeof(*param->iptr), !(param->paramflags & PARAMFLAG_NOFREE)); + + for (int i = 0; i < param->numelt; i++) { + param->iptr[i] = node[optname][i].as(); + } + } else { + param->numelt = 0; + } + break; + } + case TYPE_UINTARRAY: { + if (node[optname].IsSequence() && node[optname].size() > 0) { + param->numelt = node[optname].size(); + param->uptr = + (uint32_t *)config_allocate_new(cfg, param->numelt * sizeof(*param->uptr), !(param->paramflags & PARAMFLAG_NOFREE)); + + for (int i = 0; i < param->numelt; i++) { + param->uptr[i] = node[optname][i].as(); + } + } else { + param->numelt = 0; + } + break; + } + default: + AssertFatal(false, "Unhandled type %d", param->type); + } + param->paramflags |= PARAMFLAG_PARAMSET; +} + +void GetParams(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *params, int num_params) +{ + for (auto i = 0; i < num_params; i++) { + if (node && node[std::string(params[i].optname)]) { + SetNonDefault(cfg, node, ¶ms[i]); + } else { + SetDefault(cfg, ¶ms[i]); + } + } +} + +static YamlConfig *config; +static YAML::Node invalid_node; +} // namespace config_yaml + +extern "C" int config_yaml_init(configmodule_interface_t *cfg) +{ + char **cfgP = cfg->cfgP; + cfg->numptrs = 0; + pthread_mutex_init(&cfg->memBlocks_mutex, NULL); + memset(cfg->oneBlock, 0, sizeof(cfg->oneBlock)); + + config_yaml::config = new config_yaml::YamlConfig(std::string(cfgP[0])); + return 0; +} + +extern "C" void config_yaml_end(configmodule_interface_t *cfg) +{ + delete config_yaml::config; +} + +YAML::Node find_node(const std::string &prefix, YAML::Node node) +{ + // Iterate through each key in the prefix + std::stringstream ss(prefix); + std::string key; + YAML::Node current = node; + + while (std::getline(ss, key, '.')) { + if (key.at(0) == '[' && key.back() == ']') { + // The key is an index to a sequence + if (!current.IsSequence()) { + throw std::invalid_argument("Incorrect yaml file structure"); + } + int index = std::stoi(key.substr(1, key.size() - 2)); + current = current[index]; + continue; + } + if (!current.IsMap()) { + throw std::invalid_argument("Incorrect yaml file structure"); + } + if (!current[key]) { + return config_yaml::invalid_node; + } + current = current[key]; + } + return current; +} + +extern "C" int config_yaml_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix) +{ + std::string p; + if (prefix != nullptr) { + p = std::string(prefix); + } + auto node = find_node(p, YAML::Clone(config_yaml::config->config)); + if (node == config_yaml::invalid_node) { + return -1; + } + for (auto i = 0; i < numoptions; i++) { + if (cfgoptions[i].type != TYPE_STRING && cfgoptions[i].type != TYPE_INTARRAY && cfgoptions[i].type != TYPE_UINTARRAY + && cfgoptions[i].voidptr == nullptr) { + config_check_valptr(cfg, &cfgoptions[i], sizeof(void *), 1); + } + } + config_yaml::GetParams(cfg, node, cfgoptions, numoptions); + return 0; +} + +extern "C" int config_yaml_getlist(configmodule_interface_t *cfg, + paramlist_def_t *ParamList, + paramdef_t *params, + int numparams, + char *prefix) +{ + char path[512]; + if (prefix != nullptr) { + sprintf(path, "%s.%s", prefix, ParamList->listname); + } else { + sprintf(path, "%s", ParamList->listname); + } + ParamList->numelt = 0; + auto node = find_node(path, YAML::Clone(config_yaml::config->config)); + if (node == config_yaml::invalid_node) { + return -1; + } + + if (!node.IsSequence()) { + return -1; + } + ParamList->numelt = node.size(); + + if (ParamList->numelt > 0 && params != NULL) { + ParamList->paramarray = static_cast(config_allocate_new(cfg, ParamList->numelt * sizeof(paramdef_t *), true)); + + for (int i = 0; i < ParamList->numelt; i++) { + ParamList->paramarray[i] = static_cast(config_allocate_new(cfg, numparams * sizeof(paramdef_t), true)); + memcpy(ParamList->paramarray[i], params, sizeof(paramdef_t) * numparams); + + for (int j = 0; j < numparams; j++) { + ParamList->paramarray[i][j].strptr = NULL; + if (ParamList->paramarray[i][j].type != TYPE_STRING) { + config_check_valptr(cfg, &ParamList->paramarray[i][j], sizeof(void *), 1); + } + } + + config_yaml::GetParams(cfg, node[i], ParamList->paramarray[i], numparams); + } + } + + return ParamList->numelt; +} + +extern "C" void config_yaml_write_parsedcfg(configmodule_interface_t *cfg) +{ + (void)cfg; +} + +extern "C" int config_yaml_set(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix) +{ + (void)cfg; + (void)cfgoptions; + (void)numoptions; + (void)prefix; + return 0; +} diff --git a/common/config/yaml/tests/CMakeLists.txt b/common/config/yaml/tests/CMakeLists.txt new file mode 100644 index 0000000000..b28bb8d47f --- /dev/null +++ b/common/config/yaml/tests/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(test_yaml_config test_yaml_config.cpp) +target_link_libraries(test_yaml_config PRIVATE params_yaml_static GTest::gtest) +add_dependencies(tests test_yaml_config) +add_test(NAME test_yaml_config + COMMAND ./test_yaml_config) +configure_file(test1.yaml test1.yaml COPYONLY) +configure_file(test_recursion.yaml test_recursion.yaml COPYONLY) +configure_file(test_list.yaml test_list.yaml COPYONLY) +configure_file(test_string.yaml test_string.yaml COPYONLY) +configure_file(test_list_of_mappings.yml test_list_of_mappings.yml COPYONLY) +configure_file(test_int_array.yaml test_int_array.yaml COPYONLY) diff --git a/common/config/yaml/tests/test1.yaml b/common/config/yaml/tests/test1.yaml new file mode 100644 index 0000000000..7b064b0d38 --- /dev/null +++ b/common/config/yaml/tests/test1.yaml @@ -0,0 +1,4 @@ +test: + value1: 1 + value2: 2 + value3: 3 diff --git a/common/config/yaml/tests/test_int_array.yaml b/common/config/yaml/tests/test_int_array.yaml new file mode 100644 index 0000000000..498db5d31c --- /dev/null +++ b/common/config/yaml/tests/test_int_array.yaml @@ -0,0 +1,6 @@ +test: + array: [1, 2, 3, 4] + array2: + - 1 + - 2 + - 3 diff --git a/common/config/yaml/tests/test_list.yaml b/common/config/yaml/tests/test_list.yaml new file mode 100644 index 0000000000..a7d4b38a59 --- /dev/null +++ b/common/config/yaml/tests/test_list.yaml @@ -0,0 +1,13 @@ +test: + - + value1: 1 + value2: 2 + value3: 3 + - + value1: 4 + value2: 5 + value3: 6 + - + value1: 7 + value2: 8 + value3: 9 diff --git a/common/config/yaml/tests/test_list_of_mappings.yml b/common/config/yaml/tests/test_list_of_mappings.yml new file mode 100644 index 0000000000..e8bc8c9f00 --- /dev/null +++ b/common/config/yaml/tests/test_list_of_mappings.yml @@ -0,0 +1,14 @@ +test: + list: + - value1: 1 + value2: 3 + list: + - value1 + - value2 + - value3 + - value: 2 + value2: 6 + list: + - value4 + - value5 + - value6 diff --git a/common/config/yaml/tests/test_recursion.yaml b/common/config/yaml/tests/test_recursion.yaml new file mode 100644 index 0000000000..0cf2c723ce --- /dev/null +++ b/common/config/yaml/tests/test_recursion.yaml @@ -0,0 +1,8 @@ +test: + test1: + test2: + test3: + test4: + value1: 1 + value2: 2 + value3: 3 diff --git a/common/config/yaml/tests/test_string.yaml b/common/config/yaml/tests/test_string.yaml new file mode 100644 index 0000000000..e093ea3880 --- /dev/null +++ b/common/config/yaml/tests/test_string.yaml @@ -0,0 +1,6 @@ +test: + stringvalue: testvalue + stringlist: + - testvalue1 + - testvalue2 + - testvalue3 diff --git a/common/config/yaml/tests/test_yaml_config.cpp b/common/config/yaml/tests/test_yaml_config.cpp new file mode 100644 index 0000000000..921a455dfd --- /dev/null +++ b/common/config/yaml/tests/test_yaml_config.cpp @@ -0,0 +1,373 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "gtest/gtest.h" +extern "C" { +#include "common/config/config_paramdesc.h" +// TODO: Should use minimal_lib for this but for some reason it doesn't link properly +uint64_t get_softmodem_optmask(void) +{ + return 0; +} +configmodule_interface_t *uniqCfg; +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + if (assert) { + abort(); + } else { + exit(EXIT_SUCCESS); + } +} + +#include "common/utils/LOG/log.h" +#include "common/config/config_load_configmodule.h" +#include "common/config/config_userapi.h" +} +#include +#include +#include +#include +#include + +extern "C" { +int config_yaml_init(configmodule_interface_t *cfg); +void config_yaml_end(configmodule_interface_t *cfg); +int config_yaml_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix); +int config_yaml_getlist(configmodule_interface_t *cfg, paramlist_def_t *ParamList, paramdef_t *params, int numparams, char *prefix); +void config_yaml_write_parsedcfg(configmodule_interface_t *cfg); +int config_yaml_set(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int numoptions, char *prefix); +} + +TEST(yaml_config, yaml_basic) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test1.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + + +TEST(yaml_config, yaml_get_existing_values) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test1.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + // Testing paremters present in the test node + paramdef_t p = {0}; + for (auto i = 1; i <= 3; i++) { + sprintf(p.optname, "%s%d", "value", i); + uint16_t value; + p.type = TYPE_UINT16; + p.u16ptr = &value; + char prefix[] = "test"; + config_yaml_get(cfg, &p, 1, prefix); + EXPECT_EQ(value, i); + } + + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, yaml_get_non_existing_values) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test1.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + // Testing paremters present in the test node + paramdef_t p = {0}; + for (auto i = 4; i <= 5; i++) { + sprintf(p.optname, "%s%d", "value", i); + uint16_t value; + p.type = TYPE_UINT16; + p.u16ptr = &value; + p.defuintval = i; + char prefix[] = "test"; + config_yaml_get(cfg, &p, 1, prefix); + EXPECT_EQ(value, i); + } + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_high_recusion) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_recursion.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + // Testing paremters present in the test node + paramdef_t p = {0}; + for (auto i = 1; i <= 3; i++) { + sprintf(p.optname, "%s%d", "value", i); + uint16_t value; + p.type = TYPE_UINT16; + p.u16ptr = &value; + char prefix[] = "test.test1.test2.test3.test4"; + EXPECT_EQ(config_yaml_get(cfg, &p, 1, prefix), 0); + EXPECT_EQ(value, i); + } + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_list) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_list.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramlist_def_t param_list = {0}; + sprintf(param_list.listname, "%s", "test"); + paramdef_t params[3] = {0}; + uint16_t value[3]; + for (auto i = 0; i < 3; i++) { + sprintf(params[i].optname, "%s%d", "value", i+1); + params[i].type = TYPE_UINT16; + params[i].u16ptr = &value[i]; + } + + + config_yaml_getlist(cfg, ¶m_list, params, 3, nullptr); + + for (auto i = 0; i < 3; i++) { + for (auto j = 0; j < 3; j++) { + EXPECT_EQ(*param_list.paramarray[i][j].u16ptr, i * 3 + j + 1); + } + } + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_string_auto_alloc) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_string.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramdef_t param = {0}; + param.type = TYPE_STRING; + param.strptr = nullptr; + sprintf(param.optname, "%s", "stringvalue"); + param.defstrval = nullptr; + + // Test automatic allocation of strings + char prefix[] = "test"; + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix), 0); + EXPECT_NE(param.strptr, nullptr); + EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0); + EXPECT_EQ(cfg->numptrs, 2); + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_string_no_realloc) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_string.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramdef_t param = {0}; + param.type = TYPE_STRING; + param.strptr = nullptr; + sprintf(param.optname, "%s", "stringvalue"); + param.defstrval = nullptr; + + // check that if we at least have a non-null pointer to pointer, only one buffer is allocated + char prefix[] = "test"; + char* non_null_pointer_to_pointer = nullptr; + param.strptr = &non_null_pointer_to_pointer; + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix), 0); + EXPECT_EQ(param.strptr, &non_null_pointer_to_pointer); + EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0); + EXPECT_EQ(cfg->numptrs, 1); + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_string_pointer_available) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_string.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramdef_t param = {0}; + param.type = TYPE_STRING; + param.strptr = nullptr; + sprintf(param.optname, "%s", "stringvalue"); + param.defstrval = nullptr; + + // Test that if a strptr is provided, config module doesnt reallocate it + char prefix[] = "test"; + char *container = (char *)malloc(sizeof(char) * 30); + param.strptr = &container; + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix), 0); + EXPECT_EQ(param.strptr, &container); + EXPECT_EQ(strcmp(*param.strptr, "testvalue"), 0); + EXPECT_EQ(cfg->numptrs, 0); + free(container); + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_string_default_value) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_string.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramdef_t param = {0}; + param.type = TYPE_STRING; + param.strptr = nullptr; + sprintf(param.optname, "%s", "stringvalue"); + param.defstrval = nullptr; + + // Test that if defstrval is not null and value is missing in yaml defstrval is set + char prefix[] = "test"; + char default_value[] = "default"; + param.defstrval = default_value; + param.strptr = nullptr; + sprintf(param.optname, "%s", "stringvalue_missing"); + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix), 0); + EXPECT_NE(param.strptr, nullptr); + EXPECT_EQ(strcmp(*param.strptr, "default"), 0); + EXPECT_EQ(cfg->numptrs, 2) << " 2 pointers required, 1 for the string, one for the pointer-to string"; + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_stringlist) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_string.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramdef_t param = {0}; + param.type = TYPE_STRINGLIST; + param.strptr = nullptr; + sprintf(param.optname, "%s", "stringlist"); + param.defstrval = nullptr; + + // Test automatic allocation of string lists + char prefix[] = "test"; + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix), 0); + EXPECT_NE(param.strptr, nullptr); + for (auto i = 0; i < param.numelt; i++) { + std::cout << (param.strlistptr)[i] << std::endl; + } + // config_check_valptr allocates maximum list size regardless of the number of elements in list + EXPECT_EQ(cfg->numptrs, MAX_LIST_SIZE + 1); + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_list_of_mappings) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_list_of_mappings.yml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramdef_t param = {0}; + param.type = TYPE_STRINGLIST; + param.strlistptr = nullptr; + sprintf(param.optname, "%s", "list"); + param.defstrval = nullptr; + + // Test automatic allocation of string lists + char prefix1[] = "test.list.[0]"; + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix1), 0); + EXPECT_NE(param.strptr, nullptr); + EXPECT_STREQ("value1", param.strlistptr[0]); + EXPECT_STREQ("value2", param.strlistptr[1]); + EXPECT_STREQ("value3", param.strlistptr[2]); + + char prefix2[] = "test.list.[1]"; + param.strlistptr = nullptr; + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix2), 0); + EXPECT_NE(param.strptr, nullptr); + EXPECT_STREQ("value4", param.strlistptr[0]); + EXPECT_STREQ("value5", param.strlistptr[1]); + EXPECT_STREQ("value6", param.strlistptr[2]); + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, test_int_array) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_int_array.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + paramdef_t param = {0}; + param.type = TYPE_INTARRAY; + param.iptr = nullptr; + sprintf(param.optname, "%s", "array"); + param.defintarrayval = nullptr; + + // Test automatic allocation of int arrays + char prefix[] = "test"; + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix), 0); + EXPECT_NE(param.iptr, nullptr); + ASSERT_EQ(param.numelt, 4); + EXPECT_EQ(1, param.iptr[0]); + EXPECT_EQ(2, param.iptr[1]); + EXPECT_EQ(3, param.iptr[2]); + EXPECT_EQ(4, param.iptr[3]); + + param.uptr = nullptr; + param.numelt = 0; + sprintf(param.optname, "%s", "array2"); + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix), 0); + EXPECT_NE(param.uptr, nullptr); + ASSERT_EQ(param.numelt, 3); + EXPECT_EQ(1U, param.uptr[0]); + EXPECT_EQ(2U, param.uptr[1]); + EXPECT_EQ(3U, param.uptr[2]); + + param.uptr = nullptr; + param.numelt = 0; + sprintf(param.optname, "%s", "non-existent-array"); + EXPECT_EQ(config_yaml_get(cfg, ¶m, 1, prefix), 0); + EXPECT_EQ(param.uptr, nullptr); + ASSERT_EQ(param.numelt, 0); + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +int main(int argc, char** argv) +{ + logInit(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.yaml b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.yaml new file mode 100644 index 0000000000..a215c71304 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.yaml @@ -0,0 +1,221 @@ +Active_gNBs: + - gNB-OAI +Asn1_verbosity: none +gNBs: + # Identification parameters: + - gNB_ID: 0xe00 + gNB_name: gNB-OAI + # Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code: 1 + plmn_list: + - + mcc: 001 + mnc: 01 + mnc_length: 2 + snssaiList: + - + sst: 1 + nr_cellid: 12345678 + # Physical parameters: + do_CSIRS: 1 + do_SRS: 1 + servingCellConfigCommon: + #spCellConfigCommon + - physCellId: 0 + # downlinkConfigCommon + #frequencyInfoDL + # this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP) + absoluteFrequencySSB: 641280 + dl_frequencyBand: 78 + # this is 3600 MHz + dl_absoluteFrequencyPointA: 640008 + #scs-SpecificCarrierList + dl_offstToCarrier: 0 + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing: 1 + dl_carrierBandwidth: 106 + #initialDownlinkBWP + #genericParameters + # this is RBstart=27,L=48 (275*(L-1))+RBstart + initialDLBWPlocationAndBandwidth: 28875 # 6366 12925 12956 28875 12952 + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing: 1 + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero: 12 + initialDLBWPsearchSpaceZero: 0 + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand: 78 + #scs-SpecificCarrierList + ul_offstToCarrier: 0 + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing: 1 + ul_carrierBandwidth: 106 + pMax: 20 + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth: 28875 + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing: 1 + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex: 98 + #prach_msg1_FDM + #0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM: 0 + prach_msg1_FrequencyStart: 0 + zeroCorrelationZoneConfig: 13 + preambleReceivedTargetPower: -96 + #preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax: 6 + #powerRampingStep + # 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep: 1 + #ra_ReponseWindow + #1,2,4,8,10,20,40,80 + ra_ResponseWindow: 4 + #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR + #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR: 4 + #oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB: 14 + #ra_ContentionResolutionTimer + #(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer: 7 + rsrp_ThresholdSSB: 19 + #prach-RootSequenceIndex_PR + #1 = 839, 2 = 139 + prach_RootSequenceIndex_PR: 2 + prach_RootSequenceIndex: 1 + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + msg1_SubcarrierSpacing: 1 + # restrictedSetConfig + # 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig: 0 + msg3_DeltaPreamble: 1 + p0_NominalWithGrant: -90 + # pucch-ConfigCommon setup : + # pucchGroupHopping + # 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping: 0 + hoppingId: 40 + p0_nominal: -90 + # ssb_PositionsInBurs_BitmapPR + # 1=short, 2=medium, 3=long + ssb_PositionsInBurst_PR: 2 + ssb_PositionsInBurst_Bitmap: 1 + + # ssb_periodicityServingCell + # 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell: 2 + + # dmrs_TypeA_position + # 0 = pos2, 1 = pos3 + dmrs_TypeA_Position: 0 + + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing: 1 + + + #tdd-UL-DL-ConfigurationCommon + # subcarrierSpacing + # 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing: 1 + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity: 6 + nrofDownlinkSlots: 7 + nrofDownlinkSymbols: 6 + nrofUplinkSlots: 2 + nrofUplinkSymbols: 4 + + ssPBCH_BlockPower: -25 + SCTP: + SCTP_INSTREAMS: 2 + SCTP_OUTSTREAMS: 2 + + + # AMF parameters: + amf_ip_address: + ipv4: 192.168.70.132 + + + NETWORK_INTERFACES: + GNB_IPV4_ADDRESS_FOR_NG_AMF: 192.168.70.129 + GNB_IPV4_ADDRESS_FOR_NGU: 192.168.70.129 + GNB_PORT_FOR_S1U: 2152 # Spec 2152 + +MACRLCs: + - + num_cc: 1 + tr_s_preference: local_L1 + tr_n_preference: local_RRC + pusch_TargetSNRx10: 150 + pucch_TargetSNRx10: 200 + +L1s: + - + num_cc: 1 + tr_n_preference: local_mac + prach_dtx_threshold: 120 + pucch0_dtx_threshold: 100 + ofdm_offset_divisor: 8 #set this to UINT_MAX for offset 0 + +RUs: + - + local_rf: yes + nb_tx: 1 + nb_rx: 1 + att_tx: 12 + att_rx: 12 + bands: [78] + max_pdschReferenceSignalPower: -27 + max_rxgain: 114 + eNB_instances: [0] + bf_weights: [0x00007fff, 0x0000, 0x0000, 0x0000] + clock_src: internal + +rfsimulator: + serveraddr: server + serverport: 4043 + options: [] #("saviq"); or/and "chanmod" + modelname: AWGN + IQfile: /tmp/rfsimulator.iqs + +security: + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms: [nea0] + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms: [nia2, nia0] + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering: yes + drb_integrity: no + +log_config: + global_log_level: info + hw_log_level: info + phy_log_level: info + mac_log_level: info + rlc_log_level: info + pdcp_log_level: info + rrc_log_level: info + ngap_log_level: debug + f1ap_log_level: debug + +e2_agent: + near_ric_ip_addr: 127.0.0.1 + #sm_dir = /path/where/the/SMs/are/located/ + sm_dir: /usr/local/lib/flexric/ From 9b59ba6326f7e625ce067f80ad4c36eb42304bc8 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 23 Jul 2024 11:22:09 +0200 Subject: [PATCH 27/61] Enable configuration of NR UE through a YAML file This commit adds yaml-cpp library to required docker images and build commands. There is one workaround in cross-compilation for apt behavior for installing libyaml-cpp-dev. Apt will uninistall previous versions of the package whenever another one is installed. This means that installing the arm version breaks amd version and vice versa. This makes it impossible to have both libs installed at the same time which is required by the cross-compilation build command (it calls cmake twice, once with native and once with target architecture) --- ci-scripts/docker/Dockerfile.unittest.ubuntu22 | 3 ++- .../yaml_files/5g_rfsimulator/docker-compose.yaml | 2 +- cmake_targets/build_oai | 2 +- common/config/yaml/CMakeLists.txt | 3 +-- docker/Dockerfile.base.ubuntu22.cross-arm64 | 1 + docker/Dockerfile.build.ubuntu22.cross-arm64 | 2 ++ docker/Dockerfile.nrUE.rhel9 | 9 +++++++-- docker/Dockerfile.nrUE.rocky | 3 ++- docker/Dockerfile.nrUE.ubuntu22 | 6 ++++-- docker/scripts/nr_ue_entrypoint.sh | 12 ++++++++++-- 10 files changed, 31 insertions(+), 12 deletions(-) diff --git a/ci-scripts/docker/Dockerfile.unittest.ubuntu22 b/ci-scripts/docker/Dockerfile.unittest.ubuntu22 index 4401761c02..627b0d07f7 100644 --- a/ci-scripts/docker/Dockerfile.unittest.ubuntu22 +++ b/ci-scripts/docker/Dockerfile.unittest.ubuntu22 @@ -30,7 +30,8 @@ FROM ran-base:develop AS ran-tests RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - libgtest-dev + libgtest-dev \ + libyaml-cpp-dev RUN rm -Rf /oai-ran WORKDIR /oai-ran diff --git a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml index 06c945a250..edee7895ca 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator/docker-compose.yaml @@ -118,7 +118,7 @@ services: devices: - /dev/net/tun:/dev/net/tun volumes: - - ../../conf_files/nrue.uicc.conf:/opt/oai-nr-ue/etc/nr-ue.conf + - ../../conf_files/nrue.uicc.yaml:/opt/oai-nr-ue/etc/nr-ue.yaml healthcheck: test: /bin/bash -c "pgrep nr-uesoftmodem" interval: 10s diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index cd7e326be8..64ac258239 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -497,7 +497,7 @@ function main() { # add some default libraries that should always be built # for eNB, gNB, UEs, simulators if [[ $gNB == 1 || $eNB == 1 || $UE == 1 || $nrUE == 1 || $SIMUS_PHY == 1 || $RU == 1 ]]; then - TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts" + TARGET_LIST="$TARGET_LIST params_libconfig coding rfsimulator dfts params_yaml" fi mkdir -p $DIR/$BUILD_DIR/build diff --git a/common/config/yaml/CMakeLists.txt b/common/config/yaml/CMakeLists.txt index 67d90a0099..5ff8c23eb1 100644 --- a/common/config/yaml/CMakeLists.txt +++ b/common/config/yaml/CMakeLists.txt @@ -1,5 +1,4 @@ -find_package(yaml-cpp REQUIRED) - +find_package(yaml-cpp REQUIRED PATHS /usr/lib/aarch64-linux-gnu/pkgconfig/) # include(FetchContent) # FetchContent_Declare( diff --git a/docker/Dockerfile.base.ubuntu22.cross-arm64 b/docker/Dockerfile.base.ubuntu22.cross-arm64 index 74af391660..1bcba7bdd6 100644 --- a/docker/Dockerfile.base.ubuntu22.cross-arm64 +++ b/docker/Dockerfile.base.ubuntu22.cross-arm64 @@ -66,6 +66,7 @@ RUN apt-get update && \ libssl-dev:arm64 \ libtool:arm64 \ zlib1g-dev:arm64 \ + libyaml-cpp-dev:arm64 \ # cross build libs and compilers libc6-dev-i386 \ gcc-11-aarch64-linux-gnu \ diff --git a/docker/Dockerfile.build.ubuntu22.cross-arm64 b/docker/Dockerfile.build.ubuntu22.cross-arm64 index 349a4f791c..faadf79eb2 100644 --- a/docker/Dockerfile.build.ubuntu22.cross-arm64 +++ b/docker/Dockerfile.build.ubuntu22.cross-arm64 @@ -41,6 +41,8 @@ RUN /bin/sh oaienv && \ ninja ldpc_generators generate_T > ../../log/host-tools.txt 2>&1 && \ echo "====== End of log for host-tools ======" && \ cd ../build-cross/ && \ + # install missing libyaml-cpp-dev for arm64 + apt install -y libyaml-cpp-dev:arm64 && \ cmake ../../.. -GNinja -DCMAKE_TOOLCHAIN_FILE=../../../cmake_targets/cross-arm.cmake -DNATIVE_DIR=../build && \ echo "====== Start of log for cross-build executables ======" && \ # making always passing so we can analyze the all.txt file diff --git a/docker/Dockerfile.nrUE.rhel9 b/docker/Dockerfile.nrUE.rhel9 index 7279809fdb..8ab486bd85 100644 --- a/docker/Dockerfile.nrUE.rhel9 +++ b/docker/Dockerfile.nrUE.rhel9 @@ -34,6 +34,9 @@ FROM ran-build:latest AS nr-ue-build FROM registry.access.redhat.com/ubi9/ubi:latest AS oai-nr-ue ENV TZ=Europe/Paris +# Install EPEL for RHEL9 +RUN dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm + RUN dnf update -y && \ dnf install -y \ lksctp-tools \ @@ -47,7 +50,8 @@ RUN dnf update -y && \ python3 \ python3-pip \ libXpm \ - libX11 && \ + libX11 \ + yaml-cpp-devel && \ pip3 install six && \ pip3 install requests && \ echo "/usr/local/lib" > /etc/ld.so.conf.d/local-lib.conf && \ @@ -70,6 +74,7 @@ COPY --from=nr-ue-build \ /oai-ran/cmake_targets/ran_build/build/libldpc*.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ + /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ /usr/local/lib/ COPY --from=nr-ue-base \ @@ -117,5 +122,5 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai WORKDIR /opt/oai-nr-ue COPY --from=nr-ue-base /tini /tini -CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem", "-O", "/opt/oai-nr-ue/etc/nr-ue.conf"] +CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem"] ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-nr-ue/bin/entrypoint.sh"] diff --git a/docker/Dockerfile.nrUE.rocky b/docker/Dockerfile.nrUE.rocky index ec5ecf6a99..d0455527fa 100644 --- a/docker/Dockerfile.nrUE.rocky +++ b/docker/Dockerfile.nrUE.rocky @@ -71,6 +71,7 @@ COPY --from=nr-ue-build \ /oai-ran/cmake_targets/ran_build/build/libldpc*.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ + /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ /usr/local/lib/ COPY --from=nr-ue-base \ @@ -118,5 +119,5 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai WORKDIR /opt/oai-nr-ue COPY --from=nr-ue-base /tini /tini -CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem", "-O", "/opt/oai-nr-ue/etc/nr-ue.conf"] +CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem"] ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-nr-ue/bin/entrypoint.sh"] diff --git a/docker/Dockerfile.nrUE.ubuntu22 b/docker/Dockerfile.nrUE.ubuntu22 index 74ae9620b0..dc0d425956 100644 --- a/docker/Dockerfile.nrUE.ubuntu22 +++ b/docker/Dockerfile.nrUE.ubuntu22 @@ -64,7 +64,8 @@ RUN apt-get update && \ iputils-ping \ iproute2 \ iperf3 \ - iperf && \ + iperf \ + libyaml-cpp-dev && \ # if the --sanitize option was used to build, additional packages are required /bin/bash -c 'if [[ "$BUILD_OPTION" = "--sanitize" ]]; then DEBIAN_FRONTEND=noninteractive apt-get install --yes \ #libasan5 \ # see below @@ -97,6 +98,7 @@ COPY --from=nr-ue-build \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_ciUE.so \ /oai-ran/cmake_targets/ran_build/build/libtelnetsrv_5Gue.so \ + /oai-ran/cmake_targets/ran_build/build/libparams_yaml.so \ /usr/local/lib/ # Now we are copying from builder-image the UHD files. @@ -123,5 +125,5 @@ RUN /bin/bash -c "ln -s /usr/local/lib/liboai_usrpdevif.so /usr/local/lib/liboai WORKDIR /opt/oai-nr-ue COPY --from=nr-ue-base /tini /tini -CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem", "-O", "/opt/oai-nr-ue/etc/nr-ue.conf"] +CMD ["/opt/oai-nr-ue/bin/nr-uesoftmodem"] ENTRYPOINT ["/tini", "-v", "--", "/opt/oai-nr-ue/bin/entrypoint.sh"] diff --git a/docker/scripts/nr_ue_entrypoint.sh b/docker/scripts/nr_ue_entrypoint.sh index 31382a9b07..26ae6da7f7 100755 --- a/docker/scripts/nr_ue_entrypoint.sh +++ b/docker/scripts/nr_ue_entrypoint.sh @@ -9,8 +9,13 @@ echo "==================================" echo "/proc/sys/kernel/core_pattern=$(cat /proc/sys/kernel/core_pattern)" if [ ! -f $CONFIGFILE ]; then - echo "No configuration file found: please mount at $CONFIGFILE" - exit 255 + echo "No configuration file $CONFIGFILE found: attempting to find YAML config" + YAML_CONFIGFILE=$PREFIX/etc/nr-ue.yaml + if [ ! -f $YAML_CONFIGFILE ]; then + echo "No configuration file $YAML_CONFIGFILE found. Please mount either at $CONFIGFILE or $YAML_CONFIGFILE" + exit 255 + fi + CONFIGFILE=$YAML_CONFIGFILE fi echo "==================================" @@ -35,6 +40,9 @@ while [[ $# -gt 0 ]]; do shift done +new_args+=("-O") +new_args+=("$CONFIGFILE") + # enable printing of stack traces on assert export OAI_GDBSTACKS=1 From ca217f8f5b406521de0252a53b0a128bb9d381e3 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 2 Sep 2024 10:13:37 +0200 Subject: [PATCH 28/61] Workaround for PUSCH TX power not applied in PHY This is a temporary workaround for issue with UE PHY not applying TX power instructions from MAC. To be reverted once implementation of TX gain control is finished. --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 557a393ce2..2b54f45add 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -944,6 +944,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, delta_pusch = table_38_213_7_1_1_1[0][dci->tpc]; } } + delta_pusch = 0; // set to 0 as a workaround for PHY not applying PUSCH tx power bool is_rar_tx_retx = rnti_type == TYPE_TC_RNTI_; From 798a62271c6d97508fef4fc084144876c638d1fe Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Aug 2024 14:44:53 +0200 Subject: [PATCH 29/61] DL RRC message: print log if oldUE unknown --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 2435ed629a..426a72f391 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -743,7 +743,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) * the new UE context (with new C-RNTI), but set up everything to reuse the * old config. */ NR_UE_info_t *oldUE = find_nr_UE(&mac->UE_info, *dl_rrc->old_gNB_DU_ue_id); - DevAssert(oldUE); + AssertFatal(oldUE, "CU claims we should know UE %04x, but we don't\n", *dl_rrc->old_gNB_DU_ue_id); pthread_mutex_lock(&mac->sched_lock); /* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it * from the current configuration. Also, expect the reconfiguration from From 9b7d3351a14b15d6b5e451cad16826a646b58fdc Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Aug 2024 16:41:39 +0200 Subject: [PATCH 30/61] DU: if requested to remove non-existing UE, just ack The failure mode observed here was that the CU sent a release command for a UE that the DU does not know. Given, that the outcome of the release command (no UE) is equal to the current state (no UE), from the DU point of view, we can safely ack the command. --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 426a72f391..9b5bd938ec 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -669,8 +669,12 @@ void ue_context_release_command(const f1ap_ue_context_release_cmd_t *cmd) NR_SCHED_LOCK(&mac->sched_lock); NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, cmd->gNB_DU_ue_id); if (UE == NULL) { - LOG_E(MAC, "ERROR: unknown UE with RNTI %04x, ignoring UE Context Release Command\n", cmd->gNB_DU_ue_id); NR_SCHED_UNLOCK(&mac->sched_lock); + f1ap_ue_context_release_complete_t complete = { + .gNB_CU_ue_id = cmd->gNB_CU_ue_id, + .gNB_DU_ue_id = cmd->gNB_DU_ue_id, + }; + mac->mac_rrc.ue_context_release_complete(&complete); return; } From ec6469d0888414bda9b10e54a4963aa0579cb04a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 8 Aug 2024 08:31:21 +0200 Subject: [PATCH 31/61] F1AP: Remove unnecessary logs --- openair2/F1AP/f1ap_du_ue_context_management.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 8c32e7bea6..5ab1c07d6c 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -281,12 +281,9 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i memcpy(f1ap_ue_context_setup_req->rrc_container, ieRRC->value.choice.RRCContainer.buf, ieRRC->value.choice.RRCContainer.size); f1ap_ue_context_setup_req->rrc_container_length = ieRRC->value.choice.RRCContainer.size; - // AssertFatal(0, "check configuration, send to appropriate handler\n"); } else { LOG_E(F1AP, " RRCContainer in UEContextSetupRequestIEs size id 0\n"); } - } else { - LOG_W(F1AP, "can't find RRCContainer in UEContextSetupRequestIEs by id %ld \n", F1AP_ProtocolIE_ID_id_RRCContainer); } ue_context_setup_request(f1ap_ue_context_setup_req); From 25430e9b25c9ce4e31f50f728bf6ac9034dce99b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 4 Sep 2024 18:11:15 +0200 Subject: [PATCH 32/61] Fixup: on SCTP conn event, transmit assoc_id User of the SCTP module use the assoc_id for connection identification. The previous code set the assoc_id to -1, so there is no way of telling which connection broke. Use the assoc_id instead --- openair3/SCTP/sctp_eNB_task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index ffd4bba3f5..a6d3a11a39 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -787,7 +787,7 @@ sctp_eNB_read_from_socket( SCTP_ERROR("sctp_recvmsg (fd %d, len %d ): %s:%d\n", sctp_cnx->sd, n, strerror(errno), errno); sctp_itti_send_association_resp( - sctp_cnx->task_id, sctp_cnx->instance, -1, + sctp_cnx->task_id, sctp_cnx->instance, sctp_cnx->assoc_id, sctp_cnx->cnx_id, SCTP_STATE_UNREACHABLE, 0, 0); close(sctp_cnx->sd); From ba0b63fe2fe9dcffadcdb1bdd73eb97872889b8b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Aug 2024 15:02:30 +0200 Subject: [PATCH 33/61] F1AP: Handle SCTP communication lost It can happen that SCTP communication is simply lost, e.g. [SCTP] SCTP_ASSOC_CHANGE to SCTP_COMM_LOST [SCTP] sctp_recvmsg (fd 104, len -1 ): Connection reset by peer:104 The previous code only handled the SHUTDOWN event, but in abnormal situations, we should also handle the connection state change and signal to RRC that the endpoint is dead, which is now implemented. --- openair2/F1AP/f1ap_cu_task.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c index a320b92935..72e3d86ea2 100644 --- a/openair2/F1AP/f1ap_cu_task.c +++ b/openair2/F1AP/f1ap_cu_task.c @@ -64,27 +64,17 @@ static void cu_task_handle_sctp_association_ind(instance_t instance, static void cu_task_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) { DevAssert(sctp_new_association_resp != NULL); - if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) { + enum sctp_state_e state = sctp_new_association_resp->sctp_state; + if (state != SCTP_STATE_ESTABLISHED) { f1ap_cudu_inst_t *f1ap_cu_data = getCxt(instance); AssertFatal(f1ap_cu_data != NULL, "illegal state: SCTP shutdown for non-existing F1AP endpoint\n"); - LOG_I(F1AP, "Received SCTP shutdown for assoc_id %d, removing endpoint\n", sctp_new_association_resp->assoc_id); + LOG_I(F1AP, "Received SCTP state %d for assoc_id %d, removing endpoint\n", state, sctp_new_association_resp->assoc_id); /* inform RRC that the DU is gone */ MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_LOST_CONNECTION); message_p->ittiMsgHeader.originInstance = sctp_new_association_resp->assoc_id; itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p); return; } - - if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) { - LOG_W(F1AP, "Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n", - sctp_new_association_resp->sctp_state, - instance, - sctp_new_association_resp->ulp_cnx_id); - //if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) - //proto_agent_stop(instance); - //f1ap_handle_setup_message(instance, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN); - return; // exit -1 for debugging - } } static void cu_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) { From 32b2ad259d321780c213cbec46f6bba010971aa7 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 9 Aug 2024 13:37:05 +0200 Subject: [PATCH 34/61] Harmonize Msg3 PUSCH LOG_A to be only one, demote RA cont res timer --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index d8f6690818..160cde63f5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -560,7 +560,7 @@ static void start_ra_contention_resolution_timer(NR_RA_t *ra, const long ra_Cont // Value sf8 corresponds to 8 subframes, value sf16 corresponds to 16 subframes, and so on. // We add 2 * K2 because the timer runs from Msg2 transmission till Msg4 ACK reception ra->contention_resolution_timer = ((((int)ra_ContentionResolutionTimer + 1) * 8) << scs) + 2 * K2; - LOG_I(NR_MAC, + LOG_D(NR_MAC, "Starting RA Contention Resolution timer with %d ms + 2 * %d K2 (%d slots) duration\n", ((int)ra_ContentionResolutionTimer + 1) * 8, K2, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index d0b36a4603..d091d486ff 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -860,12 +860,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, // re-initialize ta update variables after RA procedure completion UE->UE_sched_ctrl.ta_frame = frameP; - LOG_I(NR_MAC, - "[gNB %d][RAPROC] PUSCH with TC_RNTI 0x%04x received correctly, " - "adding UE MAC Context RNTI 0x%04x\n", - gnb_mod_idP, - current_rnti, - ra->rnti); + LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frameP, slotP, current_rnti); NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl; if (ul_cqi != 0xff) { @@ -884,7 +879,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, ra->CellGroup->rlc_BearerToAddModList); nr_clear_ra_proc(ra); } else { - LOG_A(NR_MAC, "[RAPROC] RA-Msg3 received (sdu_lenP %d)\n", sdu_lenP); LOG_D(NR_MAC, "[RAPROC] Received Msg3:\n"); for (uint32_t k = 0; k < sdu_lenP; k++) { LOG_D(NR_MAC, "(%i): 0x%x\n", k, sduP[k]); From 4e7e8a6fa0c109b79cb919ea3f71c8d11cd009d1 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 6 Aug 2024 19:21:10 +0200 Subject: [PATCH 35/61] Fix bug: correctly fill LCID in ue context setup resp Before this bug fix, when using F1, we get this warning: Constraint validation failed: LCID: constraint failed (/home/richie/openairinterface5g/cmake_targets/ran_build/build/openair2/F1AP/MESSAGES/F1AP_LCID.c:30) This is because (1) we don't actually store the LCID, then (2) we did not put it into the F1 ASN.1 structures. Fix both, to make this warning disappear. To actually print the full error message, increase the error buffer size. Also, for the future, to avoid guessing, print ASN.1 XML when we encounter a failed constraint validation. --- openair2/F1AP/f1ap_du_ue_context_management.c | 1 + openair2/F1AP/f1ap_encoder.c | 6 +++--- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 5ab1c07d6c..6d9771f1f4 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -593,6 +593,7 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set F1AP_SRBs_Setup_Item_t *srbs_setup_item=&srbs_setup_item_ies->value.choice.SRBs_Setup_Item; /* sRBID */ srbs_setup_item->sRBID = resp->srbs_to_be_setup[i].srb_id; + srbs_setup_item->lCID = resp->srbs_to_be_setup[i].lcid; } } diff --git a/openair2/F1AP/f1ap_encoder.c b/openair2/F1AP/f1ap_encoder.c index 870dfd73fc..5de4ba43db 100644 --- a/openair2/F1AP/f1ap_encoder.c +++ b/openair2/F1AP/f1ap_encoder.c @@ -40,13 +40,13 @@ int f1ap_encode_pdu(F1AP_F1AP_PDU_t *pdu, uint8_t **buffer, uint32_t *length) { LOG_E(F1AP, "----------------- ASN1 ENCODER PRINT END----------------- \n"); } - char errbuf[128]; /* Buffer for error message */ + char errbuf[4096]; /* Buffer for error message */ size_t errlen = sizeof(errbuf); /* Size of the buffer */ int ret = asn_check_constraints(&asn_DEF_F1AP_F1AP_PDU, pdu, errbuf, &errlen); - /* assert(errlen < sizeof(errbuf)); // Guaranteed: you may rely on that */ if(ret) { - fprintf(stderr, "Constraint validation failed: %s\n", errbuf); + xer_fprint(stdout, &asn_DEF_F1AP_F1AP_PDU, pdu); + LOG_E(F1AP, "Constraint validation failed: %s\n", errbuf); } encoded = aper_encode_to_new_buffer(&asn_DEF_F1AP_F1AP_PDU, 0, pdu, (void **)buffer); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 9b5bd938ec..bb84a4793c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -233,7 +233,8 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .priority = priority}; nr_mac_add_lcid(&UE->UE_sched_ctrl, &c); - (*resp_srbs)[i] = *srb; + (*resp_srbs)[i].srb_id = srb->srb_id; + (*resp_srbs)[i].lcid = c.lcid; int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); DevAssert(ret == 0); From 31bad32b572ab4c08151d67b6411acd0b02416e9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 2 Aug 2024 16:55:43 +0200 Subject: [PATCH 36/61] Reestablishment with RRC setup fallback: release old UE if applicable --- openair2/RRC/NR/rrc_gNB.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index f9646468e0..14e84861a7 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1120,7 +1120,9 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, uint64_t random_value = 0; const char *scause = get_reestab_cause(req->reestablishmentCause); const long physCellId = req->ue_Identity.physCellId; - LOG_D(NR_RRC, "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", msg->crnti, physCellId, scause); + long ngap_cause = NGAP_CAUSE_RADIO_NETWORK_UNSPECIFIED; /* cause in case of NGAP release req */ + rrc_gNB_ue_context_t *ue_context_p = NULL; + LOG_I(NR_RRC, "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", msg->crnti, physCellId, scause); const nr_rrc_du_container_t *du = get_du_by_assoc_id(rrc, assoc_id); if (du == NULL) { @@ -1137,7 +1139,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, } rnti_t old_rnti = req->ue_Identity.c_RNTI; - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); + ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); if (ue_context_p == NULL) { LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); goto fallback_rrc_setup; @@ -1150,6 +1152,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, "RRC Reestablishment Request from different physCellId (%ld) than current physCellId (%d), fallback to RRC setup\n", physCellId, cell_info->nr_pci); + ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; /* 38.401 8.7: "If the UE accessed from a gNB-DU other than the original * one, the gNB-CU should trigger the UE Context Setup procedure". Let's * assume that the old DU will trigger a release request, also freeing the @@ -1168,6 +1171,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, if (!UE->as_security_active) { /* no active security context, need to restart entire connection */ LOG_E(NR_RRC, "UE requested Reestablishment without activated AS security\n"); + ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; goto fallback_rrc_setup; } @@ -1176,6 +1180,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, // SSB ARFCN and can't do reestablishment. handle it gracefully by doing // RRC setup procedure instead LOG_E(NR_RRC, "no MeasurementTimingConfiguration for this cell, cannot perform reestablishment\n"); + ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; goto fallback_rrc_setup; } @@ -1188,8 +1193,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, cu_remove_f1_ue_data(UE->rrc_ue_id); cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data); - LOG_I(NR_RRC, "Accept Reestablishment Request UE physCellId %ld cause %s\n", physCellId, scause); - rrc_gNB_generate_RRCReestablishment(ue_context_p, msg->du2cu_rrc_container, old_rnti, du); return; @@ -1197,6 +1200,10 @@ fallback_rrc_setup: fill_random(&random_value, sizeof(random_value)); random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ + /* request release of the "old" UE in case it exists */ + if (ue_context_p != NULL) + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(0, ue_context_p, NGAP_CAUSE_RADIO_NETWORK, ngap_cause); + rrc_gNB_ue_context_t *new = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); activate_srb(&new->ue_context, 1); rrc_gNB_generate_RRCSetup(0, msg->crnti, new, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); From 8d6b6676c51843f5f5e9aecc344245b15b504fbd Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 7 Aug 2024 16:50:35 +0200 Subject: [PATCH 37/61] Reorganize sequence of reestablishment checks Reorganize the sequence of checks done in reestablishment to make it more logical: - check conditions of request (correct C-RNTI) - check conditions of DU (has MIB/SIB1, MTC) - check the UE, and from which DU it comes This will also help to extend it towards reestablishment coming from different DUs in the case of handover. --- openair2/RRC/NR/rrc_gNB.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 14e84861a7..b884a2d808 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1130,6 +1130,13 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, return; } + // 3GPP TS 38.321 version 15.13.0 Section 7.1 Table 7.1-1: RNTI values + if (req->ue_Identity.c_RNTI < 0x1 || req->ue_Identity.c_RNTI > 0xffef) { + /* c_RNTI range error should not happen */ + LOG_E(NR_RRC, "NR_RRCReestablishmentRequest c_RNTI %04lx range error, fallback to RRC setup\n", req->ue_Identity.c_RNTI); + goto fallback_rrc_setup; + } + if (du->mib == NULL || du->sib1 == NULL) { /* we don't have MIB/SIB1 of the DU, and therefore cannot generate the * Reestablishment (as we would need the SSB's ARFCN, which we cannot @@ -1138,12 +1145,22 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, goto fallback_rrc_setup; } + if (du->mtc == NULL) { + // some UEs don't send MeasurementTimingConfiguration, so we don't know the + // SSB ARFCN and can't do reestablishment. handle it gracefully by doing + // RRC setup procedure instead + LOG_E(NR_RRC, "no MeasurementTimingConfiguration for this cell, cannot perform reestablishment\n"); + ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; + goto fallback_rrc_setup; + } + rnti_t old_rnti = req->ue_Identity.c_RNTI; ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); if (ue_context_p == NULL) { LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); goto fallback_rrc_setup; } + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; if (physCellId != cell_info->nr_pci) { @@ -1160,14 +1177,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, goto fallback_rrc_setup; } - gNB_RRC_UE_t *UE = &ue_context_p->ue_context; - // 3GPP TS 38.321 version 15.13.0 Section 7.1 Table 7.1-1: RNTI values - if (req->ue_Identity.c_RNTI < 0x1 || req->ue_Identity.c_RNTI > 0xffef) { - /* c_RNTI range error should not happen */ - LOG_E(NR_RRC, "NR_RRCReestablishmentRequest c_RNTI %04lx range error, fallback to RRC setup\n", req->ue_Identity.c_RNTI); - goto fallback_rrc_setup; - } - if (!UE->as_security_active) { /* no active security context, need to restart entire connection */ LOG_E(NR_RRC, "UE requested Reestablishment without activated AS security\n"); @@ -1175,15 +1184,6 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, goto fallback_rrc_setup; } - if (du->mtc == NULL) { - // some UEs don't send MeasurementTimingConfiguration, so we don't know the - // SSB ARFCN and can't do reestablishment. handle it gracefully by doing - // RRC setup procedure instead - LOG_E(NR_RRC, "no MeasurementTimingConfiguration for this cell, cannot perform reestablishment\n"); - ngap_cause = NGAP_CAUSE_RADIO_NETWORK_RELEASE_DUE_TO_NGRAN_GENERATED_REASON; - goto fallback_rrc_setup; - } - /* TODO: start timer in ITTI and drop UE if it does not come back */ // update with new RNTI, and update secondary UE association From ea171c75c0b941dc982e1e932a4c5a267705e038 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 31 May 2024 12:25:51 +0200 Subject: [PATCH 38/61] nr_timer: consistently pass by ref, rename to nr_timer_is_active() Pass consistently the NR_timer_t object through a pointer. Since we have to modify all occurrences of is_nr_timer_active(), we use that occasion and rename that function to nr_timer_is_active() to make it consistent with all other functions, starting with nr_timer. --- common/utils/nr/nr_common.c | 16 ++++++++-------- common/utils/nr/nr_common.h | 6 +++--- common/utils/nr/tests/test_nr_common.cpp | 8 ++++---- openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c | 4 ++-- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 2 +- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 4 ++-- openair2/RRC/NR_UE/rrc_UE.c | 8 ++++---- openair2/RRC/NR_UE/rrc_timers_and_constants.c | 14 +++++++------- 8 files changed, 31 insertions(+), 31 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index c1ed6c7546..f851c26eee 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -1161,9 +1161,9 @@ void nr_timer_stop(NR_timer_t *timer) timer->counter = 0; } -bool is_nr_timer_active(NR_timer_t timer) +bool nr_timer_is_active(const NR_timer_t *timer) { - return timer.active; + return timer->active; } bool nr_timer_tick(NR_timer_t *timer) @@ -1173,23 +1173,23 @@ bool nr_timer_tick(NR_timer_t *timer) timer->counter += timer->step; if (timer->target == UINT_MAX) // infinite target, never expires return false; - expired = nr_timer_expired(*timer); + expired = nr_timer_expired(timer); if (expired) timer->active = false; } return expired; } -bool nr_timer_expired(NR_timer_t timer) +bool nr_timer_expired(const NR_timer_t *timer) { - if (timer.target == UINT_MAX) // infinite target, never expires + if (timer->target == UINT_MAX) // infinite target, never expires return false; - return (timer.counter >= timer.target); + return timer->counter >= timer->target; } -uint32_t nr_timer_elapsed_time(NR_timer_t timer) +uint32_t nr_timer_elapsed_time(const NR_timer_t *timer) { - return timer.counter; + return timer->counter; } void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t step) diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index fcefa29461..0f29492181 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -163,19 +163,19 @@ void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t ste * @param timer Timer to be checked * @return Indication if the timer is expired or not */ -bool nr_timer_expired(NR_timer_t timer); +bool nr_timer_expired(const NR_timer_t *timer); /** * @brief To check if a timer is active * @param timer Timer to be checked * @return Indication if the timer is active or not */ -bool is_nr_timer_active(NR_timer_t timer); +bool nr_timer_is_active(const NR_timer_t *timer); /** * @brief To return how much time has passed since start of timer * @param timer Timer to be checked * @return Time passed since start of timer */ -uint32_t nr_timer_elapsed_time(NR_timer_t timer); +uint32_t nr_timer_elapsed_time(const NR_timer_t *timer); extern const nr_bandentry_t nr_bandtable[]; diff --git a/common/utils/nr/tests/test_nr_common.cpp b/common/utils/nr/tests/test_nr_common.cpp index fede91b8ee..c780736a51 100644 --- a/common/utils/nr/tests/test_nr_common.cpp +++ b/common/utils/nr/tests/test_nr_common.cpp @@ -29,13 +29,13 @@ TEST(nr_common, nr_timer) { NR_timer_t timer; nr_timer_setup(&timer, 10, 1); nr_timer_start(&timer); - EXPECT_TRUE(is_nr_timer_active(timer)); - EXPECT_FALSE(nr_timer_expired(timer)); + EXPECT_TRUE(nr_timer_is_active(&timer)); + EXPECT_FALSE(nr_timer_expired(&timer)); for (auto i = 0; i < 10; i++) { nr_timer_tick(&timer); } - EXPECT_FALSE(is_nr_timer_active(timer)); - EXPECT_TRUE(nr_timer_expired(timer)); + EXPECT_FALSE(nr_timer_is_active(&timer)); + EXPECT_TRUE(nr_timer_expired(&timer)); } diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c index c26e8a5629..c52a67c5a2 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c @@ -790,7 +790,7 @@ void nr_ue_get_rach(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, uint8_t gNB } } - if (is_nr_timer_active(ra->contention_resolution_timer)) { + if (nr_timer_is_active(&ra->contention_resolution_timer)) { nr_ue_contention_resolution(mac, CC_id, frame, nr_slot_tx, prach_resources); } } @@ -851,7 +851,7 @@ void nr_ue_contention_resolution(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame { RA_config_t *ra = &mac->ra; - if (nr_timer_expired(ra->contention_resolution_timer)) { + if (nr_timer_expired(&ra->contention_resolution_timer)) { ra->t_crnti = 0; nr_timer_stop(&ra->contention_resolution_timer); // Signal PHY to quit RA procedure diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index ac743c0f60..ccfa861587 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2543,7 +2543,7 @@ int8_t nr_ue_get_SR(NR_UE_MAC_INST_t *mac, frame_t frame, slot_t slot, NR_Schedu sr_id); // todo // TODO check if the PUCCH resource for the SR transmission occasion does not overlap with a UL-SCH resource - if (!sr_info->pending || is_nr_timer_active(sr_info->prohibitTimer)) + if (!sr_info->pending || nr_timer_is_active(&sr_info->prohibitTimer)) return 0; if (sr_info->counter < sr_info->maxTransmissions) { diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 557a393ce2..b66ff3203c 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -1297,7 +1297,7 @@ static void nr_update_sr(NR_UE_MAC_INST_t *mac) // if a Regular BSR has been triggered and logicalChannelSR-DelayTimer is not running if (((sched_info->BSR_reporting_active & NR_BSR_TRIGGER_REGULAR) == 0) - || is_nr_timer_active(sched_info->sr_DelayTimer)) + || nr_timer_is_active(&sched_info->sr_DelayTimer)) return; nr_lcordered_info_t *lc_info = get_lc_info_from_lcid(mac, sched_info->regularBSR_trigger_lcid); @@ -1527,7 +1527,7 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info) NR_LC_SCHEDULING_INFO *sched_info = get_scheduling_info_from_lcid(mac, lcid); int32_t bj = sched_info->Bj; if (lc_info->pbr < UINT_MAX) { - uint32_t slots_elapsed = nr_timer_elapsed_time(sched_info->Bj_timer); // slots elapsed since Bj was last incremented + uint32_t slots_elapsed = nr_timer_elapsed_time(&sched_info->Bj_timer); // slots elapsed since Bj was last incremented // it is safe to divide by 1k since pbr in lc_info is computed multiplying by 1000 the RRC value to convert kB/s to B/s uint32_t pbr_ms = lc_info->pbr / 1000; bj += ((pbr_ms * slots_elapsed) >> mac->current_UL_BWP->scs); // each slot length is 1/scs ms diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index eb5113ccee..fc3693ea7b 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -479,7 +479,7 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc, // Actions following cell selection while T311 is running NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; - if (is_nr_timer_active(timers->T311)) { + if (nr_timer_is_active(&timers->T311)) { nr_timer_stop(&timers->T311); rrc->ra_trigger = RRC_CONNECTION_REESTABLISHMENT; @@ -1695,7 +1695,7 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc, void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded) { NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants; - if (ra_succeeded && is_nr_timer_active(timers->T304)) { + if (ra_succeeded && nr_timer_is_active(&timers->T304)) { // successful Random Access procedure triggered by reconfigurationWithSync nr_timer_stop(&timers->T304); // TODO handle the rest of procedures as described in 5.3.5.3 for when @@ -2218,14 +2218,14 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc, } } if (!waitTime) { - if (is_nr_timer_active(tac->T302)) { + if (nr_timer_is_active(&tac->T302)) { nr_timer_stop(&tac->T302); // TODO barring alleviation as in 5.3.14.4 // not implemented LOG_E(NR_RRC,"Go to IDLE. Barring alleviation not implemented\n"); } } - if (is_nr_timer_active(tac->T390)) { + if (nr_timer_is_active(&tac->T390)) { nr_timer_stop(&tac->T390); // TODO barring alleviation as in 5.3.14.4 // not implemented diff --git a/openair2/RRC/NR_UE/rrc_timers_and_constants.c b/openair2/RRC/NR_UE/rrc_timers_and_constants.c index 70a467691b..9e734a3188 100644 --- a/openair2/RRC/NR_UE/rrc_timers_and_constants.c +++ b/openair2/RRC/NR_UE/rrc_timers_and_constants.c @@ -560,7 +560,7 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac, { if (sync_msg == IN_SYNC) { tac->N310_cnt = 0; - if (is_nr_timer_active(tac->T310)) { + if (nr_timer_is_active(&tac->T310)) { tac->N311_cnt++; // Upon receiving N311 consecutive "in-sync" indications if (tac->N311_cnt >= tac->N311_k) { @@ -573,12 +573,12 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac, else { // OUT_OF_SYNC tac->N311_cnt = 0; - if(is_nr_timer_active(tac->T300) || - is_nr_timer_active(tac->T301) || - is_nr_timer_active(tac->T304) || - is_nr_timer_active(tac->T310) || - is_nr_timer_active(tac->T311) || - is_nr_timer_active(tac->T319)) + if(nr_timer_is_active(&tac->T300) || + nr_timer_is_active(&tac->T301) || + nr_timer_is_active(&tac->T304) || + nr_timer_is_active(&tac->T310) || + nr_timer_is_active(&tac->T311) || + nr_timer_is_active(&tac->T319)) return; tac->N310_cnt++; // upon receiving N310 consecutive "out-of-sync" indications From 303e724845c3abf34d3abc736ef83807138d97f1 Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 2 Aug 2024 15:14:15 +0100 Subject: [PATCH 39/61] Always set firstActive/defaultBWP Always set the firstActive and defaultBWP in the initial cellGroupConfig. This is necessary to make the Quectel accept the handover RRCReconfiguration; it seems that this also works reliably in normal connection set up, so we can add it. --- openair2/RRC/NR/nr_rrc_config.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index e5f0c295b5..5631da4c0e 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -2805,6 +2805,8 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, && servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count > 0) { n_dl_bwp = servingcellconfigdedicated->downlinkBWP_ToAddModList->list.count; } + int default_dl_bwp = 0; + int first_active_dl_bwp = 0; if (n_dl_bwp > 0) { SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList)); @@ -2813,15 +2815,13 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, config_downlinkBWP(bwp, scc, servingcellconfigdedicated, NULL, 0, false, bwp_loop, true); asn1cSeqAdd(&SpCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list, bwp); } - SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = - calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id)); - *SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = - servingcellconfigdedicated->firstActiveDownlinkBWP_Id ? *servingcellconfigdedicated->firstActiveDownlinkBWP_Id : 1; - SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = - calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id)); - *SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = - servingcellconfigdedicated->defaultDownlinkBWP_Id ? *servingcellconfigdedicated->defaultDownlinkBWP_Id : 1; + const NR_BWP_Id_t *firstActiveDownlinkBWP_Id = servingcellconfigdedicated->firstActiveDownlinkBWP_Id; + first_active_dl_bwp = firstActiveDownlinkBWP_Id ? *firstActiveDownlinkBWP_Id : 1; + const NR_BWP_Id_t *defaultDownlinkBWP_Id = servingcellconfigdedicated->defaultDownlinkBWP_Id; + default_dl_bwp = defaultDownlinkBWP_Id ? *defaultDownlinkBWP_Id : 1; } + asn1cCallocOne(SpCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id, first_active_dl_bwp); + asn1cCallocOne(SpCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id, default_dl_bwp); // Uplink BWPs int n_ul_bwp = 0; @@ -2830,6 +2830,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, && servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count > 0) { n_ul_bwp = servingcellconfigdedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count; } + int first_active_ul_bwp = 0; if (n_ul_bwp > 0) { uplinkConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*uplinkConfig->uplinkBWP_ToAddModList)); for (int bwp_loop = 0; bwp_loop < n_ul_bwp; bwp_loop++) { @@ -2837,11 +2838,10 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, config_uplinkBWP(ubwp, bwp_loop, true, uid, configuration, servingcellconfigdedicated, scc, NULL); asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ubwp); } - uplinkConfig->firstActiveUplinkBWP_Id = calloc(1, sizeof(*uplinkConfig->firstActiveUplinkBWP_Id)); - *uplinkConfig->firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id - ? *servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id - : 1; + const NR_BWP_Id_t *firstActiveUplinkBWP_Id = servingcellconfigdedicated->uplinkConfig->firstActiveUplinkBWP_Id; + first_active_ul_bwp = firstActiveUplinkBWP_Id ? *firstActiveUplinkBWP_Id : 1; } + asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_ul_bwp); SpCellConfig->spCellConfigDedicated->csi_MeasConfig = calloc(1, sizeof(*SpCellConfig->spCellConfigDedicated->csi_MeasConfig)); SpCellConfig->spCellConfigDedicated->csi_MeasConfig->present = NR_SetupRelease_CSI_MeasConfig_PR_setup; From e63232576e2088e47bf5fdd26932803e5f0bfd9d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 6 Aug 2024 13:50:22 +0200 Subject: [PATCH 40/61] RRC stats: print DU's SSB ARFCN --- openair2/RRC/NR/rrc_gNB_du.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index b24e6f594c..43b657d91e 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -501,7 +501,7 @@ void dump_du_info(const gNB_RRC_INST *rrc, FILE *f) fprintf(f, "assoc_id %d", du->assoc_id); } const f1ap_served_cell_info_t *info = &sr->cell[0].info; - fprintf(f, ": nrCellID %ld, PCI %d\n", info->nr_cellid, info->nr_pci); + fprintf(f, ": nrCellID %ld, PCI %d, SSB ARFCN %d\n", info->nr_cellid, info->nr_pci, get_ssb_arfcn(du)); if (info->mode == F1AP_MODE_TDD) { const f1ap_nr_frequency_info_t *fi = &info->tdd.freqinfo; From e01957e89088304969345861762b5d0195fdfc18 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 3 Jun 2024 11:01:50 +0200 Subject: [PATCH 41/61] Remove RRC status: it is not needed --- openair2/RRC/NR/nr_rrc_defs.h | 1 - openair2/RRC/NR/rrc_gNB.c | 17 ----------------- 2 files changed, 18 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index a9234ed5bd..4159362921 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -284,7 +284,6 @@ typedef struct gNB_RRC_UE_s { NR_CipheringAlgorithm_t ciphering_algorithm; e_NR_IntegrityProtAlgorithm integrity_algorithm; - NR_UE_STATE_t StatusRrc; rnti_t rnti; uint64_t random_ue_identity; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b884a2d808..7d7f40e9df 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -477,7 +477,6 @@ static void rrc_gNB_process_RRCSetupComplete(const protocol_ctxt_t *const ctxt_p LOG_A(NR_RRC, "UE %d Processing NR_RRCSetupComplete from UE\n", ue_context_pP->ue_context.rrc_ue_id); ue_context_pP->ue_context.Srb[1].Active = 1; ue_context_pP->ue_context.Srb[2].Active = 0; - ue_context_pP->ue_context.StatusRrc = NR_RRC_CONNECTED; AssertFatal(ctxt_pP->rntiMaybeUEid == ue_context_pP->ue_context.rrc_ue_id, "logic bug: inconsistent IDs, must use CU UE ID!\n"); rrc_gNB_send_NGAP_NAS_FIRST_REQ(ctxt_pP, ue_context_pP, rrcSetupComplete); @@ -935,7 +934,6 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co int i = 0; ue_p->xids[xid] = RRC_ACTION_NONE; - ue_p->StatusRrc = NR_RRC_CONNECTED; ue_p->Srb[1].Active = 1; @@ -2262,20 +2260,6 @@ static void print_rrc_meas(FILE *f, const NR_MeasResults_t *measresults) } } -static const char *get_rrc_connection_status_text(NR_UE_STATE_t state) -{ - switch (state) { - case NR_RRC_INACTIVE: return "inactive"; - case NR_RRC_IDLE: return "idle"; - case NR_RRC_SI_RECEIVED: return "SI-received"; - case NR_RRC_CONNECTED: return "connected"; - case NR_RRC_RECONFIGURED: return "reconfigured"; - case NR_RRC_HO_EXECUTION: return "HO-execution"; - default: AssertFatal(false, "illegal RRC state %d\n", state); return "illegal"; - } - return "illegal"; -} - static const char *get_pdusession_status_text(pdu_session_status_t status) { switch (status) { @@ -2323,7 +2307,6 @@ static void write_rrc_stats(const gNB_RRC_INST *rrc) time_t last_seen = now - ue_ctxt->last_seen; fprintf(f, " last RRC activity: %ld seconds ago\n", last_seen); - fprintf(f, " RRC status %s\n", get_rrc_connection_status_text(ue_ctxt->StatusRrc)); if (ue_ctxt->nb_of_pdusessions == 0) fprintf(f, " (no PDU sessions)\n"); From 125210fa1e523826c15271f5dfaa01730c6b452e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 6 Aug 2024 13:49:45 +0200 Subject: [PATCH 42/61] RRC: Correct some logs --- openair2/RRC/NR/rrc_gNB.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 7d7f40e9df..813bbd0310 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1233,11 +1233,11 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, switch (event_triggered->eventId.present) { case NR_EventTriggerConfig__eventId_PR_eventA2: - LOG_I(NR_RRC, "\nHO LOG: Event A2 (Serving becomes worse than threshold)\n"); + LOG_I(NR_RRC, "HO LOG: Event A2 (Serving becomes worse than threshold)\n"); break; case NR_EventTriggerConfig__eventId_PR_eventA3: { - LOG_I(NR_RRC, "\nHO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n"); + LOG_I(NR_RRC, "HO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n"); const NR_MeasResults_t *measResults = &measurementReport->criticalExtensions.choice.measurementReport->measResults; for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) { @@ -1272,7 +1272,7 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, } LOG_I(NR_RRC, - "HO LOG: Measurement Report has came for the neighbour: %d with RSRP: %d\n", + "HO LOG: Measurement Report for the neighbour %d with RSRP: %d\n", neighbourCellId, neighbourCellRSRP); From 94258b0fb95a74a9ddf5957fa7c845d546eeb18e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 14:46:30 +0200 Subject: [PATCH 43/61] Remove unused fields of DRB --- openair2/RRC/NR/nr_rrc_defs.h | 4 ---- openair2/RRC/NR/rrc_gNB.c | 1 - openair2/RRC/NR/rrc_gNB_radio_bearers.c | 3 --- 3 files changed, 8 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 4159362921..f4d217c8cc 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -202,11 +202,7 @@ typedef struct f1u_tunnel_s { typedef struct drb_s { int status; - int defaultDRBid; int drb_id; - int reestablishPDCP; - int recoverPDCP; - int daps_Config_r16; struct cnAssociation_s { int present; int eps_BearerIdentity; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 813bbd0310..976f11bd72 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -345,7 +345,6 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) if (ue->established_drbs[i].status != DRB_INACTIVE) { DRB_config = generateDRB_ASN1(&ue->established_drbs[i]); if (reestablish) { - ue->established_drbs[i].reestablishPDCP = NR_DRB_ToAddMod__reestablishPDCP_true; asn1cCallocOne(DRB_config->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true); } asn1cSeqAdd(&DRB_configList->list, DRB_config); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 205a58fc36..10f16cb030 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -96,10 +96,7 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, est_drb->status = DRB_ACTIVE; est_drb->drb_id = drb_id; - est_drb->reestablishPDCP = -1; - est_drb->recoverPDCP = -1; est_drb->cnAssociation.sdap_config.defaultDRB = true; - est_drb->defaultDRBid = drb_id; /* SDAP Configuration */ est_drb->cnAssociation.present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config; From d2073d924e1fd5799bf4af1e63fa83e623adc29b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 18:45:15 +0200 Subject: [PATCH 44/61] Remove unused information from PDU session --- openair2/COMMON/ngap_messages_types.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index faeb11d377..861f5e6d2c 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -278,8 +278,6 @@ typedef struct pdusession_s { transport_layer_addr_t upf_addr; /* Outgoing (UL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ uint32_t gtp_teid; - /* Stores the DRB ID of the DRBs used by this PDU Session */ - uint8_t used_drbs[MAX_DRBS_PER_UE]; /* Incoming (DL) NG-U Tunnel Endpoint Identifier (S-GW/UPF) */ uint32_t gNB_teid_N3; transport_layer_addr_t gNB_addr_N3; From 44d427bf7b6493d3bba892edf6fbd5dede808c9f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 23 Jul 2024 17:32:29 +0200 Subject: [PATCH 45/61] Rename RRC_BUF_SIZE for 5G to increase size A maximum RRC buffer size of 1024 might be very small. We should increase it, but then the 5G RRC_BUF_SIZE does conflict with other definitions. To make it unique, also rename to NR_RRC_BUF_SIZE. --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 4 ++-- openair2/RRC/NR/rrc_gNB.c | 30 ++++++++++++++--------------- openair2/RRC/NR_UE/rrc_UE.c | 4 ++-- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 3849e157c9..13f704b2c7 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1368,7 +1368,7 @@ int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi) LOG_D(NR_RRC, "[gNB %d] do_Paging paging_record: PagingRecordList.count %d\n", Mod_id, c1->choice.paging->pagingRecordList->list.count); asn_enc_rval_t enc_rval = uper_encode_to_buffer( - &asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, RRC_BUF_SIZE); + &asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, NR_RRC_BUF_SIZE); if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { xer_fprint(stdout, &asn_DEF_NR_PCCH_Message, (void *)&pcch_msg); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index f4d217c8cc..0b246aab54 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -115,7 +115,7 @@ typedef enum { #define MAX_MEAS_ID 7 #define PAYLOAD_SIZE_MAX 1024 -#define RRC_BUF_SIZE 1024 +#define NR_RRC_BUF_SIZE 4096 #define UNDEF_SECURITY_MODE 0xff #define NO_SECURITY_MODE 0x20 @@ -156,7 +156,7 @@ typedef struct HANDOVER_INFO_NR_s { //AS_Config_t as_config; /* these two parameters are taken from 36.331 section 10.2.2: HandoverPreparationInformation-r8-IEs */ //AS_Context_t as_context; /* They are mandatory for HO */ - uint8_t buf[RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */ + uint8_t buf[NR_RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */ int size; /* size of above message in bytes */ } NR_HANDOVER_INFO; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 976f11bd72..41b71af08a 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -547,13 +547,13 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c ue_p->measConfig = measconfig; - uint8_t buffer[RRC_BUF_SIZE] = {0}; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false); NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); int size = do_RRCReconfiguration(ue_p, buffer, - RRC_BUF_SIZE, + NR_RRC_BUF_SIZE, xid, SRBs, DRBs, @@ -674,10 +674,10 @@ rrc_gNB_modify_dedicatedRRCReconfiguration( } NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); - uint8_t buffer[RRC_BUF_SIZE]; + uint8_t buffer[NR_RRC_BUF_SIZE]; int size = do_RRCReconfiguration(ue_p, buffer, - RRC_BUF_SIZE, + NR_RRC_BUF_SIZE, xid, NULL, DRBs, @@ -740,10 +740,10 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release( LOG_W(NR_RRC,"dedlicated NAS list is empty\n"); } - uint8_t buffer[RRC_BUF_SIZE] = {0}; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; int size = do_RRCReconfiguration(ue_p, buffer, - RRC_BUF_SIZE, + NR_RRC_BUF_SIZE, xid, NULL, NULL, @@ -861,12 +861,12 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context module_id_t module_id = 0; gNB_RRC_INST *rrc = RC.nrrrc[module_id]; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - uint8_t buffer[RRC_BUF_SIZE] = {0}; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; uint8_t xid = rrc_gNB_get_next_transaction_identifier(module_id); ue_p->xids[xid] = RRC_REESTABLISH; const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; uint32_t ssb_arfcn = get_ssb_arfcn(du); - int size = do_RRCReestablishment(ue_context_pP, buffer, RRC_BUF_SIZE, xid, cell_info->nr_pci, ssb_arfcn); + int size = do_RRCReestablishment(ue_context_pP, buffer, NR_RRC_BUF_SIZE, xid, cell_info->nr_pci, ssb_arfcn); LOG_I(NR_RRC, "[RAPROC] UE %04x Logical Channel DL-DCCH, Generating NR_RRCReestablishment (bytes %d)\n", ue_p->rnti, size); @@ -984,10 +984,10 @@ static void rrc_gNB_process_RRCReestablishmentComplete(const protocol_ctxt_t *co uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; - uint8_t buffer[RRC_BUF_SIZE] = {0}; + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; int size = do_RRCReconfiguration(ue_p, buffer, - RRC_BUF_SIZE, + NR_RRC_BUF_SIZE, new_xid, SRBs, DRBs, @@ -1028,8 +1028,8 @@ int nr_rrc_reconfiguration_req(rrc_gNB_ue_context_t *const ue_context_pP, *masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = ul_bwp_id; } - uint8_t buffer[RRC_BUF_SIZE]; - int size = do_RRCReconfiguration(ue_p, buffer, RRC_BUF_SIZE, xid, NULL, NULL, NULL, NULL, NULL, NULL, masterCellGroup); + uint8_t buffer[NR_RRC_BUF_SIZE]; + int size = do_RRCReconfiguration(ue_p, buffer, NR_RRC_BUF_SIZE, xid, NULL, NULL, NULL, NULL, NULL, NULL, masterCellGroup); gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size); @@ -2595,8 +2595,8 @@ rrc_gNB_generate_RRCRelease( ) //----------------------------------------------------------------------------- { - uint8_t buffer[RRC_BUF_SIZE] = {0}; - int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id)); + uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; + int size = do_NR_RRCRelease(buffer, NR_RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id)); LOG_I(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT" Logical Channel DL-DCCH, Generate RRCRelease (bytes %d)\n", @@ -2628,7 +2628,7 @@ int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint uint32_t N; /* N: min(T,nB). total count of PF in one DRX cycle */ uint32_t Ns = 0; /* Ns: max(1,nB/T) */ uint32_t T; /* DRX cycle */ - uint8_t buffer[RRC_BUF_SIZE]; + uint8_t buffer[NR_RRC_BUF_SIZE]; /* get default DRX cycle from configuration */ Tc = sib1->servingCellConfigCommon->downlinkConfigCommon.pcch_Config.defaultPagingCycle; diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index fc3693ea7b..477df28703 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -2130,7 +2130,7 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, nr_SecondaryCellGroup_buffer, nr_SecondaryCellGroup_size); process_nsa_message(NR_UE_rrc_inst, nr_RadioBearerConfigX_r15, nr_RadioBearer_buffer, nr_RadioBearer_size); LOG_I(NR_RRC, "Calling do_NR_RRCReconfigurationComplete. t_id %ld \n", t_id); - uint8_t buffer[RRC_BUF_SIZE]; + uint8_t buffer[NR_RRC_BUF_SIZE]; size_t size = do_NR_RRCReconfigurationComplete_for_nsa(buffer, sizeof(buffer), t_id); nsa_sendmsg_to_lte_ue(buffer, size, NR_RRC_CONFIG_COMPLETE_REQ); break; @@ -2138,7 +2138,7 @@ static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_l case OAI_TUN_IFACE_NSA: { LOG_I(NR_RRC, "We got an OAI_TUN_IFACE_NSA!!\n"); - char cmd_line[RRC_BUF_SIZE]; + char cmd_line[NR_RRC_BUF_SIZE]; memcpy(cmd_line, msg_buffer, sizeof(cmd_line)); LOG_D(NR_RRC, "Command line: %s\n", cmd_line); if (background_system(cmd_line) != 0) From 29d8e3ce3afa890caeff8c3bb0f52a6b06cb7b9e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 25 Jul 2024 13:51:02 +0200 Subject: [PATCH 46/61] Remove unused defines and structures --- openair2/RRC/NR/nr_rrc_common.h | 8 -------- openair2/RRC/NR/nr_rrc_defs.h | 25 ------------------------- 2 files changed, 33 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_common.h b/openair2/RRC/NR/nr_rrc_common.h index e1ff2e703e..305013ecf4 100644 --- a/openair2/RRC/NR/nr_rrc_common.h +++ b/openair2/RRC/NR/nr_rrc_common.h @@ -26,17 +26,9 @@ #include #include -#define NR_RRC_HEADER_SIZE_MAX 64 -#define NR_RRC_BUFFER_SIZE_MAX 1024 #define NR_NUM_SRB 4 /* Number of Signalling Radio Bearers according to clause 4.2.2 of 3GPP TS 38.331 */ #define NR_K_KEY_SIZE 16 /* K keys have 128 bits length */ -typedef struct { - char Payload[NR_RRC_BUFFER_SIZE_MAX]; - char Header[NR_RRC_HEADER_SIZE_MAX]; - uint16_t payload_size; -} NR_RRC_BUFFER; - typedef enum UE_STATE_NR_e { NR_RRC_INACTIVE=0, NR_RRC_IDLE, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 0b246aab54..8ade5409e0 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -88,15 +88,6 @@ #define NR_RRC_RECONFIGURATION_DELAY_MS 10 #define NR_RRC_BWP_SWITCHING_DELAY_MS 6 -// 3GPP TS 38.133 - Section 8 - Table 8.2.1.2.7-2: Parameters which cause interruption other than SCS -// This table was recently added to 3GPP. It shows that changing the parameters locationAndBandwidth, nrofSRS-Ports or -// maxMIMO-Layers-r16 causes an interruption. This parameter is not yet being used in code, but has been placed here -// for future reference. -#define NR_OF_SRS_PORTS_SWITCHING_DELAY_MS 30 - -#define NR_UE_MODULE_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! -#define NR_UE_INDEX_INVALID ((module_id_t) ~0) // FIXME attention! depends on type uint8_t!!! used to be -1 - typedef enum { NR_RRC_OK=0, NR_RRC_ConnSetup_failed, @@ -105,16 +96,10 @@ typedef enum { NR_RRC_HO_STARTED } NR_RRC_status_t; -#define RRM_FREE(p) if ( (p) != NULL) { free(p) ; p=NULL ; } -#define RRM_MALLOC(t,n) (t *) malloc16( sizeof(t) * n ) -#define RRM_CALLOC(t,n) (t *) malloc16( sizeof(t) * n) -#define RRM_CALLOC2(t,s) (t *) malloc16( s ) - #define MAX_MEAS_OBJ 7 #define MAX_MEAS_CONFIG 7 #define MAX_MEAS_ID 7 -#define PAYLOAD_SIZE_MAX 1024 #define NR_RRC_BUF_SIZE 4096 #define UNDEF_SECURITY_MODE 0xff #define NO_SECURITY_MODE 0x20 @@ -129,14 +114,6 @@ typedef struct UE_S_TMSI_NR_s { uint32_t fiveg_tmsi; } __attribute__ ((__packed__)) NR_UE_S_TMSI; - -typedef enum nr_e_rab_satus_e { - NR_E_RAB_STATUS_NEW, - NR_E_RAB_STATUS_DONE, // from the gNB perspective - NR_E_RAB_STATUS_ESTABLISHED, // get the reconfigurationcomplete form UE - NR_E_RAB_STATUS_FAILED, -} nr_e_rab_status_t; - typedef struct nr_e_rab_param_s { e_rab_t param; uint8_t status; @@ -160,8 +137,6 @@ typedef struct HANDOVER_INFO_NR_s { int size; /* size of above message in bytes */ } NR_HANDOVER_INFO; -#define NR_RRC_BUFFER_SIZE sizeof(RRC_BUFFER_NR) - typedef struct nr_rrc_guami_s { uint16_t mcc; uint16_t mnc; From d00ac2031cc84b0ee3fb4d65933ee017e301c91a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 14:50:44 +0200 Subject: [PATCH 47/61] Correct F1-U TEID variable names, simplify code In e1_send_bearer_updates(), we send the DL (DU) TEID and address to the CU-UP. Therefore, correct the variable names to reflect that the F1-U information pertains to the DU. Also, move the tunnel info update function f1u_dl_gtp_update() to a more prominent place, and take the pointer to the struct containing the "interesting" information. --- openair2/RRC/NR/nr_rrc_defs.h | 12 ++++++------ openair2/RRC/NR/rrc_gNB.c | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 8ade5409e0..234c42daaf 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -169,10 +169,10 @@ typedef struct pdu_session_param_s { * @brief F1-U tunnel configuration */ typedef struct f1u_tunnel_s { - /* Downlink F1-U Tunnel Endpoint Identifier (CU-UP/DU) */ - uint32_t cuup_teid_f1u; - /* DL F1-U Transport Layer */ - transport_layer_addr_t cuup_addr_f1u; + /* F1-U Tunnel Endpoint Identifier (on DU side) */ + uint32_t teid; + /* Downlink F1-U Transport Layer (on DU side) */ + transport_layer_addr_t addr; } f1u_tunnel_t; typedef struct drb_s { @@ -203,8 +203,8 @@ typedef struct drb_s { int cipheringDisabled; } ext1; } pdcp_config; - // F1-U - f1u_tunnel_t f1u_tunnel_config; + // F1-U Downlink Tunnel Config (on DU side) + f1u_tunnel_t du_tunnel_config; } drb_t; typedef enum { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 41b71af08a..2b0d45ed5a 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -828,8 +828,8 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) drb_e1->id = drb_id; drb_e1->numDlUpParam = 1; drb_t *drbs = &ue_p->established_drbs[drb_id]; - memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drbs->f1u_tunnel_config.cuup_addr_f1u.buffer, sizeof(uint8_t) * 4); - drb_e1->DlUpParamList[0].teId = drbs->f1u_tunnel_config.cuup_teid_f1u; + memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drbs->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb_e1->DlUpParamList[0].teId = drbs->du_tunnel_config.teid; /* PDCP configuration */ bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config; drb_t *rrc_drb = get_drb(ue_p, drb_id); @@ -1868,15 +1868,15 @@ static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to /** * @brief Store F1-U DL TL and TEID in RRC */ -static void f1u_gtp_update(f1u_tunnel_t *f1u, const f1ap_drb_to_be_setup_t *drb_f1) +static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p) { - f1u->cuup_teid_f1u = drb_f1->up_dl_tnl[0].teid; - memcpy(&f1u->cuup_addr_f1u.buffer, &drb_f1->up_dl_tnl[0].tl_address, sizeof(uint8_t) * 4); - f1u->cuup_addr_f1u.length = sizeof(in_addr_t); + f1u->teid = p->teid; + memcpy(&f1u->addr.buffer, &p->tl_address, sizeof(uint8_t) * 4); + f1u->addr.length = sizeof(in_addr_t); } /* \brief use list of DRBs and send the corresponding bearer update message via - * E1 to the CU of this UE */ + * E1 to the CU of this UE. Also updates TEID info internally */ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) { // we assume the same UE ID in CU-UP and CU-CP @@ -1896,7 +1896,7 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f DevAssert(pdu_e1 != NULL); pdu_e1->sessionId = pdu_ue->param.pdusession_id; DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; - f1u_gtp_update(&UE->established_drbs[drb_f1->drb_id].f1u_tunnel_config, drb_f1); + f1u_dl_gtp_update(&UE->established_drbs[drb_f1->drb_id].du_tunnel_config, &drb_f1->up_dl_tnl[0]); /* Fill E1 bearer context modification */ fill_e1_bearer_modif(drb_e1, drb_f1); pdu_e1->numDRB2Modify += 1; From 605dfa0142d90484db4751aa06a6c9c0d86de450 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 17:54:26 +0200 Subject: [PATCH 48/61] Refactor: Store DU's DRB TEID/address through separate function A follow-up commit refactors the filling of information of DRBs to set up in a separate function (to be reused for handover later). Hence, we cannot store the DRB TEID/address in the same functions, because it is a logically separate step, and might not always be available. --- openair2/RRC/NR/rrc_gNB.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2b0d45ed5a..3d28a9fdaa 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1875,6 +1875,20 @@ static void f1u_dl_gtp_update(f1u_tunnel_t *f1u, const f1ap_up_tnl_t *p) f1u->addr.length = sizeof(in_addr_t); } +/** + * @brief Update DRB TEID information in RRC storage from received DRB list + */ +static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_RRC_UE_t *ue) +{ + for (int i = 0; i < n; i++) { + const f1ap_drb_to_be_setup_t *drb_f1 = &drbs[i]; + AssertFatal(drb_f1->up_dl_tnl_length == 1, "can handle only one UP param\n"); + AssertFatal(drb_f1->drb_id < MAX_DRBS_PER_UE, "illegal DRB ID %ld\n", drb_f1->drb_id); + drb_t *drb = get_drb(ue, drb_f1->drb_id); + f1u_dl_gtp_update(&drb->du_tunnel_config, &drb_f1->up_dl_tnl[0]); + } +} + /* \brief use list of DRBs and send the corresponding bearer update message via * E1 to the CU of this UE. Also updates TEID info internally */ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) @@ -1896,7 +1910,6 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f DevAssert(pdu_e1 != NULL); pdu_e1->sessionId = pdu_ue->param.pdusession_id; DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; - f1u_dl_gtp_update(&UE->established_drbs[drb_f1->drb_id].du_tunnel_config, &drb_f1->up_dl_tnl[0]); /* Fill E1 bearer context modification */ fill_e1_bearer_modif(drb_e1, drb_f1); pdu_e1->numDRB2Modify += 1; @@ -1946,6 +1959,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance /* Note: we would ideally check that SRB2 is acked, but at least LiteOn DU * seems buggy and does not ack, so simply check that locally we activated */ AssertFatal(UE->Srb[1].Active && UE->Srb[2].Active, "SRBs 1 and 2 must be active during DRB Establishment"); + store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE); e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); } @@ -2023,6 +2037,7 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i gNB_RRC_UE_t *UE = &ue_context_p->ue_context; if (resp->drbs_to_be_setup_length > 0) { + store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE); e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); } From e7eb1b1c3bda680b1ee94c2afa9b844b6d81e138 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 17:52:07 +0200 Subject: [PATCH 49/61] Store DRB UL TEID information at RRC To be used later in the case of handover. --- openair2/RRC/NR/nr_rrc_defs.h | 2 ++ openair2/RRC/NR/rrc_gNB.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 234c42daaf..de4bd5f5ec 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -205,6 +205,8 @@ typedef struct drb_s { } pdcp_config; // F1-U Downlink Tunnel Config (on DU side) f1u_tunnel_t du_tunnel_config; + // F1-U Uplink Tunnel Config (on CU-UP side) + f1u_tunnel_t cuup_tunnel_config; } drb_t; typedef enum { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 3d28a9fdaa..4e5593e8b5 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1889,6 +1889,16 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R } } +/* + * @brief Store F1-U UL TEID and address in RRC + */ +static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p) +{ + f1u->teid = p->teId; + memcpy(&f1u->addr.buffer, &p->tlAddress, sizeof(uint8_t) * 4); + f1u->addr.length = sizeof(in_addr_t); +} + /* \brief use list of DRBs and send the corresponding bearer update message via * E1 to the CU of this UE. Also updates TEID info internally */ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_to_be_setup_t *drbs) @@ -2165,6 +2175,15 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp rrc_pdu->param.gNB_teid_N3 = e1_pdu->teId; memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tlAddress, sizeof(uint8_t) * 4); rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t); + + // save the tunnel address for the DRBs + for (int i = 0; i < e1_pdu->numDRBSetup; i++) { + DRB_nGRAN_setup_t *drb_config = &e1_pdu->DRBnGRanList[i]; + // numUpParam only relevant in F1, but not monolithic + AssertFatal(drb_config->numUpParam <= 1, "can only up to one UP param\n"); + drb_t *drb = get_drb(UE, drb_config->id); + f1u_ul_gtp_update(&drb->cuup_tunnel_config, &drb_config->UpParamList[0]); + } } /* Instruction towards the DU for DRB configuration and tunnel creation */ From fe9c0fba2fcef94619df13a36236ccd508aba588 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 5 Jun 2024 18:23:32 +0200 Subject: [PATCH 50/61] Refactor DRB filling from E1 response in separate function Refactor this to allow the reuse of this function for handover later. --- openair2/RRC/NR/rrc_gNB.c | 108 ++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 4e5593e8b5..c7e21671bc 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2147,6 +2147,67 @@ static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, return NULL; } +/* \bref return F1AP QoS characteristics based on Qos flow parameters */ +static f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param) +{ + f1ap_qos_characteristics_t qos_char = {0}; + if (qos_param->fiveQI_type == dynamic) { + qos_char.qos_type = dynamic; + qos_char.dynamic.fiveqi = qos_param->fiveQI; + qos_char.dynamic.qos_priority_level = qos_param->qos_priority; + } else { + qos_char.qos_type = non_dynamic; + qos_char.non_dynamic.fiveqi = qos_param->fiveQI; + qos_char.non_dynamic.qos_priority_level = qos_param->qos_priority; + } + return qos_char; +} + +/* \brief fills a list of DRBs to be setup from a number of PDU sessions in E1 + * bearer setup response */ +static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + const pdu_session_setup_t *pduSession, + int numPduSession, + f1ap_drb_to_be_setup_t drbs[32]) +{ + int nb_drb = 0; + for (int p = 0; p < numPduSession; ++p) { + rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, pduSession[p].id, false); + DevAssert(RRC_pduSession); + for (int i = 0; i < pduSession[p].numDRBSetup; i++) { + const DRB_nGRAN_setup_t *drb_config = &pduSession[p].DRBnGRanList[i]; + f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; + drb->drb_id = pduSession[p].DRBnGRanList[i].id; + drb->rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; + drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; + drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; + drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; + drb->up_ul_tnl_length = 1; + + /* pass QoS info to MAC */ + int nb_qos_flows = drb_config->numQosFlowSetup; + AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n"); + drb->drb_info.flows_to_be_setup_length = nb_qos_flows; + drb->drb_info.flows_mapped_to_drb = calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t)); + AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); + for (int j = 0; j < nb_qos_flows; j++) { + drb->drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi; + pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession); + drb->drb_info.flows_mapped_to_drb[j].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char); + } + /* the DRB QoS parameters: we just reuse the ones from the first flow */ + drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; + + /* pass NSSAI info to MAC */ + drb->nssai = RRC_pduSession->param.nssai; + + nb_drb++; + } + } + return nb_drb; +} + /** * @brief E1AP Bearer Context Setup Response processing on CU-CP */ @@ -2188,52 +2249,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp /* Instruction towards the DU for DRB configuration and tunnel creation */ f1ap_drb_to_be_setup_t drbs[32]; // maximum DRB can be 32 - int nb_drb = 0; - for (int p = 0; p < resp->numPDUSessions; ++p) { - rrc_pdu_session_param_t *RRC_pduSession = find_pduSession(UE, resp->pduSession[p].id, false); - DevAssert(RRC_pduSession); - for (int i = 0; i < resp->pduSession[p].numDRBSetup; i++) { - DRB_nGRAN_setup_t *drb_config = &resp->pduSession[p].DRBnGRanList[i]; - f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; - drb->drb_id = resp->pduSession[p].DRBnGRanList[i].id; - drb->rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; - drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; - drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; - drb->up_ul_tnl_length = 1; - - drb->nssai = RRC_pduSession->param.nssai; - - /* pass QoS info to MAC */ - int nb_qos_flows = drb_config->numQosFlowSetup; - AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n"); - drb->drb_info.flows_to_be_setup_length = nb_qos_flows; - drb->drb_info.flows_mapped_to_drb = calloc(nb_qos_flows, sizeof(f1ap_flows_mapped_to_drb_t)); - AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n"); - for (int j = 0; j < nb_qos_flows; j++) { - drb->drb_info.flows_mapped_to_drb[j].qfi = drb_config->qosFlows[j].qfi; - - pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(drb_config->qosFlows[j].qfi, RRC_pduSession); - f1ap_qos_characteristics_t *qos_char = &drb->drb_info.flows_mapped_to_drb[j].qos_params.qos_characteristics; - if (in_qos_char->fiveQI_type == dynamic) { - qos_char->qos_type = dynamic; - qos_char->dynamic.fiveqi = in_qos_char->fiveQI; - qos_char->dynamic.qos_priority_level = in_qos_char->qos_priority; - } else { - qos_char->qos_type = non_dynamic; - qos_char->non_dynamic.fiveqi = in_qos_char->fiveQI; - qos_char->non_dynamic.qos_priority_level = in_qos_char->qos_priority; - } - } - /* the DRB QoS parameters: we just reuse the ones from the first flow */ - drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params; - - /* pass NSSAI info to MAC */ - drb->nssai = RRC_pduSession->param.nssai; - - nb_drb++; - } - } + int nb_drb = fill_drb_to_be_setup_from_e1_resp(rrc, UE, resp->pduSession, resp->numPDUSessions, drbs); if (!UE->f1_ue_context_active) rrc_gNB_generate_UeContextSetupRequest(rrc, ue_context_p, nb_drb, drbs); From 35f7225fb4132314b2f74fc7ac84b899344924b9 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 24 Jul 2024 16:09:52 +0200 Subject: [PATCH 51/61] Correct cuup_notify_reestablishment() look up errors cuup_notify_reestablishment() used &ue_p->established_drbs[drb_id] to look up a bearer, which is wrong, because it should be drb_id - 1 as in the top of the loop. Also, it used the dedicated get_drb() function; harmonize to use only this function. --- openair2/RRC/NR/rrc_gNB.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index c7e21671bc..b1ab58b2ff 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -806,7 +806,8 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) return; /* loop through active DRBs */ for (int drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) { - if (ue_p->established_drbs[drb_id - 1].status == DRB_INACTIVE) + drb_t *drb = get_drb(ue_p, drb_id); + if (drb->status == DRB_INACTIVE) continue; /* fetch an existing PDU session for this DRB */ rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue_p, drb_id); @@ -827,13 +828,11 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; drb_e1->id = drb_id; drb_e1->numDlUpParam = 1; - drb_t *drbs = &ue_p->established_drbs[drb_id]; - memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drbs->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb_e1->DlUpParamList[0].teId = drbs->du_tunnel_config.teid; + memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb_e1->DlUpParamList[0].teId = drb->du_tunnel_config.teid; /* PDCP configuration */ bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config; - drb_t *rrc_drb = get_drb(ue_p, drb_id); - set_bearer_context_pdcp_config(pdcp_config, rrc_drb, rrc->configuration.um_on_default_drb); + set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb); pdcp_config->pDCP_Reestablishment = true; /* increase DRB to modify counter */ pdu_e1->numDRB2Modify += 1; From 1a9df52cf3363a45f647c8e105134eb66277471a Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 24 Jul 2024 16:12:41 +0200 Subject: [PATCH 52/61] Fixup get_drb(): can have up to 32 DRBs --- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 10f16cb030..ab2bf13071 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -51,7 +51,7 @@ rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) { - DevAssert(drb_id > 0 && drb_id < 32); + DevAssert(drb_id > 0 && drb_id <= 32); DevAssert(ue != NULL); return &ue->established_drbs[drb_id - 1]; From b3d04c1bbf09235be3e50761f916850b93bf7a42 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 14 Aug 2024 15:58:45 +0200 Subject: [PATCH 53/61] RETURN_IF_INVALID_ASSOC_ID(): use assoc_id directly In some cases, we don't have the ue_data that is used until this commit. Make this macro more general by only requiring the assoc_id to check. --- openair2/RRC/NR/rrc_gNB.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b1ab58b2ff..6035d05a67 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -113,9 +113,9 @@ mui_t rrc_gNB_mui = 0; // the assoc_id might be 0 (if the DU goes offline). Below helper macro to // print an error and return from the function in that case -#define RETURN_IF_INVALID_ASSOC_ID(ue_data) \ +#define RETURN_IF_INVALID_ASSOC_ID(assoc_id) \ { \ - if (ue_data.du_assoc_id == 0) { \ + if (assoc_id == 0) { \ LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); \ return; \ } \ @@ -197,7 +197,7 @@ void nr_rrc_transfer_protected_rrc_message(const gNB_RRC_INST *rrc, { DevAssert(size > 0); f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_dl_rrc_message_t dl_rrc = {.gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, .srb_id = srb_id}; deliver_dl_rrc_message_data_t data = {.rrc = rrc, .dl_rrc = &dl_rrc, .assoc_id = ue_data.du_assoc_id}; nr_pdcp_data_req_srb(ue_p->rrc_ue_id, @@ -423,7 +423,7 @@ static void rrc_gNB_generate_RRCSetup(instance_t instance, LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buf, size, "[MSG] RRC Setup\n"); freeSRBlist(SRBs); f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_dl_rrc_message_t dl_rrc = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -453,7 +453,7 @@ static void rrc_gNB_generate_RRCReject(module_id_t module_id, rrc_gNB_ue_context LOG_I(NR_RRC, " [RAPROC] ue %04x Logical Channel DL-CCCH, Generating NR_RRCReject (bytes %d)\n", ue_p->rnti, size); f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_dl_rrc_message_t dl_rrc = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -899,7 +899,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context &security_parameters); /* F1AP DL RRC Message Transfer */ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); uint32_t old_gNB_DU_ue_id = old_rnti; f1ap_dl_rrc_message_t dl_rrc = {.gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -2655,7 +2655,7 @@ rrc_gNB_generate_RRCRelease( gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; const gNB_RRC_UE_t *UE = &ue_context_pP->ue_context; f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_ue_context_release_cmd_t ue_context_release_cmd = { .gNB_CU_ue_id = UE->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -2781,7 +2781,7 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc, /* the callback will fill the UE context setup request and forward it */ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_ue_context_setup_t ue_context_setup_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, @@ -2825,7 +2825,7 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, } f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); - RETURN_IF_INVALID_ASSOC_ID(ue_data); + RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id); f1ap_ue_context_modif_req_t ue_context_modif_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, From b01810a8580baec28736d5e7fd89ef6370713b16 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 08:20:07 +0200 Subject: [PATCH 54/61] Introduce an_release flag: only free UE in RRC+ack if requested by core The F1AP UE context release procedure can happen in at least two cases: 1. core requested a release of a UE 2. CU requests DU a release of a UE without a core release (e.g., handover) In case 1., the CU has to fully release the UE in the CU, then ack the NGAP message from the core, whilst in 2., nothing of that should happen after the DU acknowledges the F1AP UE context release cmd. --- openair2/RRC/NR/nr_rrc_defs.h | 2 ++ openair2/RRC/NR/rrc_gNB.c | 8 +++++++- openair2/RRC/NR/rrc_gNB_NGAP.c | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index de4bd5f5ec..cff7395934 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -289,6 +289,8 @@ typedef struct gNB_RRC_UE_s { uint32_t ue_reestablishment_counter; uint32_t ue_reconfiguration_counter; + bool an_release; // flag if core requested UE release + /* NGUEContextSetup might come with PDU sessions, but setup needs to be * delayed after security (and capability); PDU sessions are stored here */ int n_initial_pdu; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6035d05a67..d7a879d248 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2030,7 +2030,13 @@ static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p) return; } - rrc_remove_ue(RC.nrrrc[0], ue_context_p); + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + if (UE->an_release) { + /* only trigger release if it has been requested by core + * otherwise, it might be CU that requested release on a DU during normal + * operation (i.e, handover) */ + rrc_remove_ue(RC.nrrrc[0], ue_context_p); + } } static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, instance_t instance) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index a98853af28..1ef1f8c808 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1180,6 +1180,7 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_ } gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + UE->an_release = true; #ifdef E2_AGENT signal_rrc_state_changed_to(UE, RC_SM_RRC_IDLE); #endif From 327baf2938ddabfe4540589d047789149746186f Mon Sep 17 00:00:00 2001 From: Roberto Magueta Date: Tue, 3 Sep 2024 10:51:39 +0200 Subject: [PATCH 55/61] Bugfix: an A3 configuration is for a specific PCI Co-authored-by: Luis Pereira --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 13f704b2c7..85b679bc62 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1262,7 +1262,7 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, if (!neighbourCell->isIntraFrequencyNeighbour) continue; - const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->nrcell_id); + const nr_a3_event_t *a3Event = get_a3_configuration(neighbourCell->physicalCellId); if (!a3Event || is_default_a3_added) continue; From fde10b92037dcd463fad676956480caf171d1488 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 14:14:27 +0200 Subject: [PATCH 56/61] Use u64 for neighbour nr_cellid: is up to 38 bits --- openair2/GNB_APP/gnb_config.c | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 0dfe99e3cb..dea4ebc9c5 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1598,7 +1598,7 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc paramdef_t NeighbourCellParams[] = GNBNEIGHBOURCELLPARAMS_DESC; paramlist_def_t NeighbourCellParamList = {GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, NULL, 0}; config_getlist(config_get_if(), &NeighbourCellParamList, NeighbourCellParams, sizeofArray(NeighbourCellParams), neighbourpath); - LOG_D(GNB_APP, "HO LOG: For the Cell: %d Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt); + LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt); if (NeighbourCellParamList.numelt < 1) continue; diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index cff7395934..60830719b5 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -367,7 +367,7 @@ typedef struct { } nr_neighbour_gnb_configuration_t; typedef struct neighbour_cell_configuration_s { - int nr_cell_id; + uint64_t nr_cell_id; seq_arr_t *neighbour_cells; } neighbour_cell_configuration_t; From d6d7064c0b6c58e1828952211c07826493e24545 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 10:49:17 +0200 Subject: [PATCH 57/61] A3 Event is for a PCI: Rename variable to make this clear --- ci-scripts/conf_files/neighbour-config.conf | 4 ++-- openair2/GNB_APP/gnb_config.c | 4 ++-- openair2/GNB_APP/gnb_paramdef.h | 6 +++--- openair2/RRC/NR/MESSAGES/asn1_msg.c | 13 ++++++------- openair2/RRC/NR/MESSAGES/asn1_msg.h | 2 +- openair2/RRC/NR/nr_rrc_defs.h | 2 +- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/ci-scripts/conf_files/neighbour-config.conf b/ci-scripts/conf_files/neighbour-config.conf index 12b023de7a..875129365e 100644 --- a/ci-scripts/conf_files/neighbour-config.conf +++ b/ci-scripts/conf_files/neighbour-config.conf @@ -62,12 +62,12 @@ nr_measurement_configuration = { }; A3 = ({ - cell_id = -1; #Default + physCellId = -1; #Default offset = 10; hysteresis = 0; timeToTrigger = 1 }, { - cell_id = 2; + physCellId = 2; offset = 5; hysteresis = 1; timeToTrigger = 2 diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index dea4ebc9c5..ef69264ac9 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1696,12 +1696,12 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) for (int i = 0; i < A3_EventList.numelt; i++) { nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t)); AssertFatal(a3_event != NULL, "out of memory\n"); - a3_event->cell_id = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_CELL_ID_IDX].i64ptr; + a3_event->pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; - if (a3_event->cell_id == -1) + if (a3_event->pci == -1) measurementConfig->is_default_a3_configuration_exists = true; seq_arr_push_back(measurementConfig->a3_event_list, a3_event, sizeof(nr_a3_event_t)); diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index a5d8cc5b42..253d94b44a 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -324,12 +324,12 @@ typedef enum { #define MEASUREMENT_EVENTS_THRESHOLD "threshold" #define MEASUREMENT_EVENTS_PERIODICAL_BEAM_MEASUREMENT "includeBeamMeasurements" #define MEASUREMENT_EVENTS_PERIODICAL_NR_OF_RS_INDEXES "maxNrofRS_IndexesToReport" -#define MEASUREMENT_EVENTS_CELL_ID "cell_id" +#define MEASUREMENT_EVENTS_PCI_ID "physCellId" #define MEASUREMENT_EVENT_ENABLE "enable" // clang-format off #define MEASUREMENT_A3_GLOBALPARAMS_DESC \ { \ - {MEASUREMENT_EVENTS_CELL_ID, "neighbour cellId for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \ + {MEASUREMENT_EVENTS_PCI_ID, "neighbour PCI for A3Report", 0, .i64ptr = NULL, .defint64val = -1, TYPE_INT64, 0}, \ {MEASUREMENT_EVENTS_TIME_TO_TRIGGER, "a3 time to trigger", 0, .i64ptr = NULL, .defint64val = 1, TYPE_INT64, 0}, \ {MEASUREMENT_EVENTS_OFFSET, "a3 offset", 0, .i64ptr = NULL, .defint64val = 60, TYPE_INT64, 0}, \ {MEASUREMENT_EVENTS_HYSTERESIS, "a3 hysteresis", 0, .i64ptr = NULL, .defint64val = 0, TYPE_INT64, 0}, \ @@ -350,7 +350,7 @@ typedef enum { } // clang-format on -#define MEASUREMENT_EVENTS_CELL_ID_IDX 0 +#define MEASUREMENT_EVENTS_PCI_ID_IDX 0 #define MEASUREMENT_EVENTS_ENABLE_IDX 0 #define MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX 1 #define MEASUREMENT_EVENTS_A2_THRESHOLD_IDX 2 diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 85b679bc62..25baed610a 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1165,10 +1165,9 @@ static NR_ReportConfigToAddMod_t *prepare_a2_event_report(const nr_a2_event_t *a static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a3_event) { NR_ReportConfigToAddMod_t *rc_A3 = calloc(1, sizeof(*rc_A3)); - rc_A3->reportConfigId = - a3_event->cell_id == -1 - ? 3 - : a3_event->cell_id + 4; // 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID starts from 4 + // 3 is default A3 Report Config ID. So cellId(0) specific Report Config ID + // starts from 4 + rc_A3->reportConfigId = a3_event->pci == -1 ? 3 : a3_event->pci + 4; rc_A3->reportConfig.present = NR_ReportConfigToAddMod__reportConfig_PR_reportConfigNR; NR_EventTriggerConfig_t *etrc_A3 = calloc(1, sizeof(*etrc_A3)); etrc_A3->eventId.present = NR_EventTriggerConfig__eventId_PR_eventA3; @@ -1194,7 +1193,7 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a return rc_A3; } -const nr_a3_event_t *get_a3_configuration(int nr_cellid) +const nr_a3_event_t *get_a3_configuration(int pci) { gNB_RRC_INST *rrc = RC.nrrrc[0]; nr_measurement_configuration_t *measurementConfiguration = &rrc->measurementConfiguration; @@ -1203,7 +1202,7 @@ const nr_a3_event_t *get_a3_configuration(int nr_cellid) for (uint8_t i = 0; i < measurementConfiguration->a3_event_list->size; i++) { nr_a3_event_t *a3_event = (nr_a3_event_t *)seq_arr_at(measurementConfiguration->a3_event_list, i); - if (a3_event->cell_id == nr_cellid) + if (a3_event->pci == pci) return a3_event; } @@ -1266,7 +1265,7 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, if (!a3Event || is_default_a3_added) continue; - if (a3Event->cell_id == -1) + if (a3Event->pci == -1) is_default_a3_added = true; NR_ReportConfigToAddMod_t *rc_A3 = prepare_a3_event_report(a3Event); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 0d8b4c547f..623573d24f 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -143,7 +143,7 @@ int do_RRCReestablishment(rrc_gNB_ue_context_t *const ue_context_pP, int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t rrc_TransactionIdentifier); -const nr_a3_event_t *get_a3_configuration(int nr_cellid); +const nr_a3_event_t *get_a3_configuration(int pci); NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, int band, int scs, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 60830719b5..b5b27a6f4d 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -342,7 +342,7 @@ typedef struct { } nr_a2_event_t; typedef struct { - int cell_id; + int pci; long a3_offset; long hysteresis; long timeToTrigger; From 3cfc10ddaabb143e20a7fddff63e31927a8cddf7 Mon Sep 17 00:00:00 2001 From: Roberto Louro Magueta Date: Thu, 5 Sep 2024 09:12:04 +0200 Subject: [PATCH 58/61] Bugfix: an A3 configuration is for a specific PCI Co-authored-by: Luis Pereira --- openair2/RRC/NR/rrc_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index d7a879d248..f7992d9757 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1282,7 +1282,7 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, // neighbour. if (!neighbour_cell_du_context && neighbour) { // No F1 connection but static neighbour configuration is available - const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->nrcell_id); + const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->physicalCellId); // Additional check - This part can be modified according to additional cell specific Handover Margin if (a3_event_configuration && ((a3_event_configuration->a3_offset + a3_event_configuration->hysteresis) From 5d05078f4e77b47d448096830c6f6baf0b0f3fe4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 14:15:22 +0200 Subject: [PATCH 59/61] Validate neighbour config when DUs connect --- openair2/GNB_APP/gnb_config.c | 5 +++ openair2/RRC/NR/rrc_gNB_du.c | 72 +++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index ef69264ac9..0cbe75bbeb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1697,6 +1697,11 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t)); AssertFatal(a3_event != NULL, "out of memory\n"); a3_event->pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; + AssertFatal(a3_event->pci >= -1 && a3_event->pci < 1024, + "entry %s.%s must be -1<=PCI<1024, but is %d\n", + measurement_path, + MEASUREMENT_EVENTS_PCI_ID, + a3_event->pci); a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 43b657d91e..97bbb685c9 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -40,12 +40,17 @@ int get_ssb_scs(const struct f1ap_served_cell_info_t *cell_info) return cell_info->mode == F1AP_MODE_TDD ? cell_info->tdd.tbw.scs : cell_info->fdd.dl_tbw.scs; } +static int ssb_arfcn_mtc(const NR_MeasurementTimingConfiguration_t *mtc) +{ + /* format has been verified when accepting MeasurementTimingConfiguration */ + NR_MeasTimingList_t *mtlist = mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; + return mtlist->list.array[0]->frequencyAndTiming->carrierFreq; +} + int get_ssb_arfcn(const struct nr_rrc_du_container_t *du) { DevAssert(du != NULL && du->mtc != NULL); - /* format has been verified when accepting MeasurementTimingConfiguration */ - NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; - return mtlist->list.array[0]->frequencyAndTiming->carrierFreq; + return ssb_arfcn_mtc(du->mtc); } static int du_compare(const nr_rrc_du_container_t *a, const nr_rrc_du_container_t *b) @@ -197,6 +202,58 @@ static void label_intra_frequency_neighbours(gNB_RRC_INST *rrc, for_each(cell_neighbour_list, (void *)&ssb_arfcn, is_intra_frequency_neighbour); } +static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_configuration, const f1ap_served_cell_info_t *cell, int ssb_arfcn) +{ + for (int c = 0; c < neighbour_cell_configuration->size; c++) { + const neighbour_cell_configuration_t *neighbour_config = seq_arr_at(neighbour_cell_configuration, c); + for (int ni = 0; ni < neighbour_config->neighbour_cells->size; ni++) { + const nr_neighbour_gnb_configuration_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); + if (nc->nrcell_id != cell->nr_cellid) + continue; + // current cell is in the nc config, check that config matches + if (nc->physicalCellId != cell->nr_pci) { + LOG_W(NR_RRC, "Cell %ld in neighbour config: PCI mismatch (%d vs %d)\n", cell->nr_cellid, cell->nr_pci, nc->physicalCellId); + return false; + } + if (cell->tac && nc->tac != *cell->tac) { + LOG_W(NR_RRC, "Cell %ld in neighbour config: TAC mismatch (%d vs %d)\n", cell->nr_cellid, *cell->tac, nc->tac); + return false; + } + if (ssb_arfcn != nc->absoluteFrequencySSB) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: SSB ARFCN mismatch (%d vs %d)\n", + cell->nr_cellid, + ssb_arfcn, + nc->absoluteFrequencySSB); + return false; + } + if (get_ssb_scs(cell) != nc->subcarrierSpacing) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: SCS mismatch (%d vs %d)\n", + cell->nr_cellid, + get_ssb_scs(cell), + nc->subcarrierSpacing); + return false; + } + if (cell->plmn.mcc != nc->plmn.mcc || cell->plmn.mnc != nc->plmn.mnc + || cell->plmn.mnc_digit_length != nc->plmn.mnc_digit_length) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: PLMN mismatch (%03d.%0*d vs %03d.%0*d)\n", + cell->nr_cellid, + cell->plmn.mcc, + cell->plmn.mnc_digit_length, + cell->plmn.mnc, + nc->plmn.mcc, + nc->plmn.mnc_digit_length, + nc->plmn.mnc); + return false; + } + LOG_D(NR_RRC, "Cell %ld is neighbor of cell %ld\n", cell->nr_cellid, neighbour_config->nr_cell_id); + } + } + return true; +} + void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) { AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n"); @@ -264,6 +321,15 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) NR_MeasurementTimingConfiguration_t *mtc = extract_mtc(cell_info->measurement_timing_config, cell_info->measurement_timing_config_len); + if (rrc->neighbour_cell_configuration + && !valid_du_in_neighbour_configs(rrc->neighbour_cell_configuration, cell_info, ssb_arfcn_mtc(mtc))) { + LOG_E(NR_RRC, "problem with DU %ld in neighbor configuration, rejecting DU\n", req->gNB_DU_id); + f1ap_setup_failure_t fail = {.cause = F1AP_CauseMisc_unspecified}; + rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); + ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); + return; + } + const f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info; NR_MIB_t *mib = NULL; NR_SIB1_t *sib1 = NULL; From ab89324b1ec38439ed07b5f014ba1350e1f069b4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 14:15:39 +0200 Subject: [PATCH 60/61] Pretty-print PLMN in F1 Setup Request --- openair2/RRC/NR/rrc_gNB_du.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 97bbb685c9..e20121e8c2 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -276,10 +276,12 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) f1ap_served_cell_info_t *cell_info = &req->cell[0].info; if (!rrc_gNB_plmn_matches(rrc, cell_info)) { LOG_E(NR_RRC, - "PLMN mismatch: CU %d%d, DU %d%d\n", + "PLMN mismatch: CU %03d.%0*d, DU %03d%0*d\n", rrc->configuration.mcc[0], + rrc->configuration.mnc_digit_length[0], rrc->configuration.mnc[0], cell_info->plmn.mcc, + cell_info->plmn.mnc_digit_length, cell_info->plmn.mnc); f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_plmn_not_served_by_the_gNB_CU}; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); From 99d2ad8e1a75e4cdf7696b99cdd38fbed52dae71 Mon Sep 17 00:00:00 2001 From: Raphael Defosseux Date: Fri, 6 Sep 2024 14:24:15 +0200 Subject: [PATCH 61/61] chore(ci): entitlement folder should be created before copying Signed-off-by: Raphael Defosseux --- ci-scripts/cls_containerize.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py index 51fb5bf28e..03aed32929 100644 --- a/ci-scripts/cls_containerize.py +++ b/ci-scripts/cls_containerize.py @@ -450,6 +450,7 @@ class Containerize(): cmd.cd(lSourcePath) # if asterix, copy the entitlement and subscription manager configurations if self.host == 'Red Hat': + cmd.run('mkdir -p ./etc-pki-entitlement') cmd.run('cp /etc/pki/entitlement/*.pem ./etc-pki-entitlement/') baseImage = 'ran-base'