diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index e0eaa73687..9d87486d62 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -72,15 +72,7 @@ components/driver/test_apps/legacy_timer_driver: depends_filepatterns: - components/driver/deprecated/**/*timer* -components/driver/test_apps/touch_sensor_v1: - disable: - - if: SOC_TOUCH_SENSOR_VERSION != 1 - -components/driver/test_apps/touch_sensor_v2: - disable: - - if: SOC_TOUCH_SENSOR_VERSION != 2 - -components/driver/test_apps/twai: +components/driver/test_apps/legacy_twai: disable: - if: SOC_TWAI_SUPPORTED != 1 or SOC_TWAI_SUPPORT_FD == 1 reason: legacy driver doesn't support FD @@ -88,3 +80,11 @@ components/driver/test_apps/twai: - components/driver/twai/**/* depends_components: - esp_driver_gpio + +components/driver/test_apps/touch_sensor_v1: + disable: + - if: SOC_TOUCH_SENSOR_VERSION != 1 + +components/driver/test_apps/touch_sensor_v2: + disable: + - if: SOC_TOUCH_SENSOR_VERSION != 2 diff --git a/components/driver/test_apps/twai/CMakeLists.txt b/components/driver/test_apps/legacy_twai/CMakeLists.txt similarity index 100% rename from components/driver/test_apps/twai/CMakeLists.txt rename to components/driver/test_apps/legacy_twai/CMakeLists.txt diff --git a/components/driver/test_apps/twai/README.md b/components/driver/test_apps/legacy_twai/README.md similarity index 100% rename from components/driver/test_apps/twai/README.md rename to components/driver/test_apps/legacy_twai/README.md diff --git a/components/driver/test_apps/twai/main/CMakeLists.txt b/components/driver/test_apps/legacy_twai/main/CMakeLists.txt similarity index 100% rename from components/driver/test_apps/twai/main/CMakeLists.txt rename to components/driver/test_apps/legacy_twai/main/CMakeLists.txt diff --git a/components/driver/test_apps/twai/main/test_app_main.c b/components/driver/test_apps/legacy_twai/main/test_app_main.c similarity index 100% rename from components/driver/test_apps/twai/main/test_app_main.c rename to components/driver/test_apps/legacy_twai/main/test_app_main.c diff --git a/components/driver/test_apps/twai/main/test_twai_interactive.c b/components/driver/test_apps/legacy_twai/main/test_twai_interactive.c similarity index 100% rename from components/driver/test_apps/twai/main/test_twai_interactive.c rename to components/driver/test_apps/legacy_twai/main/test_twai_interactive.c diff --git a/components/driver/test_apps/twai/main/test_twai_loop_back.c b/components/driver/test_apps/legacy_twai/main/test_twai_loop_back.c similarity index 100% rename from components/driver/test_apps/twai/main/test_twai_loop_back.c rename to components/driver/test_apps/legacy_twai/main/test_twai_loop_back.c diff --git a/components/driver/test_apps/twai/pytest_twai.py b/components/driver/test_apps/legacy_twai/pytest_twai.py similarity index 100% rename from components/driver/test_apps/twai/pytest_twai.py rename to components/driver/test_apps/legacy_twai/pytest_twai.py diff --git a/components/driver/test_apps/twai/sdkconfig.ci.iram_safe b/components/driver/test_apps/legacy_twai/sdkconfig.ci.iram_safe similarity index 100% rename from components/driver/test_apps/twai/sdkconfig.ci.iram_safe rename to components/driver/test_apps/legacy_twai/sdkconfig.ci.iram_safe diff --git a/components/driver/test_apps/twai/sdkconfig.ci.release b/components/driver/test_apps/legacy_twai/sdkconfig.ci.release similarity index 100% rename from components/driver/test_apps/twai/sdkconfig.ci.release rename to components/driver/test_apps/legacy_twai/sdkconfig.ci.release diff --git a/components/driver/test_apps/twai/sdkconfig.defaults b/components/driver/test_apps/legacy_twai/sdkconfig.defaults similarity index 78% rename from components/driver/test_apps/twai/sdkconfig.defaults rename to components/driver/test_apps/legacy_twai/sdkconfig.defaults index feceba725e..fff8c78591 100644 --- a/components/driver/test_apps/twai/sdkconfig.defaults +++ b/components/driver/test_apps/legacy_twai/sdkconfig.defaults @@ -1,4 +1,4 @@ CONFIG_FREERTOS_HZ=1000 -CONFIG_ESP_TASK_WDT=n +CONFIG_ESP_TASK_WDT_INIT=n # primitives for checking sleep internal state CONFIG_ESP_SLEEP_DEBUG=y diff --git a/components/esp_driver_twai/test_apps/.build-test-rules.yml b/components/esp_driver_twai/test_apps/.build-test-rules.yml index 78a389048a..3cae20b47d 100644 --- a/components/esp_driver_twai/test_apps/.build-test-rules.yml +++ b/components/esp_driver_twai/test_apps/.build-test-rules.yml @@ -1,6 +1,5 @@ -components/esp_driver_twai/test_apps/twaifd_test: +components/esp_driver_twai/test_apps/test_twai: disable: - - if: SOC_TWAI_SUPPORTED != 1 or SOC_TWAI_SUPPORT_FD != 1 - reason: Only support FD targets now + - if: SOC_TWAI_SUPPORTED != 1 depends_components: - esp_driver_twai diff --git a/components/esp_driver_twai/test_apps/twaifd_test/CMakeLists.txt b/components/esp_driver_twai/test_apps/test_twai/CMakeLists.txt similarity index 51% rename from components/esp_driver_twai/test_apps/twaifd_test/CMakeLists.txt rename to components/esp_driver_twai/test_apps/test_twai/CMakeLists.txt index 238ab3c8ee..9d7ea4d248 100644 --- a/components/esp_driver_twai/test_apps/twaifd_test/CMakeLists.txt +++ b/components/esp_driver_twai/test_apps/test_twai/CMakeLists.txt @@ -5,9 +5,23 @@ cmake_minimum_required(VERSION 3.16) set(COMPONENTS main) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(twaifd_test) +project(test_twai) message(STATUS "Checking TWAI registers are not read-write by half-word") include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake) check_register_rw_half_word(SOC_MODULES "twai*" "pcr" "hp_sys_clkrst" HAL_MODULES "twai*") + +if(CONFIG_COMPILER_DUMP_RTL_FILES) + add_custom_target( + check_test_app_sections ALL + COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py + --rtl-dirs ${CMAKE_BINARY_DIR}/esp-idf/esp_driver_twai/,${CMAKE_BINARY_DIR}/esp-idf/hal/ + --elf-file ${CMAKE_BINARY_DIR}/test_twai.elf + find-refs + --from-sections=.iram0.text + --to-sections=.flash.text,.flash.rodata + --exit-code + DEPENDS ${elf} + ) +endif() diff --git a/components/esp_driver_twai/test_apps/test_twai/README.md b/components/esp_driver_twai/test_apps/test_twai/README.md new file mode 100644 index 0000000000..46d16c788c --- /dev/null +++ b/components/esp_driver_twai/test_apps/test_twai/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_driver_twai/test_apps/test_twai/main/CMakeLists.txt b/components/esp_driver_twai/test_apps/test_twai/main/CMakeLists.txt new file mode 100644 index 0000000000..92a85f5d69 --- /dev/null +++ b/components/esp_driver_twai/test_apps/test_twai/main/CMakeLists.txt @@ -0,0 +1,15 @@ +set(srcs "test_app_main.c") + +if(CONFIG_SOC_TWAI_SUPPORTED) + list(APPEND srcs "test_twai_common.c") +endif() + +if(CONFIG_SOC_TWAI_SUPPORT_FD) + list(APPEND srcs "test_twai_fd.c") +endif() + +idf_component_register( + SRCS ${srcs} + PRIV_REQUIRES esp_driver_twai esp_timer + WHOLE_ARCHIVE +) diff --git a/components/esp_driver_twai/test_apps/twaifd_test/main/idf_component.yml b/components/esp_driver_twai/test_apps/test_twai/main/idf_component.yml similarity index 100% rename from components/esp_driver_twai/test_apps/twaifd_test/main/idf_component.yml rename to components/esp_driver_twai/test_apps/test_twai/main/idf_component.yml diff --git a/components/esp_driver_twai/test_apps/twaifd_test/main/test_app_main.c b/components/esp_driver_twai/test_apps/test_twai/main/test_app_main.c similarity index 95% rename from components/esp_driver_twai/test_apps/twaifd_test/main/test_app_main.c rename to components/esp_driver_twai/test_apps/test_twai/main/test_app_main.c index 8c66fa4030..66ba95a25d 100644 --- a/components/esp_driver_twai/test_apps/twaifd_test/main/test_app_main.c +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_app_main.c @@ -19,6 +19,7 @@ void setUp(void) void tearDown(void) { + esp_reent_cleanup(); unity_utils_evaluate_leaks_direct(LEAKS); } diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.c b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.c new file mode 100644 index 0000000000..36bef3ec61 --- /dev/null +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_common.c @@ -0,0 +1,427 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "unity_test_utils_cache.h" +#include "test_utils.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "esp_twai.h" +#include "esp_twai_onchip.h" + +#define TEST_TX_GPIO 4 +#define TEST_RX_GPIO 5 +#define TEST_TWAI_QUEUE_DEPTH 5 +#define TEST_TRANS_LEN 100 +#define TEST_FRAME_LEN 7 +#define TEST_FRAME_NUM howmany(TEST_TRANS_LEN, TEST_FRAME_LEN) + +static IRAM_ATTR bool test_driver_install_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) +{ + twai_frame_t rx_frame; + if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) { + ESP_EARLY_LOGI("Recv ", "id 0x%lx rtr %d", rx_frame.header.id, rx_frame.header.rtr); + } + if (rx_frame.header.id != 0x100) { + TEST_FAIL(); //callback is unregistered, should not run here + } + return false; +} + +TEST_CASE("twai install uninstall (loopback)", "[TWAI]") +{ + esp_err_t ret; + twai_node_handle_t node_hdl[SOC_TWAI_CONTROLLER_NUM + 1]; + twai_onchip_node_config_t node_config = { + .io_cfg.tx = TEST_TX_GPIO, + .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver + .bit_timing.bitrate = 1000000, + .data_timing.bitrate = 1000000, + .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, + .flags.enable_loopback = true, + .flags.enable_self_test = true, + }; + + // loop 10 times to check memory leak + for (uint8_t loop = 0; loop < 10; loop ++) { + for (uint8_t i = 0; i < SOC_TWAI_CONTROLLER_NUM + 1; i++) { + ret = twai_new_node_onchip(&node_config, &node_hdl[i]); + printf("Install TWAI%d return %s\n", i, esp_err_to_name(ret)); + TEST_ASSERT(ret == ((i < SOC_TWAI_CONTROLLER_NUM) ? ESP_OK : ESP_ERR_NOT_FOUND)); + } + // can't disable before enable + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_disable(node_hdl[0])); + twai_event_callbacks_t user_cbs = { + .on_rx_done = test_driver_install_rx_cb, + }; + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL)); + + printf("Test unregister callback\n"); + user_cbs.on_rx_done = NULL; + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL)); + + twai_frame_t tx_frame = { + .header.id = 0x82, + .header.rtr = true, + }; + printf("Test transmit before enable\n"); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_transmit(node_hdl[0], &tx_frame, 0)); + TEST_ESP_OK(twai_node_enable(node_hdl[0])); + TEST_ESP_OK(twai_node_disable(node_hdl[0])); + TEST_ESP_OK(twai_node_enable(node_hdl[0])); + TEST_ESP_OK(twai_node_transmit(node_hdl[0], &tx_frame, 0)); + + TEST_ESP_OK(twai_node_disable(node_hdl[0])); + TEST_ESP_OK(twai_node_delete(node_hdl[0])); + + printf("Test install after delete\n"); + TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl[SOC_TWAI_CONTROLLER_NUM])); + user_cbs.on_rx_done = test_driver_install_rx_cb, + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[SOC_TWAI_CONTROLLER_NUM], &user_cbs, NULL)); + TEST_ESP_OK(twai_node_enable(node_hdl[SOC_TWAI_CONTROLLER_NUM])); + tx_frame.header.id = 0x100; + TEST_ESP_OK(twai_node_transmit(node_hdl[SOC_TWAI_CONTROLLER_NUM], &tx_frame, 0)); + twai_frame_t rx_frame; + printf("Test receive from task\n"); + TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_receive_from_isr(node_hdl[SOC_TWAI_CONTROLLER_NUM], &rx_frame)); + + TEST_ESP_OK(twai_node_disable(node_hdl[SOC_TWAI_CONTROLLER_NUM])); + for (uint8_t i = 1; i <= SOC_TWAI_CONTROLLER_NUM; i++) { + printf("Uninstall TWAI%d\n", i - 1); + TEST_ESP_OK(twai_node_delete(node_hdl[i])); + } + } +} + +static IRAM_ATTR bool test_enable_disable_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) +{ + twai_frame_t *rx_frame = user_ctx; + if (ESP_OK == twai_node_receive_from_isr(handle, rx_frame)) { + ESP_EARLY_LOGI("Recv", "RX id 0x%x len %d ext %d brs %d esi %d", rx_frame->header.id, twaifd_dlc2len(rx_frame->header.dlc), rx_frame->header.ide, rx_frame->header.brs, rx_frame->header.esi); + rx_frame->buffer += rx_frame->buffer_len; + } + return false; +} + +TEST_CASE("twai transmit stop resume (loopback)", "[TWAI]") +{ + // prepare test memory + uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT); + uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT); + TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr); + printf("Transmit %d bytes package in %d frames\n", TEST_TRANS_LEN, TEST_FRAME_NUM); + + twai_node_handle_t node_hdl; + twai_onchip_node_config_t node_config = { + .io_cfg.tx = TEST_TX_GPIO, + .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver + .bit_timing.bitrate = 200000, + .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, + .flags.enable_loopback = true, + .flags.enable_self_test = true, + }; + TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); + + twai_frame_t rx_frame = { + .buffer = recv_pkg_ptr, + .buffer_len = TEST_FRAME_LEN, + }; + twai_event_callbacks_t user_cbs = { + .on_rx_done = test_enable_disable_rx_cb, + }; + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + + //create and enqueue all transfers + twai_frame_t *tx_msgs = heap_caps_calloc(TEST_FRAME_NUM, sizeof(twai_frame_t), MALLOC_CAP_8BIT); + TEST_ASSERT(tx_msgs); + for (uint32_t tx_cnt = 0; tx_cnt < TEST_FRAME_NUM; tx_cnt++) { + tx_msgs[tx_cnt].header.id = tx_cnt | 0x400; + tx_msgs[tx_cnt].header.ide = !!(tx_cnt % 3); + tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * TEST_FRAME_LEN; + tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == TEST_FRAME_NUM) ? (TEST_TRANS_LEN - tx_cnt * TEST_FRAME_LEN) : TEST_FRAME_LEN; + TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 500)); + } + + TEST_ESP_OK(twai_node_disable(node_hdl)); + for (uint8_t i = 3; i > 0; i--) { + printf("interrupted, %d sec\n", i); + vTaskDelay(1000); + } + printf("continuing ...\n"); + TEST_ESP_OK(twai_node_enable(node_hdl)); + + //waiting pkg receive finish + while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_LEN) { + vTaskDelay(1); + } + free(tx_msgs); + + // check if pkg receive correct + printf("pkg check %s!!\n", memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_LEN) ? "failed" : "ok"); + TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_LEN); + + free(send_pkg_ptr); + free(recv_pkg_ptr); + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_delete(node_hdl)); +} + +static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t trans_num) +{ + uint8_t send_pkg_ptr[TWAI_FRAME_MAX_LEN]; + twai_frame_t tx_msg = { + .buffer = send_pkg_ptr, + }; + printf("Sending %ld random trans ...\n", trans_num); + for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) { + tx_msg.header.id = tx_cnt | 0xf000; + tx_msg.header.ide = !!(tx_cnt % 2); + tx_msg.header.rtr = !!(tx_cnt % 3); + tx_msg.buffer_len = tx_cnt % TWAI_FRAME_MAX_LEN; + TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msg, 0)); + vTaskDelay(8); //as async transaction, waiting trans done + } +} + +static IRAM_ATTR bool test_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) +{ + uint8_t *test_ctrl = user_ctx; + uint8_t recv_pkg_ptr[TWAI_FRAME_MAX_LEN]; + twai_frame_t rx_frame = { + .buffer = recv_pkg_ptr, + .buffer_len = TWAI_FRAME_MAX_LEN, + }; + if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) { + ESP_EARLY_LOGI("Recv", "RX id 0x%4x len %2d ext %d rmt %d", rx_frame.header.id, twaifd_dlc2len(rx_frame.header.dlc), rx_frame.header.ide, rx_frame.header.rtr); + switch (test_ctrl[0]) { + case 0: // receive something + TEST_ASSERT(rx_frame.header.id >= 0x10); + TEST_ASSERT(!rx_frame.header.ide); + break; + case 1: // receive all + case 2: break; // receive none + default: TEST_ASSERT(false); + } + test_ctrl[1] ++; + } + return false; +} + +TEST_CASE("twai mask filter (loopback)", "[TWAI]") +{ + uint8_t test_ctrl[2]; + twai_node_handle_t node_hdl; + twai_onchip_node_config_t node_config = { + .io_cfg.tx = TEST_TX_GPIO, + .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver + .bit_timing.bitrate = 1000000, + .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, + .flags.enable_loopback = true, + .flags.enable_self_test = true, + }; + TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); + + twai_event_callbacks_t user_cbs = { + .on_rx_done = test_filter_rx_done_cb, + }; + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl)); + + twai_mask_filter_config_t mfilter_cfg = {0}; + for (uint8_t i = 0; i < SOC_TWAI_MASK_FILTER_NUM; i++) { + printf("\n--------------------------------------\n"); + test_ctrl[0] = 0; + test_ctrl[1] = 0; + mfilter_cfg.id = 0x10, + mfilter_cfg.mask = 0xf0, + mfilter_cfg.is_ext = false, + printf("Testing mask filter %d: id 0x%lx mask 0x%lx is_ext %d\n", i, mfilter_cfg.id, mfilter_cfg.mask, mfilter_cfg.is_ext); + TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, i, &mfilter_cfg)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + test_random_trans_generator(node_hdl, 30); + TEST_ASSERT_EQUAL(7, test_ctrl[1]); // must receive 7 of 30 frames under filter config + + test_ctrl[0] = 1; + test_ctrl[1] = 0; + mfilter_cfg.id = 0; + mfilter_cfg.mask = 0; + printf("Change filter %d to receive ALL: id 0x%lx mask 0x%lx\n", i, mfilter_cfg.id, mfilter_cfg.mask); + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, i, &mfilter_cfg)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + test_random_trans_generator(node_hdl, 20); + TEST_ASSERT_EQUAL(20, test_ctrl[1]); + + test_ctrl[0] = 2; + test_ctrl[1] = 0; + mfilter_cfg.id = 0xFFFFFFFF; + mfilter_cfg.mask = 0xFFFFFFFF; + printf("Disable filter %d: id 0x%lx mask 0x%lx\n", i, mfilter_cfg.id, mfilter_cfg.mask); + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, i, &mfilter_cfg)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + test_random_trans_generator(node_hdl, 40); + TEST_ASSERT_EQUAL(0, test_ctrl[1]); + TEST_ESP_OK(twai_node_disable(node_hdl)); + } + TEST_ESP_OK(twai_node_delete(node_hdl)); +} + +//------------------ Dual Filter Test -------------------// +#if !SOC_TWAI_SUPPORT_FD +static IRAM_ATTR bool test_dual_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) +{ + uint8_t *test_ctrl = user_ctx; + uint8_t recv_pkg_ptr[TWAI_FRAME_MAX_LEN]; + twai_frame_t rx_frame = { + .buffer = recv_pkg_ptr, + .buffer_len = TWAI_FRAME_MAX_LEN, + }; + if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) { + ESP_EARLY_LOGI("Recv", "RX id 0x%4x len %2d ext %d rmt %d", rx_frame.header.id, twaifd_dlc2len(rx_frame.header.dlc), rx_frame.header.ide, rx_frame.header.rtr); + switch (test_ctrl[0]) { + case 0: // receive something + TEST_ASSERT(!rx_frame.header.ide); + TEST_ASSERT((rx_frame.header.id >= 0x10) && (rx_frame.header.id <= 0x2f)); + break; + case 1: break; // receive none + default: TEST_ASSERT(false); + } + test_ctrl[1] ++; + } + return false; +} + +TEST_CASE("twai dual 16bit mask filter (loopback)", "[TWAI]") +{ + uint8_t test_ctrl[2]; + twai_node_handle_t node_hdl; + twai_onchip_node_config_t node_config = { + .io_cfg.tx = TEST_TX_GPIO, + .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver + .bit_timing.bitrate = 1000000, + .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, + .flags.enable_loopback = true, + .flags.enable_self_test = true, + }; + TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); + + twai_event_callbacks_t user_cbs = { + .on_rx_done = test_dual_filter_rx_done_cb, + }; + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl)); + + printf("Testing dual filter: id1 0x%x mask1 0x%x, id2 0x%x mask2 0x%x\n", 0x020, 0x7f0, 0x013, 0x7f8); + test_ctrl[0] = 0; + test_ctrl[1] = 0; + // filter 1 receive only std id 0x02x + // filter 2 receive only std id 0x010~0x017 + twai_mask_filter_config_t dual_config = twai_make_dual_filter(0x020, 0x7f0, 0x013, 0x7f8, false); + TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &dual_config)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + test_random_trans_generator(node_hdl, 50); + TEST_ASSERT_EQUAL(12, test_ctrl[1]); // must receive 12 of 50 frames under filter config + + printf("Disable filter\n"); + test_ctrl[0] = 1; + test_ctrl[1] = 0; + dual_config.id = 0xFFFFFFFF; + dual_config.mask = 0xFFFFFFFF; + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &dual_config)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + test_random_trans_generator(node_hdl, 40); + TEST_ASSERT_EQUAL(0, test_ctrl[1]); + + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_delete(node_hdl)); +} +#endif + +#if CONFIG_TWAI_ISR_CACHE_SAFE +static IRAM_ATTR bool test_iram_safe_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) +{ + twai_frame_t *rx_frame = user_ctx; + if (ESP_OK == twai_node_receive_from_isr(handle, rx_frame)) { + esp_rom_printf(DRAM_STR("RX id 0x%x len %d ext %d brs %d esi %d\n"), rx_frame->header.id, twaifd_dlc2len(rx_frame->header.dlc), rx_frame->header.ide, rx_frame->header.brs, rx_frame->header.esi); + rx_frame->buffer += rx_frame->buffer_len; + } + return false; +} + +static void IRAM_ATTR test_wait_trans_done_cache_disable(void *args) +{ + twai_frame_t *rx_frame = ((twai_frame_t **)args)[0]; + uint8_t *orig_buff = ((uint8_t **)args)[1]; + + esp_rom_printf(DRAM_STR("Cache disabled now !!!\n")); + //waiting pkg receive finish + while (rx_frame->buffer < orig_buff + TEST_TRANS_LEN) { + esp_rom_delay_us(1000); + } +} + +TEST_CASE("twai driver cache safe (loopback)", "[TWAI]") +{ + // prepare test memory + uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT); + uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT); + TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr); + printf("Transmit %d bytes package in %d frames\n", TEST_TRANS_LEN, TEST_FRAME_NUM); + + twai_node_handle_t node_hdl; + twai_onchip_node_config_t node_config = { + .io_cfg.tx = TEST_TX_GPIO, + .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver + .bit_timing.bitrate = 50000, //slow bitrate to ensure cache disabled before tx_queue finish + .tx_queue_depth = TEST_FRAME_NUM, + .flags.enable_loopback = true, + .flags.enable_self_test = true, + }; + TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); + + twai_frame_t rx_frame = { + .buffer = recv_pkg_ptr, + .buffer_len = TEST_FRAME_LEN, + }; + twai_event_callbacks_t user_cbs = { + .on_rx_done = test_iram_safe_rx_cb, + }; + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + + //create and enqueue all transfers + twai_frame_t *tx_msgs = heap_caps_calloc(TEST_FRAME_NUM, sizeof(twai_frame_t), MALLOC_CAP_8BIT); + TEST_ASSERT(tx_msgs); + for (uint32_t tx_cnt = 0; tx_cnt < TEST_FRAME_NUM; tx_cnt++) { + tx_msgs[tx_cnt].header.id = tx_cnt | 0x400; + tx_msgs[tx_cnt].header.ide = !!(tx_cnt % 3); + tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * TEST_FRAME_LEN; + tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == TEST_FRAME_NUM) ? (TEST_TRANS_LEN - tx_cnt * TEST_FRAME_LEN) : TEST_FRAME_LEN; + TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 0)); + } + + //disable cache immediately before tx_queue finish + void *user_data[2] = {&rx_frame, recv_pkg_ptr}; + unity_utils_run_cache_disable_stub(test_wait_trans_done_cache_disable, user_data); + + //if it is able to waiting finish, means pass the test + free(tx_msgs); + + // check if pkg receive correct + printf("Transaction finish, pkg check %s!!\n", memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_LEN) ? "failed" : "ok"); + TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_LEN); + + free(send_pkg_ptr); + free(recv_pkg_ptr); + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_delete(node_hdl)); +} +#endif //CONFIG_TWAI_ISR_CACHE_SAFE diff --git a/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.c b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.c new file mode 100644 index 0000000000..61cc4567c9 --- /dev/null +++ b/components/esp_driver_twai/test_apps/test_twai/main/test_twai_fd.c @@ -0,0 +1,206 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "unity.h" +#include "esp_log.h" +#include "esp_timer.h" +#include "esp_heap_caps.h" +#include "freertos/FreeRTOS.h" +#include "test_utils.h" +#include "esp_twai.h" +#include "esp_twai_onchip.h" + +#define TEST_TX_GPIO 4 +#define TEST_RX_GPIO 5 +#define TEST_TWAI_QUEUE_DEPTH 5 + +static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t trans_num) +{ + uint8_t send_pkg_ptr[TWAIFD_FRAME_MAX_LEN]; + twai_frame_t tx_msg = { + .buffer = send_pkg_ptr, + }; + printf("Sending %ld random trans ...\n", trans_num); + for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) { + tx_msg.header.id = tx_cnt | 0xf000; + tx_msg.header.ide = !!(tx_cnt % 2); + tx_msg.header.rtr = !!(tx_cnt % 3); + tx_msg.header.fdf = !!(tx_cnt % 5); + tx_msg.buffer_len = tx_msg.header.fdf ? (tx_cnt % TWAIFD_FRAME_MAX_LEN) : (tx_cnt % TWAI_FRAME_MAX_LEN); + TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msg, 0)); + vTaskDelay(8); //as async transaction, waiting trans done + } +} + +static IRAM_ATTR bool test_range_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) +{ + uint8_t *test_ctrl = user_ctx; + uint8_t recv_pkg_ptr[TWAIFD_FRAME_MAX_LEN]; + twai_frame_t rx_frame = { + .buffer = recv_pkg_ptr, + .buffer_len = TWAIFD_FRAME_MAX_LEN, + }; + if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame)) { + ESP_EARLY_LOGI("Recv", "RX id 0x%4x len %2d ext %d rmt %d fd %d", rx_frame.header.id, twaifd_dlc2len(rx_frame.header.dlc), rx_frame.header.ide, rx_frame.header.rtr, rx_frame.header.fdf); + switch (test_ctrl[0]) { + case 0: // enable range filter + TEST_ASSERT(!rx_frame.header.ide); + TEST_ASSERT((rx_frame.header.id >= 0x0a) && (rx_frame.header.id <= 0x15)); + break; + case 1: break; // disable range filter + default: TEST_ASSERT(false); + } + test_ctrl[1] ++; + } + return false; +} + +TEST_CASE("twai range filter (loopback)", "[TWAI]") +{ + uint8_t test_ctrl[2]; + twai_node_handle_t node_hdl; + twai_onchip_node_config_t node_config = { + .io_cfg.tx = TEST_TX_GPIO, + .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver + .bit_timing.bitrate = 1000000, + .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, + .flags.enable_loopback = true, + .flags.enable_self_test = true, + }; + TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); + + twai_event_callbacks_t user_cbs = { + .on_rx_done = test_range_filter_rx_done_cb, + }; + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl)); + + // disable mask filter 0 which enabled by default + twai_mask_filter_config_t mfilter_cfg = { + .id = 0xFFFFFFFF, + .mask = 0xFFFFFFFF, + }; + TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg)); + + test_ctrl[0] = 0; + test_ctrl[1] = 0; + twai_range_filter_config_t rfilter_cfg = { + .range_low = 0x0a, + .range_high = 0x15, + .is_ext = false, + }; + printf("Config range filter 0: 0x%lx - 0x%lx\n", rfilter_cfg.range_low, rfilter_cfg.range_high); + TEST_ESP_OK(twai_node_config_range_filter(node_hdl, 0, &rfilter_cfg)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + test_random_trans_generator(node_hdl, 30); + TEST_ASSERT_EQUAL(6, test_ctrl[1]); // must receive 6 of 30 frames under filter config + + test_ctrl[0] = 1; + test_ctrl[1] = 0; + rfilter_cfg.range_low = 1; + rfilter_cfg.range_high = 0; // config invalid range to disable range filter + printf("Disable range filter 0: 0x%lx - 0x%lx\n", rfilter_cfg.range_low, rfilter_cfg.range_high); + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_config_range_filter(node_hdl, 0, &rfilter_cfg)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + test_random_trans_generator(node_hdl, 30); + TEST_ASSERT_EQUAL(0, test_ctrl[1]); + + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_delete(node_hdl)); +} + +#define TEST_TRANS_TIME_BUF_LEN 20000 +static IRAM_ATTR bool test_fd_trans_time_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) +{ + twai_frame_t *rx_frame = user_ctx; + uint32_t data_len; + if (ESP_OK == twai_node_receive_from_isr(handle, rx_frame)) { + data_len = MIN(twaifd_dlc2len(rx_frame->header.dlc), rx_frame->buffer_len); + ESP_EARLY_LOGD("Recv", "RX id 0x%x len %d brs %d", rx_frame->header.id, data_len, rx_frame->header.brs); + rx_frame->buffer += data_len; + // calc the `rx_frame->buffer_len` for last frame receive + if ((rx_frame->header.id - 0x400 + 1) * rx_frame->buffer_len > (TEST_TRANS_TIME_BUF_LEN - rx_frame->buffer_len)) { + rx_frame->buffer_len = TEST_TRANS_TIME_BUF_LEN % rx_frame->buffer_len; + } + } + return false; +} + +TEST_CASE("twai fd transmit time (loopback)", "[TWAI]") +{ + // prepare test memory + uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_TIME_BUF_LEN, MALLOC_CAP_8BIT); + uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_TIME_BUF_LEN, MALLOC_CAP_8BIT); + TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr); + + twai_node_handle_t node_hdl; + twai_onchip_node_config_t node_config = { + .io_cfg.tx = TEST_TX_GPIO, + .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver + .bit_timing.bitrate = 1000000, + .data_timing.bitrate = 4000000, + .data_timing.ssp_permill = 700, // ssp 70.0% + .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, + .flags.enable_loopback = true, + .flags.enable_self_test = true, + }; + TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); + + twai_frame_t rx_frame = {.buffer_len = 64}; + twai_event_callbacks_t user_cbs = { + .on_rx_done = test_fd_trans_time_rx_cb, + }; + TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame)); + TEST_ESP_OK(twai_node_enable(node_hdl)); + printf("%-12s %-14s %-14s %-7s %-15s %s\n", "pkg_len", "frame_len", "frame_num", "brs", "trans_time/ms", "result"); + printf("-------------------------------------------------------------------------\n"); + + uint64_t time1, time2; + for (uint8_t test_mode = 0; test_mode < 3; test_mode ++) { + //create and enqueue all transfers + uint8_t frame_len = test_mode >= 1 ? 64 : 8; + uint16_t trans_num = howmany(TEST_TRANS_TIME_BUF_LEN, frame_len); + rx_frame.buffer = recv_pkg_ptr; + rx_frame.buffer_len = frame_len; + memset(recv_pkg_ptr, 0xff, TEST_TRANS_TIME_BUF_LEN); + twai_frame_t *tx_msgs = heap_caps_calloc(trans_num, sizeof(twai_frame_t), MALLOC_CAP_8BIT); + TEST_ASSERT(tx_msgs); + time1 = esp_timer_get_time(); + for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) { + tx_msgs[tx_cnt].header.id = tx_cnt | 0x400; + tx_msgs[tx_cnt].header.fdf = frame_len == 64; + tx_msgs[tx_cnt].header.brs = test_mode == 2; + tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * frame_len; + tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == trans_num) ? (TEST_TRANS_TIME_BUF_LEN - tx_cnt * frame_len) : frame_len; + TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 1000)); + } + + //waiting pkg receive finish + while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_TIME_BUF_LEN) { + vTaskDelay(1); + } + time2 = esp_timer_get_time(); + free(tx_msgs); + + // check if pkg receive correct + printf("%-12d %-14d %-14d %-7d %-15.2f %-s\n", + TEST_TRANS_TIME_BUF_LEN, + frame_len, + trans_num, + (test_mode == 2), + (time2 - time1) / 1000.f, + memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_TIME_BUF_LEN) ? "failed" : "ok"); + TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_TIME_BUF_LEN); + } + printf("-------------------------------------------------------------------------\n"); + + free(send_pkg_ptr); + free(recv_pkg_ptr); + TEST_ESP_OK(twai_node_disable(node_hdl)); + TEST_ESP_OK(twai_node_delete(node_hdl)); +} diff --git a/components/esp_driver_twai/test_apps/twaifd_test/pytest_driver_twai.py b/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py similarity index 80% rename from components/esp_driver_twai/test_apps/twaifd_test/pytest_driver_twai.py rename to components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py index bd511bd6b8..7b9aabf1a9 100644 --- a/components/esp_driver_twai/test_apps/twaifd_test/pytest_driver_twai.py +++ b/components/esp_driver_twai/test_apps/test_twai/pytest_driver_twai.py @@ -8,7 +8,7 @@ from pytest_embedded_idf.utils import soc_filtered_targets @pytest.mark.generic -@pytest.mark.parametrize('config', ['release'], indirect=True) -@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORT_FD == 1'), indirect=['target']) +@pytest.mark.parametrize('config', ['release', 'cache_safe'], indirect=True) +@idf_parametrize('target', soc_filtered_targets('SOC_TWAI_SUPPORTED == 1'), indirect=['target']) def test_driver_twai_loopbk(dut: Dut) -> None: dut.run_all_single_board_cases(reset=True) diff --git a/components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.cache_safe b/components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.cache_safe new file mode 100644 index 0000000000..91f743b36d --- /dev/null +++ b/components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.cache_safe @@ -0,0 +1,6 @@ +CONFIG_COMPILER_DUMP_RTL_FILES=y +CONFIG_TWAI_ISR_CACHE_SAFE=y +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y +CONFIG_COMPILER_OPTIMIZATION_NONE=y +CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y diff --git a/components/esp_driver_twai/test_apps/twaifd_test/sdkconfig.ci.release b/components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.release similarity index 100% rename from components/esp_driver_twai/test_apps/twaifd_test/sdkconfig.ci.release rename to components/esp_driver_twai/test_apps/test_twai/sdkconfig.ci.release diff --git a/components/esp_driver_twai/test_apps/twaifd_test/sdkconfig.defaults b/components/esp_driver_twai/test_apps/test_twai/sdkconfig.defaults similarity index 100% rename from components/esp_driver_twai/test_apps/twaifd_test/sdkconfig.defaults rename to components/esp_driver_twai/test_apps/test_twai/sdkconfig.defaults diff --git a/components/esp_driver_twai/test_apps/twaifd_test/README.md b/components/esp_driver_twai/test_apps/twaifd_test/README.md deleted file mode 100644 index 1d5f1c0a57..0000000000 --- a/components/esp_driver_twai/test_apps/twaifd_test/README.md +++ /dev/null @@ -1,2 +0,0 @@ -| Supported Targets | ESP32-C5 | -| ----------------- | -------- | diff --git a/components/esp_driver_twai/test_apps/twaifd_test/main/CMakeLists.txt b/components/esp_driver_twai/test_apps/twaifd_test/main/CMakeLists.txt deleted file mode 100644 index 15c4780688..0000000000 --- a/components/esp_driver_twai/test_apps/twaifd_test/main/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -set(srcs "test_app_main.c") - -if(CONFIG_SOC_TWAI_SUPPORT_FD) - list(APPEND srcs "test_twaifd.c") -endif() - -idf_component_register( - SRCS ${srcs} - PRIV_REQUIRES esp_driver_twai - WHOLE_ARCHIVE -) diff --git a/components/esp_driver_twai/test_apps/twaifd_test/main/test_twaifd.c b/components/esp_driver_twai/test_apps/twaifd_test/main/test_twaifd.c deleted file mode 100644 index e488c1d2b2..0000000000 --- a/components/esp_driver_twai/test_apps/twaifd_test/main/test_twaifd.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include "unity.h" -#include "esp_log.h" -#include "esp_heap_caps.h" -#include "freertos/FreeRTOS.h" -#include "test_utils.h" -#include "esp_twai.h" -#include "esp_twai_onchip.h" - -#define TEST_TX_GPIO 4 -#define TEST_RX_GPIO 5 -#define TEST_TWAI_QUEUE_DEPTH 5 -#define TEST_TRANS_LEN 100 -#define TEST_FRAME_LEN 7 -#define TEST_FRAME_NUM howmany(TEST_TRANS_LEN, TEST_FRAME_LEN) - -static bool test_driver_install_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) -{ - twai_frame_header_t rx_header; - if (ESP_OK == twai_node_receive_from_isr(handle, &rx_header, NULL, 0, NULL)) { - ESP_EARLY_LOGI("Recv ", "id 0x%lx rtr %d", rx_header.id, rx_header.rtr); - } - if (rx_header.id != 0x100) { - TEST_FAIL(); //callback is unregistered, should not run here - } - return false; -} - -TEST_CASE("twai install uninstall (loopback)", "[TWAI]") -{ - esp_err_t ret; - twai_node_handle_t node_hdl[SOC_TWAI_CONTROLLER_NUM + 1]; - twai_onchip_node_config_t node_config = { - .io_cfg.tx = TEST_TX_GPIO, - .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver - .bit_timing.bitrate = 1000000, - .data_timing.bitrate = 1000000, - .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, - .flags.enable_loopback = true, - .flags.enable_self_test = true, - }; - - // loop 10 times to check memory leak - for (uint8_t loop = 0; loop < 10; loop ++) { - for (uint8_t i = 0; i < SOC_TWAI_CONTROLLER_NUM + 1; i++) { - ret = twai_new_node_onchip(&node_config, &node_hdl[i]); - printf("Install TWAI%d return %s\n", i, esp_err_to_name(ret)); - TEST_ASSERT(ret == ((i < SOC_TWAI_CONTROLLER_NUM) ? ESP_OK : ESP_ERR_NOT_FOUND)); - } - // can't disable before enable - TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_disable(node_hdl[0])); - twai_event_callbacks_t user_cbs = { - .on_rx_done = test_driver_install_rx_cb, - }; - TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL)); - - printf("Test unregister callback\n"); - user_cbs.on_rx_done = NULL; - TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[0], &user_cbs, NULL)); - - twai_frame_t tx_frame = { - .header.id = 0x82, - .header.rtr = true, - }; - printf("Test transmit before enable\n"); - TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_transmit(node_hdl[0], &tx_frame, 0)); - TEST_ESP_OK(twai_node_enable(node_hdl[0])); - TEST_ESP_OK(twai_node_disable(node_hdl[0])); - TEST_ESP_OK(twai_node_enable(node_hdl[0])); - TEST_ESP_OK(twai_node_transmit(node_hdl[0], &tx_frame, 0)); - - TEST_ESP_OK(twai_node_disable(node_hdl[0])); - TEST_ESP_OK(twai_node_delete(node_hdl[0])); - - printf("Test install after delete\n"); - TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl[SOC_TWAI_CONTROLLER_NUM])); - user_cbs.on_rx_done = test_driver_install_rx_cb, - TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl[SOC_TWAI_CONTROLLER_NUM], &user_cbs, NULL)); - TEST_ESP_OK(twai_node_enable(node_hdl[SOC_TWAI_CONTROLLER_NUM])); - tx_frame.header.id = 0x100; - TEST_ESP_OK(twai_node_transmit(node_hdl[SOC_TWAI_CONTROLLER_NUM], &tx_frame, 0)); - twai_frame_t rx_frame; - printf("Test receive from task\n"); - TEST_ESP_ERR(ESP_ERR_INVALID_STATE, twai_node_receive_from_isr(node_hdl[SOC_TWAI_CONTROLLER_NUM], &rx_frame.header, rx_frame.buffer, rx_frame.buffer_len, NULL)); - - TEST_ESP_OK(twai_node_disable(node_hdl[SOC_TWAI_CONTROLLER_NUM])); - for (uint8_t i = 1; i <= SOC_TWAI_CONTROLLER_NUM; i++) { - printf("Uninstall TWAI%d\n", i - 1); - TEST_ESP_OK(twai_node_delete(node_hdl[i])); - } - } -} - -static bool test_enable_disable_rx_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) -{ - twai_frame_t *rx_frame = user_ctx; - size_t ret_len; - if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame->header, rx_frame->buffer, rx_frame->buffer_len, &ret_len)) { - ESP_EARLY_LOGI("twai", "RX id 0x%x len %d ext %d fd %d brs %d esi %d", rx_frame->header.id, ret_len, rx_frame->header.ide, rx_frame->header.fdf, rx_frame->header.brs, rx_frame->header.esi); - rx_frame->buffer += rx_frame->buffer_len; - } - return false; -} - -TEST_CASE("twai transmit stop resume (loopback)", "[TWAI]") -{ - // prepare test memory - uint8_t *send_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT); - uint8_t *recv_pkg_ptr = heap_caps_malloc(TEST_TRANS_LEN, MALLOC_CAP_8BIT); - TEST_ASSERT(send_pkg_ptr && recv_pkg_ptr); - printf("Transmit %d bytes package in %d frames\n", TEST_TRANS_LEN, TEST_FRAME_NUM); - - twai_node_handle_t node_hdl; - twai_onchip_node_config_t node_config = { - .io_cfg.tx = TEST_TX_GPIO, - .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver - .bit_timing.bitrate = 20000, - .data_timing.bitrate = 4000000, - .data_timing.ssp_permill = 700, // ssp 70.0% - .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, - .flags.enable_loopback = true, - .flags.enable_self_test = true, - }; - TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); - - // reconfig fd timing to 80M/(4+3+2+1)=8MHz, ssp=8/(4+3+2+1)=80% - twai_timing_advanced_config_t timing_fd = { - .brp = 1, - .prop_seg = 4, - .tseg_1 = 3, - .tseg_2 = 2, - .sjw = 2, - .ssp_offset = 8, - }; - TEST_ESP_OK(twai_node_reconfig_timing(node_hdl, NULL, &timing_fd)); - - twai_frame_t rx_frame = { - .buffer = recv_pkg_ptr, - .buffer_len = TEST_FRAME_LEN, - }; - twai_event_callbacks_t user_cbs = { - .on_rx_done = test_enable_disable_rx_cb, - }; - TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, &rx_frame)); - TEST_ESP_OK(twai_node_enable(node_hdl)); - - //create and enqueue all transfers - twai_frame_t *tx_msgs = heap_caps_calloc(TEST_FRAME_NUM, sizeof(twai_frame_t), MALLOC_CAP_8BIT); - TEST_ASSERT(tx_msgs); - for (uint32_t tx_cnt = 0; tx_cnt < TEST_FRAME_NUM; tx_cnt++) { - tx_msgs[tx_cnt].header.id = tx_cnt | 0x400; - tx_msgs[tx_cnt].header.ide = !!(tx_cnt % 3); - tx_msgs[tx_cnt].header.fdf = !!(tx_cnt % 4); - tx_msgs[tx_cnt].header.brs = !!(tx_cnt % 2); - tx_msgs[tx_cnt].buffer = send_pkg_ptr + tx_cnt * TEST_FRAME_LEN; - tx_msgs[tx_cnt].buffer_len = ((tx_cnt + 1) == TEST_FRAME_NUM) ? (TEST_TRANS_LEN - tx_cnt * TEST_FRAME_LEN) : TEST_FRAME_LEN; - TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msgs[tx_cnt], 500)); - } - - TEST_ESP_OK(twai_node_disable(node_hdl)); - for (uint8_t i = 3; i > 0; i--) { - printf("interrupted, %d sec\n", i); - vTaskDelay(1000); - } - printf("continuing ...\n"); - TEST_ESP_OK(twai_node_enable(node_hdl)); - - //waiting pkg receive finish - while (rx_frame.buffer < recv_pkg_ptr + TEST_TRANS_LEN) { - vTaskDelay(1); - } - free(tx_msgs); - - // check if pkg receive correct - printf("pkg check %s!!\n", memcmp(recv_pkg_ptr, send_pkg_ptr, TEST_TRANS_LEN) ? "failed" : "ok"); - TEST_ASSERT_EQUAL_HEX8_ARRAY(send_pkg_ptr, recv_pkg_ptr, TEST_TRANS_LEN); - - free(send_pkg_ptr); - free(recv_pkg_ptr); - TEST_ESP_OK(twai_node_disable(node_hdl)); - TEST_ESP_OK(twai_node_delete(node_hdl)); -} - -static void test_random_trans_generator(twai_node_handle_t node_hdl, uint32_t trans_num) -{ - uint8_t send_pkg_ptr[TWAIFD_FRAME_MAX_LEN]; - twai_frame_t tx_msg = { - .buffer = send_pkg_ptr, - }; - printf("Sending %ld random trans ...\n", trans_num); - for (uint32_t tx_cnt = 0; tx_cnt < trans_num; tx_cnt++) { - tx_msg.header.id = tx_cnt | 0xf000; - tx_msg.header.ide = !!(tx_cnt % 2); - tx_msg.header.rtr = !!(tx_cnt % 3); - tx_msg.header.fdf = !!(tx_cnt % 5); - tx_msg.buffer_len = tx_msg.header.fdf ? (tx_cnt % TWAIFD_FRAME_MAX_LEN) : (tx_cnt % TWAI_FRAME_MAX_LEN); - TEST_ESP_OK(twai_node_transmit(node_hdl, &tx_msg, 0)); - vTaskDelay(8); //as async transaction, waiting trans done - } -} - -static bool test_filter_rx_done_cb(twai_node_handle_t handle, const twai_rx_done_event_data_t *edata, void *user_ctx) -{ - uint8_t *test_ctrl = user_ctx; - size_t ret_len; - uint8_t recv_pkg_ptr[TWAIFD_FRAME_MAX_LEN]; - twai_frame_t rx_frame = { - .buffer = recv_pkg_ptr, - .buffer_len = TWAIFD_FRAME_MAX_LEN, - }; - if (ESP_OK == twai_node_receive_from_isr(handle, &rx_frame.header, rx_frame.buffer, rx_frame.buffer_len, &ret_len)) { - ESP_EARLY_LOGI("twai", "RX id 0x%4x len %2d ext %d rmt %d fd %d", rx_frame.header.id, ret_len, rx_frame.header.ide, rx_frame.header.rtr, rx_frame.header.fdf); - switch (test_ctrl[0]) { - case 0: //filter 0 - TEST_ASSERT(rx_frame.header.id >= 0x10); - TEST_ASSERT(!rx_frame.header.ide); - break; - case 1: - case 2: break; - case 3: //filter 1 - TEST_ASSERT((rx_frame.header.id & 0xfff0) == 0xf000); - TEST_ASSERT(rx_frame.header.ide && !rx_frame.header.fdf); - break; - case 4: //range filter 0 - TEST_ASSERT(!rx_frame.header.ide && rx_frame.header.fdf); - break; - default: TEST_ASSERT(false); - } - test_ctrl[1] ++; - } - return false; -} - -TEST_CASE("twai filter (loopback)", "[TWAI]") -{ - uint8_t test_ctrl[2]; - twai_node_handle_t node_hdl; - twai_onchip_node_config_t node_config = { - .io_cfg.tx = TEST_TX_GPIO, - .io_cfg.rx = TEST_TX_GPIO, // Using same pin for test without transceiver - .bit_timing.bitrate = 1000000, - .tx_queue_depth = TEST_TWAI_QUEUE_DEPTH, - .flags.enable_loopback = true, - .flags.enable_self_test = true, - }; - TEST_ESP_OK(twai_new_node_onchip(&node_config, &node_hdl)); - - twai_event_callbacks_t user_cbs = { - .on_rx_done = test_filter_rx_done_cb, - }; - TEST_ESP_OK(twai_node_register_event_callbacks(node_hdl, &user_cbs, test_ctrl)); - - //------------------ Filter 0 -------------------// - test_ctrl[0] = 0; - test_ctrl[1] = 0; - printf("Testing mask filter 0\n"); - twai_mask_filter_config_t mfilter_cfg0 = { - .id = 0x10, - .mask = 0xf0, - .is_ext = false, - }; - TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0)); - TEST_ESP_OK(twai_node_enable(node_hdl)); - test_random_trans_generator(node_hdl, 30); - TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]); //after filter, rx frame should less than tx num - - printf("Change to receive ALL\n"); - test_ctrl[0] = 1; - test_ctrl[1] = 0; - // set to receive ALL - mfilter_cfg0.id = 0; - mfilter_cfg0.mask = 0; - TEST_ESP_OK(twai_node_disable(node_hdl)); - TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0)); - TEST_ESP_OK(twai_node_enable(node_hdl)); - test_random_trans_generator(node_hdl, 30); - TEST_ASSERT_EQUAL(30, test_ctrl[1]); - - printf("Change to receive NONE\n"); - test_ctrl[0] = 2; - test_ctrl[1] = 0; - // set to receive NONE - mfilter_cfg0.id = 0xFFFFFFFF; - mfilter_cfg0.mask = 0xFFFFFFFF; - TEST_ESP_OK(twai_node_disable(node_hdl)); - TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 0, &mfilter_cfg0)); - TEST_ESP_OK(twai_node_enable(node_hdl)); - test_random_trans_generator(node_hdl, 30); - TEST_ASSERT_EQUAL(0, test_ctrl[1]); - - //------------------ Filter 1 -------------------// - test_ctrl[0] = 3; - test_ctrl[1] = 0; - printf("Testing mask filter 1\n"); - twai_mask_filter_config_t mfilter_cfg1 = { - .id = 0xf000, - .mask = 0xfff0, - .is_ext = true, - .no_fd = true, - }; - TEST_ESP_OK(twai_node_disable(node_hdl)); - TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 1, &mfilter_cfg1)); - TEST_ESP_OK(twai_node_enable(node_hdl)); - test_random_trans_generator(node_hdl, 30); - TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]); - // set to receive NONE - mfilter_cfg1.id = 0xFFFFFFFF; - mfilter_cfg1.mask = 0xFFFFFFFF; - TEST_ESP_OK(twai_node_disable(node_hdl)); - TEST_ESP_OK(twai_node_config_mask_filter(node_hdl, 1, &mfilter_cfg1)); - - //------------------ Range Filter 0 -------------------// - test_ctrl[0] = 4; - test_ctrl[1] = 0; - printf("Testing range filter 0\n"); - twai_range_filter_config_t rfilter_cfg0 = { - .range_low = 0, - .range_high = 0xFFFFFFFF, - .is_ext = false, - .no_classic = true, - }; - TEST_ESP_OK(twai_node_config_range_filter(node_hdl, 0, &rfilter_cfg0)); - TEST_ESP_OK(twai_node_enable(node_hdl)); - test_random_trans_generator(node_hdl, 30); - TEST_ASSERT_UINT8_WITHIN(30 / 2 - 1, 30 / 2, test_ctrl[1]); - - TEST_ESP_OK(twai_node_disable(node_hdl)); - TEST_ESP_OK(twai_node_delete(node_hdl)); -}