ci(touch): add test cases for cap touch sens driver

This commit is contained in:
laokaiyao 2024-06-07 17:22:12 +08:00
parent 865e3ee2de
commit b09a7a922d
10 changed files with 325 additions and 0 deletions

View File

@ -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

View File

@ -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()

View File

@ -0,0 +1,3 @@
| Supported Targets | ESP32-P4 |
| ----------------- | -------- |

View File

@ -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)

View File

@ -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();
}

View File

@ -0,0 +1,198 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#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);
}

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,2 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT=n