diff --git a/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml b/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml new file mode 100644 index 0000000000..ff1dc3e64c --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/.build-test-rules.yml @@ -0,0 +1,10 @@ +components/esp_driver_touch_sens/test_apps/touch_sens: + disable: + - if: SOC_TOUCH_SENSOR_VERSION != 3 + temporary: currently driver ng only support version 3 + disable_test: + - if: IDF_TARGET == "esp32p4" + temporary: true + reason: the runners do not support the pins for touch sensor + depends_components: + - esp_driver_touch_sens diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/CMakeLists.txt b/components/esp_driver_touch_sens/test_apps/touch_sens/CMakeLists.txt new file mode 100644 index 0000000000..e774828c4d --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/CMakeLists.txt @@ -0,0 +1,22 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(COMPONENTS main) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(touch_sens) + +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_touch_sens/,${CMAKE_BINARY_DIR}/esp-idf/hal/ + --elf-file ${CMAKE_BINARY_DIR}/touch_sens.elf + find-refs + --from-sections=.iram0.text + --to-sections=.flash.text,.flash.rodata + --exit-code + DEPENDS ${elf} + ) +endif() diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/README.md b/components/esp_driver_touch_sens/test_apps/touch_sens/README.md new file mode 100644 index 0000000000..f8ea707124 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/README.md @@ -0,0 +1,3 @@ +| Supported Targets | ESP32-P4 | +| ----------------- | -------- | + diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt b/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt new file mode 100644 index 0000000000..97285a1122 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/CMakeLists.txt @@ -0,0 +1,6 @@ +set(srcs "test_app_main.c" "test_touch_sens_common.c") + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + PRIV_REQUIRES unity esp_driver_touch_sens + WHOLE_ARCHIVE) diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_app_main.c b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_app_main.c new file mode 100644 index 0000000000..a7498bd1eb --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_app_main.c @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_runner.h" +#include "esp_heap_caps.h" + +// Some resources are lazy allocated in Touch Sensor driver, the threshold is left for that case +#define TEST_MEMORY_LEAK_THRESHOLD (-300) + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + // _____ _ ____ _____ _ + // |_ _|__ _ _ ___| |__ / ___| ___ _ __ ___ ___ _ __ |_ _|__ ___| |_ + // | |/ _ \| | | |/ __| '_ \ \___ \ / _ \ '_ \/ __|/ _ \| '__| | |/ _ \/ __| __| + // | | (_) | |_| | (__| | | | ___) | __/ | | \__ \ (_) | | | | __/\__ \ |_ + // |_|\___/ \__,_|\___|_| |_| |____/ \___|_| |_|___/\___/|_| |_|\___||___/\__| + + printf(" _____ _ ____ _____ _ \n"); + printf(" |_ _|__ _ _ ___| |__ / ___| ___ _ __ ___ ___ _ __ |_ _|__ ___| |_ \n"); + printf(" | |/ _ \\| | | |/ __| '_ \\ \\___ \\ / _ \\ '_ \\/ __|/ _ \\| '__| | |/ _ \\/ __| __|\n"); + printf(" | | (_) | |_| | (__| | | | ___) | __/ | | \\__ \\ (_) | | | | __/\\__ \\ |_ \n"); + printf(" |_|\\___/ \\__,_|\\___|_| |_| |____/ \\___|_| |_|___/\\___/|_| |_|\\___||___/\\__|\n"); + + unity_run_menu(); +} diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c new file mode 100644 index 0000000000..8dda1d8d6a --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/main/test_touch_sens_common.c @@ -0,0 +1,198 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "driver/touch_sens.h" +#include "hal/touch_sensor_ll.h" +#include "esp_log.h" +#include "esp_attr.h" + +static touch_sensor_sample_config_t s_sample_cfg[TOUCH_SAMPLE_CFG_NUM] = { + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG0(), +#if TOUCH_SAMPLE_CFG_NUM > 1 + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG1(), +#endif +#if TOUCH_SAMPLE_CFG_NUM > 2 + TOUCH_SENSOR_DEFAULT_SAMPLE_CONFIG2(), +#endif +}; + +static touch_channel_config_t s_chan_cfg = { + .active_thresh = { + 5000, +#if TOUCH_SAMPLE_CFG_NUM > 1 + 2500, +#endif +#if TOUCH_SAMPLE_CFG_NUM > 2 + 1000, +#endif + }, +}; + +TEST_CASE("touch_sens_install_uninstall_test", "[touch]") +{ + touch_sensor_handle_t touch = NULL; + touch_channel_handle_t touch_chan[TOUCH_TOTAL_CHAN_NUM] = {NULL}; + + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(TOUCH_SAMPLE_CFG_NUM, s_sample_cfg); + /* Allocate new controller */ + TEST_ESP_OK(touch_sensor_new_controller(&sens_cfg, &touch)); + TEST_ASSERT(touch_sensor_new_controller(&sens_cfg, &touch) == ESP_ERR_INVALID_STATE); + /* Configuring the filter */ + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + TEST_ESP_OK(touch_sensor_config_filter(touch, &filter_cfg)); + + for (int i = 0; i < TOUCH_TOTAL_CHAN_NUM; i++) { + TEST_ESP_OK(touch_sensor_new_channel(touch, i, &s_chan_cfg, &touch_chan[i])); + } + touch_channel_handle_t fault_chan = NULL; + TEST_ASSERT(touch_sensor_new_channel(touch, TOUCH_TOTAL_CHAN_NUM, &s_chan_cfg, &fault_chan) == ESP_ERR_INVALID_ARG); + TEST_ASSERT(touch_sensor_new_channel(touch, 0, &s_chan_cfg, &fault_chan) == ESP_ERR_INVALID_STATE); + + TEST_ESP_OK(touch_sensor_enable(touch)); + TEST_ASSERT(touch_sensor_del_channel(touch_chan[0]) == ESP_ERR_INVALID_STATE); + TEST_ESP_OK(touch_sensor_disable(touch)); + + TEST_ASSERT(touch_sensor_del_controller(touch) == ESP_ERR_INVALID_STATE); + + for (int i = 0; i < TOUCH_TOTAL_CHAN_NUM; i++) { + TEST_ESP_OK(touch_sensor_del_channel(touch_chan[i])); + } + TEST_ESP_OK(touch_sensor_del_controller(touch)); +} + +typedef struct { + int active_count; + int inactive_count; +} test_touch_cb_data_t; + +static touch_channel_config_t s_test_get_chan_cfg_by_benchmark(uint32_t benchmark[], uint32_t num, float coeff) +{ + touch_channel_config_t chan_cfg = {}; + for (int i = 0; i < num; i++) { + chan_cfg.active_thresh[i] = benchmark[i] * coeff; + printf("[Sampler %d] benchmark %5"PRIu32" thresh %4"PRIu32"\n", + i, benchmark[i], chan_cfg.active_thresh[i]); + } + return chan_cfg; +} + +static void s_test_touch_do_initial_scanning(touch_sensor_handle_t touch, int scan_times) +{ + /* Enable the touch sensor to do the initial scanning, so that to initialize the channel data */ + TEST_ESP_OK(touch_sensor_enable(touch)); + /* Scan the enabled touch channels for several times, to make sure the initial channel data is stable */ + for (int i = 0; i < scan_times; i++) { + TEST_ESP_OK(touch_sensor_trigger_oneshot_scanning(touch, 2000)); + } + /* Disable the touch channel to rollback the state */ + TEST_ESP_OK(touch_sensor_disable(touch)); +} + +#if CONFIG_TOUCH_ISR_IRAM_SAFE +#define TEST_TCH_IRAM_ATTR IRAM_ATTR +#else +#define TEST_TCH_IRAM_ATTR +#endif + +static bool TEST_TCH_IRAM_ATTR s_test_touch_on_active_callback(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) +{ + ESP_EARLY_LOGI("touch_callback", "[CH %d] active", (int)event->chan_id); + test_touch_cb_data_t *cb_data = (test_touch_cb_data_t *)user_ctx; + cb_data->active_count++; + return false; +} + +static bool TEST_TCH_IRAM_ATTR s_test_touch_on_inactive_callback(touch_sensor_handle_t sens_handle, const touch_inactive_event_data_t *event, void *user_ctx) +{ + ESP_EARLY_LOGI("touch_callback", "[CH %d] inactive", (int)event->chan_id); + test_touch_cb_data_t *cb_data = (test_touch_cb_data_t *)user_ctx; + cb_data->inactive_count++; + return false; +} + +static void s_test_touch_simulate_touch(touch_sensor_handle_t touch, touch_channel_handle_t touch_chan, bool active) +{ + touch_ll_set_internal_capacitor(active ? 0x7f : 0); +} + +static void s_test_touch_log_data(touch_channel_handle_t touch_chan, uint32_t sample_cfg_num, const char *tag) +{ + uint32_t data[sample_cfg_num]; + TEST_ESP_OK(touch_channel_read_data(touch_chan, TOUCH_CHAN_DATA_TYPE_SMOOTH, data)); + printf("%s:", tag); + for (int i = 0; i < sample_cfg_num; i++) { + printf(" %"PRIu32, data[i]); + } + printf("\n"); +} + +#define TEST_ACTIVE_THRESH_RATIO (0.01f) + +TEST_CASE("touch_sens_active_inactive_test", "[touch]") +{ + touch_sensor_handle_t touch = NULL; + touch_channel_handle_t touch_chan = NULL; + + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(TOUCH_SAMPLE_CFG_NUM, s_sample_cfg); + TEST_ESP_OK(touch_sensor_new_controller(&sens_cfg, &touch)); + + /* Configuring the filter */ + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + TEST_ESP_OK(touch_sensor_config_filter(touch, &filter_cfg)); + TEST_ESP_OK(touch_sensor_new_channel(touch, 0, &s_chan_cfg, &touch_chan)); + /* Connect the touch channels to the internal capacitor */ + touch_ll_enable_internal_capacitor(true); + + s_test_touch_do_initial_scanning(touch, 3); + + /* Read benchmark */ + uint32_t benchmark[TOUCH_SAMPLE_CFG_NUM] = {0}; + TEST_ESP_OK(touch_channel_read_data(touch_chan, TOUCH_CHAN_DATA_TYPE_BENCHMARK, benchmark)); + /* Re-configure the threshold according to the benchmark */ + touch_channel_config_t chan_cfg = s_test_get_chan_cfg_by_benchmark(benchmark, TOUCH_SAMPLE_CFG_NUM, TEST_ACTIVE_THRESH_RATIO); + TEST_ESP_OK(touch_sensor_reconfig_channel(touch_chan, &chan_cfg)); + + touch_event_callbacks_t callbacks = { + .on_active = s_test_touch_on_active_callback, + .on_inactive = s_test_touch_on_inactive_callback, + }; + test_touch_cb_data_t cb_data = {}; + TEST_ESP_OK(touch_sensor_register_callbacks(touch, &callbacks, &cb_data)); + + TEST_ESP_OK(touch_sensor_enable(touch)); + TEST_ESP_OK(touch_sensor_start_continuous_scanning(touch)); + vTaskDelay(pdMS_TO_TICKS(20)); + + int touch_cnt = 3; + for (int i = 0; i < touch_cnt; i++) { + printf("\nSimulate Touch [%d] ->\n--------------------------\n", i + 1); + // Read data before touched + s_test_touch_log_data(touch_chan, TOUCH_SAMPLE_CFG_NUM, "Data Before"); + // Simulate touch + s_test_touch_simulate_touch(touch, touch_chan, true); + vTaskDelay(pdMS_TO_TICKS(50)); + + // Read data after touched + s_test_touch_log_data(touch_chan, TOUCH_SAMPLE_CFG_NUM, "Data After "); + // Simulate release + s_test_touch_simulate_touch(touch, touch_chan, false); + vTaskDelay(pdMS_TO_TICKS(50)); + } + printf("\n"); + + TEST_ESP_OK(touch_sensor_stop_continuous_scanning(touch)); + TEST_ESP_OK(touch_sensor_disable(touch)); + TEST_ESP_OK(touch_sensor_del_channel(touch_chan)); + TEST_ESP_OK(touch_sensor_del_controller(touch)); + + /* Check the callback count */ + TEST_ASSERT_EQUAL_INT32(touch_cnt, cb_data.active_count); + TEST_ASSERT_EQUAL_INT32(touch_cnt, cb_data.inactive_count); +} diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py b/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py new file mode 100644 index 0000000000..871cdb6baf --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/pytest_touch_sens.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.esp32p4 +@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='esp32p4 runners do not support touch pins') +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'release', + 'iram_safe', + ], + indirect=True, +) +def test_touch_sens(dut: Dut) -> None: + dut.run_all_single_board_cases() diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.iram_safe b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.iram_safe new file mode 100644 index 0000000000..e8074e7fa8 --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.iram_safe @@ -0,0 +1,7 @@ +CONFIG_COMPILER_DUMP_RTL_FILES=y +CONFIG_TOUCH_CTRL_FUNC_IN_IRAM=y +CONFIG_TOUCH_ISR_IRAM_SAFE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y +CONFIG_COMPILER_OPTIMIZATION_NONE=y +# silent the error check, as the error string are stored in rodata, causing RTL check failure +CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.release b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.release new file mode 100644 index 0000000000..91d93f163e --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.ci.release @@ -0,0 +1,5 @@ +CONFIG_PM_ENABLE=y +CONFIG_FREERTOS_USE_TICKLESS_IDLE=y +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults new file mode 100644 index 0000000000..b308cb2ddd --- /dev/null +++ b/components/esp_driver_touch_sens/test_apps/touch_sens/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP_TASK_WDT=n