From c8637590cba875e3318bf57e3686605d6efeaa36 Mon Sep 17 00:00:00 2001 From: Mcu_sdk Ci Date: Fri, 12 Jan 2024 13:49:03 +0100 Subject: [PATCH] Apply v5.1.1 release update --- LICENSE | 2 +- README.md | 2 +- doxygen/Doxyfile.rpmsglite | 2 +- .../environment/bm/rpmsg_env_specific.h | 4 +- .../environment/freertos/rpmsg_env_specific.h | 2 - .../environment/qnx/rpmsg_env_specific.h | 4 +- .../environment/threadx/rpmsg_env_specific.h | 2 - .../environment/xos/rpmsg_env_specific.h | 2 - .../environment/zephyr/rpmsg_env_specific.h | 15 +- .../platform/imx8mp_m7/rpmsg_platform.h | 4 +- .../imx8ulp_fusionf1/rpmsg_platform.h | 107 ++ .../platform/imx8ulp_m33/rpmsg_platform.h | 115 ++ .../imxrt500_fusionf1/rpmsg_platform.h | 4 +- .../platform/imxrt500_m33/rpmsg_platform.h | 4 +- .../platform/imxrt600_hifi4/rpmsg_platform.h | 4 +- .../platform/imxrt600_m33/rpmsg_platform.h | 4 +- .../platform/lpc55s69/rpmsg_platform.h | 4 +- lib/include/rpmsg_lite.h | 2 +- .../porting/environment/rpmsg_env_freertos.c | 33 +- .../porting/environment/rpmsg_env_threadx.c | 6 +- .../porting/environment/rpmsg_env_zephyr.c | 11 +- .../platform/imx8mm_m4/rpmsg_platform.c | 4 +- .../platform/imx8mn_m7/rpmsg_platform.c | 4 +- .../platform/imx8mp_m7/rpmsg_platform.c | 4 +- .../platform/imx8mq_m4/rpmsg_platform.c | 4 +- .../platform/imx8qm_m4/rpmsg_platform.c | 4 +- .../platform/imx8qx_cm4/rpmsg_platform.c | 4 +- .../imx8ulp_fusionf1/rpmsg_platform.c | 353 ++++++ .../platform/imx8ulp_m33/rpmsg_platform.c | 503 ++++++++ .../platform/imxrt1160/rpmsg_platform.c | 4 +- .../imxrt1160/rpmsg_platform_zephyr_ipm.c | 257 ++++ .../platform/imxrt1170/rpmsg_platform.c | 4 +- .../imxrt1170/rpmsg_platform_zephyr_ipm.c | 257 ++++ .../imxrt500_fusionf1/rpmsg_platform.c | 4 +- .../platform/imxrt500_m33/rpmsg_platform.c | 4 +- .../platform/imxrt600_hifi4/rpmsg_platform.c | 4 +- .../platform/imxrt600_m33/rpmsg_platform.c | 4 +- .../porting/platform/k32l3a6/rpmsg_platform.c | 4 +- .../lpc5411x/rpmsg_platform_zephyr_ipm.c | 9 +- .../platform/lpc55s69/rpmsg_platform.c | 4 +- .../lpc55s69/rpmsg_platform_zephyr_ipm.c | 257 ++++ tests/01_rpmsg_init/main_core0.c | 199 +++ tests/01_rpmsg_init/main_core1.c | 180 +++ tests/01_rpmsg_init/readme.txt | 7 + tests/01_rpmsg_init_rtos/main_core0.c | 223 ++++ tests/01_rpmsg_init_rtos/main_core1.c | 205 +++ .../main_static_alloc_core0.c | 215 ++++ .../main_static_alloc_core1.c | 198 +++ tests/01_rpmsg_init_rtos/readme.txt | 5 + tests/02_epts_channels/main_core0.c | 212 ++++ tests/02_epts_channels/main_core1.c | 214 ++++ tests/02_epts_channels/readme.txt | 6 + tests/02_epts_channels_rtos/main_core0.c | 322 +++++ tests/02_epts_channels_rtos/main_core1.c | 320 +++++ .../main_static_alloc_core0.c | 346 ++++++ .../main_static_alloc_core1.c | 344 ++++++ tests/02_epts_channels_rtos/readme.txt | 6 + tests/03_send_receive/main_core0.c | 309 +++++ tests/03_send_receive/main_core1.c | 360 ++++++ tests/03_send_receive/readme.txt | 5 + tests/03_send_receive_rtos/main_core0.c | 390 ++++++ tests/03_send_receive_rtos/main_core1.c | 424 +++++++ .../main_static_alloc_core0.c | 408 ++++++ .../main_static_alloc_core1.c | 430 +++++++ tests/03_send_receive_rtos/readme.txt | 6 + tests/04_ping_pong/main_core0.c | 393 ++++++ tests/04_ping_pong/main_core1.c | 413 +++++++ tests/04_ping_pong/pingpong_common.h | 110 ++ tests/04_ping_pong/readme.txt | 7 + tests/04_ping_pong_rtos/main_core0.c | 1096 +++++++++++++++++ tests/04_ping_pong_rtos/main_core1.c | 522 ++++++++ .../main_static_alloc_core0.c | 1037 ++++++++++++++++ .../main_static_alloc_core1.c | 464 +++++++ tests/04_ping_pong_rtos/pingpong_common.h | 111 ++ tests/04_ping_pong_rtos/readme.txt | 5 + tests/05_thread_safety_rtos/main_core0.c | 437 +++++++ tests/05_thread_safety_rtos/main_core1.c | 415 +++++++ .../main_static_alloc_core0.c | 448 +++++++ .../main_static_alloc_core1.c | 438 +++++++ tests/05_thread_safety_rtos/pingpong_common.h | 109 ++ tests/05_thread_safety_rtos/readme.txt | 5 + tests/readme.md | 5 + zephyr/CMakeLists.txt | 83 ++ zephyr/Kconfig | 39 + zephyr/README.md | 80 ++ zephyr/module.yml | 8 + .../samples/rpmsglite_pingpong/CMakeLists.txt | 22 + zephyr/samples/rpmsglite_pingpong/Kconfig | 11 + .../rpmsglite_pingpong/Kconfig.sysbuild | 13 + zephyr/samples/rpmsglite_pingpong/README.rst | 97 ++ .../boards/lpcxpresso54114_m4.conf | 2 + .../boards/lpcxpresso54114_m4.overlay | 21 + .../boards/lpcxpresso55s69_cpu0.conf | 1 + .../boards/lpcxpresso55s69_cpu0.overlay | 23 + .../boards/mimxrt1160_evk_cm7.conf | 2 + .../boards/mimxrt1160_evk_cm7.overlay | 24 + .../boards/mimxrt1170_evk_cm7.conf | 2 + .../boards/mimxrt1170_evk_cm7.overlay | 24 + .../boards/mimxrt1170_evkb_cm7.conf | 2 + .../boards/mimxrt1170_evkb_cm7.overlay | 24 + zephyr/samples/rpmsglite_pingpong/common.h | 18 + zephyr/samples/rpmsglite_pingpong/prj.conf | 13 + .../rpmsglite_pingpong/remote/CMakeLists.txt | 11 + .../remote/boards/lpcxpresso54114_m0.conf | 2 + .../remote/boards/lpcxpresso54114_m0.overlay | 21 + .../remote/boards/lpcxpresso55s69_cpu1.conf | 2 + .../boards/lpcxpresso55s69_cpu1.overlay | 23 + .../remote/boards/mimxrt1160_evk_cm4.conf | 3 + .../remote/boards/mimxrt1160_evk_cm4.overlay | 51 + .../remote/boards/mimxrt1170_evk_cm4.conf | 3 + .../remote/boards/mimxrt1170_evk_cm4.overlay | 51 + .../remote/boards/mimxrt1170_evkb_cm4.conf | 3 + .../remote/boards/mimxrt1170_evkb_cm4.overlay | 51 + .../rpmsglite_pingpong/remote/prj.conf | 15 + .../rpmsglite_pingpong/remote/sample.yaml | 15 + .../rpmsglite_pingpong/remote/src/main.c | 96 ++ .../samples/rpmsglite_pingpong/rpmsg_config.h | 86 ++ zephyr/samples/rpmsglite_pingpong/sample.yaml | 24 + zephyr/samples/rpmsglite_pingpong/src/main.c | 109 ++ .../samples/rpmsglite_pingpong/sysbuild.cmake | 21 + 120 files changed, 14366 insertions(+), 104 deletions(-) create mode 100644 lib/include/platform/imx8ulp_fusionf1/rpmsg_platform.h create mode 100644 lib/include/platform/imx8ulp_m33/rpmsg_platform.h create mode 100644 lib/rpmsg_lite/porting/platform/imx8ulp_fusionf1/rpmsg_platform.c create mode 100644 lib/rpmsg_lite/porting/platform/imx8ulp_m33/rpmsg_platform.c create mode 100644 lib/rpmsg_lite/porting/platform/imxrt1160/rpmsg_platform_zephyr_ipm.c create mode 100644 lib/rpmsg_lite/porting/platform/imxrt1170/rpmsg_platform_zephyr_ipm.c create mode 100644 lib/rpmsg_lite/porting/platform/lpc55s69/rpmsg_platform_zephyr_ipm.c create mode 100644 tests/01_rpmsg_init/main_core0.c create mode 100644 tests/01_rpmsg_init/main_core1.c create mode 100644 tests/01_rpmsg_init/readme.txt create mode 100644 tests/01_rpmsg_init_rtos/main_core0.c create mode 100644 tests/01_rpmsg_init_rtos/main_core1.c create mode 100644 tests/01_rpmsg_init_rtos/main_static_alloc_core0.c create mode 100644 tests/01_rpmsg_init_rtos/main_static_alloc_core1.c create mode 100644 tests/01_rpmsg_init_rtos/readme.txt create mode 100644 tests/02_epts_channels/main_core0.c create mode 100644 tests/02_epts_channels/main_core1.c create mode 100644 tests/02_epts_channels/readme.txt create mode 100644 tests/02_epts_channels_rtos/main_core0.c create mode 100644 tests/02_epts_channels_rtos/main_core1.c create mode 100644 tests/02_epts_channels_rtos/main_static_alloc_core0.c create mode 100644 tests/02_epts_channels_rtos/main_static_alloc_core1.c create mode 100644 tests/02_epts_channels_rtos/readme.txt create mode 100644 tests/03_send_receive/main_core0.c create mode 100644 tests/03_send_receive/main_core1.c create mode 100644 tests/03_send_receive/readme.txt create mode 100644 tests/03_send_receive_rtos/main_core0.c create mode 100644 tests/03_send_receive_rtos/main_core1.c create mode 100644 tests/03_send_receive_rtos/main_static_alloc_core0.c create mode 100644 tests/03_send_receive_rtos/main_static_alloc_core1.c create mode 100644 tests/03_send_receive_rtos/readme.txt create mode 100644 tests/04_ping_pong/main_core0.c create mode 100644 tests/04_ping_pong/main_core1.c create mode 100644 tests/04_ping_pong/pingpong_common.h create mode 100644 tests/04_ping_pong/readme.txt create mode 100644 tests/04_ping_pong_rtos/main_core0.c create mode 100644 tests/04_ping_pong_rtos/main_core1.c create mode 100644 tests/04_ping_pong_rtos/main_static_alloc_core0.c create mode 100644 tests/04_ping_pong_rtos/main_static_alloc_core1.c create mode 100644 tests/04_ping_pong_rtos/pingpong_common.h create mode 100644 tests/04_ping_pong_rtos/readme.txt create mode 100644 tests/05_thread_safety_rtos/main_core0.c create mode 100644 tests/05_thread_safety_rtos/main_core1.c create mode 100644 tests/05_thread_safety_rtos/main_static_alloc_core0.c create mode 100644 tests/05_thread_safety_rtos/main_static_alloc_core1.c create mode 100644 tests/05_thread_safety_rtos/pingpong_common.h create mode 100644 tests/05_thread_safety_rtos/readme.txt create mode 100644 tests/readme.md create mode 100644 zephyr/CMakeLists.txt create mode 100644 zephyr/Kconfig create mode 100644 zephyr/README.md create mode 100644 zephyr/module.yml create mode 100644 zephyr/samples/rpmsglite_pingpong/CMakeLists.txt create mode 100644 zephyr/samples/rpmsglite_pingpong/Kconfig create mode 100644 zephyr/samples/rpmsglite_pingpong/Kconfig.sysbuild create mode 100644 zephyr/samples/rpmsglite_pingpong/README.rst create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso54114_m4.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso54114_m4.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso55s69_cpu0.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso55s69_cpu0.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/mimxrt1160_evk_cm7.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/mimxrt1160_evk_cm7.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evk_cm7.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evk_cm7.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evkb_cm7.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evkb_cm7.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/common.h create mode 100644 zephyr/samples/rpmsglite_pingpong/prj.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/CMakeLists.txt create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso54114_m0.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso54114_m0.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso55s69_cpu1.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso55s69_cpu1.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1160_evk_cm4.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1160_evk_cm4.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evk_cm4.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evk_cm4.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evkb_cm4.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evkb_cm4.overlay create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/prj.conf create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/sample.yaml create mode 100644 zephyr/samples/rpmsglite_pingpong/remote/src/main.c create mode 100644 zephyr/samples/rpmsglite_pingpong/rpmsg_config.h create mode 100644 zephyr/samples/rpmsglite_pingpong/sample.yaml create mode 100644 zephyr/samples/rpmsglite_pingpong/src/main.c create mode 100644 zephyr/samples/rpmsglite_pingpong/sysbuild.cmake diff --git a/LICENSE b/LICENSE index 3560e98..69d1f6a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2023 NXP +Copyright (c) 2016-2024 NXP Copyright (c) 2014-2016 Freescale Semiconductor, Inc. Copyright (c) 2014, Mentor Graphics Corporation Copyright (c) 2015 Xilinx, Inc. All rights reserved. diff --git a/README.md b/README.md index ef10fd6..8955f9c 100644 --- a/README.md +++ b/README.md @@ -138,4 +138,4 @@ This script executes the application named *clang-format.exe*. You need to have --- Copyright © 2016 Freescale Semiconductor, Inc. -Copyright © 2016-2023 NXP +Copyright © 2016-2024 NXP diff --git a/doxygen/Doxyfile.rpmsglite b/doxygen/Doxyfile.rpmsglite index e24c2a5..400d041 100644 --- a/doxygen/Doxyfile.rpmsglite +++ b/doxygen/Doxyfile.rpmsglite @@ -38,7 +38,7 @@ PROJECT_NAME = "RPMsg-Lite User's Guide" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = "Rev. 5.1.0" +PROJECT_NUMBER = "Rev. 5.1.1" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/lib/include/environment/bm/rpmsg_env_specific.h b/lib/include/environment/bm/rpmsg_env_specific.h index f468403..2bf7912 100644 --- a/lib/include/environment/bm/rpmsg_env_specific.h +++ b/lib/include/environment/bm/rpmsg_env_specific.h @@ -1,7 +1,5 @@ /* - * Copyright 2021 NXP - * All rights reserved. - * + * Copyright 2021-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/environment/freertos/rpmsg_env_specific.h b/lib/include/environment/freertos/rpmsg_env_specific.h index 731caa8..16e7af7 100644 --- a/lib/include/environment/freertos/rpmsg_env_specific.h +++ b/lib/include/environment/freertos/rpmsg_env_specific.h @@ -1,7 +1,5 @@ /* * Copyright 2021-2023 NXP - * All rights reserved. - * * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/environment/qnx/rpmsg_env_specific.h b/lib/include/environment/qnx/rpmsg_env_specific.h index 00f8cc7..8aac2d5 100644 --- a/lib/include/environment/qnx/rpmsg_env_specific.h +++ b/lib/include/environment/qnx/rpmsg_env_specific.h @@ -1,7 +1,5 @@ /* * Copyright 2021,2023 NXP - * All rights reserved. - * * * SPDX-License-Identifier: BSD-3-Clause */ @@ -37,7 +35,7 @@ typedef struct } rpmsg_queue_rx_cb_data_t; #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) - #error "This RPMsg-Lite port requires RL_USE_STATIC_API set to 0" +#error "This RPMsg-Lite port requires RL_USE_STATIC_API set to 0" #endif #endif /* RPMSG_ENV_SPECIFIC_H_ */ diff --git a/lib/include/environment/threadx/rpmsg_env_specific.h b/lib/include/environment/threadx/rpmsg_env_specific.h index 9a62282..036cfbe 100644 --- a/lib/include/environment/threadx/rpmsg_env_specific.h +++ b/lib/include/environment/threadx/rpmsg_env_specific.h @@ -1,7 +1,5 @@ /* * Copyright 2021-2023 NXP - * All rights reserved. - * * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/environment/xos/rpmsg_env_specific.h b/lib/include/environment/xos/rpmsg_env_specific.h index aae3de7..d36c614 100644 --- a/lib/include/environment/xos/rpmsg_env_specific.h +++ b/lib/include/environment/xos/rpmsg_env_specific.h @@ -1,7 +1,5 @@ /* * Copyright 2021-2023 NXP - * All rights reserved. - * * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/environment/zephyr/rpmsg_env_specific.h b/lib/include/environment/zephyr/rpmsg_env_specific.h index c147472..3a3983b 100644 --- a/lib/include/environment/zephyr/rpmsg_env_specific.h +++ b/lib/include/environment/zephyr/rpmsg_env_specific.h @@ -1,7 +1,5 @@ /* * Copyright 2021-2023 NXP - * All rights reserved. - * * * SPDX-License-Identifier: BSD-3-Clause */ @@ -21,11 +19,18 @@ #include "rpmsg_default_config.h" +typedef struct +{ + uint32_t src; + void *data; + uint32_t len; +} rpmsg_queue_rx_cb_data_t; + #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) -#include +#include -typedef k_sem LOCK_STATIC_CONTEXT; -typedef k_msgq rpmsg_static_queue_ctxt; +typedef struct k_sem LOCK_STATIC_CONTEXT; +typedef struct k_msgq rpmsg_static_queue_ctxt; /* Queue object static storage size in bytes, should be defined as (2*RL_BUFFER_COUNT*sizeof(rpmsg_queue_rx_cb_data_t)) This macro helps the application to statically allocate the queue object static storage memory. Note, the RL_BUFFER_COUNT is not applied for all instances when RL_ALLOW_CUSTOM_SHMEM_CONFIG is set to 1 ! */ diff --git a/lib/include/platform/imx8mp_m7/rpmsg_platform.h b/lib/include/platform/imx8mp_m7/rpmsg_platform.h index 6981452..801c52b 100644 --- a/lib/include/platform/imx8mp_m7/rpmsg_platform.h +++ b/lib/include/platform/imx8mp_m7/rpmsg_platform.h @@ -1,7 +1,5 @@ /* - * Copyright 2019,2022 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/platform/imx8ulp_fusionf1/rpmsg_platform.h b/lib/include/platform/imx8ulp_fusionf1/rpmsg_platform.h new file mode 100644 index 0000000..960ab2c --- /dev/null +++ b/lib/include/platform/imx8ulp_fusionf1/rpmsg_platform.h @@ -0,0 +1,107 @@ +/* + * Copyright 2021-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef RPMSG_PLATFORM_H_ +#define RPMSG_PLATFORM_H_ + +#include + +typedef struct rpmsg_platform_shmem_config +{ + uint32_t buffer_payload_size; /* custom buffer payload size setting that overwrites RL_BUFFER_PAYLOAD_SIZE global + config, must be equal to (240, 496, 1008, ...) [2^n - 16] */ + uint16_t buffer_count; /* custom buffer count setting that overwrites RL_BUFFER_COUNT global config, must be power + of two (2, 4, ...) */ + uint32_t vring_size; /* custom vring size */ + uint32_t vring_align; /* custom vring alignment */ +} rpmsg_platform_shmem_config_t; + +/* RPMSG MU channel index */ +#define RPMSG_MU_CHANNEL (1U) + +#if !(defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)) +/* + * No need to align the VRING as defined in Linux because the FUSION DSP is not intended + * to communicate with Linux. + */ +#ifndef VRING_ALIGN +#define VRING_ALIGN (0x10U) +#endif + +/* contains pool of descriptors and two circular buffers */ +#ifndef VRING_SIZE +/* set VRING_SIZE based on number of used buffers as calculated in vring_init */ +#define VRING_DESC_SIZE (((RL_BUFFER_COUNT * sizeof(struct vring_desc)) + VRING_ALIGN - 1UL) & ~(VRING_ALIGN - 1UL)) +#define VRING_AVAIL_SIZE \ + (((sizeof(struct vring_avail) + (RL_BUFFER_COUNT * sizeof(uint16_t)) + sizeof(uint16_t)) + VRING_ALIGN - 1UL) & \ + ~(VRING_ALIGN - 1UL)) +#define VRING_USED_SIZE \ + (((sizeof(struct vring_used) + (RL_BUFFER_COUNT * sizeof(struct vring_used_elem)) + sizeof(uint16_t)) + \ + VRING_ALIGN - 1UL) & \ + ~(VRING_ALIGN - 1UL)) +#define VRING_SIZE (VRING_DESC_SIZE + VRING_AVAIL_SIZE + VRING_USED_SIZE) +#endif + +/* define shared memory space for VRINGS per one channel */ +#define RL_VRING_OVERHEAD (2UL * VRING_SIZE) +#endif + +/* VQ_ID in 8ULP is defined as follows: + * com_id: [4:3] communication ID, used to identify the MU instance. + * vring_id: [2:1] vring ID, used to identify the vring. + * q_id: [0:0] queue ID, used to identify the tvq or rvq. + * com_id + vring_id = link_id + */ +#define RL_GET_VQ_ID(link_id, queue_id) (((queue_id)&0x1U) | (((link_id) << 1U) & 0xFFFFFFFEU)) +#define RL_GET_LINK_ID(vq_id) (((vq_id)&0xFFFFFFFEU) >> 1U) +#define RL_GET_Q_ID(vq_id) ((vq_id)&0x1U) +#define RL_GEN_MU_MSG(vq_id) (uint32_t)(((vq_id)&0x7U) << 16U) /* com_id is discarded in msg */ + +#define RL_GEN_LINK_ID(com_id, vring_id) (((com_id) << 2U) | (vring_id)) + +#define RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID (1U) +#define RL_PLATFORM_IMX8ULP_FUSION_SRTM_VRING_ID (0U) +#define RL_PLATFORM_IMX8ULP_FUSION_USER_VRING_ID (1U) + +/* Use same link id with master/CM33. */ +#define RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_SRTM_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID, RL_PLATFORM_IMX8ULP_FUSION_SRTM_VRING_ID) +#define RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_USER_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID, RL_PLATFORM_IMX8ULP_FUSION_USER_VRING_ID) + +#define RL_PLATFORM_HIGHEST_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID, RL_PLATFORM_IMX8ULP_FUSION_USER_VRING_ID) + +/* platform interrupt related functions */ +int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data); +int32_t platform_deinit_interrupt(uint32_t vector_id); +int32_t platform_interrupt_enable(uint32_t vector_id); +int32_t platform_interrupt_disable(uint32_t vector_id); +int32_t platform_in_isr(void); +void platform_notify(uint32_t vector_id); + +/* platform low-level time-delay (busy loop) */ +void platform_time_delay(uint32_t num_msec); + +/* platform memory functions */ +void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags); +void platform_cache_all_flush_invalidate(void); +void platform_cache_disable(void); +uintptr_t platform_vatopa(void *addr); +void *platform_patova(uintptr_t addr); + +#if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) +#define RL_VRING_SIZE_M33_FUSION_DSP_COM (0x400UL) + +#define RL_VRING_ALIGN_M33_FUSION_DSP_COM (0x10U) + +int32_t platform_get_custom_shmem_config(uint32_t link_id, rpmsg_platform_shmem_config_t *cfg); +#endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */ + +/* platform init/deinit */ +int32_t platform_init(void); +int32_t platform_deinit(void); + +#endif /* RPMSG_PLATFORM_H_ */ diff --git a/lib/include/platform/imx8ulp_m33/rpmsg_platform.h b/lib/include/platform/imx8ulp_m33/rpmsg_platform.h new file mode 100644 index 0000000..80ab002 --- /dev/null +++ b/lib/include/platform/imx8ulp_m33/rpmsg_platform.h @@ -0,0 +1,115 @@ +/* + * Copyright 2021-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef RPMSG_PLATFORM_H_ +#define RPMSG_PLATFORM_H_ + +#include + +typedef struct rpmsg_platform_shmem_config +{ + uint32_t buffer_payload_size; /* custom buffer payload size setting that overwrites RL_BUFFER_PAYLOAD_SIZE global + config, must be equal to (240, 496, 1008, ...) [2^n - 16] */ + uint16_t buffer_count; /* custom buffer count setting that overwrites RL_BUFFER_COUNT global config, must be power + of two (2, 4, ...) */ + uint32_t vring_size; /* custom vring size */ + uint32_t vring_align; /* custom vring alignment */ +} rpmsg_platform_shmem_config_t; + +/* RPMSG MU channel index */ +#define RPMSG_MU_CHANNEL (1) + +#if !(defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)) +/* + * Linux requires the ALIGN to 0x1000(4KB) instead of 0x80 + */ +#ifndef VRING_ALIGN +#define VRING_ALIGN (0x1000U) +#endif + +/* contains pool of descriptors and two circular buffers */ +#ifndef VRING_SIZE +#define VRING_SIZE (0x8000UL) +#endif + +/* define shared memory space for VRINGS per one channel */ +#define RL_VRING_OVERHEAD (2UL * VRING_SIZE) +#endif + +/* VQ_ID in 8ULP is defined as follows: + * com_id: [4:3] communication ID, used to identify the MU instance. + * vring_id: [2:1] vring ID, used to identify the vring. + * q_id: [0:0] queue ID, used to identify the tvq or rvq. + * com_id + vring_id = link_id + */ + +#define RL_GET_VQ_ID(link_id, queue_id) (((queue_id)&0x1U) | (((link_id) << 1U) & 0xFFFFFFFEU)) +#define RL_GET_LINK_ID(vq_id) ((vq_id) >> 1U) +#define RL_GET_COM_ID(vq_id) ((vq_id) >> 3U) +#define RL_GET_Q_ID(vq_id) ((vq_id)&0x1U) + +#define RL_GEN_LINK_ID(com_id, vring_id) (((com_id) << 2U) | (vring_id)) +#define RL_GEN_MU_MSG(vq_id) (uint32_t)(((vq_id)&0x7U) << 16U) /* com_id is discarded in msg */ + +#define RL_PLATFORM_IMX8ULP_M33_A35_COM_ID (0U) +#define RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID (1U) +#define RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID (2U) + +#define RL_PLATFORM_IMX8ULP_M33_SRTM_VRING_ID (0U) +#define RL_PLATFORM_IMX8ULP_M33_USER_VRING_ID (1U) + +#define RL_PLATFORM_HIGHEST_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID, RL_PLATFORM_IMX8ULP_M33_USER_VRING_ID) + +#define RL_PLATFORM_IMX8ULP_M33_A35_SRTM_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_A35_COM_ID, RL_PLATFORM_IMX8ULP_M33_SRTM_VRING_ID) +#define RL_PLATFORM_IMX8ULP_M33_A35_USER_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_A35_COM_ID, RL_PLATFORM_IMX8ULP_M33_USER_VRING_ID) + +#define RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_SRTM_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID, RL_PLATFORM_IMX8ULP_M33_SRTM_VRING_ID) +#define RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_USER_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID, RL_PLATFORM_IMX8ULP_M33_USER_VRING_ID) + +#define RL_PLATFORM_IMX8ULP_M33_HIFI4_SRTM_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID, RL_PLATFORM_IMX8ULP_M33_SRTM_VRING_ID) +#define RL_PLATFORM_IMX8ULP_M33_HIFI4_USER_LINK_ID \ + RL_GEN_LINK_ID(RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID, RL_PLATFORM_IMX8ULP_M33_USER_VRING_ID) + +/* platform interrupt related functions */ +int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data); +int32_t platform_deinit_interrupt(uint32_t vector_id); +int32_t platform_interrupt_enable(uint32_t vector_id); +int32_t platform_interrupt_disable(uint32_t vector_id); +int32_t platform_in_isr(void); +void platform_notify(uint32_t vector_id); + +/* platform low-level time-delay (busy loop) */ +void platform_time_delay(uint32_t num_msec); + +/* platform memory functions */ +void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags); +void platform_cache_all_flush_invalidate(void); +void platform_cache_disable(void); +uintptr_t platform_vatopa(void *addr); +void *platform_patova(uintptr_t addr); + +#if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) +#define RL_VRING_SIZE_M33_A35_COM (0x8000UL) /* contains pool of descriptors and two circular buffers */ +#define RL_VRING_SIZE_M33_FUSION_DSP_COM (0x400UL) +#define RL_VRING_SIZE_M33_HIFI4_COM (0x400UL) + +#define RL_VRING_ALIGN_M33_A35_COM (0x1000U) /* Linux requires the ALIGN to 0x1000(4KB) instead of 0x80 */ +#define RL_VRING_ALIGN_M33_FUSION_DSP_COM (0x10U) +#define RL_VRING_ALIGN_M33_HIFI4_COM (0x10U) + +int32_t platform_get_custom_shmem_config(uint32_t link_id, rpmsg_platform_shmem_config_t *cfg); +#endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */ + +/* platform init/deinit */ +int32_t platform_init(void); +int32_t platform_deinit(void); + +#endif /* RPMSG_PLATFORM_H_ */ diff --git a/lib/include/platform/imxrt500_fusionf1/rpmsg_platform.h b/lib/include/platform/imxrt500_fusionf1/rpmsg_platform.h index c2aaf55..468b089 100644 --- a/lib/include/platform/imxrt500_fusionf1/rpmsg_platform.h +++ b/lib/include/platform/imxrt500_fusionf1/rpmsg_platform.h @@ -1,7 +1,5 @@ /* - * Copyright 2019-2022 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/platform/imxrt500_m33/rpmsg_platform.h b/lib/include/platform/imxrt500_m33/rpmsg_platform.h index e369077..c0ce72b 100644 --- a/lib/include/platform/imxrt500_m33/rpmsg_platform.h +++ b/lib/include/platform/imxrt500_m33/rpmsg_platform.h @@ -1,7 +1,5 @@ /* - * Copyright 2019-2022 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/platform/imxrt600_hifi4/rpmsg_platform.h b/lib/include/platform/imxrt600_hifi4/rpmsg_platform.h index ba78eb0..f52849b 100644 --- a/lib/include/platform/imxrt600_hifi4/rpmsg_platform.h +++ b/lib/include/platform/imxrt600_hifi4/rpmsg_platform.h @@ -1,7 +1,5 @@ /* - * Copyright 2019-2022 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/platform/imxrt600_m33/rpmsg_platform.h b/lib/include/platform/imxrt600_m33/rpmsg_platform.h index ba78eb0..f52849b 100644 --- a/lib/include/platform/imxrt600_m33/rpmsg_platform.h +++ b/lib/include/platform/imxrt600_m33/rpmsg_platform.h @@ -1,7 +1,5 @@ /* - * Copyright 2019-2022 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/platform/lpc55s69/rpmsg_platform.h b/lib/include/platform/lpc55s69/rpmsg_platform.h index accb275..ed283ba 100644 --- a/lib/include/platform/lpc55s69/rpmsg_platform.h +++ b/lib/include/platform/lpc55s69/rpmsg_platform.h @@ -1,7 +1,5 @@ /* - * Copyright 2018-2022 NXP - * All rights reserved. - * + * Copyright 2018-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/include/rpmsg_lite.h b/lib/include/rpmsg_lite.h index 86850b7..f9cbe4c 100644 --- a/lib/include/rpmsg_lite.h +++ b/lib/include/rpmsg_lite.h @@ -52,7 +52,7 @@ extern "C" { * Definitions ******************************************************************************/ -#define RL_VERSION "5.1.0" /*!< Current RPMsg Lite version */ +#define RL_VERSION "5.1.1" /*!< Current RPMsg Lite version */ /* Shared memory "allocator" parameters */ #define RL_WORD_SIZE (sizeof(uint32_t)) diff --git a/lib/rpmsg_lite/porting/environment/rpmsg_env_freertos.c b/lib/rpmsg_lite/porting/environment/rpmsg_env_freertos.c index 1c58c85..53975c0 100644 --- a/lib/rpmsg_lite/porting/environment/rpmsg_env_freertos.c +++ b/lib/rpmsg_lite/porting/environment/rpmsg_env_freertos.c @@ -57,9 +57,13 @@ #include #include -static int32_t env_init_counter = 0; -static SemaphoreHandle_t env_sema = ((void *)0); +static int32_t env_init_counter = 0; +static SemaphoreHandle_t env_sema = ((void *)0); +#ifndef __COVERAGESCANNER__ static EventGroupHandle_t event_group = ((void *)0); +#else +EventGroupHandle_t event_group = ((void *)0); +#endif #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) LOCK_STATIC_CONTEXT env_sem_static_context; StaticEventGroup_t event_group_static_context; @@ -112,6 +116,8 @@ static int32_t env_in_isr(void) #endif } +#ifndef __COVERAGESCANNER__ + /*! * env_wait_for_link_up * @@ -162,6 +168,7 @@ void env_tx_callback(uint32_t link_id) (void)xEventGroupSetBits(event_group, (EventBits_t)(1UL << link_id)); } } +#endif /* __COVERAGESCANNER__*/ /*! * env_init @@ -188,11 +195,11 @@ int32_t env_init(void) { /* first call */ #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) - env_sema = xSemaphoreCreateBinaryStatic(&env_sem_static_context); - event_group = xEventGroupCreateStatic(&event_group_static_context); + env_sema = (SemaphoreHandle_t)xSemaphoreCreateBinaryStatic(&env_sem_static_context); + event_group = (EventGroupHandle_t)xEventGroupCreateStatic(&event_group_static_context); #else - env_sema = xSemaphoreCreateBinary(); - event_group = xEventGroupCreate(); + env_sema = (SemaphoreHandle_t)xSemaphoreCreateBinary(); + event_group = (EventGroupHandle_t)xEventGroupCreate(); #endif #if (configUSE_16_BIT_TICKS == 1) (void)xEventGroupClearBits(event_group, 0xFFu); @@ -417,10 +424,10 @@ int32_t env_create_mutex(void **lock, int32_t count) } #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) - *lock = xSemaphoreCreateCountingStatic((UBaseType_t)RL_ENV_MAX_MUTEX_COUNT, (UBaseType_t)count, - (StaticSemaphore_t *)context); + *lock = (void *)xSemaphoreCreateCountingStatic((UBaseType_t)RL_ENV_MAX_MUTEX_COUNT, (UBaseType_t)count, + (StaticSemaphore_t *)context); #else - *lock = xSemaphoreCreateCounting((UBaseType_t)RL_ENV_MAX_MUTEX_COUNT, (UBaseType_t)count); + *lock = (void *)xSemaphoreCreateCounting((UBaseType_t)RL_ENV_MAX_MUTEX_COUNT, (UBaseType_t)count); #endif if (*lock != ((void *)0)) { @@ -505,6 +512,7 @@ void env_delete_sync_lock(void *lock) } } +#ifndef __COVERAGESCANNER__ /*! * env_acquire_sync_lock * @@ -545,6 +553,7 @@ void env_release_sync_lock(void *lock) (void)xSemaphoreGive(xSemaphore); } } +#endif /* __COVERAGESCANNER__ */ /*! * env_sleep_msec @@ -698,8 +707,8 @@ int32_t env_create_queue(void **queue, uint8_t *queue_static_storage, rpmsg_static_queue_ctxt *queue_static_context) { - *queue = - xQueueCreateStatic((UBaseType_t)length, (UBaseType_t)element_size, queue_static_storage, queue_static_context); + *queue = (void *)xQueueCreateStatic((UBaseType_t)length, (UBaseType_t)element_size, queue_static_storage, + queue_static_context); #else int32_t env_create_queue(void **queue, int32_t length, int32_t element_size) { @@ -728,6 +737,7 @@ void env_delete_queue(void *queue) vQueueDelete(queue); } +#ifndef __COVERAGESCANNER__ /*! * env_put_queue * @@ -795,6 +805,7 @@ int32_t env_get_queue(void *queue, void *msg, uintptr_t timeout_ms) } return 0; } +#endif /* __COVERAGESCANNER__ */ /*! * env_get_current_queue_size diff --git a/lib/rpmsg_lite/porting/environment/rpmsg_env_threadx.c b/lib/rpmsg_lite/porting/environment/rpmsg_env_threadx.c index 9572ca8..c3dc63f 100644 --- a/lib/rpmsg_lite/porting/environment/rpmsg_env_threadx.c +++ b/lib/rpmsg_lite/porting/environment/rpmsg_env_threadx.c @@ -1,7 +1,5 @@ /* * Copyright 2020-2023 NXP - * All rights reserved. - * * * SPDX-License-Identifier: BSD-3-Clause */ @@ -42,6 +40,10 @@ static TX_EVENT_FLAGS_GROUP event_group = {0}; */ #define RL_ENV_MAX_MUTEX_COUNT (10) +#ifndef TX_TIMER_TICKS_PER_SECOND +#define TX_TIMER_TICKS_PER_SECOND ((ULONG)100) +#endif + /* Max supported ISR counts */ #define ISR_COUNT (32U) /*! diff --git a/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c b/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c index a9f5fb1..165c3d8 100644 --- a/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c +++ b/lib/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c @@ -45,7 +45,8 @@ #include "rpmsg_compiler.h" #include "rpmsg_env.h" -#include +#include +#include #include "rpmsg_platform.h" #include "virtqueue.h" @@ -106,7 +107,7 @@ uint32_t env_wait_for_link_up(volatile uint32_t *link_state, uint32_t link_id, u timeout_ms = 0; /* force timeout == 0 when in ISR */ } - if (0 != k_event_wait_all(&env_event, (1UL << link_id), false, timeout_ms)) + if (0 != k_event_wait_all(&env_event, (1UL << link_id), false, K_MSEC(timeout_ms))) { return 1U; } @@ -493,7 +494,7 @@ void env_release_sync_lock(void *lock) */ void env_sleep_msec(uint32_t num_msec) { - k_sleep(num_msec); + k_sleep(K_MSEC(num_msec)); } /*! @@ -679,7 +680,7 @@ int32_t env_put_queue(void *queue, void *msg, uintptr_t timeout_ms) timeout_ms = 0; /* force timeout == 0 when in ISR */ } - if (0 == k_msgq_put((struct k_msgq *)queue, msg, timeout_ms)) + if (0 == k_msgq_put((struct k_msgq *)queue, msg, K_MSEC(timeout_ms))) { return 1; } @@ -705,7 +706,7 @@ int32_t env_get_queue(void *queue, void *msg, uintptr_t timeout_ms) timeout_ms = 0; /* force timeout == 0 when in ISR */ } - if (0 == k_msgq_get((struct k_msgq *)queue, msg, timeout_ms)) + if (0 == k_msgq_get((struct k_msgq *)queue, msg, K_MSEC(timeout_ms))) { return 1; } diff --git a/lib/rpmsg_lite/porting/platform/imx8mm_m4/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imx8mm_m4/rpmsg_platform.c index 8be0e00..196791c 100644 --- a/lib/rpmsg_lite/porting/platform/imx8mm_m4/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imx8mm_m4/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2017-2021 NXP - * All rights reserved. - * + * Copyright 2017-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imx8mn_m7/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imx8mn_m7/rpmsg_platform.c index bfee59d..f3db0a0 100644 --- a/lib/rpmsg_lite/porting/platform/imx8mn_m7/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imx8mn_m7/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2017-2021 NXP - * All rights reserved. - * + * Copyright 2017-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imx8mp_m7/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imx8mp_m7/rpmsg_platform.c index 8c9c140..db36c66 100644 --- a/lib/rpmsg_lite/porting/platform/imx8mp_m7/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imx8mp_m7/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2019-2021 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imx8mq_m4/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imx8mq_m4/rpmsg_platform.c index db328ef..ba45b83 100644 --- a/lib/rpmsg_lite/porting/platform/imx8mq_m4/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imx8mq_m4/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2017-2021 NXP - * All rights reserved. - * + * Copyright 2017-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imx8qm_m4/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imx8qm_m4/rpmsg_platform.c index de7ea39..fef3253 100644 --- a/lib/rpmsg_lite/porting/platform/imx8qm_m4/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imx8qm_m4/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2017-2021 NXP - * All rights reserved. - * + * Copyright 2017-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imx8qx_cm4/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imx8qx_cm4/rpmsg_platform.c index 657627f..414401f 100644 --- a/lib/rpmsg_lite/porting/platform/imx8qx_cm4/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imx8qx_cm4/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2017-2021 NXP - * All rights reserved. - * + * Copyright 2017-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imx8ulp_fusionf1/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imx8ulp_fusionf1/rpmsg_platform.c new file mode 100644 index 0000000..912f95d --- /dev/null +++ b/lib/rpmsg_lite/porting/platform/imx8ulp_fusionf1/rpmsg_platform.c @@ -0,0 +1,353 @@ +/* + * Copyright 2021-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include + +#include "rpmsg_default_config.h" +#include "rpmsg_platform.h" +#include "rpmsg_env.h" +#include + +#ifdef SDK_OS_BAREMETAL +#include +#include +#else +#include +#endif + +#include "fsl_device_registers.h" +#include "fsl_mu.h" + +#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1) +#error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0" +#endif + +#define APP_FUSION_M33_MU MU1_MUB + +static int32_t isr_counter = 0; +static int32_t disable_counter = 0; +static void *platform_lock; +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +static LOCK_STATIC_CONTEXT platform_lock_static_ctxt; +#endif + +void MU1_B_IRQHandler(void *arg) +{ + uint32_t channel; + + if ((((uint32_t)kMU_Rx0FullFlag << RPMSG_MU_CHANNEL) & MU_GetStatusFlags(APP_FUSION_M33_MU)) != 0UL) + { + channel = MU_ReceiveMsgNonBlocking(APP_FUSION_M33_MU, RPMSG_MU_CHANNEL); /* Read message from RX register. */ + env_isr((uint32_t)((channel >> 16) | (RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID << 3))); + } +} + +int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data) +{ + if (platform_lock != ((void *)0)) + { + /* Register ISR to environment layer */ + env_register_isr(vector_id, isr_data); + + env_lock_mutex(platform_lock); + + RL_ASSERT(0 <= isr_counter); + + if (isr_counter < 2) + { + MU_EnableInterrupts(APP_FUSION_M33_MU, (uint32_t)kMU_Rx0FullInterruptEnable << RPMSG_MU_CHANNEL); + } + + isr_counter++; + + env_unlock_mutex(platform_lock); + + return 0; + } + else + { + return -1; + } +} + +int32_t platform_deinit_interrupt(uint32_t vector_id) +{ + if (platform_lock != ((void *)0)) + { + /* Prepare the MU Hardware */ + env_lock_mutex(platform_lock); + + RL_ASSERT(0 < isr_counter); + isr_counter--; + + if (isr_counter < 2) + { + MU_DisableInterrupts(APP_FUSION_M33_MU, (uint32_t)kMU_Rx0FullInterruptEnable << RPMSG_MU_CHANNEL); + } + + /* Unregister ISR from environment layer */ + env_unregister_isr(vector_id); + + env_unlock_mutex(platform_lock); + + return 0; + } + else + { + return -1; + } +} + +void platform_notify(uint32_t vector_id) +{ + /* Only vring id and queue id is needed in msg */ + uint32_t msg = RL_GEN_MU_MSG(vector_id); + + env_lock_mutex(platform_lock); + MU_SendMsg(APP_FUSION_M33_MU, RPMSG_MU_CHANNEL, msg); + env_unlock_mutex(platform_lock); +} + +/** + * platform_time_delay + * + * @param num_msec Delay time in ms. + * + * This is not an accurate delay, it ensures at least num_msec passed when return. + */ +void platform_time_delay(uint32_t num_msec) +{ + uint32_t loop; + + /* Recalculate the CPU frequency */ + SystemCoreClockUpdate(); + + /* Calculate the CPU loops to delay, each loop has approx. 6 cycles */ + loop = SystemCoreClock / 6U / 1000U * num_msec; + + while (loop > 0U) + { + asm("nop"); + loop--; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int32_t platform_in_isr(void) +{ + return (xthal_get_interrupt() & xthal_get_intenable()); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_enable(uint32_t vector_id) +{ + RL_ASSERT(0 < disable_counter); + +#ifdef SDK_OS_BAREMETAL + _xtos_interrupt_enable(MU1_B_IRQn); +#else + xos_interrupt_enable(MU1_B_IRQn); +#endif + disable_counter--; + return ((int32_t)vector_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_disable(uint32_t vector_id) +{ + RL_ASSERT(0 <= disable_counter); + +#ifdef SDK_OS_BAREMETAL + _xtos_interrupt_disable(MU1_B_IRQn); +#else + xos_interrupt_disable(MU1_B_IRQn); +#endif + disable_counter++; + return ((int32_t)vector_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate(void) +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable(void) +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +uintptr_t platform_vatopa(void *addr) +{ + uintptr_t tmp = (uintptr_t)(char *)addr; + if (tmp < 0x880000u) + { + return ((tmp | 0x20000000u) - 800000u); + } + else if (tmp < 0x8C0000u) + { + return (tmp - 0x800000u + 0x0FFC0000u); + } + else + { + return tmp; + } +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(uintptr_t addr) +{ + addr &= 0xEFFFFFFFu; + if (addr < 0x10000000u) /* SSRAM P7. */ + { + return ((void *)(char *)(addr - 0x0FFC0000u + 0x880000u)); + } + else if (addr < 0x20080000u) /* SSRAM P0-P6 */ + { + return ((void *)(char *)((addr & 0x0FFFFFFFu) + 0x800000u)); + } + else + { + return (void *)(char *)addr; + } +} + +#if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) +/** + * platform_get_custom_shmem_config + * + * Provide rpmsg_platform_shmem_config structure for the rpmsg_lite instance initialization + * based on the link_id. + * + * @param link_id Link ID provided by the rpmsg_lite init function + * @param cfg Pointer to the rpmsg_platform_shmem_config structure to be filled + * + * @return Status of function execution, 0 on success. + */ +int32_t platform_get_custom_shmem_config(uint32_t link_id, rpmsg_platform_shmem_config_t *cfg) +{ + /* Only MU instance. */ + cfg->buffer_payload_size = RL_BUFFER_PAYLOAD_SIZE(link_id); + cfg->buffer_count = RL_BUFFER_COUNT(link_id); + + switch (link_id) + { + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_SRTM_LINK_ID: + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_USER_LINK_ID: + cfg->vring_size = RL_VRING_SIZE_M33_FUSION_DSP_COM; + cfg->vring_align = RL_VRING_ALIGN_M33_FUSION_DSP_COM; + break; + default: + /* All the cases have been listed above, the default clause should not be reached. */ + break; + } + return 0; +} +#endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */ + +/** + * platform_init + * + * platform/environment init + */ +int32_t platform_init(void) +{ + MU_Init(APP_FUSION_M33_MU); + /* Create lock used in multi-instanced RPMsg */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (0 != env_create_mutex(&platform_lock, 1, &platform_lock_static_ctxt)) +#else + if (0 != env_create_mutex(&platform_lock, 1)) +#endif + { + return -1; + } + + /* Register interrupt handler for MU_B on HiFi4 */ +#ifdef SDK_OS_BAREMETAL + _xtos_set_interrupt_handler(MU1_B_IRQn, MU1_B_IRQHandler); +#else + xos_register_interrupt_handler(MU1_B_IRQn, MU1_B_IRQHandler, ((void *)0)); +#endif + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int32_t platform_deinit(void) +{ + MU_Deinit(APP_FUSION_M33_MU); +#ifdef SDK_OS_BAREMETAL + _xtos_set_interrupt_handler(MU1_B_IRQn, ((void *)0)); +#else + xos_register_interrupt_handler(MU1_B_IRQn, ((void *)0), ((void *)0)); +#endif + + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(platform_lock); + platform_lock = ((void *)0); + return 0; +} diff --git a/lib/rpmsg_lite/porting/platform/imx8ulp_m33/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imx8ulp_m33/rpmsg_platform.c new file mode 100644 index 0000000..67ac9b5 --- /dev/null +++ b/lib/rpmsg_lite/porting/platform/imx8ulp_m33/rpmsg_platform.c @@ -0,0 +1,503 @@ +/* + * Copyright 2021-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include + +#include "rpmsg_default_config.h" +#include "rpmsg_platform.h" +#include "rpmsg_env.h" + +#include "fsl_device_registers.h" +#include "fsl_mu.h" + +#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1) +#error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0" +#endif + +#define APP_M33_A35_MU MU0_MUA +#define APP_M33_A35_MU_IRQn MU0_A_IRQn +#define APP_M33_FUSION_DSP_MU MU1_MUA +#define APP_M33_FUSION_DSP_MU_IRQn MU1_A_IRQn +#define APP_M33_HIFI4_MU MU2_MUA +#define APP_M33_HIFI4_MU_IRQn MU2_A_IRQn + +#define APP_MU_IRQ_PRIORITY (3U) +#define APP_MU_A35_SIDE_READY (0x1U) +#define APP_MU_A35_WAIT_INTERVAL_MS (10U) + +static int32_t isr_counter0 = 0; /* RL_PLATFORM_IMX8ULP_M33_A35_USER_LINK_ID isr counter */ +static int32_t isr_counter1 = 0; /* RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_USER_LINK_ID isr counter */ +static int32_t isr_counter2 = 0; /* RL_PLATFORM_IMX8ULP_M33_HIFI4_USER_LINK_ID isr counter */ + +static int32_t disable_counter0 = 0; +static int32_t disable_counter1 = 0; +static int32_t disable_counter2 = 0; +static void *platform_lock; +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +static LOCK_STATIC_CONTEXT platform_lock_static_ctxt; +#endif + +static void platform_global_isr_disable(void) +{ + __asm volatile("cpsid i"); +} + +static void platform_global_isr_enable(void) +{ + __asm volatile("cpsie i"); +} + +int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data) +{ + if (platform_lock != ((void *)0)) + { + /* Register ISR to environment layer */ + env_register_isr(vector_id, isr_data); + + /* Prepare the MU Hardware, enable channel 1 interrupt */ + env_lock_mutex(platform_lock); + + switch (RL_GET_COM_ID(vector_id)) + { + case RL_PLATFORM_IMX8ULP_M33_A35_COM_ID: + RL_ASSERT(0 <= isr_counter0); + if (isr_counter0 == 0) + { + MU_EnableInterrupts(APP_M33_A35_MU, (uint32_t)kMU_Rx0FullInterruptEnable << RPMSG_MU_CHANNEL); + } + isr_counter0++; + break; + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID: + RL_ASSERT(0 <= isr_counter1); + if (isr_counter1 == 0) + { + MU_EnableInterrupts(APP_M33_FUSION_DSP_MU, + (uint32_t)kMU_Rx0FullInterruptEnable << RPMSG_MU_CHANNEL); + } + isr_counter1++; + break; + case RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID: + RL_ASSERT(0 <= isr_counter2); + if (isr_counter2 == 0) + { + MU_EnableInterrupts(APP_M33_HIFI4_MU, (uint32_t)kMU_Rx0FullInterruptEnable << RPMSG_MU_CHANNEL); + } + isr_counter2++; + break; + default: + /* All the cases have been listed above, the default clause should not be reached. */ + break; + } + + env_unlock_mutex(platform_lock); + return 0; + } + else + { + return -1; + } +} + +int32_t platform_deinit_interrupt(uint32_t vector_id) +{ + if (platform_lock != ((void *)0)) + { + /* Prepare the MU Hardware */ + env_lock_mutex(platform_lock); + + switch (RL_GET_COM_ID(vector_id)) + { + case RL_PLATFORM_IMX8ULP_M33_A35_COM_ID: + RL_ASSERT(0 < isr_counter0); + isr_counter0--; + if (isr_counter0 == 0) + { + MU_DisableInterrupts(APP_M33_A35_MU, (uint32_t)kMU_Rx0FullInterruptEnable << RPMSG_MU_CHANNEL); + } + break; + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID: + RL_ASSERT(0 < isr_counter1); + isr_counter1--; + if (isr_counter1 == 0) + { + MU_DisableInterrupts(APP_M33_FUSION_DSP_MU, + (uint32_t)kMU_Rx0FullInterruptEnable << RPMSG_MU_CHANNEL); + } + break; + case RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID: + RL_ASSERT(0 < isr_counter2); + isr_counter2--; + if (isr_counter2 == 0) + { + MU_DisableInterrupts(APP_M33_HIFI4_MU, (uint32_t)kMU_Rx0FullInterruptEnable << RPMSG_MU_CHANNEL); + } + break; + default: + /* All the cases have been listed above, the default clause should not be reached. */ + break; + } + + /* Unregister ISR from environment layer */ + env_unregister_isr(vector_id); + + env_unlock_mutex(platform_lock); + + return 0; + } + else + { + return -1; + } +} + +void platform_notify(uint32_t vector_id) +{ + /* Only vring id and queue id is needed in msg */ + uint32_t msg = RL_GEN_MU_MSG(vector_id); + + env_lock_mutex(platform_lock); + /* As Linux suggests, use MU->Data Channel 1 as communication channel */ + switch (RL_GET_COM_ID(vector_id)) + { + case RL_PLATFORM_IMX8ULP_M33_A35_COM_ID: + MU_SendMsg(APP_M33_A35_MU, RPMSG_MU_CHANNEL, msg); + break; + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID: + MU_SendMsg(APP_M33_FUSION_DSP_MU, RPMSG_MU_CHANNEL, msg); + break; + case RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID: + MU_SendMsg(APP_M33_HIFI4_MU, RPMSG_MU_CHANNEL, msg); + break; + default: + /* All the cases have been listed above, the default clause should not be reached. */ + break; + } + env_unlock_mutex(platform_lock); +} + +/* + * MU Interrrupt RPMsg handler + */ +int32_t MU0_A_IRQHandler(void) +{ + uint32_t channel; + + if ((((uint32_t)kMU_Rx0FullFlag << RPMSG_MU_CHANNEL) & MU_GetStatusFlags(APP_M33_A35_MU)) != 0UL) + { + channel = MU_ReceiveMsgNonBlocking(APP_M33_A35_MU, RPMSG_MU_CHANNEL); // Read message from RX register. + env_isr((uint32_t)((channel >> 16) | (RL_PLATFORM_IMX8ULP_M33_A35_COM_ID << 3))); + } + + return 0; +} + +int32_t MU1_A_IRQHandler(void) +{ + uint32_t channel; + + if ((((uint32_t)kMU_Rx0FullFlag << RPMSG_MU_CHANNEL) & MU_GetStatusFlags(APP_M33_FUSION_DSP_MU)) != 0UL) + { + channel = MU_ReceiveMsgNonBlocking(APP_M33_FUSION_DSP_MU, RPMSG_MU_CHANNEL); // Read message from RX register. + env_isr((uint32_t)((channel >> 16) | (RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID << 3))); + } + + return 0; +} + +int32_t MU2_A_IRQHandler(void) +{ + uint32_t channel; + + if ((((uint32_t)kMU_Rx0FullFlag << RPMSG_MU_CHANNEL) & MU_GetStatusFlags(APP_M33_HIFI4_MU)) != 0UL) + { + channel = MU_ReceiveMsgNonBlocking(APP_M33_HIFI4_MU, RPMSG_MU_CHANNEL); // Read message from RX register. + env_isr((uint32_t)((channel >> 16) | (RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID << 3))); + } + + return 0; +} + +/** + * platform_time_delay + * + * @param num_msec Delay time in ms. + * + * This is not an accurate delay, it ensures at least num_msec passed when return. + */ +void platform_time_delay(uint32_t num_msec) +{ + uint32_t loop; + + /* Recalculate the CPU frequency */ + SystemCoreClockUpdate(); + + /* Calculate the CPU loops to delay, each loop has 3 cycles */ + loop = SystemCoreClock / 3U / 1000U * num_msec; + + /* There's some difference among toolchains, 3 or 4 cycles each loop */ + while (loop > 0U) + { + __NOP(); + loop--; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int32_t platform_in_isr(void) +{ + return (((SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) != 0UL) ? 1 : 0); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_enable(uint32_t vector_id) +{ + platform_global_isr_disable(); + switch (RL_GET_COM_ID(vector_id)) + { + case RL_PLATFORM_IMX8ULP_M33_A35_COM_ID: + RL_ASSERT(0 < disable_counter0); + disable_counter0--; + if (disable_counter0 == 0) + { + NVIC_EnableIRQ(APP_M33_A35_MU_IRQn); + } + break; + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID: + RL_ASSERT(0 < disable_counter1); + disable_counter1--; + if (disable_counter1 == 0) + { + NVIC_EnableIRQ(APP_M33_FUSION_DSP_MU_IRQn); + } + break; + case RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID: + RL_ASSERT(0 < disable_counter2); + disable_counter2--; + if (disable_counter2 == 0) + { + NVIC_EnableIRQ(APP_M33_HIFI4_MU_IRQn); + } + break; + default: + /* All the cases have been listed above, the default clause should not be reached. */ + break; + } + platform_global_isr_enable(); + return ((int32_t)vector_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_disable(uint32_t vector_id) +{ + platform_global_isr_disable(); + /* virtqueues use the same NVIC vector + if counter is set - the interrupts are disabled */ + switch (RL_GET_COM_ID(vector_id)) + { + case RL_PLATFORM_IMX8ULP_M33_A35_COM_ID: + RL_ASSERT(0 <= disable_counter0); + disable_counter0++; + if (disable_counter0 == 0) + { + NVIC_DisableIRQ(APP_M33_A35_MU_IRQn); + } + break; + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_COM_ID: + RL_ASSERT(0 <= disable_counter1); + disable_counter1++; + if (disable_counter1 == 0) + { + NVIC_DisableIRQ(APP_M33_FUSION_DSP_MU_IRQn); + } + break; + case RL_PLATFORM_IMX8ULP_M33_HIFI4_COM_ID: + RL_ASSERT(0 <= disable_counter2); + disable_counter2++; + if (disable_counter2 == 0) + { + NVIC_DisableIRQ(APP_M33_HIFI4_MU_IRQn); + } + break; + default: + /* All the cases have been listed above, the default clause should not be reached. */ + break; + } + platform_global_isr_enable(); + return ((int32_t)vector_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate(void) +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable(void) +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +uintptr_t platform_vatopa(void *addr) +{ + return ((uintptr_t)(char *)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(uintptr_t addr) +{ + return ((void *)(char *)addr); +} + +#if defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) +/** + * platform_get_custom_shmem_config + * + * Provide rpmsg_platform_shmem_config structure for the rpmsg_lite instance initialization + * based on the link_id. + * + * @param link_id Link ID provided by the rpmsg_lite init function + * @param cfg Pointer to the rpmsg_platform_shmem_config structure to be filled + * + * @return Status of function execution, 0 on success. + * + */ +int32_t platform_get_custom_shmem_config(uint32_t link_id, rpmsg_platform_shmem_config_t *cfg) +{ + cfg->buffer_payload_size = RL_BUFFER_PAYLOAD_SIZE(link_id); + cfg->buffer_count = RL_BUFFER_COUNT(link_id); + + switch (link_id) + { + case RL_PLATFORM_IMX8ULP_M33_A35_SRTM_LINK_ID: + case RL_PLATFORM_IMX8ULP_M33_A35_USER_LINK_ID: + cfg->vring_size = RL_VRING_SIZE_M33_A35_COM; + cfg->vring_align = RL_VRING_ALIGN_M33_A35_COM; + break; + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_SRTM_LINK_ID: + case RL_PLATFORM_IMX8ULP_M33_FUSION_DSP_USER_LINK_ID: + cfg->vring_size = RL_VRING_SIZE_M33_FUSION_DSP_COM; + cfg->vring_align = RL_VRING_ALIGN_M33_FUSION_DSP_COM; + break; + case RL_PLATFORM_IMX8ULP_M33_HIFI4_SRTM_LINK_ID: + case RL_PLATFORM_IMX8ULP_M33_HIFI4_USER_LINK_ID: + cfg->vring_size = RL_VRING_SIZE_M33_HIFI4_COM; + cfg->vring_align = RL_VRING_ALIGN_M33_HIFI4_COM; + break; + default: + /* All the cases have been listed above, the default clause should not be reached. */ + break; + } + return 0; +} + +#endif /* defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1) */ + +/** + * platform_init + * + * platform/environment init + */ +int32_t platform_init(void) +{ + /* + * Prepare for the MU Interrupt + * MU must be initialized before rpmsg init is called + */ + MU_Init(APP_M33_A35_MU); + NVIC_SetPriority(APP_M33_A35_MU_IRQn, APP_MU_IRQ_PRIORITY); + NVIC_EnableIRQ(APP_M33_A35_MU_IRQn); + + MU_Init(APP_M33_FUSION_DSP_MU); + NVIC_SetPriority(APP_M33_FUSION_DSP_MU_IRQn, APP_MU_IRQ_PRIORITY); + NVIC_EnableIRQ(APP_M33_FUSION_DSP_MU_IRQn); + + MU_Init(APP_M33_HIFI4_MU); + NVIC_SetPriority(APP_M33_HIFI4_MU_IRQn, APP_MU_IRQ_PRIORITY); + NVIC_EnableIRQ(APP_M33_HIFI4_MU_IRQn); + + /* Create lock used in multi-instanced RPMsg */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (0 != env_create_mutex(&platform_lock, 1, &platform_lock_static_ctxt)) +#else + if (0 != env_create_mutex(&platform_lock, 1)) +#endif + { + return -1; + } + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int32_t platform_deinit(void) +{ + MU_Deinit(APP_M33_A35_MU); + MU_Deinit(APP_M33_FUSION_DSP_MU); + MU_Deinit(APP_M33_HIFI4_MU); + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(platform_lock); + platform_lock = ((void *)0); + return 0; +} diff --git a/lib/rpmsg_lite/porting/platform/imxrt1160/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imxrt1160/rpmsg_platform.c index 786c4b3..d22938e 100644 --- a/lib/rpmsg_lite/porting/platform/imxrt1160/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imxrt1160/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2021 NXP - * All rights reserved. - * + * Copyright 2021-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imxrt1160/rpmsg_platform_zephyr_ipm.c b/lib/rpmsg_lite/porting/platform/imxrt1160/rpmsg_platform_zephyr_ipm.c new file mode 100644 index 0000000..22c9c54 --- /dev/null +++ b/lib/rpmsg_lite/porting/platform/imxrt1160/rpmsg_platform_zephyr_ipm.c @@ -0,0 +1,257 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include + +#include "rpmsg_platform.h" +#include "rpmsg_env.h" +#include + +#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1) +#error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0" +#endif + +static int32_t isr_counter = 0; +static int32_t disable_counter = 0; +static void *platform_lock; +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +static LOCK_STATIC_CONTEXT platform_lock_static_ctxt; +#endif +static const struct device *const ipm_handle = DEVICE_DT_GET(DT_CHOSEN(zephyr_ipc)); + +void platform_ipm_callback(const struct device *dev, void *context, uint32_t id, volatile void *data) +{ + if (((*(uint32_t *)data) & 0x01) != 0UL) + { + env_isr(0); + } + if (((*(uint32_t *)data) & 0x02) != 0UL) + { + env_isr(1); + } +} + +static void platform_global_isr_disable(void) +{ + __asm volatile("cpsid i"); +} + +static void platform_global_isr_enable(void) +{ + __asm volatile("cpsie i"); +} + +int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data) +{ + /* Register ISR to environment layer */ + env_register_isr(vector_id, isr_data); + + env_lock_mutex(platform_lock); + + RL_ASSERT(0 <= isr_counter); + + isr_counter++; + + env_unlock_mutex(platform_lock); + + return 0; +} + +int32_t platform_deinit_interrupt(uint32_t vector_id) +{ + /* Prepare the MU Hardware */ + env_lock_mutex(platform_lock); + + RL_ASSERT(0 < isr_counter); + isr_counter--; + if ((isr_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 0); + } + + /* Unregister ISR from environment layer */ + env_unregister_isr(vector_id); + + env_unlock_mutex(platform_lock); + + return 0; +} + +void platform_notify(uint32_t vector_id) +{ + switch (RL_GET_LINK_ID(vector_id)) + { + case RL_PLATFORM_IMXRT1160_M7_M4_LINK_ID: + env_lock_mutex(platform_lock); + uint32_t data = (1 << RL_GET_Q_ID(vector_id)); + RL_ASSERT(ipm_handle); + ipm_send(ipm_handle, 0, 0, &data, sizeof(uint32_t)); + env_unlock_mutex(platform_lock); + return; + + default: + return; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int32_t platform_in_isr(void) +{ + return (0 != k_is_in_isr()); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_enable(uint32_t vector_id) +{ + RL_ASSERT(0 < disable_counter); + + platform_global_isr_disable(); + disable_counter--; + + if ((disable_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 1); + } + platform_global_isr_enable(); + return ((int32_t)vector_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_disable(uint32_t vector_id) +{ + RL_ASSERT(0 <= disable_counter); + + platform_global_isr_disable(); + /* virtqueues use the same NVIC vector + if counter is set - the interrupts are disabled */ + if ((disable_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 0); + } + + disable_counter++; + platform_global_isr_enable(); + return ((int32_t)vector_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate(void) +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable(void) +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +uintptr_t platform_vatopa(void *addr) +{ + return ((uintptr_t)(char *)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(uintptr_t addr) +{ + return ((void *)(char *)addr); +} + +/** + * platform_init + * + * platform/environment init + */ +int32_t platform_init(void) +{ + /* Get IPM device handle */ + if (!ipm_handle) + { + return -1; + } + + /* Register application callback with no context */ + ipm_register_callback(ipm_handle, platform_ipm_callback, ((void *)0)); + + /* Create lock used in multi-instanced RPMsg */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (0 != env_create_mutex(&platform_lock, 1, &platform_lock_static_ctxt)) +#else + if (0 != env_create_mutex(&platform_lock, 1)) +#endif + { + return -1; + } + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int32_t platform_deinit(void) +{ + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(platform_lock); + platform_lock = ((void *)0); + return 0; +} diff --git a/lib/rpmsg_lite/porting/platform/imxrt1170/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imxrt1170/rpmsg_platform.c index a0490eb..77b1a98 100644 --- a/lib/rpmsg_lite/porting/platform/imxrt1170/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imxrt1170/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2019-2021 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imxrt1170/rpmsg_platform_zephyr_ipm.c b/lib/rpmsg_lite/porting/platform/imxrt1170/rpmsg_platform_zephyr_ipm.c new file mode 100644 index 0000000..8211ea6 --- /dev/null +++ b/lib/rpmsg_lite/porting/platform/imxrt1170/rpmsg_platform_zephyr_ipm.c @@ -0,0 +1,257 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include + +#include "rpmsg_platform.h" +#include "rpmsg_env.h" +#include + +#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1) +#error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0" +#endif + +static int32_t isr_counter = 0; +static int32_t disable_counter = 0; +static void *platform_lock; +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +static LOCK_STATIC_CONTEXT platform_lock_static_ctxt; +#endif +static const struct device *const ipm_handle = DEVICE_DT_GET(DT_CHOSEN(zephyr_ipc)); + +void platform_ipm_callback(const struct device *dev, void *context, uint32_t id, volatile void *data) +{ + if (((*(uint32_t *)data) & 0x01) != 0UL) + { + env_isr(0); + } + if (((*(uint32_t *)data) & 0x02) != 0UL) + { + env_isr(1); + } +} + +static void platform_global_isr_disable(void) +{ + __asm volatile("cpsid i"); +} + +static void platform_global_isr_enable(void) +{ + __asm volatile("cpsie i"); +} + +int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data) +{ + /* Register ISR to environment layer */ + env_register_isr(vector_id, isr_data); + + env_lock_mutex(platform_lock); + + RL_ASSERT(0 <= isr_counter); + + isr_counter++; + + env_unlock_mutex(platform_lock); + + return 0; +} + +int32_t platform_deinit_interrupt(uint32_t vector_id) +{ + /* Prepare the MU Hardware */ + env_lock_mutex(platform_lock); + + RL_ASSERT(0 < isr_counter); + isr_counter--; + if ((isr_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 0); + } + + /* Unregister ISR from environment layer */ + env_unregister_isr(vector_id); + + env_unlock_mutex(platform_lock); + + return 0; +} + +void platform_notify(uint32_t vector_id) +{ + switch (RL_GET_LINK_ID(vector_id)) + { + case RL_PLATFORM_IMXRT1170_M7_M4_LINK_ID: + env_lock_mutex(platform_lock); + uint32_t data = (1 << RL_GET_Q_ID(vector_id)); + RL_ASSERT(ipm_handle); + ipm_send(ipm_handle, 0, 0, &data, sizeof(uint32_t)); + env_unlock_mutex(platform_lock); + return; + + default: + return; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int32_t platform_in_isr(void) +{ + return (0 != k_is_in_isr()); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_enable(uint32_t vector_id) +{ + RL_ASSERT(0 < disable_counter); + + platform_global_isr_disable(); + disable_counter--; + + if ((disable_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 1); + } + platform_global_isr_enable(); + return ((int32_t)vector_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_disable(uint32_t vector_id) +{ + RL_ASSERT(0 <= disable_counter); + + platform_global_isr_disable(); + /* virtqueues use the same NVIC vector + if counter is set - the interrupts are disabled */ + if ((disable_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 0); + } + + disable_counter++; + platform_global_isr_enable(); + return ((int32_t)vector_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate(void) +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable(void) +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +uintptr_t platform_vatopa(void *addr) +{ + return ((uintptr_t)(char *)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(uintptr_t addr) +{ + return ((void *)(char *)addr); +} + +/** + * platform_init + * + * platform/environment init + */ +int32_t platform_init(void) +{ + /* Get IPM device handle */ + if (!ipm_handle) + { + return -1; + } + + /* Register application callback with no context */ + ipm_register_callback(ipm_handle, platform_ipm_callback, ((void *)0)); + + /* Create lock used in multi-instanced RPMsg */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (0 != env_create_mutex(&platform_lock, 1, &platform_lock_static_ctxt)) +#else + if (0 != env_create_mutex(&platform_lock, 1)) +#endif + { + return -1; + } + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int32_t platform_deinit(void) +{ + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(platform_lock); + platform_lock = ((void *)0); + return 0; +} diff --git a/lib/rpmsg_lite/porting/platform/imxrt500_fusionf1/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imxrt500_fusionf1/rpmsg_platform.c index 7ae1ab0..bc37b2e 100644 --- a/lib/rpmsg_lite/porting/platform/imxrt500_fusionf1/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imxrt500_fusionf1/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2019-2021 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imxrt500_m33/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imxrt500_m33/rpmsg_platform.c index 764fcb2..55c15e6 100644 --- a/lib/rpmsg_lite/porting/platform/imxrt500_m33/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imxrt500_m33/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2019-2021 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imxrt600_hifi4/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imxrt600_hifi4/rpmsg_platform.c index 7ae1ab0..bc37b2e 100644 --- a/lib/rpmsg_lite/porting/platform/imxrt600_hifi4/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imxrt600_hifi4/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2019-2021 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/imxrt600_m33/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/imxrt600_m33/rpmsg_platform.c index b2cea30..a6431e4 100644 --- a/lib/rpmsg_lite/porting/platform/imxrt600_m33/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/imxrt600_m33/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2019-2021 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/k32l3a6/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/k32l3a6/rpmsg_platform.c index 26dcfe3..c1b7222 100644 --- a/lib/rpmsg_lite/porting/platform/k32l3a6/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/k32l3a6/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2019-2021 NXP - * All rights reserved. - * + * Copyright 2019-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c b/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c index 45efff8..9c4959e 100644 --- a/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c +++ b/lib/rpmsg_lite/porting/platform/lpc5411x/rpmsg_platform_zephyr_ipm.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2016 Freescale Semiconductor, Inc. - * Copyright 2016-2021 NXP + * Copyright 2016-2023 NXP * All rights reserved. * * @@ -11,7 +11,7 @@ #include "rpmsg_platform.h" #include "rpmsg_env.h" -#include +#include #if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1) #error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0" @@ -23,9 +23,9 @@ static void *platform_lock; #if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) static LOCK_STATIC_CONTEXT platform_lock_static_ctxt; #endif -static struct device *ipm_handle = ((void *)0); +static const struct device *const ipm_handle = DEVICE_DT_GET(DT_CHOSEN(zephyr_ipc)); -void platform_ipm_callback(void *context, u32_t id, volatile void *data) +void platform_ipm_callback(const struct device *dev, void *context, uint32_t id, volatile void *data) { if (((*(uint32_t *)data) & 0x01) != 0UL) { @@ -225,7 +225,6 @@ void *platform_patova(uintptr_t addr) int32_t platform_init(void) { /* Get IPM device handle */ - ipm_handle = device_get_binding(DT_NXP_LPC_MAILBOX_0_LABEL); if (!ipm_handle) { return -1; diff --git a/lib/rpmsg_lite/porting/platform/lpc55s69/rpmsg_platform.c b/lib/rpmsg_lite/porting/platform/lpc55s69/rpmsg_platform.c index d6c6162..df603d5 100644 --- a/lib/rpmsg_lite/porting/platform/lpc55s69/rpmsg_platform.c +++ b/lib/rpmsg_lite/porting/platform/lpc55s69/rpmsg_platform.c @@ -1,7 +1,5 @@ /* - * Copyright 2018-2021 NXP - * All rights reserved. - * + * Copyright 2018-2023 NXP * * SPDX-License-Identifier: BSD-3-Clause */ diff --git a/lib/rpmsg_lite/porting/platform/lpc55s69/rpmsg_platform_zephyr_ipm.c b/lib/rpmsg_lite/porting/platform/lpc55s69/rpmsg_platform_zephyr_ipm.c new file mode 100644 index 0000000..57e2ad4 --- /dev/null +++ b/lib/rpmsg_lite/porting/platform/lpc55s69/rpmsg_platform_zephyr_ipm.c @@ -0,0 +1,257 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include + +#include "rpmsg_platform.h" +#include "rpmsg_env.h" +#include + +#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1) +#error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0" +#endif + +static int32_t isr_counter = 0; +static int32_t disable_counter = 0; +static void *platform_lock; +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) +static LOCK_STATIC_CONTEXT platform_lock_static_ctxt; +#endif +static const struct device *const ipm_handle = DEVICE_DT_GET(DT_CHOSEN(zephyr_ipc)); + +void platform_ipm_callback(const struct device *dev, void *context, uint32_t id, volatile void *data) +{ + if (((*(uint32_t *)data) & 0x01) != 0UL) + { + env_isr(0); + } + if (((*(uint32_t *)data) & 0x02) != 0UL) + { + env_isr(1); + } +} + +static void platform_global_isr_disable(void) +{ + __asm volatile("cpsid i"); +} + +static void platform_global_isr_enable(void) +{ + __asm volatile("cpsie i"); +} + +int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data) +{ + /* Register ISR to environment layer */ + env_register_isr(vector_id, isr_data); + + env_lock_mutex(platform_lock); + + RL_ASSERT(0 <= isr_counter); + + isr_counter++; + + env_unlock_mutex(platform_lock); + + return 0; +} + +int32_t platform_deinit_interrupt(uint32_t vector_id) +{ + /* Prepare the MU Hardware */ + env_lock_mutex(platform_lock); + + RL_ASSERT(0 < isr_counter); + isr_counter--; + if ((isr_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 0); + } + + /* Unregister ISR from environment layer */ + env_unregister_isr(vector_id); + + env_unlock_mutex(platform_lock); + + return 0; +} + +void platform_notify(uint32_t vector_id) +{ + switch (RL_GET_LINK_ID(vector_id)) + { + case RL_PLATFORM_LPC55S69_M33_M33_LINK_ID: + env_lock_mutex(platform_lock); + uint32_t data = (1 << RL_GET_Q_ID(vector_id)); + RL_ASSERT(ipm_handle); + ipm_send(ipm_handle, 0, 0, &data, sizeof(uint32_t)); + env_unlock_mutex(platform_lock); + return; + + default: + return; + } +} + +/** + * platform_in_isr + * + * Return whether CPU is processing IRQ + * + * @return True for IRQ, false otherwise. + * + */ +int32_t platform_in_isr(void) +{ + return (0 != k_is_in_isr()); +} + +/** + * platform_interrupt_enable + * + * Enable peripheral-related interrupt + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_enable(uint32_t vector_id) +{ + RL_ASSERT(0 < disable_counter); + + platform_global_isr_disable(); + disable_counter--; + + if ((disable_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 1); + } + platform_global_isr_enable(); + return ((int32_t)vector_id); +} + +/** + * platform_interrupt_disable + * + * Disable peripheral-related interrupt. + * + * @param vector_id Virtual vector ID that needs to be converted to IRQ number + * + * @return vector_id Return value is never checked. + * + */ +int32_t platform_interrupt_disable(uint32_t vector_id) +{ + RL_ASSERT(0 <= disable_counter); + + platform_global_isr_disable(); + /* virtqueues use the same NVIC vector + if counter is set - the interrupts are disabled */ + if ((disable_counter == 0) && (ipm_handle != ((void *)0))) + { + ipm_set_enabled(ipm_handle, 0); + } + + disable_counter++; + platform_global_isr_enable(); + return ((int32_t)vector_id); +} + +/** + * platform_map_mem_region + * + * Dummy implementation + * + */ +void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags) +{ +} + +/** + * platform_cache_all_flush_invalidate + * + * Dummy implementation + * + */ +void platform_cache_all_flush_invalidate(void) +{ +} + +/** + * platform_cache_disable + * + * Dummy implementation + * + */ +void platform_cache_disable(void) +{ +} + +/** + * platform_vatopa + * + * Dummy implementation + * + */ +uintptr_t platform_vatopa(void *addr) +{ + return ((uintptr_t)(char *)addr); +} + +/** + * platform_patova + * + * Dummy implementation + * + */ +void *platform_patova(uintptr_t addr) +{ + return ((void *)(char *)addr); +} + +/** + * platform_init + * + * platform/environment init + */ +int32_t platform_init(void) +{ + /* Get IPM device handle */ + if (!ipm_handle) + { + return -1; + } + + /* Register application callback with no context */ + ipm_register_callback(ipm_handle, platform_ipm_callback, ((void *)0)); + + /* Create lock used in multi-instanced RPMsg */ +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + if (0 != env_create_mutex(&platform_lock, 1, &platform_lock_static_ctxt)) +#else + if (0 != env_create_mutex(&platform_lock, 1)) +#endif + { + return -1; + } + + return 0; +} + +/** + * platform_deinit + * + * platform/environment deinit process + */ +int32_t platform_deinit(void) +{ + /* Delete lock used in multi-instanced RPMsg */ + env_delete_mutex(platform_lock); + platform_lock = ((void *)0); + return 0; +} diff --git a/tests/01_rpmsg_init/main_core0.c b/tests/01_rpmsg_init/main_core0.c new file mode 100644 index 0000000..c119ccf --- /dev/null +++ b/tests/01_rpmsg_init/main_core0.c @@ -0,0 +1,199 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +uint32_t test_counter = 0; + +void tc_1_rpmsg_init() +{ + struct rpmsg_lite_instance *my_rpmsg; + struct rpmsg_lite_instance rpmsg_ctxt; + int32_t result = 0; + //test platform_init_interrupt() and platform_deinit_interrupt() fail when being called before platform_init() + TEST_ASSERT_MESSAGE(-1 == platform_init_interrupt(0, ((void *)0)), "platform_init_interrupt function failed when being called before platform_init"); + TEST_ASSERT_MESSAGE(-1 == platform_deinit_interrupt(0), "platform_init_interrupt function failed when being called before platform_init"); + + for (test_counter = 0; test_counter < 2; test_counter++) + { +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base+(2*test_counter), SH_MEM_TOTAL_SIZE+(2*test_counter), RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)((uint32_t)RPMSG_LITE_SHMEM_BASE+(2*test_counter)), ((uint32_t)RPMSG_LITE_SHMEM_SIZE+(2*test_counter)), RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + /* incomming interrupt changes state to state_created_channel */ + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + TEST_ASSERT_MESSAGE(1 == rpmsg_lite_is_link_up(my_rpmsg), "rpmsg_lite_is_link_up function failed"); + //increase the branch covergae in platform_init_interrupt/platform_deinit_interrupt + platform_init_interrupt(10, ((void *)0)); + platform_deinit_interrupt(10); + + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "deinit function failed"); + TEST_ASSERT_MESSAGE(RL_SUCCESS != my_rpmsg, "deinit function failed"); + +#ifdef __COVERAGESCANNER__ + /* Calling rpmsg_lite_deinit() twice should fail, tested when RL_ASSERT is off in Coco tests */ + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "repeated deinit function call failed"); +#endif /*__COVERAGESCANNER__*/ + + TEST_ASSERT_MESSAGE(RL_FALSE == rpmsg_lite_is_link_up(my_rpmsg), "link should be down"); + + /* Wait for remote side to re-initialize the rpmsg.*/ + env_sleep_msec(1000); + } + +#ifdef __COVERAGESCANNER__ + /* When RL_ASSERT is off in Coco tests */ + TEST_ASSERT_MESSAGE(-1 == env_deinit(), "env_deinit being called repeatedly failed"); +#endif /*__COVERAGESCANNER__*/ + + /* Test bad args */ + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_is_link_up(RL_NULL), "rpmsg_lite_is_link_up function with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_wait_for_link_up(RL_NULL, RL_BLOCK), "rpmsg_lite_wait_for_link_up function with bad rpmsg_lite_dev param failed"); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + /* Wrong shmem_length param */ + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE/4, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_length param failed"); + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID+1, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_master_init(RL_NULL, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#else + /* Wrong shmem_length param */ + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE/4, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_length param failed"); + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID+1, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_master_init(RL_NULL, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + + /* Wrong rpmsg_lite_instance param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_deinit(RL_NULL), "deinit function with bad rpmsg_lite_instance param failed"); +} + +void tc_2_env_testing() +{ + struct rpmsg_lite_instance my_rpmsg = {0}; + struct virtqueue my_rx_virtqueue = {0}; + struct virtqueue my_tx_virtqueue = {0}; + my_rpmsg.rvq = &my_rx_virtqueue; + my_rpmsg.tvq = &my_tx_virtqueue; + uint32_t *temp1 = env_allocate_memory(sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(RL_NULL != temp1, "env_allocate_memory function failed"); + env_free_memory(temp1); + env_free_memory(RL_NULL); + uint32_t temp2 = 0x11, temp3 = 0x22; + env_memset(&temp2, 0, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp2, "env_memset function failed"); + env_memcpy(&temp3, &temp2, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp3, "env_memcpy function failed"); + char str1[5], str2[5]; + env_strncpy(str1, "abc", 4); + env_strncpy(str2, "ABC", 4); + TEST_ASSERT_MESSAGE(0 < env_strcmp(str1, str2), "env_strcmp function failed"); + TEST_ASSERT_MESSAGE(0 < env_strncmp(str1, str2, 4), "env_strncmp function failed"); + env_mb(); + env_rmb(); + env_wmb(); + TEST_ASSERT_MESSAGE(0 != env_map_vatopa((void*)0x00000010), "env_map_vatopa function failed"); + TEST_ASSERT_MESSAGE(RL_NULL != env_map_patova(0x00000010), "env_map_patova function failed"); + void *mutex = NULL; + //TEST_ASSERT_MESSAGE(-1 == env_create_mutex(&mutex, 100), "env_create_mutex function with bad count param failed"); does not make sense in baremetal +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&mutex, 1, NULL), "env_create_mutex function failed"); +#else + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&mutex, 1), "env_create_mutex function failed"); +#endif + env_lock_mutex(mutex); + env_unlock_mutex(mutex); + env_delete_mutex(mutex); + env_sleep_msec(1); + env_map_memory(temp2, temp3, sizeof(uint32_t), 0); + env_disable_cache(); + //TEST_ASSERT_MESSAGE(0 < env_get_timestamp(), "env_get_timestamp function failed"); + platform_time_delay(1); + //virtqueue_notification testing, reach cases when (vq != VQ_NULL) by calling env_isr(0) after the rpmsg deinitialization + env_isr(0); + //virtqueue_notification testing, reach cases when (vq->callback_fc != VQ_NULL) + env_register_isr(10, my_rpmsg.rvq); + env_isr(10); + env_unregister_isr(10); + //vq_ring_notify_host testing, reach cases when (vq->notify_fc == VQ_NULL) + virtqueue_kick(&my_rx_virtqueue); + //virtqueue_free_static testing, reach cases when (vq == VQ_NULL) + virtqueue_free_static(RL_NULL); + //virtqueue_free_static testing, reach cases when (vq->vq_ring_mem == VQ_NULL) + virtqueue_free_static(my_rpmsg.tvq); +#ifdef __COVERAGESCANNER__ + //Test incorrect access to the isr_table when RL_ASSERT is off in Coco tests + env_register_isr(0xffffffff, RL_NULL); + env_unregister_isr(0xffffffff); + env_isr(0xffffffff); +#endif /*__COVERAGESCANNER__*/ +} + +void run_tests() +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("01_rpmsg_init"); + __coveragescanner_install("01_rpmsg_init.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_rpmsg_init, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_env_testing, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); +} diff --git a/tests/01_rpmsg_init/main_core1.c b/tests/01_rpmsg_init/main_core1.c new file mode 100644 index 0000000..47d6c40 --- /dev/null +++ b/tests/01_rpmsg_init/main_core1.c @@ -0,0 +1,180 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +uint32_t test_counter = 0; + +void tc_1_rpmsg_init() +{ + struct rpmsg_lite_instance *my_rpmsg; + struct rpmsg_lite_instance rpmsg_ctxt; + int32_t result = 0; + + for (test_counter = 0; test_counter < 2; test_counter++) + { +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base+(2*test_counter), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)(RPMSG_LITE_SHMEM_BASE+(2*test_counter)), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + /* incomming interrupt changes state to state_created_channel */ + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + TEST_ASSERT_MESSAGE(1 == rpmsg_lite_is_link_up(my_rpmsg), "rpmsg_lite_is_link_up function failed"); + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "deinit function failed"); + TEST_ASSERT_MESSAGE(RL_SUCCESS != my_rpmsg, "deinit function failed"); + +#ifdef __COVERAGESCANNER__ + /* Calling rpmsg_lite_deinit() twice should fail, tested when RL_ASSERT is off in Coco tests */ + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "repeated deinit function call failed"); +#endif /*__COVERAGESCANNER__*/ + + TEST_ASSERT_MESSAGE(RL_FALSE == rpmsg_lite_is_link_up(my_rpmsg), "link should be down"); + + /* Wait for remote side to re-initialize the rpmsg.*/ + //env_sleep_msec(1000); + } + +#ifdef __COVERAGESCANNER__ + /* When RL_ASSERT is off in Coco tests */ + TEST_ASSERT_MESSAGE(-1 == env_deinit(), "env_deinit being called repeatedly failed"); +#endif /*__COVERAGESCANNER__*/ + + /* Test bad args */ + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_is_link_up(RL_NULL), "rpmsg_lite_is_link_up function with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_wait_for_link_up(RL_NULL, RL_BLOCK), "rpmsg_lite_wait_for_link_up function with bad rpmsg_lite_dev param failed"); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#else + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + + /* Wrong rpmsg_lite_instance param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_deinit(RL_NULL), "deinit function with bad rpmsg_lite_instance param failed"); +} + +void tc_2_env_testing() +{ + uint32_t *temp1 = env_allocate_memory(sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(RL_NULL != temp1, "env_allocate_memory function failed"); + env_free_memory(temp1); + env_free_memory(RL_NULL); + uint32_t temp2 = 0x11, temp3 = 0x22; + env_memset(&temp2, 0, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp2, "env_memset function failed"); + env_memcpy(&temp3, &temp2, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp3, "env_memcpy function failed"); + char str1[5], str2[5]; + env_strncpy(str1, "abc", 4); + env_strncpy(str2, "ABC", 4); + TEST_ASSERT_MESSAGE(0 < env_strcmp(str1, str2), "env_strcmp function failed"); + TEST_ASSERT_MESSAGE(0 < env_strncmp(str1, str2, 4), "env_strncmp function failed"); + env_mb(); + env_rmb(); + env_wmb(); + TEST_ASSERT_MESSAGE(0 != env_map_vatopa((void*)0x00000010), "env_map_vatopa function failed"); + TEST_ASSERT_MESSAGE(RL_NULL != env_map_patova(0x00000010), "env_map_patova function failed"); + void *mutex = NULL; + //TEST_ASSERT_MESSAGE(-1 == env_create_mutex(&mutex, 100), "env_create_mutex function with bad count param failed"); does not make sense in baremetal +#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1) + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&mutex, 1, NULL), "env_create_mutex function failed"); +#else + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&mutex, 1), "env_create_mutex function failed"); +#endif + env_lock_mutex(mutex); + env_unlock_mutex(mutex); + env_delete_mutex(mutex); + env_sleep_msec(1); + env_map_memory(temp2, temp3, sizeof(uint32_t), 0); + env_disable_cache(); + //TEST_ASSERT_MESSAGE(0 < env_get_timestamp(), "env_get_timestamp function failed"); + platform_time_delay(1); +#ifdef __COVERAGESCANNER__ + //Test incorrect access to the isr_table when RL_ASSERT is off in Coco tests + env_register_isr(0xffffffff, RL_NULL); + env_unregister_isr(0xffffffff); + env_isr(0xffffffff); +#endif /*__COVERAGESCANNER__*/ +} + +void run_tests() +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("01_rpmsg_init_sec_core"); + __coveragescanner_install("01_rpmsg_init_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_rpmsg_init, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_env_testing, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); +} diff --git a/tests/01_rpmsg_init/readme.txt b/tests/01_rpmsg_init/readme.txt new file mode 100644 index 0000000..d4e028f --- /dev/null +++ b/tests/01_rpmsg_init/readme.txt @@ -0,0 +1,7 @@ +01_rpmsg_init test suite + + - baremetal project, static allocation used (#define RL_USE_STATIC_API (1) in rpmsg_config.h) + + - check multiple rpmsg initialisation and de-initialisation + - check created default channel and state + - check callbacks \ No newline at end of file diff --git a/tests/01_rpmsg_init_rtos/main_core0.c b/tests/01_rpmsg_init_rtos/main_core0.c new file mode 100644 index 0000000..5073ef7 --- /dev/null +++ b/tests/01_rpmsg_init_rtos/main_core0.c @@ -0,0 +1,223 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +uint32_t test_counter = 0; + +void tc_1_rpmsg_init() +{ + struct rpmsg_lite_instance *my_rpmsg; + int32_t result = 0; + //test platform_init_interrupt() and platform_deinit_interrupt() fail when being called before platform_init() + TEST_ASSERT_MESSAGE(-1 == platform_init_interrupt(0, ((void *)0)), "platform_init_interrupt function failed when being called before platform_init"); + TEST_ASSERT_MESSAGE(-1 == platform_deinit_interrupt(0), "platform_init_interrupt function failed when being called before platform_init"); + + for (test_counter = 0; test_counter < 2; test_counter++) + { +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base+(2*test_counter), SH_MEM_TOTAL_SIZE+(2*test_counter), RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_master_init((void *)((uint32_t)RPMSG_LITE_SHMEM_BASE+(2*test_counter)), ((uint32_t)RPMSG_LITE_SHMEM_SIZE+(2*test_counter)), RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + /* incomming interrupt changes state to state_created_channel */ + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + TEST_ASSERT_MESSAGE(1 == rpmsg_lite_is_link_up(my_rpmsg), "rpmsg_lite_is_link_up function failed"); + //increase the branch covergae in platform_init_interrupt/platform_deinit_interrupt + platform_init_interrupt(10, ((void *)0)); + platform_deinit_interrupt(10); + + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "deinit function failed"); + TEST_ASSERT_MESSAGE(RL_SUCCESS != my_rpmsg, "deinit function failed"); + +#ifdef __COVERAGESCANNER__ + /* Calling rpmsg_lite_deinit() twice should fail, tested when RL_ASSERT is off in Coco tests */ + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "repeated deinit function call failed"); +#endif /*__COVERAGESCANNER__*/ + + TEST_ASSERT_MESSAGE(RL_FALSE == rpmsg_lite_is_link_up(my_rpmsg), "link should be down"); + + /* Wait for remote side to re-initialize the rpmsg.*/ + env_sleep_msec(1000); + } + +#ifdef __COVERAGESCANNER__ + /* When RL_ASSERT is off in Coco tests */ + TEST_ASSERT_MESSAGE(-1 == env_deinit(), "env_deinit being called repeatedly failed"); +#endif /*__COVERAGESCANNER__*/ + + /* Test bad args */ + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_is_link_up(RL_NULL), "rpmsg_lite_is_link_up function with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_wait_for_link_up(RL_NULL, RL_BLOCK), "rpmsg_lite_wait_for_link_up function with bad rpmsg_lite_dev param failed"); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + /* Wrong shmem_length param */ + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE/4, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_length param failed"); + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID+1, + RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_master_init(RL_NULL, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); +#else + /* Wrong shmem_length param */ + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE/4, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_length param failed"); + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID+1, + RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_master_init(RL_NULL, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + + /* Wrong rpmsg_lite_instance param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_deinit(RL_NULL), "deinit function with bad rpmsg_lite_instance param failed"); +} + +void tc_2_env_testing() +{ + struct rpmsg_lite_instance my_rpmsg = {0}; + struct virtqueue my_rx_virtqueue = {0}; + my_rpmsg.rvq = &my_rx_virtqueue; + my_rpmsg.tvq = (struct virtqueue *)env_allocate_memory(sizeof(struct virtqueue)); + env_memset(my_rpmsg.tvq, 0x00, sizeof(struct virtqueue)); +#if defined(SDK_OS_FREE_RTOS) + HeapStats_t xHeapStats; + void *t; + /* static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );*/ + size_t xHeapStructSizeTemp = ( sizeof( uint32_t* ) + sizeof( size_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); +#endif /* SDK_OS_FREE_RTOS */ + + uint32_t *temp1 = env_allocate_memory(sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(RL_NULL != temp1, "env_allocate_memory function failed"); + env_free_memory(temp1); + env_free_memory(RL_NULL); + uint32_t temp2 = 0x11, temp3 = 0x22; + env_memset(&temp2, 0, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp2, "env_memset function failed"); + env_memcpy(&temp3, &temp2, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp3, "env_memcpy function failed"); + char str1[5], str2[5]; + env_strncpy(str1, "abc", 4); + env_strncpy(str2, "ABC", 4); + TEST_ASSERT_MESSAGE(0 < env_strcmp(str1, str2), "env_strcmp function failed"); + TEST_ASSERT_MESSAGE(0 < env_strncmp(str1, str2, 4), "env_strncmp function failed"); + env_mb(); + env_rmb(); + env_wmb(); + TEST_ASSERT_MESSAGE(0 != env_map_vatopa((void*)0x00000010), "env_map_vatopa function failed"); + TEST_ASSERT_MESSAGE(RL_NULL != env_map_patova(0x00000010), "env_map_patova function failed"); + void *mutex = NULL; +#if defined(SDK_OS_FREE_RTOS) + // Simulate out of heap memory cases + // Force env_create_mutex allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - xHeapStructSizeTemp - 1U); + TEST_ASSERT_MESSAGE(-1 == env_create_mutex(&mutex, 1), "env_create_mutex function with no free heap failed"); + env_free_memory(t); +#endif /* SDK_OS_FREE_RTOS */ + + TEST_ASSERT_MESSAGE(-1 == env_create_mutex(&mutex, 100), "env_create_mutex function with bad count param failed"); + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&mutex, 1), "env_create_mutex function failed"); + env_lock_mutex(mutex); + env_unlock_mutex(mutex); + env_delete_mutex(mutex); + TEST_ASSERT_MESSAGE(-1 == env_create_sync_lock(&mutex, 100), "env_create_sync_lock function with bad count param failed"); + TEST_ASSERT_MESSAGE(0 == env_create_sync_lock(&mutex, 1), "env_create_sync_lock function failed"); + env_delete_sync_lock(mutex); + env_delete_sync_lock(RL_NULL); + env_sleep_msec(1); + env_map_memory(temp2, temp3, sizeof(uint32_t), 0); + env_disable_cache(); + TEST_ASSERT_MESSAGE(0 < env_get_timestamp(), "env_get_timestamp function failed"); + void *q = RL_NULL; + //force env_create_queue() call to fail - request to allocate too much memory + TEST_ASSERT_MESSAGE(-1 == env_create_queue(&q, 0xfffe, 0x20), "env_create_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(0 == env_create_queue(&q, 1, sizeof(uint32_t)), "env_create_queue function failed"); + //TEST_ASSERT_MESSAGE(0 == env_put_queue(RL_NULL, &temp2, 0), "env_put_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + TEST_ASSERT_MESSAGE(1 == env_put_queue(q, &temp2, 0), "env_put_queue function failed"); + TEST_ASSERT_MESSAGE(0 == env_put_queue(q, &temp2, 0), "env_put_queue failed when the queue is full"); + TEST_ASSERT_MESSAGE(1 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + //TEST_ASSERT_MESSAGE(0 == env_get_queue(RL_NULL, &temp2, 0), "env_get_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(1 == env_get_queue(q, &temp3, 0), "env_get_queue function failed"); + TEST_ASSERT_MESSAGE(0 == env_get_queue(q, &temp3, 0), "env_get_queue failed when the queue is empty"); + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + env_delete_queue(q); + platform_time_delay(1); + //virtqueue_notification testing, reach cases when (vq != VQ_NULL) by calling env_isr(0) after the rpmsg deinitialization + env_isr(0); + //virtqueue_notification testing, reach cases when (vq->callback_fc != VQ_NULL) + env_register_isr(10, my_rpmsg.rvq); + env_isr(10); + env_unregister_isr(10); + //vq_ring_notify_host testing, reach cases when (vq->notify_fc == VQ_NULL) + virtqueue_kick(&my_rx_virtqueue); + //virtqueue_free testing, reach cases when (vq == VQ_NULL) + virtqueue_free(RL_NULL); + //virtqueue_free testing, reach cases when (vq->vq_ring_mem == VQ_NULL) + virtqueue_free(my_rpmsg.tvq); +#ifdef __COVERAGESCANNER__ + //Test incorrect access to the isr_table when RL_ASSERT is off in Coco tests + env_register_isr(0xffffffff, RL_NULL); + env_unregister_isr(0xffffffff); + env_isr(0xffffffff); +#endif /*__COVERAGESCANNER__*/ +} + +void run_tests() +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("01_rpmsg_init_rtos"); + __coveragescanner_install("01_rpmsg_init_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_rpmsg_init, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_env_testing, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); +} diff --git a/tests/01_rpmsg_init_rtos/main_core1.c b/tests/01_rpmsg_init_rtos/main_core1.c new file mode 100644 index 0000000..6b0ba77 --- /dev/null +++ b/tests/01_rpmsg_init_rtos/main_core1.c @@ -0,0 +1,205 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "assert.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +uint32_t test_counter = 0; + +void tc_1_rpmsg_init() +{ + struct rpmsg_lite_instance *my_rpmsg; + int32_t result = 0; + + for (test_counter = 0; test_counter < 2; test_counter++) + { +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base+(2*test_counter), RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)(RPMSG_LITE_SHMEM_BASE+(2*test_counter)), RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + /* incomming interrupt changes state to state_created_channel */ + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + TEST_ASSERT_MESSAGE(1 == rpmsg_lite_is_link_up(my_rpmsg), "rpmsg_lite_is_link_up function failed"); + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "deinit function failed"); + TEST_ASSERT_MESSAGE(RL_SUCCESS != my_rpmsg, "deinit function failed"); + +#ifdef __COVERAGESCANNER__ + /* Calling rpmsg_lite_deinit() twice should fail, tested when RL_ASSERT is off in Coco tests */ + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "repeated deinit function call failed"); +#endif /*__COVERAGESCANNER__*/ + + TEST_ASSERT_MESSAGE(RL_FALSE == rpmsg_lite_is_link_up(my_rpmsg), "link should be down"); + + /* Wait for remote side to re-initialize the rpmsg.*/ + //env_sleep_msec(1000); + } + +#ifdef __COVERAGESCANNER__ + /* When RL_ASSERT is off in Coco tests */ + TEST_ASSERT_MESSAGE(-1 == env_deinit(), "env_deinit being called repeatedly failed"); +#endif /*__COVERAGESCANNER__*/ + + /* Test bad args */ + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_is_link_up(RL_NULL), "rpmsg_lite_is_link_up function with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_wait_for_link_up(RL_NULL, RL_BLOCK), "rpmsg_lite_wait_for_link_up function with bad rpmsg_lite_dev param failed"); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); +#else + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + + /* Wrong rpmsg_lite_instance param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_deinit(RL_NULL), "deinit function with bad rpmsg_lite_instance param failed"); +} + +void tc_2_env_testing() +{ +#if defined(SDK_OS_FREE_RTOS) + HeapStats_t xHeapStats; + void *t; + /* static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );*/ + size_t xHeapStructSizeTemp = ( sizeof( uint32_t* ) + sizeof( size_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); +#endif /* SDK_OS_FREE_RTOS */ + + uint32_t *temp1 = env_allocate_memory(sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(RL_NULL != temp1, "env_allocate_memory function failed"); + env_free_memory(temp1); + env_free_memory(RL_NULL); + uint32_t temp2 = 0x11, temp3 = 0x22; + env_memset(&temp2, 0, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp2, "env_memset function failed"); + env_memcpy(&temp3, &temp2, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp3, "env_memcpy function failed"); + char str1[5], str2[5]; + env_strncpy(str1, "abc", 4); + env_strncpy(str2, "ABC", 4); + TEST_ASSERT_MESSAGE(0 < env_strcmp(str1, str2), "env_strcmp function failed"); + TEST_ASSERT_MESSAGE(0 < env_strncmp(str1, str2, 4), "env_strncmp function failed"); + env_mb(); + env_rmb(); + env_wmb(); + TEST_ASSERT_MESSAGE(0 != env_map_vatopa((void*)0x00000010), "env_map_vatopa function failed"); + TEST_ASSERT_MESSAGE(RL_NULL != env_map_patova(0x00000010), "env_map_patova function failed"); + void *mutex = NULL; +#if defined(SDK_OS_FREE_RTOS) + // Simulate out of heap memory cases + // Force env_create_mutex allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - xHeapStructSizeTemp - 1U); + TEST_ASSERT_MESSAGE(-1 == env_create_mutex(&mutex, 1), "env_create_mutex function with no free heap failed"); + env_free_memory(t); +#endif /* SDK_OS_FREE_RTOS */ + + TEST_ASSERT_MESSAGE(-1 == env_create_mutex(&mutex, 100), "env_create_mutex function with bad count param failed"); + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&mutex, 1), "env_create_mutex function failed"); + env_lock_mutex(mutex); + env_unlock_mutex(mutex); + env_delete_mutex(mutex); + TEST_ASSERT_MESSAGE(-1 == env_create_sync_lock(&mutex, 100), "env_create_sync_lock function with bad count param failed"); + TEST_ASSERT_MESSAGE(0 == env_create_sync_lock(&mutex, 1), "env_create_sync_lock function failed"); + env_delete_sync_lock(mutex); + env_delete_sync_lock(RL_NULL); + env_sleep_msec(1); + env_map_memory(temp2, temp3, sizeof(uint32_t), 0); + env_disable_cache(); + TEST_ASSERT_MESSAGE(0 < env_get_timestamp(), "env_get_timestamp function failed"); + void *q = RL_NULL; + //force env_create_queue() call to fail - request to allocate too much memory + TEST_ASSERT_MESSAGE(-1 == env_create_queue(&q, 0xfffe, 0x20), "env_create_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(0 == env_create_queue(&q, 1, sizeof(uint32_t)), "env_create_queue function failed"); + //TEST_ASSERT_MESSAGE(0 == env_put_queue(RL_NULL, &temp2, 0), "env_put_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + TEST_ASSERT_MESSAGE(1 == env_put_queue(q, &temp2, 0), "env_put_queue function failed"); + TEST_ASSERT_MESSAGE(0 == env_put_queue(q, &temp2, 0), "env_put_queue failed when the queue is full"); + TEST_ASSERT_MESSAGE(1 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + //TEST_ASSERT_MESSAGE(0 == env_get_queue(RL_NULL, &temp2, 0), "env_get_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(1 == env_get_queue(q, &temp3, 0), "env_get_queue function failed"); + TEST_ASSERT_MESSAGE(0 == env_get_queue(q, &temp3, 0), "env_get_queue failed when the queue is empty"); + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + env_delete_queue(q); + platform_time_delay(1); +#ifdef __COVERAGESCANNER__ + //Test incorrect access to the isr_table when RL_ASSERT is off in Coco tests + env_register_isr(0xffffffff, RL_NULL); + env_unregister_isr(0xffffffff); + env_isr(0xffffffff); +#endif /*__COVERAGESCANNER__*/ +} + +void run_tests() +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("01_rpmsg_init_rtos_sec_core"); + __coveragescanner_install("01_rpmsg_init_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_rpmsg_init, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_env_testing, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); +} diff --git a/tests/01_rpmsg_init_rtos/main_static_alloc_core0.c b/tests/01_rpmsg_init_rtos/main_static_alloc_core0.c new file mode 100644 index 0000000..3661358 --- /dev/null +++ b/tests/01_rpmsg_init_rtos/main_static_alloc_core0.c @@ -0,0 +1,215 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +uint32_t test_counter = 0; + +void tc_1_rpmsg_init() +{ + struct rpmsg_lite_instance *my_rpmsg; + struct rpmsg_lite_instance rpmsg_ctxt; + int32_t result = 0; + //test platform_init_interrupt() and platform_deinit_interrupt() fail when being called before platform_init() + TEST_ASSERT_MESSAGE(-1 == platform_init_interrupt(0, ((void *)0)), "platform_init_interrupt function failed when being called before platform_init"); + TEST_ASSERT_MESSAGE(-1 == platform_deinit_interrupt(0), "platform_init_interrupt function failed when being called before platform_init"); + + for (test_counter = 0; test_counter < 2; test_counter++) + { +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base+(2*test_counter), SH_MEM_TOTAL_SIZE+(2*test_counter), RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)((uint32_t)RPMSG_LITE_SHMEM_BASE+(2*test_counter)), ((uint32_t)RPMSG_LITE_SHMEM_SIZE+(2*test_counter)), RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + /* incomming interrupt changes state to state_created_channel */ + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + //increase the branch covergae in platform_init_interrupt/platform_deinit_interrupt + platform_init_interrupt(10, ((void *)0)); + platform_deinit_interrupt(10); + + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "deinit function failed"); + TEST_ASSERT_MESSAGE(RL_SUCCESS != my_rpmsg, "deinit function failed"); + +#ifdef __COVERAGESCANNER__ + /* Calling rpmsg_lite_deinit() twice should fail, tested when RL_ASSERT is off in Coco tests */ + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "repeated deinit function call failed"); +#endif /*__COVERAGESCANNER__*/ + + TEST_ASSERT_MESSAGE(RL_FALSE == rpmsg_lite_is_link_up(my_rpmsg), "link should be down"); + + /* Wait for remote side to re-initialize the rpmsg.*/ + env_sleep_msec(1000); + } + +#ifdef __COVERAGESCANNER__ + /* When RL_ASSERT is off in Coco tests */ + TEST_ASSERT_MESSAGE(-1 == env_deinit(), "env_deinit being called repeatedly failed"); +#endif /*__COVERAGESCANNER__*/ + + /* Test bad args */ + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_is_link_up(RL_NULL), "rpmsg_lite_is_link_up function with bad rpmsg_lite_dev param failed"); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + /* Wrong shmem_length param */ + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE/4, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_length param failed"); + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID+1, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_master_init(RL_NULL, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#else + /* Wrong shmem_length param */ + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE/4, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_length param failed"); + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID+1, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_master_init(RL_NULL, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + + /* Wrong rpmsg_lite_instance param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_deinit(RL_NULL), "deinit function with bad rpmsg_lite_instance param failed"); +} + +void tc_2_env_testing() +{ + LOCK_STATIC_CONTEXT mutex_ctxt = {0}; + rpmsg_static_queue_ctxt queue_ctxt = {0}; + uint8_t my_rpmsg_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE]; + struct rpmsg_lite_instance my_rpmsg = {0}; + struct virtqueue my_rx_virtqueue = {0}; + struct virtqueue my_tx_virtqueue = {0}; + my_rpmsg.rvq = &my_rx_virtqueue; + my_rpmsg.tvq = &my_tx_virtqueue; + //uint32_t *temp1 = env_allocate_memory(sizeof(uint32_t)); + //TEST_ASSERT_MESSAGE(RL_NULL != temp1, "env_allocate_memory function failed"); + //env_free_memory(temp1); + //env_free_memory(RL_NULL); + uint32_t temp2 = 0x11, temp3 = 0x22; + env_memset(&temp2, 0, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp2, "env_memset function failed"); + env_memcpy(&temp3, &temp2, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp3, "env_memcpy function failed"); + char str1[5], str2[5]; + env_strncpy(str1, "abc", 4); + env_strncpy(str2, "ABC", 4); + TEST_ASSERT_MESSAGE(0 < env_strcmp(str1, str2), "env_strcmp function failed"); + TEST_ASSERT_MESSAGE(0 < env_strncmp(str1, str2, 4), "env_strncmp function failed"); + env_mb(); + env_rmb(); + env_wmb(); + TEST_ASSERT_MESSAGE(0 != env_map_vatopa((void*)0x00000010), "env_map_vatopa function failed"); + TEST_ASSERT_MESSAGE(RL_NULL != env_map_patova(0x00000010), "env_map_patova function failed"); + void *mutex = NULL; + TEST_ASSERT_MESSAGE(-1 == env_create_mutex(&mutex, 100, &mutex_ctxt), "env_create_mutex function with bad count param failed"); + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&mutex, 1, &mutex_ctxt), "env_create_mutex function failed"); + env_lock_mutex(mutex); + env_unlock_mutex(mutex); + env_delete_mutex(mutex); + TEST_ASSERT_MESSAGE(-1 == env_create_sync_lock(&mutex, 100, &mutex_ctxt), "env_create_sync_lock function with bad count param failed"); + TEST_ASSERT_MESSAGE(0 == env_create_sync_lock(&mutex, 1, &mutex_ctxt), "env_create_sync_lock function failed"); + env_delete_sync_lock(mutex); + env_delete_sync_lock(RL_NULL); + env_sleep_msec(1); + env_map_memory(temp2, temp3, sizeof(uint32_t), 0); + env_disable_cache(); + TEST_ASSERT_MESSAGE(0 < env_get_timestamp(), "env_get_timestamp function failed"); + void *q = RL_NULL; + TEST_ASSERT_MESSAGE(0 == env_create_queue(&q, 1, sizeof(uint32_t), &my_rpmsg_queue_storage[0], &queue_ctxt), "env_create_queue function failed"); + //TEST_ASSERT_MESSAGE(0 == env_put_queue(RL_NULL, &temp2, 0), "env_put_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + TEST_ASSERT_MESSAGE(1 == env_put_queue(q, &temp2, 0), "env_put_queue function failed"); + TEST_ASSERT_MESSAGE(0 == env_put_queue(q, &temp2, 0), "env_put_queue failed when the queue is full"); + TEST_ASSERT_MESSAGE(1 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + //TEST_ASSERT_MESSAGE(0 == env_get_queue(RL_NULL, &temp2, 0), "env_get_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(1 == env_get_queue(q, &temp3, 0), "env_get_queue function failed"); + TEST_ASSERT_MESSAGE(0 == env_get_queue(q, &temp3, 0), "env_get_queue failed when the queue is empty"); + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + env_delete_queue(q); + platform_time_delay(1); + //virtqueue_notification testing, reach cases when (vq != VQ_NULL) by calling env_isr(0) after the rpmsg deinitialization + env_isr(0); + //virtqueue_notification testing, reach cases when (vq->callback_fc != VQ_NULL) + env_register_isr(10, my_rpmsg.rvq); + env_isr(10); + env_unregister_isr(10); + //vq_ring_notify_host testing, reach cases when (vq->notify_fc == VQ_NULL) + virtqueue_kick(&my_rx_virtqueue); + //virtqueue_free_static testing, reach cases when (vq == VQ_NULL) + virtqueue_free_static(RL_NULL); + //virtqueue_free_static testing, reach cases when (vq->vq_ring_mem == VQ_NULL) + virtqueue_free_static(my_rpmsg.tvq); +#ifdef __COVERAGESCANNER__ + //Test incorrect access to the isr_table when RL_ASSERT is off in Coco tests + env_register_isr(0xffffffff, RL_NULL); + env_unregister_isr(0xffffffff); + env_isr(0xffffffff); +#endif /*__COVERAGESCANNER__*/ +} + +void run_tests() +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("01_rpmsg_init_rtos"); + __coveragescanner_install("01_rpmsg_init_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_rpmsg_init, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_env_testing, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); +} diff --git a/tests/01_rpmsg_init_rtos/main_static_alloc_core1.c b/tests/01_rpmsg_init_rtos/main_static_alloc_core1.c new file mode 100644 index 0000000..f614737 --- /dev/null +++ b/tests/01_rpmsg_init_rtos/main_static_alloc_core1.c @@ -0,0 +1,198 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "assert.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +uint32_t test_counter = 0; + +void tc_1_rpmsg_init() +{ + struct rpmsg_lite_instance *my_rpmsg; + struct rpmsg_lite_instance rpmsg_ctxt; + int32_t result = 0; + + for (test_counter = 0; test_counter < 2; test_counter++) + { +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base+(2*test_counter), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)(RPMSG_LITE_SHMEM_BASE+(2*test_counter)), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + /* incomming interrupt changes state to state_created_channel */ + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "deinit function failed"); + TEST_ASSERT_MESSAGE(RL_SUCCESS != my_rpmsg, "deinit function failed"); + +#ifdef __COVERAGESCANNER__ + /* Calling rpmsg_lite_deinit() twice should fail, tested when RL_ASSERT is off in Coco tests */ + result = rpmsg_lite_deinit(my_rpmsg); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "repeated deinit function call failed"); +#endif /*__COVERAGESCANNER__*/ + + TEST_ASSERT_MESSAGE(RL_FALSE == rpmsg_lite_is_link_up(my_rpmsg), "link should be down"); + + /* Wait for remote side to re-initialize the rpmsg.*/ + //env_sleep_msec(1000); + } + +#ifdef __COVERAGESCANNER__ + /* When RL_ASSERT is off in Coco tests */ + TEST_ASSERT_MESSAGE(-1 == env_deinit(), "env_deinit being called repeatedly failed"); +#endif /*__COVERAGESCANNER__*/ + + /* Test bad args */ + TEST_ASSERT_MESSAGE(0 == rpmsg_lite_is_link_up(RL_NULL), "rpmsg_lite_is_link_up function with bad rpmsg_lite_dev param failed"); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#else + /* Wrong link_id param */ + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID+1, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad link_id param failed"); + /* Wrong shmem_addr param */ + my_rpmsg = rpmsg_lite_remote_init(RL_NULL, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad shmem_addr param failed"); + /* Wrong static_context param */ + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "init function with bad static_context param failed"); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + + /* Wrong rpmsg_lite_instance param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_deinit(RL_NULL), "deinit function with bad rpmsg_lite_instance param failed"); +} + +void tc_2_env_testing() +{ + LOCK_STATIC_CONTEXT mutex_ctxt = {0}; + rpmsg_static_queue_ctxt queue_ctxt = {0}; + uint8_t my_rpmsg_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE]; + //uint32_t *temp1 = env_allocate_memory(sizeof(uint32_t)); + //TEST_ASSERT_MESSAGE(RL_NULL != temp1, "env_allocate_memory function failed"); + //env_free_memory(temp1); + //env_free_memory(RL_NULL); + uint32_t temp2 = 0x11, temp3 = 0x22; + env_memset(&temp2, 0, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp2, "env_memset function failed"); + env_memcpy(&temp3, &temp2, sizeof(uint32_t)); + TEST_ASSERT_MESSAGE(0 == temp3, "env_memcpy function failed"); + char str1[5], str2[5]; + env_strncpy(str1, "abc", 4); + env_strncpy(str2, "ABC", 4); + TEST_ASSERT_MESSAGE(0 < env_strcmp(str1, str2), "env_strcmp function failed"); + TEST_ASSERT_MESSAGE(0 < env_strncmp(str1, str2, 4), "env_strncmp function failed"); + env_mb(); + env_rmb(); + env_wmb(); + TEST_ASSERT_MESSAGE(0 != env_map_vatopa((void*)0x00000010), "env_map_vatopa function failed"); + TEST_ASSERT_MESSAGE(RL_NULL != env_map_patova(0x00000010), "env_map_patova function failed"); + void *mutex = NULL; + TEST_ASSERT_MESSAGE(-1 == env_create_mutex(&mutex, 100, &mutex_ctxt), "env_create_mutex function with bad count param failed"); + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&mutex, 1, &mutex_ctxt), "env_create_mutex function failed"); + env_lock_mutex(mutex); + env_unlock_mutex(mutex); + env_delete_mutex(mutex); + TEST_ASSERT_MESSAGE(-1 == env_create_sync_lock(&mutex, 100, &mutex_ctxt), "env_create_sync_lock function with bad count param failed"); + TEST_ASSERT_MESSAGE(0 == env_create_sync_lock(&mutex, 1, &mutex_ctxt), "env_create_sync_lock function failed"); + env_delete_sync_lock(mutex); + env_delete_sync_lock(RL_NULL); + env_sleep_msec(1); + env_map_memory(temp2, temp3, sizeof(uint32_t), 0); + env_disable_cache(); + TEST_ASSERT_MESSAGE(0 < env_get_timestamp(), "env_get_timestamp function failed"); + void *q = RL_NULL; + TEST_ASSERT_MESSAGE(0 == env_create_queue(&q, 1, sizeof(uint32_t), &my_rpmsg_queue_storage[0], &queue_ctxt), "env_create_queue function failed"); + //TEST_ASSERT_MESSAGE(0 == env_put_queue(RL_NULL, &temp2, 0), "env_put_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + TEST_ASSERT_MESSAGE(1 == env_put_queue(q, &temp2, 0), "env_put_queue function failed"); + TEST_ASSERT_MESSAGE(0 == env_put_queue(q, &temp2, 0), "env_put_queue failed when the queue is full"); + TEST_ASSERT_MESSAGE(1 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + //TEST_ASSERT_MESSAGE(0 == env_get_queue(RL_NULL, &temp2, 0), "env_get_queue function with bad params failed"); + TEST_ASSERT_MESSAGE(1 == env_get_queue(q, &temp3, 0), "env_get_queue function failed"); + TEST_ASSERT_MESSAGE(0 == env_get_queue(q, &temp3, 0), "env_get_queue failed when the queue is empty"); + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)q), "env_get_current_queue_size function failed"); + env_delete_queue(q); + platform_time_delay(1); +#ifdef __COVERAGESCANNER__ + //Test incorrect access to the isr_table when RL_ASSERT is off in Coco tests + env_register_isr(0xffffffff, RL_NULL); + env_unregister_isr(0xffffffff); + env_isr(0xffffffff); +#endif /*__COVERAGESCANNER__*/ +} + +void run_tests() +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("01_rpmsg_init_rtos_sec_core"); + __coveragescanner_install("01_rpmsg_init_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_rpmsg_init, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_env_testing, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); +} diff --git a/tests/01_rpmsg_init_rtos/readme.txt b/tests/01_rpmsg_init_rtos/readme.txt new file mode 100644 index 0000000..c2a0d3e --- /dev/null +++ b/tests/01_rpmsg_init_rtos/readme.txt @@ -0,0 +1,5 @@ +01_rpmsg_init_rtos test suite + + - FreeRTOS/ThreadX/XOS-based project, covering both the static allocation (#define RL_USE_STATIC_API (1) in rpmsg_config.h) and the dynamic allocation (#define RL_USE_STATIC_API (0) in rpmsg_config.h) + + - check multiple rpmsg rtos initialisation and de-initialisation \ No newline at end of file diff --git a/tests/02_epts_channels/main_core0.c b/tests/02_epts_channels/main_core0.c new file mode 100644 index 0000000..84c1d4a --- /dev/null +++ b/tests/02_epts_channels/main_core0.c @@ -0,0 +1,212 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "assert.h" +#include "app.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_INIT_COUNT 24 +#define TC_TRANSFER_COUNT 10 +#define TC_EPT_COUNT 3 +#define TC_LOCAL_EPT_ADDR (40) +#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +volatile int32_t message_received = 0; +int32_t trans_data = 0; +uint32_t trans_src = 0; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt; + +// custom ept callback +int32_t ept_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) +{ + TEST_ASSERT_MESSAGE(0 == message_received, "interrupt miss"); + trans_data = *((int32_t *)payload); + trans_src = src; + message_received = 1; + + return RL_RELEASE; /* let RPMsg lite know it can free the received data */ +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); + env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(struct rpmsg_lite_endpoint *volatile epts[], + int32_t count, + int32_t init_addr, + struct rpmsg_lite_ept_static_context ctxts[]) +{ + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, ept_cb, NULL, &ctxts[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_create_ept(RL_NULL, init_addr, ept_cb, NULL, &ctxts[0]), "'rpmsg_lite_create_ept' with bad rpmsg_lite_dev param failed"); + /* Wrong ept_context param */ + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_create_ept(my_rpmsg, init_addr + count, ept_cb, NULL, RL_NULL), "'rpmsg_lite_create_ept' with bad ept_context param failed"); + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + TEST_ASSERT_MESSAGE(count >= 3, "increase the TC_EPT_COUNT to be at least 3"); + + //use different sequence of EP destroy to cover the case when EP is removed from the intermediate element of the EP linked list + rpmsg_lite_destroy_ept(my_rpmsg, epts[1]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[0]); + for (int32_t i = 2; i < count; i++) + { + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + /* Destroying an endpoint again when all endpoints are already destroyed */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, epts[0]), "'rpmsg_lite_destroy_ept' being called when all endpoints are alrady destroyed failed"); + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(RL_NULL, epts[0]), "'rpmsg_lite_destroy_ept' with bad rpmsg_lite_dev param failed"); + /* Wrong rl_ept param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, RL_NULL), "'rpmsg_lite_destroy_ept' with bad rl_ept param failed"); + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between default epts of default channels + * - verify create/delete/recreation of epts with same address + * - verify simple transport between custom created epts of default channels + *****************************************************************************/ +void tc_1_defchnl_transport_send(struct rpmsg_lite_endpoint *src, int32_t dst, int32_t send_value, int32_t expected_value) +{ + void *mutex = NULL; + int32_t result = 0; + result = env_create_mutex(&mutex, 1, NULL); + TEST_ASSERT_MESSAGE(0 == result, "unexpected value"); + result = rpmsg_lite_send(my_rpmsg, src, dst, (char *)&send_value, sizeof(send_value), RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "send failed"); + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + TEST_ASSERT_MESSAGE(trans_data == expected_value, "unexpected value"); + env_unlock_mutex(mutex); + env_delete_mutex(mutex); +} + +void tc_1_defchnl_transport(void) +{ + struct rpmsg_lite_endpoint *volatile epts[TC_EPT_COUNT] = {0}; + struct rpmsg_lite_ept_static_context epts_ctxts[TC_EPT_COUNT]; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + // create custom epts of default channel, check nonrecoverable error + result = ts_create_epts(epts, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR, epts_ctxts); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + // transfer data through custom epts + for (int32_t j = 0; j < TC_TRANSFER_COUNT; j++) + { + for (int32_t i = 0; i < TC_EPT_COUNT; i++) + { + // remote has custom epts with the different *address* + // send data between custom epts with different *address* + tc_1_defchnl_transport_send(epts[i], // src addr + TC_REMOTE_EPT_ADDR + i, // dst addr + i, // value to send + i + 10 // expected value to receive + ); + } + } + +end1: + result = ts_destroy_epts(epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl(void) +{ + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_transport(); + } +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("02_epts_channels"); + __coveragescanner_install("02_epts_channels.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_defchnl, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/02_epts_channels/main_core1.c b/tests/02_epts_channels/main_core1.c new file mode 100644 index 0000000..dc5df40 --- /dev/null +++ b/tests/02_epts_channels/main_core1.c @@ -0,0 +1,214 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "assert.h" +#include "app.h" + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_INIT_COUNT 24 +#define TC_TRANSFER_COUNT 10 +#define TC_EPT_COUNT 3 +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +volatile int32_t message_received = 0; +int32_t trans_data = 0; +uint32_t trans_src = 0; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt; + +// custom ept callback +int32_t ept_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) +{ + TEST_ASSERT_MESSAGE(0 == message_received, "interrupt miss"); + trans_data = *((int32_t *)payload); + trans_src = src; + message_received = 1; + + return RL_RELEASE; /* let RPMsg lite know it can free the received data */ +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(struct rpmsg_lite_endpoint *volatile epts[], + int32_t count, + int32_t init_addr, + struct rpmsg_lite_ept_static_context ctxts[]) +{ + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, ept_cb, NULL, &ctxts[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_create_ept(RL_NULL, init_addr, ept_cb, NULL, &ctxts[0]), "'rpmsg_lite_create_ept' with bad rpmsg_lite_dev param failed"); + /* Wrong ept_context param */ + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_create_ept(my_rpmsg, init_addr + count, ept_cb, NULL, RL_NULL), "'rpmsg_lite_create_ept' with bad ept_context param failed"); + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + TEST_ASSERT_MESSAGE(count >= 3, "increase the TC_EPT_COUNT to be at least 3"); + + //use different sequence of EP destroy to cover the case when EP is removed from the intermediate element of the EP linked list + rpmsg_lite_destroy_ept(my_rpmsg, epts[1]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[0]); + for (int32_t i = 2; i < count; i++) + { + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(RL_NULL, epts[0]), "'rpmsg_lite_destroy_ept' with bad rpmsg_lite_dev param failed"); + /* Wrong rl_ept param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, RL_NULL), "'rpmsg_lite_destroy_ept' with bad rl_ept param failed"); + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between default epts of default channels + * - verify create/delete/recreation of epts with same address + * - verify simple transport between custom created epts of default channels + *****************************************************************************/ +void tc_1_defchnl_transport_receive(struct rpmsg_lite_endpoint *src, int32_t dst, int32_t reply_value, int32_t expected_value) +{ + void *mutex = NULL; + int32_t result = 0; + result = env_create_mutex(&mutex, 1, NULL); + TEST_ASSERT_MESSAGE(0 == result, "unexpected value"); + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + TEST_ASSERT_MESSAGE(trans_data == expected_value, "unexpected value"); + TEST_ASSERT_MESSAGE(src != NULL, "src is NULL"); + result = rpmsg_lite_send(my_rpmsg, src, dst, (char *)&reply_value, sizeof(trans_data), RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "send failed"); + env_unlock_mutex(mutex); + env_delete_mutex(mutex); +} + +void tc_1_defchnl_transport(void) +{ + struct rpmsg_lite_endpoint *volatile epts[TC_EPT_COUNT] = {0}; + struct rpmsg_lite_ept_static_context epts_ctxts[TC_EPT_COUNT]; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + // create custom epts of default channel, check nonrecoverable error + result = ts_create_epts(epts, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR, epts_ctxts); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // transfer data through custom epts + for (int32_t j = 0; j < TC_TRANSFER_COUNT; j++) + { + for (int32_t i = 0; i < TC_EPT_COUNT; i++) + { + // receive message and reply + tc_1_defchnl_transport_receive(epts[i], // src ept + TC_REMOTE_EPT_ADDR + i, // dst addr + i + 10, // value to reply + i // expected value to receive + ); + } + } + +end1: + result = ts_destroy_epts(epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl(void) +{ + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_transport(); + } +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("02_epts_channels_sec_core"); + __coveragescanner_install("02_epts_channels_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_defchnl, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/02_epts_channels/readme.txt b/tests/02_epts_channels/readme.txt new file mode 100644 index 0000000..9092371 --- /dev/null +++ b/tests/02_epts_channels/readme.txt @@ -0,0 +1,6 @@ +02_epts_channels test suite + + - baremetal project, static allocation used (#define RL_USE_STATIC_API (1) in rpmsg_config.h) + + - send user data through default channel + - create several custom epts and send data through them \ No newline at end of file diff --git a/tests/02_epts_channels_rtos/main_core0.c b/tests/02_epts_channels_rtos/main_core0.c new file mode 100644 index 0000000..7740ba8 --- /dev/null +++ b/tests/02_epts_channels_rtos/main_core0.c @@ -0,0 +1,322 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "rpmsg_queue.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_INIT_COUNT 10 +#define TC_TRANSFER_COUNT 10 +#define TC_EPT_COUNT 3 +#define TC_LOCAL_EPT_ADDR (40) +#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *default_ept; +rpmsg_queue_handle default_queue; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); + env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count, int32_t init_addr) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + queues[i] = rpmsg_queue_create(my_rpmsg); + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, rpmsg_queue_rx_cb, queues[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_create_ept(RL_NULL, init_addr, rpmsg_queue_rx_cb, NULL), "'rpmsg_lite_create_ept' with bad rpmsg_lite_dev param failed"); + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + TEST_ASSERT_MESSAGE(count >= 3, "increase the TC_EPT_COUNT to be at least 3"); + + //use different sequence of EP destroy to cover the case when EP is removed from the intermediate element of the EP linked list + rpmsg_queue_destroy(my_rpmsg, queues[1]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[1]); + rpmsg_queue_destroy(my_rpmsg, queues[0]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[0]); + for (int32_t i = 2; i < count; i++) + { + rpmsg_queue_destroy(my_rpmsg, queues[i]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + /* Destroying an endpoint again when all endpoints are already destroyed */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, epts[0]), "'rpmsg_lite_destroy_ept' being called when all endpoints are alrady destroyed failed"); + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(RL_NULL, epts[0]), "'rpmsg_lite_destroy_ept' with bad rpmsg_lite_dev param failed"); + /* Wrong rl_ept param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, RL_NULL), "'rpmsg_lite_destroy_ept' with bad rl_ept param failed"); + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between default epts of default channels + * - verify simple nocopy transport between default epts of default channels + * - verify simple transport between custom created epts of default channels + * - verify simple nocopy transport between custom created epts of default channels + *****************************************************************************/ +void tc_1_defchnl_1(void) +{ + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(&default_queue, &default_ept, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + int32_t received = 0, send = i; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_lite_send(my_rpmsg, default_ept, TC_REMOTE_EPT_ADDR, (char *)&send, sizeof(send), RL_BLOCK); + rpmsg_queue_recv(my_rpmsg, default_queue, &remote_addr, (char *)&received, sizeof(received), &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(received == i + 10, "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(send), "'rpmsg_queue_recv' failed"); + } + +end1: + result = rpmsg_queue_destroy(my_rpmsg, default_queue); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_queue_destroy' failed"); + result = rpmsg_lite_destroy_ept(my_rpmsg, default_ept); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_lite_destroy_ept' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_2(void) +{ + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(&default_queue, &default_ept, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + int32_t *received = NULL, send = i; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_lite_send(my_rpmsg, default_ept, TC_REMOTE_EPT_ADDR, (char *)&send, sizeof(send), RL_BLOCK); + rpmsg_queue_recv_nocopy(my_rpmsg, default_queue, &remote_addr, (char **)&received, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(*received == i + 10, "'rpmsg_queue_recv_nocopy' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(send), "'rpmsg_queue_recv_nocopy' failed"); + rpmsg_queue_nocopy_free(my_rpmsg, received); + } + +end1: + result = rpmsg_queue_destroy(my_rpmsg, default_queue); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_queue_destroy' failed"); + result = rpmsg_lite_destroy_ept(my_rpmsg, default_ept); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_lite_destroy_ept' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_3(void) +{ + struct rpmsg_lite_endpoint *volatile epts[TC_EPT_COUNT] = {0}; + rpmsg_queue_handle queues[TC_EPT_COUNT] = {0}; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(queues, epts, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + for (int32_t j = 0; j < TC_EPT_COUNT; j++) + { + int32_t received = 0, send = 0; + uint32_t len = 0; + send = 0; + uint32_t remote_addr = 0; + rpmsg_lite_send(my_rpmsg, epts[j], TC_REMOTE_EPT_ADDR + j, (char *)&send, sizeof(send), RL_BLOCK); + rpmsg_queue_recv(my_rpmsg, queues[j], &remote_addr, (char *)&received, sizeof(received), &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(received == send + 10, "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(remote_addr == (TC_REMOTE_EPT_ADDR + j), "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_queue_recv' failed"); + } + } + +end1: + result = ts_destroy_epts(queues, epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_4(void) +{ + struct rpmsg_lite_endpoint *epts[TC_EPT_COUNT] = {0}; + rpmsg_queue_handle queues[TC_EPT_COUNT] = {0}; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(queues, epts, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + for (int32_t j = 0; j < TC_EPT_COUNT; j++) + { + int32_t *received = NULL, send = 0; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_lite_send(my_rpmsg, epts[j], TC_REMOTE_EPT_ADDR + j, (char *)&send, sizeof(send), RL_BLOCK); + rpmsg_queue_recv_nocopy(my_rpmsg, queues[j], &remote_addr, (char **)&received, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(*received == send + 10, "'rpmsg_rtos_recv' failed"); + TEST_ASSERT_MESSAGE(remote_addr == (TC_REMOTE_EPT_ADDR + j), "'rpmsg_rtos_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_rtos_recv' failed"); + rpmsg_queue_nocopy_free(my_rpmsg, received); + } + } + +end1: + result = ts_destroy_epts(queues, epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl(void) +{ + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_1(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_2(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_3(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_4(); + } +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("02_epts_channels_rtos"); + __coveragescanner_install("02_epts_channels_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_defchnl, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/02_epts_channels_rtos/main_core1.c b/tests/02_epts_channels_rtos/main_core1.c new file mode 100644 index 0000000..33dc71e --- /dev/null +++ b/tests/02_epts_channels_rtos/main_core1.c @@ -0,0 +1,320 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "rpmsg_queue.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_INIT_COUNT 10 +#define TC_TRANSFER_COUNT 10 +#define TC_EPT_COUNT 3 +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *default_ept; +rpmsg_queue_handle default_queue; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count, int32_t init_addr) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + queues[i] = rpmsg_queue_create(my_rpmsg); + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, rpmsg_queue_rx_cb, queues[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_create_ept(RL_NULL, init_addr, rpmsg_queue_rx_cb, NULL), "'rpmsg_lite_create_ept' with bad rpmsg_lite_dev param failed"); + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + TEST_ASSERT_MESSAGE(count >= 3, "increase the TC_EPT_COUNT to be at least 3"); + + //use different sequence of EP destroy to cover the case when EP is removed from the intermediate element of the EP linked list + rpmsg_queue_destroy(my_rpmsg, queues[1]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[1]); + rpmsg_queue_destroy(my_rpmsg, queues[0]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[0]); + for (int32_t i = 2; i < count; i++) + { + rpmsg_queue_destroy(my_rpmsg, queues[i]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(RL_NULL, epts[0]), "'rpmsg_lite_destroy_ept' with bad rpmsg_lite_dev param failed"); + /* Wrong rl_ept param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, RL_NULL), "'rpmsg_lite_destroy_ept' with bad rl_ept param failed"); + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between default epts of default channels + * - verify simple nocopy transport between default epts of default channels + * - verify simple transport between custom created epts of default channels + * - verify simple nocopy transport between custom created epts of default channels + *****************************************************************************/ +void tc_1_defchnl_1(void) +{ + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(&default_queue, &default_ept, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + int32_t received = 0; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_queue_recv(my_rpmsg, default_queue, &remote_addr, (char *)&received, sizeof(received), &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(received == i, "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_queue_recv' failed"); + received += 10; + rpmsg_lite_send(my_rpmsg, default_ept, remote_addr, (char *)&received, sizeof(received), RL_BLOCK); + } + +end1: + result = rpmsg_queue_destroy(my_rpmsg, default_queue); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_queue_destroy' failed"); + result = rpmsg_lite_destroy_ept(my_rpmsg, default_ept); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_lite_destroy_ept' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_2(void) +{ + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(&default_queue, &default_ept, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + int32_t *received = 0; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_queue_recv_nocopy(my_rpmsg, default_queue, &remote_addr, (char **)&received, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(*received == i, "'rpmsg_queue_recv_nocopy' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(int), "'rpmsg_queue_recv_nocopy' failed"); + (*received) += 10; + rpmsg_lite_send(my_rpmsg, default_ept, remote_addr, (char *)received, sizeof(received), RL_BLOCK); + rpmsg_queue_nocopy_free(my_rpmsg, received); + } + +end1: + result = rpmsg_queue_destroy(my_rpmsg, default_queue); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_queue_destroy' failed"); + result = rpmsg_lite_destroy_ept(my_rpmsg, default_ept); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_lite_destroy_ept' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_3(void) +{ + struct rpmsg_lite_endpoint *volatile epts[TC_EPT_COUNT] = {0}; + rpmsg_queue_handle queues[TC_EPT_COUNT] = {0}; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(queues, epts, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + for (int32_t j = 0; j < TC_EPT_COUNT; j++) + { + int32_t received = 123; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_queue_recv(my_rpmsg, queues[j], &remote_addr, (char *)&received, sizeof(received), &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(received == 0, "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(remote_addr == (TC_REMOTE_EPT_ADDR + j), "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_queue_recv' failed"); + received += 10; + rpmsg_lite_send(my_rpmsg, epts[j], remote_addr, (char *)&received, sizeof(received), RL_BLOCK); + } + } + +end1: + result = ts_destroy_epts(queues, epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_4(void) +{ + struct rpmsg_lite_endpoint *epts[TC_EPT_COUNT] = {0}; + rpmsg_queue_handle queues[TC_EPT_COUNT] = {0}; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(queues, epts, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + for (int32_t j = 0; j < TC_EPT_COUNT; j++) + { + int32_t *received = NULL; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_queue_recv_nocopy(my_rpmsg, queues[j], &remote_addr, (char **)&received, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(*received == 0, "'rpmsg_rtos_recv' failed"); + TEST_ASSERT_MESSAGE(remote_addr == (TC_REMOTE_EPT_ADDR + j), "'rpmsg_rtos_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_rtos_recv' failed"); + (*received) += 10; + rpmsg_lite_send(my_rpmsg, epts[j], remote_addr, (char *)received, sizeof(received), RL_BLOCK); + rpmsg_queue_nocopy_free(my_rpmsg, received); + } + } + +end1: + result = ts_destroy_epts(queues, epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl(void) +{ + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_1(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_2(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_3(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_4(); + } +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("02_epts_channels_rtos_sec_core"); + __coveragescanner_install("02_epts_channels_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_defchnl, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/02_epts_channels_rtos/main_static_alloc_core0.c b/tests/02_epts_channels_rtos/main_static_alloc_core0.c new file mode 100644 index 0000000..a2dcf22 --- /dev/null +++ b/tests/02_epts_channels_rtos/main_static_alloc_core0.c @@ -0,0 +1,346 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "rpmsg_queue.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_INIT_COUNT 10 +#define TC_TRANSFER_COUNT 10 +#define TC_EPT_COUNT 3 +#define TC_LOCAL_EPT_ADDR (40) +#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *default_ept; +struct rpmsg_lite_ept_static_context default_ept_ctxt; + +rpmsg_queue_handle default_queue = NULL; +rpmsg_static_queue_ctxt default_queue_ctxt = {0}; +uint8_t default_rpmsg_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; + +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt = {0}; + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); + env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_deinit(my_rpmsg); + my_rpmsg = NULL; + env_memset(&rpmsg_ctxt, 0, sizeof(struct rpmsg_lite_instance)); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(rpmsg_queue_handle queues[], uint8_t queues_storage[], rpmsg_static_queue_ctxt queues_ctxt[], struct rpmsg_lite_endpoint *volatile epts[], struct rpmsg_lite_ept_static_context epts_ctxt[], int32_t count, int32_t init_addr) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + queues[i] = rpmsg_queue_create(my_rpmsg, &queues_storage[i], &queues_ctxt[i]); + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, rpmsg_queue_rx_cb, queues[i], &epts_ctxt[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_create_ept(RL_NULL, init_addr, rpmsg_queue_rx_cb, NULL, &epts_ctxt[0]), "'rpmsg_lite_create_ept' with bad rpmsg_lite_dev param failed"); + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + TEST_ASSERT_MESSAGE(count >= 3, "increase the TC_EPT_COUNT to be at least 3"); + + //use different sequence of EP destroy to cover the case when EP is removed from the intermediate element of the EP linked list + rpmsg_queue_destroy(my_rpmsg, queues[1]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[1]); + rpmsg_queue_destroy(my_rpmsg, queues[0]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[0]); + for (int32_t i = 2; i < count; i++) + { + rpmsg_queue_destroy(my_rpmsg, queues[i]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + /* Destroying an endpoint again when all endpoints are already destroyed */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, epts[0]), "'rpmsg_lite_destroy_ept' being called when all endpoints are alrady destroyed failed"); + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(RL_NULL, epts[0]), "'rpmsg_lite_destroy_ept' with bad rpmsg_lite_dev param failed"); + /* Wrong rl_ept param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, RL_NULL), "'rpmsg_lite_destroy_ept' with bad rl_ept param failed"); + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between default epts of default channels + * - verify simple nocopy transport between default epts of default channels + * - verify simple transport between custom created epts of default channels + * - verify simple nocopy transport between custom created epts of default channels + *****************************************************************************/ +void tc_1_defchnl_1(void) +{ + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(&default_queue, &default_rpmsg_queue_storage[0], &default_queue_ctxt, &default_ept, &default_ept_ctxt, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + int32_t received = 0, send = i; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_lite_send(my_rpmsg, default_ept, TC_REMOTE_EPT_ADDR, (char *)&send, sizeof(send), RL_BLOCK); + rpmsg_queue_recv(my_rpmsg, default_queue, &remote_addr, (char *)&received, sizeof(received), &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(received == i + 10, "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(send), "'rpmsg_queue_recv' failed"); + } + +end1: + result = rpmsg_queue_destroy(my_rpmsg, default_queue); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_queue_destroy' failed"); + default_queue = NULL; + env_memset(&default_rpmsg_queue_storage, 0, RL_ENV_QUEUE_STATIC_STORAGE_SIZE); + env_memset(&default_queue_ctxt, 0, sizeof(rpmsg_static_queue_ctxt)); + result = rpmsg_lite_destroy_ept(my_rpmsg, default_ept); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_lite_destroy_ept' failed"); + default_ept = NULL; + env_memset(&default_ept_ctxt, 0, sizeof(struct rpmsg_lite_ept_static_context)); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_2(void) +{ + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(&default_queue, &default_rpmsg_queue_storage[0], &default_queue_ctxt, &default_ept, &default_ept_ctxt, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + int32_t *received = NULL, send = i; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_lite_send(my_rpmsg, default_ept, TC_REMOTE_EPT_ADDR, (char *)&send, sizeof(send), RL_BLOCK); + rpmsg_queue_recv_nocopy(my_rpmsg, default_queue, &remote_addr, (char **)&received, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(*received == i + 10, "'rpmsg_queue_recv_nocopy' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(send), "'rpmsg_queue_recv_nocopy' failed"); + rpmsg_queue_nocopy_free(my_rpmsg, received); + } + +end1: + result = rpmsg_queue_destroy(my_rpmsg, default_queue); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_queue_destroy' failed"); + default_queue = NULL; + env_memset(&default_rpmsg_queue_storage, 0, RL_ENV_QUEUE_STATIC_STORAGE_SIZE); + env_memset(&default_queue_ctxt, 0, sizeof(rpmsg_static_queue_ctxt)); + result = rpmsg_lite_destroy_ept(my_rpmsg, default_ept); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_lite_destroy_ept' failed"); + default_ept = NULL; + env_memset(&default_ept_ctxt, 0, sizeof(struct rpmsg_lite_ept_static_context)); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_3(void) +{ + struct rpmsg_lite_endpoint *volatile epts[TC_EPT_COUNT] = {0}; + struct rpmsg_lite_ept_static_context ept_ctxt[TC_EPT_COUNT]; + rpmsg_queue_handle queues[TC_EPT_COUNT] = {0}; + rpmsg_static_queue_ctxt queues_ctxt[TC_EPT_COUNT] = {0}; + uint8_t rpmsg_queue_storage[TC_EPT_COUNT][RL_ENV_QUEUE_STATIC_STORAGE_SIZE]; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(queues, &rpmsg_queue_storage[0][0], queues_ctxt, epts, ept_ctxt, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + for (int32_t j = 0; j < TC_EPT_COUNT; j++) + { + int32_t received = 0, send = 0; + uint32_t len = 0; + send = 0; + uint32_t remote_addr = 0; + rpmsg_lite_send(my_rpmsg, epts[j], TC_REMOTE_EPT_ADDR + j, (char *)&send, sizeof(send), RL_BLOCK); + rpmsg_queue_recv(my_rpmsg, queues[j], &remote_addr, (char *)&received, sizeof(received), &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(received == send + 10, "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(remote_addr == (TC_REMOTE_EPT_ADDR + j), "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_queue_recv' failed"); + } + } + +end1: + result = ts_destroy_epts(queues, epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_4(void) +{ + struct rpmsg_lite_endpoint *epts[TC_EPT_COUNT] = {0}; + struct rpmsg_lite_ept_static_context ept_ctxt[TC_EPT_COUNT]; + rpmsg_queue_handle queues[TC_EPT_COUNT] = {0}; + rpmsg_static_queue_ctxt queues_ctxt[TC_EPT_COUNT] = {0}; + uint8_t rpmsg_queue_storage[TC_EPT_COUNT][RL_ENV_QUEUE_STATIC_STORAGE_SIZE]; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(queues, &rpmsg_queue_storage[0][0], queues_ctxt, epts, ept_ctxt, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + // wait some time to allow remote side to create epts and be ready for messages handling + env_sleep_msec(200); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + for (int32_t j = 0; j < TC_EPT_COUNT; j++) + { + int32_t *received = NULL, send = 0; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_lite_send(my_rpmsg, epts[j], TC_REMOTE_EPT_ADDR + j, (char *)&send, sizeof(send), RL_BLOCK); + rpmsg_queue_recv_nocopy(my_rpmsg, queues[j], &remote_addr, (char **)&received, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(*received == send + 10, "'rpmsg_rtos_recv' failed"); + TEST_ASSERT_MESSAGE(remote_addr == (TC_REMOTE_EPT_ADDR + j), "'rpmsg_rtos_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_rtos_recv' failed"); + rpmsg_queue_nocopy_free(my_rpmsg, received); + } + } + +end1: + result = ts_destroy_epts(queues, epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl(void) +{ + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_1(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_2(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_3(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_4(); + } +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("02_epts_channels_rtos"); + __coveragescanner_install("02_epts_channels_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_defchnl, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/02_epts_channels_rtos/main_static_alloc_core1.c b/tests/02_epts_channels_rtos/main_static_alloc_core1.c new file mode 100644 index 0000000..81f9c4f --- /dev/null +++ b/tests/02_epts_channels_rtos/main_static_alloc_core1.c @@ -0,0 +1,344 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "unity.h" +#include "rpmsg_queue.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_INIT_COUNT 10 +#define TC_TRANSFER_COUNT 10 +#define TC_EPT_COUNT 3 +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *default_ept; +struct rpmsg_lite_ept_static_context default_ept_ctxt; + +rpmsg_queue_handle default_queue = NULL; +rpmsg_static_queue_ctxt default_queue_ctxt = {0}; +uint8_t default_rpmsg_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; + +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt = {0}; + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_deinit(my_rpmsg); + my_rpmsg = NULL; + env_memset(&rpmsg_ctxt, 0, sizeof(struct rpmsg_lite_instance)); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(rpmsg_queue_handle queues[], uint8_t queues_storage[], rpmsg_static_queue_ctxt queues_ctxt[], struct rpmsg_lite_endpoint *volatile epts[], struct rpmsg_lite_ept_static_context epts_ctxt[], int32_t count, int32_t init_addr) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + queues[i] = rpmsg_queue_create(my_rpmsg, &queues_storage[i], &queues_ctxt[i]); + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, rpmsg_queue_rx_cb, queues[i], &epts_ctxt[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_create_ept(RL_NULL, init_addr, rpmsg_queue_rx_cb, NULL, &epts_ctxt[0]), "'rpmsg_lite_create_ept' with bad rpmsg_lite_dev param failed"); + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + TEST_ASSERT_MESSAGE(count >= 3, "increase the TC_EPT_COUNT to be at least 3"); + + //use different sequence of EP destroy to cover the case when EP is removed from the intermediate element of the EP linked list + rpmsg_queue_destroy(my_rpmsg, queues[1]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[1]); + rpmsg_queue_destroy(my_rpmsg, queues[0]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[0]); + for (int32_t i = 2; i < count; i++) + { + rpmsg_queue_destroy(my_rpmsg, queues[i]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + /* Test bad args */ + /* Wrong rpmsg_lite_dev param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(RL_NULL, epts[0]), "'rpmsg_lite_destroy_ept' with bad rpmsg_lite_dev param failed"); + /* Wrong rl_ept param */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_destroy_ept(my_rpmsg, RL_NULL), "'rpmsg_lite_destroy_ept' with bad rl_ept param failed"); + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between default epts of default channels + * - verify simple nocopy transport between default epts of default channels + * - verify simple transport between custom created epts of default channels + * - verify simple nocopy transport between custom created epts of default channels + *****************************************************************************/ +void tc_1_defchnl_1(void) +{ + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(&default_queue, &default_rpmsg_queue_storage[0], &default_queue_ctxt, &default_ept, &default_ept_ctxt, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + int32_t received = 0; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_queue_recv(my_rpmsg, default_queue, &remote_addr, (char *)&received, sizeof(received), &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(received == i, "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_queue_recv' failed"); + received += 10; + rpmsg_lite_send(my_rpmsg, default_ept, remote_addr, (char *)&received, sizeof(received), RL_BLOCK); + } + +end1: + result = rpmsg_queue_destroy(my_rpmsg, default_queue); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_queue_destroy' failed"); + default_queue = NULL; + env_memset(&default_rpmsg_queue_storage, 0, RL_ENV_QUEUE_STATIC_STORAGE_SIZE); + env_memset(&default_queue_ctxt, 0, sizeof(rpmsg_static_queue_ctxt)); + result = rpmsg_lite_destroy_ept(my_rpmsg, default_ept); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_lite_destroy_ept' failed"); + default_ept = NULL; + env_memset(&default_ept_ctxt, 0, sizeof(struct rpmsg_lite_ept_static_context)); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_2(void) +{ + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(&default_queue, &default_rpmsg_queue_storage[0], &default_queue_ctxt, &default_ept, &default_ept_ctxt, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + int32_t *received = 0; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_queue_recv_nocopy(my_rpmsg, default_queue, &remote_addr, (char **)&received, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(*received == i, "'rpmsg_queue_recv_nocopy' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(int), "'rpmsg_queue_recv_nocopy' failed"); + (*received) += 10; + rpmsg_lite_send(my_rpmsg, default_ept, remote_addr, (char *)received, sizeof(received), RL_BLOCK); + rpmsg_queue_nocopy_free(my_rpmsg, received); + } + +end1: + result = rpmsg_queue_destroy(my_rpmsg, default_queue); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_queue_destroy' failed"); + default_queue = NULL; + env_memset(&default_rpmsg_queue_storage, 0, RL_ENV_QUEUE_STATIC_STORAGE_SIZE); + env_memset(&default_queue_ctxt, 0, sizeof(rpmsg_static_queue_ctxt)); + result = rpmsg_lite_destroy_ept(my_rpmsg, default_ept); + TEST_ASSERT_MESSAGE(0 == result, "'rpmsg_lite_destroy_ept' failed"); + default_ept = NULL; + env_memset(&default_ept_ctxt, 0, sizeof(struct rpmsg_lite_ept_static_context)); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_3(void) +{ + struct rpmsg_lite_endpoint *volatile epts[TC_EPT_COUNT] = {0}; + struct rpmsg_lite_ept_static_context ept_ctxt[TC_EPT_COUNT]; + rpmsg_queue_handle queues[TC_EPT_COUNT] = {0}; + rpmsg_static_queue_ctxt queues_ctxt[TC_EPT_COUNT] = {0}; + uint8_t rpmsg_queue_storage[TC_EPT_COUNT][RL_ENV_QUEUE_STATIC_STORAGE_SIZE]; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(queues, &rpmsg_queue_storage[0][0], queues_ctxt, epts, ept_ctxt, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + for (int32_t j = 0; j < TC_EPT_COUNT; j++) + { + int32_t received = 123; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_queue_recv(my_rpmsg, queues[j], &remote_addr, (char *)&received, sizeof(received), &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(received == 0, "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(remote_addr == (TC_REMOTE_EPT_ADDR + j), "'rpmsg_queue_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_queue_recv' failed"); + received += 10; + rpmsg_lite_send(my_rpmsg, epts[j], remote_addr, (char *)&received, sizeof(received), RL_BLOCK); + } + } + +end1: + result = ts_destroy_epts(queues, epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl_4(void) +{ + struct rpmsg_lite_endpoint *epts[TC_EPT_COUNT] = {0}; + struct rpmsg_lite_ept_static_context ept_ctxt[TC_EPT_COUNT]; + rpmsg_queue_handle queues[TC_EPT_COUNT] = {0}; + rpmsg_static_queue_ctxt queues_ctxt[TC_EPT_COUNT] = {0}; + uint8_t rpmsg_queue_storage[TC_EPT_COUNT][RL_ENV_QUEUE_STATIC_STORAGE_SIZE]; + int32_t result = 0; + + // init rpmsg and environment, check nonrecoverable error + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_init_rpmsg' failed"); + if (result) + goto end0; + + result = ts_create_epts(queues, &rpmsg_queue_storage[0][0], queues_ctxt, epts, ept_ctxt, TC_EPT_COUNT, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + if (result) + goto end1; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + for (int32_t j = 0; j < TC_EPT_COUNT; j++) + { + int32_t *received = NULL; + uint32_t len = 0; + uint32_t remote_addr = 0; + rpmsg_queue_recv_nocopy(my_rpmsg, queues[j], &remote_addr, (char **)&received, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(*received == 0, "'rpmsg_rtos_recv' failed"); + TEST_ASSERT_MESSAGE(remote_addr == (TC_REMOTE_EPT_ADDR + j), "'rpmsg_rtos_recv' failed"); + TEST_ASSERT_MESSAGE(len == sizeof(received), "'rpmsg_rtos_recv' failed"); + (*received) += 10; + rpmsg_lite_send(my_rpmsg, epts[j], remote_addr, (char *)received, sizeof(received), RL_BLOCK); + rpmsg_queue_nocopy_free(my_rpmsg, received); + } + } + +end1: + result = ts_destroy_epts(queues, epts, TC_EPT_COUNT); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); +end0: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "'ts_deinit_rpmsg' failed"); +} + +void tc_1_defchnl(void) +{ + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_1(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_2(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_3(); + } + for (int32_t i = 0; i < TC_INIT_COUNT; i++) + { + tc_1_defchnl_4(); + } +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("02_epts_channels_rtos_sec_core"); + __coveragescanner_install("02_epts_channels_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_defchnl, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/02_epts_channels_rtos/readme.txt b/tests/02_epts_channels_rtos/readme.txt new file mode 100644 index 0000000..da0d690 --- /dev/null +++ b/tests/02_epts_channels_rtos/readme.txt @@ -0,0 +1,6 @@ +02_epts_channels_rtos test suite + + - FreeRTOS/ThreadX/XOS-based project, covering both the static allocation (#define RL_USE_STATIC_API (1) in rpmsg_config.h) and the dynamic allocation (#define RL_USE_STATIC_API (0) in rpmsg_config.h) + + - send user data through default channel + - create several custom epts and send data through them diff --git a/tests/03_send_receive/main_core0.c b/tests/03_send_receive/main_core0.c new file mode 100644 index 0000000..6469239 --- /dev/null +++ b/tests/03_send_receive/main_core0.c @@ -0,0 +1,309 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "rpmsg_ns.h" +#include +#include "unity.h" +#include "assert.h" +#include "app.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define DATA_LEN 45 +#define TRYSEND_COUNT 12 +#define TC_LOCAL_EPT_ADDR (40) +#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +volatile int32_t test_no = 0, rx_data_len = 0; +void *rx_buffer = NULL; +struct rpmsg_lite_endpoint *volatile my_ept = NULL; +struct rpmsg_lite_ept_static_context my_ept_ctxt; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt; +rpmsg_ns_handle ns_handle = NULL; +rpmsg_ns_static_context nameservice_ept_ctxt; +volatile uint32_t remote_addr = 0U; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ + uint32_t *data = (uint32_t *)user_data; + + *data = new_ept; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +// endpoint callback +int32_t ept_cb(void *data, uint32_t len, uint32_t src, void *priv) +{ + int32_t result = 0; + TEST_ASSERT_MESSAGE(src == TC_REMOTE_EPT_ADDR, "receive error"); + TEST_ASSERT_MESSAGE(DATA_LEN == len, "receive error"); + switch (test_no) + { + case 0: + result = pattern_cmp(data, test_no, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); + + test_no++; + return RL_RELEASE; + + case 1: + result = pattern_cmp(data, test_no, len); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); + + test_no++; + return RL_RELEASE; + + case 2: + rx_data_len = len; + rx_buffer = data; + + test_no++; + return RL_HOLD; + } + return RL_RELEASE; +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); + env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr, &nameservice_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_ns_unbind(my_rpmsg, ns_handle); + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(struct rpmsg_lite_endpoint *volatile epts[], + int32_t count, + int32_t init_addr, + struct rpmsg_lite_ept_static_context ctxts[]) +{ + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, ept_cb, NULL, &ctxts[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + return 0; +} + +/****************************************************************************** + * Test case 1 + * - send data with different pattern for each send function + * - call send function with invalid parameters + *****************************************************************************/ +void tc_1_send(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t buf_size = 0; + + // send - invalid rpmsg_lite_dev + result = rpmsg_lite_send(RL_NULL, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_send' with bad rpmsg_lite_dev param failed"); + + // send - invalid endpoint + result = rpmsg_lite_send(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + result = rpmsg_lite_send_nocopy(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + + // send - invalid data + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + + // send - invalid size + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xffffffff, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xffffffff); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + + // invalid params for alloc_tx_buffer + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL == data_addr, "send error"); + + // send - valid all params + env_memset(data, 0, DATA_LEN); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "send error"); + + // send message to non-existing endpoint address, message will be dropped on the receiver side + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR + 1, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + + //non-blocking send to the auxiliary endpoint that does not consume messages - called to reach the RL_ERR_NO_MEM error and thus increase the code coverage + while(RL_ERR_NO_MEM != rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR+2, data, DATA_LEN, RL_DONT_BLOCK)); + while(RL_ERR_NO_MEM != rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR+2, data, DATA_LEN, 1)); + + //non-blocking nocopy send to the auxiliary endpoint that does not consume messages - called to reach the RL_ERR_NO_MEM error in rpmsg_lite_alloc_tx_buffer() and thus increase the code coverage + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_DONT_BLOCK); + while(RL_NULL == data_addr) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_DONT_BLOCK); + } + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR+2, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "send error"); + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, 1); + while(RL_NULL == data_addr) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, 1); + } + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR+2, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "send error"); + + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != buf_size, "send error"); + env_memset(data_addr, 1, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "send error"); + data_addr = NULL; + + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != buf_size, "send error"); + env_memset(data_addr, 2, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "send error"); + data_addr = NULL; + + /* wait a while to process the last message on the opposite side */ + env_sleep_msec(200); +} + +/****************************************************************************** + * Test case 2 + * - check received data + *****************************************************************************/ +void tc_2_receive(void) +{ + int32_t result = 0; + // wait for incoming interrupts + while (test_no != 3) + ; + // check the last message content - this message has not been processed within the rx callback + TEST_ASSERT_MESSAGE(NULL != rx_buffer, "receive error"); + TEST_ASSERT_MESSAGE(0 != rx_data_len, "receive error"); + result = pattern_cmp(rx_buffer, 2, rx_data_len); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); + + /* Before releasing the rx buffer try to call the rpmsg_lite_release_rx_buffer API with incorrect params */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_release_rx_buffer(RL_NULL, rx_buffer), "'rpmsg_lite_release_rx_buffer' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_release_rx_buffer(my_rpmsg, RL_NULL), "'rpmsg_lite_release_rx_buffer' with bad rxbuf param failed"); + /* Release the buffer now */ + result = rpmsg_lite_release_rx_buffer(my_rpmsg, rx_buffer); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "rpmsg_lite_release_rx_buffer error"); +} + +void run_tests(void *unused) +{ + int32_t result = 0; + struct rpmsg_lite_endpoint fake_ept = {0}; + struct rpmsg_lite_instance fake_rpmsg = {0}; + uint32_t bufer_size = 1; + + // call send before rpmsg_lite is initialized + result = rpmsg_lite_send(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_alloc_tx_buffer(&fake_rpmsg, &bufer_size, RL_BLOCK), "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(0 == bufer_size, "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + result = rpmsg_lite_send_nocopy(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send_nocopy' called before rpmsg_lite is initialized failed"); + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); + + // create custom epts of default channel, check nonrecoverable error + result = ts_create_epts(&my_ept, 1, TC_LOCAL_EPT_ADDR, &my_ept_ctxt); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + + /* Wait until the secondary core application issues the nameservice isr and the remote endpoint address is known. */ + while (0U == remote_addr) + { + }; + if (!result) + { +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("03_send_receive"); + __coveragescanner_install("03_send_receive.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_send, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_receive, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); + } + + result = ts_destroy_epts(&my_ept, 1); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); + + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); +} diff --git a/tests/03_send_receive/main_core1.c b/tests/03_send_receive/main_core1.c new file mode 100644 index 0000000..928aab1 --- /dev/null +++ b/tests/03_send_receive/main_core1.c @@ -0,0 +1,360 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "rpmsg_ns.h" +#include +#include "unity.h" +#include "assert.h" +#include "app.h" + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define DATA_LEN 45 +#define TRYSEND_COUNT 12 +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) +#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-test-channel" + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +#ifdef __COVERAGESCANNER__ +/* rpmsg_std_hdr contains a reserved field, + * this implementation of RPMSG uses this reserved + * field to hold the idx and totlen of the buffer + * not being returned to the vring in the receive + * callback function. This way, the no-copy API + * can use this field to return the buffer later. + */ +struct my_rpmsg_hdr_reserved +{ + uint16_t rfu; /* reserved for future usage */ + uint16_t idx; +}; + +RL_PACKED_BEGIN +/*! + * Common header for all rpmsg messages. + * Every message sent/received on the rpmsg bus begins with this header. + */ +struct my_rpmsg_std_hdr +{ + uint32_t src; /*!< source endpoint address */ + uint32_t dst; /*!< destination endpoint address */ + struct my_rpmsg_hdr_reserved reserved; /*!< reserved for future use */ + uint16_t len; /*!< length of payload (in bytes) */ + uint16_t flags; /*!< message flags */ +} RL_PACKED_END; + +RL_PACKED_BEGIN +/*! + * Common message structure. + * Contains the header and the payload. + */ +struct my_rpmsg_std_msg +{ + struct my_rpmsg_std_hdr hdr; /*!< RPMsg message header */ + uint8_t data[1]; /*!< bytes of message payload data */ +} RL_PACKED_END; +#endif /*__COVERAGESCANNER__*/ + +volatile int32_t test_no = 0, rx_data_len = 0; +void *rx_buffer = NULL; +struct rpmsg_lite_endpoint *volatile my_ept = NULL; +struct rpmsg_lite_endpoint *aux_ept = NULL; +struct rpmsg_lite_ept_static_context my_ept_ctxt; +struct rpmsg_lite_ept_static_context aux_ept_ctxt; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt; +rpmsg_ns_handle ns_handle = NULL; +rpmsg_ns_static_context nameservice_ept_ctxt; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +// endpoint callback +int32_t ept_cb(void *data, uint32_t len, uint32_t src, void *priv) +{ + int32_t result = 0; + TEST_ASSERT_MESSAGE(src == TC_REMOTE_EPT_ADDR, "receive error"); + TEST_ASSERT_MESSAGE(DATA_LEN == len, "receive error"); + switch (test_no) + { + case 0: + result = pattern_cmp(data, test_no, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); + + test_no++; + return RL_RELEASE; + + case 1: + result = pattern_cmp(data, test_no, len); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); + + test_no++; + return RL_RELEASE; + + case 2: + rx_data_len = len; + rx_buffer = data; + + test_no++; + return RL_HOLD; + } + return RL_RELEASE; +} + +int32_t aux_ept_cb(void *data, uint32_t len, uint32_t src, void *priv) +{ + /* Introduce some delay and release the message */ + env_sleep_msec(10); + return RL_RELEASE; +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + + /* wait for a while to allow the primary side to bind_ns and register the NS callback */ + env_sleep_msec(200); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0), &nameservice_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_ns_unbind(my_rpmsg, ns_handle); + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(struct rpmsg_lite_endpoint *volatile epts[], + int32_t count, + int32_t init_addr, + struct rpmsg_lite_ept_static_context ctxts[]) +{ + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, ept_cb, NULL, &ctxts[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + for (int32_t i = 0; i < count; i++) + { + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + return 0; +} +/****************************************************************************** + * Test case 1 + * - check received data + *****************************************************************************/ +void tc_1_receive(void) +{ + int32_t result = 0; +#ifdef __COVERAGESCANNER__ + uint16_t my_rpmsg_hdr_idx = 0; + struct my_rpmsg_std_msg *msg; +#endif /*__COVERAGESCANNER__*/ + + // wait for incoming interrupts + while (test_no != 3) + ; + // check the last message content - this message has not been processed within the rx callback + TEST_ASSERT_MESSAGE(NULL != rx_buffer, "receive error"); + TEST_ASSERT_MESSAGE(0 != rx_data_len, "receive error"); + result = pattern_cmp(rx_buffer, 2, rx_data_len); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); + + /* Before releasing the rx buffer try to call the rpmsg_lite_release_rx_buffer API with incorrect params */ + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_release_rx_buffer(RL_NULL, rx_buffer), "'rpmsg_lite_release_rx_buffer' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_lite_release_rx_buffer(my_rpmsg, RL_NULL), "'rpmsg_lite_release_rx_buffer' with bad rxbuf param failed"); + +#ifdef __COVERAGESCANNER__ + /* Force ERROR_VRING_NO_BUFF error in virtqueue_add_consumed_buffer() when RL_ASSERT is off in Coco tests */ + msg = (struct my_rpmsg_std_msg *)(void *)((char *)(rx_buffer)-offsetof(struct my_rpmsg_std_msg, data)); + my_rpmsg_hdr_idx = msg->hdr.reserved.idx; + msg->hdr.reserved.idx = 2*RL_BUFFER_COUNT; + result = rpmsg_lite_release_rx_buffer(my_rpmsg, rx_buffer); + msg->hdr.reserved.idx = my_rpmsg_hdr_idx; +#endif /*__COVERAGESCANNER__*/ + + /* Release the buffer now */ + result = rpmsg_lite_release_rx_buffer(my_rpmsg, rx_buffer); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "rpmsg_lite_release_rx_buffer error"); +} + +/****************************************************************************** + * Test case 2 + * - send data with different pattern for each send function + * - call send function with invalid parameters + *****************************************************************************/ +void tc_2_send(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t buf_size = 0; + + // send - invalid rpmsg_lite_dev + result = rpmsg_lite_send(RL_NULL, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_send' with bad rpmsg_lite_dev param failed"); + + // send - invalid endpoint + result = rpmsg_lite_send(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + result = rpmsg_lite_send_nocopy(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + + // send - invalid data + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + + // send - invalid size + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xffffffff, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xffffffff); + TEST_ASSERT_MESSAGE(0 != result, "send error"); + + // invalid params for alloc_tx_buffer + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL == data_addr, "send error"); + + // send - valid all params + env_memset(data, 0, DATA_LEN); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "send error"); + + // send message to non-existing endpoint address, message will be dropped on the receiver side + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR + 1, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != buf_size, "send error"); + env_memset(data_addr, 1, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "send error"); + data_addr = NULL; + + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != buf_size, "send error"); + env_memset(data_addr, 2, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "send error"); + data_addr = NULL; + + /* wait a while to process the last message on the opposite side */ + env_sleep_msec(1000); +} + +void run_tests(void *unused) +{ + int32_t result = 0; + struct rpmsg_lite_endpoint fake_ept = {0}; + struct rpmsg_lite_instance fake_rpmsg = {0}; + uint32_t bufer_size = 1; + + // call send before rpmsg_lite is initialized + result = rpmsg_lite_send(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_alloc_tx_buffer(&fake_rpmsg, &bufer_size, RL_BLOCK), "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(0 == bufer_size, "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + result = rpmsg_lite_send_nocopy(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send_nocopy' called before rpmsg_lite is initialized failed"); + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); + + // create custom epts of default channel, check nonrecoverable error + result = ts_create_epts(&my_ept, 1, TC_LOCAL_EPT_ADDR, &my_ept_ctxt); + TEST_ASSERT_MESSAGE(0 == result, "'ts_create_epts' failed"); + + // create auxiliary endpoint that does not consume messages + aux_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR+2, aux_ept_cb, NULL, &aux_ept_ctxt); + + TEST_ASSERT_MESSAGE(RL_SUCCESS == rpmsg_ns_announce(my_rpmsg, my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE), "'rpmsg_ns_announce' failed"); + + if (!result) + { +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("03_send_receive_sec_core"); + __coveragescanner_install("03_send_receive_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_receive, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_send, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); + } + result = ts_destroy_epts(&my_ept, 1); + TEST_ASSERT_MESSAGE(0 == result, "'ts_destroy_epts' failed"); + + rpmsg_lite_destroy_ept(my_rpmsg, aux_ept); + + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "receive error"); +} diff --git a/tests/03_send_receive/readme.txt b/tests/03_send_receive/readme.txt new file mode 100644 index 0000000..f2e1690 --- /dev/null +++ b/tests/03_send_receive/readme.txt @@ -0,0 +1,5 @@ +03_send_receive test suite + + - baremetal project, static allocation used (#define RL_USE_STATIC_API (1) in rpmsg_config.h) + + - test all send send functions with valid/invalid parameters \ No newline at end of file diff --git a/tests/03_send_receive_rtos/main_core0.c b/tests/03_send_receive_rtos/main_core0.c new file mode 100644 index 0000000..a0aaadc --- /dev/null +++ b/tests/03_send_receive_rtos/main_core0.c @@ -0,0 +1,390 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include +#include "unity.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (40) +#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +typedef struct +{ + uint32_t src; + void *data; + uint32_t len; +} my_rpmsg_queue_rx_cb_data_t; + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *volatile my_ept = NULL; +rpmsg_queue_handle my_queue = NULL; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +rpmsg_ns_handle ns_handle = NULL; +volatile uint32_t remote_addr = 0U; +void *aux_mutex = NULL; +void *aux_q = RL_NULL; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ + uint32_t *data = (uint32_t *)user_data; + + *data = new_ept; + + //test mutex-related operations in ISR + env_lock_mutex(aux_mutex); + env_unlock_mutex(aux_mutex); + //test env_get_timestamp() being called from ISR + TEST_ASSERT_MESSAGE(0 < env_get_timestamp(), "env_get_timestamp function in ISR failed"); + //test queue-related operations in ISR + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)aux_q), "env_get_current_queue_size function in ISR failed"); +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); + env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_ns_unbind(my_rpmsg, ns_handle); + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count, int32_t init_addr) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + + // invalid params for rpmsg_queue_create + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(RL_NULL), "'rpmsg_queue_create' with bad rpmsg_lite_dev param failed"); + //force env_create_queue() call inside rpmsg_queue_create() to fail - request to allocate too much memory + uint16_t temp = my_rpmsg->rvq->vq_nentries; + my_rpmsg->rvq->vq_nentries = 0xfffe; + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(my_rpmsg), "'rpmsg_queue_create' with forced error in queue allocation failed"); + my_rpmsg->rvq->vq_nentries = temp; + + for (int32_t i = 0; i < count; i++) + { + queues[i] = rpmsg_queue_create(my_rpmsg); + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, rpmsg_queue_rx_cb, queues[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + + // invalid params for rpmsg_queue_destroy + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_queue_destroy(RL_NULL, queues[0]), "'rpmsg_queue_destroy' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_queue_destroy(my_rpmsg, RL_NULL), "'rpmsg_queue_destroy' with bad q param failed"); + + for (int32_t i = 0; i < count; i++) + { + rpmsg_queue_destroy(my_rpmsg, queues[i]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between custom created epts + * - verify simple nocopy transport between custom created epts + *****************************************************************************/ +void tc_1_send_receive(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t src; + uint32_t len; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + env_memset(data, i, DATA_LEN); + while(RL_SUCCESS != rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, 1)); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + env_memset(data, i, DATA_LEN); + while(RL_SUCCESS != rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_DONT_BLOCK)); + } + + // send message to non-existing endpoint address, message will be dropped on the receiver side + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR + 1, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + + // send - invalid rpmsg_lite_dev + result = rpmsg_lite_send(RL_NULL, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_send' with bad rpmsg_lite_dev param failed"); + + // invalid params for send + result = rpmsg_lite_send(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xFFFFFFFF, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + + // invalid params for receive + result = rpmsg_queue_recv(RL_NULL, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_recv(my_rpmsg, RL_NULL, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad q param failed"); + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, RL_NULL, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad data param failed"); + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, 0, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_BUFF_SIZE == result, "'rpmsg_queue_recv' with bad maxlen param failed"); + + // invalid params for receive_nocopy + result = rpmsg_queue_recv_nocopy(RL_NULL, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, RL_NULL, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad q param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, RL_NULL, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad data param failed"); + + // invalid params for receive_nocopy_free + result = rpmsg_queue_nocopy_free(RL_NULL, data_addr); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_nocopy_free' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_nocopy_free(my_rpmsg, RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_nocopy_free' with bad data param failed"); + + // invalid params for rpmsg_lite_release_rx_buffer - this should not be used in an app and rpmsg_queue_nocopy_free should be used instead + result = rpmsg_lite_release_rx_buffer(RL_NULL, data_addr); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_release_rx_buffer' with bad rpmsg_lite_dev param failed"); + result = rpmsg_lite_release_rx_buffer(my_rpmsg, RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_release_rx_buffer' with bad data param failed"); + + // invalid params for rpmsg_queue_get_current_size + result = rpmsg_queue_get_current_size(RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_get_current_size' with bad q param failed"); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data_addr, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + /* for invalid length remote receive */ + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); +} + +/****************************************************************************** + * Test case 2 + * - same as for test case 1 but send with copy replaced by send_nocopy + *****************************************************************************/ +void tc_2_send_receive(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t buf_size = 0; + uint32_t src; + uint32_t len; + my_rpmsg_queue_rx_cb_data_t fake_msg = {0}; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, 1); + while(RL_NULL == data_addr) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, 1); + } + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_DONT_BLOCK); + while(RL_NULL == data_addr) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_DONT_BLOCK); + } + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } + + // invalid params for alloc_tx_buffer + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL == data_addr, "negative number"); + + // invalid params for send_nocopy + result = rpmsg_lite_send_nocopy(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xFFFFFFFF); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data_addr, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + // put fake message into the queue to allow queue full state and incomming messages dropping + TEST_ASSERT_MESSAGE(1 == env_put_queue(my_queue, &fake_msg, 0), "env_put_queue function failed"); + // send a message to the secondary side to trigger messages sending from the secondary side to the primary side + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, 0, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + //wait a while to allow the secondary side to send all messages and made the receive queue full + env_sleep_msec(200); + // invalid src and len pointer params for receive + result = rpmsg_queue_recv(my_rpmsg, my_queue, RL_NULL, data, DATA_LEN, RL_NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad src and len pointer param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, RL_NULL, (char **)&data_addr, RL_NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "'rpmsg_queue_recv_nocopy' with bad bad src and len pointer param failed"); +} + +void run_tests(void *unused) +{ + int32_t result = 0; + struct rpmsg_lite_endpoint fake_ept = {0}; + struct rpmsg_lite_instance fake_rpmsg = {0}; + uint32_t bufer_size = 1; + + // call send before rpmsg_lite is initialized + result = rpmsg_lite_send(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_alloc_tx_buffer(&fake_rpmsg, &bufer_size, RL_BLOCK), "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(0 == bufer_size, "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + result = rpmsg_lite_send_nocopy(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send_nocopy' called before rpmsg_lite is initialized failed"); + + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&aux_mutex, 1), "env_create_mutex function failed"); + TEST_ASSERT_MESSAGE(0 == env_create_queue(&aux_q, 1, sizeof(uint32_t)), "env_create_queue function failed"); + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = ts_create_epts(&my_queue, &my_ept, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + /* Wait until the secondary core application issues the nameservice isr and the remote endpoint address is known. */ + while (0U == remote_addr) + { + }; + if (!result) + { +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("03_send_receive_rtos"); + __coveragescanner_install("03_send_receive_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_send_receive, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_send_receive, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); + } + env_delete_mutex(aux_mutex); + env_delete_queue(aux_q); + + ts_destroy_epts(&my_queue, &my_ept, 1); + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); +} diff --git a/tests/03_send_receive_rtos/main_core1.c b/tests/03_send_receive_rtos/main_core1.c new file mode 100644 index 0000000..1ab275a --- /dev/null +++ b/tests/03_send_receive_rtos/main_core1.c @@ -0,0 +1,424 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include +#include "unity.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) +#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-test-channel" + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +#ifdef __COVERAGESCANNER__ +/* rpmsg_std_hdr contains a reserved field, + * this implementation of RPMSG uses this reserved + * field to hold the idx and totlen of the buffer + * not being returned to the vring in the receive + * callback function. This way, the no-copy API + * can use this field to return the buffer later. + */ +struct my_rpmsg_hdr_reserved +{ + uint16_t rfu; /* reserved for future usage */ + uint16_t idx; +}; + +RL_PACKED_BEGIN +/*! + * Common header for all rpmsg messages. + * Every message sent/received on the rpmsg bus begins with this header. + */ +struct my_rpmsg_std_hdr +{ + uint32_t src; /*!< source endpoint address */ + uint32_t dst; /*!< destination endpoint address */ + struct my_rpmsg_hdr_reserved reserved; /*!< reserved for future use */ + uint16_t len; /*!< length of payload (in bytes) */ + uint16_t flags; /*!< message flags */ +} RL_PACKED_END; + +RL_PACKED_BEGIN +/*! + * Common message structure. + * Contains the header and the payload. + */ +struct my_rpmsg_std_msg +{ + struct my_rpmsg_std_hdr hdr; /*!< RPMsg message header */ + uint8_t data[1]; /*!< bytes of message payload data */ +} RL_PACKED_END; +#endif /*__COVERAGESCANNER__*/ + +struct rpmsg_lite_endpoint *volatile my_ept = NULL; +rpmsg_queue_handle my_queue = NULL; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +rpmsg_ns_handle ns_handle = NULL; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + + /* wait for a while to allow the primary side to bind_ns and register the NS callback */ + env_sleep_msec(200); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0)); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_ns_unbind(my_rpmsg, ns_handle); + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count, int32_t init_addr) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + + // invalid params for rpmsg_queue_create + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(RL_NULL), "'rpmsg_queue_create' with bad rpmsg_lite_dev param failed"); +#if !(defined(CPU_MIMXRT685SFAWBR_dsp) || defined(CPU_MIMXRT685SFFOB_dsp) || defined(CPU_MIMXRT685SFVKB_dsp) || \ + defined(CPU_MIMXRT595SFAWC_dsp) || defined(CPU_MIMXRT595SFFOC_dsp)) + //force env_create_queue() call inside rpmsg_queue_create() to fail - request to allocate too much memory + uint16_t temp = my_rpmsg->rvq->vq_nentries; + my_rpmsg->rvq->vq_nentries = 0xfffe; + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(my_rpmsg), "'rpmsg_queue_create' with forced error in queue allocation failed"); + my_rpmsg->rvq->vq_nentries = temp; +#endif + for (int32_t i = 0; i < count; i++) + { + queues[i] = rpmsg_queue_create(my_rpmsg); + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, rpmsg_queue_rx_cb, queues[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + + // invalid params for rpmsg_queue_destroy + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_queue_destroy(RL_NULL, queues[0]), "'rpmsg_queue_destroy' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_queue_destroy(my_rpmsg, RL_NULL), "'rpmsg_queue_destroy' with bad q param failed"); + + for (int32_t i = 0; i < count; i++) + { + rpmsg_queue_destroy(my_rpmsg, queues[i]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between default epts of default channels + * - verify simple nocopy transport between default epts of default channels + * - verify simple transport between custom created epts of default channels + * - verify simple nocopy transport between custom created epts of default channels + *****************************************************************************/ +void tc_1_receive_send(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t src; + uint32_t len; +#ifdef __COVERAGESCANNER__ + uint16_t my_rpmsg_hdr_idx = 0; + struct my_rpmsg_std_msg *msg; +#endif /*__COVERAGESCANNER__*/ + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data_addr, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + +#ifdef __COVERAGESCANNER__ + /* Force ERROR_VRING_NO_BUFF error in virtqueue_add_consumed_buffer() when RL_ASSERT is off in Coco tests */ + msg = (struct my_rpmsg_std_msg *)(void *)((char *)(data_addr)-offsetof(struct my_rpmsg_std_msg, data)); + my_rpmsg_hdr_idx = msg->hdr.reserved.idx; + msg->hdr.reserved.idx = 2*RL_BUFFER_COUNT; + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + msg->hdr.reserved.idx = my_rpmsg_hdr_idx; +#endif /*__COVERAGESCANNER__*/ + + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + /* for invalid length remote receive */ + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + env_memset(data, i, DATA_LEN); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + env_memset(data, i, DATA_LEN); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + // send message to non-existing endpoint address, message will be dropped on the receiver side + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR + 1, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + + // send - invalid rpmsg_lite_dev + result = rpmsg_lite_send(RL_NULL, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_send' with bad rpmsg_lite_dev param failed"); + + // invalid params for send + result = rpmsg_lite_send(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xFFFFFFFF, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + + // invalid params for receive + result = rpmsg_queue_recv(RL_NULL, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_recv(my_rpmsg, RL_NULL, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad q param failed"); + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, RL_NULL, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad data param failed"); + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, 0, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_BUFF_SIZE == result, "'rpmsg_queue_recv' with bad maxlen param failed"); + + // invalid params for receive_nocopy + result = rpmsg_queue_recv_nocopy(RL_NULL, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, RL_NULL, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad q param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, RL_NULL, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad data param failed"); + + // invalid params for receive_nocopy_free + result = rpmsg_queue_nocopy_free(RL_NULL, data_addr); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_nocopy_free' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_nocopy_free(my_rpmsg, RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_nocopy_free' with bad data param failed"); + + // invalid params for rpmsg_lite_release_rx_buffer - this should not be used in an app and rpmsg_queue_nocopy_free should be used instead + result = rpmsg_lite_release_rx_buffer(RL_NULL, data_addr); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_release_rx_buffer' with bad rpmsg_lite_dev param failed"); + result = rpmsg_lite_release_rx_buffer(my_rpmsg, RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_release_rx_buffer' with bad data param failed"); +} + +/****************************************************************************** + * Test case 2 + * - same as for test case 1 but send with copy replaced by send_nocopy + *****************************************************************************/ +void tc_2_receive_send(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t buf_size = 0; + uint32_t src; + uint32_t len; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data_addr, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } + + // invalid params for alloc_tx_buffer + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL == data_addr, "negative number"); + + // invalid params for send_nocopy + result = rpmsg_lite_send_nocopy(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, 0xFFFFFFFF); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + + // wait until all messages are consumed on the primary side and a new message is received + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, 0, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + // send RL_BUFFER_COUNT messages to made the message queue on the primary side full +#if !(defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1)) + for (int32_t i = 0; i < RL_BUFFER_COUNT; i++) +#else + for (int32_t i = 0; i < RL_BUFFER_COUNT(RPMSG_LITE_LINK_ID); i++) +#endif + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } +} + +void run_tests(void *unused) +{ + int32_t result = 0; + struct rpmsg_lite_endpoint fake_ept = {0}; + struct rpmsg_lite_instance fake_rpmsg = {0}; + uint32_t bufer_size = 1; + + // call send before rpmsg_lite is initialized + result = rpmsg_lite_send(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_alloc_tx_buffer(&fake_rpmsg, &bufer_size, RL_BLOCK), "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(0 == bufer_size, "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + result = rpmsg_lite_send_nocopy(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send_nocopy' called before rpmsg_lite is initialized failed"); + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = ts_create_epts(&my_queue, &my_ept, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + TEST_ASSERT_MESSAGE(RL_SUCCESS == rpmsg_ns_announce(my_rpmsg, my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE), "'rpmsg_ns_announce' failed"); + + if (!result) + { +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("03_send_receive_rtos_sec_core"); + __coveragescanner_install("03_send_receive_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_receive_send, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_receive_send, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); + } + ts_destroy_epts(&my_queue, &my_ept, 1); + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); +} diff --git a/tests/03_send_receive_rtos/main_static_alloc_core0.c b/tests/03_send_receive_rtos/main_static_alloc_core0.c new file mode 100644 index 0000000..3d09785 --- /dev/null +++ b/tests/03_send_receive_rtos/main_static_alloc_core0.c @@ -0,0 +1,408 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include +#include "unity.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (40) +#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +typedef struct +{ + uint32_t src; + void *data; + uint32_t len; +} my_rpmsg_queue_rx_cb_data_t; + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *volatile my_ept = NULL; +struct rpmsg_lite_ept_static_context my_ept_ctxt; + +rpmsg_queue_handle my_queue = NULL; +rpmsg_static_queue_ctxt my_queue_ctxt = {0}; +uint8_t my_rpmsg_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt = {0}; +rpmsg_ns_handle ns_handle = NULL; +rpmsg_ns_static_context my_ns_ctxt = {0}; +volatile uint32_t remote_addr = 0U; +void *aux_mutex = NULL; +LOCK_STATIC_CONTEXT aux_mutex_ctxt = {0}; +void *aux_q = RL_NULL; +rpmsg_static_queue_ctxt aux_queue_ctxt = {0}; +uint8_t aux_rpmsg_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE]; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ + uint32_t *data = (uint32_t *)user_data; + + *data = new_ept; + + //test mutex-related operations in ISR + env_lock_mutex(aux_mutex); + env_unlock_mutex(aux_mutex); + //test env_get_timestamp() being called from ISR + TEST_ASSERT_MESSAGE(0 < env_get_timestamp(), "env_get_timestamp function in ISR failed"); + //test queue-related operations in ISR + TEST_ASSERT_MESSAGE(0 == env_get_current_queue_size((void *)aux_q), "env_get_current_queue_size function in ISR failed"); +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); + env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr, &my_ns_ctxt); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_ns_unbind(my_rpmsg, ns_handle); + ns_handle = NULL; + env_memset(&my_ns_ctxt, 0, sizeof(rpmsg_ns_static_context)); + rpmsg_lite_deinit(my_rpmsg); + my_rpmsg = NULL; + env_memset(&rpmsg_ctxt, 0, sizeof(struct rpmsg_lite_instance)); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(rpmsg_queue_handle queues[], uint8_t queues_storage[], rpmsg_static_queue_ctxt queues_ctxt[], struct rpmsg_lite_endpoint *volatile epts[], struct rpmsg_lite_ept_static_context epts_ctxt[], int32_t count, int32_t init_addr) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + + // invalid params for rpmsg_queue_create + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(RL_NULL, &queues_storage[0], &queues_ctxt[0]), "'rpmsg_queue_create' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(my_rpmsg, RL_NULL, &queues_ctxt[0]), "'rpmsg_queue_create' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(my_rpmsg, &queues_storage[0], RL_NULL), "'rpmsg_queue_create' with bad rpmsg_lite_dev param failed"); + + for (int32_t i = 0; i < count; i++) + { + queues[i] = rpmsg_queue_create(my_rpmsg, &queues_storage[i], &queues_ctxt[i]); + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, rpmsg_queue_rx_cb, queues[i], &epts_ctxt[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + + // invalid params for rpmsg_queue_destroy + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_queue_destroy(RL_NULL, queues[0]), "'rpmsg_queue_destroy' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_queue_destroy(my_rpmsg, RL_NULL), "'rpmsg_queue_destroy' with bad q param failed"); + + for (int32_t i = 0; i < count; i++) + { + rpmsg_queue_destroy(my_rpmsg, queues[i]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between custom created epts + * - verify simple nocopy transport between custom created epts + *****************************************************************************/ +void tc_1_send_receive(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t src; + uint32_t len; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + env_memset(data, i, DATA_LEN); + while(RL_SUCCESS != rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, 1)); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + env_memset(data, i, DATA_LEN); + while(RL_SUCCESS != rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_DONT_BLOCK)); + } + + // send message to non-existing endpoint address, message will be dropped on the receiver side + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR + 1, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + + // send - invalid rpmsg_lite_dev + result = rpmsg_lite_send(RL_NULL, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_send' with bad rpmsg_lite_dev param failed"); + + // invalid params for send + result = rpmsg_lite_send(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xFFFFFFFF, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + + // invalid params for receive + result = rpmsg_queue_recv(RL_NULL, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_recv(my_rpmsg, RL_NULL, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad q param failed"); + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, RL_NULL, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad data param failed"); + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, 0, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_BUFF_SIZE == result, "'rpmsg_queue_recv' with bad maxlen param failed"); + + // invalid params for receive_nocopy + result = rpmsg_queue_recv_nocopy(RL_NULL, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, RL_NULL, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad q param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, RL_NULL, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad data param failed"); + + // invalid params for receive_nocopy_free + result = rpmsg_queue_nocopy_free(RL_NULL, data_addr); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_nocopy_free' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_nocopy_free(my_rpmsg, RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_nocopy_free' with bad data param failed"); + + // invalid params for rpmsg_lite_release_rx_buffer - this should not be used in an app and rpmsg_queue_nocopy_free should be used instead + result = rpmsg_lite_release_rx_buffer(RL_NULL, data_addr); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_release_rx_buffer' with bad rpmsg_lite_dev param failed"); + result = rpmsg_lite_release_rx_buffer(my_rpmsg, RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_release_rx_buffer' with bad data param failed"); + + // invalid params for rpmsg_queue_get_current_size + result = rpmsg_queue_get_current_size(RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_get_current_size' with bad q param failed"); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data_addr, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + /* for invalid length remote receive */ + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); +} + +/****************************************************************************** + * Test case 2 + * - same as for test case 1 but send with copy replaced by send_nocopy + *****************************************************************************/ +void tc_2_send_receive(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t buf_size = 0; + uint32_t src; + uint32_t len; + my_rpmsg_queue_rx_cb_data_t fake_msg = {0}; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, 1); + while(RL_NULL == data_addr) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, 1); + } + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_DONT_BLOCK); + while(RL_NULL == data_addr) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_DONT_BLOCK); + } + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } + + // invalid params for alloc_tx_buffer + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL == data_addr, "negative number"); + + // invalid params for send_nocopy + result = rpmsg_lite_send_nocopy(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xFFFFFFFF); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data_addr, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + // put fake message into the queue to allow queue full state and incomming messages dropping + TEST_ASSERT_MESSAGE(1 == env_put_queue(my_queue, &fake_msg, 0), "env_put_queue function failed"); + // send a message to the secondary side to trigger messages sending from the secondary side to the primary side + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, 0, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + //wait a while to allow the secondary side to send all messages and made the receive queue full + env_sleep_msec(200); + // invalid src and len pointer params for receive + result = rpmsg_queue_recv(my_rpmsg, my_queue, RL_NULL, data, DATA_LEN, RL_NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad src and len pointer param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, RL_NULL, (char **)&data_addr, RL_NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "'rpmsg_queue_recv_nocopy' with bad bad src and len pointer param failed"); +} + +void run_tests(void *unused) +{ + int32_t result = 0; + struct rpmsg_lite_endpoint fake_ept = {0}; + struct rpmsg_lite_instance fake_rpmsg = {0}; + uint32_t bufer_size = 1; + + // call send before rpmsg_lite is initialized + result = rpmsg_lite_send(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_alloc_tx_buffer(&fake_rpmsg, &bufer_size, RL_BLOCK), "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(0 == bufer_size, "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + result = rpmsg_lite_send_nocopy(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send_nocopy' called before rpmsg_lite is initialized failed"); + + TEST_ASSERT_MESSAGE(0 == env_create_mutex(&aux_mutex, 1, &aux_mutex_ctxt), "env_create_mutex function failed"); + TEST_ASSERT_MESSAGE(0 == env_create_queue(&aux_q, 1, sizeof(uint32_t), &aux_rpmsg_queue_storage[0], &aux_queue_ctxt), "env_create_queue function failed"); + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = ts_create_epts(&my_queue, &my_rpmsg_queue_storage[0], &my_queue_ctxt, &my_ept, &my_ept_ctxt, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + /* Wait until the secondary core application issues the nameservice isr and the remote endpoint address is known. */ + while (0U == remote_addr) + { + }; + if (!result) + { +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("03_send_receive_rtos"); + __coveragescanner_install("03_send_receive_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_send_receive, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_send_receive, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); + } + env_delete_mutex(aux_mutex); + env_memset(&aux_mutex_ctxt, 0, sizeof(LOCK_STATIC_CONTEXT)); + env_delete_queue(aux_q); + env_memset(&aux_rpmsg_queue_storage, 0, RL_ENV_QUEUE_STATIC_STORAGE_SIZE); + env_memset(&aux_queue_ctxt, 0, sizeof(rpmsg_static_queue_ctxt)); + + ts_destroy_epts(&my_queue, &my_ept, 1); + my_queue = NULL; + env_memset(&my_rpmsg_queue_storage, 0, RL_ENV_QUEUE_STATIC_STORAGE_SIZE); + env_memset(&my_queue_ctxt, 0, sizeof(rpmsg_static_queue_ctxt)); + my_ept = NULL; + env_memset(&my_ept_ctxt, 0, sizeof(struct rpmsg_lite_ept_static_context)); + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); +} diff --git a/tests/03_send_receive_rtos/main_static_alloc_core1.c b/tests/03_send_receive_rtos/main_static_alloc_core1.c new file mode 100644 index 0000000..75fc1b3 --- /dev/null +++ b/tests/03_send_receive_rtos/main_static_alloc_core1.c @@ -0,0 +1,430 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include +#include "unity.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) +#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-test-channel" + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +#ifdef __COVERAGESCANNER__ +/* rpmsg_std_hdr contains a reserved field, + * this implementation of RPMSG uses this reserved + * field to hold the idx and totlen of the buffer + * not being returned to the vring in the receive + * callback function. This way, the no-copy API + * can use this field to return the buffer later. + */ +struct my_rpmsg_hdr_reserved +{ + uint16_t rfu; /* reserved for future usage */ + uint16_t idx; +}; + +RL_PACKED_BEGIN +/*! + * Common header for all rpmsg messages. + * Every message sent/received on the rpmsg bus begins with this header. + */ +struct my_rpmsg_std_hdr +{ + uint32_t src; /*!< source endpoint address */ + uint32_t dst; /*!< destination endpoint address */ + struct my_rpmsg_hdr_reserved reserved; /*!< reserved for future use */ + uint16_t len; /*!< length of payload (in bytes) */ + uint16_t flags; /*!< message flags */ +} RL_PACKED_END; + +RL_PACKED_BEGIN +/*! + * Common message structure. + * Contains the header and the payload. + */ +struct my_rpmsg_std_msg +{ + struct my_rpmsg_std_hdr hdr; /*!< RPMsg message header */ + uint8_t data[1]; /*!< bytes of message payload data */ +} RL_PACKED_END; +#endif /*__COVERAGESCANNER__*/ + +struct rpmsg_lite_endpoint *volatile my_ept = NULL; +struct rpmsg_lite_ept_static_context my_ept_ctxt; + +rpmsg_queue_handle my_queue = NULL; +rpmsg_static_queue_ctxt my_queue_ctxt = {0}; +uint8_t my_rpmsg_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt = {0}; +rpmsg_ns_handle ns_handle = NULL; +rpmsg_ns_static_context my_ns_ctxt = {0}; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + + /* wait for a while to allow the primary side to bind_ns and register the NS callback */ + env_sleep_msec(200); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0), &my_ns_ctxt); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_ns_unbind(my_rpmsg, ns_handle); + ns_handle = NULL; + env_memset(&my_ns_ctxt, 0, sizeof(rpmsg_ns_static_context)); + rpmsg_lite_deinit(my_rpmsg); + my_rpmsg = NULL; + env_memset(&rpmsg_ctxt, 0, sizeof(struct rpmsg_lite_instance)); + return 0; +} + +// utility: create number of epts +int32_t ts_create_epts(rpmsg_queue_handle queues[], uint8_t queues_storage[], rpmsg_static_queue_ctxt queues_ctxt[], struct rpmsg_lite_endpoint *volatile epts[], struct rpmsg_lite_ept_static_context epts_ctxt[], int32_t count, int32_t init_addr) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + + // invalid params for rpmsg_queue_create + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(RL_NULL, &queues_storage[0], &queues_ctxt[0]), "'rpmsg_queue_create' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(my_rpmsg, RL_NULL, &queues_ctxt[0]), "'rpmsg_queue_create' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_queue_create(my_rpmsg, &queues_storage[0], RL_NULL), "'rpmsg_queue_create' with bad rpmsg_lite_dev param failed"); + + for (int32_t i = 0; i < count; i++) + { + queues[i] = rpmsg_queue_create(my_rpmsg, &queues_storage[i], &queues_ctxt[i]); + epts[i] = rpmsg_lite_create_ept(my_rpmsg, init_addr + i, rpmsg_queue_rx_cb, queues[i], &epts_ctxt[i]); + TEST_ASSERT_MESSAGE(NULL != epts[i], "'rpmsg_lite_create_ept' failed"); + TEST_ASSERT_MESSAGE(init_addr + i == epts[i]->addr, + "'rpmsg_lite_create_ept' does not provide expected address"); + } + return 0; +} + +// utility: destroy number of epts +int32_t ts_destroy_epts(rpmsg_queue_handle queues[], struct rpmsg_lite_endpoint *volatile epts[], int32_t count) +{ + TEST_ASSERT_MESSAGE(queues != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(epts != NULL, "NULL param"); + TEST_ASSERT_MESSAGE(count > 0, "negative number"); + + // invalid params for rpmsg_queue_destroy + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_queue_destroy(RL_NULL, queues[0]), "'rpmsg_queue_destroy' with bad rpmsg_lite_dev param failed"); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == rpmsg_queue_destroy(my_rpmsg, RL_NULL), "'rpmsg_queue_destroy' with bad q param failed"); + + for (int32_t i = 0; i < count; i++) + { + rpmsg_queue_destroy(my_rpmsg, queues[i]); + rpmsg_lite_destroy_ept(my_rpmsg, epts[i]); + } + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/****************************************************************************** + * Test case 1 + * - verify simple transport between default epts of default channels + * - verify simple nocopy transport between default epts of default channels + * - verify simple transport between custom created epts of default channels + * - verify simple nocopy transport between custom created epts of default channels + *****************************************************************************/ +void tc_1_receive_send(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t src; + uint32_t len; +#ifdef __COVERAGESCANNER__ + uint16_t my_rpmsg_hdr_idx = 0; + struct my_rpmsg_std_msg *msg; +#endif /*__COVERAGESCANNER__*/ + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data_addr, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + +#ifdef __COVERAGESCANNER__ + /* Force ERROR_VRING_NO_BUFF error in virtqueue_add_consumed_buffer() when RL_ASSERT is off in Coco tests */ + msg = (struct my_rpmsg_std_msg *)(void *)((char *)(data_addr)-offsetof(struct my_rpmsg_std_msg, data)); + my_rpmsg_hdr_idx = msg->hdr.reserved.idx; + msg->hdr.reserved.idx = 2*RL_BUFFER_COUNT; + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + msg->hdr.reserved.idx = my_rpmsg_hdr_idx; +#endif /*__COVERAGESCANNER__*/ + + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + /* for invalid length remote receive */ + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + env_memset(data, i, DATA_LEN); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + env_memset(data, i, DATA_LEN); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + // send message to non-existing endpoint address, message will be dropped on the receiver side + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR + 1, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + + // send - invalid rpmsg_lite_dev + result = rpmsg_lite_send(RL_NULL, my_ept, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_send' with bad rpmsg_lite_dev param failed"); + + // invalid params for send + result = rpmsg_lite_send(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data, 0xFFFFFFFF, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + + // invalid params for receive + result = rpmsg_queue_recv(RL_NULL, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_recv(my_rpmsg, RL_NULL, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad q param failed"); + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, RL_NULL, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv' with bad data param failed"); + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, 0, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_BUFF_SIZE == result, "'rpmsg_queue_recv' with bad maxlen param failed"); + + // invalid params for receive_nocopy + result = rpmsg_queue_recv_nocopy(RL_NULL, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, RL_NULL, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad q param failed"); + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, RL_NULL, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_recv_nocopy' with bad data param failed"); + + // invalid params for receive_nocopy_free + result = rpmsg_queue_nocopy_free(RL_NULL, data_addr); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_nocopy_free' with bad rpmsg_lite_dev param failed"); + result = rpmsg_queue_nocopy_free(my_rpmsg, RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_queue_nocopy_free' with bad data param failed"); + + // invalid params for rpmsg_lite_release_rx_buffer - this should not be used in an app and rpmsg_queue_nocopy_free should be used instead + result = rpmsg_lite_release_rx_buffer(RL_NULL, data_addr); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_release_rx_buffer' with bad rpmsg_lite_dev param failed"); + result = rpmsg_lite_release_rx_buffer(my_rpmsg, RL_NULL); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_lite_release_rx_buffer' with bad data param failed"); +} + +/****************************************************************************** + * Test case 2 + * - same as for test case 1 but send with copy replaced by send_nocopy + *****************************************************************************/ +void tc_2_receive_send(void) +{ + int32_t result = 0; + char data[DATA_LEN] = {0}; + void *data_addr = NULL; + uint32_t buf_size = 0; + uint32_t src; + uint32_t len; + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + result = rpmsg_queue_recv_nocopy(my_rpmsg, my_queue, &src, (char **)&data_addr, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data_addr, i, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = rpmsg_queue_nocopy_free(my_rpmsg, data_addr); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } + + for (int32_t i = 0; i < TC_TRANSFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } + + // invalid params for alloc_tx_buffer + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, NULL, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL == data_addr, "negative number"); + + // invalid params for send_nocopy + result = rpmsg_lite_send_nocopy(my_rpmsg, NULL, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, NULL, DATA_LEN); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, 0xFFFFFFFF); + TEST_ASSERT_MESSAGE(0 != result, "negative number"); + + // wait until all messages are consumed on the primary side and a new message is received + result = rpmsg_queue_recv(my_rpmsg, my_queue, &src, data, DATA_LEN, &len, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = pattern_cmp(data, 0, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + // send RL_BUFFER_COUNT messages to made the message queue on the primary side full + for (int32_t i = 0; i < RL_BUFFER_COUNT; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE(NULL != data_addr, "negative number"); + TEST_ASSERT_MESSAGE(0 != buf_size, "negative number"); + env_memset(data_addr, i, DATA_LEN); + result = rpmsg_lite_send_nocopy(my_rpmsg, my_ept, TC_REMOTE_EPT_ADDR, data_addr, DATA_LEN); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + data_addr = NULL; + } +} + +void run_tests(void *unused) +{ + int32_t result = 0; + struct rpmsg_lite_endpoint fake_ept = {0}; + struct rpmsg_lite_instance fake_rpmsg = {0}; + uint32_t bufer_size = 1; + + // call send before rpmsg_lite is initialized + result = rpmsg_lite_send(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN, RL_BLOCK); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(RL_NULL == rpmsg_lite_alloc_tx_buffer(&fake_rpmsg, &bufer_size, RL_BLOCK), "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + TEST_ASSERT_MESSAGE(0 == bufer_size, "'rpmsg_lite_alloc_tx_buffer' called before rpmsg_lite is initialized failed"); + result = rpmsg_lite_send_nocopy(&fake_rpmsg, &fake_ept, TC_REMOTE_EPT_ADDR, (char*)0x12345678, DATA_LEN); + TEST_ASSERT_MESSAGE(RL_NOT_READY == result, "'rpmsg_lite_send_nocopy' called before rpmsg_lite is initialized failed"); + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + result = ts_create_epts(&my_queue, &my_rpmsg_queue_storage[0], &my_queue_ctxt, &my_ept, &my_ept_ctxt, 1, TC_LOCAL_EPT_ADDR); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + TEST_ASSERT_MESSAGE(RL_SUCCESS == rpmsg_ns_announce(my_rpmsg, my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE), "'rpmsg_ns_announce' failed"); + + if (!result) + { +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("03_send_receive_rtos_sec_core"); + __coveragescanner_install("03_send_receive_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_receive_send, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_receive_send, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); + } + ts_destroy_epts(&my_queue, &my_ept, 1); + my_queue = NULL; + env_memset(&my_rpmsg_queue_storage, 0, RL_ENV_QUEUE_STATIC_STORAGE_SIZE); + env_memset(&my_queue_ctxt, 0, sizeof(rpmsg_static_queue_ctxt)); + my_ept = NULL; + env_memset(&my_ept_ctxt, 0, sizeof(struct rpmsg_lite_ept_static_context)); + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); +} diff --git a/tests/03_send_receive_rtos/readme.txt b/tests/03_send_receive_rtos/readme.txt new file mode 100644 index 0000000..309a7c6 --- /dev/null +++ b/tests/03_send_receive_rtos/readme.txt @@ -0,0 +1,6 @@ +03_send_receive_rtos test suite + + - FreeRTOS/ThreadX/XOS-based project, covering both the static allocation (#define RL_USE_STATIC_API (1) in rpmsg_config.h) and the dynamic allocation (#define RL_USE_STATIC_API (0) in rpmsg_config.h) + + - test all send functions with valid/invalid parameters + - test all receive functions with valid/invalid parameters \ No newline at end of file diff --git a/tests/04_ping_pong/main_core0.c b/tests/04_ping_pong/main_core0.c new file mode 100644 index 0000000..83263b6 --- /dev/null +++ b/tests/04_ping_pong/main_core0.c @@ -0,0 +1,393 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "rpmsg_ns.h" +#include +#include "unity.h" +#include "assert.h" +#include "app.h" +#include "pingpong_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_LOCAL_EPT_ADDR (40) +//#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +/* This is for the responder side */ +volatile int32_t message_received = 0; +volatile int32_t message_received_2 = 0; +ACKNOWLEDGE_MESSAGE ack_msg = {0}; +char trans_data[100] = {0}; +struct rpmsg_lite_endpoint *ctrl_ept = {0}; +struct rpmsg_lite_endpoint *ept_with_addr_1 = {0}; +struct rpmsg_lite_ept_static_context ctrl_ept_ctxt; +struct rpmsg_lite_ept_static_context ept_with_addr_1_ctxt; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt; +rpmsg_ns_handle ns_handle = NULL; +rpmsg_ns_static_context nameservice_ept_ctxt; +volatile uint32_t remote_addr = 0U; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ + uint32_t *data = (uint32_t *)user_data; + + *data = new_ept; +} + + +// control ept callback +int32_t test_read_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) +{ + TEST_ASSERT_MESSAGE(0 == message_received, "interrupt missed"); + ack_msg = *((ACKNOWLEDGE_MESSAGE_PTR)payload); + message_received = 1; + return RL_RELEASE; +} + +// custom ept callback +int32_t ept_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) +{ + TEST_ASSERT_MESSAGE(0 == message_received_2, "interrupt missed"); + env_memcpy((void *)trans_data, payload, payload_len); + message_received_2 = 1; + return RL_RELEASE; +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + //Register name service callback as soon as the rpmsg_lite_master_init() finishes + //(virtqueue_kick unblocks the rpmsg_lite_wait_for_link_up() on the remote side and rpmsg_ns_announce is sent consequently) + // invalid params for rpmsg_ns_bind + ns_handle = rpmsg_ns_bind(my_rpmsg, RL_NULL, (void *)&remote_addr, &nameservice_ept_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with bad app_cb param failed"); + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0), RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with bad ns_ept_ctxt param failed"); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr, &nameservice_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + + /* Wait until the secondary core application issues the nameservice isr and the remote endpoint address is known. */ + while (0U == remote_addr) + { + }; + + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, test_read_cb, NULL, &ctrl_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + /* This endpoint is created just to force the for loop iteration in rpmsg_lite_create_ept when RL_ADDR_ANY address is passed as the parameter */ + ept_with_addr_1 = rpmsg_lite_create_ept(my_rpmsg, 1, test_read_cb, NULL, &ept_with_addr_1_ctxt); + TEST_ASSERT_MESSAGE(NULL != ept_with_addr_1, "'rpmsg_lite_create_ept' failed"); + + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_lite_destroy_ept(my_rpmsg, ept_with_addr_1); + rpmsg_ns_unbind(my_rpmsg, ns_handle); + rpmsg_lite_deinit(my_rpmsg); + ept_with_addr_1 = NULL; + ctrl_ept = NULL; + remote_addr = 0U; + ns_handle = NULL; + my_rpmsg = NULL; + return 0; +} + +// this test case is to test the endpoint functionality. +void tc_1_create_delete_ep_cmd_sender(void) +{ + void *mutex = NULL; + int32_t result = 0; + uint32_t data = EP_SIGNATURE; + uint32_t dest = 0; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ep_param; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ep_param; + CONTROL_MESSAGE control_msg = {0}; + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! failed to init"); + if (result) + goto end; + + result = env_create_mutex(&mutex, 1, NULL); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! failed to create mutex"); + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + + // create ep command + data_create_ep_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ep_param.ept_to_create_addr = RL_ADDR_ANY; + control_msg.CMD = CTR_CMD_CREATE_EP; + control_msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)control_msg.DATA, (void *)(&data_create_ep_param), + sizeof(struct control_message_data_create_ept_param)); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&control_msg, + sizeof(struct control_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + + /* Check acknowledge message */ + TEST_ASSERT_MESSAGE((ack_msg.CMD_ACK == CTR_CMD_CREATE_EP ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting acknowledge of create endpoint command operation"); + TEST_ASSERT_MESSAGE((ack_msg.RETURN_VALUE == 0 ? 1 : (0 != ts_deinit_rpmsg())), + "error! create endpoint command operation in other side failed"); + dest = ack_msg.RESP_DATA[0]; + /* send message to newly created endpoint */ + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, dest, (char *)&data, sizeof(uint32_t), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + + // create another endpoint with same address + data_create_ep_param.ept_to_create_addr = dest; + env_memcpy((void *)control_msg.DATA, (void *)(&data_create_ep_param), + sizeof(struct control_message_data_create_ept_param)); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&control_msg, + sizeof(struct control_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + /* Check acknowledge message */ + TEST_ASSERT_MESSAGE((ack_msg.CMD_ACK == CTR_CMD_CREATE_EP ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting acknowledge of create endpoint command operation"); + TEST_ASSERT_MESSAGE((ack_msg.RETURN_VALUE != 0 ? 1 : (0 != ts_deinit_rpmsg())), + "error! create new endpoint with same address as another endpoint in the other side failed"); + + // delete created endpoint + /* destroy endpoint not created yet */ + data_destroy_ep_param.ept_to_ack_addr = ctrl_ept->addr; + data_destroy_ep_param.ept_to_destroy_addr = dest + 1; + control_msg.CMD = CTR_CMD_DESTROY_EP; + control_msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)control_msg.DATA, (void *)(&data_destroy_ep_param), + sizeof(struct control_message_data_destroy_ept_param)); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&control_msg, + sizeof(struct control_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + /* Check acknowledge message */ + TEST_ASSERT_MESSAGE((ack_msg.CMD_ACK == CTR_CMD_DESTROY_EP ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting acknowledge of destroy endpoint command operation"); + TEST_ASSERT_MESSAGE((ack_msg.RETURN_VALUE != 0 ? 1 : (0 != ts_deinit_rpmsg())), + "error! destroy an unexisted endpoint failed"); + /* destroy endpoint created before */ + data_destroy_ep_param.ept_to_destroy_addr = dest; + env_memcpy((void *)control_msg.DATA, (void *)(&data_destroy_ep_param), + sizeof(struct control_message_data_destroy_ept_param)); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&control_msg, + sizeof(struct control_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + /* Check acknowledge message */ + TEST_ASSERT_MESSAGE((ack_msg.CMD_ACK == CTR_CMD_DESTROY_EP ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting acknowledge of destroy endpoint command operation"); + TEST_ASSERT_MESSAGE((ack_msg.RETURN_VALUE == 0 ? 1 : (0 != ts_deinit_rpmsg())), + "error! destroy an endpoint failed"); + + env_delete_mutex(mutex); +end: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "system clean up error"); +} + +// this test case is to test the send functionality. +void tc_2_send_cmd_sender(void) +{ + void *mutex = NULL; + int32_t result = 0; + char data[10] = "abc"; + char data_2[15] = "abc nocopy"; + CONTROL_MESSAGE control_msg = {0}; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param = {0}; + struct rpmsg_lite_endpoint *my_ept = {0}; + struct rpmsg_lite_ept_static_context my_ept_ctxt; + + result = env_create_mutex(&mutex, 1, NULL); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! failed to create mutex"); + + env_lock_mutex(mutex); + message_received = 0; + message_received_2 = 0; + env_unlock_mutex(mutex); + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! failed to init"); + if (result) + goto end; + + // this custom endpoint is to receive the data from responder. + my_ept = rpmsg_lite_create_ept(my_rpmsg, RL_ADDR_ANY, ept_cb, NULL, &my_ept_ctxt); + TEST_ASSERT_MESSAGE((NULL != my_ept ? 1 : (0 != ts_deinit_rpmsg())), "error! creation of an endpoint failed"); + + // send command + // send message "abc" and get back message "abc" + data_send_param.dest_addr = my_ept->addr; + data_send_param.ept_to_ack_addr = ctrl_ept->addr; + env_memcpy((void *)data_send_param.msg, (void *)data, 4); + data_send_param.msg_size = 4; + control_msg.CMD = CTR_CMD_SEND; + control_msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)control_msg.DATA, (void *)(&data_send_param), sizeof(struct control_message_data_send_param)); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&control_msg, + sizeof(struct control_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + /* wait for acknowledge message */ + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + /* Check acknowledge message */ + TEST_ASSERT_MESSAGE((ack_msg.CMD_ACK == CTR_CMD_SEND ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting acknowledge of send command operation"); + TEST_ASSERT_MESSAGE((ack_msg.RETURN_VALUE == 0 ? 1 : (0 != ts_deinit_rpmsg())), + "error! send operation in the other side failed"); + /* wait for responder's message */ + while (!message_received_2) + ; + env_lock_mutex(mutex); + message_received_2 = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((0 == env_strncmp(trans_data, data, 3) ? 1 : (0 != ts_deinit_rpmsg())), + "error! incorrect data received"); + + // send an empty message "" and get back "cba" + control_msg.ACK_REQUIRED = ACK_REQUIRED_NO; + data_send_param.msg[0] = '\0'; + data_send_param.msg_size = 1; + env_memcpy((void *)control_msg.DATA, (void *)(&data_send_param), sizeof(struct control_message_data_send_param)); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&control_msg, + sizeof(struct control_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + /* wait for responder's message */ + while (!message_received_2) + ; + env_lock_mutex(mutex); + message_received_2 = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((0 == env_strncmp(trans_data, "cba", 3) ? 1 : (0 != ts_deinit_rpmsg())), + "error! incorrect data received"); + + // send nocopy command + // send message "abc nocopy" and get back message "abc nocopy" + data_send_param.dest_addr = my_ept->addr; + data_send_param.ept_to_ack_addr = ctrl_ept->addr; + env_memcpy((void *)data_send_param.msg, (void *)data_2, 11); + data_send_param.msg_size = 11; + control_msg.CMD = CTR_CMD_SEND_NO_COPY; + control_msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)control_msg.DATA, (void *)(&data_send_param), sizeof(struct control_message_data_send_param)); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&control_msg, + sizeof(struct control_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + /* wait for acknowledge message */ + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + /* Check acknowledge message */ + TEST_ASSERT_MESSAGE((ack_msg.CMD_ACK == CTR_CMD_SEND_NO_COPY ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting acknowledge of send nocopy command operation"); + TEST_ASSERT_MESSAGE((ack_msg.RETURN_VALUE == 0 ? 1 : (0 != ts_deinit_rpmsg())), + "error! send operation in the other side failed"); + /* wait for responder's message */ + while (!message_received_2) + ; + env_lock_mutex(mutex); + message_received_2 = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((0 == env_strncmp(trans_data, data, 3) ? 1 : (0 != ts_deinit_rpmsg())), + "error! incorrect data received"); + + // send an empty message "" and get back "cba nocopy" + control_msg.ACK_REQUIRED = ACK_REQUIRED_NO; + data_send_param.msg[0] = '\0'; + data_send_param.msg_size = 1; + env_memcpy((void *)control_msg.DATA, (void *)(&data_send_param), sizeof(struct control_message_data_send_param)); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&control_msg, + sizeof(struct control_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + /* wait for responder's message */ + while (!message_received_2) + ; + env_lock_mutex(mutex); + message_received_2 = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((0 == env_strncmp(trans_data, "cba nocopy", 10) ? 1 : (0 != ts_deinit_rpmsg())), + "error! incorrect data received"); + + rpmsg_lite_destroy_ept(my_rpmsg, my_ept); + env_delete_mutex(mutex); +end: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "system clean up error"); +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("04_ping_pong"); + __coveragescanner_install("04_ping_pong.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_create_delete_ep_cmd_sender, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_send_cmd_sender, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); +} + +/* EOF */ diff --git a/tests/04_ping_pong/main_core1.c b/tests/04_ping_pong/main_core1.c new file mode 100644 index 0000000..fcd0081 --- /dev/null +++ b/tests/04_ping_pong/main_core1.c @@ -0,0 +1,413 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include "rpmsg_ns.h" +#include +#include "unity.h" +#include "assert.h" +#include "app.h" +#include "pingpong_common.h" + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +CONTROL_MESSAGE control_msg = {0}; +uint32_t trans_data = 0; + +/* This is for the responder side */ +volatile int32_t message_received = 0; +volatile int32_t message_received_2 = 0; +ACKNOWLEDGE_MESSAGE ack_msg = {0}; +struct rpmsg_lite_endpoint *ctrl_ept = {0}; +struct rpmsg_lite_ept_static_context ctrl_ept_ctxt; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt; +rpmsg_ns_handle ns_handle = NULL; +rpmsg_ns_static_context nameservice_ept_ctxt; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ +} + + +//copied from the rpsmg_lite.c (internal function) +static struct llist *test_rpmsg_lite_get_endpoint_from_addr(struct rpmsg_lite_instance *rpmsg_lite_dev, uint32_t addr) +{ + struct llist *rl_ept_lut_head; + + rl_ept_lut_head = rpmsg_lite_dev->rl_endpoints; + while (rl_ept_lut_head) + { + struct rpmsg_lite_endpoint *rl_ept = (struct rpmsg_lite_endpoint *)rl_ept_lut_head->data; + if (rl_ept->addr == addr) + { + return rl_ept_lut_head; + } + rl_ept_lut_head = rl_ept_lut_head->next; + } + return RL_NULL; +} + +// control ept callback +int32_t test_read_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) +{ + TEST_ASSERT_MESSAGE(0 == message_received, "interrupt missed"); + + env_memcpy((void *)&control_msg, payload, payload_len); + message_received = 1; + + return RL_RELEASE; +} + +// custom ept callback +int32_t ept_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) +{ + TEST_ASSERT_MESSAGE(0 == message_received_2, "interrupt missed"); + env_memcpy((void *)&trans_data, payload, payload_len); + message_received_2 = 1; + + return RL_RELEASE; +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + + /* wait for a while to allow the primary side to bind_ns and register the NS callback */ + env_sleep_msec(200); + + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, test_read_cb, NULL, &ctrl_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_lite_deinit(my_rpmsg); + ctrl_ept = NULL; + my_rpmsg = NULL; + return 0; +} + +// this test case is to test the endpoint functionality. +void tc_1_create_delete_ep_cmd_responder(void) +{ + void *mutex = NULL; + int32_t result = 0; + struct rpmsg_lite_endpoint *my_ept, *ept_to_delete; + struct rpmsg_lite_ept_static_context my_ept_ctxt; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM_PTR data_create_ep_param; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM_PTR data_destroy_ep_param; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! failed to init"); + if (result) + goto end; + + // invalid params for rpmsg_ns_bind + ns_handle = rpmsg_ns_bind(my_rpmsg, RL_NULL, ((void *)0), &nameservice_ept_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with bad app_cb param failed"); + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0), RL_NULL); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with bad ns_ept_ctxt param failed"); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0), &nameservice_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + + // invalid params for rpmsg_ns_announce + result = rpmsg_ns_announce(my_rpmsg, ctrl_ept, RL_NULL, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_ns_announce' with bad ept_name param failed"); + result = rpmsg_ns_announce(my_rpmsg, RL_NULL, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_ns_announce' with bad new_ept param failed"); + + // send invalid NS message to the RL_NS_EPT_ADDR - wrong paylod_len identified in the ns cb and the message is dropped (condition coverage increase) + rpmsg_lite_send(my_rpmsg, ctrl_ept, RL_NS_EPT_ADDR, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + + /* wait for a while to allow the primary side to bind_ns and register the NS callback */ + env_sleep_msec(200); + // send correct NS message + result = rpmsg_ns_announce(my_rpmsg, ctrl_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "'rpmsg_ns_announce' failed"); + + result = env_create_mutex(&mutex, 1, NULL); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! failed to create mutex"); + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + + // create an endpoint. + /* wait for control message */ + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((control_msg.CMD == CTR_CMD_CREATE_EP ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting the create endpoint command"); + data_create_ep_param = env_allocate_memory(sizeof(struct control_message_data_create_ept_param)); + env_memcpy((void *)(data_create_ep_param), (void *)control_msg.DATA, + sizeof(struct control_message_data_create_ept_param)); + my_ept = rpmsg_lite_create_ept(my_rpmsg, data_create_ep_param->ept_to_create_addr, ept_cb, NULL, &my_ept_ctxt); + TEST_ASSERT_MESSAGE((NULL != my_ept ? 1 : (0 != ts_deinit_rpmsg())), "error! creation of an endpoint failed"); + + /* this is to send back the ack message */ + if (control_msg.ACK_REQUIRED == ACK_REQUIRED_YES) + { + env_memset(&ack_msg, 0, sizeof(ACKNOWLEDGE_MESSAGE)); + ack_msg.CMD_ACK = CTR_CMD_CREATE_EP; + ack_msg.RETURN_VALUE = (my_ept == NULL); + ack_msg.RESP_DATA[0] = my_ept->addr; + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_create_ep_param->ept_to_ack_addr, (char *)&ack_msg, + sizeof(struct acknowledge_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send acknowledge message failed"); + TEST_ASSERT_MESSAGE((my_ept != NULL ? 1 : (0 != ts_deinit_rpmsg())), "error! endpoint creation failed"); + + /* wait for a message from sender to newly created endpoint */ + while (!message_received_2) + ; + TEST_ASSERT_MESSAGE((EP_SIGNATURE == trans_data ? 1 : (0 != ts_deinit_rpmsg())), + "error! failed to receive from custom endpoint"); + trans_data = 0; + env_lock_mutex(mutex); + message_received_2 = 0; + env_unlock_mutex(mutex); + } + + // create another endpoint with same address as above. + /* wait for control message */ + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((control_msg.CMD == CTR_CMD_CREATE_EP ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting the create endpoint command"); + env_memcpy((void *)(data_create_ep_param), (void *)control_msg.DATA, + sizeof(struct control_message_data_create_ept_param)); + my_ept = NULL; + my_ept = rpmsg_lite_create_ept(my_rpmsg, data_create_ep_param->ept_to_create_addr, ept_cb, NULL, &my_ept_ctxt); + /* send the ack message if required */ + if (control_msg.ACK_REQUIRED == ACK_REQUIRED_YES) + { + env_memset(&ack_msg, 0, sizeof(ACKNOWLEDGE_MESSAGE)); + ack_msg.CMD_ACK = CTR_CMD_CREATE_EP; + ack_msg.RETURN_VALUE = (my_ept == NULL); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_create_ep_param->ept_to_ack_addr, (char *)&ack_msg, + sizeof(struct acknowledge_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send acknowledge message failed"); + TEST_ASSERT_MESSAGE((my_ept == NULL ? 1 : (0 != ts_deinit_rpmsg())), + "error! creation of endpoint with similar address failed"); + } + env_free_memory(data_create_ep_param); + + // delete endpoint + data_destroy_ep_param = env_allocate_memory(sizeof(struct control_message_data_destroy_ept_param)); + for (int32_t i = 0; i < 2; i++) + { + /* wait for control message */ + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((control_msg.CMD == CTR_CMD_DESTROY_EP ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting the destroy endpoint command"); + env_memcpy((void *)(data_destroy_ep_param), (void *)control_msg.DATA, + sizeof(struct control_message_data_destroy_ept_param)); + struct llist *node; + node = test_rpmsg_lite_get_endpoint_from_addr(my_rpmsg, data_destroy_ep_param->ept_to_destroy_addr); + if (node != NULL) + { + ept_to_delete = (struct rpmsg_lite_endpoint *)node->data; + rpmsg_lite_destroy_ept(my_rpmsg, ept_to_delete); + } + /* send the ack message if required */ + if (control_msg.ACK_REQUIRED == ACK_REQUIRED_YES) + { + env_memset(&ack_msg, 0, sizeof(ACKNOWLEDGE_MESSAGE)); + ack_msg.CMD_ACK = CTR_CMD_DESTROY_EP; + ack_msg.RETURN_VALUE = (node == NULL); + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_destroy_ep_param->ept_to_ack_addr, (char *)&ack_msg, + sizeof(struct acknowledge_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send acknowledge message failed"); + } + } + env_free_memory(data_destroy_ep_param); + + env_delete_mutex(mutex); +end: + rpmsg_ns_unbind(my_rpmsg, ns_handle); + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "system clean up error"); +} + +// this test case is to test the send functionality. +void tc_2_send_cmd_responder(void) +{ + void *mutex = NULL, *data_addr = NULL; + int32_t result = 0; + uint32_t buf_size; + CONTROL_MESSAGE_DATA_SEND_PARAM_PTR data_send_param; + char data[4] = "cba"; + char data_2[11] = "cba nocopy"; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + + result = env_create_mutex(&mutex, 1, NULL); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! failed to create mutex"); + + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! failed to init"); + if (result) + goto end; + + // send NS message + result = rpmsg_ns_announce(my_rpmsg, ctrl_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "'rpmsg_ns_announce' failed"); + + data_send_param = env_allocate_memory(sizeof(struct control_message_data_send_param)); + // execute the send command + for (int32_t i = 0; i < 2; i++) + { + /* wait for control message */ + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((control_msg.CMD == CTR_CMD_SEND ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting the send command"); + env_memcpy((void *)(data_send_param), (void *)control_msg.DATA, sizeof(struct control_message_data_send_param)); + if (env_strncmp(data_send_param->msg, "", 1) == 0) + { + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param->dest_addr, data, 4, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + } + else + { + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param->dest_addr, data_send_param->msg, + data_send_param->msg_size, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + } + /* send the ack message if required */ + if (control_msg.ACK_REQUIRED == ACK_REQUIRED_YES) + { + env_memset(&ack_msg, 0, sizeof(ACKNOWLEDGE_MESSAGE)); + ack_msg.CMD_ACK = CTR_CMD_SEND; + ack_msg.RETURN_VALUE = result; + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param->ept_to_ack_addr, (char *)&ack_msg, + sizeof(struct acknowledge_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send acknowledge message failed"); + } + } + + // execute the send nocopy command + for (int32_t i = 0; i < 2; i++) + { + /* wait for control message */ + while (!message_received) + ; + env_lock_mutex(mutex); + message_received = 0; + env_unlock_mutex(mutex); + TEST_ASSERT_MESSAGE((control_msg.CMD == CTR_CMD_SEND_NO_COPY ? 1 : (0 != ts_deinit_rpmsg())), + "error! expecting the send nocopy command"); + env_memcpy((void *)(data_send_param), (void *)control_msg.DATA, sizeof(struct control_message_data_send_param)); + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + TEST_ASSERT_MESSAGE((NULL != data_addr ? 1 : (0 != ts_deinit_rpmsg())), "error! no more buffer available"); + if (env_strncmp(data_send_param->msg, "", 1) == 0) + { + env_memcpy(data_addr, data_2, 11); + result = rpmsg_lite_send_nocopy(my_rpmsg, ctrl_ept, data_send_param->dest_addr, data_addr, 11); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + data_addr = NULL; + } + else + { + env_memcpy(data_addr, data_send_param->msg, data_send_param->msg_size); + result = rpmsg_lite_send_nocopy(my_rpmsg, ctrl_ept, data_send_param->dest_addr, data_addr, + data_send_param->msg_size); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send message failed"); + data_addr = NULL; + } + /* send the ack message if required */ + if (control_msg.ACK_REQUIRED == ACK_REQUIRED_YES) + { + env_memset(&ack_msg, 0, sizeof(ACKNOWLEDGE_MESSAGE)); + ack_msg.CMD_ACK = CTR_CMD_SEND_NO_COPY; + ack_msg.RETURN_VALUE = result; + result = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param->ept_to_ack_addr, (char *)&ack_msg, + sizeof(struct acknowledge_message), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == result ? 1 : (0 != ts_deinit_rpmsg())), "error! send acknowledge message failed"); + } + } + + env_free_memory(data_send_param); + env_delete_mutex(mutex); +end: + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "system clean up error"); +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("04_ping_pong_sec_core"); + __coveragescanner_install("04_ping_pong_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_create_delete_ep_cmd_responder, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_send_cmd_responder, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); +} + +/* EOF */ diff --git a/tests/04_ping_pong/pingpong_common.h b/tests/04_ping_pong/pingpong_common.h new file mode 100644 index 0000000..45ac48c --- /dev/null +++ b/tests/04_ping_pong/pingpong_common.h @@ -0,0 +1,110 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __common_h__ +#define __common_h__ + +#define CTR_CMD_CREATE_EP (10) +#define CTR_CMD_DESTROY_EP (11) +#define CTR_CMD_SEND (12) +#define CTR_CMD_SEND_NO_COPY (13) +#define CTR_CMD_RECV (14) +#define CTR_CMD_CREATE_CHANNEL (15) +#define CTR_CMD_DESTROY_CHANNEL (16) + +/* recv command modes */ +#define CMD_RECV_MODE_COPY (1) +#define CMD_RECV_MODE_NOCOPY (2) + +/* send command modes */ +#define CMD_SEND_MODE_COPY (1) +#define CMD_SEND_MODE_NOCOPY (2) + +/* acknowledge required? */ +#define ACK_REQUIRED_YES (1) +#define ACK_REQUIRED_NO (0) + +#define INIT_EPT_ADDR (2) +#define TEST_CNT (10) +#define TC_EPT_COUNT (6) +#define RESPONDER_APP_BUF_SIZE (30) +#define SENDER_APP_BUF_SIZE (50) +#define CMD_SEND_MSG_SIZE (20) +#define BUFFER_MAX_LENGTH (100) + +#define CMD_RECV_TIMEOUT_MS (2000) + +#define DESTROY_ALL_EPT (0xFFFFFFFF) + +#define EP_SIGNATURE (('H' << 24) | ('D' << 16) | ('O' << 8) | ('D' << 0)) + +#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-test-channel" + +typedef struct control_message +{ + char CMD; + char ACK_REQUIRED; + char DATA[BUFFER_MAX_LENGTH]; +} CONTROL_MESSAGE, *CONTROL_MESSAGE_PTR; + +typedef struct acknowledge_message +{ + char CMD_ACK; + int32_t RETURN_VALUE; + int32_t TIMEOUT_MSEC; + char RESP_DATA[BUFFER_MAX_LENGTH]; +} ACKNOWLEDGE_MESSAGE, *ACKNOWLEDGE_MESSAGE_PTR; + +/* create endpoint data message format */ +typedef struct control_message_data_create_ept_param +{ + uint32_t ept_to_create_addr; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM, *CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM_PTR; + +/* destroy endpoint data message format */ +typedef struct control_message_data_destroy_ept_param +{ + uint32_t ept_to_destroy_addr; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM, *CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM_PTR; + +/* create channel data message format */ +typedef struct control_message_data_create_channel_param +{ + char name[32]; + uint32_t ep_to_ack_addr; +} CONTROL_MESSAGE_DATA_CREATE_CHANNEL_PARAM, *CONTROL_MESSAGE_DATA_CREATE_CHANNEL_PARAM_PTR; + +/* delete channel data message format */ +typedef struct control_message_data_delete_channel_param +{ + char name[32]; + uint32_t ep_to_ack_addr; +} CONTROL_MESSAGE_DATA_DELETE_CHANNEL_PARAM, *CONTROL_MESSAGE_DATA_DELETE_CHANNEL_PARAM_PTR; + +/* send data message format */ +typedef struct control_message_data_send_param +{ + uint32_t dest_addr; + char msg[BUFFER_MAX_LENGTH - 20]; + int32_t msg_size; + uint32_t repeat_count; + uint32_t mode; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_SEND_PARAM, *CONTROL_MESSAGE_DATA_SEND_PARAM_PTR; + +/* receive data message format */ +typedef struct control_message_data_recv_param +{ + struct rpmsg_endpoint *responder_ept; + int32_t buffer_size; + uint32_t timeout_ms; + uint32_t mode; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_RECV_PARAM, *CONTROL_MESSAGE_DATA_RECV_PARAM_PTR; + +#endif // __common_h__ diff --git a/tests/04_ping_pong/readme.txt b/tests/04_ping_pong/readme.txt new file mode 100644 index 0000000..6465f17 --- /dev/null +++ b/tests/04_ping_pong/readme.txt @@ -0,0 +1,7 @@ +04_ping_pong test suite + + - baremetal project, static allocation used (#define RL_USE_STATIC_API (1) in rpmsg_config.h) + + - test ping pong functionality + +- test name service anouncement functionality \ No newline at end of file diff --git a/tests/04_ping_pong_rtos/main_core0.c b/tests/04_ping_pong_rtos/main_core0.c new file mode 100644 index 0000000..c1ce841 --- /dev/null +++ b/tests/04_ping_pong_rtos/main_core0.c @@ -0,0 +1,1096 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include +#include "pingpong_common.h" +#include "unity.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (40) +//#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *volatile ctrl_ept = NULL; +rpmsg_queue_handle ctrl_q = NULL; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +rpmsg_ns_handle ns_handle = NULL; +volatile uint32_t remote_addr = 0U; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ + uint32_t *data = (uint32_t *)user_data; + + *data = new_ept; +} + +/* + * utility: initialize rpmsg and environment + * and wait for default channel + */ +int32_t ts_init_rpmsg(void) +{ +#if defined(SDK_OS_FREE_RTOS) + HeapStats_t xHeapStats; + void *t; + /* static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );*/ + size_t xHeapStructSizeTemp = ( sizeof( uint32_t* ) + sizeof( size_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); +#endif /* SDK_OS_FREE_RTOS */ + + env_init(); + //env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#if defined(SDK_OS_FREE_RTOS) + // Simulate out of heap memory cases + // Force rpmsg_lite_instance allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - xHeapStructSizeTemp - 1U); + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_master_init' with no free heap failed"); + + // Force allocation fail in first virtqueue_create call + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - 1U); + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_master_init' with no free heap failed"); + + // Force allocation fail in second virtqueue_create call + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - sizeof(struct virtqueue) - 8U - 1U); + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_master_init' with no free heap failed"); + + // Force allocation fail in env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1) + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - (2*sizeof(struct virtqueue)) - 16U - 1U); + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_master_init' with no free heap failed"); +#endif /* SDK_OS_FREE_RTOS */ + + // Correct call + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + //Register name service callback as soon as the rpmsg_lite_master_init() finishes + //(virtqueue_kick unblocks the rpmsg_lite_wait_for_link_up() on the remote side and rpmsg_ns_announce is sent consequently) +#if defined(SDK_OS_FREE_RTOS) + // Simulate out of heap memory cases + // Force rpmsg_ns_callback_data allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - xHeapStructSizeTemp - 1U); + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with no free heap failed"); + // Force rpmsg_ns_context allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_ns_callback_data) - 8U - 1U); + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with no free heap failed"); +#endif /* SDK_OS_FREE_RTOS */ + + // Correct call + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + + /* Wait until the secondary core application issues the nameservice isr and the remote endpoint address is known. */ + while (0U == remote_addr) + { + }; + + ctrl_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE(NULL != ctrl_q, "'rpmsg_queue_create' failed"); + +#if defined(SDK_OS_FREE_RTOS) + // Simulate out of heap memory cases + // Force rpmsg_lite_endpoint allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - xHeapStructSizeTemp - 1U); + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == ctrl_ept, "'rpmsg_lite_create_ept' with no free heap failed"); + + // Force llist allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_endpoint) - 8U - 1U); + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == ctrl_ept, "'rpmsg_lite_create_ept' with no free heap failed"); +#endif /* SDK_OS_FREE_RTOS */ + + // Correct call + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + // Invalid params for rpmsg_ns_bind + ns_handle = rpmsg_ns_bind(my_rpmsg, RL_NULL, (void *)&remote_addr); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with bad app_cb param failed"); + + return 0; +} + +/* + * utility: deinitialize rpmsg and enviroment + */ +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_queue_destroy(my_rpmsg, ctrl_q); + rpmsg_ns_unbind(my_rpmsg, ns_handle); + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/* + * Destroy all created endpoints on the other side + */ +int32_t ts_destroy_epts() +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + int32_t ret_value; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ept_param; + + data_destroy_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_destroy_ept_param.ept_to_destroy_addr = DESTROY_ALL_EPT; + + msg.CMD = CTR_CMD_DESTROY_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_destroy_ept_param), sizeof(CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM)); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + + TEST_ASSERT_MESSAGE(0 == ret_value, "error! failed to send CTR_CMD_DESTROY_EP command to other side"); + /* Receive response from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == ret_value, "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE(CTR_CMD_DESTROY_EP == ack_msg.CMD_ACK, + "error! expecting acknowledge of CTR_CMD_DESTROY_EP copmmand"); + TEST_ASSERT_MESSAGE(0 == ack_msg.RETURN_VALUE, "error! failed to destroy endpoints on other side"); + + return 0; +} + +/* + * Endpoint creation testing + */ +void tc_1_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + int32_t ret_value, i = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + uint32_t ept_address; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + + ret_value = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "error! init function failed"); + if (ret_value) + { + ret_value = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "error! deinit function failed"); + return; + } + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + + /* + * EP creation testing with desired address of 1 + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + data_create_ept_param.ept_to_create_addr = 1; /* Address to create endpoint */ + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on the other side"); + + /* + * Creation of the same EP should not be possible - ERROR should be returned + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 != ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + + /* + * Create endpoint with address = RL_ADDR_ANY + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + data_create_ept_param.ept_to_create_addr = RL_ADDR_ANY; /* Address to create endpoint */ + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + + /* Receive response from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on the other side"); + /* Get address of endpoint that was created with RL_ADDR_ANY parameter*/ + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, sizeof(uint32_t)); + ept_address = responder_ept_addr; + + /* + * Create endpoint with address of endpoint that was created with RL_ADDR_ANY parameter + * This should not be possible. FALSE will returned. + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + /* Address to create endpoint */ + data_create_ept_param.ept_to_create_addr = ept_address; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 != ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on the other side"); + + /* + * Create another endpoints (TC_EPT_COUNT - 3) + */ + for (i = 0; i < TC_EPT_COUNT - 3; i++) + { + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + data_create_ept_param.ept_to_create_addr++; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + } + + /* + * Testing destroy endpoints + */ + ts_destroy_epts(); +} + +/* + * TEST #2: Testing RPMSG pingpong1 + * rpmsg_rtos_recv() and rpmsg_rtos_send() functions are called on + * the other side. Both blocking and non-blocking modes of the rpmsg_rtos_recv() function are tested. + */ +void tc_2_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + struct rpmsg_lite_endpoint *sender_ept; + rpmsg_queue_handle sender_q; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value, i = 0, testing_count = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + char recv_buffer[SENDER_APP_BUF_SIZE]; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + env_memcpy((void *)data_send_param.msg, "abc", (uint32_t)4); + data_send_param.ept_to_ack_addr = ctrl_ept->addr; + data_send_param.msg_size = CMD_SEND_MSG_SIZE; + data_send_param.repeat_count = 1; + data_send_param.mode = CMD_SEND_MODE_COPY; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = RL_BLOCK; + data_recv_param.mode = CMD_RECV_MODE_COPY; + + /* Testing with blocking call and non-blocking call (timeout = 0) */ + for (testing_count = 0; testing_count < 2; testing_count++) + { + for (i = 0; i < TEST_CNT; i++) + { + /* + * Test receive function + * Sender sends a request to create endpoint on the other side + * Responder will receive the data from sender through this endpoint + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, (uint32_t)(sizeof(uint32_t))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + /* send CTR_CMD_RECV command to the other side */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + + /* Send "aaa" string to other side */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + + /* Get respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(ack_msg.RESP_DATA, "aaa", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Test send function + * Create a new endpoint on the sender side and sender will receive data through this endpoint + */ + sender_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE((NULL != sender_q ? 1 : (0 != ts_destroy_epts())), "error! failed to create queue"); + sender_ept = rpmsg_lite_create_ept(my_rpmsg, ept_address, rpmsg_queue_rx_cb, sender_q); + TEST_ASSERT_MESSAGE((NULL != sender_ept ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint"); + + data_send_param.dest_addr = sender_ept->addr; + + msg.CMD = CTR_CMD_SEND; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + env_memcpy((void *)msg.DATA, (void *)&data_send_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_SEND command to other side"); + + /* Wait untill the response msg is received, use rpmsg_queue_recv() with RL_DONT_BLOCK parameter then. */ + while(1 > rpmsg_queue_get_current_size(sender_q)) {}; + ret_value = rpmsg_queue_recv(my_rpmsg, sender_q, &src, (char *)&recv_buffer, SENDER_APP_BUF_SIZE, + &num_of_received_bytes, RL_DONT_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive data from other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(recv_buffer, "abc", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + ret_value = rpmsg_queue_get_current_size(sender_q); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! expected number of messages in the sender queue is not equal to 0"); + + /* + * Destroy created endpoint on the sender side + */ + rpmsg_lite_destroy_ept(my_rpmsg, sender_ept); + rpmsg_queue_destroy(my_rpmsg, sender_q); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); + } + + /* + * Attempt to call receive function on the other side with the invalid EP pointer (not yet created EP) + */ + data_recv_param.responder_ept_addr = 123456; /* invalid non-existing addr */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((RL_ERR_PARAM == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + + /* + * Test receive function on the other side with non-blocking call (timeout = 0) + */ + data_recv_param.timeout_ms = RL_DONT_BLOCK; + } +} + +/* + * TEST #3: Testing RPMSG pingpong2 + * rpmsg_rtos_recv_nocopy() and rpmsg_rtos_send() functions are called on + * the other side. Both blocking and non-blocking modes of the rpmsg_rtos_recv_nocopy() function are tested. + */ +void tc_3_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + struct rpmsg_lite_endpoint *sender_ept; + rpmsg_queue_handle sender_q; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value, i = 0, testing_count = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + char recv_buffer[SENDER_APP_BUF_SIZE]; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + env_memcpy((void *)data_send_param.msg, "abc", (uint32_t)4); + data_send_param.ept_to_ack_addr = ctrl_ept->addr; + data_send_param.msg_size = CMD_SEND_MSG_SIZE; + data_send_param.repeat_count = 1; + data_send_param.mode = CMD_SEND_MODE_COPY; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = RL_BLOCK; + data_recv_param.mode = CMD_RECV_MODE_NOCOPY; + + /* Testing with blocking call and non-blocking call (timeout = 0) */ + for (testing_count = 0; testing_count < 2; testing_count++) + { + for (i = 0; i < TEST_CNT; i++) + { + /* + * Test receive function + * Sender sends a request to the responder to create endpoint on other side + * Responder will receive the data from sender through this endpoint + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to responder"); + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from responder"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, (uint32_t)(sizeof(uint32_t))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + + /* Send "aaa" string to other side */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(ack_msg.RESP_DATA, "aaa", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Test send function + * Create a new endpoint on the sender side and sender will receive data through this endpoint + */ + sender_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE((NULL != sender_q ? 1 : (0 != ts_destroy_epts())), "error! failed to create queue"); + sender_ept = rpmsg_lite_create_ept(my_rpmsg, ept_address, rpmsg_queue_rx_cb, sender_q); + TEST_ASSERT_MESSAGE((NULL != sender_ept ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint"); + + data_send_param.dest_addr = sender_ept->addr; + + msg.CMD = CTR_CMD_SEND; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + env_memcpy((void *)msg.DATA, (void *)&data_send_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_SEND command to other side"); + + ret_value = rpmsg_queue_recv(my_rpmsg, sender_q, &src, (char *)recv_buffer, SENDER_APP_BUF_SIZE, + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive data from other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(recv_buffer, "abc", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Destroy created endpoint on the sender side + */ + rpmsg_lite_destroy_ept(my_rpmsg, sender_ept); + rpmsg_queue_destroy(my_rpmsg, sender_q); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); + } + + /* + * Attempt to call receive function on the other side with the invalid EP pointer (not yet created EP) + */ + data_recv_param.responder_ept_addr = 123456; /* non-existing ept addr */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((RL_ERR_PARAM == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + + /* + * Test receive function on the other side with non-blocking call (timeout = 0) + */ + data_recv_param.timeout_ms = RL_DONT_BLOCK; + } +} + +/* + * TEST #4: Testing timeout for receive function with copy mode + */ +void tc_4_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = CMD_RECV_TIMEOUT_MS; + data_recv_param.mode = CMD_RECV_MODE_COPY; + + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, + (uint32_t)(sizeof(struct rpmsg_lite_endpoint *))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + /* Wait for a new message until the timeout expires, no message is sent. */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 != ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_INT_WITHIN_MESSAGE(CMD_RECV_TIMEOUT_MS * 0.2, CMD_RECV_TIMEOUT_MS, ack_msg.TIMEOUT_MSEC, + "error! incorrect timeout received"); + + /* Wait for a new message until the timeout expires, a message is sent at half of the timeout. */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + env_sleep_msec(CMD_RECV_TIMEOUT_MS / 2); + /* Send "aaa" string to other side */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_INT_WITHIN_MESSAGE((CMD_RECV_TIMEOUT_MS / 2) * 0.2, CMD_RECV_TIMEOUT_MS / 2, ack_msg.TIMEOUT_MSEC, + "error! incorrect timeout received"); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); +} + +/* + * Testing timeout for receive function with no-copy mode + */ +void tc_5_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = CMD_RECV_TIMEOUT_MS; + data_recv_param.mode = CMD_RECV_MODE_NOCOPY; + + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, + (uint32_t)(sizeof(struct rpmsg_lite_endpoint *))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + /* Wait for a new message until the timeout expires, no message is sent. */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 != ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_INT_WITHIN_MESSAGE(CMD_RECV_TIMEOUT_MS * 0.2, CMD_RECV_TIMEOUT_MS, ack_msg.TIMEOUT_MSEC, + "error! incorrect timeout received"); + + /* Wait for a new message until the timeout expires, a message is sent at half of the timeout. */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + env_sleep_msec(CMD_RECV_TIMEOUT_MS / 2); + /* Send "aaa" string to other side */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv on the other side"); + TEST_ASSERT_INT_WITHIN_MESSAGE((CMD_RECV_TIMEOUT_MS / 2) * 0.2, CMD_RECV_TIMEOUT_MS / 2, ack_msg.TIMEOUT_MSEC, + "error! incorrect timeout received"); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); +} + +/* + * TEST #6: Testing RPMSG pingpong3 + * rpmsg_rtos_recv_nocopy() and rpmsg_rtos_send_nocopy() functions are called on + * the other side. Both blocking and non-blocking modes of the rpmsg_rtos_recv_nocopy() function are tested. + */ +void tc_6_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + struct rpmsg_lite_endpoint *sender_ept; + rpmsg_queue_handle sender_q; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value, i = 0, testing_count = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + char recv_buffer[SENDER_APP_BUF_SIZE]; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + env_memcpy((void *)data_send_param.msg, "abc", (uint32_t)4); + data_send_param.ept_to_ack_addr = ctrl_ept->addr; + data_send_param.msg_size = CMD_SEND_MSG_SIZE; + data_send_param.repeat_count = 1; + data_send_param.mode = CMD_SEND_MODE_NOCOPY; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = RL_BLOCK; + data_recv_param.mode = CMD_RECV_MODE_NOCOPY; + + /* Testing with blocking call and non-blocking call (timeout = 0) */ + for (testing_count = 0; testing_count < 2; testing_count++) + { + for (i = 0; i < TEST_CNT; i++) + { + /* + * Test receive function + * Sender sends a request to the responder to create endpoint on other side + * Responder will receive the data from sender through this endpoint + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to responder"); + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from responder"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, + (uint32_t)(sizeof(struct rpmsg_lite_endpoint *))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + + /* Send "aaa" string to other side */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(ack_msg.RESP_DATA, "aaa", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Test send function + * Create a new endpoint on the sender side and sender will receive data through this endpoint + */ + ept_address = INIT_EPT_ADDR + 1; + + sender_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE((NULL != sender_q ? 1 : (0 != ts_destroy_epts())), "error! failed to create queue"); + sender_ept = rpmsg_lite_create_ept(my_rpmsg, ept_address, rpmsg_queue_rx_cb, sender_q); + TEST_ASSERT_MESSAGE((NULL != sender_ept ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint"); + + data_send_param.dest_addr = sender_ept->addr; + + msg.CMD = CTR_CMD_SEND; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + env_memcpy((void *)msg.DATA, (void *)&data_send_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_SEND command to other side"); + + ret_value = rpmsg_queue_recv(my_rpmsg, sender_q, &src, (char *)recv_buffer, SENDER_APP_BUF_SIZE, + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive data from other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(recv_buffer, "abc", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Destroy created endpoint on the sender side + */ + rpmsg_lite_destroy_ept(my_rpmsg, sender_ept); + rpmsg_queue_destroy(my_rpmsg, sender_q); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); + } + + /* + * Attempt to call receive function on the other side with the invalid EP pointer (not yet created EP) + */ + data_recv_param.responder_ept_addr = 123456; /* non-existing ept addr */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((RL_ERR_PARAM == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + + /* + * Test receive function on the other side with non-blocking call (timeout = 0) + */ + data_recv_param.timeout_ms = RL_DONT_BLOCK; + } +} + +void tc_7_finish_task(void) +{ + CONTROL_MESSAGE msg = {0}; + msg.CMD = CTR_CMD_FINISH; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + int32_t ret_value; + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_FINISH command to other side"); + +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("04_ping_pong_rtos"); + __coveragescanner_install("04_ping_pong_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); + RUN_EXAMPLE(tc_3_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 2)); + RUN_EXAMPLE(tc_4_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 3)); + RUN_EXAMPLE(tc_5_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 4)); + RUN_EXAMPLE(tc_6_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 5)); + RUN_EXAMPLE(tc_7_finish_task, MAKE_UNITY_NUM(k_unity_rpmsg, 6)); +} diff --git a/tests/04_ping_pong_rtos/main_core1.c b/tests/04_ping_pong_rtos/main_core1.c new file mode 100644 index 0000000..d95e01f --- /dev/null +++ b/tests/04_ping_pong_rtos/main_core1.c @@ -0,0 +1,522 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include "pingpong_common.h" +#include "unity.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#elif defined(FSL_RTOS_XOS) +#include +#elif defined(FSL_RTOS_THREADX) +#include "tx_api.h" +#endif + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *volatile ctrl_ept = NULL; +rpmsg_queue_handle ctrl_q = NULL; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; + +struct rpmsg_lite_endpoint *endpoints[TC_EPT_COUNT] = {NULL}; +rpmsg_queue_handle qs[TC_EPT_COUNT] = {NULL}; +int32_t ept_num = 0; +rpmsg_ns_handle ns_handle = NULL; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + int32_t result = 0; +#if defined(SDK_OS_FREE_RTOS) + HeapStats_t xHeapStats; + void *t; + /* static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );*/ + size_t xHeapStructSizeTemp = ( sizeof( uint32_t* ) + sizeof( size_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); +#endif /* SDK_OS_FREE_RTOS */ + + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#if defined(SDK_OS_FREE_RTOS) + // Simulate out of heap memory cases + // Force rpmsg_lite_instance allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - xHeapStructSizeTemp - 1U); + my_rpmsg = rpmsg_lite_remote_init((void *)rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_remote_init' with no free heap failed"); + + // Force allocation fail in first virtqueue_create call + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - 1U); + my_rpmsg = rpmsg_lite_remote_init((void *)rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_remote_init' with no free heap failed"); + + // Force allocation fail in second virtqueue_create call + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - sizeof(struct virtqueue) - 8U - 1U); + my_rpmsg = rpmsg_lite_remote_init((void *)rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_remote_init' with no free heap failed"); + + // Force allocation fail in env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1) + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - (2*sizeof(struct virtqueue)) - 16U - 1U); + my_rpmsg = rpmsg_lite_remote_init((void *)rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_remote_init' with no free heap failed"); +#endif /* SDK_OS_FREE_RTOS */ + + // Correct call + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else +#if defined(SDK_OS_FREE_RTOS) + // Simulate out of heap memory cases + // Force rpmsg_lite_instance allocation fail + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - xHeapStructSizeTemp - 1U); + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_remote_init' with no free heap failed"); + + // Force allocation fail in first virtqueue_create call + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - 1U); + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_remote_init' with no free heap failed"); + + // Force allocation fail in second virtqueue_create call + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - sizeof(struct virtqueue) - 8U - 1U); + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_remote_init' with no free heap failed"); + + // Force allocation fail in env_create_mutex((LOCK *)&rpmsg_lite_dev->lock, 1) + vPortGetHeapStats(&xHeapStats); + t = env_allocate_memory(xHeapStats.xAvailableHeapSpaceInBytes - (2*xHeapStructSizeTemp) - sizeof(struct rpmsg_lite_instance) - 8U - (2*sizeof(struct virtqueue)) - 16U - 1U); + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); + env_free_memory(t); + TEST_ASSERT_MESSAGE(RL_NULL == my_rpmsg, "'rpmsg_lite_remote_init' with no free heap failed"); +#endif /* SDK_OS_FREE_RTOS */ + + // Correct call + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + ctrl_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE(NULL != ctrl_q, "'rpmsg_queue_create' failed"); + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + // invalid params for rpmsg_ns_bind + ns_handle = rpmsg_ns_bind(my_rpmsg, RL_NULL, ((void *)0)); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with bad app_cb param failed"); + + /* wait for a while to allow the primary side to bind_ns and register the NS callback */ + env_sleep_msec(200); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0)); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + + // invalid params for rpmsg_ns_announce + result = rpmsg_ns_announce(my_rpmsg, ctrl_ept, RL_NULL, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_ns_announce' with bad ept_name param failed"); + result = rpmsg_ns_announce(my_rpmsg, RL_NULL, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_ns_announce' with bad new_ept param failed"); + + // send invalid NS message to the RL_NS_EPT_ADDR - wrong paylod_len identified in the ns cb and the message is dropped (condition coverage increase) + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + rpmsg_lite_send(my_rpmsg, ctrl_ept, RL_NS_EPT_ADDR, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + + /* wait for a while to allow the primary side to bind_ns and register the NS callback */ + env_sleep_msec(200); + // send correct NS message + result = rpmsg_ns_announce(my_rpmsg, ctrl_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "'rpmsg_ns_announce' failed"); + return 0; +} + +// utility: deinitialize rpmsg and enviroment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_queue_destroy(my_rpmsg, ctrl_q); + rpmsg_ns_unbind(my_rpmsg, ns_handle); + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/****************************************************************************** + * Responder task + *****************************************************************************/ +void responder_task(void) +{ + int32_t ret_value = 0; + void *data_addr = NULL; + uint32_t num_of_received_control_bytes; + uint32_t i = 0; + uint32_t src = 0; + struct rpmsg_lite_endpoint *my_ept; + rpmsg_queue_handle q; + CONTROL_MESSAGE msg; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + unsigned char *recv_buffer[BUFFER_MAX_LENGTH]; + void *nocopy_buffer_ptr = NULL; // pointer to receive data in no-copy mode + uint32_t buf_size = 0; /* use to store size of buffer for + rpmsg_rtos_alloc_tx_buffer() */ + + ret_value = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "Testing function init rpmsg"); + if (ret_value) + goto end; + + while (1) + { + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&msg, sizeof(CONTROL_MESSAGE), + &num_of_received_control_bytes, RL_BLOCK); + + if (0 != ret_value) + { + /* PRINTF("Responder task receive error: %i\n", ret_value); */ + } + else + { + /* PRINTF("Responder task received a msg\n\r"); */ + /* PRINTF("Message: Size=0x%x, CMD = 0x%x, DATA = 0x%x 0x%x 0x%x 0x%x\n\r", num_of_received_control_bytes, + msg.CMD, msg.DATA[0], msg.DATA[1], msg.DATA[2], msg.DATA[3]); */ + + switch (msg.CMD) + { + case CTR_CMD_CREATE_EP: + ret_value = -1; + env_memcpy((void *)(&data_create_ept_param), (void *)msg.DATA, + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + + q = rpmsg_queue_create(my_rpmsg); + my_ept = + rpmsg_lite_create_ept(my_rpmsg, data_create_ept_param.ept_to_create_addr, rpmsg_queue_rx_cb, q); + + if ((NULL == my_ept) || (NULL == q)) + { + if (NULL != q) + { + rpmsg_queue_destroy(my_rpmsg, q); + } + + if (NULL != my_ept) + { + rpmsg_lite_destroy_ept(my_rpmsg, my_ept); + } + + ret_value = 1; /* Fail to create enpoint */ + } + else + { + qs[ept_num] = q; + endpoints[ept_num++] = my_ept; + ret_value = 0; + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_CREATE_EP; + ack_msg.RETURN_VALUE = ret_value; + env_memcpy((void *)ack_msg.RESP_DATA, (void *)&(my_ept->addr), sizeof(uint32_t)); + /* Send ack_msg to sender */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_create_ept_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + break; + + case CTR_CMD_DESTROY_EP: + ret_value = -1; + env_memcpy((void *)(&data_destroy_ept_param), (void *)msg.DATA, + sizeof(CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM)); + + if (data_destroy_ept_param.ept_to_destroy_addr == DESTROY_ALL_EPT) + { + for (i = 0; i < ept_num; i++) + { + rpmsg_lite_destroy_ept(my_rpmsg, endpoints[i]); + rpmsg_queue_destroy(my_rpmsg, qs[i]); + } + ept_num = 0; + /* We can't check return value of destroy function due to this function return void */ + ret_value = 0; + } + else + { + rpmsg_lite_destroy_ept(my_rpmsg, endpoints[data_destroy_ept_param.ept_to_destroy_addr]); + rpmsg_queue_destroy(my_rpmsg, qs[data_destroy_ept_param.ept_to_destroy_addr]); + /* We can't check return value of destroy function due to this function return void */ + ret_value = 0; + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_DESTROY_EP; + ack_msg.RETURN_VALUE = ret_value; + /* Send ack_msg to tea_control_endpoint */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_destroy_ept_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + break; + case CTR_CMD_RECV: + ret_value = -1; + env_memcpy((void *)&data_recv_param, (void *)msg.DATA, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + + my_ept = NULL; + q = NULL; + for (i = 0; i < ept_num; i++) + { + if (endpoints[i]->addr == data_recv_param.responder_ept_addr) + { + my_ept = endpoints[i]; + q = qs[i]; + break; + } + } + + if (CMD_RECV_MODE_COPY == data_recv_param.mode) + { + if (RL_BLOCK == data_recv_param.timeout_ms) + { + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, RL_BLOCK); + } + else if (RL_DONT_BLOCK == data_recv_param.timeout_ms) + { + /* receive function with non-blocking call */ + do + { + ret_value = rpmsg_queue_recv( + my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, RL_DONT_BLOCK); + if (ret_value == RL_ERR_PARAM) + break; + } while (0 != ret_value); + } + else + { +#if defined(SDK_OS_FREE_RTOS) + TickType_t tick_count = xTaskGetTickCount(); +#elif defined(FSL_RTOS_XOS) + uint64_t tick_count = xos_get_system_cycles(); +#elif defined(FSL_RTOS_THREADX) + uint64_t tick_count = tx_time_get(); +#endif + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, data_recv_param.timeout_ms); +#if defined(SDK_OS_FREE_RTOS) + tick_count = xTaskGetTickCount() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / configTICK_RATE_HZ); +#elif defined(FSL_RTOS_XOS) + tick_count = xos_get_system_cycles() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = xos_cycles_to_msecs(tick_count); +#elif defined(FSL_RTOS_THREADX) + tick_count = tx_time_get() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = (1000 * tick_count) / TX_TIMER_TICKS_PER_SECOND; +#endif + } + } + else if (CMD_RECV_MODE_NOCOPY == data_recv_param.mode) + { + if (RL_BLOCK == data_recv_param.timeout_ms) + { + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, RL_BLOCK); + } + else if (RL_DONT_BLOCK == data_recv_param.timeout_ms) + { + /* receive function with non-blocking call */ + do + { + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, RL_DONT_BLOCK); + + if (ret_value == RL_ERR_PARAM) + break; + } while (0 != ret_value); + } + else + { +#if defined(SDK_OS_FREE_RTOS) + TickType_t tick_count = xTaskGetTickCount(); +#elif defined(FSL_RTOS_XOS) + uint64_t tick_count = xos_get_system_cycles(); +#elif defined(FSL_RTOS_THREADX) + uint64_t tick_count = tx_time_get(); +#endif + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, data_recv_param.timeout_ms); +#if defined(SDK_OS_FREE_RTOS) + tick_count = xTaskGetTickCount() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / configTICK_RATE_HZ); +#elif defined(FSL_RTOS_XOS) + tick_count = xos_get_system_cycles() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = xos_cycles_to_msecs(tick_count); +#elif defined(FSL_RTOS_THREADX) + tick_count = tx_time_get() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = (1000 * tick_count) / TX_TIMER_TICKS_PER_SECOND; +#endif + } + + /* Free buffer when use rpmsg_rtos_recv_nocopy function */ + if (0 == ret_value) + { + env_memcpy((void *)recv_buffer, (void *)nocopy_buffer_ptr, num_of_received_control_bytes); + ret_value = rpmsg_queue_nocopy_free(my_rpmsg, nocopy_buffer_ptr); + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_RECV; + ack_msg.RETURN_VALUE = ret_value; + + env_memcpy((void *)ack_msg.RESP_DATA, (void *)recv_buffer, num_of_received_control_bytes); + env_memset(recv_buffer, 0, BUFFER_MAX_LENGTH); + /* Send ack_msg to sender */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + + break; + case CTR_CMD_SEND: + ret_value = -1; + env_memcpy((void *)&data_send_param, (void *)msg.DATA, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + + if (CMD_SEND_MODE_COPY == data_send_param.mode) + { + for (i = 0; i < data_send_param.repeat_count; i++) + { + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param.dest_addr, + (char *)data_send_param.msg, data_send_param.msg_size, RL_BLOCK); + } + } + else if (CMD_SEND_MODE_NOCOPY == data_send_param.mode) + { + for (i = 0; i < data_send_param.repeat_count; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + if (buf_size == 0 || data_addr == NULL) + { + ret_value = -1; /* Failed to alloc tx buffer */ + break; + } + env_memcpy((void *)data_addr, (void *)data_send_param.msg, data_send_param.msg_size); + ret_value = rpmsg_lite_send_nocopy(my_rpmsg, ctrl_ept, data_send_param.dest_addr, + (char *)data_addr, data_send_param.msg_size); + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_SEND; + ack_msg.RETURN_VALUE = ret_value; + /* Send ack_msg to tea_control_endpoint */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + + break; + case CTR_CMD_FINISH: + goto end; + break; + } + } + } + +end: + ret_value = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "negative number"); +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("04_ping_pong_rtos_sec_core"); + __coveragescanner_install("04_ping_pong_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(responder_task, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/04_ping_pong_rtos/main_static_alloc_core0.c b/tests/04_ping_pong_rtos/main_static_alloc_core0.c new file mode 100644 index 0000000..974c5fa --- /dev/null +++ b/tests/04_ping_pong_rtos/main_static_alloc_core0.c @@ -0,0 +1,1037 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include +#include "pingpong_common.h" +#include "unity.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (40) +//#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *volatile ctrl_ept = NULL; +struct rpmsg_lite_ept_static_context ctrl_ept_ctxt = {0}; + +rpmsg_queue_handle ctrl_q = NULL; +rpmsg_static_queue_ctxt ctrl_queue_ctxt = {0}; +uint8_t ctrl_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt = {0}; +rpmsg_ns_handle ns_handle = NULL; +rpmsg_ns_static_context my_ns_ctxt = {0}; +volatile uint32_t remote_addr = 0U; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ + uint32_t *data = (uint32_t *)user_data; + + *data = new_ept; +} + +/* + * utility: initialize rpmsg and environment + * and wait for default channel + */ +int32_t ts_init_rpmsg(void) +{ + env_init(); + //env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr, &my_ns_ctxt); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + + /* Wait until the secondary core application issues the nameservice isr and the remote endpoint address is known. */ + while (0U == remote_addr) + { + }; + + ctrl_q = rpmsg_queue_create(my_rpmsg, &ctrl_queue_storage[0], &ctrl_queue_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_q, "'rpmsg_queue_create' failed"); + + + // Correct call + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q, &ctrl_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + // Invalid params for rpmsg_ns_bind + ns_handle = rpmsg_ns_bind(my_rpmsg, RL_NULL, (void *)&remote_addr, &my_ns_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with bad app_cb param failed"); + + return 0; +} + +/* + * utility: deinitialize rpmsg and enviroment + */ +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_queue_destroy(my_rpmsg, ctrl_q); + rpmsg_ns_unbind(my_rpmsg, ns_handle); + ns_handle = NULL; + env_memset(&my_ns_ctxt, 0, sizeof(rpmsg_ns_static_context)); + rpmsg_lite_deinit(my_rpmsg); + my_rpmsg = NULL; + env_memset(&rpmsg_ctxt, 0, sizeof(struct rpmsg_lite_instance)); + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/* + * Destroy all created endpoints on the other side + */ +int32_t ts_destroy_epts() +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + int32_t ret_value; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ept_param; + + data_destroy_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_destroy_ept_param.ept_to_destroy_addr = DESTROY_ALL_EPT; + + msg.CMD = CTR_CMD_DESTROY_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_destroy_ept_param), sizeof(CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM)); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + + TEST_ASSERT_MESSAGE(0 == ret_value, "error! failed to send CTR_CMD_DESTROY_EP command to other side"); + /* Receive response from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == ret_value, "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE(CTR_CMD_DESTROY_EP == ack_msg.CMD_ACK, + "error! expecting acknowledge of CTR_CMD_DESTROY_EP copmmand"); + TEST_ASSERT_MESSAGE(0 == ack_msg.RETURN_VALUE, "error! failed to destroy endpoints on other side"); + + return 0; +} + +/* + * Endpoint creation testing + */ +void tc_1_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + int32_t ret_value, i = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + uint32_t ept_address; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + + ret_value = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "error! init function failed"); + if (ret_value) + { + ret_value = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "error! deinit function failed"); + return; + } + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + + /* + * EP creation testing with desired address of 1 + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + data_create_ept_param.ept_to_create_addr = 1; /* Address to create endpoint */ + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on the other side"); + + /* + * Creation of the same EP should not be possible - ERROR should be returned + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 != ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + + /* + * Create endpoint with address = RL_ADDR_ANY + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + data_create_ept_param.ept_to_create_addr = RL_ADDR_ANY; /* Address to create endpoint */ + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + + /* Receive response from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on the other side"); + /* Get address of endpoint that was created with RL_ADDR_ANY parameter*/ + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, sizeof(uint32_t)); + ept_address = responder_ept_addr; + + /* + * Create endpoint with address of endpoint that was created with RL_ADDR_ANY parameter + * This should not be possible. FALSE will returned. + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + /* Address to create endpoint */ + data_create_ept_param.ept_to_create_addr = ept_address; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 != ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on the other side"); + + /* + * Create another endpoints (TC_EPT_COUNT - 3) + */ + for (i = 0; i < TC_EPT_COUNT - 3; i++) + { + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + data_create_ept_param.ept_to_create_addr++; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + } + + /* + * Testing destroy endpoints + */ + ts_destroy_epts(); +} + +/* + * TEST #2: Testing RPMSG pingpong1 + * rpmsg_rtos_recv() and rpmsg_rtos_send() functions are called on + * the other side. Both blocking and non-blocking modes of the rpmsg_rtos_recv() function are tested. + */ +void tc_2_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + struct rpmsg_lite_endpoint *sender_ept = NULL; + struct rpmsg_lite_ept_static_context sender_ept_ctxt = {0}; + rpmsg_queue_handle sender_q = NULL; + rpmsg_static_queue_ctxt sender_queue_ctxt = {0}; + uint8_t sender_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value, i = 0, testing_count = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + char recv_buffer[SENDER_APP_BUF_SIZE]; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + env_memcpy((void *)data_send_param.msg, "abc", (uint32_t)4); + data_send_param.ept_to_ack_addr = ctrl_ept->addr; + data_send_param.msg_size = CMD_SEND_MSG_SIZE; + data_send_param.repeat_count = 1; + data_send_param.mode = CMD_SEND_MODE_COPY; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = RL_BLOCK; + data_recv_param.mode = CMD_RECV_MODE_COPY; + + /* Testing with blocking call and non-blocking call (timeout = 0) */ + for (testing_count = 0; testing_count < 2; testing_count++) + { + for (i = 0; i < TEST_CNT; i++) + { + /* + * Test receive function + * Sender sends a request to create endpoint on the other side + * Responder will receive the data from sender through this endpoint + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, (uint32_t)(sizeof(uint32_t))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + /* send CTR_CMD_RECV command to the other side */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + + /* Send "aaa" string to other side */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + + /* Get respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(ack_msg.RESP_DATA, "aaa", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Test send function + * Create a new endpoint on the sender side and sender will receive data through this endpoint + */ + sender_q = rpmsg_queue_create(my_rpmsg, &sender_queue_storage[0], &sender_queue_ctxt); + TEST_ASSERT_MESSAGE((NULL != sender_q ? 1 : (0 != ts_destroy_epts())), "error! failed to create queue"); + sender_ept = rpmsg_lite_create_ept(my_rpmsg, ept_address, rpmsg_queue_rx_cb, sender_q, &sender_ept_ctxt); + TEST_ASSERT_MESSAGE((NULL != sender_ept ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint"); + + data_send_param.dest_addr = sender_ept->addr; + + msg.CMD = CTR_CMD_SEND; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + env_memcpy((void *)msg.DATA, (void *)&data_send_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_SEND command to other side"); + + /* Wait untill the response msg is received, use rpmsg_queue_recv() with RL_DONT_BLOCK parameter then. */ + while(1 > rpmsg_queue_get_current_size(sender_q)) {}; + ret_value = rpmsg_queue_recv(my_rpmsg, sender_q, &src, (char *)&recv_buffer, SENDER_APP_BUF_SIZE, + &num_of_received_bytes, RL_DONT_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive data from other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(recv_buffer, "abc", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + ret_value = rpmsg_queue_get_current_size(sender_q); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! expected number of messages in the sender queue is not equal to 0"); + + /* + * Destroy created endpoint on the sender side + */ + rpmsg_lite_destroy_ept(my_rpmsg, sender_ept); + rpmsg_queue_destroy(my_rpmsg, sender_q); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); + } + + /* + * Attempt to call receive function on the other side with the invalid EP pointer (not yet created EP) + */ + data_recv_param.responder_ept_addr = 123456; /* invalid non-existing addr */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((RL_ERR_PARAM == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + + /* + * Test receive function on the other side with non-blocking call (timeout = 0) + */ + data_recv_param.timeout_ms = RL_DONT_BLOCK; + } +} + +/* + * TEST #3: Testing RPMSG pingpong2 + * rpmsg_rtos_recv_nocopy() and rpmsg_rtos_send() functions are called on + * the other side. Both blocking and non-blocking modes of the rpmsg_rtos_recv_nocopy() function are tested. + */ +void tc_3_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + struct rpmsg_lite_endpoint *sender_ept = NULL; + struct rpmsg_lite_ept_static_context sender_ept_ctxt = {0}; + rpmsg_queue_handle sender_q = NULL; + rpmsg_static_queue_ctxt sender_queue_ctxt = {0}; + uint8_t sender_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value, i = 0, testing_count = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + char recv_buffer[SENDER_APP_BUF_SIZE]; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + env_memcpy((void *)data_send_param.msg, "abc", (uint32_t)4); + data_send_param.ept_to_ack_addr = ctrl_ept->addr; + data_send_param.msg_size = CMD_SEND_MSG_SIZE; + data_send_param.repeat_count = 1; + data_send_param.mode = CMD_SEND_MODE_COPY; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = RL_BLOCK; + data_recv_param.mode = CMD_RECV_MODE_NOCOPY; + + /* Testing with blocking call and non-blocking call (timeout = 0) */ + for (testing_count = 0; testing_count < 2; testing_count++) + { + for (i = 0; i < TEST_CNT; i++) + { + /* + * Test receive function + * Sender sends a request to the responder to create endpoint on other side + * Responder will receive the data from sender through this endpoint + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to responder"); + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from responder"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, (uint32_t)(sizeof(uint32_t))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + + /* Send "aaa" string to other side */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(ack_msg.RESP_DATA, "aaa", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Test send function + * Create a new endpoint on the sender side and sender will receive data through this endpoint + */ + sender_q = rpmsg_queue_create(my_rpmsg, &sender_queue_storage[0], &sender_queue_ctxt); + TEST_ASSERT_MESSAGE((NULL != sender_q ? 1 : (0 != ts_destroy_epts())), "error! failed to create queue"); + sender_ept = rpmsg_lite_create_ept(my_rpmsg, ept_address, rpmsg_queue_rx_cb, sender_q, &sender_ept_ctxt); + TEST_ASSERT_MESSAGE((NULL != sender_ept ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint"); + + data_send_param.dest_addr = sender_ept->addr; + + msg.CMD = CTR_CMD_SEND; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + env_memcpy((void *)msg.DATA, (void *)&data_send_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_SEND command to other side"); + + ret_value = rpmsg_queue_recv(my_rpmsg, sender_q, &src, (char *)recv_buffer, SENDER_APP_BUF_SIZE, + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive data from other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(recv_buffer, "abc", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Destroy created endpoint on the sender side + */ + rpmsg_lite_destroy_ept(my_rpmsg, sender_ept); + rpmsg_queue_destroy(my_rpmsg, sender_q); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); + } + + /* + * Attempt to call receive function on the other side with the invalid EP pointer (not yet created EP) + */ + data_recv_param.responder_ept_addr = 123456; /* non-existing ept addr */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((RL_ERR_PARAM == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + + /* + * Test receive function on the other side with non-blocking call (timeout = 0) + */ + data_recv_param.timeout_ms = RL_DONT_BLOCK; + } +} + +/* + * TEST #4: Testing timeout for receive function with copy mode + */ +void tc_4_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = CMD_RECV_TIMEOUT_MS; + data_recv_param.mode = CMD_RECV_MODE_COPY; + + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, + (uint32_t)(sizeof(struct rpmsg_lite_endpoint *))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + /* Wait for a new message until the timeout expires, no message is sent. */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 != ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_INT_WITHIN_MESSAGE(CMD_RECV_TIMEOUT_MS * 0.2, CMD_RECV_TIMEOUT_MS, ack_msg.TIMEOUT_MSEC, + "error! incorrect timeout received"); + + /* Wait for a new message until the timeout expires, a message is sent at half of the timeout. */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + env_sleep_msec(CMD_RECV_TIMEOUT_MS / 2); + /* Send "aaa" string to other side */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_INT_WITHIN_MESSAGE((CMD_RECV_TIMEOUT_MS / 2) * 0.2, CMD_RECV_TIMEOUT_MS / 2, ack_msg.TIMEOUT_MSEC, + "error! incorrect timeout received"); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); +} + +/* + * Testing timeout for receive function with no-copy mode + */ +void tc_5_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = CMD_RECV_TIMEOUT_MS; + data_recv_param.mode = CMD_RECV_MODE_NOCOPY; + + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, + (uint32_t)(sizeof(struct rpmsg_lite_endpoint *))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + /* Wait for a new message until the timeout expires, no message is sent. */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 != ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_INT_WITHIN_MESSAGE(CMD_RECV_TIMEOUT_MS * 0.2, CMD_RECV_TIMEOUT_MS, ack_msg.TIMEOUT_MSEC, + "error! incorrect timeout received"); + + /* Wait for a new message until the timeout expires, a message is sent at half of the timeout. */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + env_sleep_msec(CMD_RECV_TIMEOUT_MS / 2); + /* Send "aaa" string to other side */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv on the other side"); + TEST_ASSERT_INT_WITHIN_MESSAGE((CMD_RECV_TIMEOUT_MS / 2) * 0.2, CMD_RECV_TIMEOUT_MS / 2, ack_msg.TIMEOUT_MSEC, + "error! incorrect timeout received"); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); +} + +/* + * TEST #6: Testing RPMSG pingpong3 + * rpmsg_rtos_recv_nocopy() and rpmsg_rtos_send_nocopy() functions are called on + * the other side. Both blocking and non-blocking modes of the rpmsg_rtos_recv_nocopy() function are tested. + */ +void tc_6_main_task(void) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + uint32_t responder_ept_addr; + struct rpmsg_lite_endpoint *sender_ept = NULL; + struct rpmsg_lite_ept_static_context sender_ept_ctxt = {0}; + rpmsg_queue_handle sender_q = NULL; + rpmsg_static_queue_ctxt sender_queue_ctxt = {0}; + uint8_t sender_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; + uint32_t ept_address = INIT_EPT_ADDR; + int32_t ret_value, i = 0, testing_count = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + char recv_buffer[SENDER_APP_BUF_SIZE]; + + data_create_ept_param.ept_to_ack_addr = ctrl_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + env_memcpy((void *)data_send_param.msg, "abc", (uint32_t)4); + data_send_param.ept_to_ack_addr = ctrl_ept->addr; + data_send_param.msg_size = CMD_SEND_MSG_SIZE; + data_send_param.repeat_count = 1; + data_send_param.mode = CMD_SEND_MODE_NOCOPY; + + data_recv_param.ept_to_ack_addr = ctrl_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = RL_BLOCK; + data_recv_param.mode = CMD_RECV_MODE_NOCOPY; + + /* Testing with blocking call and non-blocking call (timeout = 0) */ + for (testing_count = 0; testing_count < 2; testing_count++) + { + for (i = 0; i < TEST_CNT; i++) + { + /* + * Test receive function + * Sender sends a request to the responder to create endpoint on other side + * Responder will receive the data from sender through this endpoint + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_CREATE_EP command to responder"); + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from responder"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, + (uint32_t)(sizeof(struct rpmsg_lite_endpoint *))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + + /* Send "aaa" string to other side */ + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send 'aaa' string to other side"); + + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(ack_msg.RESP_DATA, "aaa", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Test send function + * Create a new endpoint on the sender side and sender will receive data through this endpoint + */ + ept_address = INIT_EPT_ADDR + 1; + + sender_q = rpmsg_queue_create(my_rpmsg, &sender_queue_storage[0], &sender_queue_ctxt); + TEST_ASSERT_MESSAGE((NULL != sender_q ? 1 : (0 != ts_destroy_epts())), "error! failed to create queue"); + sender_ept = rpmsg_lite_create_ept(my_rpmsg, ept_address, rpmsg_queue_rx_cb, sender_q, &sender_ept_ctxt); + TEST_ASSERT_MESSAGE((NULL != sender_ept ? 1 : (0 != ts_destroy_epts())), + "error! failed to create endpoint"); + + data_send_param.dest_addr = sender_ept->addr; + + msg.CMD = CTR_CMD_SEND; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + env_memcpy((void *)msg.DATA, (void *)&data_send_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_SEND command to other side"); + + ret_value = rpmsg_queue_recv(my_rpmsg, sender_q, &src, (char *)recv_buffer, SENDER_APP_BUF_SIZE, + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive data from other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(recv_buffer, "abc", 3) ? 1 : (0 != ts_destroy_epts())), + "error! incorrect data received"); + + /* + * Destroy created endpoint on the sender side + */ + rpmsg_lite_destroy_ept(my_rpmsg, sender_ept); + rpmsg_queue_destroy(my_rpmsg, sender_q); + + /* + * Destroy created endpoint on the other side + */ + ts_destroy_epts(); + } + + /* + * Attempt to call receive function on the other side with the invalid EP pointer (not yet created EP) + */ + data_recv_param.responder_ept_addr = 123456; /* non-existing ept addr */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : (0 != ts_destroy_epts())), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((RL_ERR_PARAM == ack_msg.RETURN_VALUE ? 1 : (0 != ts_destroy_epts())), + "error! failed when call rpmsg_rtos_recv function on the other side"); + + /* + * Test receive function on the other side with non-blocking call (timeout = 0) + */ + data_recv_param.timeout_ms = RL_DONT_BLOCK; + } +} + +void tc_7_finish_task(void) +{ + CONTROL_MESSAGE msg = {0}; + msg.CMD = CTR_CMD_FINISH; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + int32_t ret_value; + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, remote_addr, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : (0 != ts_destroy_epts())), + "error! failed to send CTR_CMD_FINISH command to other side"); + +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("04_ping_pong_rtos"); + __coveragescanner_install("04_ping_pong_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); + RUN_EXAMPLE(tc_2_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 1)); + RUN_EXAMPLE(tc_3_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 2)); + RUN_EXAMPLE(tc_4_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 3)); + RUN_EXAMPLE(tc_5_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 4)); + RUN_EXAMPLE(tc_6_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 5)); + RUN_EXAMPLE(tc_7_finish_task, MAKE_UNITY_NUM(k_unity_rpmsg, 6)); +} diff --git a/tests/04_ping_pong_rtos/main_static_alloc_core1.c b/tests/04_ping_pong_rtos/main_static_alloc_core1.c new file mode 100644 index 0000000..b974972 --- /dev/null +++ b/tests/04_ping_pong_rtos/main_static_alloc_core1.c @@ -0,0 +1,464 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include "pingpong_common.h" +#include "unity.h" +#include "rpmsg_queue.h" +#include "rpmsg_ns.h" +#include "assert.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#elif defined(FSL_RTOS_XOS) +#include +#elif defined(FSL_RTOS_THREADX) +#include "tx_api.h" +#endif + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *volatile ctrl_ept = NULL; +struct rpmsg_lite_ept_static_context ctrl_ept_ctxt = {0}; + +rpmsg_queue_handle ctrl_q = NULL; +rpmsg_static_queue_ctxt ctrl_queue_ctxt = {0}; +uint8_t ctrl_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt = {0}; + +struct rpmsg_lite_endpoint *endpoints[TC_EPT_COUNT] = {NULL}; +struct rpmsg_lite_ept_static_context endpoints_ctxt[TC_EPT_COUNT] = {0}; +rpmsg_queue_handle qs[TC_EPT_COUNT] = {NULL}; +rpmsg_static_queue_ctxt qs_ctxt[TC_EPT_COUNT] = {0}; +uint8_t qs_storage[TC_EPT_COUNT][RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; +int32_t ept_num = 0; +rpmsg_ns_handle ns_handle = NULL; +rpmsg_ns_static_context my_ns_ctxt = {0}; + +static void app_nameservice_isr_cb(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data) +{ +} + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + int32_t result = 0; + + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + // Correct call + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + // Correct call + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + ctrl_q = rpmsg_queue_create(my_rpmsg, &ctrl_queue_storage[0], &ctrl_queue_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_q, "'rpmsg_queue_create' failed"); + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q, &ctrl_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + // invalid params for rpmsg_ns_bind + ns_handle = rpmsg_ns_bind(my_rpmsg, RL_NULL, ((void *)0), &my_ns_ctxt); + TEST_ASSERT_MESSAGE(RL_NULL == ns_handle, "'rpmsg_ns_bind' with bad app_cb param failed"); + + ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, ((void *)0), &my_ns_ctxt); + TEST_ASSERT_MESSAGE(NULL != ns_handle, "'rpmsg_ns_bind' failed"); + + // invalid params for rpmsg_ns_announce + result = rpmsg_ns_announce(my_rpmsg, ctrl_ept, RL_NULL, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_ns_announce' with bad ept_name param failed"); + result = rpmsg_ns_announce(my_rpmsg, RL_NULL, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_ERR_PARAM == result, "'rpmsg_ns_announce' with bad new_ept param failed"); + + // send invalid NS message to the RL_NS_EPT_ADDR - wrong paylod_len identified in the ns cb and the message is dropped (condition coverage increase) + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + rpmsg_lite_send(my_rpmsg, ctrl_ept, RL_NS_EPT_ADDR, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + + /* wait for a while to allow the primary side to bind_ns and register the NS callback */ + env_sleep_msec(200); + // send correct NS message + result = rpmsg_ns_announce(my_rpmsg, ctrl_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, (uint32_t)RL_NS_CREATE); + TEST_ASSERT_MESSAGE(RL_SUCCESS == result, "'rpmsg_ns_announce' failed"); + return 0; +} + +// utility: deinitialize rpmsg and enviroment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_queue_destroy(my_rpmsg, ctrl_q); + rpmsg_ns_unbind(my_rpmsg, ns_handle); + ns_handle = NULL; + env_memset(&my_ns_ctxt, 0, sizeof(rpmsg_ns_static_context)); + rpmsg_lite_deinit(my_rpmsg); + my_rpmsg = NULL; + env_memset(&rpmsg_ctxt, 0, sizeof(struct rpmsg_lite_instance)); + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/****************************************************************************** + * Responder task + *****************************************************************************/ +void responder_task(void) +{ + int32_t ret_value = 0; + void *data_addr = NULL; + uint32_t num_of_received_control_bytes; + uint32_t i = 0; + uint32_t src = 0; + struct rpmsg_lite_endpoint *my_ept = NULL; + rpmsg_queue_handle q = NULL; + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + unsigned char *recv_buffer[BUFFER_MAX_LENGTH]; + void *nocopy_buffer_ptr = NULL; // pointer to receive data in no-copy mode + uint32_t buf_size = 0; /* use to store size of buffer for + rpmsg_rtos_alloc_tx_buffer() */ + + ret_value = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "Testing function init rpmsg"); + if (ret_value) + goto end; + + while (1) + { + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&msg, sizeof(CONTROL_MESSAGE), + &num_of_received_control_bytes, RL_BLOCK); + + if (0 != ret_value) + { + /* PRINTF("Responder task receive error: %i\n", ret_value); */ + } + else + { + /* PRINTF("Responder task received a msg\n\r"); */ + /* PRINTF("Message: Size=0x%x, CMD = 0x%x, DATA = 0x%x 0x%x 0x%x 0x%x\n\r", num_of_received_control_bytes, + msg.CMD, msg.DATA[0], msg.DATA[1], msg.DATA[2], msg.DATA[3]); */ + + switch (msg.CMD) + { + case CTR_CMD_CREATE_EP: + ret_value = -1; + env_memcpy((void *)(&data_create_ept_param), (void *)msg.DATA, + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + + q = rpmsg_queue_create(my_rpmsg, &qs_storage[ept_num][0], &qs_ctxt[ept_num]); + my_ept = + rpmsg_lite_create_ept(my_rpmsg, data_create_ept_param.ept_to_create_addr, rpmsg_queue_rx_cb, q, &endpoints_ctxt[ept_num]); + + if ((NULL == my_ept) || (NULL == q)) + { + if (NULL != q) + { + rpmsg_queue_destroy(my_rpmsg, q); + } + + if (NULL != my_ept) + { + rpmsg_lite_destroy_ept(my_rpmsg, my_ept); + } + + ret_value = 1; /* Fail to create enpoint */ + } + else + { + qs[ept_num] = q; + endpoints[ept_num++] = my_ept; + ret_value = 0; + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_CREATE_EP; + ack_msg.RETURN_VALUE = ret_value; + env_memcpy((void *)ack_msg.RESP_DATA, (void *)&(my_ept->addr), sizeof(uint32_t)); + /* Send ack_msg to sender */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_create_ept_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + break; + + case CTR_CMD_DESTROY_EP: + ret_value = -1; + env_memcpy((void *)(&data_destroy_ept_param), (void *)msg.DATA, + sizeof(CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM)); + + if (data_destroy_ept_param.ept_to_destroy_addr == DESTROY_ALL_EPT) + { + for (i = 0; i < ept_num; i++) + { + rpmsg_lite_destroy_ept(my_rpmsg, endpoints[i]); + rpmsg_queue_destroy(my_rpmsg, qs[i]); + } + ept_num = 0; + /* We can't check return value of destroy function due to this function return void */ + ret_value = 0; + } + else + { + rpmsg_lite_destroy_ept(my_rpmsg, endpoints[data_destroy_ept_param.ept_to_destroy_addr]); + rpmsg_queue_destroy(my_rpmsg, qs[data_destroy_ept_param.ept_to_destroy_addr]); + /* We can't check return value of destroy function due to this function return void */ + ret_value = 0; + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_DESTROY_EP; + ack_msg.RETURN_VALUE = ret_value; + /* Send ack_msg to tea_control_endpoint */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_destroy_ept_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + break; + case CTR_CMD_RECV: + ret_value = -1; + env_memcpy((void *)&data_recv_param, (void *)msg.DATA, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + + my_ept = NULL; + q = NULL; + for (i = 0; i < ept_num; i++) + { + if (endpoints[i]->addr == data_recv_param.responder_ept_addr) + { + my_ept = endpoints[i]; + q = qs[i]; + break; + } + } + + if (CMD_RECV_MODE_COPY == data_recv_param.mode) + { + if (RL_BLOCK == data_recv_param.timeout_ms) + { + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, RL_BLOCK); + } + else if (RL_DONT_BLOCK == data_recv_param.timeout_ms) + { + /* receive function with non-blocking call */ + do + { + ret_value = rpmsg_queue_recv( + my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, RL_DONT_BLOCK); + if (ret_value == RL_ERR_PARAM) + break; + } while (0 != ret_value); + } + else + { +#if defined(SDK_OS_FREE_RTOS) + TickType_t tick_count = xTaskGetTickCount(); +#elif defined(FSL_RTOS_XOS) + uint64_t tick_count = xos_get_system_cycles(); +#elif defined(FSL_RTOS_THREADX) + uint64_t tick_count = tx_time_get(); +#endif + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, data_recv_param.timeout_ms); +#if defined(SDK_OS_FREE_RTOS) + tick_count = xTaskGetTickCount() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / configTICK_RATE_HZ); +#elif defined(FSL_RTOS_XOS) + tick_count = xos_get_system_cycles() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = xos_cycles_to_msecs(tick_count); +#elif defined(FSL_RTOS_THREADX) + tick_count = tx_time_get() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / TX_TIMER_TICKS_PER_SECOND); +#endif + } + } + else if (CMD_RECV_MODE_NOCOPY == data_recv_param.mode) + { + if (RL_BLOCK == data_recv_param.timeout_ms) + { + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, RL_BLOCK); + } + else if (RL_DONT_BLOCK == data_recv_param.timeout_ms) + { + /* receive function with non-blocking call */ + do + { + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, RL_DONT_BLOCK); + + if (ret_value == RL_ERR_PARAM) + break; + } while (0 != ret_value); + } + else + { +#if defined(SDK_OS_FREE_RTOS) + TickType_t tick_count = xTaskGetTickCount(); +#elif defined(FSL_RTOS_XOS) + uint64_t tick_count = xos_get_system_cycles(); +#elif defined(FSL_RTOS_THREADX) + uint64_t tick_count = tx_time_get(); +#endif + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, data_recv_param.timeout_ms); +#if defined(SDK_OS_FREE_RTOS) + tick_count = xTaskGetTickCount() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / configTICK_RATE_HZ); +#elif defined(FSL_RTOS_XOS) + tick_count = xos_get_system_cycles() - tick_count; + // Calculate milisecond + ack_msg.TIMEOUT_MSEC = xos_cycles_to_msecs(tick_count); +#elif defined(FSL_RTOS_THREADX) + tick_count = tx_time_get() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / TX_TIMER_TICKS_PER_SECOND); +#endif + } + + /* Free buffer when use rpmsg_rtos_recv_nocopy function */ + if (0 == ret_value) + { + env_memcpy((void *)recv_buffer, (void *)nocopy_buffer_ptr, num_of_received_control_bytes); + ret_value = rpmsg_queue_nocopy_free(my_rpmsg, nocopy_buffer_ptr); + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_RECV; + ack_msg.RETURN_VALUE = ret_value; + + env_memcpy((void *)ack_msg.RESP_DATA, (void *)recv_buffer, num_of_received_control_bytes); + env_memset(recv_buffer, 0, BUFFER_MAX_LENGTH); + /* Send ack_msg to sender */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + + break; + case CTR_CMD_SEND: + ret_value = -1; + env_memcpy((void *)&data_send_param, (void *)msg.DATA, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + + if (CMD_SEND_MODE_COPY == data_send_param.mode) + { + for (i = 0; i < data_send_param.repeat_count; i++) + { + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param.dest_addr, + (char *)data_send_param.msg, data_send_param.msg_size, RL_BLOCK); + } + } + else if (CMD_SEND_MODE_NOCOPY == data_send_param.mode) + { + for (i = 0; i < data_send_param.repeat_count; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + if (buf_size == 0 || data_addr == NULL) + { + ret_value = -1; /* Failed to alloc tx buffer */ + break; + } + env_memcpy((void *)data_addr, (void *)data_send_param.msg, data_send_param.msg_size); + ret_value = rpmsg_lite_send_nocopy(my_rpmsg, ctrl_ept, data_send_param.dest_addr, + (char *)data_addr, data_send_param.msg_size); + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_SEND; + ack_msg.RETURN_VALUE = ret_value; + /* Send ack_msg to tea_control_endpoint */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + + break; + case CTR_CMD_FINISH: + goto end; + break; + } + } + } + +end: + ret_value = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "negative number"); +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("04_ping_pong_rtos_sec_core"); + __coveragescanner_install("04_ping_pong_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(responder_task, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/04_ping_pong_rtos/pingpong_common.h b/tests/04_ping_pong_rtos/pingpong_common.h new file mode 100644 index 0000000..fa9079f --- /dev/null +++ b/tests/04_ping_pong_rtos/pingpong_common.h @@ -0,0 +1,111 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __common_h__ +#define __common_h__ + +#define CTR_CMD_CREATE_EP (10) +#define CTR_CMD_DESTROY_EP (11) +#define CTR_CMD_SEND (12) +#define CTR_CMD_SEND_NO_COPY (13) +#define CTR_CMD_RECV (14) +#define CTR_CMD_CREATE_CHANNEL (15) +#define CTR_CMD_DESTROY_CHANNEL (16) +#define CTR_CMD_FINISH (17) + +/* recv command modes */ +#define CMD_RECV_MODE_COPY (1) +#define CMD_RECV_MODE_NOCOPY (2) + +/* send command modes */ +#define CMD_SEND_MODE_COPY (1) +#define CMD_SEND_MODE_NOCOPY (2) + +/* acknowledge required? */ +#define ACK_REQUIRED_YES (1) +#define ACK_REQUIRED_NO (0) + +#define INIT_EPT_ADDR (2) +#define TEST_CNT (10) +#define TC_EPT_COUNT (6) +#define RESPONDER_APP_BUF_SIZE (30) +#define SENDER_APP_BUF_SIZE (50) +#define CMD_SEND_MSG_SIZE (20) +#define BUFFER_MAX_LENGTH (100) + +#define CMD_RECV_TIMEOUT_MS (2000) + +#define DESTROY_ALL_EPT (0xFFFFFFFF) + +#define EP_SIGNATURE (('H' << 24) | ('D' << 16) | ('O' << 8) | ('D' << 0)) + +#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-test-channel" + +typedef struct control_message +{ + char CMD; + char ACK_REQUIRED; + char DATA[BUFFER_MAX_LENGTH]; +} CONTROL_MESSAGE, *CONTROL_MESSAGE_PTR; + +typedef struct acknowledge_message +{ + char CMD_ACK; + int32_t RETURN_VALUE; + uint32_t TIMEOUT_MSEC; + char RESP_DATA[BUFFER_MAX_LENGTH]; +} ACKNOWLEDGE_MESSAGE, *ACKNOWLEDGE_MESSAGE_PTR; + +/* create endpoint data message format */ +typedef struct control_message_data_create_ept_param +{ + uint32_t ept_to_create_addr; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM, *CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM_PTR; + +/* destroy endpoint data message format */ +typedef struct control_message_data_destroy_ept_param +{ + uint32_t ept_to_destroy_addr; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM, *CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM_PTR; + +/* create channel data message format */ +typedef struct control_message_data_create_channel_param +{ + char name[32]; + uint32_t ep_to_ack_addr; +} CONTROL_MESSAGE_DATA_CREATE_CHANNEL_PARAM, *CONTROL_MESSAGE_DATA_CREATE_CHANNEL_PARAM_PTR; + +/* delete channel data message format */ +typedef struct control_message_data_delete_channel_param +{ + char name[32]; + uint32_t ep_to_ack_addr; +} CONTROL_MESSAGE_DATA_DELETE_CHANNEL_PARAM, *CONTROL_MESSAGE_DATA_DELETE_CHANNEL_PARAM_PTR; + +/* send data message format */ +typedef struct control_message_data_send_param +{ + uint32_t dest_addr; + char msg[BUFFER_MAX_LENGTH - 20]; + int32_t msg_size; + uint32_t repeat_count; + uint32_t mode; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_SEND_PARAM, *CONTROL_MESSAGE_DATA_SEND_PARAM_PTR; + +/* receive data message format */ +typedef struct control_message_data_recv_param +{ + uint32_t responder_ept_addr; + int32_t buffer_size; + uint32_t timeout_ms; + uint32_t mode; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_RECV_PARAM, *CONTROL_MESSAGE_DATA_RECV_PARAM_PTR; + +#endif // __common_h__ diff --git a/tests/04_ping_pong_rtos/readme.txt b/tests/04_ping_pong_rtos/readme.txt new file mode 100644 index 0000000..7ecbd24 --- /dev/null +++ b/tests/04_ping_pong_rtos/readme.txt @@ -0,0 +1,5 @@ +04_ping_pong_rtos test suite + + - FreeRTOS/ThreadX/XOS-based project, covering both the static allocation (#define RL_USE_STATIC_API (1) in rpmsg_config.h) and the dynamic allocation (#define RL_USE_STATIC_API (0) in rpmsg_config.h) + + - test ping pong functionality in rtos env. \ No newline at end of file diff --git a/tests/05_thread_safety_rtos/main_core0.c b/tests/05_thread_safety_rtos/main_core0.c new file mode 100644 index 0000000..9aa2890 --- /dev/null +++ b/tests/05_thread_safety_rtos/main_core0.c @@ -0,0 +1,437 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include "pingpong_common.h" +#include "unity.h" +#include "assert.h" +#include "rpmsg_queue.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#elif defined(FSL_RTOS_THREADX) +#include "tx_api.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (40) +#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *endpoints[TC_EPT_COUNT] = {NULL}; +rpmsg_queue_handle qs[TC_EPT_COUNT] = {NULL}; +int32_t ept_num = 0; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; + +struct rpmsg_lite_endpoint *volatile ctrl_ept = NULL; +rpmsg_queue_handle ctrl_q; + +/* + * utility: initialize rpmsg and environment + * and wait for default channel + */ +int32_t ts_init_rpmsg(void) +{ + env_init(); + env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + ctrl_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE(NULL != ctrl_q, "'rpmsg_queue_create' failed"); + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +/* + * utility: deinitialize rpmsg and environment + */ +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_queue_destroy(my_rpmsg, ctrl_q); + rpmsg_lite_deinit(my_rpmsg); + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/****************************************************************************** + * Responder task + *****************************************************************************/ +void responder_task(void) +{ + int32_t ret_value = 0; + void *data_addr = NULL; + uint32_t num_of_received_control_bytes; + uint32_t i; + uint32_t src = 0; + rpmsg_queue_handle q; + struct rpmsg_lite_endpoint *my_ept; + CONTROL_MESSAGE msg; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + unsigned char *recv_buffer[BUFFER_MAX_LENGTH]; + void *nocopy_buffer_ptr = NULL; // pointer to receive data in no-copy mode + uint32_t buf_size = 0; /* use to store size of buffer for + rpmsg_rtos_alloc_tx_buffer() */ + + ret_value = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "Testing function init rpmsg"); + if (ret_value) + goto end; + + /* start the test */ + rpmsg_lite_send(my_rpmsg, ctrl_ept, TC_REMOTE_EPT_ADDR, (char *)"start", 5, RL_BLOCK); + env_sleep_msec(200); + + while (1) + { + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&msg, sizeof(CONTROL_MESSAGE), + &num_of_received_control_bytes, RL_BLOCK); + env_sleep_msec(2); + if (0 != ret_value) + { + //PRINTF("Responder task receive error: %i\n", ret_value); + } + else + { + //PRINTF("Responder task received a msg\n\r"); + //PRINTF("Message: Size=0x%x, CMD = 0x%x, DATA = 0x%x 0x%x 0x%x 0x%x\n\r", num_of_received_control_bytes, + // msg.CMD, msg.DATA[0], msg.DATA[1], msg.DATA[2], msg.DATA[3]); + switch (msg.CMD) + { + case CTR_CMD_CREATE_EP: + ret_value = -1; + env_memcpy((void *)(&data_create_ept_param), (void *)msg.DATA, + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + + q = rpmsg_queue_create(my_rpmsg); + my_ept = + rpmsg_lite_create_ept(my_rpmsg, data_create_ept_param.ept_to_create_addr, rpmsg_queue_rx_cb, q); + + if ((NULL == my_ept) || (NULL == q)) + { + if (NULL != q) + { + rpmsg_queue_destroy(my_rpmsg, q); + } + + if (NULL != my_ept) + { + rpmsg_lite_destroy_ept(my_rpmsg, my_ept); + } + + ret_value = 1; /* Fail to create enpoint */ + } + else + { + ret_value = 2; + for (i = 0; i < TC_EPT_COUNT; i++) + { + if (endpoints[i] == NULL) + { + endpoints[i] = my_ept; + qs[i] = q; + ept_num++; + ret_value = 0; + break; + } + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_CREATE_EP; + ack_msg.RETURN_VALUE = ret_value; + env_memcpy((void *)ack_msg.RESP_DATA, (void *)&(my_ept->addr), sizeof(uint32_t)); + /* Send ack_msg to sender */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_create_ept_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + break; + case CTR_CMD_DESTROY_EP: + ret_value = -1; + env_memcpy((void *)(&data_destroy_ept_param), (void *)msg.DATA, + sizeof(CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM)); + + if (data_destroy_ept_param.ept_to_destroy_addr == DESTROY_ALL_EPT) + { + for (i = 0; i < TC_EPT_COUNT; i++) + { + if (endpoints[i] != NULL) + { + rpmsg_lite_destroy_ept(my_rpmsg, endpoints[i]); + rpmsg_queue_destroy(my_rpmsg, qs[i]); + ept_num--; + endpoints[i] = NULL; + /* We can't check return value of destroy function due to this function return void */ + ret_value = 0; + } + } + } + else + { + ret_value = 1; + for (i = 0; i < TC_EPT_COUNT; i++) + { + if (endpoints[i] != NULL) + { + if (data_destroy_ept_param.ept_to_destroy_addr == endpoints[i]->addr) + { + rpmsg_lite_destroy_ept(my_rpmsg, endpoints[i]); + rpmsg_queue_destroy(my_rpmsg, qs[i]); + ept_num--; + endpoints[i] = NULL; + /* We can't check return value of destroy function due to this function return void + */ + ret_value = 0; + break; + } + } + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_DESTROY_EP; + ack_msg.RETURN_VALUE = ret_value; + /* Send ack_msg to tea_control_endpoint */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_destroy_ept_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + break; + case CTR_CMD_RECV: + ret_value = -1; + env_memcpy((void *)&data_recv_param, (void *)msg.DATA, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + + my_ept = NULL; + for (i = 0; i < TC_EPT_COUNT; i++) + { + if (endpoints[i] != NULL) + { + if (data_recv_param.responder_ept_addr == endpoints[i]->addr) + { + my_ept = endpoints[i]; + q = qs[i]; + // printf("Found ept with address %d\n", data_recv_param.responder_ept_addr); + } + } + } + + if (my_ept == NULL) + { + ret_value = -1; + } + else if (CMD_RECV_MODE_COPY == data_recv_param.mode) + { + if (RL_BLOCK == data_recv_param.timeout_ms) + { + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, RL_BLOCK); + } + else if (RL_DONT_BLOCK == data_recv_param.timeout_ms) + { + /* receive function with non-blocking call */ + do + { + ret_value = rpmsg_queue_recv( + my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, RL_DONT_BLOCK); + if (ret_value == RL_ERR_PARAM) + break; + } while (0 != ret_value); + } + else + { +#if defined(SDK_OS_FREE_RTOS) + TickType_t tick_count = xTaskGetTickCount(); + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, data_recv_param.timeout_ms); + tick_count = xTaskGetTickCount() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / configTICK_RATE_HZ); +#elif defined(FSL_RTOS_THREADX) + ULONG tick_count = tx_time_get(); + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, data_recv_param.timeout_ms); + tick_count = tx_time_get() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / TX_TIMER_TICKS_PER_SECOND); +#endif + } + } + else if (CMD_RECV_MODE_NOCOPY == data_recv_param.mode) + { + if (RL_BLOCK == data_recv_param.timeout_ms) + { + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, RL_BLOCK); + } + else if (RL_DONT_BLOCK == data_recv_param.timeout_ms) + { + /* receive function with non-blocking call */ + do + { + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, RL_DONT_BLOCK); + + if (ret_value == RL_ERR_PARAM) + break; + } while (0 != ret_value); + } + else + { +#if defined(SDK_OS_FREE_RTOS) + TickType_t tick_count = xTaskGetTickCount(); + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, data_recv_param.timeout_ms); + tick_count = xTaskGetTickCount() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / configTICK_RATE_HZ); +#elif defined(FSL_RTOS_THREADX) + ULONG tick_count = tx_time_get(); + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, data_recv_param.timeout_ms); + tick_count = tx_time_get() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / TX_TIMER_TICKS_PER_SECOND); +#endif + } + + /* Free buffer when use rpmsg_rtos_recv_nocopy function */ + if (0 == ret_value) + { + env_memcpy((void *)recv_buffer, (void *)nocopy_buffer_ptr, num_of_received_control_bytes); + ret_value = rpmsg_queue_nocopy_free(my_rpmsg, nocopy_buffer_ptr); + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_RECV; + ack_msg.RETURN_VALUE = ret_value; + + env_memcpy((void *)ack_msg.RESP_DATA, (void *)recv_buffer, num_of_received_control_bytes); + env_memset(recv_buffer, 0, BUFFER_MAX_LENGTH); + /* Send ack_msg to sender */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + + break; + case CTR_CMD_SEND: + ret_value = -1; + env_memcpy((void *)&data_send_param, (void *)msg.DATA, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + + if (CMD_SEND_MODE_COPY == data_send_param.mode) + { + for (i = 0; i < data_send_param.repeat_count; i++) + { + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param.dest_addr, + (char *)data_send_param.msg, data_send_param.msg_size, RL_BLOCK); + } + } + else if (CMD_SEND_MODE_NOCOPY == data_send_param.mode) + { + for (i = 0; i < data_send_param.repeat_count; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + if (buf_size == 0 || data_addr == NULL) + { + ret_value = -1; /* Failed to alloc tx buffer */ + break; + } + env_memcpy((void *)data_addr, (void *)data_send_param.msg, data_send_param.msg_size); + ret_value = rpmsg_lite_send_nocopy(my_rpmsg, ctrl_ept, data_send_param.dest_addr, + (char *)data_addr, data_send_param.msg_size); + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_SEND; + ack_msg.RETURN_VALUE = ret_value; + /* Send ack_msg to tea_control_endpoint */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + + break; + case CTR_CMD_FINISH: + goto end; + break; + } + } + } + +end: + ret_value = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "negative number"); +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("05_thread_safety_rtos"); + __coveragescanner_install("05_thread_safety_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(responder_task, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/05_thread_safety_rtos/main_core1.c b/tests/05_thread_safety_rtos/main_core1.c new file mode 100644 index 0000000..5fe3e2c --- /dev/null +++ b/tests/05_thread_safety_rtos/main_core1.c @@ -0,0 +1,415 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include "pingpong_common.h" +#include "unity.h" +#include "assert.h" +#include "rpmsg_queue.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#elif defined(FSL_RTOS_XOS) +#include +#include +#elif defined(FSL_RTOS_THREADX) +#include "tx_api.h" +#endif +#include "string.h" +#include "stdint.h" + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define WORKER_NUMBER (2) /* Number of concurrent threads, needs enough heap... */ +#define TEST_EPT_NUM_BASE (60) +#define REMOTE_DEFAULT_EPT (TC_REMOTE_EPT_ADDR) +#if defined (CPU_LPC54102J512BD64_cm0plus) +#define TEST_THREAD_SAFETY_TASK_STACK_SIZE (192) /* Verified for Niobe1/2 boards */ +#else +#define TEST_THREAD_SAFETY_TASK_STACK_SIZE (250) +#endif + +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +typedef struct +{ + struct rpmsg_lite_endpoint *ack_ept; + rpmsg_queue_handle ack_q; + uint8_t worker_id; +#if defined(FSL_RTOS_XOS) + XosThread test_thread_handle; + void *task_stack_base; +#elif defined(FSL_RTOS_THREADX) + TX_THREAD test_thread_handle; + void *task_stack_base; +#endif +} initParamTypedef; + +/******************************************************************************* + * Code + ******************************************************************************/ +volatile int32_t globCntr = 0; + +struct rpmsg_lite_endpoint *volatile ctrl_ept = NULL; +rpmsg_queue_handle ctrl_q; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; + +#if defined(FSL_RTOS_THREADX) +VOID sendRecvTestTask(ULONG arg); +#else +void sendRecvTestTask(void *ept_number); +#endif + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + ctrl_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE(NULL != ctrl_q, "'rpmsg_queue_create' failed"); + + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_queue_destroy(my_rpmsg, ctrl_q); + rpmsg_lite_deinit(my_rpmsg); + return 0; +} +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/* + * Destroy an endpoint on the other side + */ +int32_t ts_destroy_ept(int32_t addr, struct rpmsg_lite_endpoint *ack_ept, rpmsg_queue_handle ack_q) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + int32_t ret_value; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ept_param; + + data_destroy_ept_param.ept_to_ack_addr = ack_ept->addr; + data_destroy_ept_param.ept_to_destroy_addr = addr; + + msg.CMD = CTR_CMD_DESTROY_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_destroy_ept_param), sizeof(CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM)); + ret_value = rpmsg_lite_send(my_rpmsg, ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == ret_value, "error! failed to send CTR_CMD_DESTROY_EP command to other side"); + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ack_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE(0 == ret_value, "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE(CTR_CMD_DESTROY_EP == ack_msg.CMD_ACK, + "error! expecting acknowledge of CTR_CMD_DESTROY_EP copmmand"); + TEST_ASSERT_MESSAGE(0 == ack_msg.RETURN_VALUE, "error! failed to destroy endpoints on other side"); + + return 0; +} + +/* + * Thread safety testing + */ +void tc_1_main_task(void) +{ + int32_t result, i; + initParamTypedef *initParam = NULL; + uint32_t src; + uint32_t recved; + char buf[32]; + CONTROL_MESSAGE msg = {0}; + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + if (result == 0) + { + rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)buf, 32, &recved, RL_BLOCK); + for (i = 0; i < WORKER_NUMBER; i++) + { +#if defined(SDK_OS_FREE_RTOS) + initParam = pvPortMalloc(sizeof(initParamTypedef)); +#elif defined(FSL_RTOS_XOS) || defined(FSL_RTOS_THREADX) + initParam = env_allocate_memory(sizeof(initParamTypedef)); +#endif + TEST_ASSERT_MESSAGE(NULL != initParam, "Out of memory"); + initParam->worker_id = (uint8_t)i; + initParam->ack_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE(NULL != initParam->ack_q, "Out of memory"); + initParam->ack_ept = rpmsg_lite_create_ept(my_rpmsg, RL_ADDR_ANY, rpmsg_queue_rx_cb, initParam->ack_q); + TEST_ASSERT_MESSAGE(NULL != initParam->ack_ept, "Out of memory"); +#if defined(SDK_OS_FREE_RTOS) + result = xTaskCreate(sendRecvTestTask, "THREAD_SAFETY_TASK", TEST_THREAD_SAFETY_TASK_STACK_SIZE, (void *)(initParam), tskIDLE_PRIORITY + 2, + NULL); + TEST_ASSERT_MESSAGE(pdPASS == result, "Could not create worker!"); +#elif defined(FSL_RTOS_XOS) + initParam->task_stack_base = malloc(XOS_STACK_MIN_SIZE + 4*TEST_THREAD_SAFETY_TASK_STACK_SIZE); + result = xos_thread_create(&initParam->test_thread_handle, NULL, (XosThreadFunc*)sendRecvTestTask, (void *)(initParam), "THREAD_SAFETY_TASK", initParam->task_stack_base, (uint32_t)(XOS_STACK_MIN_SIZE + 4*TEST_THREAD_SAFETY_TASK_STACK_SIZE), 6, 0, 0); + TEST_ASSERT_MESSAGE(XOS_OK == result, "Could not create worker!"); +#elif defined(FSL_RTOS_THREADX) + initParam->task_stack_base = env_allocate_memory(TEST_THREAD_SAFETY_TASK_STACK_SIZE * sizeof(ULONG)); + TEST_ASSERT_MESSAGE(NULL != initParam->task_stack_base, "Out of memory"); + result = tx_thread_create(&initParam->test_thread_handle, "THREAD_SAFETY_TASK", sendRecvTestTask, (ULONG)(initParam), (VOID *)initParam->task_stack_base, (TEST_THREAD_SAFETY_TASK_STACK_SIZE * sizeof(ULONG)), (TX_MAX_PRIORITIES - 2), (TX_MAX_PRIORITIES - 2), 1, TX_AUTO_START); + TEST_ASSERT_MESSAGE(TX_SUCCESS == result, "Could not create worker!"); +#endif + } + + globCntr = 0; + while (globCntr < WORKER_NUMBER) + { +#if defined(SDK_OS_FREE_RTOS) + vTaskDelay(100); +#elif defined(FSL_RTOS_XOS) + xos_thread_sleep_msec(1000); +#elif defined(FSL_RTOS_THREADX) + tx_thread_sleep(100); +#endif + } + + /* Send command to end to the other core to finish testing */ + msg.CMD = CTR_CMD_FINISH; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + rpmsg_lite_send(my_rpmsg, ctrl_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + } + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); +} + +#if defined(FSL_RTOS_THREADX) +VOID sendRecvTestTask(ULONG initParam) +#else +void sendRecvTestTask(void *initParam) +#endif +{ + initParamTypedef *init = (initParamTypedef *)initParam; + TEST_ASSERT_MESSAGE(NULL != init, "Out of memory"); + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + rpmsg_queue_handle sender_q = NULL; + struct rpmsg_lite_endpoint *sender_ept = NULL; + uint32_t responder_ept_addr = -1; + uint32_t ept_address = TEST_EPT_NUM_BASE + init->worker_id; +#ifndef UNITY_NOT_PRINT_LOG + char worker_id_str[2] = {init->worker_id + 'a', '\0'}; +#endif + int32_t ret_value, i = 0, testing_count = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + char recv_buffer[SENDER_APP_BUF_SIZE]; + + data_create_ept_param.ept_to_ack_addr = init->ack_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + env_memcpy((void *)data_send_param.msg, "abc", (uint32_t)4); + data_send_param.ept_to_ack_addr = init->ack_ept->addr; + data_send_param.msg_size = CMD_SEND_MSG_SIZE; + data_send_param.repeat_count = 1; + data_send_param.mode = CMD_SEND_MODE_COPY; + + data_recv_param.ept_to_ack_addr = init->ack_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = RL_BLOCK; + data_recv_param.mode = CMD_RECV_MODE_COPY; + + /* Testing with blocking call and non-blocking call (timeout = 0) */ + for (testing_count = 0; testing_count < 16; testing_count++) + { + UnityPrint(worker_id_str); /* Print a dot, showing progress */ + + for (i = 0; i < TEST_CNT; i++) + { + /* + * Test receive function + * Sender sends a request to create endpoint on the other side + * Responder will receive the data from sender through this endpoint + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, + sizeof(CONTROL_MESSAGE), RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, init->ack_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : 0), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : 0), "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, (uint32_t)(sizeof(uint32_t))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + /* send CTR_CMD_RECV command to the other side */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, + sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to send CTR_CMD_RECV command to other side"); + + /* Send "aaa" string to other side */ + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, + RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to send 'aaa' string to other side"); + + /* Get respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, init->ack_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : 0), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : 0), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(ack_msg.RESP_DATA, "aaa", 3) ? 1 : 0), "error! incorrect data received"); + + /* + * Test send function + * Create a new endpoint on the sender side and sender will receive data through this endpoint + */ + sender_q = rpmsg_queue_create(my_rpmsg); + TEST_ASSERT_MESSAGE(NULL != sender_q, "error! failed to create queue"); + sender_ept = rpmsg_lite_create_ept(my_rpmsg, ept_address, rpmsg_queue_rx_cb, sender_q); + TEST_ASSERT_MESSAGE(NULL != sender_ept, "error! failed to create endpoint"); + + data_send_param.dest_addr = sender_ept->addr; + + msg.CMD = CTR_CMD_SEND; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + env_memcpy((void *)msg.DATA, (void *)&data_send_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, + sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to send CTR_CMD_SEND command to other side"); + + ret_value = rpmsg_queue_recv(my_rpmsg, sender_q, &src, (char *)recv_buffer, SENDER_APP_BUF_SIZE, + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to receive data from other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(recv_buffer, "abc", 3) ? 1 : 0), "error! incorrect data received"); + + /* + * Destroy created endpoint on the sender side + */ + rpmsg_lite_destroy_ept(my_rpmsg, sender_ept); + rpmsg_queue_destroy(my_rpmsg, sender_q); + sender_q = NULL; + sender_ept = NULL; + + ts_destroy_ept(responder_ept_addr, init->ack_ept, init->ack_q); + } + + /* + * Attempt to call receive function on the other side with the invalid EP pointer (not yet created EP) + */ + data_recv_param.responder_ept_addr = -1; + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, init->ack_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : 0), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((ack_msg.RETURN_VALUE < 0 ? 1 : 0), + "error! failed when call rpmsg_rtos_recv function on the other side"); + } + globCntr++; + + rpmsg_lite_destroy_ept(my_rpmsg, init->ack_ept); + rpmsg_queue_destroy(my_rpmsg, init->ack_q); +#if defined(SDK_OS_FREE_RTOS) + vPortFree(init); + vTaskDelete(NULL); +#elif defined(FSL_RTOS_XOS) + free(init->task_stack_base); + free(init); + xos_thread_exit(0); +#elif defined(FSL_RTOS_THREADX) + env_free_memory(init->task_stack_base); + env_free_memory(init); + tx_thread_delete(&(init->test_thread_handle)); +#endif +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("05_thread_safety_rtos_sec_core"); + __coveragescanner_install("05_thread_safety_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/05_thread_safety_rtos/main_static_alloc_core0.c b/tests/05_thread_safety_rtos/main_static_alloc_core0.c new file mode 100644 index 0000000..e38dd72 --- /dev/null +++ b/tests/05_thread_safety_rtos/main_static_alloc_core0.c @@ -0,0 +1,448 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include "pingpong_common.h" +#include "unity.h" +#include "assert.h" +#include "rpmsg_queue.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#elif defined(FSL_RTOS_THREADX) +#include "tx_api.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define TC_LOCAL_EPT_ADDR (40) +#define TC_REMOTE_EPT_ADDR (30) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +struct rpmsg_lite_endpoint *volatile ctrl_ept = NULL; +struct rpmsg_lite_ept_static_context ctrl_ept_ctxt = {0}; + +rpmsg_queue_handle ctrl_q = NULL; +rpmsg_static_queue_ctxt ctrl_queue_ctxt = {0}; +uint8_t ctrl_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt = {0}; + +struct rpmsg_lite_endpoint *endpoints[TC_EPT_COUNT] = {NULL}; +struct rpmsg_lite_ept_static_context endpoints_ctxt[TC_EPT_COUNT] = {0}; +rpmsg_queue_handle qs[TC_EPT_COUNT] = {NULL}; +rpmsg_static_queue_ctxt qs_ctxt[TC_EPT_COUNT] = {0}; +uint8_t qs_storage[TC_EPT_COUNT][RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; +int32_t ept_num = 0; + +/* + * utility: initialize rpmsg and environment + * and wait for default channel + */ +int32_t ts_init_rpmsg(void) +{ + env_init(); + env_sleep_msec(200); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_SHMEM_SIZE, RPMSG_LITE_LINK_ID, + RL_NO_FLAGS, &rpmsg_ctxt); +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + ctrl_q = rpmsg_queue_create(my_rpmsg, &ctrl_queue_storage[0], &ctrl_queue_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_q, "'rpmsg_queue_create' failed"); + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q, &ctrl_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +/* + * utility: deinitialize rpmsg and environment + */ +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_queue_destroy(my_rpmsg, ctrl_q); + rpmsg_lite_deinit(my_rpmsg); + my_rpmsg = NULL; + env_memset(&rpmsg_ctxt, 0, sizeof(struct rpmsg_lite_instance)); + return 0; +} + +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/****************************************************************************** + * Responder task + *****************************************************************************/ +void responder_task(void) +{ + int32_t ret_value = 0; + void *data_addr = NULL; + uint32_t num_of_received_control_bytes; + uint32_t i = 0; + uint32_t src = 0; + struct rpmsg_lite_endpoint *my_ept = NULL; + rpmsg_queue_handle q = NULL; + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + unsigned char *recv_buffer[BUFFER_MAX_LENGTH]; + void *nocopy_buffer_ptr = NULL; // pointer to receive data in no-copy mode + uint32_t buf_size = 0; /* use to store size of buffer for + rpmsg_rtos_alloc_tx_buffer() */ + + ret_value = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "Testing function init rpmsg"); + if (ret_value) + goto end; + + /* start the test */ + rpmsg_lite_send(my_rpmsg, ctrl_ept, TC_REMOTE_EPT_ADDR, (char *)"start", 5, RL_BLOCK); + env_sleep_msec(200); + + while (1) + { + ret_value = rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)&msg, sizeof(CONTROL_MESSAGE), + &num_of_received_control_bytes, RL_BLOCK); + env_sleep_msec(2); + if (0 != ret_value) + { + /* PRINTF("Responder task receive error: %i\n", ret_value); */ + } + else + { + /* PRINTF("Responder task received a msg\n\r"); */ + /* PRINTF("Message: Size=0x%x, CMD = 0x%x, DATA = 0x%x 0x%x 0x%x 0x%x\n\r", num_of_received_control_bytes, + msg.CMD, msg.DATA[0], msg.DATA[1], msg.DATA[2], msg.DATA[3]); */ + + switch (msg.CMD) + { + case CTR_CMD_CREATE_EP: + ret_value = -1; + env_memcpy((void *)(&data_create_ept_param), (void *)msg.DATA, + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + + q = rpmsg_queue_create(my_rpmsg, &qs_storage[ept_num][0], &qs_ctxt[ept_num]); + my_ept = + rpmsg_lite_create_ept(my_rpmsg, data_create_ept_param.ept_to_create_addr, rpmsg_queue_rx_cb, q, &endpoints_ctxt[ept_num]); + + if ((NULL == my_ept) || (NULL == q)) + { + if (NULL != q) + { + rpmsg_queue_destroy(my_rpmsg, q); + } + + if (NULL != my_ept) + { + rpmsg_lite_destroy_ept(my_rpmsg, my_ept); + } + + ret_value = 1; /* Fail to create enpoint */ + } + else + { + ret_value = 2; + for (i = 0; i < TC_EPT_COUNT; i++) + { + if (endpoints[i] == NULL) + { + endpoints[i] = my_ept; + qs[i] = q; + ept_num++; + ret_value = 0; + break; + } + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_CREATE_EP; + ack_msg.RETURN_VALUE = ret_value; + env_memcpy((void *)ack_msg.RESP_DATA, (void *)&(my_ept->addr), sizeof(uint32_t)); + /* Send ack_msg to sender */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_create_ept_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + break; + case CTR_CMD_DESTROY_EP: + ret_value = -1; + env_memcpy((void *)(&data_destroy_ept_param), (void *)msg.DATA, + sizeof(CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM)); + + if (data_destroy_ept_param.ept_to_destroy_addr == DESTROY_ALL_EPT) + { + for (i = 0; i < TC_EPT_COUNT; i++) + { + if (endpoints[i] != NULL) + { + rpmsg_lite_destroy_ept(my_rpmsg, endpoints[i]); + rpmsg_queue_destroy(my_rpmsg, qs[i]); + ept_num--; + endpoints[i] = NULL; + /* We can't check return value of destroy function due to this function return void */ + ret_value = 0; + } + } + } + else + { + ret_value = 1; + for (i = 0; i < TC_EPT_COUNT; i++) + { + if (endpoints[i] != NULL) + { + if (data_destroy_ept_param.ept_to_destroy_addr == endpoints[i]->addr) + { + rpmsg_lite_destroy_ept(my_rpmsg, endpoints[i]); + rpmsg_queue_destroy(my_rpmsg, qs[i]); + ept_num--; + endpoints[i] = NULL; + /* We can't check return value of destroy function due to this function return void + */ + ret_value = 0; + break; + } + } + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_DESTROY_EP; + ack_msg.RETURN_VALUE = ret_value; + /* Send ack_msg to tea_control_endpoint */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_destroy_ept_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + break; + case CTR_CMD_RECV: + ret_value = -1; + env_memcpy((void *)&data_recv_param, (void *)msg.DATA, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + + my_ept = NULL; + for (i = 0; i < TC_EPT_COUNT; i++) + { + if (endpoints[i] != NULL) + { + if (data_recv_param.responder_ept_addr == endpoints[i]->addr) + { + my_ept = endpoints[i]; + q = qs[i]; + // printf("Found ept with address %d\n", data_recv_param.responder_ept_addr); + } + } + } + + if (my_ept == NULL) + { + ret_value = -1; + } + else if (CMD_RECV_MODE_COPY == data_recv_param.mode) + { + if (RL_BLOCK == data_recv_param.timeout_ms) + { + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, RL_BLOCK); + } + else if (RL_DONT_BLOCK == data_recv_param.timeout_ms) + { + /* receive function with non-blocking call */ + do + { + ret_value = rpmsg_queue_recv( + my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, RL_DONT_BLOCK); + if (ret_value == RL_ERR_PARAM) + break; + } while (0 != ret_value); + } + else + { +#if defined(SDK_OS_FREE_RTOS) + TickType_t tick_count = xTaskGetTickCount(); + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, data_recv_param.timeout_ms); + tick_count = xTaskGetTickCount() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / configTICK_RATE_HZ); +#elif defined(FSL_RTOS_THREADX) + ULONG tick_count = tx_time_get(); + ret_value = + rpmsg_queue_recv(my_rpmsg, q, &src, (char *)recv_buffer, data_recv_param.buffer_size, + &num_of_received_control_bytes, data_recv_param.timeout_ms); + tick_count = tx_time_get() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / TX_TIMER_TICKS_PER_SECOND); +#endif + } + } + else if (CMD_RECV_MODE_NOCOPY == data_recv_param.mode) + { + if (RL_BLOCK == data_recv_param.timeout_ms) + { + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, RL_BLOCK); + } + else if (RL_DONT_BLOCK == data_recv_param.timeout_ms) + { + /* receive function with non-blocking call */ + do + { + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, RL_DONT_BLOCK); + + if (ret_value == RL_ERR_PARAM) + break; + } while (0 != ret_value); + } + else + { +#if defined(SDK_OS_FREE_RTOS) + TickType_t tick_count = xTaskGetTickCount(); + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, data_recv_param.timeout_ms); + tick_count = xTaskGetTickCount() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / configTICK_RATE_HZ); +#elif defined(FSL_RTOS_THREADX) + ULONG tick_count = tx_time_get(); + ret_value = + rpmsg_queue_recv_nocopy(my_rpmsg, q, &src, (char **)&nocopy_buffer_ptr, + &num_of_received_control_bytes, data_recv_param.timeout_ms); + tick_count = tx_time_get() - tick_count; + // Calculate millisecond + ack_msg.TIMEOUT_MSEC = tick_count * (1000 / TX_TIMER_TICKS_PER_SECOND); +#endif + } + + /* Free buffer when use rpmsg_rtos_recv_nocopy function */ + if (0 == ret_value) + { + env_memcpy((void *)recv_buffer, (void *)nocopy_buffer_ptr, num_of_received_control_bytes); + ret_value = rpmsg_queue_nocopy_free(my_rpmsg, nocopy_buffer_ptr); + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_RECV; + ack_msg.RETURN_VALUE = ret_value; + + env_memcpy((void *)ack_msg.RESP_DATA, (void *)recv_buffer, num_of_received_control_bytes); + env_memset(recv_buffer, 0, BUFFER_MAX_LENGTH); + /* Send ack_msg to sender */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_recv_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + + break; + case CTR_CMD_SEND: + ret_value = -1; + env_memcpy((void *)&data_send_param, (void *)msg.DATA, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + + if (CMD_SEND_MODE_COPY == data_send_param.mode) + { + for (i = 0; i < data_send_param.repeat_count; i++) + { + ret_value = + rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param.dest_addr, + (char *)data_send_param.msg, data_send_param.msg_size, RL_BLOCK); + } + } + else if (CMD_SEND_MODE_NOCOPY == data_send_param.mode) + { + for (i = 0; i < data_send_param.repeat_count; i++) + { + data_addr = rpmsg_lite_alloc_tx_buffer(my_rpmsg, &buf_size, RL_BLOCK); + if (buf_size == 0 || data_addr == NULL) + { + ret_value = -1; /* Failed to alloc tx buffer */ + break; + } + env_memcpy((void *)data_addr, (void *)data_send_param.msg, data_send_param.msg_size); + ret_value = rpmsg_lite_send_nocopy(my_rpmsg, ctrl_ept, data_send_param.dest_addr, + (char *)data_addr, data_send_param.msg_size); + } + } + + if (ACK_REQUIRED_YES == msg.ACK_REQUIRED) + { + ack_msg.CMD_ACK = CTR_CMD_SEND; + ack_msg.RETURN_VALUE = ret_value; + /* Send ack_msg to tea_control_endpoint */ + ret_value = rpmsg_lite_send(my_rpmsg, ctrl_ept, data_send_param.ept_to_ack_addr, + (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), RL_BLOCK); + } + + break; + case CTR_CMD_FINISH: + goto end; + break; + } + } + } + +end: + ret_value = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == ret_value, "negative number"); +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("05_thread_safety_rtos"); + __coveragescanner_install("05_thread_safety_rtos.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(responder_task, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/05_thread_safety_rtos/main_static_alloc_core1.c b/tests/05_thread_safety_rtos/main_static_alloc_core1.c new file mode 100644 index 0000000..8fb2272 --- /dev/null +++ b/tests/05_thread_safety_rtos/main_static_alloc_core1.c @@ -0,0 +1,438 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "rpmsg_lite.h" +#include +#include "pingpong_common.h" +#include "unity.h" +#include "assert.h" +#include "rpmsg_queue.h" +#include "app.h" +#if defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "task.h" +#elif defined(FSL_RTOS_XOS) +#include +#include +#elif defined(FSL_RTOS_THREADX) +#include "tx_api.h" +#endif +#include "string.h" +#include "stdint.h" + +#include "fsl_common.h" +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) +#include "fsl_memory.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define TC_TRANSFER_COUNT 10 +#define DATA_LEN 45 +#define WORKER_NUMBER (2) /* Number of concurrent threads, needs enough heap... */ +#define TEST_EPT_NUM_BASE (60) +#define REMOTE_DEFAULT_EPT (TC_REMOTE_EPT_ADDR) +#if defined (CPU_LPC54102J512BD64_cm0plus) +#define TEST_THREAD_SAFETY_TASK_STACK_SIZE (192) /* Verified for Niobe1/2 boards */ +#else +#define TEST_THREAD_SAFETY_TASK_STACK_SIZE (300) +#endif + +#define TC_LOCAL_EPT_ADDR (30) +#define TC_REMOTE_EPT_ADDR (40) + +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER +#define SH_MEM_TOTAL_SIZE (6144) +#if defined(__ICCARM__) /* IAR Workbench */ +#pragma location = "rpmsg_sh_mem_section" +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil MDK */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section("rpmsg_sh_mem_section"))); +#elif defined(__GNUC__) /* LPCXpresso */ +char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(".noinit.$rpmsg_sh_mem"))); +#else +#error "RPMsg: Please provide your definition of rpmsg_lite_base[]!" +#endif +#endif /*SH_MEM_NOT_TAKEN_FROM_LINKER */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +typedef struct +{ + struct rpmsg_lite_endpoint *ack_ept; + struct rpmsg_lite_ept_static_context ack_ept_ctxt; + rpmsg_queue_handle ack_q; + rpmsg_static_queue_ctxt ack_q_ctxt; + uint8_t ack_q_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE]; + uint8_t worker_id; +#if defined(SDK_OS_FREE_RTOS) + TaskHandle_t test_thread_handle; + StaticTask_t xTaskBuffer; + void *task_stack_base; +#elif defined(FSL_RTOS_XOS) + XosThread test_thread_handle; + void *task_stack_base; +#elif defined(FSL_RTOS_THREADX) + TX_THREAD test_thread_handle; + void *task_stack_base; +#endif +} initParamTypedef; + +/******************************************************************************* + * Code + ******************************************************************************/ +volatile int32_t globCntr = 0; + +struct rpmsg_lite_endpoint *volatile ctrl_ept = NULL; +struct rpmsg_lite_ept_static_context ctrl_ept_ctxt = {0}; + +rpmsg_queue_handle ctrl_q = NULL; +rpmsg_static_queue_ctxt ctrl_queue_ctxt = {0}; +uint8_t ctrl_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; +struct rpmsg_lite_instance *volatile my_rpmsg = NULL; +struct rpmsg_lite_instance rpmsg_ctxt = {0}; + +#if defined(FSL_RTOS_THREADX) +VOID sendRecvTestTask(ULONG arg); +#else +void sendRecvTestTask(void *ept_number); +#endif + +// utility: initialize rpmsg and environment +// and wait for default channel +int32_t ts_init_rpmsg(void) +{ + env_init(); +#ifndef SH_MEM_NOT_TAKEN_FROM_LINKER + my_rpmsg = rpmsg_lite_remote_init(rpmsg_lite_base, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else +#if (defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) + my_rpmsg = rpmsg_lite_remote_init((void *)MEMORY_ConvertMemoryMapAddress((uint32_t)RPMSG_LITE_SHMEM_BASE, kMEMORY_DMA2Local), RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#else + my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &rpmsg_ctxt); +#endif +#endif /* SH_MEM_NOT_TAKEN_FROM_LINKER */ + TEST_ASSERT_MESSAGE(NULL != my_rpmsg, "init function failed"); + + ctrl_q = rpmsg_queue_create(my_rpmsg, &ctrl_queue_storage[0], &ctrl_queue_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_q, "'rpmsg_queue_create' failed"); + + ctrl_ept = rpmsg_lite_create_ept(my_rpmsg, TC_LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, ctrl_q, &ctrl_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != ctrl_ept, "'rpmsg_lite_create_ept' failed"); + + rpmsg_lite_wait_for_link_up(my_rpmsg, RL_BLOCK); + return 0; +} + +// utility: deinitialize rpmsg and environment +int32_t ts_deinit_rpmsg(void) +{ + rpmsg_lite_destroy_ept(my_rpmsg, ctrl_ept); + rpmsg_queue_destroy(my_rpmsg, ctrl_q); + rpmsg_lite_deinit(my_rpmsg); + my_rpmsg = NULL; + env_memset(&rpmsg_ctxt, 0, sizeof(struct rpmsg_lite_instance)); + return 0; +} +int32_t pattern_cmp(char *buffer, char pattern, int32_t len) +{ + for (int32_t i = 0; i < len; i++) + if (buffer[i] != pattern) + return -1; + return 0; +} + +/* + * Destroy an endpoint on the other side + */ +int32_t ts_destroy_ept(int32_t addr, struct rpmsg_lite_endpoint *ack_ept, rpmsg_queue_handle ack_q) +{ + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + int32_t ret_value; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM data_destroy_ept_param; + + data_destroy_ept_param.ept_to_ack_addr = ack_ept->addr; + data_destroy_ept_param.ept_to_destroy_addr = addr; + + msg.CMD = CTR_CMD_DESTROY_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_destroy_ept_param), sizeof(CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM)); + ret_value = rpmsg_lite_send(my_rpmsg, ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE(0 == ret_value, "error! failed to send CTR_CMD_DESTROY_EP command to other side"); + /* Receive respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, ack_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE(0 == ret_value, "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE(CTR_CMD_DESTROY_EP == ack_msg.CMD_ACK, + "error! expecting acknowledge of CTR_CMD_DESTROY_EP copmmand"); + TEST_ASSERT_MESSAGE(0 == ack_msg.RETURN_VALUE, "error! failed to destroy endpoints on other side"); + + return 0; +} + +/* + * Thread safety testing + */ +void tc_1_main_task(void) +{ + int32_t result, i; + initParamTypedef *initParam = NULL; + uint32_t src; + uint32_t recved; + char buf[32]; + CONTROL_MESSAGE msg = {0}; + + result = ts_init_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); + if (result == 0) + { + rpmsg_queue_recv(my_rpmsg, ctrl_q, &src, (char *)buf, 32, &recved, RL_BLOCK); + for (i = 0; i < WORKER_NUMBER; i++) + { +#if defined(SDK_OS_FREE_RTOS) + initParam = malloc(sizeof(initParamTypedef)); +#elif defined(FSL_RTOS_XOS) || defined(FSL_RTOS_THREADX) + initParam = env_allocate_memory(sizeof(initParamTypedef)); +#endif + TEST_ASSERT_MESSAGE(NULL != initParam, "Out of memory"); + initParam->worker_id = (uint8_t)i; + initParam->ack_q = rpmsg_queue_create(my_rpmsg, &initParam->ack_q_storage[0], &initParam->ack_q_ctxt); + TEST_ASSERT_MESSAGE(NULL != initParam->ack_q, "Out of memory"); + initParam->ack_ept = rpmsg_lite_create_ept(my_rpmsg, RL_ADDR_ANY, rpmsg_queue_rx_cb, initParam->ack_q, &initParam->ack_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != initParam->ack_ept, "Out of memory"); +#if defined(SDK_OS_FREE_RTOS) +#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + result = xTaskCreate(sendRecvTestTask, "THREAD_SAFETY_TASK", TEST_THREAD_SAFETY_TASK_STACK_SIZE, (void *)(initParam), tskIDLE_PRIORITY + 2, &initParam->test_thread_handle); + TEST_ASSERT_MESSAGE(pdPASS == result, "Could not create worker!"); +#else + initParam->task_stack_base = malloc(TEST_THREAD_SAFETY_TASK_STACK_SIZE * sizeof(StackType_t)); + TEST_ASSERT_MESSAGE(NULL != initParam->task_stack_base, "Out of memory"); + initParam->test_thread_handle = xTaskCreateStatic(sendRecvTestTask, "THREAD_SAFETY_TASK", TEST_THREAD_SAFETY_TASK_STACK_SIZE, (void *)(initParam), tskIDLE_PRIORITY + 2, initParam->task_stack_base, &initParam->xTaskBuffer); +#endif +#elif defined(FSL_RTOS_XOS) + initParam->task_stack_base = malloc(XOS_STACK_MIN_SIZE + 4*TEST_THREAD_SAFETY_TASK_STACK_SIZE); + TEST_ASSERT_MESSAGE(NULL != initParam->task_stack_base, "Out of memory"); + result = xos_thread_create(&initParam->test_thread_handle, NULL, (XosThreadFunc*)sendRecvTestTask, (void *)(initParam), "THREAD_SAFETY_TASK", initParam->task_stack_base, (uint32_t)(XOS_STACK_MIN_SIZE + 4*TEST_THREAD_SAFETY_TASK_STACK_SIZE), 6, 0, 0); + TEST_ASSERT_MESSAGE(XOS_OK == result, "Could not create worker!"); +#elif defined(FSL_RTOS_THREADX) + initParam->task_stack_base = env_allocate_memory(TEST_THREAD_SAFETY_TASK_STACK_SIZE * sizeof(ULONG)); + TEST_ASSERT_MESSAGE(NULL != initParam->task_stack_base, "Out of memory"); + result = tx_thread_create(&initParam->test_thread_handle, "THREAD_SAFETY_TASK", sendRecvTestTask, (ULONG)(initParam), (VOID *)initParam->task_stack_base, (TEST_THREAD_SAFETY_TASK_STACK_SIZE * sizeof(ULONG)), (TX_MAX_PRIORITIES - 2), (TX_MAX_PRIORITIES - 2), 1, TX_AUTO_START); + TEST_ASSERT_MESSAGE(TX_SUCCESS == result, "Could not create worker!"); +#endif + } + + globCntr = 0; + while (globCntr < WORKER_NUMBER) + { +#if defined(SDK_OS_FREE_RTOS) + vTaskDelay(100); +#elif defined(FSL_RTOS_XOS) + xos_thread_sleep_msec(1000); +#elif defined(FSL_RTOS_THREADX) + tx_thread_sleep(100); +#endif + } + + /* Send command to end to the other core to finish testing */ + msg.CMD = CTR_CMD_FINISH; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + rpmsg_lite_send(my_rpmsg, ctrl_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, sizeof(CONTROL_MESSAGE), RL_BLOCK); + } + result = ts_deinit_rpmsg(); + TEST_ASSERT_MESSAGE(0 == result, "negative number"); +} + +#if defined(FSL_RTOS_THREADX) +VOID sendRecvTestTask(ULONG initParam) +#else +void sendRecvTestTask(void *initParam) +#endif +{ + initParamTypedef *init = (initParamTypedef *)initParam; + TEST_ASSERT_MESSAGE(NULL != init, "Out of memory"); + CONTROL_MESSAGE msg = {0}; + ACKNOWLEDGE_MESSAGE ack_msg = {0}; + rpmsg_queue_handle sender_q = NULL; + rpmsg_static_queue_ctxt sender_queue_ctxt = {0}; + uint8_t sender_queue_storage[RL_ENV_QUEUE_STATIC_STORAGE_SIZE] = {0}; + struct rpmsg_lite_endpoint *sender_ept = NULL; + struct rpmsg_lite_ept_static_context sender_ept_ctxt = {0}; + uint32_t responder_ept_addr = -1; + uint32_t ept_address = TEST_EPT_NUM_BASE + init->worker_id; +#ifndef UNITY_NOT_PRINT_LOG + char worker_id_str[2] = {init->worker_id + 'a', '\0'}; +#endif + int32_t ret_value, i = 0, testing_count = 0; + uint32_t num_of_received_bytes = 0; + uint32_t src; + CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM data_create_ept_param; + CONTROL_MESSAGE_DATA_RECV_PARAM data_recv_param; + CONTROL_MESSAGE_DATA_SEND_PARAM data_send_param; + char recv_buffer[SENDER_APP_BUF_SIZE]; + + data_create_ept_param.ept_to_ack_addr = init->ack_ept->addr; + data_create_ept_param.ept_to_create_addr = ept_address; + + env_memcpy((void *)data_send_param.msg, "abc", (uint32_t)4); + data_send_param.ept_to_ack_addr = init->ack_ept->addr; + data_send_param.msg_size = CMD_SEND_MSG_SIZE; + data_send_param.repeat_count = 1; + data_send_param.mode = CMD_SEND_MODE_COPY; + + data_recv_param.ept_to_ack_addr = init->ack_ept->addr; + data_recv_param.buffer_size = RESPONDER_APP_BUF_SIZE; + data_recv_param.timeout_ms = RL_BLOCK; + data_recv_param.mode = CMD_RECV_MODE_COPY; + + /* Testing with blocking call and non-blocking call (timeout = 0) */ + for (testing_count = 0; testing_count < 16; testing_count++) + { + UnityPrint(worker_id_str); /* Print a dot, showing progress */ + + for (i = 0; i < TEST_CNT; i++) + { + /* + * Test receive function + * Sender sends a request to create endpoint on the other side + * Responder will receive the data from sender through this endpoint + */ + msg.CMD = CTR_CMD_CREATE_EP; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)(&data_create_ept_param), + sizeof(CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM)); + /* Send command to create endpoint to the other core */ + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, + sizeof(CONTROL_MESSAGE), RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), + "error! failed to send CTR_CMD_CREATE_EP command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, init->ack_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_CREATE_EP == ack_msg.CMD_ACK ? 1 : 0), + "error! expecting acknowledge of CTR_CMD_CREATE_EP copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : 0), "error! failed to create endpoint on other side"); + env_memcpy((void *)&responder_ept_addr, (void *)ack_msg.RESP_DATA, (uint32_t)(sizeof(uint32_t))); + data_recv_param.responder_ept_addr = responder_ept_addr; + + /* send CTR_CMD_RECV command to the other side */ + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, + sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to send CTR_CMD_RECV command to other side"); + + /* Send "aaa" string to other side */ + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, data_recv_param.responder_ept_addr, (char *)"aaa", 3, + RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to send 'aaa' string to other side"); + + /* Get respond from other core */ + ret_value = rpmsg_queue_recv(my_rpmsg, init->ack_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), + "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : 0), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((0 == ack_msg.RETURN_VALUE ? 1 : 0), + "error! failed when call rpmsg_rtos_recv function on the other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(ack_msg.RESP_DATA, "aaa", 3) ? 1 : 0), "error! incorrect data received"); + + /* + * Test send function + * Create a new endpoint on the sender side and sender will receive data through this endpoint + */ + sender_q = rpmsg_queue_create(my_rpmsg, &sender_queue_storage[0], &sender_queue_ctxt); + TEST_ASSERT_MESSAGE(NULL != sender_q, "error! failed to create queue"); + sender_ept = rpmsg_lite_create_ept(my_rpmsg, ept_address, rpmsg_queue_rx_cb, sender_q, &sender_ept_ctxt); + TEST_ASSERT_MESSAGE(NULL != sender_ept, "error! failed to create endpoint"); + + data_send_param.dest_addr = sender_ept->addr; + + msg.CMD = CTR_CMD_SEND; + msg.ACK_REQUIRED = ACK_REQUIRED_NO; + env_memcpy((void *)msg.DATA, (void *)&data_send_param, + (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_SEND_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, + sizeof(CONTROL_MESSAGE), RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to send CTR_CMD_SEND command to other side"); + + ret_value = rpmsg_queue_recv(my_rpmsg, sender_q, &src, (char *)recv_buffer, SENDER_APP_BUF_SIZE, + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to receive data from other side"); + TEST_ASSERT_MESSAGE((0 == strncmp(recv_buffer, "abc", 3) ? 1 : 0), "error! incorrect data received"); + + /* + * Destroy created endpoint on the sender side + */ + rpmsg_lite_destroy_ept(my_rpmsg, sender_ept); + rpmsg_queue_destroy(my_rpmsg, sender_q); + sender_q = NULL; + sender_ept = NULL; + + ts_destroy_ept(responder_ept_addr, init->ack_ept, init->ack_q); + } + + /* + * Attempt to call receive function on the other side with the invalid EP pointer (not yet created EP) + */ + data_recv_param.responder_ept_addr = -1; + msg.CMD = CTR_CMD_RECV; + msg.ACK_REQUIRED = ACK_REQUIRED_YES; + env_memcpy((void *)msg.DATA, (void *)&data_recv_param, (uint32_t)(sizeof(CONTROL_MESSAGE_DATA_RECV_PARAM))); + ret_value = rpmsg_lite_send(my_rpmsg, init->ack_ept, TC_REMOTE_EPT_ADDR, (char *)&msg, sizeof(CONTROL_MESSAGE), + RL_BLOCK); + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to send CTR_CMD_RECV command to other side"); + /* Get respond from other side */ + ret_value = rpmsg_queue_recv(my_rpmsg, init->ack_q, &src, (char *)&ack_msg, sizeof(ACKNOWLEDGE_MESSAGE), + &num_of_received_bytes, RL_BLOCK); + + TEST_ASSERT_MESSAGE((0 == ret_value ? 1 : 0), "error! failed to receive acknowledge message from other side"); + TEST_ASSERT_MESSAGE((CTR_CMD_RECV == ack_msg.CMD_ACK ? 1 : 0), + "error! expecting acknowledge of CTR_CMD_RECV copmmand"); + TEST_ASSERT_MESSAGE((ack_msg.RETURN_VALUE < 0 ? 1 : 0), + "error! failed when call rpmsg_rtos_recv function on the other side"); + } + globCntr++; + + rpmsg_lite_destroy_ept(my_rpmsg, init->ack_ept); + rpmsg_queue_destroy(my_rpmsg, init->ack_q); +#if defined(SDK_OS_FREE_RTOS) + free(init); + vTaskDelete(NULL); +#elif defined(FSL_RTOS_XOS) + free(init->task_stack_base); + free(init); + xos_thread_exit(0); +#elif defined(FSL_RTOS_THREADX) + env_free_memory(init->task_stack_base); + env_free_memory(init); + tx_thread_delete(&(init->test_thread_handle)); +#endif +} + +void run_tests(void *unused) +{ +#ifdef __COVERAGESCANNER__ + __coveragescanner_testname("05_thread_safety_rtos_sec_core"); + __coveragescanner_install("05_thread_safety_rtos_sec_core.csexe"); +#endif /*__COVERAGESCANNER__*/ + RUN_EXAMPLE(tc_1_main_task, MAKE_UNITY_NUM(k_unity_rpmsg, 0)); +} diff --git a/tests/05_thread_safety_rtos/pingpong_common.h b/tests/05_thread_safety_rtos/pingpong_common.h new file mode 100644 index 0000000..54fd299 --- /dev/null +++ b/tests/05_thread_safety_rtos/pingpong_common.h @@ -0,0 +1,109 @@ +/* + * Copyright 2016-2023 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __common_h__ +#define __common_h__ + +#define CTR_CMD_CREATE_EP (10) +#define CTR_CMD_DESTROY_EP (11) +#define CTR_CMD_SEND (12) +#define CTR_CMD_SEND_NO_COPY (13) +#define CTR_CMD_RECV (14) +#define CTR_CMD_CREATE_CHANNEL (15) +#define CTR_CMD_DESTROY_CHANNEL (16) +#define CTR_CMD_FINISH (17) + +/* recv command modes */ +#define CMD_RECV_MODE_COPY (1) +#define CMD_RECV_MODE_NOCOPY (2) + +/* send command modes */ +#define CMD_SEND_MODE_COPY (1) +#define CMD_SEND_MODE_NOCOPY (2) + +/* acknowledge required? */ +#define ACK_REQUIRED_YES (1) +#define ACK_REQUIRED_NO (0) + +#define INIT_EPT_ADDR (2) +#define TEST_CNT (10) +#define TC_EPT_COUNT (20) +#define RESPONDER_APP_BUF_SIZE (30) +#define SENDER_APP_BUF_SIZE (50) +#define CMD_SEND_MSG_SIZE (20) +#define BUFFER_MAX_LENGTH (32) + +#define CMD_RECV_TIMEOUT_MS (2000) + +#define DESTROY_ALL_EPT (0xFFFFFFFF) + +#define EP_SIGNATURE (('H' << 24) | ('D' << 16) | ('O' << 8) | ('D' << 0)) + +typedef struct control_message +{ + char CMD; + char ACK_REQUIRED; + char DATA[BUFFER_MAX_LENGTH]; +} CONTROL_MESSAGE, *CONTROL_MESSAGE_PTR; + +typedef struct acknowledge_message +{ + char CMD_ACK; + int32_t RETURN_VALUE; + int32_t TIMEOUT_MSEC; + char RESP_DATA[BUFFER_MAX_LENGTH]; +} ACKNOWLEDGE_MESSAGE, *ACKNOWLEDGE_MESSAGE_PTR; + +/* create endpoint data message format */ +typedef struct control_message_data_create_ept_param +{ + uint32_t ept_to_create_addr; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM, *CONTROL_MESSAGE_DATA_CREATE_EPT_PARAM_PTR; + +/* destroy endpoint data message format */ +typedef struct control_message_data_destroy_ept_param +{ + uint32_t ept_to_destroy_addr; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM, *CONTROL_MESSAGE_DATA_DESTROY_EPT_PARAM_PTR; + +/* create channel data message format */ +typedef struct control_message_data_create_channel_param +{ + char name[32]; + uint32_t ep_to_ack_addr; +} CONTROL_MESSAGE_DATA_CREATE_CHANNEL_PARAM, *CONTROL_MESSAGE_DATA_CREATE_CHANNEL_PARAM_PTR; + +/* delete channel data message format */ +typedef struct control_message_data_delete_channel_param +{ + char name[32]; + uint32_t ep_to_ack_addr; +} CONTROL_MESSAGE_DATA_DELETE_CHANNEL_PARAM, *CONTROL_MESSAGE_DATA_DELETE_CHANNEL_PARAM_PTR; + +/* send data message format */ +typedef struct control_message_data_send_param +{ + uint32_t dest_addr; + char msg[BUFFER_MAX_LENGTH - 20]; + int32_t msg_size; + uint32_t repeat_count; + uint32_t mode; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_SEND_PARAM, *CONTROL_MESSAGE_DATA_SEND_PARAM_PTR; + +/* receive data message format */ +typedef struct control_message_data_recv_param +{ + uint32_t responder_ept_addr; + int32_t buffer_size; + uint32_t timeout_ms; + uint32_t mode; + uint32_t ept_to_ack_addr; +} CONTROL_MESSAGE_DATA_RECV_PARAM, *CONTROL_MESSAGE_DATA_RECV_PARAM_PTR; + +#endif // __common_h__ diff --git a/tests/05_thread_safety_rtos/readme.txt b/tests/05_thread_safety_rtos/readme.txt new file mode 100644 index 0000000..63904f1 --- /dev/null +++ b/tests/05_thread_safety_rtos/readme.txt @@ -0,0 +1,5 @@ +05_thread_safety_rtos test suite + + - FreeRTOS/ThreadX/XOS-based project, covering both the static allocation (#define RL_USE_STATIC_API (1) in rpmsg_config.h) and the dynamic allocation (#define RL_USE_STATIC_API (0) in rpmsg_config.h) + + - Thread safety testing \ No newline at end of file diff --git a/tests/readme.md b/tests/readme.md new file mode 100644 index 0000000..2863c72 --- /dev/null +++ b/tests/readme.md @@ -0,0 +1,5 @@ +This directory and subdirectories contain RPMsg-Lite unit test source codes. +These are intended to be used in primary and secondary core projects of a dual core platform. +Tests are designed to cover all APIs and to reach the maximum code coverage. +The [Unity Test Project framework](https://github.com/ThrowTheSwitch/Unity) is utilized for tests management. + diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt new file mode 100644 index 0000000..7973bae --- /dev/null +++ b/zephyr/CMakeLists.txt @@ -0,0 +1,83 @@ +cmake_minimum_required (VERSION 3.5) + +if(CONFIG_RPMSGLITE) + set(ZEPHYR_BUILD 1) + set(ZEPHYR_BOARD ${CONFIG_BOARD}) + + set(RPMSGLITE_DIR ${ZEPHYR_CURRENT_MODULE_DIR}/lib) + + project (rpmsglite C) + + # Get MCUX_DEVICE and MCUX_DEVICE_PATH from CONFIG_SOC + # For example, if CONFIG_SOC=mimx8ml8_ca53, then MCUX_DEVICE=MIMX8ML8_ca53 + # and MCUX_DEVICE_PATH=MIMX8ML8 + string(FIND ${CONFIG_SOC} "_" pos) + if(pos GREATER -1) + string(REPLACE "_" ";" MCUX_DEVICE_TMP ${CONFIG_SOC}) + list(GET MCUX_DEVICE_TMP 0 MCUX_DEVICE_SOC) + list(GET MCUX_DEVICE_TMP 1 MCUX_DEVICE_CORE) + string(TOUPPER ${MCUX_DEVICE_SOC} MCUX_DEVICE_PATH) + set(MCUX_DEVICE ${MCUX_DEVICE_PATH}_${MCUX_DEVICE_CORE}) + else() + string(TOUPPER ${CONFIG_SOC} MCUX_DEVICE) + string(TOUPPER ${CONFIG_SOC} MCUX_DEVICE_PATH) + endif() + + # + # Select only supported platforms for RPMSG-Lite based on Zephyr selected SOC. + # + if(("${MCUX_DEVICE}" STREQUAL "LPC54114") OR ("${MCUX_DEVICE}" STREQUAL "LPC54114_m0")) + set(RPMSG_LITE_PLATFORM_PATH "lpc5411x") + elseif("${MCUX_DEVICE}" STREQUAL "LPC55S69_cpu0" OR "${MCUX_DEVICE}" STREQUAL "LPC55S69_cpu1") + set(RPMSG_LITE_PLATFORM_PATH "lpc55s69") + elseif("${MCUX_DEVICE}" STREQUAL "MIMXRT1176_cm4" OR "${MCUX_DEVICE}" STREQUAL "MIMXRT1176_cm7") + set(RPMSG_LITE_PLATFORM_PATH "imxrt1170") + elseif("${MCUX_DEVICE}" STREQUAL "MIMXRT1166_cm4" OR "${MCUX_DEVICE}" STREQUAL "MIMXRT1166_cm7") + set(RPMSG_LITE_PLATFORM_PATH "imxrt1160") + else() + message(FATAL_ERROR "RPMSG-Lite Selected for unsupported platform: ${CONFIG_SOC}") + endif() + + + set (RPMSGLITE_LIB rpmsg_lite) + + if (ZEPHYR_BUILD) + # + # Main RPMSG-Lite Sources + # + list(APPEND _SOURCES + ${RPMSGLITE_DIR}/common/llist.c + ${RPMSGLITE_DIR}/rpmsg_lite/rpmsg_lite.c + ${RPMSGLITE_DIR}/virtio/virtqueue.c + ) + + # + # Platform Specific RPMSG-Lite Sources + # + list(APPEND _SOURCES + ${RPMSGLITE_DIR}/rpmsg_lite/porting/platform/${RPMSG_LITE_PLATFORM_PATH}/rpmsg_platform_zephyr_ipm.c + ) + + # + # Environment Specific RPMSG-Lite Sources + # + list(APPEND _SOURCES + ${RPMSGLITE_DIR}/rpmsg_lite/porting/environment/rpmsg_env_zephyr.c + ) + + zephyr_library_named(${RPMSGLITE_LIB}) + add_dependencies(${ZEPHYR_CURRENT_LIBRARY} ${OFFSETS_H_TARGET}) + zephyr_library_sources(${_SOURCES}) + zephyr_include_directories( + ${RPMSGLITE_DIR}/include/platform/${RPMSG_LITE_PLATFORM_PATH} + ${RPMSGLITE_DIR}/include/environment/zephyr + ${RPMSGLITE_DIR}/include + ) + + zephyr_library_sources_ifdef(CONFIG_RPMSGLITE_QUEUE ${RPMSGLITE_DIR}/rpmsg_lite/rpmsg_queue.c) + zephyr_library_sources_ifdef(CONFIG_RPMSGLITE_NS ${RPMSGLITE_DIR}/rpmsg_lite/rpmsg_ns.c) + + else(ZEPHYR_BUILD) + # other way from MCUXSDK? + endif (ZEPHYR_BUILD) +endif(CONFIG_RPMSGLITE) diff --git a/zephyr/Kconfig b/zephyr/Kconfig new file mode 100644 index 0000000..3dc046c --- /dev/null +++ b/zephyr/Kconfig @@ -0,0 +1,39 @@ +# +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +config ZEPHYR_RPMSG_LITE_MODULE + bool + +config RPMSGLITE + bool "RPMSG-Lite Support" + depends on ZEPHYR_RPMSG_LITE_MODULE + help + This option enables the RPMSG-Lite library + +config ZEPHYR_BUILD + bool + +if RPMSGLITE + +config ZEPHYR_BUILD + default y + depends on RPMSGLITE + +config RPMSGLITE_QUEUE + bool "RPMSG-Lite Queue" + default n + depends on RPMSGLITE + help + This option enables RPMSG-Lite Queue support. + +config RPMSGLITE_NS + bool "RPMSG-Lite Name Service" + default n + depends on RPMSGLITE + help + This option enables RPMSG-Lite Name Service support. + +endif # RPMSGLITE diff --git a/zephyr/README.md b/zephyr/README.md new file mode 100644 index 0000000..fd98871 --- /dev/null +++ b/zephyr/README.md @@ -0,0 +1,80 @@ +# RPMSG-Lite Zephyr support + +## Adding RPMSG-Lite to Zephyr as module + +To include RPMSG-Lite Zephyr, update Zephyr's west.yml: + +``` yml + projects: + - name: rpmsg-lite + revision: + url: + path: modules/lib/rpmsg-lite +``` +Then run: +``` sh +west update rpmsg-lite +``` + +## Supported Platforms + +The RPSMG-Lite is currently supported on these platforms: + + * lpc5411x + * lpc55s69 + * imxrt1170 + * imxrt1160 + +To support other platform please create new platform specific file `rpmsg_platform_zephyr_ipm.c` in +directory **`rpmsg-lite/lib/rpmsg_lite/porting/platform/`** and add new entry in file `rpmsg-lite/zephyr/CMakeLists.txt`. +```cmake + if(("${MCUX_DEVICE}" STREQUAL "LPC54114") OR ("${MCUX_DEVICE}" STREQUAL "LPC54114_m0")) + set(RPMSG_LITE_PLATFORM_PATH "lpc5411x") + ... + ... + elseif("${MCUX_DEVICE}" STREQUAL "MIMXRT1176_cm4" OR "${MCUX_DEVICE}" STREQUAL "MIMXRT1176_cm7") + set(RPMSG_LITE_PLATFORM_PATH "imxrt1170") +``` +Also update samples with board/platform specific configs or DT overlays in: `rpmsg-lite/zephyr/samples//boards` and +`rpmsg-lite/zephyr/samples//remote/boards` + +## RPMSG-Lite module files + +- *rpmsg-lite/zephyr/* - This directory holds all files required for Zephyr module +- *rpmsg-lite/zephyr/module.yml* - This file defines module name and Cmake and Kconfig location +- *rpmsg-lite/zephyr/CMakeList.txt* - Defines module's includes and source files base on Kconfig +- *rpmsg-lite/zephyr/Kconfig* - Defines RPMSG-Lite module configuration + +### Kconfig + +Kconfig options: + +- **CONFIG_RPMSGLITE** - enable RPMSG-Lite support +- **CONFIG_RPMSGLITE_QUEUE** - enable RPMSG-Lite Queue support +- **CONFIG_RPMSGLITE_QUEUE** - enable RPMSG-Lite Name Service support + +### RPMSG-Lite User/Project Configuration + +The RPMSG-Lite Library can be further configured by `rpmsg_config.h` header file. + +This header file needs to be included per application project. + +File can be found in `rpmsg-lite/zephyr/samples/rpmsglite_pingpong/rpmsg_config.h`. + +User can copy and update this config file. + +### CMakeList + +CMakeLists.txt defines RPSMG-Lite as Zephyr library. Includes all required directories and source files for Zephyr environment. + +## Samples + +Samples are located in *zephyr/samples*. Examples can be build by west tool: + +### RPMSG-Lite Ping Pong Example + +```sh +cd path/to/zephyrproject +west build --sysbuild -b modules/lib/rpmsg-lite/zephyr/samples/rpmsglite_pingpong/ -p +west flash +``` diff --git a/zephyr/module.yml b/zephyr/module.yml new file mode 100644 index 0000000..cd640e4 --- /dev/null +++ b/zephyr/module.yml @@ -0,0 +1,8 @@ +name: rpmsg-lite +build: + cmake: ./zephyr/ + kconfig: ./zephyr/Kconfig +samples: + - ./zephyr/samples +tests: + - ./zephyr/tests diff --git a/zephyr/samples/rpmsglite_pingpong/CMakeLists.txt b/zephyr/samples/rpmsglite_pingpong/CMakeLists.txt new file mode 100644 index 0000000..74970dd --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.20.0) + +set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/../rpmsglite_remote/zephyr) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(rpmsglite_pingpong) + +message(STATUS "${BOARD} compile as Main Core in this sample") + +if(CONFIG_INCLUDE_REMOTE_DIR) + target_include_directories(zephyr_interface + INTERFACE ${REMOTE_ZEPHYR_DIR}/include/public) +endif() + +enable_language(C ASM) + +target_sources(app PRIVATE src/main.c) + +target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +# Also include this directory into rpmsg_lite library because of project specific include rpsmg_config.h +target_include_directories(rpmsg_lite PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/zephyr/samples/rpmsglite_pingpong/Kconfig b/zephyr/samples/rpmsglite_pingpong/Kconfig new file mode 100644 index 0000000..3837c49 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/Kconfig @@ -0,0 +1,11 @@ +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "Kconfig.zephyr" + +config INCLUDE_REMOTE_DIR + bool "Include remote core header directory" + help + Include remote build header files. Can be used if primary image + needs to be aware of size or base address of secondary image diff --git a/zephyr/samples/rpmsglite_pingpong/Kconfig.sysbuild b/zephyr/samples/rpmsglite_pingpong/Kconfig.sysbuild new file mode 100644 index 0000000..8ba4595 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/Kconfig.sysbuild @@ -0,0 +1,13 @@ +# Copyright 2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +source "share/sysbuild/Kconfig" + +config RPMSG_LITE_REMOTE_BOARD +string + default "lpcxpresso54114_m0" if $(BOARD) = "lpcxpresso54114_m4" + default "lpcxpresso55s69_cpu1" if $(BOARD) = "lpcxpresso55s69_cpu0" + default "mimxrt1170_evk_cm4" if $(BOARD) = "mimxrt1170_evk_cm7" + default "mimxrt1160_evk_cm4" if $(BOARD) = "mimxrt1160_evk_cm7" + default "mimxrt1170_evkb_cm4" if $(BOARD) = "mimxrt1170_evkb_cm7" diff --git a/zephyr/samples/rpmsglite_pingpong/README.rst b/zephyr/samples/rpmsglite_pingpong/README.rst new file mode 100644 index 0000000..f3bbbb8 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/README.rst @@ -0,0 +1,97 @@ +.. _rpmsglite_pingpong: + +RPMSG-Lite Ping Pong +########### + +Overview +******** + +The Multicore RPMsg-Lite pingpong sample that can be used with: :ref:`supported board `. + +The Multicore RPMsg-Lite pingpong project is a simple demonstration program that uses the +Zephyr OS and the RPMsg-Lite library and shows how to implement the inter-core +communicaton between cores of the multicore system. The primary core releases the secondary core +from the reset and then the inter-core communication is established. Once the RPMsg is initialized +and endpoints are created the message exchange starts, incrementing a virtual counter that is part +of the message payload. The message pingpong finishes when the counter reaches the value of 100. +Then the RPMsg-Lite is deinitialized and the procedure of the data exchange is repeated again. + +Building and Running +******************** + +This application can be built and executed on Supported Multi Core boards as follows: + +Building the application for lpcxpresso54114_m4 +*********************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/rpmsglite_pingpong + :board: lpcxpresso54114_m4 + :goals: debug + :west-args: --sysbuild + +Building the application for lpcxpresso55s69_cpu0 +************************************************* + +.. zephyr-app-commands:: + :zephyr-app: samples/rpmsglite_pingpong + :board: lpcxpresso55s69_cpu0 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1160_evk_cm7 +*********************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/rpmsglite_pingpong + :board: mimxrt1160_evk_cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1170_evk_cm7 +*********************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/rpmsglite_pingpong + :board: mimxrt1170_evk_cm7 + :goals: debug + :west-args: --sysbuild + +Building the application for mimxrt1170_evkb_cm7 +*********************************************** + +.. zephyr-app-commands:: + :zephyr-app: samples/rpmsglite_pingpong + :board: mimxrt1170_evkb_cm7 + :goals: debug + :west-args: --sysbuild + +Sample Output +============= + +Open a serial terminal (minicom, putty, etc.) and connect the board with the +following settings: + +- Speed: 115200 +- Data: 8 bits +- Parity: None +- Stop bits: 1 + +Reset the board and the following message will appear on the corresponding +serial port, one is master another is remote: + +.. code-block:: console + + *** Booting Zephyr OS build zephyr-v3.5.0-2239-ga51bd53cef2b *** + Starting application thread on Main Core! + Primary core received a msg + Message: Size=4, DATA = 1 + Primary core received a msg + Message: Size=4, DATA = 3 + ... + Primary core received a msg + Message: Size=4, DATA = 99 + Primary core received a msg + Message: Size=4, DATA = 101 + + RPMsg demo ends diff --git a/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso54114_m4.conf b/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso54114_m4.conf new file mode 100644 index 0000000..60eead5 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso54114_m4.conf @@ -0,0 +1,2 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_INCLUDE_REMOTE_DIR=y diff --git a/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso54114_m4.overlay b/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso54114_m4.overlay new file mode 100644 index 0000000..e061dcc --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso54114_m4.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2019 Linaro Limited + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* + * shared memory reserved for the inter-processor communication + */ + zephyr,ipc_shm = &sramx1; + zephyr,ipc = &mailbox0; + }; + + sramx1:memory@4000000{ + compatible = "mmio-sram"; + reg = <0x4000000 0x8000>; + }; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso55s69_cpu0.conf b/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso55s69_cpu0.conf new file mode 100644 index 0000000..7e6904d --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso55s69_cpu0.conf @@ -0,0 +1 @@ +CONFIG_SECOND_CORE_MCUX=y diff --git a/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso55s69_cpu0.overlay b/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso55s69_cpu0.overlay new file mode 100644 index 0000000..270eb0e --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/lpcxpresso55s69_cpu0.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019 Linaro Limited + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* + * shared memory reserved for the inter-processor communication + */ + + zephyr,ipc_shm = &sram4duplicate; + zephyr,ipc = &mailbox0; + }; + + /* This is a duplication of sram4, workaround */ + sram4duplicate: memory@20040000 { + compatible = "mmio-sram"; + reg = <0x20040000 DT_SIZE_K(16)>; + }; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1160_evk_cm7.conf b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1160_evk_cm7.conf new file mode 100644 index 0000000..630a193 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1160_evk_cm7.conf @@ -0,0 +1,2 @@ +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1160_evk_cm7.overlay b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1160_evk_cm7.overlay new file mode 100644 index 0000000..c4a5c56 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1160_evk_cm7.overlay @@ -0,0 +1,24 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + chosen { + zephyr,ipc_shm = &ocram2_overlay; + }; + + /* OpenAMP fails with full 512K OCRAM2 memory region as shared memory. + * Define a subset of the OCRAM2 region for demo to use + * Note that shared memory must have specific MPU attributes set + */ + ocram2_overlay: memory@202c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_OVERLAY"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evk_cm7.conf b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evk_cm7.conf new file mode 100644 index 0000000..630a193 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evk_cm7.conf @@ -0,0 +1,2 @@ +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evk_cm7.overlay b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evk_cm7.overlay new file mode 100644 index 0000000..c4a5c56 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evk_cm7.overlay @@ -0,0 +1,24 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + chosen { + zephyr,ipc_shm = &ocram2_overlay; + }; + + /* OpenAMP fails with full 512K OCRAM2 memory region as shared memory. + * Define a subset of the OCRAM2 region for demo to use + * Note that shared memory must have specific MPU attributes set + */ + ocram2_overlay: memory@202c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_OVERLAY"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evkb_cm7.conf b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evkb_cm7.conf new file mode 100644 index 0000000..630a193 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evkb_cm7.conf @@ -0,0 +1,2 @@ +CONFIG_INCLUDE_REMOTE_DIR=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evkb_cm7.overlay b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evkb_cm7.overlay new file mode 100644 index 0000000..c4a5c56 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/boards/mimxrt1170_evkb_cm7.overlay @@ -0,0 +1,24 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + chosen { + zephyr,ipc_shm = &ocram2_overlay; + }; + + /* OpenAMP fails with full 512K OCRAM2 memory region as shared memory. + * Define a subset of the OCRAM2 region for demo to use + * Note that shared memory must have specific MPU attributes set + */ + ocram2_overlay: memory@202c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_OVERLAY"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/common.h b/zephyr/samples/rpmsglite_pingpong/common.h new file mode 100644 index 0000000..7fbaa45 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/common.h @@ -0,0 +1,18 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef RPMSG_LITE_COMMON_H_ +#define RPMSG_LITE_COMMON_H_ + +/* + * Define here hardcoded to `0`. As all supported boards start with the link_id 0. + * In case application specific change is required please refer to bellow. + * + * Link ID used to define the rpmsg-lite instance, see rpmsg-lite/lib/include//rpmsg_platform.h + */ +#define RPMSG_LITE_LINK_ID (0) + +#endif /* RPMSG_LITE_COMMON_H_ */ diff --git a/zephyr/samples/rpmsglite_pingpong/prj.conf b/zephyr/samples/rpmsglite_pingpong/prj.conf new file mode 100644 index 0000000..3527774 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/prj.conf @@ -0,0 +1,13 @@ +CONFIG_IPM=y +CONFIG_EVENTS=y +CONFIG_PRINTK=y +CONFIG_RPMSGLITE=y +CONFIG_TIMESLICE_SIZE=1 +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_HEAP_MEM_POOL_SIZE=4096 + +# Uncomment for Debugging Support +# CONFIG_INIT_STACKS=y +# CONFIG_NO_OPTIMIZATIONS=y +# CONFIG_DEBUG_THREAD_INFO=y +# CONFIG_THREAD_STACK_INFO=y diff --git a/zephyr/samples/rpmsglite_pingpong/remote/CMakeLists.txt b/zephyr/samples/rpmsglite_pingpong/remote/CMakeLists.txt new file mode 100644 index 0000000..a4028f5 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(rpmsglite_remote) +message(STATUS "${BOARD} compiles as Remote Core in this sample") + +target_sources(app PRIVATE src/main.c) +target_include_directories(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) + +# Also include this directory into rpmsg_lite library because of project specific include rpsmg_config.h +target_include_directories(rpmsg_lite PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso54114_m0.conf b/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso54114_m0.conf new file mode 100644 index 0000000..b9e2b07 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso54114_m0.conf @@ -0,0 +1,2 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso54114_m0.overlay b/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso54114_m0.overlay new file mode 100644 index 0000000..e061dcc --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso54114_m0.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2019 Linaro Limited + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* + * shared memory reserved for the inter-processor communication + */ + zephyr,ipc_shm = &sramx1; + zephyr,ipc = &mailbox0; + }; + + sramx1:memory@4000000{ + compatible = "mmio-sram"; + reg = <0x4000000 0x8000>; + }; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso55s69_cpu1.conf b/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso55s69_cpu1.conf new file mode 100644 index 0000000..b9e2b07 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso55s69_cpu1.conf @@ -0,0 +1,2 @@ +CONFIG_SECOND_CORE_MCUX=y +CONFIG_BUILD_OUTPUT_HEX=y diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso55s69_cpu1.overlay b/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso55s69_cpu1.overlay new file mode 100644 index 0000000..270eb0e --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/lpcxpresso55s69_cpu1.overlay @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019 Linaro Limited + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + chosen { + /* + * shared memory reserved for the inter-processor communication + */ + + zephyr,ipc_shm = &sram4duplicate; + zephyr,ipc = &mailbox0; + }; + + /* This is a duplication of sram4, workaround */ + sram4duplicate: memory@20040000 { + compatible = "mmio-sram"; + reg = <0x20040000 DT_SIZE_K(16)>; + }; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1160_evk_cm4.conf b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1160_evk_cm4.conf new file mode 100644 index 0000000..4dfc4a6 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1160_evk_cm4.conf @@ -0,0 +1,3 @@ +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1160_evk_cm4.overlay b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1160_evk_cm4.overlay new file mode 100644 index 0000000..83589d7 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1160_evk_cm4.overlay @@ -0,0 +1,51 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + /* Switch to lpuart2, since primary core uses lpuart1 */ + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + zephyr,ipc_shm = &ocram2_overlay; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + }; + + /* OpenAMP fails with full 512K OCRAM2 memory region as shared memory. + * Define a subset of the OCRAM2 region for demo to use + * Note that shared memory must have specific MPU attributes set + */ + ocram2_overlay: memory@202c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_OVERLAY"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evk_cm4.conf b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evk_cm4.conf new file mode 100644 index 0000000..4dfc4a6 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evk_cm4.conf @@ -0,0 +1,3 @@ +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evk_cm4.overlay b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evk_cm4.overlay new file mode 100644 index 0000000..83589d7 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evk_cm4.overlay @@ -0,0 +1,51 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + /* Switch to lpuart2, since primary core uses lpuart1 */ + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart2; + zephyr,shell-uart = &lpuart2; + zephyr,ipc_shm = &ocram2_overlay; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + }; + + /* OpenAMP fails with full 512K OCRAM2 memory region as shared memory. + * Define a subset of the OCRAM2 region for demo to use + * Note that shared memory must have specific MPU attributes set + */ + ocram2_overlay: memory@202c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_OVERLAY"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evkb_cm4.conf b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evkb_cm4.conf new file mode 100644 index 0000000..4dfc4a6 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evkb_cm4.conf @@ -0,0 +1,3 @@ +CONFIG_BUILD_OUTPUT_INFO_HEADER=y +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_SECOND_CORE_MCUX=y diff --git a/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evkb_cm4.overlay b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evkb_cm4.overlay new file mode 100644 index 0000000..b9c0439 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/boards/mimxrt1170_evkb_cm4.overlay @@ -0,0 +1,51 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + /* Switch to lpuart2, since primary core uses lpuart1 */ + chosen { + zephyr,flash = &ocram; + zephyr,console = &lpuart1; + zephyr,shell-uart = &lpuart1; + zephyr,ipc_shm = &ocram2_overlay; + }; + + soc { + /delete-node/ gpt@400f0000; + + /* Replace GPT2 with another GPT kernel timer */ + gpt2_hw_timer:gpt@400f0000 { + compatible = "nxp,gpt-hw-timer"; + reg = <0x400f0000 0x4000>; + interrupts = <120 0>; + status = "okay"; + }; + }; + + /* OpenAMP fails with full 512K OCRAM2 memory region as shared memory. + * Define a subset of the OCRAM2 region for demo to use + * Note that shared memory must have specific MPU attributes set + */ + ocram2_overlay: memory@202c0000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x202c0000 DT_SIZE_K(16)>; + zephyr,memory-region="OCRAM2_OVERLAY"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_IO) )>; + }; +}; + +/* Enable secondary LPUART */ +&lpuart2 { + status = "okay"; + current-speed = <115200>; +}; + +/* Disable primary GPT timer */ +&gpt_hw_timer { + status = "disabled"; +}; diff --git a/zephyr/samples/rpmsglite_pingpong/remote/prj.conf b/zephyr/samples/rpmsglite_pingpong/remote/prj.conf new file mode 100644 index 0000000..30d0038 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/prj.conf @@ -0,0 +1,15 @@ +CONFIG_IPM=y +CONFIG_EVENTS=y +CONFIG_PRINTK=y +CONFIG_RPMSGLITE=y +CONFIG_STDOUT_CONSOLE=n +CONFIG_TIMESLICE_SIZE=1 +CONFIG_HEAP_MEM_POOL_SIZE=4096 +CONFIG_PLATFORM_SPECIFIC_INIT=n +CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096 + +# Uncomment for Debugging Support +# CONFIG_INIT_STACKS=y +# CONFIG_NO_OPTIMIZATIONS=y +# CONFIG_DEBUG_THREAD_INFO=y +# CONFIG_THREAD_STACK_INFO=y diff --git a/zephyr/samples/rpmsglite_pingpong/remote/sample.yaml b/zephyr/samples/rpmsglite_pingpong/remote/sample.yaml new file mode 100644 index 0000000..218da1b --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/sample.yaml @@ -0,0 +1,15 @@ +sample: + description: RPMSG-Lite Ping Pong sample + name: rpmsglite pingpong (remote) +tests: + sample.ipc.rpmsglite_pingpong.remote: + platform_allow: + - lpcxpresso54114_m4 + - lpcxpresso55s69_cpu0 + - mimxrt1160_evk_cm7 + - mimxrt1170_evk_cm7 + - mimxrt1170_evkb_cm7 + integration_platforms: + - mimxrt1170_evk_cm7 + tags: ipm + harness: remote diff --git a/zephyr/samples/rpmsglite_pingpong/remote/src/main.c b/zephyr/samples/rpmsglite_pingpong/remote/src/main.c new file mode 100644 index 0000000..878cac0 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/remote/src/main.c @@ -0,0 +1,96 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "rpmsg_lite.h" + +#define LOCAL_EPT_ADDR (30U) +#define APP_RPMSG_READY_EVENT_DATA (1U) +#define APP_RPMSG_EP_READY_EVENT_DATA (2U) + +#define SHM_MEM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ipc_shm)) +#define SHM_MEM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ipc_shm)) + +#define APP_THREAD_STACK_SIZE (1024) +K_THREAD_STACK_DEFINE(thread_stack, APP_THREAD_STACK_SIZE); +static struct k_thread thread_data; + +struct rpmsg_lite_instance *gp_rpmsg_dev_inst; +struct rpmsg_lite_endpoint *gp_rpmsg_ept; +struct rpmsg_lite_instance g_rpmsg_ctxt; +struct rpmsg_lite_ept_static_context g_ept_context; +volatile int32_t g_has_received; + +uint32_t *shared_memory = (uint32_t *)SHM_MEM_ADDR; + +typedef struct the_message +{ + uint32_t DATA; +} THE_MESSAGE, *THE_MESSAGE_PTR; + +static THE_MESSAGE volatile g_msg = {0}; +static uint32_t g_remote_addr = 0; + +/* Internal functions */ +static int32_t rpmsg_ept_read_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) +{ + int32_t *has_received = priv; + + if (payload_len <= sizeof(THE_MESSAGE)) + { + (void)memcpy((void *)&g_msg, payload, payload_len); + g_remote_addr = src; + *has_received = 1; + } + return RL_RELEASE; +} + +static void application_thread(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + gp_rpmsg_dev_inst = rpmsg_lite_remote_init(shared_memory, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &g_rpmsg_ctxt); + + rpmsg_lite_wait_for_link_up(gp_rpmsg_dev_inst, 600000); + + gp_rpmsg_ept = rpmsg_lite_create_ept(gp_rpmsg_dev_inst, LOCAL_EPT_ADDR, rpmsg_ept_read_cb, (void *)&g_has_received, + &g_ept_context); + + while (g_msg.DATA <= 100U) + { + if (1 == g_has_received) + { + g_has_received = 0; + g_msg.DATA++; + (void)rpmsg_lite_send(gp_rpmsg_dev_inst, gp_rpmsg_ept, g_remote_addr, (char *)&g_msg, sizeof(THE_MESSAGE), + RL_DONT_BLOCK); + } + } + + (void)rpmsg_lite_destroy_ept(gp_rpmsg_dev_inst, gp_rpmsg_ept); + gp_rpmsg_ept = ((void *)0); + (void)rpmsg_lite_deinit(gp_rpmsg_dev_inst); + g_msg.DATA = 0U; +} + +int main(void) +{ + printk("Starting application thread on Remote Core!\n"); + k_thread_create(&thread_data, thread_stack, APP_THREAD_STACK_SIZE, application_thread, NULL, NULL, NULL, + K_PRIO_COOP(7), 0, K_NO_WAIT); + + return 0; +} diff --git a/zephyr/samples/rpmsglite_pingpong/rpmsg_config.h b/zephyr/samples/rpmsglite_pingpong/rpmsg_config.h new file mode 100644 index 0000000..e5bf2b1 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/rpmsg_config.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, Mentor Graphics Corporation + * Copyright (c) 2015 Xilinx, Inc. + * Copyright (c) 2016 Freescale Semiconductor, Inc. + * Copyright 2016-2023 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RPMSG_CONFIG_H_ +#define RPMSG_CONFIG_H_ + +/*! + * @addtogroup config + * @{ + * @file + */ + +//! @name Configuration options +//@{ + +//! @def RL_MS_PER_INTERVAL +//! +//! Delay in milliseconds used in non-blocking API functions for polling. +//! The default value is 1. +#define RL_MS_PER_INTERVAL (1) + +//! @def RL_BUFFER_PAYLOAD_SIZE +//! +//! Size of the buffer payload, it must be equal to (240, 496, 1008, ...) +//! [2^n - 16]. Ensure the same value is defined on both sides of rpmsg +//! communication. The default value is 496U. +#define RL_BUFFER_PAYLOAD_SIZE (496U) + +//! @def RL_BUFFER_COUNT +//! +//! Number of the buffers, it must be power of two (2, 4, ...). +//! The default value is 2U. +//! Note this value defines the buffer count for one direction of the rpmsg +//! communication only, i.e. if the default value of 2 is used +//! in rpmsg_config.h files for the master and the remote side, 4 buffers +//! in total are created in the shared memory. +#define RL_BUFFER_COUNT (2U) + +//! @def RL_API_HAS_ZEROCOPY +//! +//! Zero-copy API functions enabled/disabled. +//! The default value is 1 (enabled). +#define RL_API_HAS_ZEROCOPY (1) + +//! @def RL_USE_STATIC_API +//! +//! Static API functions (no dynamic allocation) enabled/disabled. +//! The default value is 0 (static API disabled). +#define RL_USE_STATIC_API (1) + +//! @def RL_CLEAR_USED_BUFFERS +//! +//! Clearing used buffers before returning back to the pool of free buffers +//! enabled/disabled. +//! The default value is 0 (disabled). +#define RL_CLEAR_USED_BUFFERS (0) + +//! @def RL_USE_MCMGR_IPC_ISR_HANDLER +//! +//! When enabled IPC interrupts are managed by the Multicore Manager (IPC +//! interrupts router), when disabled RPMsg-Lite manages IPC interrupts +//! by itself. +//! The default value is 0 (no MCMGR IPC ISR handler used). +#define RL_USE_MCMGR_IPC_ISR_HANDLER (0) + +//! @def RL_USE_ENVIRONMENT_CONTEXT +//! +//! When enabled the environment layer uses its own context. +//! Added for QNX port mainly, but can be used if required. +//! The default value is 0 (no context, saves some RAM). +#define RL_USE_ENVIRONMENT_CONTEXT (0) + +//! @def RL_DEBUG_CHECK_BUFFERS +//! +//! Do not use in RPMsg-Lite to Linux configuration +#define RL_DEBUG_CHECK_BUFFERS (0) +//@} + +#endif /* RPMSG_CONFIG_H_ */ diff --git a/zephyr/samples/rpmsglite_pingpong/sample.yaml b/zephyr/samples/rpmsglite_pingpong/sample.yaml new file mode 100644 index 0000000..0389247 --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/sample.yaml @@ -0,0 +1,24 @@ +sample: + description: RPMSG-Lite Ping Pong sample + name: rpmsglite pingpong +tests: + sample.ipc.rpmsglite_pingpong: + platform_allow: + - lpcxpresso54114_m4 + - lpcxpresso55s69_cpu0 + - mimxrt1160_evk_cm7 + - mimxrt1170_evk_cm7 + - mimxrt1170_evkb_cm7 + integration_platforms: + - mimxrt1170_evk_cm7 + tags: ipm + harness: console + sysbuild: true + harness_config: + type: multi_line + regex: + - "Primary core received a msg" + - "Message: Size=4, DATA = 1" + - "Primary core received a msg" + - "Message: Size=4, DATA = 101" + - "RPMsg demo ends" diff --git a/zephyr/samples/rpmsglite_pingpong/src/main.c b/zephyr/samples/rpmsglite_pingpong/src/main.c new file mode 100644 index 0000000..a5065df --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/src/main.c @@ -0,0 +1,109 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "rpmsg_lite.h" + +#define REMOTE_EPT_ADDR (30U) +#define LOCAL_EPT_ADDR (40U) +#define APP_RPMSG_READY_EVENT_DATA (1U) +#define APP_RPMSG_EP_READY_EVENT_DATA (2U) + +#define SHM_MEM_ADDR DT_REG_ADDR(DT_CHOSEN(zephyr_ipc_shm)) +#define SHM_MEM_SIZE DT_REG_SIZE(DT_CHOSEN(zephyr_ipc_shm)) + +#define APP_THREAD_STACK_SIZE (1024) +K_THREAD_STACK_DEFINE(thread_stack, APP_THREAD_STACK_SIZE); +static struct k_thread thread_data; + +struct rpmsg_lite_instance *gp_rpmsg_dev_inst; +struct rpmsg_lite_endpoint *gp_rpmsg_ept; +struct rpmsg_lite_instance g_rpmsg_ctxt; +struct rpmsg_lite_ept_static_context g_ept_context; +volatile int32_t g_has_received; + +uint32_t *shared_memory = (uint32_t *)SHM_MEM_ADDR; + +K_EVENT_DEFINE(wait_event); + +typedef struct the_message +{ + uint32_t DATA; +} THE_MESSAGE, *THE_MESSAGE_PTR; + +static THE_MESSAGE volatile g_msg = {0}; + +/* This is the read callback, note we are in a task context when this callback +is invoked, so kernel primitives can be used freely */ +static int32_t rpmsg_ept_read_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv) +{ + int32_t *has_received = priv; + + if (payload_len <= sizeof(THE_MESSAGE)) + { + (void)memcpy((void *)&g_msg, payload, payload_len); + *has_received = 1; + } + (void)printk("Primary core received a msg\r\n"); + (void)printk("Message: Size=%x, DATA = %i\r\n", payload_len, g_msg.DATA); + return RL_RELEASE; +} + +static void application_thread(void *arg1, void *arg2, void *arg3) +{ + ARG_UNUSED(arg1); + ARG_UNUSED(arg2); + ARG_UNUSED(arg3); + + gp_rpmsg_dev_inst = + rpmsg_lite_master_init(shared_memory, SHM_MEM_SIZE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS, &g_rpmsg_ctxt); + + gp_rpmsg_ept = rpmsg_lite_create_ept(gp_rpmsg_dev_inst, LOCAL_EPT_ADDR, rpmsg_ept_read_cb, (void *)&g_has_received, + &g_ept_context); + + /* Temporary wait a bit here until remote core will process initialization and is ready to receive data */ + (void)k_event_wait_all(&wait_event, 5, false, K_MSEC(20)); + + /* Send the first message to the remoteproc */ + g_msg.DATA = 0U; + (void)rpmsg_lite_send(gp_rpmsg_dev_inst, gp_rpmsg_ept, REMOTE_EPT_ADDR, (char *)&g_msg, sizeof(THE_MESSAGE), + RL_DONT_BLOCK); + + while (g_msg.DATA <= 100U) + { + if (1 == g_has_received) + { + g_has_received = 0; + g_msg.DATA++; + (void)rpmsg_lite_send(gp_rpmsg_dev_inst, gp_rpmsg_ept, REMOTE_EPT_ADDR, (char *)&g_msg, sizeof(THE_MESSAGE), + RL_DONT_BLOCK); + } + } + + (void)rpmsg_lite_destroy_ept(gp_rpmsg_dev_inst, gp_rpmsg_ept); + gp_rpmsg_ept = ((void *)0); + (void)rpmsg_lite_deinit(gp_rpmsg_dev_inst); + + /* Print the ending banner */ + (void)printk("\r\nRPMsg demo ends\r\n"); +} + +int main(void) +{ + printk("Starting application thread on Main Core!\n"); + k_thread_create(&thread_data, thread_stack, APP_THREAD_STACK_SIZE, application_thread, NULL, NULL, NULL, + K_PRIO_COOP(7), 0, K_NO_WAIT); + + return 0; +} diff --git a/zephyr/samples/rpmsglite_pingpong/sysbuild.cmake b/zephyr/samples/rpmsglite_pingpong/sysbuild.cmake new file mode 100644 index 0000000..71bbafd --- /dev/null +++ b/zephyr/samples/rpmsglite_pingpong/sysbuild.cmake @@ -0,0 +1,21 @@ +# Copyright 2022-2023 NXP +# +# SPDX-License-Identifier: Apache-2.0 + +# Add external project +ExternalZephyrProject_Add( + APPLICATION rpmsglite_remote + SOURCE_DIR ${APP_DIR}/remote + BOARD ${SB_CONFIG_RPMSG_LITE_REMOTE_BOARD} + ) + +# Add dependencies so that the remote sample will be built first +# This is required because some primary cores need information from the +# remote core's build, such as the output image's LMA +add_dependencies(rpmsglite_pingpong rpmsglite_remote) +sysbuild_add_dependencies(CONFIGURE rpmsglite_pingpong rpmsglite_remote) + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + # Make sure MCUboot is flashed first + sysbuild_add_dependencies(FLASH rpmsglite_remote mcuboot) +endif()