diff --git a/CMakeLists.txt b/CMakeLists.txt index b2605c529c..936938ed23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -726,7 +726,6 @@ set(SCHED_SRC_NR_UE add_library(SCHED_NR_UE_LIB ${SCHED_SRC_NR_UE}) target_link_libraries(SCHED_NR_UE_LIB PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) - # nFAPI ################################# set(NFAPI_COMMON_SRC @@ -2066,6 +2065,8 @@ add_executable(nr-softmodem ${OPENAIR1_DIR}/PHY/TOOLS/phy_scope_interface.c ) +include(${OPENAIR_DIR}/nfapi/CMakeLists.txt) + target_link_libraries(nr-softmodem PRIVATE -Wl,--start-group UTIL HASHTABLE SCTP_CLIENT SCHED_LIB SCHED_RU_LIB SCHED_NR_LIB PHY_NR PHY PHY_COMMON PHY_NR_COMMON PHY_RU GTPV1U SECURITY diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 4fd7defd0c..8870597164 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -93,7 +93,7 @@ Options: --UE-gen-nvram [output path] Specify gen_nvram_path (default \"$gen_nvram_path\") -w | --hardware - USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, None (Default) + USRP, BLADERF, LMSSDR, IRIS, SIMU, AW2SORI, AERIAL, None (Default) Adds this RF board support (in external packages installation and in compilation) -t | --transport Selects the transport protocol type, options: None, Ethernet, benetel4g, benetel5g, oran_fhlib_5g @@ -289,6 +289,10 @@ function main() { TARGET_LIST="$TARGET_LIST aw2sori_transpro" CMAKE_CMD="$CMAKE_CMD -DOAI_$2=ON" ;; + "AERIAL"|"Aerial"|"aerial") + HW="OAI_AERIAL" + CMAKE_CMD="$CMAKE_CMD -DOAI_AERIAL=ON" + ;; "None") ;; *) diff --git a/cmake_targets/tools/install_libraries_to_system.patch b/cmake_targets/tools/install_libraries_to_system.patch new file mode 100644 index 0000000000..1e28c28418 --- /dev/null +++ b/cmake_targets/tools/install_libraries_to_system.patch @@ -0,0 +1,76 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 04cfa53..6eef6d6 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -42,6 +42,8 @@ OPTION(DOCA_GPU_DPDK "Enable DOCA GPUNetIO" ON) + OPTION(NVIPC_DOCA_ENABLE "Build libnvipc.so with DOCA" ON) + OPTION(NVIPC_DOCA_GPUNETIO "Use DOCA gpunetio in DOCA GPU DMA" OFF) + ++project(gt_common_libs) ++ + find_package(PkgConfig REQUIRED) + + # Disable NVIPC_DOCA_ENABLE if DOCA version < 2 +diff --git a/nvIPC/CMakeLists.txt b/nvIPC/CMakeLists.txt +index 633bbb7..dad7a7a 100644 +--- a/nvIPC/CMakeLists.txt ++++ b/nvIPC/CMakeLists.txt +@@ -19,7 +19,7 @@ + # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +- ++include(GNUInstallDirs) + # lib: nvipc + set(SOURCES configs/nv_ipc_config.c + configs/nv_ipc_yaml_parser.cpp +@@ -68,6 +68,8 @@ target_include_directories(nvipc PUBLIC $) + target_include_directories(nvipc PUBLIC $) + ++set_target_properties(nvipc PROPERTIES PUBLIC_HEADER $) ++ + target_compile_options(nvipc PRIVATE ${AERIAL_ARCH_TUNE_FLAGS}) + + if(NVIPC_DPDK_ENABLE OR NVIPC_DOCA_GPUNETIO) +@@ -120,4 +122,8 @@ else() + target_link_libraries(nvipc PUBLIC rt -pthread nvlog) + endif() + ++install(TARGETS nvipc ++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/..) ++ + add_subdirectory(tests) +diff --git a/nvlog/CMakeLists.txt b/nvlog/CMakeLists.txt +index 7b65242..c0c5080 100644 +--- a/nvlog/CMakeLists.txt ++++ b/nvlog/CMakeLists.txt +@@ -20,6 +20,8 @@ + # STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ++include(GNUInstallDirs) ++ + if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -g") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g") +@@ -42,6 +44,8 @@ target_include_directories(nvlog PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../extern + target_include_directories(nvlog PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../external/fmtlog_flat) + target_link_libraries(nvlog rt -pthread yaml fmtlog-shared fmt::fmt) + ++set_target_properties(nvlog PROPERTIES PUBLIC_HEADER $) ++ + ######## libnvlog_static.a ############# + add_library(nvlog_static STATIC ${SOURCES}) + set_property(TARGET nvlog_static PROPERTY POSITION_INDEPENDENT_CODE ON) +@@ -68,5 +72,9 @@ target_compile_options(nvlog_static PRIVATE ${AERIAL_ARCH_TUNE_FLAGS}) + #add_executable(nvlog_observer ${SOURCES}) + #target_link_libraries(nvlog_observer nvlog_static -pthread) + ++install(TARGETS nvlog ++ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ++ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/../) ++ + ######## test directory ################ + add_subdirectory(test) diff --git a/docker/Dockerfile.gNB.aerial.ubuntu20 b/docker/Dockerfile.gNB.aerial.ubuntu20 new file mode 100644 index 0000000000..1fa9909b90 --- /dev/null +++ b/docker/Dockerfile.gNB.aerial.ubuntu20 @@ -0,0 +1,103 @@ +#/* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# +# Dockerfile for the Open-Air-Interface BUILD service +# Valid for Ubuntu 22.04 +# +#--------------------------------------------------------------------- + +FROM ran-base:latest as ran-build + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ + DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + wget \ + ninja-build \ + #unzip is needed for protobuf + unzip \ + moreutils \ + vim-tiny \ + nano \ + # To build libnvipc + cmake libpcap-dev libcunit1-dev libnuma-dev pkg-config + +RUN rm -Rf /oai-ran +WORKDIR /oai-ran +COPY . . + +RUN /bin/sh oaienv && \ + tar -xvzf nvipc_src.*.tar.gz && \ + cd nvipc_src.* && \ + git init && \ + git apply ../cmake_targets/tools/install_libraries_to_system.patch --verbose && \ + rm -rf build && mkdir build && cd build && \ + cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \ + make -j && make install + +RUN /bin/sh oaienv && \ + cd cmake_targets && \ + mkdir -p log && \ + ./build_oai -w AERIAL --gNB --ninja + + +#start from scratch for target executable +FROM ubuntu:focal as oai-gnb-aerial +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=Europe + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ + DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + software-properties-common \ + procps \ + libsctp1 \ + tzdata \ + libatlas3-base \ + libconfig9 \ + openssl \ + net-tools \ + iperf \ + iproute2 \ + iputils-ping \ + gdb \ + libusb-1.0-0 && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/oai-gnb/bin +COPY --from=ran-build \ + /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ +COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh + +COPY --from=ran-build /oai-ran/cmake_targets/ran_build/build/libparams_libconfig.so /usr/local/lib/ + +#copy files from nvIPC +COPY --from=ran-build \ + /usr/local/lib/libfmtlog-shared.so \ + /usr/local/lib/libnvlog.so \ + /usr/local/lib/libnvipc.so \ + /usr/local/lib/ + + +WORKDIR /opt/oai-gnb +COPY --from=ran-build /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"] diff --git a/docker/Dockerfile.gNB.aerial.ubuntu20.sanitize-address b/docker/Dockerfile.gNB.aerial.ubuntu20.sanitize-address new file mode 100644 index 0000000000..60565a5429 --- /dev/null +++ b/docker/Dockerfile.gNB.aerial.ubuntu20.sanitize-address @@ -0,0 +1,109 @@ +#/* +# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +# * contributor license agreements. See the NOTICE file distributed with +# * this work for additional information regarding copyright ownership. +# * The OpenAirInterface Software Alliance licenses this file to You under +# * the OAI Public License, Version 1.1 (the "License"); you may not use this file +# * except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.openairinterface.org/?page_id=698 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# *------------------------------------------------------------------------------- +# * For more information about the OpenAirInterface (OAI) Software Alliance: +# * contact@openairinterface.org +# */ +#--------------------------------------------------------------------- +# +# Dockerfile for the Open-Air-Interface BUILD service +# Valid for Ubuntu 22.04 +# +#--------------------------------------------------------------------- + +FROM ran-base:latest as ran-build + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ + DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + wget \ + ninja-build \ + #unzip is needed for protobuf + unzip \ + moreutils \ + vim-tiny \ + nano \ + # To build libnvipc + cmake libpcap-dev libcunit1-dev libnuma-dev pkg-config + +RUN rm -Rf /oai-ran +WORKDIR /oai-ran +COPY . . + +RUN /bin/sh oaienv && \ + tar -xvzf nvipc_src.*.tar.gz && \ + cd nvipc_src.* && \ + git init && \ + git apply ../cmake_targets/tools/install_libraries_to_system.patch --verbose && \ + rm -rf build && mkdir build && cd build && \ + cmake .. -DNVIPC_DPDK_ENABLE=OFF -DNVIPC_DOCA_ENABLE=OFF -DNVIPC_CUDA_ENABLE=OFF -DENABLE_SLT_RSP=ON && \ + make -j && make install + +RUN /bin/sh oaienv && \ + cd cmake_targets && \ + mkdir -p log && \ + ./build_oai -w AERIAL --gNB --ninja --sanitize-address + + +#start from scratch for target executable +FROM ubuntu:focal as oai-gnb-aerial +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=Europe + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ + DEBIAN_FRONTEND=noninteractive apt-get install --yes \ + software-properties-common \ + procps \ + libsctp1 \ + tzdata \ + libatlas3-base \ + libconfig9 \ + openssl \ + net-tools \ + iperf \ + iproute2 \ + iputils-ping \ + gdb \ + libusb-1.0-0 && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/oai-gnb/bin +COPY --from=ran-build \ + /oai-ran/cmake_targets/ran_build/build/nr-softmodem ./ +COPY ./docker/scripts/gnb_entrypoint.sh ./entrypoint.sh + +COPY --from=ran-build \ + /oai-ran/cmake_targets/ran_build/build/libcoding.so \ + /oai-ran/cmake_targets/ran_build/build/librfsimulator.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 \ + /usr/local/lib/ + +#copy files from nvIPC +COPY --from=ran-build \ + /usr/local/lib/libfmtlog-shared.so \ + /usr/local/lib/libnvlog.so \ + /usr/local/lib/libnvipc.so \ + /usr/local/lib/ + + +WORKDIR /opt/oai-gnb +COPY --from=ran-build /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"] diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 2a12126d7d..87b9d30391 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -394,7 +394,7 @@ void init_gNB_Tpool(int inst) { // this will be removed when the msgDataTx is not necessary anymore gNB->msgDataTx = msgDataTx; - if ((!get_softmodem_params()->emulate_l1) && (!IS_SOFTMODEM_NOSTATS_BIT) && (NFAPI_MODE!=NFAPI_MODE_VNF)) + if ((!get_softmodem_params()->emulate_l1) && (!IS_SOFTMODEM_NOSTATS_BIT) && (NFAPI_MODE!=NFAPI_MODE_VNF) && (NFAPI_MODE != NFAPI_MODE_AERIAL)) threadCreate(&proc->L1_stats_thread,nrL1_stats_thread,(void*)gNB,"L1_stats",-1,OAI_PRIORITY_RT_LOW); } diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 92fdc57e00..4287e6687b 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1285,7 +1285,7 @@ void *ru_thread( void *param ) { while (!oai_exit) { - if (NFAPI_MODE==NFAPI_MODE_VNF) { + if (NFAPI_MODE==NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL ) { // We should make a VNF main loop with proper tasks calls in case of VNF slot_start = timespec_add(slot_start,slot_duration); struct timespec curr_time; diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 3d9c02f5e4..85bb9056fb 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -80,7 +80,9 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "nfapi/oai_integration/vendor_ext.h" #include "gnb_config.h" #include "openair2/E1AP/e1ap_common.h" - +#ifdef ENABLE_AERIAL +#include "nfapi/oai_integration/aerial/fapi_nvIPC.h" +#endif #ifdef E2_AGENT #include "openair2/E2AP/flexric/src/agent/e2_agent_api.h" #include "openair2/E2AP/RAN_FUNCTION/init_ran_func.h" @@ -286,9 +288,15 @@ static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cf itti_wait_ready(1); LOG_I(PHY, "%s() Task ready initialize structures\n", __FUNCTION__); +#ifdef ENABLE_AERIAL + AssertFatal(NFAPI_MODE == NFAPI_MODE_AERIAL,"Can only be run with '--nfapi AERIAL' when compiled with AERIAL support, if you want to run other (n)FAPI modes, please run ./build_oai without -w AERIAL"); +#endif + RCconfig_verify(cfg, node_type); - RCconfig_nr_prs(); + if(NFAPI_MODE != NFAPI_MODE_AERIAL){ + RCconfig_nr_prs(); + } if (RC.nb_nr_macrlc_inst > 0) RCconfig_nr_macrlc(cfg); @@ -687,7 +695,7 @@ int main( int argc, char **argv ) { pthread_mutex_init(&sync_mutex, NULL); usleep(1000); - if (NFAPI_MODE) { + if (NFAPI_MODE && NFAPI_MODE != NFAPI_MODE_AERIAL) { printf("NFAPI*** - mutex and cond created - will block shortly for completion of PNF connection\n"); pthread_cond_init(&sync_cond,NULL); pthread_mutex_init(&sync_mutex, NULL); @@ -706,7 +714,7 @@ int main( int argc, char **argv ) { printf("wait_gNBs()\n"); wait_gNBs(); printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU); - int sl_ahead=6; + int sl_ahead = NFAPI_MODE == NFAPI_MODE_AERIAL ? 0 : 6; if (RC.nb_RU >0) { printf("Initializing RU threads\n"); init_NR_RU(uniqCfg, get_softmodem_params()->rf_config_file); @@ -749,7 +757,9 @@ int main( int argc, char **argv ) { if (RC.nb_RU > 0) start_NR_RU(); - +#ifdef ENABLE_AERIAL + nvIPC_Init(); +#endif if (RC.nb_nr_L1_inst > 0) { printf("wait RUs\n"); wait_RUs(); @@ -778,7 +788,7 @@ int main( int argc, char **argv ) { load_softscope("nrqt", &p); } - if (NFAPI_MODE != NFAPI_MODE_PNF && NFAPI_MODE != NFAPI_MODE_VNF) { + if (NFAPI_MODE != NFAPI_MODE_PNF && NFAPI_MODE != NFAPI_MODE_VNF && NFAPI_MODE != NFAPI_MODE_AERIAL) { printf("Not NFAPI mode - call init_eNB_afterRU()\n"); init_eNB_afterRU(); } else { diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 50aa335efb..43c8b4625e 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -103,7 +103,7 @@ extern "C" #define CONFIG_HLP_NOKRNMOD "(noS1 only): Use tun instead of namesh module \n" #define CONFIG_HLP_DISABLNBIOT "disable nb-iot, even if defined in config\n" #define CONFIG_HLP_USRP_THREAD "having extra thead for usrp tx\n" -#define CONFIG_HLP_NFAPI "Change the nFAPI mode for NR 'MONOLITHIC', 'PNF', 'VNF','UE_STUB_PNF','UE_STUB_OFFNET','STANDALONE_PNF'\n" +#define CONFIG_HLP_NFAPI "Change the nFAPI mode for NR 'MONOLITHIC', 'PNF', 'VNF', 'AERIAL','UE_STUB_PNF','UE_STUB_OFFNET','STANDALONE_PNF'\n" #define CONFIG_L1_EMULATOR "Run in L1 emulated mode (disable PHY layer)\n" #define CONFIG_HLP_CONTINUOUS_TX "perform continuous transmission, even in TDD mode (to work around USRP issues)\n" #define CONFIG_HLP_STATS_DISABLE "disable globally the stats generation and persistence" @@ -232,9 +232,9 @@ extern int usrp_tx_thread; { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s3a = { config_checkstr_assign_integer, \ - {"MONOLITHIC", "PNF", "VNF","UE_STUB_PNF","UE_STUB_OFFNET","STANDALONE_PNF"}, \ - {NFAPI_MONOLITHIC, NFAPI_MODE_PNF, NFAPI_MODE_VNF,NFAPI_UE_STUB_PNF,NFAPI_UE_STUB_OFFNET,NFAPI_MODE_STANDALONE_PNF}, \ - 6 } }, \ + {"MONOLITHIC", "PNF", "VNF", "AERIAL","UE_STUB_PNF","UE_STUB_OFFNET","STANDALONE_PNF"}, \ + {NFAPI_MONOLITHIC, NFAPI_MODE_PNF, NFAPI_MODE_VNF, NFAPI_MODE_AERIAL,NFAPI_UE_STUB_PNF,NFAPI_UE_STUB_OFFNET,NFAPI_MODE_STANDALONE_PNF}, \ + 7 } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ diff --git a/maketags b/maketags index 4c25bf6292..207d7ab376 100755 --- a/maketags +++ b/maketags @@ -1,4 +1,4 @@ #!/bin/sh echo "building ctags for openair1 and openair2 ..." -ctags -e -R --exclude=openair1/DOCS/ --exclude=openair2/DOCS/ --exclude=openair1/SIMULATION/ --exclude=targets/DOCS/ --exclude=targets/PROJECTS/ openair1 openair2 openair3 targets cmake_targets common nfapi executables radio +ctags -e -R --exclude=openair1/DOCS/ --exclude=openair2/DOCS/ --exclude=openair1/SIMULATION/ --exclude=targets/DOCS/ --exclude=targets/PROJECTS/ openair1 openair2 openair3 targets cmake_targets common fapi nfapi executables radio diff --git a/nfapi/CMakeLists.txt b/nfapi/CMakeLists.txt new file mode 100644 index 0000000000..7c75480aa6 --- /dev/null +++ b/nfapi/CMakeLists.txt @@ -0,0 +1 @@ +include(${OPENAIR_DIR}/nfapi/oai_integration/aerial/CMakeLists.txt) \ No newline at end of file diff --git a/nfapi/oai_integration/aerial/CMakeLists.txt b/nfapi/oai_integration/aerial/CMakeLists.txt new file mode 100644 index 0000000000..2514edf602 --- /dev/null +++ b/nfapi/oai_integration/aerial/CMakeLists.txt @@ -0,0 +1,33 @@ +add_boolean_option(OAI_AERIAL OFF "Activate OAI's AERIAL driver" OFF) +if (OAI_AERIAL) + message(STATUS "Building with support for Aerial") + + target_sources( + nr-softmodem + PRIVATE + ${OPENAIR_DIR}/nfapi/oai_integration/aerial/fapi_nvIPC.c + ${OPENAIR_DIR}/nfapi/oai_integration/aerial/fapi_vnf_p7.c + ${OPENAIR_DIR}/nfapi/oai_integration/aerial/fapi_vnf_p5.c ) + + find_library(NVIPC_LIB nvipc REQUIRED) + if (NOT NVIPC_LIB) + message(FATAL_ERROR "-- nvipc library not found") + else () + message(STATUS " nvipc library found in ${NVIPC_LIB}") + #add_library(nvipc STATIC SHARED IMPORTED GLOBAL) + endif () + + find_library(NVLOG_LIB nvlog REQUIRED) + if (NOT NVLOG_LIB) + message(FATAL_ERROR "-- nvlog library not found") + else () + message(STATUS " nvlog library found in ${NVLOG_LIB}") + endif () + + add_compile_definitions(ENABLE_L2_SLT_RSP) + add_compile_definitions(FAPI_BYTE_ORDERING_BIG_ENDIAN) + add_compile_definitions(ENABLE_AERIAL) + target_link_libraries(nr-softmodem PRIVATE "${NVLOG_LIB}" "${NVIPC_LIB}") +else() + message(STATUS "No Support for Aerial") +endif() \ No newline at end of file diff --git a/nfapi/oai_integration/aerial/fapi_nvIPC.c b/nfapi/oai_integration/aerial/fapi_nvIPC.c new file mode 100644 index 0000000000..e080e51031 --- /dev/null +++ b/nfapi/oai_integration/aerial/fapi_nvIPC.c @@ -0,0 +1,683 @@ +/* +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org +*/ + +/*! \file fapi/oai-integration/fapi_nvIPC.c +* \brief OAI MAC/Aerial L1 interface file using FAPI over shared memory +* \author Ruben S. Silva +* \date 2023 +* \version 0.1 +* \company OpenAirInterface Software Alliance +* \email: contact@openairinterface.org, rsilva@allbesmart.pt +* \note +* \warning +*/ +#ifdef ENABLE_AERIAL +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fapi_nvIPC.h" +#include "nfapi_interface.h" +#include "nfapi.h" +#include "nfapi_nr_interface_scf.h" +#include "nfapi/open-nFAPI/vnf/inc/vnf_p7.h" + +#include "fapi_vnf_p5.h" +#include "fapi_vnf_p7.h" + +#define MAX_EVENTS 10 +#define RECV_BUF_LEN 8192 +char cpu_buf_recv[RECV_BUF_LEN]; + +uint16_t sfn = 0, slot = 0; +nv_ipc_t *ipc; +nfapi_vnf_config_t *vnf_config = 0; + +void set_config(nfapi_vnf_config_t *conf) +{ + vnf_config = conf; +} +static uint16_t old_sfn = 0; +static uint16_t old_slot = 0; +//////////////////////////////////////////////////////////////////////// +// Handle an RX message +static int ipc_handle_rx_msg(nv_ipc_t *ipc, nv_ipc_msg_t *msg) +{ + if (msg == NULL) { + LOG_E(NFAPI_VNF, "%s: ERROR: buffer is empty\n", __func__); + return -1; + } + + char *p_cpu_data = NULL; + if (msg->data_buf != NULL) { + int gpu; + if (msg->data_pool == NV_IPC_MEMPOOL_CUDA_DATA) { + gpu = 1; + } else { + gpu = 0; + } + +#ifdef NVIPC_CUDA_ENABLE + // Test CUDA: call CUDA functions to change all string to lower case + test_cuda_to_lower_case(test_cuda_device_id, msg->data_buf, TEST_DATA_BUF_LEN, gpu); +#endif + + if (gpu) { + p_cpu_data = cpu_buf_recv; + memset(cpu_buf_recv, 0, RECV_BUF_LEN); + ipc->cuda_memcpy_to_host(ipc, p_cpu_data, msg->data_buf, RECV_BUF_LEN); + } else { + p_cpu_data = msg->data_buf; + } + } + + int messageBufLen = msg->msg_len; + int dataBufLen = msg->data_len; + uint8_t msgbuf[messageBufLen]; + uint8_t databuf[dataBufLen]; + memcpy(msgbuf, msg->msg_buf, messageBufLen); + memcpy(databuf, msg->data_buf, dataBufLen); + uint8_t *pReadPackedMessage = msgbuf; + uint8_t *pReadData = databuf; + uint8_t *end = msgbuf + messageBufLen; + uint8_t *data_end = databuf + dataBufLen; + + // unpack FAPI messages and handle them + if (vnf_config != 0) { + // first, unpack the header + fapi_phy_api_msg *fapi_msg = calloc(1, sizeof(fapi_phy_api_msg)); + if (!(pull8(&pReadPackedMessage, &fapi_msg->num_msg, end) && pull8(&pReadPackedMessage, &fapi_msg->opaque_handle, end) + && pull16(&pReadPackedMessage, &fapi_msg->message_id, end) + && pull32(&pReadPackedMessage, &fapi_msg->message_length, end))) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "FAPI message header unpack failed\n"); + return -1; + } + + switch (fapi_msg->message_id) { + case NFAPI_NR_PHY_MSG_TYPE_PARAM_RESPONSE: + + if (vnf_config->nr_param_resp) { + nfapi_nr_param_response_scf_t msg_param_resp; + aerial_unpack_nr_param_response(&pReadPackedMessage, end, &msg_param_resp, &vnf_config->codec_config); + (vnf_config->nr_param_resp)(vnf_config, vnf_config->pnf_list->p5_idx, &msg_param_resp); + } + break; + + case NFAPI_NR_PHY_MSG_TYPE_CONFIG_RESPONSE: { + // unpack message + nfapi_nr_config_response_scf_t msg_config_response; + aerial_unpack_nr_config_response(&pReadPackedMessage, end, &msg_config_response, &vnf_config->codec_config); + // Check the error code + if (msg_config_response.error_code == NFAPI_NR_CONFIG_MSG_OK) { + // Invoke the call back + if (vnf_config->nr_config_resp) { + (vnf_config->nr_config_resp)(vnf_config, vnf_config->pnf_list->p5_idx, &msg_config_response); + } + } else { + // Error code not OK (MSG_INVALID_CONFIG) + /* MSG_INVALID_CONFIG.response structure + * Error code uint8_t + * Number of invalid or unsupported TLVs uint8_t + * Number of invalid TLVs that can only be configured in IDLE state uint8_t + * Number of invalid TLVs that can only be configured in RUNNING state uint8_t + * Number of missing TLVs uint8_t + * List of invalid or unsupported TLVs + * List of invalid TLVs that can only be configured in IDLE state + * List of invalid TLVs that can only be configured in RUNNING state + * List of missing TLVs + * */ + } + break; + } + + case NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION: { + // TODO : ADD Support for NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION (0x06) + LOG_D(NFAPI_VNF,"Received NFAPI_NR_PHY_MSG_TYPE_STOP_INDICATION\n"); + break; + } + + case NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION: { + // TODO: Add Support for NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION (0x07) + LOG_D(NFAPI_VNF,"Received NFAPI_NR_PHY_MSG_TYPE_ERROR_INDICATION\n"); + //for (int i = 0; i < msg->msg_len; i++) { + // printf(" msg->msg_buf[%d] = 0x%02x\n", i, ((uint8_t *) msg->msg_buf)[i]); + //} + LOG_D(NFAPI_VNF,"old sfn %u\n", old_sfn); + LOG_D(NFAPI_VNF,"old slot %u\n", old_slot); + + break; + } + // P7 Messages + // P7 Message Handlers -> ((vnf_info *)vnf_config->user_data)->p7_vnfs->config-> + case NFAPI_NR_PHY_MSG_TYPE_SLOT_INDICATION: { + nfapi_nr_slot_indication_scf_t ind; + aerial_unpack_nr_slot_indication(&pReadPackedMessage, + end, + &ind, + &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); + // check if the sfn/slot unpacked come wrong at any time, should be old + 1 (slot 0 -- 19, sfn 0 -- 1023) + // add 1 to current sfn number + uint16_t old_slot_plus = ((old_slot + 1) % 20); + uint16_t old_sfn_plus = old_slot_plus == 0 ? ((old_sfn + 1) % 1024) : old_sfn; + if (old_slot_plus != ind.slot || old_sfn_plus != ind.sfn) { + LOG_E(NFAPI_VNF, + "\n============================================================================\n" + "sfn slot doesn't match unpacked one! L2->L1 %d.%d vs L1->L2 %d.%d \n" + "============================================================================\n", + old_sfn, + old_slot, + ind.sfn, + ind.slot); + } + old_sfn = ind.sfn; + old_slot = ind.slot; + if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_slot_indication) { + (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_slot_indication)(&ind); + } + break; + } + + case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION: { + nfapi_nr_rx_data_indication_t ind; + ind.header.message_id = fapi_msg->message_id; + ind.header.message_length = fapi_msg->message_length; + aerial_unpack_nr_rx_data_indication( + &pReadPackedMessage, + end, + &pReadData, + data_end, + &ind, + &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s: Handling RX Indication\n", __FUNCTION__); + if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_rx_data_indication) { + (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_rx_data_indication)(&ind); + } + break; + } + + case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION: { + nfapi_nr_crc_indication_t crc_ind; + crc_ind.header.message_id = fapi_msg->message_id; + crc_ind.header.message_length = fapi_msg->message_length; + aerial_unpack_nr_crc_indication(&pReadPackedMessage, + end, + &crc_ind, + &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); + if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_crc_indication) { + (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_crc_indication)(&crc_ind); + } + break; + } + + case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION: { + nfapi_nr_uci_indication_t ind; + aerial_unpack_nr_uci_indication(&pReadPackedMessage, + end, + &ind, + &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); + + if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_uci_indication) { + (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_uci_indication)(&ind); + } + + break; + } + + case NFAPI_NR_PHY_MSG_TYPE_SRS_INDICATION: { + nfapi_nr_srs_indication_t ind; + aerial_unpack_nr_srs_indication(&pReadPackedMessage, + end, + &ind, + &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); + if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_srs_indication) { + (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_srs_indication)(&ind); + } + break; + } + + case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: { + nfapi_nr_rach_indication_t ind; + aerial_unpack_nr_rach_indication(&pReadPackedMessage, + end, + &ind, + &((vnf_p7_t *)((vnf_info *)vnf_config->user_data)->p7_vnfs->config)->_public.codec_config); + if (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_rach_indication) { + (((vnf_info *)vnf_config->user_data)->p7_vnfs->config->nr_rach_indication)(&ind); + } + break; + } + + default: { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s P5 Unknown message ID %d\n", __FUNCTION__, fapi_msg->message_id); + + break; + } + } + } + return 0; +} + +int8_t buf[1024]; + +nv_ipc_config_t nv_ipc_config; + +int aerial_send_P5_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_p4_p5_message_header_t *header) +{ + if (ipc == NULL) { + return -1; + } + nv_ipc_msg_t send_msg = {0}; + // look for the specific message + switch (header->message_id) { + case NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_PARAM_RESPONSE: + case NFAPI_NR_PHY_MSG_TYPE_CONFIG_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_CONFIG_RESPONSE: + case NFAPI_NR_PHY_MSG_TYPE_START_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_START_RESPONSE: + case NFAPI_NR_PHY_MSG_TYPE_STOP_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_STOP_RESPONSE: + break; + default: { + if (header->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && header->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) { + // if(config && config->pack_p4_p5_vendor_extension) { + // result = (config->pack_p4_p5_vendor_extension)(header, ppWritePackedMsg, end, config); + // } else { + // NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s VE NFAPI message ID %d. No ve ecoder provided\n", __FUNCTION__, header->message_id); + // } + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown message ID %d\n", __FUNCTION__, header->message_id); + } + } break; + } + send_msg.msg_id = header->message_id; + send_msg.cell_id = 0; + send_msg.msg_len = packedMsgLength + 8; // adding 8 to account for the size of the FAPI header + send_msg.data_len = 0; + send_msg.data_buf = NULL; + send_msg.data_pool = NV_IPC_MEMPOOL_CPU_MSG; + + // procedure is allocate->fill->send + int alloc_retval = ipc->tx_allocate(ipc, &send_msg, 0); + if (alloc_retval != 0) { + LOG_E(NFAPI_VNF, "%s error: allocate TX buffer failed Error: %d\n", __FUNCTION__, alloc_retval); + ipc->tx_release(ipc, &send_msg); + return alloc_retval; + } + + memcpy(send_msg.msg_buf, packedBuf, send_msg.msg_len); + LOG_D(NFAPI_VNF, + "send: cell_id=%d msg_id=0x%02X msg_len=%d data_len=%d data_pool=%d\n", + send_msg.cell_id, + send_msg.msg_id, + send_msg.msg_len, + send_msg.data_len, + send_msg.data_pool); + // Send the message + int send_retval = ipc->tx_send_msg(ipc, &send_msg); + if (send_retval < 0) { + LOG_E(NFAPI_VNF, "%s error: send TX message failed Error: %d\n", __FUNCTION__, send_retval); + ipc->tx_release(ipc, &send_msg); + return send_retval; + } + + ipc->notify(ipc, 1); // notify that there's 1 message in queue + return 0; +} + +int aerial_send_P7_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_p7_message_header_t *header) +{ + if (ipc == NULL) { + return -1; + } + nv_ipc_msg_t send_msg; + uint8_t *pPacketBodyField = &((uint8_t *)packedBuf)[8]; + uint8_t *pPackMessageEnd = packedBuf + packedMsgLength + 8; + + uint16_t present_sfn = 0; + uint16_t present_slot = 0; + pull16(&pPacketBodyField, &present_sfn, pPackMessageEnd); + pull16(&pPacketBodyField, &present_slot, pPackMessageEnd); + + if (present_sfn != old_sfn || present_slot != old_slot) { + LOG_E(NFAPI_VNF, + "\n============================================================================\n" + "sfn slot doesn't match unpacked one! L2->L1 %d.%d vs L1->L2 %d.%d \n" + "============================================================================\n", + present_sfn, + present_slot, + old_sfn, + old_slot); + } + // look for the specific message + switch (header->message_id) { + case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST: + case NFAPI_UE_RELEASE_REQUEST: + case NFAPI_UE_RELEASE_RESPONSE: + case NFAPI_NR_PHY_MSG_TYPE_SLOT_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_SRS_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_DL_NODE_SYNC: + case NFAPI_NR_PHY_MSG_TYPE_UL_NODE_SYNC: + case NFAPI_TIMING_INFO: + case 0x8f: + break; + default: { + if (header->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && header->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) { + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown message ID %d\n", __FUNCTION__, header->message_id); + } + } break; + } + + send_msg.msg_id = header->message_id; + send_msg.cell_id = 0; + send_msg.msg_len = packedMsgLength + 8; // adding 8 to account for the size of the FAPI header + send_msg.data_len = 0; + send_msg.data_buf = NULL; + send_msg.data_pool = NV_IPC_MEMPOOL_CPU_MSG; + // procedure is allocate->fill->send + + // Allocate buffer for TX message + int alloc_retval = ipc->tx_allocate(ipc, &send_msg, 0); + if (alloc_retval != 0) { + LOG_E(NFAPI_VNF, "%s error: allocate TX buffer failed Error: %d\n", __FUNCTION__, alloc_retval); + ipc->tx_release(ipc, &send_msg); + return alloc_retval; + } + + memcpy(send_msg.msg_buf, packedBuf, send_msg.msg_len); + LOG_D(NFAPI_VNF, + "send: cell_id=%d msg_id=0x%02X msg_len=%d data_len=%d data_pool=%d\n", + send_msg.cell_id, + send_msg.msg_id, + send_msg.msg_len, + send_msg.data_len, + send_msg.data_pool); + // Send the message + int send_retval = ipc->tx_send_msg(ipc, &send_msg); + if (send_retval < 0) { + LOG_E(NFAPI_VNF, "%s error: send TX message failed Error: %d\n", __FUNCTION__, send_retval); + ipc->tx_release(ipc, &send_msg); + return send_retval; + } + + ipc->notify(ipc, 1); // notify that there's 1 message in queue + return 0; +} + +int aerial_send_P7_msg_with_data(void *packedBuf, + uint32_t packedMsgLength, + void *dataBuf, + uint32_t dataLength, + nfapi_p7_message_header_t *header) +{ + if (ipc == NULL) { + return -1; + } + nv_ipc_msg_t send_msg; + uint8_t *pPacketBodyField = &((uint8_t *)packedBuf)[8]; + uint8_t *pPackMessageEnd = packedBuf + packedMsgLength + 8; + uint16_t present_sfn = 0; + uint16_t present_slot = 0; + pull16(&pPacketBodyField, &present_sfn, pPackMessageEnd); + pull16(&pPacketBodyField, &present_slot, pPackMessageEnd); + + if (present_sfn != old_sfn || present_slot != old_slot) { + LOG_E(NFAPI_VNF, + "\n============================================================================\n" + "sfn slot doesn't match unpacked one! L2->L1 %d.%d vs L1->L2 %d.%d \n" + "============================================================================\n", + present_sfn, + present_slot, + old_sfn, + old_slot); + } + // look for the specific message + switch (header->message_id) { + case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST: + case NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST: + case NFAPI_UE_RELEASE_REQUEST: + case NFAPI_UE_RELEASE_RESPONSE: + case NFAPI_NR_PHY_MSG_TYPE_SLOT_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_SRS_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: + case NFAPI_NR_PHY_MSG_TYPE_DL_NODE_SYNC: + case NFAPI_NR_PHY_MSG_TYPE_UL_NODE_SYNC: + case NFAPI_TIMING_INFO: + break; + default: { + if (header->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && header->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) { + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown message ID %d\n", __FUNCTION__, header->message_id); + } + } break; + } + + send_msg.msg_id = header->message_id; + send_msg.cell_id = 0; + send_msg.msg_len = packedMsgLength + 8; // adding 8 to account for the size of the FAPI header + send_msg.data_len = dataLength; + send_msg.data_pool = NV_IPC_MEMPOOL_CPU_DATA; + + // procedure is allocate->fill->send + + // Allocate buffer for TX message + int alloc_retval = ipc->tx_allocate(ipc, &send_msg, 0); + if (alloc_retval != 0) { + LOG_E(NFAPI_VNF, "%s error: allocate TX buffer failed Error: %d\n", __FUNCTION__, alloc_retval); + ipc->tx_release(ipc, &send_msg); + return alloc_retval; + } + + memcpy(send_msg.msg_buf, packedBuf, send_msg.msg_len); + memcpy(send_msg.data_buf, dataBuf, send_msg.data_len); + LOG_D(NFAPI_VNF, + "send: cell_id=%d msg_id=0x%02X msg_len=%d data_len=%d data_pool=%d\n", + send_msg.cell_id, + send_msg.msg_id, + send_msg.msg_len, + send_msg.data_len, + send_msg.data_pool); + // Send the message + int send_retval = ipc->tx_send_msg(ipc, &send_msg); + if (send_retval != 0) { + LOG_E(NFAPI_VNF, "%s error: send TX message failed Error: %d\n", __FUNCTION__, send_retval); + ipc->tx_release(ipc, &send_msg); + return send_retval; + } + + ipc->notify(ipc, 1); // notify that there's 1 message in queue + return 0; +} + +// Always allocate message buffer, but allocate data buffer only when data_len > 0 +static int aerial_recv_msg(nv_ipc_t *ipc, nv_ipc_msg_t *recv_msg) +{ + if (ipc == NULL) { + return -1; + } + recv_msg->msg_buf = NULL; + recv_msg->data_buf = NULL; + + // Allocate buffer for TX message + if (ipc->rx_recv_msg(ipc, recv_msg) < 0) { + LOG_D(NFAPI_VNF, "%s: no more message available\n", __func__); + return -1; + } + LOG_D(NFAPI_VNF, + "recv: cell_id=%d msg_id=0x%02X msg_len=%d data_len=%d data_pool=%d\n", + recv_msg->cell_id, + recv_msg->msg_id, + recv_msg->msg_len, + recv_msg->data_len, + recv_msg->data_pool); + ipc_handle_rx_msg(ipc, recv_msg); + + // Release buffer of RX message + int release_retval = ipc->rx_release(ipc, recv_msg); + if (release_retval != 0) { + LOG_E(NFAPI_VNF, "%s error: release RX buffer failed Error: %d\n", __FUNCTION__, release_retval); + return release_retval; + } + return 0; +} + +bool recv_task_running = false; +int stick_this_thread_to_core(int core_id) +{ + int num_cores = sysconf(_SC_NPROCESSORS_ONLN); + if (core_id < 0 || core_id >= num_cores) + return EINVAL; + + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(core_id, &cpuset); + + pthread_t current_thread = pthread_self(); + return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset); +} +void *epoll_recv_task(void *arg) +{ + struct epoll_event ev, events[MAX_EVENTS]; + stick_this_thread_to_core(10); + LOG_D(NFAPI_VNF,"Aerial recv task start \n"); + int epoll_fd = epoll_create1(0); + if (epoll_fd == -1) { + LOG_E(NFAPI_VNF, "%s epoll_create failed\n", __func__); + } + + int ipc_rx_event_fd = ipc->get_fd(ipc); + ev.events = EPOLLIN; + ev.data.fd = ipc_rx_event_fd; + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, ev.data.fd, &ev) == -1) { + LOG_E(NFAPI_VNF, "%s epoll_ctl failed\n", __func__); + } + + while (1) { + if (!recv_task_running) { + recv_task_running = true; + } + LOG_D(NFAPI_VNF, "%s: epoll_wait fd_rx=%d ...\n", __func__, ipc_rx_event_fd); + + int nfds; + do { + // epoll_wait() may return EINTR when get unexpected signal SIGSTOP from system + nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); + } while (nfds == -1 && errno == EINTR); + + if (nfds < 0) { + LOG_E(NFAPI_VNF, "epoll_wait failed: epoll_fd=%d nfds=%d err=%d - %s\n", epoll_fd, nfds, errno, strerror(errno)); + } + + int n = 0; + for (n = 0; n < nfds; ++n) { + if (events[n].data.fd == ipc_rx_event_fd) { + ipc->get_value(ipc); + nv_ipc_msg_t recv_msg; + while (aerial_recv_msg(ipc, &recv_msg) == 0); + } + } + } + close(epoll_fd); + return NULL; +} + +int create_recv_thread(void) +{ + pthread_t thread_id; + + void *(*recv_task)(void *); + + recv_task = epoll_recv_task; + + int ret = pthread_create(&thread_id, NULL, recv_task, NULL); + if (ret != 0) { + LOG_E(NFAPI_VNF, "%s failed, ret = %d\n", __func__, ret); + } + return ret; +} + +int load_hard_code_config(nv_ipc_config_t *config, int module_type, nv_ipc_transport_t _transport) +{ + // Create configuration + config->ipc_transport = _transport; + if (set_nv_ipc_default_config(config, module_type) < 0) { + LOG_E(NFAPI_VNF, "%s: set configuration failed\n", __func__); + return -1; + } + +#ifdef NVIPC_CUDA_ENABLE + int test_cuda_device_id = get_cuda_device_id(); +#else + int test_cuda_device_id = -1; +#endif + LOG_D(NFAPI_VNF,"CUDA device ID configured : %d \n", test_cuda_device_id); + config->transport_config.shm.cuda_device_id = test_cuda_device_id; + if (test_cuda_device_id >= 0) { + config->transport_config.shm.mempool_size[NV_IPC_MEMPOOL_CUDA_DATA].pool_len = 128; + config->transport_config.shm.mempool_size[NV_IPC_MEMPOOL_CPU_DATA].pool_len = 1024; + config->transport_config.shm.mempool_size[NV_IPC_MEMPOOL_CPU_MSG].pool_len = 4096; + } + + return 0; +} + +int nvIPC_Init() { +// Want to use transport SHM, type epoll, module secondary (reads the created shm from cuphycontroller) + load_hard_code_config(&nv_ipc_config, NV_IPC_MODULE_SECONDARY, NV_IPC_TRANSPORT_SHM); + // Create nv_ipc_t instance + if ((ipc = create_nv_ipc_interface(&nv_ipc_config)) == NULL) { + LOG_E(NFAPI_VNF, "%s: create IPC interface failed\n", __func__); + return -1; + } + LOG_I(NFAPI_VNF, "%s: create IPC interface successful\n", __func__); + sleep(1); + create_recv_thread(); + while(!recv_task_running){usleep(100000);} + aerial_pnf_nr_connection_indication_cb(vnf_config, 1); + return 0; +} +#endif diff --git a/nfapi/oai_integration/aerial/fapi_nvIPC.h b/nfapi/oai_integration/aerial/fapi_nvIPC.h new file mode 100644 index 0000000000..0fe559658c --- /dev/null +++ b/nfapi/oai_integration/aerial/fapi_nvIPC.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 + */ + +/*! \file fapi/oai-integration/fapi_nvIPC.h +* \brief Header file for fapi_nvIPC.c +* \author Ruben S. Silva +* \date 2023 +* \version 0.1 +* \company OpenAirInterface Software Alliance +* \email: contact@openairinterface.org, rsilva@allbesmart.pt +* \note +* \warning + */ +#ifdef ENABLE_AERIAL +#ifndef OPENAIRINTERFACE_FAPI_NVIPC_H +#define OPENAIRINTERFACE_FAPI_NVIPC_H + +#include "nv_ipc.h" +#include "nv_ipc_utils.h" +#include "nvlog.h" +#include "nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h" +#include "openair1/PHY/defs_gNB.h" +#include "debug.h" + +typedef struct { + uint8_t num_msg; + uint8_t opaque_handle; + uint16_t message_id; + uint32_t message_length; +} fapi_phy_api_msg; + +int aerial_send_P5_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_p4_p5_message_header_t *header); +int aerial_send_P7_msg(void *packedBuf, uint32_t packedMsgLength, nfapi_p7_message_header_t *header); +int aerial_send_P7_msg_with_data(void *packedBuf, + uint32_t packedMsgLength, + void *dataBuf, + uint32_t dataLength, + nfapi_p7_message_header_t *header); +void set_config(nfapi_vnf_config_t *conf); +int nvIPC_Init(); + +#endif // OPENAIRINTERFACE_FAPI_NVIPC_H +#endif diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p5.c b/nfapi/oai_integration/aerial/fapi_vnf_p5.c new file mode 100644 index 0000000000..57ef1ddc11 --- /dev/null +++ b/nfapi/oai_integration/aerial/fapi_vnf_p5.c @@ -0,0 +1,765 @@ +/* +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org + */ + +/*! \file fapi/oai-integration/fapi_vnf_p5.c +* \brief OAI FAPI VNF P5 message handler procedures +* \author Ruben S. Silva +* \date 2023 +* \version 0.1 +* \company OpenAirInterface Software Alliance +* \email: contact@openairinterface.org, rsilva@allbesmart.pt +* \note +* \warning + */ +#ifdef ENABLE_AERIAL +#include "fapi_vnf_p5.h" +#include "fapi_vnf_p7.h" +#include "nfapi/open-nFAPI/nfapi/src/nfapi_p5.c" +#include "nfapi/open-nFAPI/vnf/inc/vnf_p7.h" + +extern RAN_CONTEXT_t RC; +extern UL_RCC_IND_t UL_RCC_INFO; +extern int single_thread_flag; +extern uint16_t sf_ahead; +extern uint16_t slot_ahead; + + +static pthread_t vnf_aerial_p7_start_pthread; +void *aerial_vnf_nr_aerial_p7_start_thread(void *ptr) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); + pthread_setname_np(pthread_self(), "VNF_P7_AERIAL"); + nfapi_vnf_p7_config_t *config = (nfapi_vnf_p7_config_t *)ptr; + aerial_nfapi_nr_vnf_p7_start(config); + return config; +} + +void *aerial_vnf_nr_p7_thread_start(void *ptr) +{ + // set_thread_priority(79); + int s; + cpu_set_t cpuset; + + CPU_SET(8, &cpuset); + s = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); + if (s != 0) + printf("failed to set afinity\n"); + + set_priority(79); + + pthread_attr_t ptAttr; + if (pthread_attr_setschedpolicy(&ptAttr, SCHED_RR) != 0) { + printf("Failed to set pthread sched policy SCHED_RR\n"); + } + + pthread_attr_setinheritsched(&ptAttr, PTHREAD_EXPLICIT_SCHED); + struct sched_param thread_params; + thread_params.sched_priority = 20; + + if (pthread_attr_setschedparam(&ptAttr, &thread_params) != 0) { + printf("failed to set sched param\n"); + } + + init_queue(&gnb_rach_ind_queue); + init_queue(&gnb_rx_ind_queue); + init_queue(&gnb_crc_ind_queue); + init_queue(&gnb_uci_ind_queue); + init_queue(&gnb_slot_ind_queue); + + vnf_p7_info *p7_vnf = (vnf_p7_info *)ptr; + p7_vnf->config->port = p7_vnf->local_port; + p7_vnf->config->sync_indication = &aerial_phy_sync_indication; + p7_vnf->config->slot_indication = &aerial_phy_slot_indication; + p7_vnf->config->harq_indication = &aerial_phy_harq_indication; + p7_vnf->config->nr_crc_indication = &aerial_phy_nr_crc_indication; + p7_vnf->config->nr_rx_data_indication = &aerial_phy_nr_rx_data_indication; + p7_vnf->config->nr_rach_indication = &aerial_phy_nr_rach_indication; + p7_vnf->config->nr_uci_indication = &aerial_phy_nr_uci_indication; + p7_vnf->config->srs_indication = &aerial_phy_srs_indication; + p7_vnf->config->sr_indication = &aerial_phy_sr_indication; + p7_vnf->config->cqi_indication = &aerial_phy_cqi_indication; + p7_vnf->config->lbt_dl_indication = &aerial_phy_lbt_dl_indication; + p7_vnf->config->nb_harq_indication = &aerial_phy_nb_harq_indication; + p7_vnf->config->nrach_indication = &aerial_phy_nrach_indication; + p7_vnf->config->nr_slot_indication = &aerial_phy_nr_slot_indication; + p7_vnf->config->nr_srs_indication = &aerial_phy_nr_srs_indication; + p7_vnf->config->malloc = &aerial_vnf_allocate; + p7_vnf->config->free = &aerial_vnf_deallocate; + p7_vnf->config->vendor_ext = &aerial_phy_vendor_ext; + p7_vnf->config->user_data = p7_vnf; + p7_vnf->mac->user_data = p7_vnf; + p7_vnf->config->codec_config.unpack_p7_vendor_extension = &aerial_phy_unpack_p7_vendor_extension; + p7_vnf->config->codec_config.pack_p7_vendor_extension = &aerial_phy_pack_p7_vendor_extension; + p7_vnf->config->codec_config.unpack_vendor_extension_tlv = &aerial_phy_unpack_vendor_extension_tlv; + p7_vnf->config->codec_config.pack_vendor_extension_tlv = &aerial_phy_pack_vendor_extension_tlv; + p7_vnf->config->codec_config.allocate = &aerial_vnf_allocate; + p7_vnf->config->codec_config.deallocate = &aerial_vnf_deallocate; + p7_vnf->config->allocate_p7_vendor_ext = &aerial_phy_allocate_p7_vendor_ext; + p7_vnf->config->deallocate_p7_vendor_ext = &aerial_phy_deallocate_p7_vendor_ext; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI P7 start thread %s\n", __FUNCTION__); + pthread_create(&vnf_aerial_p7_start_pthread, NULL, &aerial_vnf_nr_aerial_p7_start_thread, p7_vnf->config); + return 0; +} + + +int aerial_pnf_nr_connection_indication_cb(nfapi_vnf_config_t *config, int p5_idx) +{ + printf("[VNF] pnf connection indication idx:%d\n", p5_idx); + // in aerial, send first CONFIG.request, not PARAM.request + nfapi_nr_config_request_scf_t conf_req; + memset(&conf_req, 0, sizeof(conf_req)); + conf_req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_CONFIG_REQUEST; + printf("Try to send first CONFIG.request\n"); + aerial_nr_send_config_request(config, p5_idx); + return 0; +} + +int aerial_pnf_disconnection_indication_cb(nfapi_vnf_config_t *config, int p5_idx) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] pnf disconnection indication idx:%d\n", p5_idx); + vnf_info *vnf = (vnf_info *)(config->user_data); + pnf_info *pnf = vnf->pnfs; + phy_info *phy = pnf->phys; + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + nfapi_vnf_p7_del_pnf((p7_vnf->config), phy->id); + return 0; +} + +int aerial_pnf_nr_param_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_param_response_t *resp) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] pnf param response idx:%d error:%d\n", p5_idx, resp->error_code); + vnf_info *vnf = (vnf_info *)(config->user_data); + pnf_info *pnf = vnf->pnfs; + + for (int i = 0; i < resp->pnf_phy.number_of_phys; ++i) { + phy_info phy; + memset(&phy, 0, sizeof(phy)); + phy.index = resp->pnf_phy.phy[i].phy_config_index; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) phy_config_idx:%d\n", i, resp->pnf_phy.phy[i].phy_config_index); + nfapi_vnf_allocate_phy(config, p5_idx, &(phy.id)); + + for (int j = 0; j < resp->pnf_phy.phy[i].number_of_rfs; ++j) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) (RF%d) %d\n", i, j, resp->pnf_phy.phy[i].rf_config[j].rf_config_index); + phy.rfs[0] = resp->pnf_phy.phy[i].rf_config[j].rf_config_index; + } + + pnf->phys[0] = phy; + } + nfapi_nr_pnf_config_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_CONFIG_REQUEST; + req.pnf_phy_rf_config.tl.tag = NFAPI_PNF_PHY_RF_TAG; + req.pnf_phy_rf_config.number_phy_rf_config_info = 2; // DJP pnf.phys.size(); + NFAPI_TRACE(NFAPI_TRACE_INFO, "DJP:Hard coded num phy rf to 2\n"); + + for (unsigned i = 0; i < 2; ++i) { + req.pnf_phy_rf_config.phy_rf_config[i].phy_id = pnf->phys[i].id; + req.pnf_phy_rf_config.phy_rf_config[i].phy_config_index = pnf->phys[i].index; + req.pnf_phy_rf_config.phy_rf_config[i].rf_config_index = pnf->phys[i].rfs[0]; + } + + nfapi_nr_vnf_pnf_config_req(config, p5_idx, &req); + return 0; +} + +int aerial_pnf_nr_config_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_config_response_t *resp) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, + "[VNF] pnf config response idx:%d resp[header[phy_id:%u message_id:%02x message_length:%u]]\n", + p5_idx, + resp->header.phy_id, + resp->header.message_id, + resp->header.message_length); + + if (1) { + nfapi_nr_pnf_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.phy_id = resp->header.phy_id; + req.header.message_id = NFAPI_PNF_START_REQUEST; + nfapi_nr_vnf_pnf_start_req(config, p5_idx, &req); + } else { + // Rather than send the pnf_start_request we will demonstrate + // sending a vendor extention message. The start request will be + // send when the vendor extension response is received + // vnf_info* vnf = (vnf_info*)(config->user_data); + vendor_ext_p5_req req; + memset(&req, 0, sizeof(req)); + req.header.message_id = P5_VENDOR_EXT_REQ; + req.dummy1 = 45; + req.dummy2 = 1977; + nfapi_vnf_vendor_extension(config, p5_idx, &req.header); + } + + return 0; +} + +int aerial_pnf_nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_pnf_start_response_t *resp) +{ + vnf_info *vnf = (vnf_info *)(config->user_data); + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + pnf_info *pnf = vnf->pnfs; + nfapi_nr_param_request_scf_t req; + NFAPI_TRACE(NFAPI_TRACE_INFO, + "[VNF] pnf start response idx:%d config:%p user_data:%p p7_vnf[config:%p thread_started:%d]\n", + p5_idx, + config, + config->user_data, + vnf->p7_vnfs[0].config, + vnf->p7_vnfs[0].thread_started); + + if (p7_vnf->thread_started == 0) { + pthread_t vnf_p7_thread; + pthread_create(&vnf_p7_thread, NULL, &aerial_vnf_nr_p7_thread_start, p7_vnf); + p7_vnf->thread_started = 1; + } else { + // P7 thread already running. + } + + // start all the phys in the pnf. + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Sending NFAPI_VNF_PARAM_REQUEST phy_id:%d\n", pnf->phys[0].id); + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_PARAM_REQUEST; + req.header.phy_id = pnf->phys[0].id; + nfapi_nr_vnf_param_req(config, p5_idx, &req); + return 0; +} + +int aerial_nr_param_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_param_response_scf_t *resp) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Received NFAPI_PARAM_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + vnf_info *vnf = (vnf_info *)(config->user_data); + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + pnf_info *pnf = vnf->pnfs; + phy_info *phy = pnf->phys; + struct sockaddr_in pnf_p7_sockaddr; + nfapi_nr_config_request_scf_t *req = &RC.nrmac[0]->config[0]; // check + phy->remote_port = resp->nfapi_config.p7_pnf_port.value; + // phy->remote_port = 32123;//resp->nfapi_config.p7_pnf_port.value; + memcpy(&pnf_p7_sockaddr.sin_addr.s_addr, &(resp->nfapi_config.p7_pnf_address_ipv4.address[0]), 4); + phy->remote_addr = inet_ntoa(pnf_p7_sockaddr.sin_addr); + // for now just 1 + NFAPI_TRACE(NFAPI_TRACE_INFO, + "[VNF] %d.%d pnf p7 %s:%d timing %u %u %u %u\n", + p5_idx, + phy->id, + phy->remote_addr, + phy->remote_port, + p7_vnf->timing_window, + p7_vnf->periodic_timing_period, + p7_vnf->aperiodic_timing_enabled, + p7_vnf->periodic_timing_period); + req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_CONFIG_REQUEST; + req->header.phy_id = phy->id; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Send NFAPI_CONFIG_REQUEST\n"); + // NFAPI_TRACE(NFAPI_TRACE_INFO, "\n NR bandP =%d\n",req->nfapi_config.rf_bands.rf_band[0]); + + req->nfapi_config.p7_vnf_port.tl.tag = NFAPI_NR_NFAPI_P7_VNF_PORT_TAG; + req->nfapi_config.p7_vnf_port.value = p7_vnf->local_port; + req->num_tlv++; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] DJP local_port:%d\n", ntohs(p7_vnf->local_port)); + req->nfapi_config.p7_vnf_address_ipv4.tl.tag = NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG; + struct sockaddr_in vnf_p7_sockaddr; + vnf_p7_sockaddr.sin_addr.s_addr = inet_addr(p7_vnf->local_addr); + memcpy(&(req->nfapi_config.p7_vnf_address_ipv4.address[0]), &vnf_p7_sockaddr.sin_addr.s_addr, 4); + req->num_tlv++; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] DJP local_addr:%s\n", p7_vnf->local_addr); + req->nfapi_config.timing_window.tl.tag = NFAPI_NR_NFAPI_TIMING_WINDOW_TAG; + req->nfapi_config.timing_window.value = p7_vnf->timing_window; + NFAPI_TRACE(NFAPI_TRACE_INFO, + "\n[VNF]Timing window tag : %d Timing window:%u\n", + NFAPI_NR_NFAPI_TIMING_WINDOW_TAG, + p7_vnf->timing_window); + req->num_tlv++; + + if (p7_vnf->periodic_timing_enabled || p7_vnf->aperiodic_timing_enabled) { + req->nfapi_config.timing_info_mode.tl.tag = NFAPI_NR_NFAPI_TIMING_INFO_MODE_TAG; + req->nfapi_config.timing_info_mode.value = (p7_vnf->aperiodic_timing_enabled << 1) | (p7_vnf->periodic_timing_enabled); + req->num_tlv++; + + if (p7_vnf->periodic_timing_enabled) { + req->nfapi_config.timing_info_period.tl.tag = NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG; + req->nfapi_config.timing_info_period.value = p7_vnf->periodic_timing_period; + req->num_tlv++; + } + } + // TODO: Assign tag and value for P7 message offsets + req->nfapi_config.dl_tti_timing_offset.tl.tag = NFAPI_NR_NFAPI_DL_TTI_TIMING_OFFSET; + req->nfapi_config.ul_tti_timing_offset.tl.tag = NFAPI_NR_NFAPI_UL_TTI_TIMING_OFFSET; + req->nfapi_config.ul_dci_timing_offset.tl.tag = NFAPI_NR_NFAPI_UL_DCI_TIMING_OFFSET; + req->nfapi_config.tx_data_timing_offset.tl.tag = NFAPI_NR_NFAPI_TX_DATA_TIMING_OFFSET; + + vendor_ext_tlv_2 ve2; + memset(&ve2, 0, sizeof(ve2)); + ve2.tl.tag = VENDOR_EXT_TLV_2_TAG; + ve2.dummy = 2016; + req->vendor_extension = &ve2.tl; + nfapi_nr_vnf_config_req(config, p5_idx, req); + printf("[VNF] Sent NFAPI_VNF_CONFIG_REQ num_tlv:%u\n", req->num_tlv); + return 0; +} + +int aerial_nr_send_config_request(nfapi_vnf_config_t *config, int p5_idx) +{ + vnf_info *vnf = (vnf_info *)(config->user_data); + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + pnf_info *pnf = vnf->pnfs; + phy_info *phy = pnf->phys; + + nfapi_nr_config_request_scf_t *req = &RC.nrmac[0]->config[0]; //&RC.gNB[0]->gNB_config; // check + + NFAPI_TRACE(NFAPI_TRACE_INFO, + "[VNF] %d.%d pnf p7 %s:%d timing %u %u %u %u\n", + p5_idx, + phy->id, + phy->remote_addr, + phy->remote_port, + p7_vnf->timing_window, + p7_vnf->periodic_timing_period, + p7_vnf->aperiodic_timing_enabled, + p7_vnf->periodic_timing_period); + req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_CONFIG_REQUEST; + req->header.phy_id = phy->id; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Send NFAPI_CONFIG_REQUEST\n"); + + + vnf_t *_this = (vnf_t *)(config); + + nfapi_vnf_phy_info_t *vnf_phy = nfapi_vnf_phy_info_list_find(config, req->header.phy_id); + + if (vnf_phy == NULL) { + printf("%s failed to find phy information phy_id:%d\n", __FUNCTION__, req->header.phy_id); + return -1; + } + + nfapi_p4_p5_message_header_t *msg = &req->header; + uint16_t msg_len = sizeof(nfapi_nr_config_request_scf_t); + nfapi_p4_p5_message_header_t *msgFAPI = calloc(1, msg_len); + memcpy(msgFAPI, &req->header, msg_len); + uint8_t tx_messagebufferFAPI[sizeof(_this->tx_message_buffer)]; + int packedMessageLengthFAPI = -1; + packedMessageLengthFAPI = + fapi_nr_p5_message_pack(msgFAPI, msg_len, tx_messagebufferFAPI, sizeof(tx_messagebufferFAPI), &_this->_public.codec_config); + + aerial_send_P5_msg(tx_messagebufferFAPI, packedMessageLengthFAPI, msg); + + return 0; +} + +int aerial_nr_config_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_config_response_scf_t *resp) +{ + nfapi_nr_start_request_scf_t req; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Received NFAPI_CONFIG_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + LOG_I(NFAPI_VNF, "Received CONFIG.response, gNB is ready! \n"); + + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_NR_PHY_MSG_TYPE_START_REQUEST; + req.header.phy_id = resp->header.phy_id; + nfapi_nr_vnf_start_req(config, p5_idx, &req); + return 0; +} + +int aerial_nr_start_resp_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_nr_start_response_scf_t *resp) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Received NFAPI_START_RESP idx:%d phy_id:%d\n", p5_idx, resp->header.phy_id); + vnf_info *vnf = (vnf_info *)(config->user_data); + pnf_info *pnf = vnf->pnfs; + phy_info *phy = pnf->phys; + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + + nfapi_vnf_p7_add_pnf((p7_vnf->config), phy->remote_addr, phy->remote_port, phy->id); + return 0; +} + +int aerial_vendor_ext_cb(nfapi_vnf_config_t *config, int p5_idx, nfapi_p4_p5_message_header_t *msg) +{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %s\n", __FUNCTION__); + + switch (msg->message_id) { + case P5_VENDOR_EXT_RSP: { + vendor_ext_p5_rsp *rsp = (vendor_ext_p5_rsp *)msg; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] P5_VENDOR_EXT_RSP error_code:%d\n", rsp->error_code); + // send the start request + nfapi_pnf_start_request_t req; + memset(&req, 0, sizeof(req)); + req.header.message_id = NFAPI_PNF_START_REQUEST; + nfapi_vnf_pnf_start_req(config, p5_idx, &req); + } break; + } + + return 0; +} + +int aerial_vnf_unpack_vendor_extension_tlv(nfapi_tl_t *tl, + uint8_t **ppReadPackedMessage, + uint8_t *end, + void **ve, + nfapi_p4_p5_codec_config_t *codec) +{ + return -1; +} + +int aerial_vnf_pack_vendor_extension_tlv(void *vext, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p4_p5_codec_config_t *codec) +{ + nfapi_tl_t *tlv = (nfapi_tl_t *)vext; + + switch (tlv->tag) { + case VENDOR_EXT_TLV_2_TAG: { + vendor_ext_tlv_2 *ve = (vendor_ext_tlv_2 *)tlv; + + if (!push32(ve->dummy, ppWritePackedMsg, end)) + return 0; + + return 1; + } break; + } + + return -1; +} + +int aerial_vnf_unpack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t *header, + uint8_t **ppReadPackedMessage, + uint8_t *end, + nfapi_p4_p5_codec_config_t *codec) +{ + if (header->message_id == P5_VENDOR_EXT_RSP) { + vendor_ext_p5_rsp *req = (vendor_ext_p5_rsp *)(header); + return (!pull16(ppReadPackedMessage, &req->error_code, end)); + } + + return 0; +} + +int aerial_vnf_pack_p4_p5_vendor_extension(nfapi_p4_p5_message_header_t *header, + uint8_t **ppWritePackedMsg, + uint8_t *end, + nfapi_p4_p5_codec_config_t *codec) +{ + if (header->message_id == P5_VENDOR_EXT_REQ) { + vendor_ext_p5_req *req = (vendor_ext_p5_req *)(header); + return (!(push16(req->dummy1, ppWritePackedMsg, end) && push16(req->dummy2, ppWritePackedMsg, end))); + } + + return 0; +} + +nfapi_p4_p5_message_header_t *aerial_vnf_allocate_p4_p5_vendor_ext(uint16_t message_id, uint16_t *msg_size) +{ + if (message_id == P5_VENDOR_EXT_RSP) { + *msg_size = sizeof(vendor_ext_p5_rsp); + return (nfapi_p4_p5_message_header_t *)malloc(sizeof(vendor_ext_p5_rsp)); + } + + return 0; +} + +void aerial_vnf_deallocate_p4_p5_vendor_ext(nfapi_p4_p5_message_header_t *header) +{ + free(header); +} + +void *aerial_vnf_p5_allocate(size_t size) +{ + // return (void*)memory_pool::allocate(size); + return (void *)malloc(size); +} + +void aerial_vnf_p5_deallocate(void *ptr) +{ + // memory_pool::deallocate((uint8_t*)ptr); + free(ptr); +} + +static vnf_info aerial_vnf; +void aerial_configure_nr_fapi_vnf() +{ + // TODO: Implement for FAPI + // nfapi_setmode(NFAPI_MODE_VNF); + memset(&aerial_vnf, 0, sizeof(aerial_vnf)); + memset(aerial_vnf.p7_vnfs, 0, sizeof(aerial_vnf.p7_vnfs)); + aerial_vnf.p7_vnfs[0].timing_window = 30; + aerial_vnf.p7_vnfs[0].periodic_timing_enabled = 0; + aerial_vnf.p7_vnfs[0].aperiodic_timing_enabled = 0; + aerial_vnf.p7_vnfs[0].periodic_timing_period = 10; + aerial_vnf.p7_vnfs[0].config = nfapi_vnf_p7_config_create(); + aerial_vnf.p7_vnfs[0].mac = (mac_t *)malloc(sizeof(mac_t)); + nfapi_vnf_config_t *config = nfapi_vnf_config_create(); + config->malloc = malloc; + config->free = free; + config->vnf_ipv4 = 1; + config->vnf_ipv6 = 0; + config->pnf_list = 0; + config->phy_list = 0; + + config->pnf_nr_connection_indication = &aerial_pnf_nr_connection_indication_cb; + config->pnf_disconnect_indication = &aerial_pnf_disconnection_indication_cb; + + config->pnf_nr_param_resp = &aerial_pnf_nr_param_resp_cb; + config->pnf_nr_config_resp = &aerial_pnf_nr_config_resp_cb; + config->pnf_nr_start_resp = &aerial_pnf_nr_start_resp_cb; + config->nr_param_resp = &aerial_nr_param_resp_cb; + config->nr_config_resp = &aerial_nr_config_resp_cb; + config->nr_start_resp = &aerial_nr_start_resp_cb; + config->vendor_ext = &aerial_vendor_ext_cb; + config->user_data = &aerial_vnf; + // To allow custom vendor extentions to be added to nfapi + config->codec_config.unpack_vendor_extension_tlv = &aerial_vnf_unpack_vendor_extension_tlv; + config->codec_config.pack_vendor_extension_tlv = &aerial_vnf_pack_vendor_extension_tlv; + config->codec_config.unpack_p4_p5_vendor_extension = &aerial_vnf_unpack_p4_p5_vendor_extension; + config->codec_config.pack_p4_p5_vendor_extension = &aerial_vnf_pack_p4_p5_vendor_extension; + config->allocate_p4_p5_vendor_ext = &aerial_vnf_allocate_p4_p5_vendor_ext; + config->deallocate_p4_p5_vendor_ext = &aerial_vnf_deallocate_p4_p5_vendor_ext; + config->codec_config.allocate = &aerial_vnf_allocate; + config->codec_config.deallocate = &aerial_vnf_deallocate; + memset(&UL_RCC_INFO, 0, sizeof(UL_RCC_IND_t)); + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__); + set_config(config); + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Created VNF NFAPI start thread %s\n", __FUNCTION__); + nfapi_vnf_pnf_info_t *pnf = (nfapi_vnf_pnf_info_t *)malloc(sizeof(nfapi_vnf_pnf_info_t)); + NFAPI_TRACE(NFAPI_TRACE_INFO, "MALLOC nfapi_vnf_pnf_info_t for pnf_list pnf:%p\n", pnf); + memset(pnf, 0, sizeof(nfapi_vnf_pnf_info_t)); + pnf->p5_idx = 1; + pnf->connected = 1; + // Add needed parameters + + vnf_info *vnf = (vnf_info *)(config->user_data); + pnf_info *pnf_info = vnf->pnfs; + + for (int i = 0; i < 1; ++i) { + phy_info phy; + memset(&phy, 0, sizeof(phy)); + phy.index = 0; + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) phy_config_idx:%d\n", i, 0); + nfapi_vnf_allocate_phy(config, 1, &(phy.id)); + + for (int j = 0; j < 1; ++j) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] (PHY:%d) (RF%d) %d\n", i, j, 0); + phy.rfs[0] = 0; + } + + pnf_info->phys[0] = phy; + } + + + nfapi_vnf_pnf_list_add(config, pnf); + + vnf_p7_info *p7_vnf = vnf->p7_vnfs; + + NFAPI_TRACE(NFAPI_TRACE_INFO, + "[VNF] pnf start response idx:%d config:%p user_data:%p p7_vnf[config:%p thread_started:%d]\n", + 1, + config, + config->user_data, + vnf->p7_vnfs[0].config, + vnf->p7_vnfs[0].thread_started); + + if (p7_vnf->thread_started == 0) { + pthread_t vnf_p7_thread; + pthread_create(&vnf_p7_thread, NULL, &aerial_vnf_nr_p7_thread_start, p7_vnf); + p7_vnf->thread_started = 1; + } else { + // P7 thread already running. + } +} +uint8_t aerial_unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config) +{ + return unpack_nr_param_response(ppReadPackedMsg, end, msg, config); +} +uint8_t aerial_unpack_nr_config_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config) +{ + return unpack_nr_config_response(ppReadPackedMsg, end, msg, config); +} + +// monitor the p7 endpoints and the timing loop and +// send indications to mac +int aerial_nfapi_nr_vnf_p7_start(nfapi_vnf_p7_config_t *config) +{ + if (config == 0) + return -1; + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__); + + vnf_p7_t *vnf_p7 = (vnf_p7_t *)config; + + // Create p7 receive udp port + // todo : this needs updating for Ipv6 + + NFAPI_TRACE(NFAPI_TRACE_INFO, "Initialising VNF P7 port:%u\n", config->port); + + + struct timespec ref_time; + clock_gettime(CLOCK_MONOTONIC, &ref_time); + uint8_t setup_done = 0; + while (vnf_p7->terminate == 0) { + if (setup_done == 0) { + struct timespec curr_time; + clock_gettime(CLOCK_MONOTONIC, &curr_time); + uint8_t setup_time = curr_time.tv_sec - ref_time.tv_sec; + if (setup_time > 3) { + setup_done = 1; + } + } + + } + NFAPI_TRACE(NFAPI_TRACE_INFO, "Closing p7 socket\n"); + close(vnf_p7->socket); + + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() returning\n", __FUNCTION__); + + return 0; +} + +int fapi_nr_p5_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t *config){ + + nfapi_p4_p5_message_header_t *pMessageHeader = pMessageBuf; + uint8_t *pWritePackedMessage = pPackedBuf; + + uint32_t packedMsgLen; + //uint16_t packedMsgLen16; + + if (pMessageBuf == NULL || pPackedBuf == NULL) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 Pack supplied pointers are null\n"); + return -1; + } + uint8_t *pPackMessageEnd = pPackedBuf + packedBufLen; + uint8_t *pPackedLengthField = &pWritePackedMessage[4]; + uint8_t *pPacketBodyField = &pWritePackedMessage[8]; + uint8_t *pPacketBodyFieldStart = &pWritePackedMessage[8]; + + pack_nr_p5_message_body(pMessageHeader, &pPacketBodyField, pPackMessageEnd, config); + + // PHY API message header + push8(1, &pWritePackedMessage, pPackMessageEnd); // Number of messages + push8(0, &pWritePackedMessage, pPackMessageEnd); // Opaque handle + + // PHY API Message structure + push16(pMessageHeader->message_id, &pWritePackedMessage, pPackMessageEnd); // Message type ID + + if(1==1) { + // check for a valid message length + packedMsgLen = get_packed_msg_len((uintptr_t)pPacketBodyFieldStart, (uintptr_t)pPacketBodyField); + packedMsgLen-=1; + if(pMessageHeader->message_id == NFAPI_NR_PHY_MSG_TYPE_START_REQUEST){ + //START.request doesn't have a body, length is 0 + packedMsgLen = 0; + }else if (packedMsgLen > 0xFFFF || packedMsgLen > packedBufLen) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Packed message 0x%02x length error %d, buffer supplied %d\n",pMessageHeader->message_id, packedMsgLen, packedBufLen); + return -1; + } else { + + } + + // Update the message length in the header + if(!push32(packedMsgLen, &pPackedLengthField, pPackMessageEnd)) + return -1; + + // return the packed length + return (packedMsgLen); + } else { + // Failed to pack the meassage + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P5 Failed to pack message\n"); + return -1; + } + +} + + +int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req) +{ + nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; + + ul_tti_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + ul_tti_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST; + + // int retval = nfapi_vnf_p7_ul_tti_req(p7_config, ul_tti_req); + int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &ul_tti_req->header); + + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + // Reset number of PDUs so that it is not resent + ul_tti_req->n_pdus = 0; + ul_tti_req->n_group = 0; + ul_tti_req->n_ulcch = 0; + ul_tti_req->n_ulsch = 0; + } + return retval; +} + +int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req) +{ + nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; + ul_dci_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + ul_dci_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST; + // int retval = nfapi_vnf_p7_ul_dci_req(p7_config, ul_dci_req); + int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &ul_dci_req->header); + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + ul_dci_req->numPdus = 0; + } + return retval; +} + +int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req) +{ + nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; + tx_data_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + tx_data_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST; + // LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_data_req->SFN), + // tx_data_req->Number_of_PDUs); int retval = nfapi_vnf_p7_tx_data_req(p7_config, tx_data_req); + int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &tx_data_req->header); + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } else { + tx_data_req->Number_of_PDUs = 0; + } + + return retval; +} + +int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req) +{ + nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; + dl_config_req->header.message_id = NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST; + dl_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!! + int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &dl_config_req->header); + dl_config_req->dl_tti_request_body.nPDUs = 0; + dl_config_req->dl_tti_request_body.nGroup = 0; + + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } + return retval; +} + +int oai_fapi_send_end_request(int cell, uint32_t frame, uint32_t slot){ + nfapi_vnf_p7_config_t *p7_config = aerial_vnf.p7_vnfs[0].config; + nfapi_nr_slot_indication_scf_t *nr_slot_resp = CALLOC(1, sizeof(*nr_slot_resp)); + nr_slot_resp->header.message_id = 0x8F; + nr_slot_resp->sfn = frame; + nr_slot_resp->slot = slot; + int retval = fapi_nr_pack_and_send_p7_message((vnf_p7_t *)p7_config, &nr_slot_resp->header); + if (retval != 0) { + LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval); + } + return retval; +} +#endif diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p5.h b/nfapi/oai_integration/aerial/fapi_vnf_p5.h new file mode 100644 index 0000000000..9d3fb6d170 --- /dev/null +++ b/nfapi/oai_integration/aerial/fapi_vnf_p5.h @@ -0,0 +1,75 @@ +/* +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org + */ + +/*! \file fapi/oai-integration/fapi_vnf_p5.h +* \brief Header file for fapi_vnf_p5.c +* \author Ruben S. Silva +* \date 2023 +* \version 0.1 +* \company OpenAirInterface Software Alliance +* \email: contact@openairinterface.org, rsilva@allbesmart.pt +* \note +* \warning + */ +#ifdef ENABLE_AERIAL +#ifndef OPENAIRINTERFACE_FAPI_VNF_P5_H +#define OPENAIRINTERFACE_FAPI_VNF_P5_H +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfapi_nr_interface_scf.h" +#include "nfapi_vnf_interface.h" +#include "nfapi_vnf.h" +#include "nfapi.h" +#include "nfapi/oai_integration/vendor_ext.h" +#include "fapi_nvIPC.h" + +#include "PHY/defs_eNB.h" +#include "PHY/LTE_TRANSPORT/transport_proto.h" + +#include "common/ran_context.h" +#include "openair2/PHY_INTERFACE/queue_t.h" +#include "gnb_ind_vars.h" +#include "nfapi/open-nFAPI/vnf/inc/vnf.h" + +void aerial_configure_nr_fapi_vnf(); +int aerial_nr_send_config_request(nfapi_vnf_config_t *config, int p5_idx); +int oai_fapi_send_end_request(int cell_id, uint32_t frame, uint32_t slot); +uint8_t aerial_unpack_nr_param_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config); +uint8_t aerial_unpack_nr_config_response(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p4_p5_codec_config_t *config); +int aerial_pnf_nr_connection_indication_cb(nfapi_vnf_config_t *config, int p5_idx); +int aerial_nfapi_nr_vnf_p7_start(nfapi_vnf_p7_config_t *config); +int fapi_nr_p5_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, uint32_t packedBufLen, nfapi_p4_p5_codec_config_t* config); + +int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req); +int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req); +int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req); +int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req); +#endif //OPENAIRINTERFACE_FAPI_VNF_P5_H +#endif diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p7.c b/nfapi/oai_integration/aerial/fapi_vnf_p7.c new file mode 100644 index 0000000000..3e54b75375 --- /dev/null +++ b/nfapi/oai_integration/aerial/fapi_vnf_p7.c @@ -0,0 +1,1315 @@ +/* +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org + */ + +/*! \file fapi/oai-integration/fapi_vnf_p7.c +* \brief OAI FAPI VNF P7 message handler procedures +* \author Ruben S. Silva +* \date 2023 +* \version 0.1 +* \company OpenAirInterface Software Alliance +* \email: contact@openairinterface.org, rsilva@allbesmart.pt +* \note +* \warning + */ +#ifdef ENABLE_AERIAL +#include "fapi_vnf_p7.h" +#include "nfapi/open-nFAPI/nfapi/src/nfapi_p7.c" + +extern RAN_CONTEXT_t RC; +extern UL_RCC_IND_t UL_RCC_INFO; +extern int single_thread_flag; +extern uint16_t sf_ahead; + +int aerial_wake_gNB_rxtx(PHY_VARS_gNB *gNB, uint16_t sfn, uint16_t slot) +{ + struct timespec curr_t; + clock_gettime(CLOCK_MONOTONIC, &curr_t); + // NFAPI_TRACE(NFAPI_TRACE_INFO, "\n wake_gNB_rxtx before assignment sfn:%d slot:%d TIME + // %d.%d",sfn,slot,curr_t.tv_sec,curr_t.tv_nsec); + gNB_L1_proc_t *proc = &gNB->proc; + gNB_L1_rxtx_proc_t *L1_proc = (slot & 1) ? &proc->L1_proc : &proc->L1_proc_tx; + + NR_DL_FRAME_PARMS *fp = &gNB->frame_parms; + // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(eNB:%p, sfn:%d, sf:%d)\n", __FUNCTION__, eNB, sfn, sf); + // int i; + struct timespec wait; + clock_gettime(CLOCK_REALTIME, &wait); + wait.tv_sec = 0; + wait.tv_nsec += 5000L; + // wait.tv_nsec = 0; + // wake up TX for subframe n+sf_ahead + // lock the TX mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&L1_proc->mutex, &wait) != 0) { + LOG_E(PHY, "[gNB] ERROR pthread_mutex_lock for gNB RXTX thread %d (IC %d)\n", L1_proc->slot_rx & 1, L1_proc->instance_cnt); + exit_fun("error locking mutex_rxtx"); + return (-1); + } + + { + static uint16_t old_slot = 0; + static uint16_t old_sfn = 0; + proc->slot_rx = old_slot; + proc->frame_rx = old_sfn; + // Try to be 1 frame back + old_slot = slot; + old_sfn = sfn; + // NFAPI_TRACE(NFAPI_TRACE_INFO, "\n wake_gNB_rxtx after assignment sfn:%d slot:%d",proc->frame_rx,proc->slot_rx); + if (old_slot == 0 && old_sfn % 100 == 0) + LOG_W(PHY, + "[gNB] sfn/slot:%d%d old_sfn/slot:%d%d proc[rx:%d%d]\n", + sfn, + slot, + old_sfn, + old_slot, + proc->frame_rx, + proc->slot_rx); + } + + ++L1_proc->instance_cnt; + // LOG_D( PHY,"[VNF-subframe_ind] sfn/sf:%d:%d proc[frame_rx:%d subframe_rx:%d] L1_proc->instance_cnt_rxtx:%d \n", sfn, sf, + // proc->frame_rx, proc->subframe_rx, L1_proc->instance_cnt_rxtx); + // We have just received and processed the common part of a subframe, say n. + // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired + // transmitted timestamp of the next TX slot (first). + // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, + // we want to generate subframe (n+N), so TS_tx = TX_rx+N*samples_per_tti, + // and proc->subframe_tx = proc->subframe_rx+sf_ahead + L1_proc->timestamp_tx = proc->timestamp_rx + (gNB->if_inst->sl_ahead * fp->samples_per_subframe); + L1_proc->frame_rx = proc->frame_rx; + L1_proc->slot_rx = proc->slot_rx; + L1_proc->frame_tx = (L1_proc->slot_rx > (19 - gNB->if_inst->sl_ahead)) ? (L1_proc->frame_rx + 1) & 1023 : L1_proc->frame_rx; + L1_proc->slot_tx = (L1_proc->slot_rx + gNB->if_inst->sl_ahead) % 20; + + // LOG_I(PHY, "sfn/sf:%d%d proc[rx:%d%d] rx:%d%d] About to wake rxtx thread\n\n", sfn, slot, proc->frame_rx, proc->slot_rx, + // L1_proc->frame_rx, L1_proc->slot_rx); NFAPI_TRACE(NFAPI_TRACE_INFO, "\nEntering wake_gNB_rxtx sfn %d slot + // %d\n",L1_proc->frame_rx,L1_proc->slot_rx); + // the thread can now be woken up + if (pthread_cond_signal(&L1_proc->cond) != 0) { + LOG_E(PHY, "[gNB] ERROR pthread_cond_signal for gNB RXn-TXnp4 thread\n"); + exit_fun("ERROR pthread_clond_signal"); + return (-1); + } + + // LOG_D(PHY,"%s() About to attempt pthread_mutex_unlock\n", __FUNCTION__); + pthread_mutex_unlock(&L1_proc->mutex); + // LOG_D(PHY,"%s() UNLOCKED pthread_mutex_unlock\n", __FUNCTION__); + return (0); +} + +int aerialwake_eNB_rxtx(PHY_VARS_eNB *eNB, uint16_t sfn, uint16_t sf) +{ + L1_proc_t *proc = &eNB->proc; + L1_rxtx_proc_t *L1_proc = (sf & 1) ? &proc->L1_proc : &proc->L1_proc_tx; + LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms; + // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s(eNB:%p, sfn:%d, sf:%d)\n", __FUNCTION__, eNB, sfn, sf); + // int i; + struct timespec wait; + wait.tv_sec = 0; + wait.tv_nsec = 5000000L; + + // wake up TX for subframe n+sf_ahead + // lock the TX mutex and make sure the thread is ready + // if (pthread_mutex_timedlock(&L1_proc->mutex,&wait) != 0) { + // LOG_E( PHY, "[eNB] ERROR pthread_mutex_lock for eNB RXTX thread %d (IC %d)\n", L1_proc->subframe_rx&1,L1_proc->instance_cnt ); + // exit_fun( "error locking mutex_rxtx" ); + // return(-1); + //} + + { + static uint16_t old_sf = 0; + static uint16_t old_sfn = 0; + proc->subframe_rx = old_sf; + proc->frame_rx = old_sfn; + // Try to be 1 frame back + old_sf = sf; + old_sfn = sfn; + + if (old_sf == 0 && old_sfn % 100 == 0) + LOG_D(PHY, "[eNB] sfn/sf:%d%d old_sfn/sf:%d%d proc[rx:%d%d]\n", sfn, sf, old_sfn, old_sf, proc->frame_rx, proc->subframe_rx); + } + // wake up TX for subframe n+sf_ahead + // lock the TX mutex and make sure the thread is ready + if (pthread_mutex_timedlock(&L1_proc->mutex, &wait) != 0) { + LOG_E(PHY, "[eNB] ERROR pthread_mutex_lock for eNB RXTX thread %d (IC %d)\n", L1_proc->subframe_rx & 1, L1_proc->instance_cnt); + // exit_fun( "error locking mutex_rxtx" ); + return (-1); + } + static int busy_log_cnt = 0; + if (L1_proc->instance_cnt < 0) { + ++L1_proc->instance_cnt; + if (busy_log_cnt != 0) { + LOG_E(MAC, + "RCC singal to rxtx frame %d subframe %d busy end %d (frame %d subframe %d)\n", + L1_proc->frame_rx, + L1_proc->subframe_rx, + busy_log_cnt, + proc->frame_rx, + proc->subframe_rx); + } + busy_log_cnt = 0; + } else { + if (busy_log_cnt == 0) { + LOG_E(MAC, + "RCC singal to rxtx frame %d subframe %d busy %d (frame %d subframe %d)\n", + L1_proc->frame_rx, + L1_proc->subframe_rx, + L1_proc->instance_cnt, + proc->frame_rx, + proc->subframe_rx); + } + pthread_mutex_unlock(&L1_proc->mutex); + busy_log_cnt++; + return (0); + } + + pthread_mutex_unlock(&L1_proc->mutex); + + // LOG_D( PHY,"[VNF-subframe_ind] sfn/sf:%d:%d proc[frame_rx:%d subframe_rx:%d] L1_proc->instance_cnt_rxtx:%d \n", sfn, sf, + // proc->frame_rx, proc->subframe_rx, L1_proc->instance_cnt_rxtx); + // We have just received and processed the common part of a subframe, say n. + // TS_rx is the last received timestamp (start of 1st slot), TS_tx is the desired + // transmitted timestamp of the next TX slot (first). + // The last (TS_rx mod samples_per_frame) was n*samples_per_tti, + // we want to generate subframe (n+N), so TS_tx = TX_rx+N*samples_per_tti, + // and proc->subframe_tx = proc->subframe_rx+sf_ahead + L1_proc->timestamp_tx = proc->timestamp_rx + (sf_ahead * fp->samples_per_tti); + L1_proc->frame_rx = proc->frame_rx; + L1_proc->subframe_rx = proc->subframe_rx; + L1_proc->frame_tx = (L1_proc->subframe_rx > (9 - sf_ahead)) ? (L1_proc->frame_rx + 1) & 1023 : L1_proc->frame_rx; + L1_proc->subframe_tx = (L1_proc->subframe_rx + sf_ahead) % 10; + + // LOG_D(PHY, "sfn/sf:%d%d proc[rx:%d%d] L1_proc[instance_cnt_rxtx:%d rx:%d%d] About to wake rxtx thread\n\n", sfn, sf, + // proc->frame_rx, proc->subframe_rx, L1_proc->instance_cnt_rxtx, L1_proc->frame_rx, L1_proc->subframe_rx); + + // the thread can now be woken up + if (pthread_cond_signal(&L1_proc->cond) != 0) { + LOG_E(PHY, "[eNB] ERROR pthread_cond_signal for eNB RXn-TXnp4 thread\n"); + exit_fun("ERROR pthread_cond_signal"); + return (-1); + } + + return (0); +} + +extern pthread_cond_t nfapi_sync_cond; +extern pthread_mutex_t nfapi_sync_mutex; +extern int nfapi_sync_var; + +int aerial_phy_sync_indication(struct nfapi_vnf_p7_config *config, uint8_t sync) +{ + // NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] SYNC %s\n", sync==1 ? "ACHIEVED" : "LOST"); + + if (sync == 1 && nfapi_sync_var != 0) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Signal to OAI main code that it can go\n"); + pthread_mutex_lock(&nfapi_sync_mutex); + nfapi_sync_var = 0; + pthread_cond_broadcast(&nfapi_sync_cond); + pthread_mutex_unlock(&nfapi_sync_mutex); + } + + return (0); +} + +int aerial_phy_slot_indication(struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn, uint16_t slot) +{ + static uint8_t first_time = 1; + + if (first_time) { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] slot indication %d\n", NFAPI_SFNSLOT2DEC(sfn, slot)); + first_time = 0; + } + + if (RC.gNB && RC.gNB[0]->configured) { + // uint16_t sfn = NFAPI_SFNSF2SFN(sfn_sf); + // uint16_t sf = NFAPI_SFNSF2SF(sfn_sf); + LOG_D(PHY, "[VNF] slot indication sfn:%d slot:%d\n", sfn, slot); + aerial_wake_gNB_rxtx(RC.gNB[0], sfn, slot); // DONE: find NR equivalent + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] %s() RC.gNB:%p\n", __FUNCTION__, RC.gNB); + + if (RC.gNB) + NFAPI_TRACE(NFAPI_TRACE_INFO, "RC.gNB[0]->configured:%d\n", RC.gNB[0]->configured); + } + + return 0; +} + +int aerial_phy_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_harq_indication_t *ind) +{ + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + LOG_D(MAC, + "%s() NFAPI SFN/SF:%d number_of_harqs:%u\n", + __FUNCTION__, + NFAPI_SFNSF2DEC(ind->sfn_sf), + ind->harq_indication_body.number_of_harqs); + AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex) == 0, "Mutex lock failed"); + if (NFAPI_MODE == NFAPI_MODE_VNF) { + int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf); + + UL_RCC_INFO.harq_ind[index] = *ind; + + assert(ind->harq_indication_body.number_of_harqs <= NFAPI_HARQ_IND_MAX_PDU); + if (ind->harq_indication_body.number_of_harqs > 0) { + UL_RCC_INFO.harq_ind[index].harq_indication_body.harq_pdu_list = + malloc(sizeof(nfapi_harq_indication_pdu_t) * NFAPI_HARQ_IND_MAX_PDU); + } + for (int i = 0; i < ind->harq_indication_body.number_of_harqs; i++) { + memcpy(&UL_RCC_INFO.harq_ind[index].harq_indication_body.harq_pdu_list[i], + &ind->harq_indication_body.harq_pdu_list[i], + sizeof(nfapi_harq_indication_pdu_t)); + } + } else { + eNB->UL_INFO.harq_ind = *ind; + eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list; + + assert(ind->harq_indication_body.number_of_harqs <= NFAPI_HARQ_IND_MAX_PDU); + for (int i = 0; i < ind->harq_indication_body.number_of_harqs; i++) { + memcpy(&eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[i], + &ind->harq_indication_body.harq_pdu_list[i], + sizeof(eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[i])); + } + } + AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex) == 0, "Mutex unlock failed"); + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + // mac_harq_ind(p7_vnf->mac, ind); + return 1; +} + +int aerial_phy_nr_crc_indication(nfapi_nr_crc_indication_t *ind) +{ + if (NFAPI_MODE == NFAPI_MODE_AERIAL) { + nfapi_nr_crc_indication_t *crc_ind = CALLOC(1, sizeof(*crc_ind)); + crc_ind->header.message_id = ind->header.message_id; + crc_ind->number_crcs = ind->number_crcs; + crc_ind->sfn = ind->sfn; + crc_ind->slot = ind->slot; + if (ind->number_crcs > 0) { + crc_ind->crc_list = CALLOC(NFAPI_NR_CRC_IND_MAX_PDU, sizeof(nfapi_nr_crc_t)); + AssertFatal(crc_ind->crc_list != NULL, "Memory not allocated for crc_ind->crc_list in phy_nr_crc_indication."); + } + for (int j = 0; j < ind->number_crcs; j++) { + crc_ind->crc_list[j].handle = ind->crc_list[j].handle; + crc_ind->crc_list[j].rnti = ind->crc_list[j].rnti; + crc_ind->crc_list[j].harq_id = ind->crc_list[j].harq_id; + crc_ind->crc_list[j].tb_crc_status = ind->crc_list[j].tb_crc_status; + crc_ind->crc_list[j].num_cb = ind->crc_list[j].num_cb; + crc_ind->crc_list[j].cb_crc_status = ind->crc_list[j].cb_crc_status; + crc_ind->crc_list[j].ul_cqi = ind->crc_list[j].ul_cqi; + crc_ind->crc_list[j].timing_advance = ind->crc_list[j].timing_advance; + crc_ind->crc_list[j].rssi = ind->crc_list[j].rssi; + if (crc_ind->crc_list[j].tb_crc_status != 0) { + LOG_D(NR_MAC, + "Received crc_ind.harq_id %d status %d for index %d SFN SLot %u %u with rnti %04x\n", + crc_ind->crc_list[j].harq_id, + crc_ind->crc_list[j].tb_crc_status, + j, + crc_ind->sfn, + crc_ind->slot, + crc_ind->crc_list[j].rnti); + } + } + if (!put_queue(&gnb_crc_ind_queue, crc_ind)) { + LOG_E(NR_MAC, "Put_queue failed for crc_ind\n"); + free(crc_ind->crc_list); + free(crc_ind); + } + } else { + LOG_E(NR_MAC, "NFAPI_MODE = %d not NFAPI_MODE_AERIAL(3)\n", nfapi_getmode()); + } + return 1; +} + +int aerial_phy_nr_rx_data_indication(nfapi_nr_rx_data_indication_t *ind) +{ + if (NFAPI_MODE == NFAPI_MODE_AERIAL) { + nfapi_nr_rx_data_indication_t *rx_ind = CALLOC(1, sizeof(*rx_ind)); + rx_ind->header.message_id = ind->header.message_id; + rx_ind->sfn = ind->sfn; + rx_ind->slot = ind->slot; + rx_ind->number_of_pdus = ind->number_of_pdus; + + if (ind->number_of_pdus > 0) { + rx_ind->pdu_list = CALLOC(NFAPI_NR_RX_DATA_IND_MAX_PDU, sizeof(nfapi_nr_rx_data_pdu_t)); + AssertFatal(rx_ind->pdu_list != NULL, "Memory not allocated for rx_ind->pdu_list in phy_nr_rx_data_indication."); + } + for (int j = 0; j < ind->number_of_pdus; j++) { + rx_ind->pdu_list[j].handle = ind->pdu_list[j].handle; + rx_ind->pdu_list[j].rnti = ind->pdu_list[j].rnti; + rx_ind->pdu_list[j].harq_id = ind->pdu_list[j].harq_id; + rx_ind->pdu_list[j].pdu_length = ind->pdu_list[j].pdu_length; + rx_ind->pdu_list[j].ul_cqi = ind->pdu_list[j].ul_cqi; + rx_ind->pdu_list[j].timing_advance = ind->pdu_list[j].timing_advance; + rx_ind->pdu_list[j].rssi = ind->pdu_list[j].rssi; + rx_ind->pdu_list[j].pdu = ind->pdu_list[j].pdu; + LOG_D(NR_MAC, + "(%d.%d) Handle %d for index %d, RNTI, %04x, HARQID %d\n", + ind->sfn, + ind->slot, + ind->pdu_list[j].handle, + j, + ind->pdu_list[j].rnti, + ind->pdu_list[j].harq_id); + } + if (!put_queue(&gnb_rx_ind_queue, rx_ind)) { + LOG_E(NR_MAC, "Put_queue failed for rx_ind\n"); + free(rx_ind->pdu_list); + free(rx_ind); + } + } else { + LOG_E(NR_MAC, "NFAPI_MODE = %d not NFAPI_MODE_AERIAL(3)\n", nfapi_getmode()); + } + return 1; +} + +int aerial_phy_nr_rach_indication(nfapi_nr_rach_indication_t *ind) +{ + if (NFAPI_MODE == NFAPI_MODE_AERIAL) { + nfapi_nr_rach_indication_t *rach_ind = CALLOC(1, sizeof(*rach_ind)); + rach_ind->header.message_id = ind->header.message_id; + rach_ind->sfn = ind->sfn; + rach_ind->slot = ind->slot; + rach_ind->number_of_pdus = ind->number_of_pdus; + rach_ind->pdu_list = CALLOC(rach_ind->number_of_pdus, sizeof(*rach_ind->pdu_list)); + AssertFatal(rach_ind->pdu_list != NULL, "Memory not allocated for rach_ind->pdu_list in phy_nr_rach_indication."); + for (int i = 0; i < ind->number_of_pdus; i++) { + rach_ind->pdu_list[i].phy_cell_id = ind->pdu_list[i].phy_cell_id; + rach_ind->pdu_list[i].symbol_index = ind->pdu_list[i].symbol_index; + rach_ind->pdu_list[i].slot_index = ind->pdu_list[i].slot_index; + rach_ind->pdu_list[i].freq_index = ind->pdu_list[i].freq_index; + rach_ind->pdu_list[i].avg_rssi = ind->pdu_list[i].avg_rssi; + rach_ind->pdu_list[i].avg_snr = ind->pdu_list[i].avg_snr; + rach_ind->pdu_list[i].num_preamble = ind->pdu_list[i].num_preamble; + rach_ind->pdu_list[i].preamble_list = CALLOC(ind->pdu_list[i].num_preamble, sizeof(nfapi_nr_prach_indication_preamble_t)); + AssertFatal(rach_ind->pdu_list[i].preamble_list != NULL, + "Memory not allocated for rach_ind->pdu_list[i].preamble_list in phy_nr_rach_indication."); + for (int j = 0; j < ind->pdu_list[i].num_preamble; j++) { + rach_ind->pdu_list[i].preamble_list[j].preamble_index = ind->pdu_list[i].preamble_list[j].preamble_index; + rach_ind->pdu_list[i].preamble_list[j].timing_advance = ind->pdu_list[i].preamble_list[j].timing_advance; + rach_ind->pdu_list[i].preamble_list[j].preamble_pwr = ind->pdu_list[i].preamble_list[j].preamble_pwr; + } + } + if (!put_queue(&gnb_rach_ind_queue, rach_ind)) { + LOG_E(NR_MAC, "Put_queue failed for rach_ind\n"); + for (int i = 0; i < ind->number_of_pdus; i++) { + free(rach_ind->pdu_list[i].preamble_list); + } + free(rach_ind->pdu_list); + free(rach_ind); + } else { + LOG_I(NR_MAC, "RACH.indication put_queue successfull\n"); + } + } else { + LOG_E(NR_MAC, "NFAPI_MODE = %d not NFAPI_MODE_AERIAL(3)\n", nfapi_getmode()); + } + return 1; +} + +int aerial_phy_nr_uci_indication(nfapi_nr_uci_indication_t *ind) +{ + if (NFAPI_MODE == NFAPI_MODE_AERIAL) { + nfapi_nr_uci_indication_t *uci_ind = CALLOC(1, sizeof(*uci_ind)); + AssertFatal(uci_ind != NULL, "Memory not allocated for uci_ind in phy_nr_uci_indication."); + *uci_ind = *ind; + + uci_ind->uci_list = CALLOC(NFAPI_NR_UCI_IND_MAX_PDU, sizeof(nfapi_nr_uci_t)); + AssertFatal(uci_ind->uci_list != NULL, "Memory not allocated for uci_ind->uci_list in phy_nr_uci_indication."); + for (int i = 0; i < ind->num_ucis; i++) { + uci_ind->uci_list[i] = ind->uci_list[i]; + + switch (uci_ind->uci_list[i].pdu_type) { + case NFAPI_NR_UCI_PUSCH_PDU_TYPE: + LOG_E(MAC, "%s(): unhandled NFAPI_NR_UCI_PUSCH_PDU_TYPE\n", __func__); + break; + + case NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE: { +// nfapi_nr_uci_pucch_pdu_format_0_1_t *uci_ind_pdu = &uci_ind->uci_list[i].pucch_pdu_format_0_1; +// nfapi_nr_uci_pucch_pdu_format_0_1_t *ind_pdu = &ind->uci_list[i].pucch_pdu_format_0_1; +// if (ind_pdu->sr) { +// uci_ind_pdu->sr = CALLOC(1, sizeof(*uci_ind_pdu->sr)); +// AssertFatal(uci_ind_pdu->sr != NULL, "Memory not allocated for uci_ind_pdu->harq in phy_nr_uci_indication."); +// *uci_ind_pdu->sr = *ind_pdu->sr; +// } +// if (ind_pdu->harq) { +// uci_ind_pdu->harq = CALLOC(1, sizeof(*uci_ind_pdu->harq)); +// AssertFatal(uci_ind_pdu->harq != NULL, "Memory not allocated for uci_ind_pdu->harq in phy_nr_uci_indication."); +// +// *uci_ind_pdu->harq = *ind_pdu->harq; +// uci_ind_pdu->harq->harq_list = CALLOC(uci_ind_pdu->harq->num_harq, sizeof(*uci_ind_pdu->harq->harq_list)); +// AssertFatal(uci_ind_pdu->harq->harq_list != NULL, +// "Memory not allocated for uci_ind_pdu->harq->harq_list in phy_nr_uci_indication."); +// for (int j = 0; j < uci_ind_pdu->harq->num_harq; j++) +// uci_ind_pdu->harq->harq_list[j].harq_value = ind_pdu->harq->harq_list[j].harq_value; +// } + break; + } + + case NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE: { + nfapi_nr_uci_pucch_pdu_format_2_3_4_t *uci_ind_pdu = &uci_ind->uci_list[i].pucch_pdu_format_2_3_4; + nfapi_nr_uci_pucch_pdu_format_2_3_4_t *ind_pdu = &ind->uci_list[i].pucch_pdu_format_2_3_4; + *uci_ind_pdu = *ind_pdu; + if (ind_pdu->harq.harq_payload) { + uci_ind_pdu->harq.harq_payload = CALLOC(1, sizeof(*uci_ind_pdu->harq.harq_payload)); + AssertFatal(uci_ind_pdu->harq.harq_payload != NULL, + "Memory not allocated for uci_ind_pdu->harq.harq_payload in phy_nr_uci_indication."); + *uci_ind_pdu->harq.harq_payload = *ind_pdu->harq.harq_payload; + } + if (ind_pdu->sr.sr_payload) { + uci_ind_pdu->sr.sr_payload = CALLOC(1, sizeof(*uci_ind_pdu->sr.sr_payload)); + AssertFatal(uci_ind_pdu->sr.sr_payload != NULL, + "Memory not allocated for uci_ind_pdu->sr.sr_payload in phy_nr_uci_indication."); + *uci_ind_pdu->sr.sr_payload = *ind_pdu->sr.sr_payload; + } + if (ind_pdu->csi_part1.csi_part1_payload) { + uci_ind_pdu->csi_part1.csi_part1_payload = CALLOC(1, sizeof(*uci_ind_pdu->csi_part1.csi_part1_payload)); + AssertFatal(uci_ind_pdu->csi_part1.csi_part1_payload != NULL, + "Memory not allocated for uci_ind_pdu->csi_part1.csi_part1_payload in phy_nr_uci_indication."); + *uci_ind_pdu->csi_part1.csi_part1_payload = *ind_pdu->csi_part1.csi_part1_payload; + } + if (ind_pdu->csi_part2.csi_part2_payload) { + uci_ind_pdu->csi_part2.csi_part2_payload = CALLOC(1, sizeof(*uci_ind_pdu->csi_part2.csi_part2_payload)); + AssertFatal(uci_ind_pdu->csi_part2.csi_part2_payload != NULL, + "Memory not allocated for uci_ind_pdu->csi_part2.csi_part2_payload in phy_nr_uci_indication."); + *uci_ind_pdu->csi_part2.csi_part2_payload = *ind_pdu->csi_part2.csi_part2_payload; + } + break; + } + } + } + + if (!put_queue(&gnb_uci_ind_queue, uci_ind)) { + LOG_E(NR_MAC, "Put_queue failed for uci_ind\n"); + for (int i = 0; i < ind->num_ucis; i++) { + if (uci_ind->uci_list[i].pdu_type == NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE) { +// if (uci_ind->uci_list[i].pucch_pdu_format_0_1.harq) { +// free(uci_ind->uci_list[i].pucch_pdu_format_0_1.harq->harq_list); +// uci_ind->uci_list[i].pucch_pdu_format_0_1.harq->harq_list = NULL; +// free(uci_ind->uci_list[i].pucch_pdu_format_0_1.harq); +// uci_ind->uci_list[i].pucch_pdu_format_0_1.harq = NULL; +// } +// if (uci_ind->uci_list[i].pucch_pdu_format_0_1.sr) { +// free(uci_ind->uci_list[i].pucch_pdu_format_0_1.sr); +// uci_ind->uci_list[i].pucch_pdu_format_0_1.sr = NULL; +// } + } + if (uci_ind->uci_list[i].pdu_type == NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE) { + free(uci_ind->uci_list[i].pucch_pdu_format_2_3_4.harq.harq_payload); + free(uci_ind->uci_list[i].pucch_pdu_format_2_3_4.csi_part1.csi_part1_payload); + free(uci_ind->uci_list[i].pucch_pdu_format_2_3_4.csi_part2.csi_part2_payload); + } + } + free(uci_ind->uci_list); + uci_ind->uci_list = NULL; + free(uci_ind); + uci_ind = NULL; + } + } else { + LOG_E(NR_MAC, "NFAPI_MODE = %d not NFAPI_MODE_AERIAL(3)\n", nfapi_getmode()); + } + return 1; +} + +int aerial_phy_srs_indication(struct nfapi_vnf_p7_config *config, nfapi_srs_indication_t *ind) +{ + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + // mac_srs_ind(p7_vnf->mac, ind); + return 1; +} + +int aerial_phy_sr_indication(struct nfapi_vnf_p7_config *config, nfapi_sr_indication_t *ind) +{ + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + LOG_D(MAC, "%s() NFAPI SFN/SF:%d srs:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->sr_indication_body.number_of_srs); + AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex) == 0, "Mutex lock failed"); + if (NFAPI_MODE == NFAPI_MODE_VNF) { + int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf); + + UL_RCC_INFO.sr_ind[index] = *ind; + LOG_D(MAC, + "%s() UL_INFO[%d].sr_ind.sr_indication_body.number_of_srs:%d\n", + __FUNCTION__, + index, + eNB->UL_INFO.sr_ind.sr_indication_body.number_of_srs); + if (ind->sr_indication_body.number_of_srs > 0) { + assert(ind->sr_indication_body.number_of_srs <= NFAPI_SR_IND_MAX_PDU); + UL_RCC_INFO.sr_ind[index].sr_indication_body.sr_pdu_list = malloc(sizeof(nfapi_sr_indication_pdu_t) * NFAPI_SR_IND_MAX_PDU); + } + + assert(ind->sr_indication_body.number_of_srs <= NFAPI_SR_IND_MAX_PDU); + for (int i = 0; i < ind->sr_indication_body.number_of_srs; i++) { + nfapi_sr_indication_pdu_t *dest_pdu = &UL_RCC_INFO.sr_ind[index].sr_indication_body.sr_pdu_list[i]; + nfapi_sr_indication_pdu_t *src_pdu = &ind->sr_indication_body.sr_pdu_list[i]; + + LOG_D(MAC, + "SR_IND[PDU:%d %d][rnti:%x cqi:%d channel:%d]\n", + index, + i, + src_pdu->rx_ue_information.rnti, + src_pdu->ul_cqi_information.ul_cqi, + src_pdu->ul_cqi_information.channel); + + memcpy(dest_pdu, src_pdu, sizeof(*src_pdu)); + } + } else { + nfapi_sr_indication_t *dest_ind = &eNB->UL_INFO.sr_ind; + nfapi_sr_indication_pdu_t *dest_pdu_list = eNB->sr_pdu_list; + *dest_ind = *ind; + dest_ind->sr_indication_body.sr_pdu_list = dest_pdu_list; + LOG_D(MAC, + "%s() eNB->UL_INFO.sr_ind.sr_indication_body.number_of_srs:%d\n", + __FUNCTION__, + eNB->UL_INFO.sr_ind.sr_indication_body.number_of_srs); + + assert(eNB->UL_INFO.sr_ind.sr_indication_body.number_of_srs <= NFAPI_SR_IND_MAX_PDU); + for (int i = 0; i < eNB->UL_INFO.sr_ind.sr_indication_body.number_of_srs; i++) { + nfapi_sr_indication_pdu_t *dest_pdu = &dest_ind->sr_indication_body.sr_pdu_list[i]; + nfapi_sr_indication_pdu_t *src_pdu = &ind->sr_indication_body.sr_pdu_list[i]; + LOG_D(MAC, + "SR_IND[PDU:%d][rnti:%x cqi:%d channel:%d]\n", + i, + src_pdu->rx_ue_information.rnti, + src_pdu->ul_cqi_information.ul_cqi, + src_pdu->ul_cqi_information.channel); + memcpy(dest_pdu, src_pdu, sizeof(*src_pdu)); + } + } + AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex) == 0, "Mutex unlock failed"); + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + // mac_sr_ind(p7_vnf->mac, ind); + return 1; +} + +static bool aerial_is_ue_same(uint16_t ue_id_1, uint16_t ue_id_2) +{ + return (ue_id_1 == ue_id_2); +} + +static void aerial_analyze_cqi_pdus_for_duplicates(nfapi_cqi_indication_t *ind) +{ + uint16_t num_cqis = ind->cqi_indication_body.number_of_cqis; + assert(num_cqis <= NFAPI_CQI_IND_MAX_PDU); + for (int i = 0; i < num_cqis; i++) { + nfapi_cqi_indication_pdu_t *src_pdu = &ind->cqi_indication_body.cqi_pdu_list[i]; + + LOG_I(MAC, + "CQI_IND[PDU:%d][rnti:%x cqi:%d channel:%d]\n", + i, + src_pdu->rx_ue_information.rnti, + src_pdu->ul_cqi_information.ul_cqi, + src_pdu->ul_cqi_information.channel); + + for (int j = i + 1; j < num_cqis; j++) { + uint16_t rnti_i = ind->cqi_indication_body.cqi_pdu_list[i].rx_ue_information.rnti; + uint16_t rnti_j = ind->cqi_indication_body.cqi_pdu_list[j].rx_ue_information.rnti; + if (aerial_is_ue_same(rnti_i, rnti_j)) { + LOG_E(MAC, "Problem, two cqis received from a single UE for rnti %x\n", rnti_i); + // abort(); This will be fixed in merge request which handles multiple CQIs. + } + } + } +} + +int aerial_phy_cqi_indication(struct nfapi_vnf_p7_config *config, nfapi_cqi_indication_t *ind) +{ + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + // mac_cqi_ind(p7_vnf->mac, ind); + struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0]; + LOG_D(MAC, + "%s() NFAPI SFN/SF:%d number_of_cqis:%u\n", + __FUNCTION__, + NFAPI_SFNSF2DEC(ind->sfn_sf), + ind->cqi_indication_body.number_of_cqis); + AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex) == 0, "Mutex lock failed"); + if (NFAPI_MODE == NFAPI_MODE_VNF) { + int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf); + + UL_RCC_INFO.cqi_ind[index] = *ind; + assert(ind->cqi_indication_body.number_of_cqis <= NFAPI_CQI_IND_MAX_PDU); + if (ind->cqi_indication_body.number_of_cqis > 0) { + UL_RCC_INFO.cqi_ind[index].cqi_indication_body.cqi_pdu_list = + malloc(sizeof(nfapi_cqi_indication_pdu_t) * NFAPI_CQI_IND_MAX_PDU); + UL_RCC_INFO.cqi_ind[index].cqi_indication_body.cqi_raw_pdu_list = + malloc(sizeof(nfapi_cqi_indication_raw_pdu_t) * NFAPI_CQI_IND_MAX_PDU); + } + + aerial_analyze_cqi_pdus_for_duplicates(ind); + + assert(ind->cqi_indication_body.number_of_cqis <= NFAPI_CQI_IND_MAX_PDU); + for (int i = 0; i < ind->cqi_indication_body.number_of_cqis; i++) { + nfapi_cqi_indication_pdu_t *src_pdu = &ind->cqi_indication_body.cqi_pdu_list[i]; + LOG_D(MAC, + "SR_IND[PDU:%d][rnti:%x cqi:%d channel:%d]\n", + i, + src_pdu->rx_ue_information.rnti, + src_pdu->ul_cqi_information.ul_cqi, + src_pdu->ul_cqi_information.channel); + memcpy(&UL_RCC_INFO.cqi_ind[index].cqi_indication_body.cqi_pdu_list[i], src_pdu, sizeof(nfapi_cqi_indication_pdu_t)); + + memcpy(&UL_RCC_INFO.cqi_ind[index].cqi_indication_body.cqi_raw_pdu_list[i], + &ind->cqi_indication_body.cqi_raw_pdu_list[i], + sizeof(nfapi_cqi_indication_raw_pdu_t)); + } + } else { + nfapi_cqi_indication_t *dest_ind = &eNB->UL_INFO.cqi_ind; + *dest_ind = *ind; + dest_ind->cqi_indication_body.cqi_pdu_list = ind->cqi_indication_body.cqi_pdu_list; + dest_ind->cqi_indication_body.cqi_raw_pdu_list = ind->cqi_indication_body.cqi_raw_pdu_list; + assert(ind->cqi_indication_body.number_of_cqis <= NFAPI_CQI_IND_MAX_PDU); + for (int i = 0; i < ind->cqi_indication_body.number_of_cqis; i++) { + nfapi_cqi_indication_pdu_t *src_pdu = &ind->cqi_indication_body.cqi_pdu_list[i]; + LOG_D(MAC, + "CQI_IND[PDU:%d][rnti:%x cqi:%d channel:%d]\n", + i, + src_pdu->rx_ue_information.rnti, + src_pdu->ul_cqi_information.ul_cqi, + src_pdu->ul_cqi_information.channel); + memcpy(&dest_ind->cqi_indication_body.cqi_pdu_list[i], src_pdu, sizeof(nfapi_cqi_indication_pdu_t)); + memcpy(&dest_ind->cqi_indication_body.cqi_raw_pdu_list[i], + &ind->cqi_indication_body.cqi_raw_pdu_list[i], + sizeof(nfapi_cqi_indication_raw_pdu_t)); + } + } + AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex) == 0, "Mutex unlock failed"); + return 1; +} + +int aerial_phy_lbt_dl_indication(struct nfapi_vnf_p7_config *config, nfapi_lbt_dl_indication_t *ind) +{ + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + // mac_lbt_dl_ind(p7_vnf->mac, ind); + return 1; +} + +int aerial_phy_nb_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_nb_harq_indication_t *ind) +{ + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + // mac_nb_harq_ind(p7_vnf->mac, ind); + return 1; +} + +int aerial_phy_nrach_indication(struct nfapi_vnf_p7_config *config, nfapi_nrach_indication_t *ind) +{ + // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data); + // mac_nrach_ind(p7_vnf->mac, ind); + return 1; +} + + +NR_Sched_Rsp_t g_sched_resp; +void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, sub_frame_t slot, NR_Sched_Rsp_t* sched_info); +int oai_fapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req); +int oai_fapi_ul_tti_req(nfapi_nr_ul_tti_request_t *ul_tti_req); +int oai_fapi_tx_data_req(nfapi_nr_tx_data_request_t* tx_data_req); +int oai_fapi_ul_dci_req(nfapi_nr_ul_dci_request_t* ul_dci_req); +int oai_fapi_send_end_request(int cell, uint32_t frame, uint32_t slot); + +int trigger_scheduler(nfapi_nr_slot_indication_scf_t *slot_ind) +{ + + NR_UL_IND_t ind = {.frame = slot_ind->sfn, .slot = slot_ind->slot, }; + NR_UL_indication(&ind); + // Call into the scheduler (this is hardcoded and should be init properly!) + // memset(sched_resp, 0, sizeof(*sched_resp)); + gNB_dlsch_ulsch_scheduler(0, slot_ind->sfn, slot_ind->slot, &g_sched_resp); + if (NFAPI_MODE == NFAPI_MODE_AERIAL) { +#ifdef ENABLE_AERIAL + bool send_slt_resp = false; + if (g_sched_resp.DL_req.dl_tti_request_body.nPDUs> 0) { + oai_fapi_dl_tti_req(&g_sched_resp.DL_req); + send_slt_resp = true; + } + if (g_sched_resp.UL_tti_req.n_pdus > 0) { + oai_fapi_ul_tti_req(&g_sched_resp.UL_tti_req); + send_slt_resp = true; + } + if (g_sched_resp.TX_req.Number_of_PDUs > 0) { + oai_fapi_tx_data_req(&g_sched_resp.TX_req); + send_slt_resp = true; + } + if (g_sched_resp.UL_dci_req.numPdus > 0) { + oai_fapi_ul_dci_req(&g_sched_resp.UL_dci_req); + send_slt_resp = true; + } + if (send_slt_resp) { + oai_fapi_send_end_request(0,slot_ind->sfn, slot_ind->slot); + } +#endif + } + + return 1; +} + + +int aerial_phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind) +{ + uint8_t vnf_slot_ahead = 0; + uint32_t vnf_sfn_slot = sfnslot_add_slot(ind->sfn, ind->slot, vnf_slot_ahead); + uint16_t vnf_sfn = NFAPI_SFNSLOT2SFN(vnf_sfn_slot); + uint8_t vnf_slot = NFAPI_SFNSLOT2SLOT(vnf_sfn_slot); + LOG_D(MAC, "VNF SFN/Slot %d.%d \n", vnf_sfn, vnf_slot); + // printf( "VNF SFN/Slot %d.%d \n", vnf_sfn, vnf_slot); + trigger_scheduler(ind); + + return 1; +} + +int aerial_phy_nr_srs_indication(nfapi_nr_srs_indication_t *ind) +{ + struct PHY_VARS_gNB_s *gNB = RC.gNB[0]; + + gNB->UL_INFO.srs_ind = *ind; + + if (ind->number_of_pdus > 0) + gNB->UL_INFO.srs_ind.pdu_list = malloc(sizeof(nfapi_nr_srs_indication_pdu_t) * ind->number_of_pdus); + + for (int i = 0; i < ind->number_of_pdus; i++) { + memcpy(&gNB->UL_INFO.srs_ind.pdu_list[i], &ind->pdu_list[i], sizeof(ind->pdu_list[0])); + + LOG_D(MAC, + "%s() NFAPI SFN/Slot:%d.%d SRS_IND:number_of_pdus:%d UL_INFO:pdus:%d\n", + __FUNCTION__, + ind->sfn, + ind->slot, + ind->number_of_pdus, + gNB->UL_INFO.srs_ind.number_of_pdus); + } + + + return 1; +} + +void *aerial_vnf_allocate(size_t size) +{ + // return (void*)memory_pool::allocate(size); + return (void *)malloc(size); +} + +void aerial_vnf_deallocate(void *ptr) +{ + // memory_pool::deallocate((uint8_t*)ptr); + free(ptr); +} + +int aerial_phy_vendor_ext(struct nfapi_vnf_p7_config *config, nfapi_p7_message_header_t *msg) +{ + if (msg->message_id == P7_VENDOR_EXT_IND) { + // vendor_ext_p7_ind* ind = (vendor_ext_p7_ind*)msg; + // NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] vendor_ext (error_code:%d)\n", ind->error_code); + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] unknown %02x\n", msg->message_id); + } + + return 0; +} + +int aerial_phy_unpack_p7_vendor_extension(nfapi_p7_message_header_t *header, + uint8_t **ppReadPackedMessage, + uint8_t *end, + nfapi_p7_codec_config_t *config) +{ + // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if (header->message_id == P7_VENDOR_EXT_IND) { + vendor_ext_p7_ind *req = (vendor_ext_p7_ind *)(header); + + if (!pull16(ppReadPackedMessage, &req->error_code, end)) + return 0; + } + + return 1; +} + +int aerial_phy_pack_p7_vendor_extension(nfapi_p7_message_header_t *header, + uint8_t **ppWritePackedMsg, + uint8_t *end, + nfapi_p7_codec_config_t *config) +{ + // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + if (header->message_id == P7_VENDOR_EXT_REQ) { + // NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__); + vendor_ext_p7_req *req = (vendor_ext_p7_req *)(header); + + if (!(push16(req->dummy1, ppWritePackedMsg, end) && push16(req->dummy2, ppWritePackedMsg, end))) + return 0; + } + + return 1; +} + +int aerial_phy_unpack_vendor_extension_tlv(nfapi_tl_t *tl, + uint8_t **ppReadPackedMessage, + uint8_t *end, + void **ve, + nfapi_p7_codec_config_t *codec) +{ + (void)tl; + (void)ppReadPackedMessage; + (void)ve; + return -1; +} + +int aerial_phy_pack_vendor_extension_tlv(void *ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *codec) +{ + // NFAPI_TRACE(NFAPI_TRACE_INFO, "phy_pack_vendor_extension_tlv\n"); + nfapi_tl_t *tlv = (nfapi_tl_t *)ve; + + switch (tlv->tag) { + case VENDOR_EXT_TLV_1_TAG: { + // NFAPI_TRACE(NFAPI_TRACE_INFO, "Packing VENDOR_EXT_TLV_1\n"); + vendor_ext_tlv_1 *ve = (vendor_ext_tlv_1 *)tlv; + + if (!push32(ve->dummy, ppWritePackedMsg, end)) + return 0; + + return 1; + } break; + + default: + return -1; + break; + } +} + +nfapi_p7_message_header_t *aerial_phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t *msg_size) +{ + if (message_id == P7_VENDOR_EXT_IND) { + *msg_size = sizeof(vendor_ext_p7_ind); + return (nfapi_p7_message_header_t *)malloc(sizeof(vendor_ext_p7_ind)); + } + + return 0; +} + +void aerial_phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t *header) +{ + free(header); +} + +uint8_t aerial_unpack_nr_slot_indication(uint8_t **ppReadPackedMsg, + uint8_t *end, + nfapi_nr_slot_indication_scf_t *msg, + nfapi_p7_codec_config_t *config) +{ + return unpack_nr_slot_indication(ppReadPackedMsg, end, msg, config); +} + +static uint8_t aerial_unpack_nr_rx_data_indication_body(nfapi_nr_rx_data_pdu_t *value, + uint8_t **ppReadPackedMsg, + uint8_t *end, + nfapi_p7_codec_config_t *config) +{ + if (!(pull32(ppReadPackedMsg, &value->handle, end) && pull16(ppReadPackedMsg, &value->rnti, end) + && pull8(ppReadPackedMsg, &value->harq_id, end) && + // For Aerial, RX_DATA.indication PDULength is changed to 32 bit field + pull32(ppReadPackedMsg, &value->pdu_length, end) && pull8(ppReadPackedMsg, &value->ul_cqi, end) + && pull16(ppReadPackedMsg, &value->timing_advance, end) && pull16(ppReadPackedMsg, &value->rssi, end))) { + return 0; + } + + // Allocate space for the pdu to be unpacked later + uint32_t length = value->pdu_length; + value->pdu = nfapi_p7_allocate(sizeof(*value->pdu) * length, config); + + return 1; +} +uint8_t aerial_unpack_nr_rx_data_indication(uint8_t **ppReadPackedMsg, + uint8_t *end, + uint8_t **pDataMsg, + uint8_t *data_end, + nfapi_nr_rx_data_indication_t *msg, + nfapi_p7_codec_config_t *config) +{ + // For Aerial unpacking, the PDU data is packed in pDataMsg, and we read it after unpacking the PDU headers + + nfapi_nr_rx_data_indication_t *pNfapiMsg = (nfapi_nr_rx_data_indication_t *)msg; + // Unpack SFN, slot, nPDU + if (!(pull16(ppReadPackedMsg, &pNfapiMsg->sfn, end) && pull16(ppReadPackedMsg, &pNfapiMsg->slot, end) + && pull16(ppReadPackedMsg, &pNfapiMsg->number_of_pdus, end))) { + return 0; + } + // Allocate the PDU list for number of PDUs + if (pNfapiMsg->number_of_pdus > 0) { + pNfapiMsg->pdu_list = nfapi_p7_allocate(sizeof(*pNfapiMsg->pdu_list) * pNfapiMsg->number_of_pdus, config); + } + // For each PDU, unpack its header + for (int i = 0; i < pNfapiMsg->number_of_pdus; i++) { + if (!aerial_unpack_nr_rx_data_indication_body(&pNfapiMsg->pdu_list[i], ppReadPackedMsg, end, config)) + return 0; + } + // After unpacking the PDU headers, unpack the PDU data from the separate buffer + for (int i = 0; i < pNfapiMsg->number_of_pdus; i++) { + if(!pullarray8(pDataMsg, + pNfapiMsg->pdu_list[i].pdu, + pNfapiMsg->pdu_list[i].pdu_length, + pNfapiMsg->pdu_list[i].pdu_length, + data_end)){ + return 0; + } + } + + return 1; +} + +uint8_t aerial_unpack_nr_crc_indication(uint8_t **ppReadPackedMsg, + uint8_t *end, + nfapi_nr_crc_indication_t *msg, + nfapi_p7_codec_config_t *config) +{ + return unpack_nr_crc_indication(ppReadPackedMsg, end, msg, config); +} + +uint8_t aerial_unpack_nr_uci_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config) +{ + return unpack_nr_uci_indication(ppReadPackedMsg, end, msg, config); +} + +uint8_t aerial_unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config) +{ + return unpack_nr_srs_indication(ppReadPackedMsg, end, msg, config); +} + +uint8_t aerial_unpack_nr_rach_indication(uint8_t **ppReadPackedMsg, + uint8_t *end, + nfapi_nr_rach_indication_t *msg, + nfapi_p7_codec_config_t *config) +{ + return unpack_nr_rach_indication(ppReadPackedMsg, end, msg, config); +} + +static int32_t aerial_pack_tx_data_request(void *pMessageBuf, + void *pPackedBuf, + void *pDataBuf, + uint32_t packedBufLen, + uint32_t dataBufLen, + nfapi_p7_codec_config_t *config, + uint32_t *data_len) +{ + nfapi_p7_message_header_t *pMessageHeader = pMessageBuf; + uint8_t *end = pPackedBuf + packedBufLen; + uint8_t *data_end = pDataBuf + dataBufLen; + uint8_t *pWritePackedMessage = pPackedBuf; + uint8_t *pDataPackedMessage = pDataBuf; + uint8_t *pPackMessageEnd = pPackedBuf + packedBufLen; + uint8_t *pPackedLengthField = &pWritePackedMessage[4]; + uint8_t *pPacketBodyField = &pWritePackedMessage[8]; + uint8_t *pPacketBodyFieldStart = &pWritePackedMessage[8]; + uint8_t *pPackedDataField = &pDataPackedMessage[0]; + uint8_t *pPackedDataFieldStart = &pDataPackedMessage[0]; + + if (pMessageBuf == NULL || pPackedBuf == NULL) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack supplied pointers are null\n"); + return -1; + } + + // PHY API message header + // Number of messages [0] + // Opaque handle [1] + // PHY API Message structure + // Message type ID [2,3] + // Message Length [4,5,6,7] + // Message Body [8,...] + if (!(push8(1, &pWritePackedMessage, pPackMessageEnd) && push8(0, &pWritePackedMessage, pPackMessageEnd) + && push16(pMessageHeader->message_id, &pWritePackedMessage, pPackMessageEnd))) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack header failed\n"); + return -1; + } + + uint8_t **ppWriteBody = &pPacketBodyField; + uint8_t **ppWriteData = &pPackedDataField; + nfapi_nr_tx_data_request_t *pNfapiMsg = (nfapi_nr_tx_data_request_t *)pMessageHeader; + + if (!(push16(pNfapiMsg->SFN, ppWriteBody, end) && push16(pNfapiMsg->Slot, ppWriteBody, end) + && push16(pNfapiMsg->Number_of_PDUs, ppWriteBody, end))) { + return 0; + } + + for (int i = 0; i < pNfapiMsg->Number_of_PDUs; i++) { + nfapi_nr_pdu_t *value = (nfapi_nr_pdu_t *)&pNfapiMsg->pdu_list[i]; + // recalculate PDU_Length for Aerial (leave only the size occupied in the payload buffer afterward) + // assuming there is only 1 TLV present + value->PDU_length = value->TLVs[0].length; + if (!(push32(value->PDU_length, ppWriteBody, end) + && // cuBB expects TX_DATA.request PDUSize to be 32 bit + push16(value->PDU_index, ppWriteBody, end) && push32(value->num_TLV, ppWriteBody, end))) { + return 0; + } + uint16_t k = 0; + uint16_t total_number_of_tlvs = value->num_TLV; + + for (; k < total_number_of_tlvs; ++k) { + // For Aerial, the TLV tag is always 2 + if (!(push16(/*value->TLVs[k].tag*/ 2, ppWriteBody, end) && push16(/*value->TLVs[k].length*/ 4, ppWriteBody, end))) { + return 0; + } + // value + if (!push32(0, ppWriteBody, end)) { + return 0; + } + } + } + + //Actual payloads are packed in a separate buffer + for (int i = 0; i < pNfapiMsg->Number_of_PDUs; i++) { + nfapi_nr_pdu_t *value = (nfapi_nr_pdu_t *)&pNfapiMsg->pdu_list[i]; + + uint16_t k = 0; + uint16_t total_number_of_tlvs = value->num_TLV; + + for (; k < total_number_of_tlvs; ++k) { + if (value->TLVs[k].length > 0) { + if (value->TLVs[k].length % 4 != 0) { + if (!pusharray32(value->TLVs[k].value.direct, 16384, ((value->TLVs[k].length + 3) / 4) - 1, ppWriteData, data_end)) { + return 0; + } + int bytesToAdd = 4 - (4 - (value->TLVs[k].length % 4)) % 4; + if (bytesToAdd != 4) { + for (int j = 0; j < bytesToAdd; j++) { + uint8_t toPush = (uint8_t)(value->TLVs[k].value.direct[((value->TLVs[k].length + 3) / 4) - 1] >> (j * 8)); + if (!push8(toPush, ppWriteData, data_end)) { + return 0; + } + } + } + } else { + // no padding needed + if (!pusharray32(value->TLVs[k].value.direct, 16384, ((value->TLVs[k].length + 3) / 4), ppWriteData, data_end)) { + return 0; + } + } + } else { + LOG_E(NR_MAC,"value->TLVs[i].length was 0! (%d.%d) \n", pNfapiMsg->SFN, pNfapiMsg->Slot); + } + } + } + + + // calculate data_len + uintptr_t dataHead = (uintptr_t)pPackedDataFieldStart; + uintptr_t dataEnd = (uintptr_t)pPackedDataField; + data_len[0] = dataEnd - dataHead; + + // check for a valid message length + uintptr_t msgHead = (uintptr_t)pPacketBodyFieldStart; + uintptr_t msgEnd = (uintptr_t)pPacketBodyField; + uint32_t packedMsgLen = msgEnd - msgHead; + uint16_t packedMsgLen16; + if (packedMsgLen > 0xFFFF || packedMsgLen > packedBufLen) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Packed message length error %d, buffer supplied %d\n", packedMsgLen, packedBufLen); + return 0; + } else { + packedMsgLen16 = (uint16_t)packedMsgLen; + } + + // Update the message length in the header + pMessageHeader->message_length = packedMsgLen16; + + // Update the message length in the header + if (!push32(packedMsgLen, &pPackedLengthField, pPackMessageEnd)) + return 0; + + if (1) { + // quick test + if (pMessageHeader->message_length != packedMsgLen) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "nfapi packedMsgLen(%d) != message_length(%d) id %d\n", + packedMsgLen, + pMessageHeader->message_length, + pMessageHeader->message_id); + } + } + + return (packedMsgLen16); +} + +int fapi_nr_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t *config) +{ + nfapi_p7_message_header_t *pMessageHeader = pMessageBuf; + uint8_t *end = pPackedBuf + packedBufLen; + uint8_t *pWritePackedMessage = pPackedBuf; + uint8_t *pPackMessageEnd = pPackedBuf + packedBufLen; + uint8_t *pPackedLengthField = &pWritePackedMessage[4]; + uint8_t *pPacketBodyField = &pWritePackedMessage[8]; + uint8_t *pPacketBodyFieldStart = &pWritePackedMessage[8]; + + if (pMessageBuf == NULL || pPackedBuf == NULL) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack supplied pointers are null\n"); + return -1; + } + + // PHY API message header + // Number of messages [0] + // Opaque handle [1] + // PHY API Message structure + // Message type ID [2,3] + // Message Length [4,5,6,7] + // Message Body [8,...] + if (!(push8(1, &pWritePackedMessage, pPackMessageEnd) && push8(0, &pWritePackedMessage, pPackMessageEnd) + && push16(pMessageHeader->message_id, &pWritePackedMessage, pPackMessageEnd))) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack header failed\n"); + return -1; + } + + // look for the specific message + uint8_t result = 0; + switch (pMessageHeader->message_id) { + case NFAPI_NR_PHY_MSG_TYPE_DL_TTI_REQUEST: + result = pack_dl_tti_request(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_UL_TTI_REQUEST: + result = pack_ul_tti_request(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST: + // TX_DATA.request already handled by aerial_pack_tx_data_request + break; + + case NFAPI_NR_PHY_MSG_TYPE_UL_DCI_REQUEST: + result = pack_ul_dci_request(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_UE_RELEASE_REQUEST: + result = pack_ue_release_request(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_UE_RELEASE_RESPONSE: + result = pack_ue_release_response(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_SLOT_INDICATION: + result = pack_nr_slot_indication(pMessageHeader, &pPacketBodyField, end, config); + + case NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION: + result = pack_nr_rx_data_indication(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION: + result = pack_nr_crc_indication(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION: + result = pack_nr_uci_indication(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_SRS_INDICATION: + result = pack_nr_srs_indication(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION: + result = pack_nr_rach_indication(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_DL_NODE_SYNC: + result = pack_nr_dl_node_sync(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_NR_PHY_MSG_TYPE_UL_NODE_SYNC: + result = pack_nr_ul_node_sync(pMessageHeader, &pPacketBodyField, end, config); + break; + + case NFAPI_TIMING_INFO: + result = pack_nr_timing_info(pMessageHeader, &pPacketBodyField, end, config); + break; + + case 0x8f: + result = pack_nr_slot_indication(pMessageHeader, &pPacketBodyField, end, config); + break; + + default: { + if (pMessageHeader->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && pMessageHeader->message_id <= NFAPI_VENDOR_EXT_MSG_MAX) { + if (config && config->pack_p7_vendor_extension) { + result = (config->pack_p7_vendor_extension)(pMessageHeader, &pPacketBodyField, end, config); + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "%s VE NFAPI message ID %d. No ve ecoder provided\n", + __FUNCTION__, + pMessageHeader->message_id); + } + } else { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s NFAPI Unknown message ID %d\n", __FUNCTION__, pMessageHeader->message_id); + } + } break; + } + + if (result == 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "P7 Pack failed to pack message\n"); + return -1; + } + + // check for a valid message length + uintptr_t msgHead = (uintptr_t)pPacketBodyFieldStart; + uintptr_t msgEnd = (uintptr_t)pPacketBodyField; + uint32_t packedMsgLen = msgEnd - msgHead; + uint16_t packedMsgLen16; + if (packedMsgLen > 0xFFFF || packedMsgLen > packedBufLen) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "Packed message length error %d, buffer supplied %d\n", packedMsgLen, packedBufLen); + return -1; + } else { + packedMsgLen16 = (uint16_t)packedMsgLen; + } + + // Update the message length in the header + pMessageHeader->message_length = packedMsgLen16; + + // Update the message length in the header + if (!push32(packedMsgLen, &pPackedLengthField, pPackMessageEnd)) + return -1; + + if (1) { + // quick test + if (pMessageHeader->message_length != packedMsgLen) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, + "nfapi packedMsgLen(%d) != message_length(%d) id %d\n", + packedMsgLen, + pMessageHeader->message_length, + pMessageHeader->message_id); + } + } + + return (packedMsgLen16); +} + +int fapi_nr_pack_and_send_p7_message(vnf_p7_t *vnf_p7, nfapi_p7_message_header_t *header) +{ + uint8_t FAPI_buffer[1024 * 64]; + // Check if TX_DATA request, if true, need to pack to data_buf + if (header->message_id + == NFAPI_NR_PHY_MSG_TYPE_TX_DATA_REQUEST) { + uint8_t FAPI_data_buffer[1024 * 64]; + uint32_t data_len = 0; + int32_t len_FAPI = aerial_pack_tx_data_request(header, + FAPI_buffer, + FAPI_data_buffer, + sizeof(FAPI_buffer), + sizeof(FAPI_data_buffer), + &vnf_p7->_public.codec_config, + &data_len); + if (len_FAPI <=0) { + LOG_E(NFAPI_VNF,"Problem packing TX_DATA_request\n"); + return len_FAPI; + } + else + return aerial_send_P7_msg_with_data(FAPI_buffer, len_FAPI, FAPI_data_buffer, data_len, header); + } else { + // Create and send FAPI P7 message + int len_FAPI = fapi_nr_p7_message_pack(header, FAPI_buffer, sizeof(FAPI_buffer), &vnf_p7->_public.codec_config); + return aerial_send_P7_msg(FAPI_buffer, len_FAPI, header); + } +} +#endif diff --git a/nfapi/oai_integration/aerial/fapi_vnf_p7.h b/nfapi/oai_integration/aerial/fapi_vnf_p7.h new file mode 100644 index 0000000000..a09ca94aa9 --- /dev/null +++ b/nfapi/oai_integration/aerial/fapi_vnf_p7.h @@ -0,0 +1,243 @@ +/* +* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The OpenAirInterface Software Alliance licenses this file to You under +* the OAI Public License, Version 1.1 (the "License"); you may not use this file +* except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.openairinterface.org/?page_id=698 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*------------------------------------------------------------------------------- +* For more information about the OpenAirInterface (OAI) Software Alliance: +* contact@openairinterface.org + */ + +/*! \file fapi/oai-integration/fapi_vnf_p7.h +* \brief Header file for fapi_vnf_p7.c +* \author Ruben S. Silva +* \date 2023 +* \version 0.1 +* \company OpenAirInterface Software Alliance +* \email: contact@openairinterface.org, rsilva@allbesmart.pt +* \note +* \warning + */ + +#ifdef ENABLE_AERIAL +#ifndef OPENAIRINTERFACE_FAPI_VNF_P7_H +#define OPENAIRINTERFACE_FAPI_VNF_P7_H + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfapi_nr_interface_scf.h" +#include "nfapi_vnf_interface.h" +#include "nfapi_vnf.h" +#include "nfapi.h" +#include "nfapi/oai_integration/vendor_ext.h" +#include "fapi_nvIPC.h" + +#include "PHY/defs_eNB.h" +#include "PHY/LTE_TRANSPORT/transport_proto.h" +#include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" +#include "lte-softmodem.h" + +#include "common/ran_context.h" +#include "openair2/PHY_INTERFACE/queue_t.h" +#include "gnb_ind_vars.h" +#include "nfapi/open-nFAPI/vnf/inc/vnf.h" +#include "nfapi/open-nFAPI/vnf/inc/vnf_p7.h" +typedef struct { + uint8_t enabled; + uint32_t rx_port; + uint32_t tx_port; + char tx_addr[80]; +} udp_data; + +typedef struct { + uint16_t index; + uint16_t id; + uint8_t rfs[2]; + uint8_t excluded_rfs[2]; + + udp_data udp; + + char local_addr[80]; + int local_port; + + char *remote_addr; + int remote_port; + + uint8_t duplex_mode; + uint16_t dl_channel_bw_support; + uint16_t ul_channel_bw_support; + uint8_t num_dl_layers_supported; + uint8_t num_ul_layers_supported; + uint16_t release_supported; + uint8_t nmm_modes_supported; + + uint8_t dl_ues_per_subframe; + uint8_t ul_ues_per_subframe; + + uint8_t first_subframe_ind; + + // timing information recevied from the vnf + uint8_t timing_window; + uint8_t timing_info_mode; + uint8_t timing_info_period; + +} phy_info; + +typedef struct { + uint16_t index; + uint16_t band; + int16_t max_transmit_power; + int16_t min_transmit_power; + uint8_t num_antennas_supported; + uint32_t min_downlink_frequency; + uint32_t max_downlink_frequency; + uint32_t max_uplink_frequency; + uint32_t min_uplink_frequency; +} rf_info; + +typedef struct { + int release; + phy_info phys[2]; + rf_info rfs[2]; + + uint8_t sync_mode; + uint8_t location_mode; + uint8_t location_coordinates[6]; + uint32_t dl_config_timing; + uint32_t ul_config_timing; + uint32_t tx_timing; + uint32_t hi_dci0_timing; + + uint16_t max_phys; + uint16_t max_total_bw; + uint16_t max_total_dl_layers; + uint16_t max_total_ul_layers; + uint8_t shared_bands; + uint8_t shared_pa; + int16_t max_total_power; + uint8_t oui; + + uint8_t wireshark_test_mode; + +} pnf_info; + +typedef struct mac mac_t; +typedef struct mac { + void *user_data; + + void (*dl_config_req)(mac_t *mac, nfapi_dl_config_request_t *req); + void (*ul_config_req)(mac_t *mac, nfapi_ul_config_request_t *req); + void (*hi_dci0_req)(mac_t *mac, nfapi_hi_dci0_request_t *req); + void (*tx_req)(mac_t *mac, nfapi_tx_request_t *req); +} mac_t; + +typedef struct { + int local_port; + char local_addr[80]; + + unsigned timing_window; + unsigned periodic_timing_enabled; + unsigned aperiodic_timing_enabled; + unsigned periodic_timing_period; + + // This is not really the right place if we have multiple PHY, + // should be part of the phy struct + udp_data udp; + + uint8_t thread_started; + + nfapi_vnf_p7_config_t *config; + + mac_t *mac; + +} vnf_p7_info; + +typedef struct { + uint8_t wireshark_test_mode; + pnf_info pnfs[2]; + vnf_p7_info p7_vnfs[2]; + +} vnf_info; + +int aerial_wake_gNB_rxtx(PHY_VARS_gNB *gNB, uint16_t sfn, uint16_t slot); +int aerial_wake_eNB_rxtx(PHY_VARS_eNB *eNB, uint16_t sfn, uint16_t sf); +int aerial_phy_sync_indication(struct nfapi_vnf_p7_config *config, uint8_t sync); +int aerial_phy_slot_indication(struct nfapi_vnf_p7_config *config, uint16_t phy_id, uint16_t sfn, uint16_t slot); +int aerial_phy_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_harq_indication_t *ind); +int aerial_phy_nr_crc_indication(nfapi_nr_crc_indication_t *ind); +int aerial_phy_nr_rx_data_indication(nfapi_nr_rx_data_indication_t *ind); +int aerial_phy_nr_rach_indication(nfapi_nr_rach_indication_t *ind); +int aerial_phy_nr_uci_indication(nfapi_nr_uci_indication_t *ind); +int aerial_phy_srs_indication(struct nfapi_vnf_p7_config *config, nfapi_srs_indication_t *ind); +int aerial_phy_sr_indication(struct nfapi_vnf_p7_config *config, nfapi_sr_indication_t *ind); +int aerial_phy_cqi_indication(struct nfapi_vnf_p7_config *config, nfapi_cqi_indication_t *ind); +int aerial_phy_lbt_dl_indication(struct nfapi_vnf_p7_config *config, nfapi_lbt_dl_indication_t *ind); +int aerial_phy_nb_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_nb_harq_indication_t *ind); +int aerial_phy_nrach_indication(struct nfapi_vnf_p7_config *config, nfapi_nrach_indication_t *ind); +int aerial_phy_nr_slot_indication(nfapi_nr_slot_indication_scf_t *ind); +int aerial_phy_nr_srs_indication(nfapi_nr_srs_indication_t *ind); +void *aerial_vnf_allocate(size_t size); +void aerial_vnf_deallocate(void *ptr); +int aerial_phy_vendor_ext(struct nfapi_vnf_p7_config *config, nfapi_p7_message_header_t *msg); +int aerial_phy_unpack_p7_vendor_extension(nfapi_p7_message_header_t *header, + uint8_t **ppReadPackedMessage, + uint8_t *end, + nfapi_p7_codec_config_t *config); +int aerial_phy_pack_p7_vendor_extension(nfapi_p7_message_header_t *header, + uint8_t **ppWritePackedMsg, + uint8_t *end, + nfapi_p7_codec_config_t *config); +int aerial_phy_unpack_vendor_extension_tlv(nfapi_tl_t *tl, + uint8_t **ppReadPackedMessage, + uint8_t *end, + void **ve, + nfapi_p7_codec_config_t *codec); +int aerial_phy_pack_vendor_extension_tlv(void *ve, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t *codec); +nfapi_p7_message_header_t *aerial_phy_allocate_p7_vendor_ext(uint16_t message_id, uint16_t *msg_size); +void aerial_phy_deallocate_p7_vendor_ext(nfapi_p7_message_header_t *header); + +uint8_t aerial_unpack_nr_slot_indication(uint8_t **ppReadPackedMsg, + uint8_t *end, + nfapi_nr_slot_indication_scf_t *msg, + nfapi_p7_codec_config_t *config); +uint8_t aerial_unpack_nr_rx_data_indication(uint8_t **ppReadPackedMsg, + uint8_t *end, + uint8_t **pDataMsg, + uint8_t *data_end, + nfapi_nr_rx_data_indication_t *msg, + nfapi_p7_codec_config_t *config); +uint8_t aerial_unpack_nr_crc_indication(uint8_t **ppReadPackedMsg, + uint8_t *end, + nfapi_nr_crc_indication_t *msg, + nfapi_p7_codec_config_t *config); +uint8_t aerial_unpack_nr_uci_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config); +uint8_t aerial_unpack_nr_srs_indication(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t *config); +uint8_t aerial_unpack_nr_rach_indication(uint8_t **ppReadPackedMsg, + uint8_t *end, + nfapi_nr_rach_indication_t *msg, + nfapi_p7_codec_config_t *config); + +// int fapi_nr_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBufLen, nfapi_p7_codec_config_t* config); +int fapi_nr_pack_and_send_p7_message(vnf_p7_t *vnf_p7, nfapi_p7_message_header_t *header); +#endif // OPENAIRINTERFACE_FAPI_VNF_P7_H +#endif diff --git a/nfapi/oai_integration/nfapi.c b/nfapi/oai_integration/nfapi.c index 5e71c5e2a4..f60e36fb06 100644 --- a/nfapi/oai_integration/nfapi.c +++ b/nfapi/oai_integration/nfapi.c @@ -27,6 +27,7 @@ static const char *const nfapi_str_mode[] = { "MONOLITHIC", "PNF", "VNF", + "AERIAL", "UE_STUB_PNF", "UE_STUB_OFFNET", "STANDALONE_PNF", @@ -64,7 +65,7 @@ const char *nfapi_get_strmode(void) { } void nfapi_logmode() { - LOG_I(ENB_APP,"nfapi running mode: %s\n",nfapi_get_strmode()); + LOG_I(ENB_APP,"nfapi (%d) running mode: %s\n",nfapi_params.nfapi_mode,nfapi_get_strmode()); } nfapi_mode_t nfapi_getmode(void) { diff --git a/nfapi/oai_integration/vendor_ext.h b/nfapi/oai_integration/vendor_ext.h index 9a377dc27d..fe9117cad0 100644 --- a/nfapi/oai_integration/vendor_ext.h +++ b/nfapi/oai_integration/vendor_ext.h @@ -68,6 +68,7 @@ typedef enum { NFAPI_MONOLITHIC=0, NFAPI_MODE_PNF, NFAPI_MODE_VNF, + NFAPI_MODE_AERIAL, NFAPI_UE_STUB_PNF, NFAPI_UE_STUB_OFFNET, NFAPI_MODE_STANDALONE_PNF, diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index a70e18af11..39674a1edf 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -328,6 +328,7 @@ typedef struct #define NFAPI_NR_CONFIG_SLOT_CONFIG_TAG 0x1027 #define NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG 0x1028 +#define NFAPI_NR_CONFIG_TDD_TABLE 0x1035 //table 3-21 typedef struct @@ -1467,11 +1468,9 @@ typedef enum { //table 3-58 #define NFAPI_NR_MAX_TX_REQUEST_TLV 2 -typedef struct { - uint16_t PDU_length; // SCF 222.10.02 The total length (in bytes) of the PDU description and PDU data, without the padding bytes. - // (2 bytes PDU_Length + 2 bytes PDU_Index + 4 bytes num_TLV + TLV size ( 2 bytes tag + 2 bytes length + - // value size without padding)) - // TBS + 12 +typedef struct +{ + uint32_t PDU_length; uint16_t PDU_index; uint32_t num_TLV; nfapi_nr_tx_data_request_tlv_t TLVs[NFAPI_NR_MAX_TX_REQUEST_TLV]; @@ -1505,7 +1504,7 @@ typedef struct uint32_t handle; uint16_t rnti; uint8_t harq_id; - uint16_t pdu_length; + uint32_t pdu_length;// For Aerial, RX_DATA.indication PDULength is changed to 32 bit field uint8_t ul_cqi; uint16_t timing_advance;//Timing advance 𝑇𝐴 measured for the UE [TS 38.213, Section 4.2] NTA_new = NTA_old + (TA − 31) ⋅ 16 ⋅ 64⁄2μ Value: 0 → 63 0xffff should be set if this field is invalid uint16_t rssi; diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi.c b/nfapi/open-nFAPI/nfapi/src/nfapi.c index 62d79bb511..b4b078cbed 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi.c @@ -102,8 +102,13 @@ uint8_t push16(uint16_t in, uint8_t **out, uint8_t *end) { uint8_t *pOut = *out; if((end - pOut) >= 2) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + pOut[1] = (in & 0xFF00) >> 8; + pOut[0] = (in & 0xFF); +#else pOut[0] = (in & 0xFF00) >> 8; pOut[1] = (in & 0xFF); +#endif (*out)+=2; return 2; } else { @@ -117,8 +122,13 @@ uint8_t pushs16(int16_t in, uint8_t **out, uint8_t *end) { uint8_t *pOut = *out; if((end - pOut) >= 2) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + pOut[1] = (in & 0xFF00) >> 8; + pOut[0] = (in & 0xFF); +#else pOut[0] = (in & 0xFF00) >> 8; pOut[1] = (in & 0xFF); +#endif (*out)+=2; return 2; } else { @@ -132,10 +142,17 @@ uint8_t push32(uint32_t in, uint8_t **out, uint8_t *end) { uint8_t *pOut = *out; if((end - pOut) >= 4) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + pOut[3] = (in & 0xFF000000) >> 24; + pOut[2] = (in & 0xFF0000) >> 16; + pOut[1] = (in & 0xFF00) >> 8; + pOut[0] = (in & 0xFF); +#else pOut[0] = (in & 0xFF000000) >> 24; pOut[1] = (in & 0xFF0000) >> 16; pOut[2] = (in & 0xFF00) >> 8; pOut[3] = (in & 0xFF); +#endif (*out)+=4; return 4; } else { @@ -149,10 +166,17 @@ uint8_t pushs32(int32_t in, uint8_t **out, uint8_t *end) { uint8_t *pOut = *out; if((end - pOut) >= 4) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + pOut[3] = (in & 0xFF000000) >> 24; + pOut[2] = (in & 0xFF0000) >> 16; + pOut[1] = (in & 0xFF00) >> 8; + pOut[0] = (in & 0xFF); +#else pOut[0] = (in & 0xFF000000) >> 24; pOut[1] = (in & 0xFF0000) >> 16; pOut[2] = (in & 0xFF00) >> 8; pOut[3] = (in & 0xFF); +#endif (*out)+=4; return 4; } else { @@ -194,7 +218,11 @@ uint8_t pull16(uint8_t **in, uint16_t *out, uint8_t *end) { uint8_t *pIn = *in; if((end - pIn) >=2 ) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + *out = ((pIn[1]) << 8) | pIn[0]; +#else *out = ((pIn[0]) << 8) | pIn[1]; +#endif (*in)+=2; return 2; } else { @@ -208,7 +236,11 @@ uint8_t pulls16(uint8_t **in, int16_t *out, uint8_t *end) { uint8_t *pIn = *in; if((end - pIn) >=2 ) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + *out = ((pIn[1]) << 8) | pIn[0]; +#else *out = ((pIn[0]) << 8) | pIn[1]; +#endif (*in)+=2; return 2; } else { @@ -222,7 +254,11 @@ uint8_t pull32(uint8_t **in, uint32_t *out, uint8_t *end) { uint8_t *pIn = *in; if((end - pIn) >= 4) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + *out = ((uint32_t)pIn[3] << 24) | (pIn[2] << 16) | (pIn[1] << 8) | pIn[0]; +#else *out = ((uint32_t)pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; +#endif (*in) += 4; return 4; } else { @@ -236,7 +272,11 @@ uint8_t pulls32(uint8_t **in, int32_t *out, uint8_t *end) { uint8_t *pIn = *in; if((end - pIn) >=4 ) { +#ifdef FAPI_BYTE_ORDERING_BIG_ENDIAN + *out = (pIn[3] << 24) | (pIn[2] << 16) | (pIn[1] << 8) | pIn[0]; +#else *out = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3]; +#endif (*in)+=4; return 4; } else { @@ -839,7 +879,6 @@ int unpack_nr_tlv_list(unpack_tlv_t unpack_fns[], } } } - return 1; } diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c index 661120d961..d1ac9fcdcb 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c @@ -35,6 +35,7 @@ #include #include "nfapi_nr_interface.h" #include "nfapi_nr_interface_scf.h" +#include "nfapi/oai_integration/vendor_ext.h" #include @@ -1670,6 +1671,16 @@ static uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uin end, &pack_uint16_tlv_value); numTLVs++; + + if (NFAPI_MODE != NFAPI_MODE_AERIAL) { + // TLV not supported by Aerial L1 + pack_nr_tlv(NFAPI_NR_CONFIG_FREQUENCY_SHIFT_7P5KHZ_TAG, + &(pNfapiMsg->carrier_config.frequency_shift_7p5khz), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; + } // END Carrier Configuration // START Cell Configuration @@ -1695,13 +1706,15 @@ static uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uin end, &pack_uint32_tlv_value); numTLVs++; - - retval &= pack_nr_tlv(NFAPI_NR_CONFIG_BCH_PAYLOAD_TAG, - &(pNfapiMsg->ssb_config.bch_payload), - ppWritePackedMsg, - end, - &pack_uint8_tlv_value); - numTLVs++; + if (NFAPI_MODE != NFAPI_MODE_AERIAL) { + // TLV not supported by Aerial L1 + retval &= pack_nr_tlv(NFAPI_NR_CONFIG_BCH_PAYLOAD_TAG, + &(pNfapiMsg->ssb_config.bch_payload), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; + } retval &= pack_nr_tlv(NFAPI_NR_CONFIG_SCS_COMMON_TAG, &(pNfapiMsg->ssb_config.scs_common), @@ -1780,6 +1793,16 @@ static uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uin end, &pack_uint16_tlv_value); numTLVs++; + for (int k = 0; k < prach_fd_occasion.num_unused_root_sequences.value; k++) { + prach_fd_occasion.unused_root_sequences_list[k].tl.tag = NFAPI_NR_CONFIG_UNUSED_ROOT_SEQUENCES_TAG; + prach_fd_occasion.unused_root_sequences_list[k].value = 0; + pack_nr_tlv(NFAPI_NR_CONFIG_UNUSED_ROOT_SEQUENCES_TAG, + &(prach_fd_occasion.unused_root_sequences_list[k]), + ppWritePackedMsg, + end, + &pack_uint16_tlv_value); + numTLVs++; + } } retval &= pack_nr_tlv(NFAPI_NR_CONFIG_SSB_PER_RACH_TAG, @@ -1788,15 +1811,25 @@ static uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uin end, &pack_uint8_tlv_value); numTLVs++; + pNfapiMsg->prach_config.prach_multiple_carriers_in_a_band.tl.tag = NFAPI_NR_CONFIG_PRACH_MULTIPLE_CARRIERS_IN_A_BAND_TAG; + pNfapiMsg->prach_config.prach_multiple_carriers_in_a_band.value = 0; + pack_nr_tlv(NFAPI_NR_CONFIG_PRACH_MULTIPLE_CARRIERS_IN_A_BAND_TAG, + &(pNfapiMsg->prach_config.prach_multiple_carriers_in_a_band), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; // END PRACH Configuration // START SSB Table - retval &= pack_nr_tlv(NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG, - &(pNfapiMsg->ssb_table.ssb_offset_point_a), - ppWritePackedMsg, - end, - &pack_uint16_tlv_value); - numTLVs++; - + if (NFAPI_MODE != NFAPI_MODE_AERIAL) { + // TLV not supported by Aerial L1 + retval &= pack_nr_tlv(NFAPI_NR_CONFIG_SSB_OFFSET_POINT_A_TAG, + &(pNfapiMsg->ssb_table.ssb_offset_point_a), + ppWritePackedMsg, + end, + &pack_uint16_tlv_value); + numTLVs++; + } retval &= pack_nr_tlv(NFAPI_NR_CONFIG_SSB_PERIOD_TAG, &(pNfapiMsg->ssb_table.ssb_period), ppWritePackedMsg, end, &pack_uint8_tlv_value); numTLVs++; @@ -1807,7 +1840,10 @@ static uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uin end, &pack_uint8_tlv_value); numTLVs++; - + /* was unused */ + pNfapiMsg->ssb_table.MIB.tl.tag = NFAPI_NR_CONFIG_MIB_TAG; + pack_nr_tlv(NFAPI_NR_CONFIG_MIB_TAG, &(pNfapiMsg->ssb_table.MIB), ppWritePackedMsg, end, &pack_uint32_tlv_value); + numTLVs++; // SCF222.10.02 Table 3-25 : If included there must be two instances of this TLV retval &= pack_nr_tlv(NFAPI_NR_CONFIG_SSB_MASK_TAG, &(pNfapiMsg->ssb_table.ssb_mask_list[0].ssb_mask), @@ -1822,26 +1858,48 @@ static uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uin end, &pack_uint32_tlv_value); numTLVs++; + if (NFAPI_MODE != NFAPI_MODE_AERIAL) { + // TLV not supported by Aerial L1 + for (int i = 0; i < 64; i++) { + // SCF222.10.02 Table 3-25 : If included there must be 64 instances of this TLV + retval &= pack_nr_tlv(NFAPI_NR_CONFIG_BEAM_ID_TAG, + &(pNfapiMsg->ssb_table.ssb_beam_id_list[i].beam_id), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; + } - for (int i = 0; i < 64; i++) { - // SCF222.10.02 Table 3-25 : If included there must be 64 instances of this TLV - retval &= pack_nr_tlv(NFAPI_NR_CONFIG_BEAM_ID_TAG, - &(pNfapiMsg->ssb_table.ssb_beam_id_list[i].beam_id), + // END SSB Table + // START TDD Table + retval &= pack_nr_tlv(NFAPI_NR_CONFIG_TDD_PERIOD_TAG, + &(pNfapiMsg->tdd_table.tdd_period), ppWritePackedMsg, end, &pack_uint8_tlv_value); numTLVs++; + // END TDD Table + for (int i = 0; i < 40; i++) { + for (int k = 0; k < 14; k++) { + pack_nr_tlv(NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, + &(pNfapiMsg->tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list[k].slot_config), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; + } + } } - - // END SSB Table - // START TDD Table - retval &= - pack_nr_tlv(NFAPI_NR_CONFIG_TDD_PERIOD_TAG, &(pNfapiMsg->tdd_table.tdd_period), ppWritePackedMsg, end, &pack_uint8_tlv_value); - numTLVs++; - // END TDD Table - // START Measurement Config // SCF222.10.02 Table 3-27 : Contains only one TLV and is currently unused + pNfapiMsg->measurement_config.rssi_measurement.tl.tag = NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG; + pNfapiMsg->measurement_config.rssi_measurement.value = 1; + pack_nr_tlv(NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, + &(pNfapiMsg->measurement_config.rssi_measurement), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; // END Measurement Config // START Digital Beam Table (DBT) PDU @@ -1851,57 +1909,57 @@ static uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uin // START Precoding Matrix (PM) PDU // Struct in nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h nfapi_nr_pm_pdu_t, currently unused, tag to use for AERIAL // is 0xA011 END Precoding Matrix (PM) PDU - - // START nFAPI TLVs included in CONFIG.request for IDLE and CONFIGURED states - retval &= pack_nr_tlv(NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, - &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), - ppWritePackedMsg, - end, - &pack_ipv4_address_value); - numTLVs++; - - retval &= pack_nr_tlv(NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, - &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), - ppWritePackedMsg, - end, - &pack_ipv6_address_value); - numTLVs++; - - retval &= pack_nr_tlv(NFAPI_NR_NFAPI_P7_VNF_PORT_TAG, - &(pNfapiMsg->nfapi_config.p7_vnf_port), - ppWritePackedMsg, - end, - &pack_uint16_tlv_value); - numTLVs++; - - retval &= pack_nr_tlv(NFAPI_NR_NFAPI_TIMING_WINDOW_TAG, - &(pNfapiMsg->nfapi_config.timing_window), - ppWritePackedMsg, - end, - &pack_uint8_tlv_value); - numTLVs++; - - retval &= pack_nr_tlv(NFAPI_NR_NFAPI_TIMING_INFO_MODE_TAG, - &(pNfapiMsg->nfapi_config.timing_info_mode), - ppWritePackedMsg, - end, - &pack_uint8_tlv_value); - numTLVs++; - - retval &= pack_nr_tlv(NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG, - &(pNfapiMsg->nfapi_config.timing_info_period), - ppWritePackedMsg, - end, - &pack_uint8_tlv_value); - numTLVs++; - // END nFAPI TLVs included in CONFIG.request for IDLE and CONFIGURED states - - if (pNfapiMsg->vendor_extension != 0 && config != 0) { - retval &= pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); - NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Packing CONFIG.request vendor_extension_tlv %d\n", pNfapiMsg->vendor_extension->tag); + if(NFAPI_MODE != NFAPI_MODE_AERIAL){ + // START nFAPI TLVs included in CONFIG.request for IDLE and CONFIGURED states + retval &= pack_nr_tlv(NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, + &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), + ppWritePackedMsg, + end, + &pack_ipv4_address_value); numTLVs++; - } + retval &= pack_nr_tlv(NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, + &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), + ppWritePackedMsg, + end, + &pack_ipv6_address_value); + numTLVs++; + + retval &= pack_nr_tlv(NFAPI_NR_NFAPI_P7_VNF_PORT_TAG, + &(pNfapiMsg->nfapi_config.p7_vnf_port), + ppWritePackedMsg, + end, + &pack_uint16_tlv_value); + numTLVs++; + + retval &= pack_nr_tlv(NFAPI_NR_NFAPI_TIMING_WINDOW_TAG, + &(pNfapiMsg->nfapi_config.timing_window), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; + + retval &= pack_nr_tlv(NFAPI_NR_NFAPI_TIMING_INFO_MODE_TAG, + &(pNfapiMsg->nfapi_config.timing_info_mode), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; + + retval &= pack_nr_tlv(NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG, + &(pNfapiMsg->nfapi_config.timing_info_period), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + numTLVs++; + // END nFAPI TLVs included in CONFIG.request for IDLE and CONFIGURED states + + if (pNfapiMsg->vendor_extension != 0 && config != 0) { + retval &= pack_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config); + NFAPI_TRACE(NFAPI_TRACE_DEBUG, "Packing CONFIG.request vendor_extension_tlv %d\n", pNfapiMsg->vendor_extension->tag); + numTLVs++; + } + } pNfapiMsg->num_tlv = numTLVs; retval &= push8(pNfapiMsg->num_tlv, &pNumTLVFields, end); return retval; @@ -2170,7 +2228,7 @@ static uint8_t pack_p5_message_body(nfapi_p4_p5_message_header_t *header, uint8_ static uint32_t get_packed_msg_len(uintptr_t msgHead, uintptr_t msgEnd) { if (msgEnd < msgHead) { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "get_packed_msg_len: Error in pointers supplied %lu, %lu\n", msgHead, msgEnd); + NFAPI_TRACE(NFAPI_TRACE_ERROR, "get_packed_msg_len: Error in pointers supplied %p, %p\n", &msgHead, &msgEnd); return 0; } @@ -2178,6 +2236,7 @@ static uint32_t get_packed_msg_len(uintptr_t msgHead, uintptr_t msgEnd) { } // Main pack function - public + int nfapi_nr_p5_message_pack(void *pMessageBuf, uint32_t messageBufLen, void *pPackedBuf, diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c index e0868f8573..e11e2a1d16 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -328,8 +328,8 @@ static uint8_t pack_dl_tti_pdsch_pdu_rel15_value(void *tlv, uint8_t **ppWritePac } // TODO Add TX power info // Hardcoded values that represent 0db - if (!(push8(8, ppWritePackedMsg, end) && // powerControlOffset - push8(1, ppWritePackedMsg, end))) { // powerControlOffsetSS + if (!(push8(0, ppWritePackedMsg, end) && // powerControlOffset + push8(0, ppWritePackedMsg, end))) { // powerControlOffsetSS return 0; } // TODO Add CBG Fields @@ -346,9 +346,8 @@ static uint8_t pack_dl_tti_ssb_pdu_rel15_value(void *tlv, uint8_t **ppWritePacke && push16(value->ssbOffsetPointA, ppWritePackedMsg, end) && push8(value->bchPayloadFlag, ppWritePackedMsg, end) && push8((value->bchPayload >> 16) & 0xff, ppWritePackedMsg, end) && push8((value->bchPayload >> 8) & 0xff, ppWritePackedMsg, end) && push8(value->bchPayload & 0xff, ppWritePackedMsg, end) - && push8(0, ppWritePackedMsg, end) && + && push8(0, ppWritePackedMsg, end) // TODO add Tx Power Info - push8(0, ppWritePackedMsg, end) && push8(0, ppWritePackedMsg, end) && push16(value->precoding_and_beamforming.num_prgs, ppWritePackedMsg, end) && push16(value->precoding_and_beamforming.prg_size, ppWritePackedMsg, end) && push8(value->precoding_and_beamforming.dig_bf_interfaces, ppWritePackedMsg, end))) { @@ -1092,7 +1091,7 @@ static uint8_t pack_ul_tti_request_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, ui } static uint8_t pack_ul_tti_request_srs_pdu(nfapi_nr_srs_pdu_t *srs_pdu, uint8_t **ppWritePackedMsg, uint8_t *end) { - return( + if(!( push16(srs_pdu->rnti, ppWritePackedMsg, end) && push32(srs_pdu->handle, ppWritePackedMsg, end) && push16(srs_pdu->bwp_size, ppWritePackedMsg, end) && @@ -1117,7 +1116,23 @@ static uint8_t pack_ul_tti_request_srs_pdu(nfapi_nr_srs_pdu_t *srs_pdu, uint8_t push16(srs_pdu->t_srs, ppWritePackedMsg, end) && push16(srs_pdu->t_offset, ppWritePackedMsg, end) // TODO: ignoring beamforming tlv for now - ); + )){ + return 0; + } + // Rx Beamforming PDU + if(!(push16(srs_pdu->beamforming.num_prgs,ppWritePackedMsg,end) && + push16(srs_pdu->beamforming.prg_size,ppWritePackedMsg,end) && + push8(srs_pdu->beamforming.dig_bf_interface,ppWritePackedMsg,end))){ + return 0; + } + for(int prg = 0; prg < srs_pdu->beamforming.num_prgs; prg ++){ + for(int digInt = 0; digInt < srs_pdu->beamforming.dig_bf_interface; digInt++){ + if(!push16(srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx,ppWritePackedMsg,end)){ + return 0; + } + } + } + return 1; } static uint8_t pack_ul_config_request_ulsch_pdu(nfapi_ul_config_ulsch_pdu *ulsch_pdu, uint8_t **ppWritePackedMsg, uint8_t *end) { @@ -2002,6 +2017,7 @@ static uint8_t pack_hi_dci0_request(void *msg, uint8_t **ppWritePackedMsg, uint8 static uint8_t pack_tx_data_pdu_list_value(void *tlv, uint8_t **ppWritePackedMsg, uint8_t *end) { nfapi_nr_pdu_t *value = (nfapi_nr_pdu_t *)tlv; + AssertFatal(value->PDU_length <= 0xFFFF,"TX_DATA.request PDU_Length should be within 16 bit, according to SCF222.10.02"); if (!(push16(value->PDU_length, ppWritePackedMsg, end) && push16(value->PDU_index, ppWritePackedMsg, end) && push32(value->num_TLV, ppWritePackedMsg, end))) return 0; @@ -3153,6 +3169,7 @@ return 1; static uint8_t pack_nr_rx_data_indication_body(nfapi_nr_rx_data_pdu_t *value, uint8_t **ppWritePackedMsg, uint8_t *end) { + AssertFatal(value->pdu_length <= 0xFFFF,"RX_DATA.indication PDU_Length should be within 16 bit, according to SCF222.10.02"); if(!(push32(value->handle, ppWritePackedMsg, end) && push16(value->rnti, ppWritePackedMsg, end) && push8(value->harq_id, ppWritePackedMsg, end) && @@ -5886,7 +5903,7 @@ static uint8_t unpack_hi_dci0_request(uint8_t **ppReadPackedMsg, uint8_t *end, v static uint8_t unpack_tx_data_pdu_list_value(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg) { nfapi_nr_pdu_t *pNfapiMsg = (nfapi_nr_pdu_t *)msg; - if(!(pull16(ppReadPackedMsg, &pNfapiMsg->PDU_length, end) && + if(!(pull16(ppReadPackedMsg, (uint16_t *)&pNfapiMsg->PDU_length, end) && pull16(ppReadPackedMsg, &pNfapiMsg->PDU_index, end) && pull32(ppReadPackedMsg, &pNfapiMsg->num_TLV, end) )) @@ -5939,13 +5956,6 @@ static uint8_t unpack_tx_data_request(uint8_t **ppReadPackedMsg, uint8_t *end, v for (int i = 0; i < pNfapiMsg->Number_of_PDUs; i++) { if (!unpack_tx_data_pdu_list_value(ppReadPackedMsg, end, &pNfapiMsg->pdu_list[i])) { - printf("%s():%d. Error packing TX_DATA.request PDU #%d, PDU length = %d PDU IDX = %d\n", - __FUNCTION__, - __LINE__, - i, - pNfapiMsg->pdu_list[i].PDU_length, - pNfapiMsg->pdu_list[i].PDU_index); - return 0; } } @@ -6065,7 +6075,7 @@ static uint8_t unpack_nr_rx_data_indication_body(nfapi_nr_rx_data_pdu_t *value, nfapi_p7_codec_config_t *config) { if (!(pull32(ppReadPackedMsg, &value->handle, end) && pull16(ppReadPackedMsg, &value->rnti, end) - && pull8(ppReadPackedMsg, &value->harq_id, end) && pull16(ppReadPackedMsg, &value->pdu_length, end) + && pull8(ppReadPackedMsg, &value->harq_id, end) && pull16(ppReadPackedMsg, (uint16_t *)&value->pdu_length, end) && pull8(ppReadPackedMsg, &value->ul_cqi, end) && pull16(ppReadPackedMsg, &value->timing_advance, end) && pull16(ppReadPackedMsg, &value->rssi, end))) return 0; diff --git a/nfapi/open-nFAPI/pnf/src/pnf.c b/nfapi/open-nFAPI/pnf/src/pnf.c index a4ff93b5e8..f16fd776d2 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf.c +++ b/nfapi/open-nFAPI/pnf/src/pnf.c @@ -2040,8 +2040,10 @@ int pnf_read_dispatch_message(pnf_t* pnf) { NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Failed to unpack p5 message header\n"); return 0; - } - message_size = header.message_length; + }else{ + NFAPI_TRACE(NFAPI_TRACE_INFO, "PNF Unpack p5 message header success\n"); + } + message_size = header.message_length+header_buffer_size; // now have the size of the mesage } @@ -2206,7 +2208,7 @@ int pnf_nr_read_dispatch_message(pnf_t* pnf) // print the received message printf("\n MESSAGE RECEIVED: \n"); for(int i=0; itx_message_buffer, sizeof(vnf->tx_message_buffer), &vnf->_public.codec_config); + int packedMessageLength = 0; + if (NFAPI_MODE == NFAPI_MODE_AERIAL) { +#ifdef ENABLE_AERIAL + // In case it is a FAPI message, create 2 messages, one with nFAPI header for OAI PNF and one with no nFAPI header for Aerial + // L1 + nfapi_p4_p5_message_header_t *msgFAPI = calloc(1, msg_len); + memcpy(msgFAPI, msg, msg_len); + // create FAPI tx_buffer + uint8_t tx_messagebufferFAPI[sizeof(vnf->tx_message_buffer)]; + int packedMessageLengthFAPI = -1; + packedMessageLengthFAPI = + fapi_nr_p5_message_pack(msgFAPI, msg_len, tx_messagebufferFAPI, sizeof(tx_messagebufferFAPI), &vnf->_public.codec_config); + return aerial_send_P5_msg(tx_messagebufferFAPI, packedMessageLengthFAPI, msg); +#else + return 0; +#endif + } else { + packedMessageLength = nfapi_nr_p5_message_pack(msg, + msg_len, + vnf->tx_message_buffer, + sizeof(vnf->tx_message_buffer), + &vnf->_public.codec_config); + + if (packedMessageLength < 0) { + NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p5_message_pack failed with return %d\n", packedMessageLength); + return -1; + } + // printf("msg id = 0x%02x, entire message length: %d\n", msg->message_id, packedMessageLength); + // for (int i = 0; i < packedMessageLength; i++) { + // printf(" msg->msg_buf[%d] = 0x%02x\n", i, ((uint8_t *) vnf->tx_message_buffer)[i]); + // } + + return vnf_send_p5_msg(pnf, vnf->tx_message_buffer, packedMessageLength, 0); + } + } else { + NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find pnf info for p5_idx:%d\n", __FUNCTION__, p5_idx); + return -1; + } - if (packedMessageLength < 0) - { - NFAPI_TRACE(NFAPI_TRACE_ERROR, "nfapi_p5_message_pack failed with return %d\n", packedMessageLength); - return -1; - } - return vnf_send_p5_msg(pnf, vnf->tx_message_buffer, packedMessageLength, 0); - } - else - { - NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() cannot find pnf info for p5_idx:%d\n", __FUNCTION__, p5_idx); - return -1; - } } diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7.c b/nfapi/open-nFAPI/vnf/src/vnf_p7.c index e4b4bef848..28c7b71656 100644 --- a/nfapi/open-nFAPI/vnf/src/vnf_p7.c +++ b/nfapi/open-nFAPI/vnf/src/vnf_p7.c @@ -25,7 +25,9 @@ #include #include #include - +#ifdef ENABLE_AERIAL +#include "nfapi/oai_integration/aerial/fapi_nvIPC.h" +#endif #include "vnf_p7.h" #ifdef NDEBUG diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 23f22a9f2a..504c5fabe0 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -29,6 +29,9 @@ * \note * \warning */ +#ifdef ENABLE_AERIAL +#include "nfapi/oai_integration/aerial/fapi_vnf_p5.h" +#endif #include "fapi_nr_l1.h" #include "common/ran_context.h" #include "PHY/NR_TRANSPORT/nr_transport_proto.h" @@ -37,7 +40,6 @@ #include "nfapi/oai_integration/vendor_ext.h" #include "openair2/NR_PHY_INTERFACE/nr_sched_response.h" - extern int oai_nfapi_dl_tti_req(nfapi_nr_dl_tti_request_t *dl_config_req); extern int oai_nfapi_tx_data_req(nfapi_nr_tx_data_request_t *tx_data_req); extern int oai_nfapi_ul_dci_req(nfapi_nr_ul_dci_request_t *ul_dci_req); @@ -237,19 +239,43 @@ void nr_schedule_response(NR_Sched_Rsp_t *Sched_INFO) } } - if (NFAPI_MODE == NFAPI_MODE_VNF) { //If VNF, oai_nfapi functions send respective p7 msgs to PNF for which nPDUs is greater than 0 + if (NFAPI_MODE == NFAPI_MODE_VNF) { // If VNF, oai_nfapi functions send respective p7 msgs to PNF for which nPDUs > 0 - if(number_ul_tti_pdu>0) + if (number_ul_tti_pdu > 0) oai_nfapi_ul_tti_req(UL_tti_req); - if (number_ul_dci_pdu>0) + if (number_ul_dci_pdu > 0) oai_nfapi_ul_dci_req(UL_dci_req); - if (number_tx_data_pdu>0) + if (number_dl_pdu > 0) + oai_nfapi_dl_tti_req(DL_req); + + if (number_tx_data_pdu > 0) oai_nfapi_tx_data_req(TX_req); - if (number_dl_pdu>0) - oai_nfapi_dl_tti_req(DL_req); + } else if (NFAPI_MODE == NFAPI_MODE_AERIAL) { +#ifdef ENABLE_AERIAL + bool send_slt_resp = false; + if (number_dl_pdu > 0) { + oai_fapi_dl_tti_req(DL_req); + send_slt_resp = true; + } + if (number_ul_tti_pdu > 0) { + oai_fapi_ul_tti_req(UL_tti_req); + send_slt_resp = true; + } + if (number_tx_data_pdu > 0) { + oai_fapi_tx_data_req(TX_req); + send_slt_resp = true; + } + if (number_ul_dci_pdu > 0) { + oai_fapi_ul_dci_req(UL_dci_req); + send_slt_resp = true; + } + if (send_slt_resp) { + oai_fapi_send_end_request(0,frame,slot); + } +#endif } /* this thread is done with the sched_info, decrease the reference counter */ diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 3b5d159d34..cc872eb73c 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -91,6 +91,9 @@ #include "RRC/NR/nr_rrc_extern.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp.h" #include "nfapi/oai_integration/vendor_ext.h" +#ifdef ENABLE_AERIAL +#include "nfapi/oai_integration/aerial/fapi_vnf_p5.h" +#endif extern uint16_t sf_ahead; @@ -1303,6 +1306,11 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) configure_nr_nfapi_vnf( RC.nrmac[j]->eth_params_s.my_addr, RC.nrmac[j]->eth_params_s.my_portc, RC.nrmac[j]->eth_params_s.remote_addr, RC.nrmac[j]->eth_params_s.remote_portd, RC.nrmac[j]->eth_params_s.my_portd); printf("**************** RETURNED FROM configure_nfapi_vnf() vnf_port:%d\n", RC.nrmac[j]->eth_params_s.my_portc); + } else if(strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr), "aerial") == 0){ +#ifdef ENABLE_AERIAL + printf("Configuring VNF for Aerial connection\n"); + aerial_configure_nr_fapi_vnf(); +#endif } else { // other midhaul AssertFatal(1 == 0, "MACRLC %d: %s unknown southbound midhaul\n", j, *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr)); } diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 9abb5ab748..34763011f4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -708,6 +708,12 @@ static void config_common(gNB_MAC_INST *nrmac, nr_pdsch_AntennaPorts_t pdsch_Ant cfg->ssb_table.ssb_subcarrier_offset.tl.tag = NFAPI_NR_CONFIG_SSB_SUBCARRIER_OFFSET_TAG; cfg->num_tlv++; + uint8_t *mib_payload = nrmac->common_channels[0].MIB_pdu; + uint32_t mib = (mib_payload[2] << 16) | (mib_payload[1] << 8) | mib_payload[0]; + cfg->ssb_table.MIB.tl.tag = NFAPI_NR_CONFIG_MIB_TAG; + cfg->ssb_table.MIB.value = mib; + cfg->num_tlv++; + nrmac->ssb_SubcarrierOffset = cfg->ssb_table.ssb_subcarrier_offset.value; nrmac->ssb_OffsetPointA = cfg->ssb_table.ssb_offset_point_a.value; LOG_I(NR_MAC, @@ -837,11 +843,8 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c config_common(nrmac, config->pdsch_AntennaPorts, config->pusch_AntennaPorts, scc); - if (NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MODE_VNF) { - // fake that the gNB is configured in nFAPI mode, which would normally be - // done in a NR_PHY_config_req, but in this mode, there is no PHY - RC.gNB[0]->configured = 1; - } else { + if (NFAPI_MODE == NFAPI_MONOLITHIC) { + // nothing to be sent in the other cases NR_PHY_Config_t phycfg = {.Mod_id = 0, .CC_id = 0, .cfg = &nrmac->config[0]}; DevAssert(nrmac->if_inst->NR_PHY_config_req); nrmac->if_inst->NR_PHY_config_req(&phycfg); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index 98e642279c..af8b077dea 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -91,6 +91,53 @@ void clear_nr_nfapi_information(gNB_MAC_INST *gNB, future_ul_tti_req->SFN = (prev_slot / num_slots) % 1024; LOG_D(NR_MAC, "%d.%d UL_tti_req_ahead SFN.slot = %d.%d for index %d \n", frameP, slotP, future_ul_tti_req->SFN, future_ul_tti_req->Slot, prev_slot % size); /* future_ul_tti_req->Slot is fixed! */ + for (int i = 0; i < future_ul_tti_req->n_pdus; i++) { + switch(future_ul_tti_req->pdus_list[i].pdu_type){ + case NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE: + if(future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.prgs_list){ + for (int j = 0; j < future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.num_prgs; ++j) { + if(future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.prgs_list[j].dig_bf_interface_list){ + free(future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.prgs_list[j].dig_bf_interface_list); + } + } + free(future_ul_tti_req->pdus_list[i].prach_pdu.beamforming.prgs_list); + } + break; + case NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE: + if(future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.prgs_list){ + for (int j = 0; j < future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.num_prgs; ++j) { + if(future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.prgs_list[j].dig_bf_interface_list){ + free(future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.prgs_list[j].dig_bf_interface_list); + } + } + free(future_ul_tti_req->pdus_list[i].pusch_pdu.beamforming.prgs_list); + } + break; + case NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE: + if(future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.prgs_list){ + for (int j = 0; j < future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.num_prgs; ++j) { + if(future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.prgs_list[j].dig_bf_interface_list){ + free(future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.prgs_list[j].dig_bf_interface_list); + } + } + free(future_ul_tti_req->pdus_list[i].pucch_pdu.beamforming.prgs_list); + } + break; + case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: + if(future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.prgs_list){ + for (int j = 0; j < future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.num_prgs; ++j) { + if(future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.prgs_list[j].dig_bf_interface_list){ + free(future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.prgs_list[j].dig_bf_interface_list); + } + } + free(future_ul_tti_req->pdus_list[i].srs_pdu.beamforming.prgs_list); + } + default: + break; + } + future_ul_tti_req->pdus_list[i].pdu_type = 0; + future_ul_tti_req->pdus_list[i].pdu_size = 0; + } future_ul_tti_req->n_pdus = 0; future_ul_tti_req->n_ulsch = 0; future_ul_tti_req->n_ulcch = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 161598ec2d..e110f531ac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -317,6 +317,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, sub_frame_t slotP UL_tti_req->SFN = frameP; UL_tti_req->Slot = slotP; + UL_tti_req->rach_present = 1; for (int fdm_index=0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion for (int td_index=0; td_index 0) { // Aerial needs slot_ahead = 0, requiring addition of another TDD period + eff_slot += tdd_period_slot; + } +#endif int FR = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0] >= 257 ? nr_FR2 : nr_FR1; if (FR==nr_FR2) { int num_tdd_period = (eff_slot%nr_slots_per_frame[mu])/tdd_period_slot; @@ -1052,10 +1057,12 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, LOG_D(NR_MAC, "MSG3 start_sym:%d NR Symb:%d mappingtype:%d, ul_dmrs_symb_pos:%x\n", start_symbol_index, nr_of_symbols, mappingtype, pusch_pdu->ul_dmrs_symb_pos); pusch_pdu->dmrs_config_type = 0; pusch_pdu->ul_dmrs_scrambling_id = *scc->physCellId; //If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id. + pusch_pdu->pusch_identity = *scc->physCellId; //If provided and the PUSCH is not a msg3 PUSCH, otherwise, L2 should set this to physical cell id. pusch_pdu->scid = 0; //DMRS sequence initialization [TS38.211, sec 6.4.1.1.1]. Should match what is sent in DCI 0_1, otherwise set to 0. pusch_pdu->dmrs_ports = 1; // 6.2.2 in 38.214 only port 0 to be used pusch_pdu->num_dmrs_cdm_grps_no_data = 2; // no data in dmrs symbols as in 6.2.2 in 38.214 pusch_pdu->resource_alloc = 1; //type 1 + memset(pusch_pdu->rb_bitmap, 0, sizeof(pusch_pdu->rb_bitmap)); pusch_pdu->rb_start = msg3_first_rb; if (msg3_nb_rb > pusch_pdu->bwp_size) AssertFatal(1==0,"MSG3 allocated number of RBs exceed the BWP size\n"); @@ -1077,6 +1084,23 @@ static void fill_msg3_pusch_pdu(nfapi_nr_pusch_pdu_t *pusch_pdu, pusch_pdu->pusch_data.harq_process_id = 0; pusch_pdu->pusch_data.new_data_indicator = (round == 0) ? 1 : 0;; pusch_pdu->pusch_data.num_cb = 0; + + // Beamforming + pusch_pdu->beamforming.num_prgs = 0; + pusch_pdu->beamforming.prg_size = 0; // bwp_size; + pusch_pdu->beamforming.dig_bf_interface = 0; + if (pusch_pdu->beamforming.num_prgs > 0) { + if (pusch_pdu->beamforming.prgs_list == NULL) { + pusch_pdu->beamforming.prgs_list = calloc(pusch_pdu->beamforming.num_prgs, sizeof(*pusch_pdu->beamforming.prgs_list)); + } + if (pusch_pdu->beamforming.dig_bf_interface > 0) { + if (pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list == NULL) { + pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list = + calloc(pusch_pdu->beamforming.dig_bf_interface, sizeof(*pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list)); + } + } + pusch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = 0; + } int num_dmrs_symb = 0; for(int i = start_symbol_index; i < start_symbol_index+nr_of_symbols; i++) num_dmrs_symb += (pusch_pdu->ul_dmrs_symb_pos >> i) & 1; @@ -1279,6 +1303,12 @@ static void nr_generate_Msg2(module_id_t module_idP, dl_req->nPDUs+=1; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; + pdsch_pdu_rel15->precodingAndBeamforming.num_prgs = 0; + pdsch_pdu_rel15->precodingAndBeamforming.prg_size = 0; + pdsch_pdu_rel15->precodingAndBeamforming.dig_bf_interfaces = 0; + pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].pm_idx = 0; + pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = 0; + LOG_A(NR_MAC,"[gNB %d][RAPROC] CC_id %d Frame %d, slotP %d: Generating RA-Msg2 DCI, rnti 0x%x, state %d, CoreSetType %d\n", module_idP, CC_id, frameP, slotP, ra->RA_rnti, ra->state,pdcch_pdu_rel15->CoreSetType); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 9a554dc0bb..22a2b034e6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -426,6 +426,12 @@ static void nr_fill_nfapi_dl_sib1_pdu(int Mod_idP, dl_req->nPDUs += 1; nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_pdu_rel15 = &dl_tti_pdsch_pdu->pdsch_pdu.pdsch_pdu_rel15; + pdsch_pdu_rel15->precodingAndBeamforming.num_prgs=0; + pdsch_pdu_rel15->precodingAndBeamforming.prg_size=0; + pdsch_pdu_rel15->precodingAndBeamforming.dig_bf_interfaces=0; + pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].pm_idx = 0; + pdsch_pdu_rel15->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = 0; + pdcch_pdu_rel15->CoreSetType = NFAPI_NR_CSET_CONFIG_MIB_SIB1; pdsch_pdu_rel15->pduBitmap = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 97c42c57f0..e8c0a33c3b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -1066,6 +1066,10 @@ void nr_schedule_ue_spec(module_id_t module_id, pdsch_pdu->qamModOrder[0] = Qm; pdsch_pdu->mcsIndex[0] = sched_pdsch->mcs; pdsch_pdu->mcsTable[0] = current_BWP->mcsTableIdx; + // NVIDIA: Workaround for MCSTableIdx mismatch error + if (nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx) != R) { + pdsch_pdu->mcsTable[0] = 0; + } AssertFatal(harq!=NULL,"harq is null\n"); AssertFatal(harq->rounddl_bler.harq_round_max,"%d",harq->round); pdsch_pdu->rvIndex[0] = nr_rv_round_map[harq->round%4]; @@ -1090,8 +1094,11 @@ void nr_schedule_ue_spec(module_id_t module_id, pdsch_pdu->StartSymbolIndex = tda_info->startSymbolIndex; pdsch_pdu->NrOfSymbols = tda_info->nrOfSymbols; // Precoding + pdsch_pdu->precodingAndBeamforming.num_prgs = 0; pdsch_pdu->precodingAndBeamforming.prg_size = pdsch_pdu->rbSize; + pdsch_pdu->precodingAndBeamforming.dig_bf_interfaces = 0; pdsch_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = sched_pdsch->pm_index; + pdsch_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = 0; // TBS_LBRM according to section 5.4.2.1 of 38.212 // TODO: verify the case where maxMIMO_Layers is NULL, in which case // in principle maxMIMO_layers should be given by the maximum number of layers @@ -1146,6 +1153,13 @@ void nr_schedule_ue_spec(module_id_t module_id, dci_pdu->CceIndex = sched_ctrl->cce_index; dci_pdu->beta_PDCCH_1_0 = 0; dci_pdu->powerControlOffsetSS = 1; + + dci_pdu->precodingAndBeamforming.num_prgs = 0; + dci_pdu->precodingAndBeamforming.prg_size = 0; + dci_pdu->precodingAndBeamforming.dig_bf_interfaces = 0; + dci_pdu->precodingAndBeamforming.prgs_list[0].pm_idx = 0; + dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = 0; + /* DCI payload */ dci_pdu_rel15_t dci_payload; memset(&dci_payload, 0, sizeof(dci_pdu_rel15_t)); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 9199327501..2ebfa874db 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -57,6 +57,7 @@ #define DEBUG_gNB_SCHEDULER 1 #include "common/ran_context.h" +#include "nfapi/oai_integration/vendor_ext.h" //#define DEBUG_DCI @@ -227,13 +228,23 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc, switch (Layers) { case 1: +#ifdef ENABLE_AERIAL + dmrs.dmrs_ports_id = 3; + dmrs.numDmrsCdmGrpsNoData = 2; +#else dmrs.dmrs_ports_id = 0; dmrs.numDmrsCdmGrpsNoData = 1; +#endif frontloaded_symb = 1; break; case 2: +#ifdef ENABLE_AERIAL + dmrs.dmrs_ports_id = 7; + dmrs.numDmrsCdmGrpsNoData = 2; +#else dmrs.dmrs_ports_id = 2; dmrs.numDmrsCdmGrpsNoData = 1; +#endif frontloaded_symb = 1; break; case 3: @@ -606,10 +617,14 @@ NR_pusch_dmrs_t get_ul_dmrs_params(const NR_ServingCellConfigCommon_t *scc, NR_pusch_dmrs_t dmrs = {0}; // TODO setting of cdm groups with no data to be redone for MIMO - if (ul_bwp->transform_precoding && Layers < 3) - dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols == 2 ? 1 : 2; - else + if(NFAPI_MODE == NFAPI_MODE_AERIAL) { dmrs.num_dmrs_cdm_grps_no_data = 2; + } else { + if (ul_bwp->transform_precoding && Layers < 3) + dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols == 2 ? 1 : 2; + else + dmrs.num_dmrs_cdm_grps_no_data = 2; + } NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = ul_bwp->pusch_Config ? (tda_info->mapping_type == typeA ? @@ -738,7 +753,8 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info, // antenna_ports.val = 0 for transform precoder is disabled, dmrs-Type=1, maxLength=1, Rank=1/2/3/4 // Antenna Ports - dci_pdu_rel15->antenna_ports.val = 0; + + dci_pdu_rel15->antenna_ports.val = NFAPI_MODE == NFAPI_MODE_AERIAL ? 2 : 0; // DMRS sequence initialization dci_pdu_rel15->dmrs_sequence_initialization.val = pusch_pdu->scid; @@ -1031,6 +1047,22 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, pucch_pdu->sr_flag = O_sr; pucch_pdu->prb_size=1; } + // Beamforming + pucch_pdu->beamforming.num_prgs = 0; + pucch_pdu->beamforming.prg_size = 0; // pucch_pdu->prb_size; + pucch_pdu->beamforming.dig_bf_interface = 0; + if (pucch_pdu->beamforming.num_prgs > 0) { + if (pucch_pdu->beamforming.prgs_list == NULL) { + pucch_pdu->beamforming.prgs_list = calloc(pucch_pdu->beamforming.num_prgs, sizeof(*pucch_pdu->beamforming.prgs_list)); + } + if (pucch_pdu->beamforming.dig_bf_interface > 0) { + if (pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list == NULL) { + pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list = + calloc(pucch_pdu->beamforming.dig_bf_interface, sizeof(*pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list)); + } + } + pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = 0; + } } void set_r_pucch_parms(int rsetindex, @@ -2580,9 +2612,9 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti) delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator); } -uint8_t nr_get_tpc(int target, uint8_t cqi, int incr) { - // al values passed to this function are x10 - int snrx10 = (cqi*5) - 640; +uint8_t nr_get_tpc(int target, int snrx10, int incr) +{ + // all values passed to this function are in dB x10 if (snrx10 > target + incr) return 0; // decrease 1dB if (snrx10 < target - (3*incr)) return 3; // increase 3dB if (snrx10 < target - incr) return 2; // increase 1dB diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index aef5b11340..e949d84dca 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -1042,11 +1042,11 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, } // tpc (power control) only if we received AckNack - if (uci_01->harq.harq_confidence_level==0) - sched_ctrl->tpc1 = nr_get_tpc(nrmac->pucch_target_snrx10, uci_01->ul_cqi, 30); - else - sched_ctrl->tpc1 = 3; - sched_ctrl->pucch_snrx10 = uci_01->ul_cqi * 5 - 640; + if (uci_01->harq.harq_confidence_level == 0 && uci_01->ul_cqi != 0xff) { + sched_ctrl->pucch_snrx10 = uci_01->ul_cqi * 5 - 640; + sched_ctrl->tpc1 = nr_get_tpc(nrmac->pucch_target_snrx10, sched_ctrl->pucch_snrx10, 30); + } else + sched_ctrl->tpc1 = 1; } // check scheduling request result, confidence_level == 0 is good @@ -1085,10 +1085,10 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, // tpc (power control) // TODO PUCCH2 SNR computation is not correct -> ignore the following - //sched_ctrl->tpc1 = nr_get_tpc(RC.nrmac[mod_id]->pucch_target_snrx10, - // uci_234->ul_cqi, - // 30); - //sched_ctrl->pucch_snrx10 = uci_234->ul_cqi * 5 - 640; + if (uci_234->ul_cqi != 0xff) { + sched_ctrl->pucch_snrx10 = uci_234->ul_cqi * 5 - 640; + sched_ctrl->tpc1 = nr_get_tpc(nrmac->pucch_target_snrx10, sched_ctrl->pucch_snrx10, 30); + } // TODO: handle SR if (uci_234->pduBitmap & 0x1) { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index b3aadd816d..4eb43081b2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -625,11 +625,13 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, // if not missed detection (10dB threshold for now) if (rssi>0) { - UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10,ul_cqi,30); + if (ul_cqi != 0xff) { + UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640; + UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, UE_scheduling_control->pusch_snrx10, 30); + } if (timing_advance != 0xffff) UE_scheduling_control->ta_update = timing_advance; UE_scheduling_control->raw_rssi = rssi; - UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640; LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n",UE->rnti,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update); } @@ -670,7 +672,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, if (UE_scheduling_control->sched_ul_bytes < 0) UE_scheduling_control->sched_ul_bytes = 0; } - if (ul_cqi <= 128) { + if (ul_cqi == 0xff || ul_cqi <= 128) { UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt++; UE->mac_stats.ulsch_DTX++; } @@ -756,7 +758,10 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP, NR_UE_sched_ctrl_t *UE_scheduling_control = &UE_msg3_stage->UE_sched_ctrl; - UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30); + if (ul_cqi != 0xff) { + UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640; + UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, UE_scheduling_control->pusch_snrx10, 30); + } if (timing_advance != 0xffff) UE_scheduling_control->ta_update = timing_advance; UE_scheduling_control->raw_rssi = rssi; @@ -2245,11 +2250,15 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, n pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data; /* FAPI: DMRS */ + pusch_pdu->num_dmrs_cdm_grps_no_data = sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data; + pusch_pdu->dmrs_ports = ((1<nrOfLayers) - 1); pusch_pdu->ul_dmrs_symb_pos = sched_pusch->dmrs_info.ul_dmrs_symb_pos; pusch_pdu->dmrs_config_type = sched_pusch->dmrs_info.dmrs_config_type; + pusch_pdu->scid = 0; // DMRS sequence initialization [TS38.211, sec 6.4.1.1.1] const NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = get_DMRS_UplinkConfig(current_BWP->pusch_Config, &sched_pusch->tda_info); if (pusch_pdu->transform_precoding) { // transform precoding disabled long *scramblingid=NULL; + pusch_pdu->pusch_identity = *scc->physCellId; if (NR_DMRS_UplinkConfig && pusch_pdu->scid == 0) scramblingid = NR_DMRS_UplinkConfig->transformPrecodingDisabled->scramblingID0; else if (NR_DMRS_UplinkConfig) @@ -2356,7 +2365,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, sub_frame_t slot, n nfapi_nr_ul_dci_request_pdus_t *ul_dci_request_pdu = &ul_dci_req->ul_dci_pdu_list[ul_dci_req->numPdus]; memset(ul_dci_request_pdu, 0, sizeof(nfapi_nr_ul_dci_request_pdus_t)); ul_dci_request_pdu->PDUType = NFAPI_NR_DL_TTI_PDCCH_PDU_TYPE; - ul_dci_request_pdu->PDUSize = (uint8_t)(2+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); + ul_dci_request_pdu->PDUSize = (uint8_t)(4+sizeof(nfapi_nr_dl_tti_pdcch_pdu)); pdcch_pdu = &ul_dci_request_pdu->pdcch_pdu.pdcch_pdu_rel15; ul_dci_req->numPdus += 1; nr_configure_pdcch(pdcch_pdu, coreset, &sched_ctrl->sched_pdcch); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 61ce2c49f9..5f19d60458 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -272,7 +272,7 @@ NR_pusch_dmrs_t get_ul_dmrs_params(const NR_ServingCellConfigCommon_t *scc, const NR_tda_info_t *tda_info, const int Layers); -uint8_t nr_get_tpc(int target, uint8_t cqi, int incr); +uint8_t nr_get_tpc(int target, int snrx10, int incr); int get_spf(nfapi_nr_config_request_scf_t *cfg); diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c index 37bedddf46..57d7c05b2b 100644 --- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c @@ -202,12 +202,12 @@ void handle_nr_ulsch(NR_UL_IND_t *UL_info) UL_info->CC_id, UL_info->rx_ind.sfn, UL_info->rx_ind.slot, - rx->rnti, + crc->rnti, crc->tb_crc_status ? NULL : rx->pdu, rx->pdu_length, - rx->timing_advance, - rx->ul_cqi, - rx->rssi); + crc->timing_advance, + crc->ul_cqi, + crc->rssi); handle_nr_ul_harq(UL_info->CC_id, UL_info->module_id, UL_info->frame, UL_info->slot, crc); } } @@ -440,7 +440,7 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) { nfapi_nr_uci_indication_t *uci_ind = NULL; nfapi_nr_rx_data_indication_t *rx_ind = NULL; nfapi_nr_crc_indication_t *crc_ind = NULL; - if (get_softmodem_params()->emulate_l1) + if (get_softmodem_params()->emulate_l1 || NFAPI_MODE == NFAPI_MODE_AERIAL) { if (gnb_rach_ind_queue.num_items > 0) { LOG_D(NR_MAC, "gnb_rach_ind_queue size = %zu\n", gnb_rach_ind_queue.num_items); @@ -483,7 +483,7 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) { handle_nr_ulsch(UL_info); handle_nr_srs(UL_info); - if (get_softmodem_params()->emulate_l1) { + if (get_softmodem_params()->emulate_l1 || NFAPI_MODE == NFAPI_MODE_AERIAL) { free_unqueued_nfapi_indications(rach_ind, uci_ind, rx_ind, crc_ind); } } diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c index 68d390f097..f7af67ba8b 100644 --- a/openair2/PHY_INTERFACE/IF_Module.c +++ b/openair2/PHY_INTERFACE/IF_Module.c @@ -26,7 +26,7 @@ void handle_rach(UL_IND_t *UL_info) { int i; int j = UL_info->subframe; AssertFatal(j < sizeof(UL_RCC_INFO.rach_ind) / sizeof(UL_RCC_INFO.rach_ind[0]), "j index out of range of index of rach_ind\n"); - if (NFAPI_MODE == NFAPI_MODE_VNF) + if (NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { if (UL_RCC_INFO.rach_ind[j].rach_indication_body.number_of_preambles > 0) { @@ -97,7 +97,7 @@ void handle_sr(UL_IND_t *UL_info) { if (UL_info->sr_ind.sr_indication_body.number_of_srs>0) { oai_nfapi_sr_indication(&UL_info->sr_ind); } - } else if(NFAPI_MODE == NFAPI_MODE_VNF) { + } else if(NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { for(uint8_t j = 0; j < NUM_NFAPI_SUBFRAME; j++) { if(UL_RCC_INFO.sr_ind[j].sr_indication_body.number_of_srs > 0) { assert(UL_RCC_INFO.sr_ind[j].sr_indication_body.number_of_srs <= NFAPI_SR_IND_MAX_PDU); @@ -140,7 +140,7 @@ void handle_cqi(UL_IND_t *UL_info) { oai_nfapi_cqi_indication(&UL_info->cqi_ind); UL_info->cqi_ind.cqi_indication_body.number_of_cqis=0; } - } else if (NFAPI_MODE == NFAPI_MODE_VNF) { + } else if (NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { for(uint8_t j = 0; j < NUM_NFAPI_SUBFRAME; j++) { if(UL_RCC_INFO.cqi_ind[j].cqi_indication_body.number_of_cqis > 0) { assert(UL_RCC_INFO.cqi_ind[j].cqi_indication_body.number_of_cqis <= NFAPI_CQI_IND_MAX_PDU); @@ -187,7 +187,7 @@ void handle_harq(UL_IND_t *UL_info) { } UL_info->harq_ind.harq_indication_body.number_of_harqs = 0; - } else if(NFAPI_MODE == NFAPI_MODE_VNF) { + } else if(NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { for(uint8_t j = 0; j < NUM_NFAPI_SUBFRAME; j++) { if(UL_RCC_INFO.harq_ind[j].harq_indication_body.number_of_harqs > 0) { assert(UL_RCC_INFO.harq_ind[j].harq_indication_body.number_of_harqs <= NFAPI_HARQ_IND_MAX_PDU); @@ -232,7 +232,7 @@ void handle_ulsch(UL_IND_t *UL_info) { oai_nfapi_rx_ind(&UL_info->rx_ind); UL_info->rx_ind.rx_indication_body.number_of_pdus = 0; } - } else if(NFAPI_MODE == NFAPI_MODE_VNF) { + } else if(NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL) { for(uint8_t k = 0; k < NUM_NFAPI_SUBFRAME; k++) { if((UL_RCC_INFO.rx_ind[k].rx_indication_body.number_of_pdus>0) && (UL_RCC_INFO.crc_ind[k].crc_indication_body.number_of_crcs>0)) { assert(UL_RCC_INFO.rx_ind[k].rx_indication_body.number_of_pdus <= NFAPI_RX_IND_MAX_PDU); diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.aerial.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.aerial.conf new file mode 100644 index 0000000000..149aaedb4c --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-vnf.sa.band78.273prb.aerial.conf @@ -0,0 +1,262 @@ +Active_gNBs = ( "gNB-OAI"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +sa = 1; +nfapi = "AERIAL"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + gNB_name = "gNB-OAI"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + plmn_list = ({ + mcc = 001; + mnc = 01; + mnc_length = 2; + snssaiList = ( + { + sst = 1; + } + ); + }); + + nr_cellid = 12345678L; + + ////////// Physical parameters: + + pdsch_AntennaPorts_XP = 2; + pusch_AntennaPorts = 2; + do_CSIRS = 1; + do_SRS = 0; + min_rxtxtime = 2; + + pdcch_ConfigSIB1 = ( + { + controlResourceSetZero = 12; + searchSpaceZero = 0; + } + ); + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3300.24 + 134*12*30e3 = 3348.48 MHz (5G NR GSCN: 7741) + absoluteFrequencySSB = 649920; + #652860; #should be 649920 +#647520; +#647540; +#649920; +#650208; +#647540; + dl_frequencyBand = 78; + # this is 3300.24 MHz + dl_absoluteFrequencyPointA = 646724; +#649104; +#646724; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 273; + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=162 (275*(275-L+1))+(274-RBstart)) + initialDLBWPlocationAndBandwidth = 1099; + # +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 12; + initialDLBWPsearchSpaceZero = 0; + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 273; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 1099; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 159;# testMAC 158; OAI gNB 98 +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + preambleReceivedTargetPower = -96; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 3; +#oneHalf (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant = -90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; +# ssb_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 = 5; #6; + nrofDownlinkSlots = 3; #7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 1; #2; + nrofUplinkSymbols = 0; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + + ////////// AMF parameters: + amf_ip_address = ( { ipv4 = "192.168.70.132"; + ipv6 = "192:168:30::17"; + active = "yes"; + preference = "ipv4"; + } + ); + + + NETWORK_INTERFACES : + { + GNB_INTERFACE_NAME_FOR_NG_AMF = "demo-oai"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129"; + GNB_INTERFACE_NAME_FOR_NGU = "demo-oai"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( +{ + num_cc = 1; + local_s_if_name = "lo:"; + remote_s_address = "127.0.0.1"; // pnf addr [!] + local_s_address = "127.0.0.2"; // vnf addr + local_s_portc = 50001; // vnf p5 port + remote_s_portc = 50000; // pnf p5 port [!] + local_s_portd = 50011; // vnf p7 port [!] + remote_s_portd = 50010; // pnf p7 port [!] + tr_s_preference = "aerial"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 200; #150; + pucch_TargetSNRx10 = 200; #200; + ulsch_max_frame_inactivity = 10; + dl_max_mcs = 28; + ul_max_mcs = 28; +} +); + + +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"; +};