Ver código fonte

Merge branch 'feature/touch_sense_test_case' into 'master'

touch_element: add unit test for touch element lib

Closes IDF-2667

See merge request espressif/esp-idf!11825
Michael (XIAO Xufeng) 4 anos atrás
pai
commit
7357d777e3

+ 7 - 0
components/touch_element/test/CMakeLists.txt

@@ -0,0 +1,7 @@
+if(IDF_TARGET STREQUAL "esp32s2")
+    idf_component_register(SRCS "test_touch_element.c"
+                                "test_touch_button.c"
+                                "test_touch_slider.c"
+                                "test_touch_matrix.c"
+            PRIV_REQUIRES unity touch_element)
+endif()

+ 5 - 0
components/touch_element/test/component.mk

@@ -0,0 +1,5 @@
+#
+# Component Makefile
+#
+# Touch Element lib is not supported in GNU Make build system
+COMPONENT_CONFIG_ONLY := 1

+ 570 - 0
components/touch_element/test/test_touch_button.c

@@ -0,0 +1,570 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+#include "unity.h"
+
+#include "touch_element/touch_element_private.h"
+#include "touch_element/touch_button.h"
+
+static portMUX_TYPE test_button_spinlock = portMUX_INITIALIZER_UNLOCKED;
+#define TEST_BUTTON_ENTER_CRITICAL()       portENTER_CRITICAL(&test_button_spinlock)
+#define TEST_BUTTON_EXIT_CRITICAL()        portEXIT_CRITICAL(&test_button_spinlock)
+
+static const touch_pad_t button_channel_array[14] = {
+    TOUCH_PAD_NUM1,
+    TOUCH_PAD_NUM2,
+    TOUCH_PAD_NUM3,
+    TOUCH_PAD_NUM4,
+    TOUCH_PAD_NUM5,
+    TOUCH_PAD_NUM6,
+    TOUCH_PAD_NUM7,
+    TOUCH_PAD_NUM8,
+    TOUCH_PAD_NUM9,
+    TOUCH_PAD_NUM10,
+    TOUCH_PAD_NUM11,
+    TOUCH_PAD_NUM12,
+    TOUCH_PAD_NUM13,
+    TOUCH_PAD_NUM14,
+};
+const uint8_t BUTTON_CHANNEL_NUM = sizeof(button_channel_array) / sizeof(touch_pad_t);
+
+typedef struct {
+    QueueHandle_t valid_msg_handle;
+    SemaphoreHandle_t response_sig_handle;
+} test_monitor_t;
+
+typedef struct {
+    QueueHandle_t valid_msg_handle;
+    SemaphoreHandle_t response_sig_handle;
+    touch_button_handle_t button_handle;
+} test_concurrent_monitor_t;
+
+/* ------------------------------------------------------------------------------------------------------------------ */
+void test_button_event_simulator(touch_button_handle_t button_handle, touch_button_event_t button_event);
+void test_button_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);
+static void test_button_callback_check(touch_button_handle_t current_handle, touch_button_message_t *current_message, touch_elem_message_t *valid_message);
+void test_button_event_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event);
+void test_button_callback_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event, bool should_trigger, test_monitor_t *monitor);
+/* ------------------------------------------------ Dispatch method test -------------------------------------------- */
+static void test_button_disp_event(void);
+static void test_button_disp_callback(void);
+void test_button_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);
+/* ------------------------------------------------ Run-time test --------------------------------------------------- */
+static void test_button_event_change_lp(void);
+static void test_button_callback_change_lp(void);
+static void test_button_change_lp_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);
+/* ------------------------------------------------ Concurrent test ------------------------------------------------- */
+static void test_button_event_concurrent(void);
+static void test_button_random_trigger_concurrent(void);
+void test_random_trigger_concurrent_task(void *arg);
+static void random_trigger_concurrent_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);
+/* ------------------------------------------------------------------------------------------------------------------ */
+
+TEST_CASE("Touch button dispatch methods test", "[button][touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_button_disp_event();
+    test_button_disp_callback();
+    touch_element_uninstall();
+}
+
+TEST_CASE("Touch button run-time test", "[button][touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_button_event_change_lp();
+    test_button_callback_change_lp();
+    touch_element_uninstall();
+}
+
+TEST_CASE("Touch button concurrent test", "[button][touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_button_event_concurrent();
+    test_button_random_trigger_concurrent();
+    touch_element_uninstall();
+}
+
+void test_button_event_simulator(touch_button_handle_t button_handle, touch_button_event_t button_event)
+{
+    te_button_handle_t te_button = (te_button_handle_t) button_handle;
+    touch_pad_t channel = te_button->device->channel;
+    if (button_event == TOUCH_BUTTON_EVT_ON_PRESS) {
+        touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);
+    } else if (button_event == TOUCH_BUTTON_EVT_ON_RELEASE) {
+        touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT);
+    } else {
+        touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);  //LongPress
+    }
+}
+
+void test_button_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message)
+{
+    TEST_ASSERT_MESSAGE(current_message->handle == valid_message->handle, "check handle failed");
+    TEST_ASSERT_MESSAGE(current_message->element_type == valid_message->element_type, "check element type failed");
+    const touch_button_message_t *valid_button_message = touch_button_get_message(valid_message);
+    const touch_button_message_t *current_button_message = touch_button_get_message(current_message);
+    TEST_ASSERT_MESSAGE(current_button_message->event == valid_button_message->event, "check event failed");
+}
+
+static void test_button_callback_check(touch_button_handle_t current_handle, touch_button_message_t *current_message, touch_elem_message_t *valid_message)
+{
+    const touch_button_message_t *valid_button_message = touch_button_get_message(valid_message);
+    TEST_ASSERT_MESSAGE(valid_message->handle == current_handle, "check handle failed");
+    TEST_ASSERT_MESSAGE(valid_message->element_type == TOUCH_ELEM_TYPE_BUTTON, "check element type failed");
+    TEST_ASSERT_MESSAGE(valid_button_message->event == current_message->event, "check event failed");
+}
+
+void test_button_event_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event)
+{//TODO: refactor this with a constructor
+    touch_elem_message_t valid_message = {
+        .handle = handle,
+        .element_type = TOUCH_ELEM_TYPE_BUTTON,
+        .arg = NULL,
+    };
+    touch_button_message_t button_message = {
+        .event = button_event
+    };
+    memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message
+
+    test_button_event_simulator(handle, button_event);  //Trigger signal
+
+    touch_elem_message_t current_message;
+    te_button_handle_t te_button = handle;
+    esp_err_t ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(2 * te_button->trigger_thr * 10));
+    TEST_ASSERT_MESSAGE(ret == ESP_OK, "button event receive timeout");
+
+    test_button_event_check(&valid_message, &current_message);  //Verification
+}
+
+void test_button_callback_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event, bool should_trigger, test_monitor_t *monitor)
+{
+    if (should_trigger) {
+        touch_elem_message_t valid_message = {
+            .handle = handle,
+            .element_type = TOUCH_ELEM_TYPE_BUTTON,
+            .arg = NULL
+        };
+        touch_button_message_t button_message = {
+            .event = button_event
+        };
+        memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message
+        xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
+    }
+
+    test_button_event_simulator(handle, button_event);  //Trigger signal
+
+    te_button_handle_t te_button = handle;
+    if (should_trigger) { //Verification
+        BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(2 * te_button->trigger_thr * 10));
+        TEST_ASSERT_MESSAGE(os_ret == pdPASS, "Button queue timeout");
+    } else {
+        BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(500));
+        TEST_ASSERT_MESSAGE(os_ret == pdFALSE, "Button invalid trigger");
+    }
+}
+
+static void test_button_disp_event(void)
+{
+    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
+    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_button_install(&global_config));
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        touch_button_config_t button_config = {
+            .channel_num = button_channel_array[i],
+            .channel_sens = 0.1F
+        };
+        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
+        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i],
+                    TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,
+                    (void *) button_channel_array[i]));
+        TEST_ESP_OK(touch_button_set_longpress(button_handle[i], 300));
+        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));
+    }
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    //10 times random press/longpress/release test
+    printf("Touch button event test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch button event test... (%d/10)\n", i + 1);
+        touch_button_handle_t current_handle = button_handle[random() % 14];
+        test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS);
+        test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_LONGPRESS);
+        test_button_event_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE);
+    }
+    printf("Touch button event test finish\n");
+    TEST_ESP_OK(touch_element_stop());
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        TEST_ESP_OK(touch_button_delete(button_handle[i]));
+    }
+    touch_button_uninstall();
+}
+
+static void test_button_disp_callback(void)
+{
+    test_monitor_t monitor;
+    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
+    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
+    monitor.response_sig_handle = xSemaphoreCreateBinary();
+    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
+
+    touch_button_global_config_t button_init = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_button_install(&button_init));
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        touch_button_config_t button_config = {
+            .channel_num = button_channel_array[i],
+            .channel_sens = 0.1F
+        };
+        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
+        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i],
+                    TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE | TOUCH_ELEM_EVENT_ON_LONGPRESS,
+                    (void *) &monitor));
+        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));
+        TEST_ESP_OK(touch_button_set_callback(button_handle[i], &test_button_handler));
+        TEST_ESP_OK(touch_button_set_longpress(button_handle[i], 300));
+    }
+    TEST_ESP_OK(touch_element_start());
+
+    srandom((unsigned int)time(NULL));
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+    //10 times random press/longpress/release test
+    printf("Touch button callback test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch button callback test... (%d/10)\n", i + 1);
+        touch_button_handle_t current_handle = button_handle[random() % 14];
+        test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, true, &monitor);
+        test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_LONGPRESS, true, &monitor);
+        test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, true, &monitor);
+    }
+    printf("Touch button callback test finish\n");
+    TEST_ESP_OK(touch_element_stop());
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        TEST_ESP_OK(touch_button_delete(button_handle[i]));
+    }
+    touch_button_uninstall();
+    vQueueDelete(monitor.valid_msg_handle);
+    vSemaphoreDelete(monitor.response_sig_handle);
+}
+
+void test_button_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)
+{
+    test_monitor_t *monitor = (test_monitor_t *)arg;
+    touch_elem_message_t valid_message;
+    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));  //Get the valid message for the verification, 500ms timeout
+    TEST_ASSERT_MESSAGE(os_ret == pdPASS, "test_button_handler: queue timeout");
+    test_button_callback_check(handle, message, &valid_message);
+    xSemaphoreGive(monitor->response_sig_handle);
+}
+
+static void test_button_event_change_lp(void)
+{
+    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
+    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_button_install(&global_config));
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        touch_button_config_t button_config = {
+            .channel_num = button_channel_array[i],
+            .channel_sens = 0.1F
+        };
+        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
+        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_LONGPRESS, NULL));
+        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));
+    }
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    //10 times random press/longpress/release test
+    printf("Touch button event change longtime test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch button event change longtime test... (%d/10)\n", i + 1);
+        esp_err_t ret;
+        uint8_t channel_index = random() % BUTTON_CHANNEL_NUM;
+        touch_elem_message_t valid_message = {
+            .handle = button_handle[channel_index],
+            .element_type = TOUCH_ELEM_TYPE_BUTTON,
+            .arg = NULL
+        };
+        touch_button_message_t button_message = {
+            .event = TOUCH_BUTTON_EVT_ON_LONGPRESS
+        };
+        memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message
+
+        TEST_ESP_OK(touch_button_set_longpress(valid_message.handle, 200 + (i + 1) * 50));
+        test_button_event_simulator(valid_message.handle, button_message.event);  //Trigger signal
+
+        touch_elem_message_t current_message;
+        ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(10 * 1000));
+        TEST_ASSERT_MESSAGE(ret == ESP_OK, "button event LongPress timeout");
+        test_button_event_check(&valid_message, &current_message);  //Verification
+
+        test_button_event_simulator(valid_message.handle, TOUCH_BUTTON_EVT_ON_RELEASE); //Release the button.
+    }
+    printf("Touch button event change longtime test finish\n");
+    TEST_ESP_OK(touch_element_stop());
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        TEST_ESP_OK(touch_button_delete(button_handle[i]));
+    }
+    touch_button_uninstall();
+}
+
+static void test_button_callback_change_lp(void)
+{
+    test_monitor_t monitor;
+    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
+    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
+    monitor.response_sig_handle = xSemaphoreCreateBinary();
+    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
+
+    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_button_install(&global_config));
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        touch_button_config_t button_config = {
+            .channel_num = button_channel_array[i],
+            .channel_sens = 0.1F
+        };
+        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
+        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_LONGPRESS, (void *)&monitor));
+        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));
+        TEST_ESP_OK(touch_button_set_callback(button_handle[i], &test_button_change_lp_handler));
+    }
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    //10 times random press/longpress/release test
+    printf("Touch button event change longtime test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch button event change longtime test... (%d/10)\n", i + 1);
+        uint8_t channel_index = 5;  //Always this channel
+        touch_elem_message_t valid_message = {
+            .handle = button_handle[channel_index],
+            .element_type = TOUCH_ELEM_TYPE_BUTTON,
+            .arg = NULL,
+        };
+        touch_button_message_t button_message = {
+            .event = TOUCH_BUTTON_EVT_ON_LONGPRESS
+        };
+        memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message
+
+        xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);
+        test_button_event_simulator(button_handle[channel_index], button_message.event);
+
+        BaseType_t os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(10 * 1000)); //100ms timeout
+        TEST_ASSERT_MESSAGE(os_ret == pdPASS, "Button LongPress queue timeout");
+        test_button_event_simulator(valid_message.handle, TOUCH_BUTTON_EVT_ON_RELEASE); //Reset hardware
+    }
+    printf("Touch button event change longtime test finish\n");
+    TEST_ESP_OK(touch_element_stop());
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        TEST_ESP_OK(touch_button_delete(button_handle[i]));
+    }
+    touch_button_uninstall();
+}
+
+static void test_button_change_lp_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)
+{
+    test_monitor_t *monitor = (test_monitor_t *)arg;
+    touch_elem_message_t valid_message;
+    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));  //Get the valid message for the verification, 500ms timeout
+    TEST_ASSERT_MESSAGE(os_ret == pdPASS, "test_button_handler: queue timeout");
+    test_button_callback_check(handle, message, &valid_message);
+    xSemaphoreGive(monitor->response_sig_handle);
+    TEST_ESP_OK(touch_button_set_longpress(valid_message.handle, 300)); // Always 300ms
+}
+
+static void test_button_event_concurrent(void)
+{
+    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
+    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_button_install(&global_config));
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        touch_button_config_t button_config = {
+            .channel_num = button_channel_array[i],
+            .channel_sens = 0.1F
+        };
+        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
+        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));
+        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));
+    }
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    //10 times random press/longpress/release test
+    printf("Touch button event concurrent test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch button event concurrent test... (%d/10)\n", i + 1);
+        esp_err_t ret;
+        uint32_t message_count = 0;
+        touch_elem_message_t current_message;
+
+        TEST_BUTTON_ENTER_CRITICAL();
+        for (int idx = 0; idx < BUTTON_CHANNEL_NUM; idx++) {
+            test_button_event_simulator(button_handle[idx], TOUCH_BUTTON_EVT_ON_PRESS);  //All channels trigger
+        }
+        TEST_BUTTON_EXIT_CRITICAL();
+        message_count = 0;
+        do {
+            ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(500));
+            if (ret == ESP_OK) {
+                message_count++;
+            }
+        } while (ret == ESP_OK);
+        TEST_ASSERT_MESSAGE(message_count == BUTTON_CHANNEL_NUM, "button concurrent Press failed");
+
+        TEST_BUTTON_ENTER_CRITICAL();
+        for (int idx = 0; idx < BUTTON_CHANNEL_NUM; idx++) {
+            test_button_event_simulator(button_handle[idx], TOUCH_BUTTON_EVT_ON_RELEASE);  //All channels trigger
+        }
+        TEST_BUTTON_EXIT_CRITICAL();
+        message_count = 0;
+        do {
+            ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(500));
+            if (ret == ESP_OK) {
+                message_count++;
+            }
+        } while (ret == ESP_OK);
+        TEST_ASSERT_MESSAGE(message_count == BUTTON_CHANNEL_NUM, "button concurrent Release failed");
+    }
+    printf("Touch button event concurrent test finish\n");
+    TEST_ESP_OK(touch_element_stop());
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        TEST_ESP_OK(touch_button_delete(button_handle[i]));
+    }
+    touch_button_uninstall();
+}
+
+static void test_button_random_trigger_concurrent(void)
+{
+    uint64_t sem_and_monitor[BUTTON_CHANNEL_NUM];
+    printf("Touch button random trigger concurrent test start\n");
+    test_concurrent_monitor_t monitor[BUTTON_CHANNEL_NUM];
+
+    SemaphoreHandle_t count_sem = xSemaphoreCreateCounting(BUTTON_CHANNEL_NUM, 0);
+
+    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_button_install(&global_config));
+    for (uint32_t i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        touch_button_config_t button_config = {
+            .channel_num = button_channel_array[i],
+            .channel_sens = 0.1F
+        };
+        monitor[i].response_sig_handle = xSemaphoreCreateBinary();
+        monitor[i].valid_msg_handle = xQueueCreate(BUTTON_CHANNEL_NUM, sizeof(touch_elem_message_t));
+        TEST_ASSERT(monitor[i].valid_msg_handle != NULL && monitor[i].response_sig_handle != NULL);
+        uintptr_t temp_count_sem = (uint32_t)count_sem;
+        uintptr_t temp_monitor = (uint32_t)&monitor[i];  //Prevent compiler warning
+        sem_and_monitor[i] = (uint64_t)(((uint64_t)temp_count_sem << 32) | (uint64_t) temp_monitor);
+        TEST_ESP_OK(touch_button_create(&button_config, &monitor[i].button_handle));
+        TEST_ESP_OK(touch_button_subscribe_event(monitor[i].button_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_LONGPRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *)&sem_and_monitor[i]));
+        TEST_ESP_OK(touch_button_set_longpress(monitor[i].button_handle, 500));
+        TEST_ESP_OK(touch_button_set_dispatch_method(monitor[i].button_handle, TOUCH_ELEM_DISP_CALLBACK));
+        TEST_ESP_OK(touch_button_set_callback(monitor[i].button_handle, &random_trigger_concurrent_handler));
+    }
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    for (uint32_t i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        BaseType_t os_ret = xTaskCreate(test_random_trigger_concurrent_task, "test_random_trigger_concurrent_task", 1024 * 4, (void *)&sem_and_monitor[i], 10, NULL);
+        TEST_ASSERT(os_ret == pdPASS);
+    }
+
+
+    uint32_t run_count = 0;
+    while (1) {
+        if (run_count++ % 1000 == 0) {
+            printf("Touch button random trigger concurrent test running... (1/1)\n");
+        }
+        uint8_t count = uxSemaphoreGetCount(count_sem);
+        if (count == BUTTON_CHANNEL_NUM) {
+            vTaskDelay(1); //Let IDLE task running and get tasks cleanup
+            break;
+        }
+        vTaskDelay(1);
+    }
+
+    TEST_ESP_OK(touch_element_stop());
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        vQueueDelete(monitor[i].valid_msg_handle);
+        vSemaphoreDelete(monitor[i].response_sig_handle);
+        TEST_ESP_OK(touch_button_delete(monitor[i].button_handle));
+    }
+    touch_button_uninstall();
+    printf("Touch button random trigger concurrent test stop\n");
+}
+
+void test_random_trigger_concurrent_task(void *arg)
+{
+    uintptr_t temp_monitor = *((uint32_t *) arg);
+    uintptr_t temp_count_sem = (*((uint64_t *) arg) >> 32);  //Prevent compiler warning
+    test_concurrent_monitor_t *monitor = (test_concurrent_monitor_t *)temp_monitor;
+    SemaphoreHandle_t count_sem = (SemaphoreHandle_t) temp_count_sem;
+    uint32_t start_delay_time = (esp_random() % 100) * 10;
+    vTaskDelay(pdMS_TO_TICKS(start_delay_time));
+
+    touch_elem_message_t valid_message = {
+        .handle = monitor->button_handle,
+        .element_type = TOUCH_ELEM_TYPE_BUTTON,
+        .arg = NULL,
+    };
+    touch_button_message_t button_message;
+    button_message.event = TOUCH_BUTTON_EVT_ON_PRESS;
+    memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message
+    xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
+    test_button_event_simulator(valid_message.handle, button_message.event);  //Trigger signal
+    BaseType_t res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000));
+    TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, "Response timeout");
+
+    uint32_t hold_state_time_ms = (esp_random() % 100) * 10 + 100;
+    te_button_handle_t te_button = (te_button_handle_t) valid_message.handle;
+    if ((int)(hold_state_time_ms - te_button->trigger_thr * 10) > 50) {  //should raise longpress event
+        button_message.event = TOUCH_BUTTON_EVT_ON_LONGPRESS;
+        memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message
+        xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
+        test_button_event_simulator(valid_message.handle, button_message.event);  //Trigger signal
+        res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000)); //+100 make sure it will really raise longpress event
+        TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, "Response timeout");
+    } else { //should not raise longpress event
+        //Do nothing
+    }
+
+    button_message.event = TOUCH_BUTTON_EVT_ON_RELEASE;
+    memcpy(valid_message.child_msg, &button_message, sizeof(touch_button_message_t));  //Construct valid_message
+    xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
+    test_button_event_simulator(valid_message.handle, button_message.event);  //Trigger signal
+    res_sem_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(1000));
+    TEST_ASSERT_MESSAGE(res_sem_ret == pdPASS, "Response timeout");
+
+    xSemaphoreGive(count_sem);
+    vTaskDelete(NULL);
+}
+
+static void random_trigger_concurrent_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg)
+{
+    uintptr_t temp_monitor = *((uint32_t *) arg);  //Prevent compiler warning
+    test_concurrent_monitor_t *monitor = (test_concurrent_monitor_t *) temp_monitor;
+    touch_elem_message_t valid_message;
+    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(1000));
+    TEST_ASSERT_MESSAGE(os_ret == pdPASS, "valid message timeout");
+    const touch_button_message_t *button_message =  touch_button_get_message(&valid_message);
+    if (button_message->event == TOUCH_BUTTON_EVT_ON_LONGPRESS) {
+        touch_button_set_longpress(handle, portMAX_DELAY);  //Prevent button triggers LongPress event again
+    }
+    TEST_ASSERT_MESSAGE(handle == valid_message.handle, "check handle failed");
+    TEST_ASSERT_MESSAGE(valid_message.element_type == TOUCH_ELEM_TYPE_BUTTON, "check element type failed");
+    TEST_ASSERT_MESSAGE(message->event == button_message->event, "check event failed");
+    xSemaphoreGive(monitor->response_sig_handle);
+}

+ 412 - 0
components/touch_element/test/test_touch_element.c

@@ -0,0 +1,412 @@
+/* ---------------------------------------------------------- README ------------------------------------------------
+ *  This doc is aimed at explain some important code block and do some records for the test result, if developer or
+ *  test-owner has some question in reading this code implementation, please read it first.
+ *
+ *  CODE Block:
+ *  `code-block-1`: Touch Element lib need some time to finish the initialization so as to configure the right threshold.
+ *                  Since some hardware issue(Must to pass 2 times "meas_done" interrupt), Touch Element lib will spend
+ *                  some time(Maybe <30ms) to finish the initialization, every operations (interrupts) happen to touch
+ *                  sensor will be ignored before initialization. That's why "vTaskDelay()" could be saw in after call
+ *                  "touch_element_start()". However, this just for the unit test, in the real application, users don't
+ *                  need to delay something.
+ *
+ *  NOTES:
+ *  `Simulator`: Currently the event simulator depend on the touch sensor driver and play some "hack" in some register so
+ *               as to raise a FAKE interrupt. It means that Touch Element lib test case must be burned on dev-kit and keep
+ *               the touch channel as clean as possible, ESP32-S2-Saola is good test board.  //TODO: Remove the dependent of touch sensor driver.
+ ------------------------------------------------------------------------------------------------------------------ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+#include "unity.h"
+
+#include "touch_element/touch_button.h"
+#include "touch_element/touch_slider.h"
+#include "touch_element/touch_matrix.h"
+
+typedef struct {
+    QueueHandle_t valid_msg_handle;
+    SemaphoreHandle_t response_sig_handle;
+} test_monitor_t;
+
+/* ------------------------------------------------------------------------------------------------------------------ */
+extern void test_button_event_simulator(touch_button_handle_t button_handle, touch_button_event_t button_event);
+extern void test_button_handler(touch_button_handle_t handle, touch_button_message_t *message, void *arg);
+extern void test_button_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);
+extern void test_button_event_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event);
+extern void test_button_callback_trigger_and_check(touch_button_handle_t handle, touch_button_event_t button_event, bool should_trigger, test_monitor_t *monitor);
+extern void test_slider_event_simulator(touch_slider_handle_t slider_handle, touch_slider_event_t slider_event, uint32_t random);
+extern void test_slider_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);
+extern void test_matrix_event_simulator(touch_matrix_handle_t matrix_handle, touch_matrix_event_t matrix_event, uint32_t pos_index);
+extern void test_matrix_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);
+/* ------------------------------------------------------------------------------------------------------------------ */
+static void test_waterproof_event_simulator(touch_pad_t guard_channel, touch_button_event_t guard_state);
+static void test_system_waterproof_guard(void);
+static void test_integrat_btn_sld_mat(void);
+static void test_integration_monitor_task(void *arg);
+/* ------------------------------------------------------------------------------------------------------------------ */
+TEST_CASE("Touch element integration test", "[touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_integrat_btn_sld_mat();
+    touch_element_uninstall();
+}
+
+TEST_CASE("Touch element waterproof test", "[touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_system_waterproof_guard(); //TODO: add waterproof work with slider and matrix
+    touch_element_uninstall();
+}
+
+static void test_system_waterproof_guard(void)
+{
+    static const touch_pad_t button_channel_array[12] = {
+        TOUCH_PAD_NUM1,
+        TOUCH_PAD_NUM2,
+        TOUCH_PAD_NUM3,
+        TOUCH_PAD_NUM4,
+        TOUCH_PAD_NUM5,
+        TOUCH_PAD_NUM6,
+        TOUCH_PAD_NUM7,
+        TOUCH_PAD_NUM8,
+        TOUCH_PAD_NUM9,
+        TOUCH_PAD_NUM10,
+        TOUCH_PAD_NUM11,
+        TOUCH_PAD_NUM12
+    };
+    const uint8_t BUTTON_CHANNEL_NUM = sizeof(button_channel_array) / sizeof(touch_pad_t);
+
+    test_monitor_t monitor;
+    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
+    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
+    monitor.response_sig_handle = xSemaphoreCreateBinary();
+    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
+    touch_button_global_config_t global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_button_install(&global_config));
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        touch_button_config_t button_config = {
+            .channel_num = button_channel_array[i],
+            .channel_sens = 0.1F
+        };
+        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
+        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *)&monitor));
+        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_CALLBACK));
+        TEST_ESP_OK(touch_button_set_callback(button_handle[i], test_button_handler));
+    }
+    printf("Touch Element waterproof guard sensor test start\n");
+
+    srandom((unsigned int)time(NULL));
+    {//No use waterproof guard sensor
+        touch_elem_waterproof_config_t waterproof_config = {
+            .guard_channel = TOUCH_WATERPROOF_GUARD_NOUSE,
+            .guard_sensitivity = 0.0F
+        };
+        TEST_ESP_OK(touch_element_waterproof_install(&waterproof_config));
+        TEST_ESP_OK(touch_element_start());
+        vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+        for (int i = 0; i < 10; i++) { //Start state test
+            printf("Touch Element waterproof no-use guard sensor test... (%d/10)\n", i + 1);
+            touch_button_handle_t current_handle = button_handle[random() % 12];
+            test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, true, &monitor);
+            test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, true, &monitor);
+        }
+        TEST_ESP_OK(touch_element_stop());
+        touch_element_waterproof_uninstall();
+    }
+
+    {//Use waterproof guard sensor(Add all handles)
+        touch_elem_waterproof_config_t waterproof_config = {
+            .guard_channel = TOUCH_PAD_NUM13,
+            .guard_sensitivity = 0.1F
+        };
+        TEST_ESP_OK(touch_element_waterproof_install(&waterproof_config));
+        for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+            TEST_ESP_OK(touch_element_waterproof_add(button_handle[i]));
+        }
+        TEST_ESP_OK(touch_element_start());
+        vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+        for (int i = 0; i < 10; i++) {
+            printf("Touch Element waterproof use guard sensor random trigger test... (%d/10)\n", i + 1);
+            bool should_trigger = random() % 2;
+            if (should_trigger) {
+                touch_button_handle_t current_handle = button_handle[random() % 12];
+                test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, should_trigger, &monitor);
+                test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, should_trigger, &monitor);
+            } else {
+                test_waterproof_event_simulator(waterproof_config.guard_channel, TOUCH_BUTTON_EVT_ON_PRESS);  //Waterproof guard sensor trigger
+                touch_button_handle_t current_handle = button_handle[random() % 12];
+                test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, should_trigger, &monitor);
+                test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, should_trigger, &monitor);
+                test_waterproof_event_simulator(waterproof_config.guard_channel, TOUCH_BUTTON_EVT_ON_RELEASE);  //Waterproof guard sensor release
+            }
+        }
+        TEST_ESP_OK(touch_element_stop());
+        touch_element_waterproof_uninstall();
+    }
+
+    {//Put half button handles into guard ring
+        const uint8_t protect_handle_threshold = BUTTON_CHANNEL_NUM / 2;
+        touch_elem_waterproof_config_t waterproof_config = {
+            .guard_channel = TOUCH_PAD_NUM13,
+            .guard_sensitivity = 0.1F
+        };
+        TEST_ESP_OK(touch_element_waterproof_install(&waterproof_config));
+        for (int i = 0; i < protect_handle_threshold; i++) {
+            TEST_ESP_OK(touch_element_waterproof_add(button_handle[i]));
+        }
+        TEST_ESP_OK(touch_element_start());
+        vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+        for (int i = 0; i < 10; i++) {
+            printf("Touch Element waterproof use guard sensor test(guard sensor is triggered will half button handles)... (%d/10)\n", i + 1);
+            test_waterproof_event_simulator(waterproof_config.guard_channel, TOUCH_BUTTON_EVT_ON_PRESS);  //Waterproof guard sensor trigger
+            uint32_t handle_index = random() % 12;
+            touch_button_handle_t current_handle = button_handle[handle_index];
+            bool should_trigger = (handle_index < protect_handle_threshold) ? false : true;
+            test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_PRESS, should_trigger, &monitor);
+            test_button_callback_trigger_and_check(current_handle, TOUCH_BUTTON_EVT_ON_RELEASE, should_trigger, &monitor);
+            test_waterproof_event_simulator(waterproof_config.guard_channel, TOUCH_BUTTON_EVT_ON_RELEASE);  //Waterproof guard sensor release
+        }
+        TEST_ESP_OK(touch_element_stop());
+        touch_element_waterproof_uninstall();
+    }
+
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        TEST_ESP_OK(touch_button_delete(button_handle[i]));
+    }
+    touch_button_uninstall();
+    vQueueDelete(monitor.valid_msg_handle);
+    vSemaphoreDelete(monitor.response_sig_handle);
+    printf("Touch Element waterproof guard sensor test finish\n");
+}
+
+static void test_waterproof_event_simulator(touch_pad_t guard_channel, touch_button_event_t guard_state)
+{
+    if (guard_state == TOUCH_BUTTON_EVT_ON_PRESS) {
+        touch_pad_set_cnt_mode(guard_channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);
+    } else if (guard_state == TOUCH_BUTTON_EVT_ON_RELEASE) {
+        touch_pad_set_cnt_mode(guard_channel, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT);
+    } else {
+        printf("guard sensor simulator doesn't support this operation\n");
+    }
+    /* Fixme: If the normal instance and guard sensor trigger at the same time, guard sensor will lock the state failed */
+    vTaskDelay(pdMS_TO_TICKS(100));
+}
+
+static void test_integrat_btn_sld_mat(void)
+{
+    static const touch_pad_t button_channel_array[3] = {
+        TOUCH_PAD_NUM1,
+        TOUCH_PAD_NUM2,
+        TOUCH_PAD_NUM3
+    };
+    static const float button_sens_array[3] = {
+        0.1F,
+        0.1F,
+        0.1F
+    };
+    static const touch_pad_t slider_channel_array[5] = {
+        TOUCH_PAD_NUM4,
+        TOUCH_PAD_NUM5,
+        TOUCH_PAD_NUM6,
+        TOUCH_PAD_NUM7,
+        TOUCH_PAD_NUM8
+    };
+    static const float slider_sens_array[5] = {
+        0.1F,
+        0.1F,
+        0.1F,
+        0.1F,
+        0.1F
+    };
+    static const touch_pad_t x_axis_channel[3] = {
+        TOUCH_PAD_NUM9,
+        TOUCH_PAD_NUM10,
+        TOUCH_PAD_NUM11,
+    };
+    static const touch_pad_t y_axis_channel[3] = {
+        TOUCH_PAD_NUM12,
+        TOUCH_PAD_NUM13,
+        TOUCH_PAD_NUM14,
+    };
+    static const float x_axis_channel_sens[3] = {
+        0.1F,
+        0.1F,
+        0.1F,
+    };
+    static const float y_axis_channel_sens[3] = {
+        0.1F,
+        0.1F,
+        0.1F,
+    };
+    const uint8_t BUTTON_CHANNEL_NUM = sizeof(button_channel_array) / sizeof(touch_pad_t);
+    const uint8_t SLIDER_CHANNEL_NUM = sizeof(slider_channel_array) / sizeof(touch_pad_t);
+    const uint8_t MATRIX_CHANNEL_NUM_X = sizeof(x_axis_channel) / sizeof(touch_pad_t);
+    const uint8_t MATRIX_CHANNEL_NUM_Y = sizeof(y_axis_channel) / sizeof(touch_pad_t);
+
+    printf("Integration test(button + slider + matrix) start\n");
+
+    BaseType_t os_ret;
+    touch_button_handle_t button_handle[BUTTON_CHANNEL_NUM];
+    touch_slider_handle_t slider_handle;
+    touch_matrix_handle_t matrix_handle;
+    test_monitor_t monitor;
+    TaskHandle_t task_handle = NULL;
+
+    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
+    monitor.response_sig_handle = xSemaphoreCreateBinary();
+    os_ret = xTaskCreate(&test_integration_monitor_task, "test_integration_monitor_task", 4096, (void *)&monitor, 5, &task_handle);
+    TEST_ASSERT(monitor.valid_msg_handle != NULL && monitor.response_sig_handle != NULL && os_ret == pdPASS);
+
+    touch_button_global_config_t button_global_config = TOUCH_BUTTON_GLOBAL_DEFAULT_CONFIG();
+    touch_slider_global_config_t slider_global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();
+    touch_matrix_global_config_t matrix_global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_button_install(&button_global_config));
+    TEST_ESP_OK(touch_slider_install(&slider_global_config));
+    TEST_ESP_OK(touch_matrix_install(&matrix_global_config));
+
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        touch_button_config_t button_config = {
+            .channel_num = button_channel_array[i],
+            .channel_sens = button_sens_array[i]
+        };
+        TEST_ESP_OK(touch_button_create(&button_config, &button_handle[i]));
+        TEST_ESP_OK(touch_button_subscribe_event(button_handle[i], TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));
+        TEST_ESP_OK(touch_button_set_dispatch_method(button_handle[i], TOUCH_ELEM_DISP_EVENT));
+    }
+
+    touch_slider_config_t slider_config = {
+        .channel_array = slider_channel_array,
+        .sensitivity_array = slider_sens_array,
+        .channel_num = SLIDER_CHANNEL_NUM,
+        .position_range = 101
+    };
+    TEST_ESP_OK(touch_slider_create(&slider_config, &slider_handle));
+    TEST_ESP_OK(touch_slider_subscribe_event(slider_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));
+    TEST_ESP_OK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_EVENT));
+
+    touch_matrix_config_t matrix_config = {
+        .x_channel_array = x_axis_channel,
+        .y_channel_array = y_axis_channel,
+        .x_sensitivity_array = x_axis_channel_sens,
+        .y_sensitivity_array = y_axis_channel_sens,
+        .x_channel_num = MATRIX_CHANNEL_NUM_X,
+        .y_channel_num = MATRIX_CHANNEL_NUM_Y
+    };
+    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));
+    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));
+    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_EVENT));
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500)); //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    for (int i = 0; i < 30; i++) {
+        printf("Integration test... (%d/30)\n", i + 1);
+        touch_elem_message_t valid_message;
+        valid_message.element_type = (random() % (TOUCH_ELEM_TYPE_MATRIX + 1));
+        if (valid_message.element_type == TOUCH_ELEM_TYPE_BUTTON) {
+            uint32_t button_index = random() % BUTTON_CHANNEL_NUM;
+            valid_message.handle = button_handle[button_index];
+            touch_button_message_t button_message = {
+                .event = TOUCH_BUTTON_EVT_ON_PRESS
+            };
+            memcpy(valid_message.child_msg, &button_message, sizeof(button_message));  //Construct child message
+            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);
+            test_button_event_simulator(valid_message.handle, button_message.event);
+        } else if (valid_message.element_type == TOUCH_ELEM_TYPE_SLIDER) {
+            valid_message.handle = slider_handle;
+            touch_slider_message_t slider_message = {
+                .event = TOUCH_SLIDER_EVT_ON_PRESS,
+                .position = 0  //No check
+            };
+            memcpy(valid_message.child_msg, &slider_message, sizeof(slider_message));  //Construct child message
+            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);
+            test_slider_event_simulator(valid_message.handle, slider_message.event, 1);
+        } else if (valid_message.element_type == TOUCH_ELEM_TYPE_MATRIX) {
+            uint32_t matrix_x_axis_index = random() % MATRIX_CHANNEL_NUM_X;
+            uint32_t matrix_y_axis_index = random() % MATRIX_CHANNEL_NUM_Y;
+            valid_message.handle = matrix_handle;
+            touch_matrix_message_t matrix_message = {
+                .event = TOUCH_MATRIX_EVT_ON_PRESS,
+                .position.x_axis = matrix_x_axis_index,
+                .position.y_axis = matrix_y_axis_index,
+                .position.index = matrix_x_axis_index * MATRIX_CHANNEL_NUM_Y + matrix_y_axis_index
+            };
+            memcpy(valid_message.child_msg, &matrix_message, sizeof(matrix_message));  //Construct child message
+            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);
+            test_matrix_event_simulator(valid_message.handle, matrix_message.event, matrix_message.position.index);
+        }
+        os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(500));
+        TEST_ASSERT_MESSAGE(os_ret == pdPASS, "response queue timeout (500ms)");
+
+        if (valid_message.element_type == TOUCH_ELEM_TYPE_BUTTON) {
+            touch_button_message_t button_message;
+            button_message.event = TOUCH_BUTTON_EVT_ON_RELEASE;
+            memcpy(valid_message.child_msg, &button_message, sizeof(button_message));
+            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);
+            test_button_event_simulator(valid_message.handle, button_message.event);
+        } else if (valid_message.element_type == TOUCH_ELEM_TYPE_SLIDER) {
+            touch_slider_message_t slider_message;
+            slider_message.event = TOUCH_SLIDER_EVT_ON_RELEASE;
+            memcpy(valid_message.child_msg, &slider_message, sizeof(slider_message));
+            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);
+            test_slider_event_simulator(valid_message.handle, slider_message.event, 1);
+        } else if (valid_message.element_type == TOUCH_ELEM_TYPE_MATRIX) {
+            touch_matrix_message_t matrix_message;
+            matrix_message.event = TOUCH_MATRIX_EVT_ON_RELEASE;
+            memcpy(valid_message.child_msg, &matrix_message, sizeof(matrix_message));
+            xQueueSend(monitor.valid_msg_handle, &valid_message, portMAX_DELAY);
+            const touch_matrix_message_t *matrix_message_ptr = touch_matrix_get_message(&valid_message);
+            test_matrix_event_simulator(valid_message.handle, matrix_message.event, matrix_message_ptr->position.index);
+        }
+        os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(500));
+        TEST_ASSERT_MESSAGE(os_ret == pdPASS, "response queue timeout (500ms)");
+    }
+
+    TEST_ESP_OK(touch_element_stop());
+    for (int i = 0; i < BUTTON_CHANNEL_NUM; i++) {
+        TEST_ESP_OK(touch_button_delete(button_handle[i]));
+    }
+    TEST_ESP_OK(touch_slider_delete(slider_handle));
+    TEST_ESP_OK(touch_matrix_delete(matrix_handle));
+    touch_button_uninstall();
+    touch_slider_uninstall();
+    touch_matrix_uninstall();
+
+    while (eTaskGetState(task_handle) == eRunning) {
+        vTaskDelay(pdTICKS_TO_MS(1));
+    }
+    vTaskDelete(task_handle);
+    vQueueDelete(monitor.valid_msg_handle);
+    vSemaphoreDelete(monitor.response_sig_handle);
+    printf("Integration test(button + slider + matrix) finish\n");
+}
+
+static void test_integration_monitor_task(void *arg)
+{
+    test_monitor_t *monitor = (test_monitor_t *)arg;
+    BaseType_t os_ret;
+    touch_elem_message_t current_message, valid_message;
+    while (1) {
+        touch_element_message_receive(&current_message, portMAX_DELAY);
+        os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(500)); //Get the valid message for the verification, 500ms timeout
+        TEST_ASSERT_MESSAGE(os_ret == pdPASS, "trigger queue timeout (500ms)");
+        if (current_message.element_type == TOUCH_ELEM_TYPE_BUTTON) {
+            test_button_event_check(&valid_message, &current_message);
+        } else if (current_message.element_type == TOUCH_ELEM_TYPE_SLIDER) {
+            test_slider_event_check(&valid_message, &current_message);
+        } else if (current_message.element_type == TOUCH_ELEM_TYPE_MATRIX) {
+            test_matrix_event_check(&valid_message, &current_message);
+        }
+        xSemaphoreGive(monitor->response_sig_handle);
+    }
+}

+ 442 - 0
components/touch_element/test/test_touch_matrix.c

@@ -0,0 +1,442 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+#include "unity.h"
+
+#include "touch_element/touch_element_private.h"
+#include "touch_element/touch_matrix.h"
+
+static const touch_pad_t x_axis_channel[3] = {
+    TOUCH_PAD_NUM5,
+    TOUCH_PAD_NUM7,
+    TOUCH_PAD_NUM9,
+};
+static const touch_pad_t y_axis_channel[3] = {
+    TOUCH_PAD_NUM11,
+    TOUCH_PAD_NUM12,
+    TOUCH_PAD_NUM14,
+};
+static const float x_axis_channel_sens[3] = {
+    0.1F,
+    0.1F,
+    0.1F,
+};
+static const float y_axis_channel_sens[3] = {
+    0.1F,
+    0.1F,
+    0.1F,
+};
+const uint8_t MATRIX_CHANNEL_NUM_X = sizeof(x_axis_channel) / sizeof(touch_pad_t);
+const uint8_t MATRIX_CHANNEL_NUM_Y = sizeof(y_axis_channel) / sizeof(touch_pad_t);
+
+typedef struct {
+    QueueHandle_t valid_msg_handle;
+    SemaphoreHandle_t response_sig_handle;
+} test_monitor_t;
+
+/* ------------------------------------------------------------------------------------------------------------------ */
+void test_matrix_event_simulator(touch_matrix_handle_t matrix_handle, touch_matrix_event_t matrix_event, uint32_t pos_index);
+static void test_matrix_channel_simulator(touch_pad_t channel, touch_matrix_event_t matrix_event);
+void test_matrix_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);
+static void test_matrix_callback_check(touch_matrix_handle_t current_handle, touch_matrix_message_t *current_message, touch_elem_message_t *valid_message);
+void test_matrix_event_trigger_and_check(touch_matrix_handle_t handle, touch_matrix_event_t matrix_event, uint32_t pos_index);
+void test_matrix_callback_trigger_and_check(touch_matrix_handle_t handle, touch_matrix_event_t matrix_event, uint32_t pos_index, bool should_trigger, test_monitor_t *monitor);
+/* ------------------------------------------------ Dispatch method test -------------------------------------------- */
+static void test_matrix_disp_event(void);
+static void test_matrix_disp_callback(void);
+static void test_matrix_handler(touch_matrix_handle_t handle, touch_matrix_message_t *message, void *arg);
+/* ------------------------------------------------ Run-time test --------------------------------------------------- */
+static void test_matrix_event_change_lp(void);
+static void test_matrix_callback_change_lp(void);
+static void test_matrix_change_lp_handler(touch_matrix_handle_t out_handle, touch_matrix_message_t *out_message, void *arg);
+/* ----------------------------------------------- Random channel trigger test -------------------------------------- */
+static void test_matrix_random_channel_trigger(void);
+/* ------------------------------------------------------------------------------------------------------------------ */
+
+TEST_CASE("Touch matrix dispatch methods test", "[matrix][touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_matrix_disp_event();
+    test_matrix_disp_callback();
+    touch_element_uninstall();
+}
+
+TEST_CASE("Touch matrix run-time test", "[matrix][touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_matrix_event_change_lp();
+    test_matrix_callback_change_lp();
+    touch_element_uninstall();
+}
+
+TEST_CASE("Touch matrix random channel trigger test", "[matrix][touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_matrix_random_channel_trigger();
+    touch_element_uninstall();
+}
+
+void test_matrix_event_simulator(touch_matrix_handle_t matrix_handle, touch_matrix_event_t matrix_event, uint32_t pos_index)
+{
+    te_matrix_handle_t te_matrix = (te_matrix_handle_t) matrix_handle;
+    touch_pad_t x_channel = te_matrix->device[pos_index / te_matrix->y_channel_num]->channel;
+    touch_pad_t y_channel = te_matrix->device[te_matrix->x_channel_num + (pos_index % te_matrix->y_channel_num)]->channel;
+    if (matrix_event == TOUCH_MATRIX_EVT_ON_PRESS) {
+        touch_pad_set_cnt_mode(x_channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);
+        touch_pad_set_cnt_mode(y_channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);
+    } else if (matrix_event == TOUCH_MATRIX_EVT_ON_RELEASE) {
+        touch_pad_set_cnt_mode(x_channel, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT);
+        touch_pad_set_cnt_mode(y_channel, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT);
+    } else {
+        touch_pad_set_cnt_mode(x_channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT); // LongPress
+        touch_pad_set_cnt_mode(y_channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);
+    }
+}
+
+static void test_matrix_channel_simulator(touch_pad_t channel, touch_matrix_event_t matrix_event)
+{
+    if (matrix_event == TOUCH_MATRIX_EVT_ON_PRESS) {
+        touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);
+    } else if (matrix_event == TOUCH_MATRIX_EVT_ON_RELEASE) {
+        touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT);
+    }
+}
+
+void test_matrix_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message)
+{
+    TEST_ASSERT_MESSAGE(current_message->handle == valid_message->handle, "check handle failed");
+    TEST_ASSERT_MESSAGE(current_message->element_type == valid_message->element_type, "check element type failed");
+    const touch_matrix_message_t *valid_matrix_message = touch_matrix_get_message(valid_message);
+    const touch_matrix_message_t *current_matrix_message = touch_matrix_get_message(current_message);
+    TEST_ASSERT_MESSAGE(current_matrix_message->event == valid_matrix_message->event, "check event failed");
+    TEST_ASSERT_MESSAGE(current_matrix_message->position.index == valid_matrix_message->position.index, "check index failed");
+    TEST_ASSERT_MESSAGE(current_matrix_message->position.x_axis == valid_matrix_message->position.x_axis, "check x_axis failed");
+    TEST_ASSERT_MESSAGE(current_matrix_message->position.y_axis == valid_matrix_message->position.y_axis, "check y_axis failed");
+}
+
+static inline void test_matrix_callback_check(touch_matrix_handle_t current_handle, touch_matrix_message_t *current_message, touch_elem_message_t *valid_message)
+{
+    const touch_matrix_message_t *valid_matrix_message = touch_matrix_get_message(valid_message);
+    TEST_ASSERT_MESSAGE(valid_message->handle == current_handle, "check handle failed");
+    TEST_ASSERT_MESSAGE(valid_message->element_type == TOUCH_ELEM_TYPE_MATRIX, "check element type failed");
+    TEST_ASSERT_MESSAGE(valid_matrix_message->event == current_message->event, "check event failed");
+    TEST_ASSERT_MESSAGE(valid_matrix_message->position.index == current_message->position.index, "check index failed");
+    TEST_ASSERT_MESSAGE(valid_matrix_message->position.x_axis == current_message->position.x_axis, "check x_axis failed");
+    TEST_ASSERT_MESSAGE(valid_matrix_message->position.y_axis == current_message->position.y_axis, "check y_axis failed");
+}
+
+void test_matrix_event_trigger_and_check(touch_matrix_handle_t handle, touch_matrix_event_t matrix_event, uint32_t pos_index)
+{
+    touch_elem_message_t valid_message = {
+        .handle = handle,
+        .element_type = TOUCH_ELEM_TYPE_MATRIX,
+        .arg = NULL
+    };
+    touch_matrix_message_t matrix_message = {
+        .event = matrix_event,
+        .position.index = pos_index,
+        .position.x_axis = pos_index / MATRIX_CHANNEL_NUM_Y,
+        .position.y_axis = pos_index % MATRIX_CHANNEL_NUM_Y
+    };
+    memcpy(valid_message.child_msg, &matrix_message, sizeof(touch_matrix_message_t));  //Construct valid_message
+
+    test_matrix_event_simulator(handle, matrix_event, pos_index);  //Trigger signal
+
+    touch_elem_message_t current_message;
+    te_matrix_handle_t te_matrix = handle;
+    esp_err_t ret = touch_element_message_receive(&current_message, pdMS_TO_TICKS(2 * te_matrix->trigger_thr * 10));  //Get current message for verification
+    TEST_ASSERT_MESSAGE(ret == ESP_OK, "matrix event receive timeout");
+
+    test_matrix_event_check(&valid_message, &current_message);  //Verification
+}
+
+void test_matrix_callback_trigger_and_check(touch_matrix_handle_t handle, touch_matrix_event_t matrix_event, uint32_t pos_index, bool should_trigger, test_monitor_t *monitor)
+{
+    if (should_trigger) {
+        touch_elem_message_t valid_message = {
+            .handle = handle,
+            .element_type = TOUCH_ELEM_TYPE_MATRIX,
+            .arg = NULL
+        };
+        touch_matrix_message_t matrix_message = {
+            .event = matrix_event,
+            .position.index = pos_index,
+            .position.x_axis = pos_index / MATRIX_CHANNEL_NUM_Y,
+            .position.y_axis = pos_index % MATRIX_CHANNEL_NUM_Y
+        };
+        memcpy(valid_message.child_msg, &matrix_message, sizeof(touch_matrix_message_t));  //Construct valid_message
+        xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
+    }
+
+    test_matrix_event_simulator(handle, matrix_event, pos_index);  //Trigger signal
+
+    te_matrix_handle_t te_matrix = handle;
+    if (should_trigger) {
+        BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(2 * te_matrix->trigger_thr * 10));
+        TEST_ASSERT_MESSAGE(os_ret == pdPASS, "Matrix queue timeout");
+    } else {
+        BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(500));
+        TEST_ASSERT_MESSAGE(os_ret == pdFALSE, "Matrix invalid trigger");
+    }
+}
+
+static void test_matrix_disp_event(void)
+{
+    touch_matrix_handle_t matrix_handle = NULL;
+    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_matrix_install(&global_config));
+    touch_matrix_config_t matrix_config = {
+        .x_channel_array = x_axis_channel,
+        .y_channel_array = y_axis_channel,
+        .x_sensitivity_array = x_axis_channel_sens,
+        .y_sensitivity_array = y_axis_channel_sens,
+        .x_channel_num = MATRIX_CHANNEL_NUM_X,
+        .y_channel_num = MATRIX_CHANNEL_NUM_Y
+    };
+    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));
+    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_LONGPRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL));
+    TEST_ESP_OK(touch_matrix_set_longpress(matrix_handle, 300));
+    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_EVENT));
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    printf("Touch matrix event test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch matrix event test... (%d/10)\n", i + 1);
+        uint32_t button_num = random() % ( MATRIX_CHANNEL_NUM_X * MATRIX_CHANNEL_NUM_Y );
+        test_matrix_event_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_PRESS, button_num);
+        test_matrix_event_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_LONGPRESS, button_num);
+        test_matrix_event_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num);
+    }
+    printf("Touch matrix event test finish\n");
+
+    TEST_ESP_OK(touch_element_stop());
+    TEST_ESP_OK(touch_matrix_delete(matrix_handle));
+    touch_matrix_uninstall();
+}
+
+static void test_matrix_disp_callback(void)
+{
+    test_monitor_t monitor;
+    touch_matrix_handle_t matrix_handle = NULL;
+    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
+    monitor.response_sig_handle = xSemaphoreCreateBinary();
+    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
+
+    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_matrix_install(&global_config));
+    touch_matrix_config_t matrix_config = {
+        .x_channel_array = x_axis_channel,
+        .y_channel_array = y_axis_channel,
+        .x_sensitivity_array = x_axis_channel_sens,
+        .y_sensitivity_array = y_axis_channel_sens,
+        .x_channel_num = MATRIX_CHANNEL_NUM_X,
+        .y_channel_num = MATRIX_CHANNEL_NUM_Y
+    };
+    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));
+    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_LONGPRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *)&monitor));
+    TEST_ESP_OK(touch_matrix_set_longpress(matrix_handle, 300));
+    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_CALLBACK));
+    TEST_ESP_OK(touch_matrix_set_callback(matrix_handle, test_matrix_handler));
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    printf("Touch matrix callback test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch matrix callback test... (%d/10)\n", i + 1);
+        uint32_t button_num = random() % (MATRIX_CHANNEL_NUM_X * MATRIX_CHANNEL_NUM_Y);
+        test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_PRESS, button_num, true, &monitor);
+        test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_LONGPRESS, button_num, true, &monitor);
+        test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num, true, &monitor);
+    }
+    printf("Touch matrix callback test finish\n");
+
+    TEST_ESP_OK(touch_element_stop());
+    TEST_ESP_OK(touch_matrix_delete(matrix_handle));
+    touch_matrix_uninstall();
+    vQueueDelete(monitor.valid_msg_handle);
+    vSemaphoreDelete(monitor.response_sig_handle);
+}
+
+static void test_matrix_handler(touch_matrix_handle_t handle, touch_matrix_message_t *message, void *arg)
+{
+    test_monitor_t *monitor = (test_monitor_t *)arg;
+    touch_elem_message_t valid_message;
+    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));
+    TEST_ASSERT_MESSAGE(os_ret == pdPASS, "test_matrix_handler: queue timeout");
+    test_matrix_callback_check(handle, message, &valid_message);
+    xSemaphoreGive(monitor->response_sig_handle);
+}
+
+static void test_matrix_random_channel_trigger(void)
+{
+    test_monitor_t monitor;
+    touch_matrix_handle_t matrix_handle = NULL;
+    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
+    monitor.response_sig_handle = xSemaphoreCreateBinary();
+    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
+
+    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_matrix_install(&global_config));
+    touch_matrix_config_t matrix_config = {
+        .x_channel_array = x_axis_channel,
+        .y_channel_array = y_axis_channel,
+        .x_sensitivity_array = x_axis_channel_sens,
+        .y_sensitivity_array = y_axis_channel_sens,
+        .x_channel_num = MATRIX_CHANNEL_NUM_X,
+        .y_channel_num = MATRIX_CHANNEL_NUM_Y
+    };
+    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));
+    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *) &monitor));
+    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_CALLBACK));
+    TEST_ESP_OK(touch_matrix_set_callback(matrix_handle, test_matrix_handler));
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    printf("Touch matrix random channel trigger test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch matrix random channel trigger test... (%d/10)\n", i + 1);
+        uint32_t channel_index_1 = random() % (MATRIX_CHANNEL_NUM_X + MATRIX_CHANNEL_NUM_Y);
+        uint32_t channel_index_2 = random() % (MATRIX_CHANNEL_NUM_X + MATRIX_CHANNEL_NUM_Y);
+        touch_pad_t channel_1 = (channel_index_1 < MATRIX_CHANNEL_NUM_X) ? x_axis_channel[channel_index_1] : y_axis_channel[channel_index_1 - MATRIX_CHANNEL_NUM_X];
+        touch_pad_t channel_2 = (channel_index_2 < MATRIX_CHANNEL_NUM_X) ? x_axis_channel[channel_index_2] : y_axis_channel[channel_index_2 - MATRIX_CHANNEL_NUM_X];
+        if ((channel_index_1 <= 2 && channel_index_2 <= 2) || (channel_index_1 > 2 && channel_index_2 > 2)) {  //all x channels triggered or all y channels triggered
+            //Should not be triggered
+            BaseType_t os_ret;
+            test_matrix_channel_simulator(channel_1, TOUCH_MATRIX_EVT_ON_PRESS);
+            test_matrix_channel_simulator(channel_2, TOUCH_MATRIX_EVT_ON_PRESS);
+            os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(500));
+            TEST_ASSERT_MESSAGE(os_ret == pdFAIL, "Matrix Press event invalid trigger");
+
+            test_matrix_channel_simulator(channel_1, TOUCH_MATRIX_EVT_ON_RELEASE);
+            test_matrix_channel_simulator(channel_2, TOUCH_MATRIX_EVT_ON_RELEASE);
+            os_ret = xSemaphoreTake(monitor.response_sig_handle, pdMS_TO_TICKS(500));
+            TEST_ASSERT_MESSAGE(os_ret == pdFAIL, "Matrix Release event invalid trigger");
+        } else {
+            //Should be triggered
+            uint8_t button_num;
+            if (channel_index_1 <= 2) {
+                button_num = channel_index_1 * matrix_config.y_channel_num + (channel_index_2 - MATRIX_CHANNEL_NUM_X);
+            } else {
+                button_num = channel_index_2 * matrix_config.x_channel_num + (channel_index_1 - MATRIX_CHANNEL_NUM_Y);
+            }
+            test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_PRESS, button_num, true, &monitor);
+            test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num, true, &monitor);
+        }
+    }
+    printf("Touch matrix random channel trigger test finish\n");
+
+    TEST_ESP_OK(touch_element_stop());
+    TEST_ESP_OK(touch_matrix_delete(matrix_handle));
+    touch_matrix_uninstall();
+    vQueueDelete(monitor.valid_msg_handle);
+    vSemaphoreDelete(monitor.response_sig_handle);
+}
+
+static void test_matrix_event_change_lp(void)
+{
+    touch_matrix_handle_t matrix_handle = NULL;
+    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_matrix_install(&global_config));
+    touch_matrix_config_t matrix_config = {
+        .x_channel_array = x_axis_channel,
+        .y_channel_array = y_axis_channel,
+        .x_sensitivity_array = x_axis_channel_sens,
+        .y_sensitivity_array = y_axis_channel_sens,
+        .x_channel_num = MATRIX_CHANNEL_NUM_X,
+        .y_channel_num = MATRIX_CHANNEL_NUM_Y
+    };
+    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));
+    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_LONGPRESS, NULL));
+    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_EVENT));
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    //10 times random press/longpress/release test
+    printf("Touch matrix event change longtime test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch matrix event change longtime test... (%d/10)\n", i + 1);
+        uint32_t button_num = random() % ( MATRIX_CHANNEL_NUM_X * MATRIX_CHANNEL_NUM_Y );
+        TEST_ESP_OK(touch_matrix_set_longpress(matrix_handle, 200 + (i + 1) * 50));
+        test_matrix_event_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_LONGPRESS, button_num);
+        test_matrix_event_simulator(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num); //Reset hardware
+        vTaskDelay(pdMS_TO_TICKS(100));  //Fixme: Waiting for driver core handle release event
+    }
+    printf("Touch matrix event change longtime test finish\n");
+    TEST_ESP_OK(touch_element_stop());
+    TEST_ESP_OK(touch_matrix_delete(matrix_handle));
+    touch_matrix_uninstall();
+}
+
+static void test_matrix_callback_change_lp(void)
+{
+    test_monitor_t monitor;
+    touch_matrix_handle_t matrix_handle = NULL;
+    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
+    monitor.response_sig_handle = xSemaphoreCreateBinary();
+    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
+
+    touch_matrix_global_config_t global_config = TOUCH_MATRIX_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_matrix_install(&global_config));
+    touch_matrix_config_t matrix_config = {
+        .x_channel_array = x_axis_channel,
+        .y_channel_array = y_axis_channel,
+        .x_sensitivity_array = x_axis_channel_sens,
+        .y_sensitivity_array = y_axis_channel_sens,
+        .x_channel_num = MATRIX_CHANNEL_NUM_X,
+        .y_channel_num = MATRIX_CHANNEL_NUM_Y
+    };
+    TEST_ESP_OK(touch_matrix_create(&matrix_config, &matrix_handle));
+    TEST_ESP_OK(touch_matrix_subscribe_event(matrix_handle, TOUCH_ELEM_EVENT_ON_LONGPRESS, (void *)&monitor));
+    TEST_ESP_OK(touch_matrix_set_longpress(matrix_handle, 300));
+    TEST_ESP_OK(touch_matrix_set_dispatch_method(matrix_handle, TOUCH_ELEM_DISP_CALLBACK));
+    TEST_ESP_OK(touch_matrix_set_callback(matrix_handle, test_matrix_change_lp_handler));
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    printf("Touch matrix callback change longtime test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch matrix callback change longtime test... (%d/10)\n", i + 1);
+        uint32_t button_num = random() % (MATRIX_CHANNEL_NUM_X * MATRIX_CHANNEL_NUM_Y);
+        test_matrix_callback_trigger_and_check(matrix_handle, TOUCH_MATRIX_EVT_ON_LONGPRESS, button_num, true, &monitor);
+        test_matrix_event_simulator(matrix_handle, TOUCH_MATRIX_EVT_ON_RELEASE, button_num); //Reset hardware
+        vTaskDelay(pdMS_TO_TICKS(100));  //Fixme: Waiting for driver core handle release event
+
+    }
+    printf("Touch matrix callback change longtime test finish\n");
+
+    TEST_ESP_OK(touch_element_stop());
+    TEST_ESP_OK(touch_matrix_delete(matrix_handle));
+    touch_matrix_uninstall();
+    vQueueDelete(monitor.valid_msg_handle);
+    vSemaphoreDelete(monitor.response_sig_handle);
+}
+
+static void test_matrix_change_lp_handler(touch_matrix_handle_t out_handle, touch_matrix_message_t *out_message, void *arg)
+{
+    test_monitor_t *monitor = (test_monitor_t *)arg;
+    touch_elem_message_t valid_message;
+    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));  //500ms timeout
+    TEST_ASSERT_MESSAGE(os_ret == pdPASS, "test_matrix_handler: queue timeout");
+    test_matrix_callback_check(out_handle, out_message, &valid_message);
+    xSemaphoreGive(monitor->response_sig_handle);
+    TEST_ESP_OK(touch_matrix_set_longpress(valid_message.handle, 300)); // Always 300ms
+}

+ 211 - 0
components/touch_element/test/test_touch_slider.c

@@ -0,0 +1,211 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+#include "unity.h"
+
+#include "touch_element/touch_element_private.h"
+#include "touch_element/touch_slider.h"
+
+static const touch_pad_t slider_channel_array[5] = {
+    TOUCH_PAD_NUM1,
+    TOUCH_PAD_NUM2,
+    TOUCH_PAD_NUM3,
+    TOUCH_PAD_NUM4,
+    TOUCH_PAD_NUM5
+};
+static const float slider_sens_array[5] = {
+    0.1F,
+    0.1F,
+    0.1F,
+    0.1F,
+    0.1F
+};
+const uint8_t SLIDER_CHANNEL_NUM = sizeof(slider_channel_array) / sizeof(touch_pad_t);
+
+typedef struct {
+    QueueHandle_t valid_msg_handle;
+    SemaphoreHandle_t response_sig_handle;
+} test_monitor_t;
+
+/* ------------------------------------------------------------------------------------------------------------------ */
+void test_slider_event_simulator(touch_slider_handle_t slider_handle, touch_slider_event_t slider_event, uint32_t random);
+void test_slider_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message);
+static void test_slider_callback_check(touch_slider_handle_t current_handle, touch_slider_message_t *current_message, touch_elem_message_t *valid_message);
+void test_slider_event_trigger_and_check(touch_slider_handle_t handle, touch_slider_event_t slider_event, uint32_t random_channel);
+void test_slider_callback_trigger_and_check(touch_slider_handle_t handle, touch_slider_event_t slider_event, bool should_trigger, test_monitor_t *monitor, uint32_t random_channel);
+/* ------------------------------------------------ Dispatch method test -------------------------------------------- */
+static void test_slider_disp_event(void);
+static void test_slider_disp_callback(void);
+static void test_slider_handler(touch_slider_handle_t handle, touch_slider_message_t *message, void *arg);
+/* ------------------------------------------------------------------------------------------------------------------ */
+
+TEST_CASE("Touch slider dispatch methods test", "[slider][touch_element]")
+{
+    touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_element_install(&global_config));
+    test_slider_disp_event();
+    test_slider_disp_callback();
+    touch_element_uninstall();
+}
+
+void test_slider_event_simulator(touch_slider_handle_t slider_handle, touch_slider_event_t slider_event, uint32_t random)
+{
+    te_slider_handle_t te_slider = (te_slider_handle_t) slider_handle;
+    touch_pad_t channel = te_slider->device[random % te_slider->channel_sum]->channel;
+    if (slider_event == TOUCH_SLIDER_EVT_ON_PRESS) {
+        touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_3, TOUCH_PAD_TIE_OPT_DEFAULT);
+    } else if (slider_event == TOUCH_SLIDER_EVT_ON_RELEASE) {
+        touch_pad_set_cnt_mode(channel, TOUCH_PAD_SLOPE_7, TOUCH_PAD_TIE_OPT_DEFAULT);
+    }
+}
+
+void test_slider_event_check(touch_elem_message_t *valid_message, touch_elem_message_t *current_message)
+{
+    TEST_ASSERT_MESSAGE(current_message->handle == valid_message->handle, "check handle failed");
+    TEST_ASSERT_MESSAGE(current_message->element_type == valid_message->element_type, "check element type failed");
+    const touch_slider_message_t *valid_slider_message = touch_slider_get_message(valid_message);
+    const touch_slider_message_t *current_slider_message = touch_slider_get_message(current_message);
+    TEST_ASSERT_MESSAGE(current_slider_message->event == valid_slider_message->event, "check event failed");
+}
+
+static void test_slider_callback_check(touch_slider_handle_t current_handle, touch_slider_message_t *current_message, touch_elem_message_t *valid_message)
+{
+    const touch_slider_message_t *valid_slider_message = touch_slider_get_message(valid_message);
+    TEST_ASSERT_MESSAGE(valid_message->handle == current_handle, "check handle failed");
+    TEST_ASSERT_MESSAGE(valid_message->element_type == TOUCH_ELEM_TYPE_SLIDER, "check element type failed");
+    TEST_ASSERT_MESSAGE(valid_slider_message->event == current_message->event, "check event failed");
+}
+
+void test_slider_event_trigger_and_check(touch_slider_handle_t handle, touch_slider_event_t slider_event, uint32_t random_channel)
+{
+    touch_elem_message_t valid_message, current_message;
+    touch_slider_message_t slider_message;
+    valid_message.handle = handle;
+    valid_message.element_type = TOUCH_ELEM_TYPE_SLIDER;
+    slider_message.event = slider_event;
+    memcpy(valid_message.child_msg, &slider_message, sizeof(touch_slider_message_t));
+    test_slider_event_simulator(handle, slider_event, random_channel);
+    esp_err_t ret = touch_element_message_receive(&current_message, 300);
+    TEST_ASSERT_MESSAGE(ret == ESP_OK, "slider event receive timeout");
+    test_slider_event_check(&valid_message, &current_message);
+}
+
+void test_slider_callback_trigger_and_check(touch_slider_handle_t handle, touch_slider_event_t slider_event, bool should_trigger, test_monitor_t *monitor, uint32_t random_channel)
+{
+    if (should_trigger) {
+        touch_elem_message_t valid_message = {
+            .handle = handle,
+            .element_type = TOUCH_ELEM_TYPE_SLIDER,
+            .arg = NULL
+        };
+        touch_slider_message_t slider_message = {
+            .event = slider_event,
+            .position = 0  //No use
+        };
+        memcpy(valid_message.child_msg, &slider_message, sizeof(touch_slider_message_t));  //Construct valid_message
+        xQueueSend(monitor->valid_msg_handle, &valid_message, portMAX_DELAY);
+    }
+
+    test_slider_event_simulator(handle, slider_event, random_channel);  //Trigger signal
+
+    BaseType_t os_ret = xSemaphoreTake(monitor->response_sig_handle, pdMS_TO_TICKS(300));
+    if (should_trigger) {
+        TEST_ASSERT_MESSAGE(os_ret == pdPASS, "Button queue timeout");
+    } else {
+        TEST_ASSERT_MESSAGE(os_ret == pdFALSE, "Button invalid trigger");
+    }
+}
+
+
+static void test_slider_disp_event(void)
+{
+    touch_slider_handle_t slider_handle;
+    touch_slider_global_config_t global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_slider_install(&global_config));
+    /*< Create Touch Slider */
+    touch_slider_config_t slider_config = {
+        .channel_array = slider_channel_array,
+        .sensitivity_array = slider_sens_array,
+        .channel_num = SLIDER_CHANNEL_NUM,
+        .position_range = 101
+    };
+    TEST_ESP_OK(touch_slider_create(&slider_config, &slider_handle));
+    TEST_ESP_OK(touch_slider_subscribe_event(slider_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *) slider_handle));
+    TEST_ESP_OK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_EVENT));
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    //10 times random (x channels) press/release test
+    printf("Touch slider event test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch slider event test... (%d/10)\n", i + 1);
+        uint32_t random_channel = random() % SLIDER_CHANNEL_NUM;
+        test_slider_event_trigger_and_check(slider_handle, TOUCH_SLIDER_EVT_ON_PRESS, random_channel);
+        test_slider_event_trigger_and_check(slider_handle, TOUCH_SLIDER_EVT_ON_RELEASE, random_channel);
+    }
+    printf("Touch slider event test finish\n");
+    TEST_ESP_OK(touch_element_stop());
+    TEST_ESP_OK(touch_slider_delete(slider_handle));
+    touch_slider_uninstall();
+}
+
+
+static void test_slider_disp_callback(void)
+{
+    test_monitor_t monitor;
+    monitor.valid_msg_handle = xQueueCreate(10, sizeof(touch_elem_message_t));
+    monitor.response_sig_handle = xSemaphoreCreateBinary();
+    TEST_ASSERT(monitor.valid_msg_handle != NULL || monitor.response_sig_handle != NULL);
+
+    touch_slider_handle_t slider_handle;
+    touch_slider_global_config_t global_config = TOUCH_SLIDER_GLOBAL_DEFAULT_CONFIG();
+    TEST_ESP_OK(touch_slider_install(&global_config));
+    touch_slider_config_t slider_config = {
+        .channel_array = slider_channel_array,
+        .sensitivity_array = slider_sens_array,
+        .channel_num = SLIDER_CHANNEL_NUM,
+        .position_range = 101
+    };
+    TEST_ESP_OK(touch_slider_create(&slider_config, &slider_handle));
+    TEST_ESP_OK(touch_slider_subscribe_event(slider_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, (void *) &monitor));
+    TEST_ESP_OK(touch_slider_set_dispatch_method(slider_handle, TOUCH_ELEM_DISP_CALLBACK));
+    TEST_ESP_OK(touch_slider_set_callback(slider_handle, test_slider_handler));
+    TEST_ESP_OK(touch_element_start());
+
+    vTaskDelay(pdMS_TO_TICKS(500));  //Mention in README, code-block-1
+
+    srandom((unsigned int)time(NULL));
+    printf("Touch slider callback test start\n");
+    for (int i = 0; i < 10; i++) {
+        printf("Touch slider callback test... (%d/10)\n", i + 1);
+        uint32_t random_channel = random() % SLIDER_CHANNEL_NUM;
+        test_slider_callback_trigger_and_check(slider_handle, TOUCH_SLIDER_EVT_ON_PRESS, true, &monitor, random_channel);
+        test_slider_callback_trigger_and_check(slider_handle, TOUCH_SLIDER_EVT_ON_RELEASE, true, &monitor, random_channel);
+    }
+    printf("Touch slider callback test finish\n");
+
+    TEST_ESP_OK(touch_element_stop());
+    TEST_ESP_OK(touch_slider_delete(slider_handle));
+    touch_slider_uninstall();
+    vQueueDelete(monitor.valid_msg_handle);
+    vSemaphoreDelete(monitor.response_sig_handle);
+}
+
+static void test_slider_handler(touch_slider_handle_t handle, touch_slider_message_t *message, void *arg)
+{
+    test_monitor_t *monitor = (test_monitor_t *)arg;
+    touch_elem_message_t valid_message;
+    BaseType_t os_ret = xQueueReceive(monitor->valid_msg_handle, &valid_message, pdMS_TO_TICKS(200));  //Get the valid message for verification, 200ms timeout
+    TEST_ASSERT_MESSAGE(os_ret == pdPASS, "test_slider_handler: queue timeout");
+
+    test_slider_callback_check(handle, message, &valid_message);  //Verification
+
+    xSemaphoreGive(monitor->response_sig_handle);
+}